sparkletown/sparkle

View on GitHub
src/components/molecules/ProfilePictureInput/ProfilePictureInput.tsx

Summary

Maintainability
A
0 mins
Test Coverage
import React, { useCallback, useRef, useState } from "react";
import { useForm } from "react-hook-form";
import firebase from "firebase/app";

import { ACCEPTED_IMAGE_TYPES } from "settings";

import { determineAvatar } from "utils/image";

import { useUploadProfilePictureHandler } from "hooks/useUploadProfilePictureHandler";

import { DefaultAvatars } from "components/molecules/DefaultAvatars/DefaultAvatars";

import "./ProfilePictureInput.scss";

export interface ProfilePictureInputProps {
  setValue: (inputName: string, value: string, rerender: boolean) => void;
  user: firebase.UserInfo;
  errors: ReturnType<typeof useForm>["errors"];
  pictureUrl: string;
  register: ReturnType<typeof useForm>["register"];
}

export const ProfilePictureInput: React.FunctionComponent<ProfilePictureInputProps> = ({
  setValue,
  user,
  errors,
  pictureUrl,
  register,
}) => {
  const [isPictureUploading, setIsPictureUploading] = useState(false);
  const [error, setError] = useState("");
  const uploadRef = useRef<HTMLInputElement>(null);

  const uploadProfilePictureHandler = useUploadProfilePictureHandler(
    setError,
    user
  );

  const handleFileChange = useCallback(
    async (e: React.ChangeEvent<HTMLInputElement>) => {
      setIsPictureUploading(true);
      try {
        const pictureUrlRef = await uploadProfilePictureHandler(e);
        if (pictureUrlRef) {
          setValue("pictureUrl", pictureUrlRef, true);
        }
      } finally {
        setIsPictureUploading(false);
      }
    },
    [setValue, uploadProfilePictureHandler]
  );

  const uploadProfilePic = useCallback((event) => {
    event.preventDefault();
    uploadRef.current?.click();
  }, []);

  const setPictureUrl = useCallback(
    (url: string) => {
      setValue("pictureUrl", url, true);
    },
    [setValue]
  );

  const hasError = !!error;

  const { src: pictureSrc, onError: onPictureSrcError } = determineAvatar({
    pictureUrl,
    userInfo: user,
  });

  return (
    <div className="ProfilePictureUploadForm">
      <div
        className="ProfilePicturePreviewContainer"
        onClick={() => uploadRef.current?.click()}
      >
        <img
          src={pictureSrc}
          onError={onPictureSrcError}
          className="profile-icon ProfilePicturePreviewContainer__image"
          alt="your profile"
        />
      </div>
      <input
        type="file"
        id="profile-picture-input"
        name="profilePicture"
        onChange={handleFileChange}
        accept={ACCEPTED_IMAGE_TYPES}
        className="ProfilePictureUploadForm__input"
        ref={uploadRef}
      />
      <button
        className="ProfilePictureUploadForm__uploadButton"
        onClick={(event) => uploadProfilePic(event)}
      >
        Upload your profile pic
      </button>
      {errors.pictureUrl && errors.pictureUrl.type === "required" && (
        <span className="input-error">Profile picture is required</span>
      )}
      {isPictureUploading && <small>Picture uploading...</small>}
      {error && <small>Error uploading: {error}</small>}
      <small>Or pick one from our Sparkle profile pics</small>
      <DefaultAvatars
        onAvatarClick={setPictureUrl}
        isLoadingExternal={hasError}
      />
      <input
        name="pictureUrl"
        className="ProfilePictureUploadForm__input"
        ref={register({
          required: true,
        })}
      />
    </div>
  );
};