sparkletown/sparkle

View on GitHub
src/components/organisms/ScreeningRoomVideoAddEditForm/ScreeningRoomVideoAddEditForm.tsx

Summary

Maintainability
C
1 day
Test Coverage
import React, { useCallback, useEffect, useMemo } from "react";
import { Form } from "react-bootstrap";
import { useForm } from "react-hook-form";
import { useParams } from "react-router";
import { useAsyncFn } from "react-use";
import omit from "lodash/omit";

import { deleteScreeningRoomVideo, upsertScreeningRoomVideo } from "api/admin";

import { ScreeningRoomVideo } from "types/screeningRoom";

import { uploadFile } from "utils/file";
import { WithId } from "utils/id";
import { isTruthy } from "utils/types";

import { screeningRoomVideoSchema } from "forms/screeningRoomVideoSchema";

import { useWorldAndSpaceBySlug } from "hooks/spaces/useWorldAndSpaceBySlug";
import { useUser } from "hooks/useUser";

import { AdminInput } from "components/molecules/AdminInput";
import { SubmitError } from "components/molecules/SubmitError";

import { ButtonNG } from "components/atoms/ButtonNG";
import ImageInput from "components/atoms/ImageInput";

import { AdminVenueViewRouteParams } from "../AdminVenueView/AdminVenueView";

import "./ScreeningRoomVideoAddEditForm.scss";

export interface ScreeningRoomVideoAddEditFormProps {
  onDone: () => void;
  video?: WithId<ScreeningRoomVideo>;
}

export const ScreeningRoomVideoAddEditForm: React.FC<ScreeningRoomVideoAddEditFormProps> = ({
  video,
  onDone,
}) => {
  const { user } = useUser();
  const { worldSlug, spaceSlug } = useParams<AdminVenueViewRouteParams>();
  const { spaceId: currentSpaceId } = useWorldAndSpaceBySlug(
    worldSlug,
    spaceSlug
  );

  const isEditMode = isTruthy(video);
  const title = isEditMode ? "Edit video" : "Add video";

  const defaultValues = useMemo(
    () => ({
      title: video?.title ?? "",
      category: video?.category ?? "",
      authorName: video?.authorName ?? "",
      videoSrc: video?.videoSrc ?? "",
      subCategory: video?.subCategory ?? "",
      thumbnailSrcUrl: video?.thumbnailSrc ?? "",
      introduction: video?.introduction ?? "",
    }),
    [
      video?.title,
      video?.category,
      video?.authorName,
      video?.videoSrc,
      video?.subCategory,
      video?.thumbnailSrc,
      video?.introduction,
    ]
  );

  const {
    register,
    getValues,
    handleSubmit,
    errors,
    setValue,
    reset,
  } = useForm({
    reValidateMode: "onChange",

    validationSchema: screeningRoomVideoSchema,
    defaultValues,
  });

  useEffect(() => reset(defaultValues), [defaultValues, reset]);
  const changeRoomImageUrl = useCallback(
    (val: string) => {
      setValue("image_url", val, false);
    },
    [setValue]
  );

  const [
    { loading: isLoading, error: submitError },
    addVideo,
  ] = useAsyncFn(async () => {
    if (!user || !currentSpaceId) return;

    const {
      title,
      category,
      authorName,
      videoSrc,
      subCategory,
      introduction,
      // @debt this needs resolving properly
      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
      // @ts-ignore
      thumbnailSrcFile,
    } = getValues();

    const videoSource = video ? omit(video, ["id"]) : {};
    const fileDirectory = `users/${user.uid}/venues/${currentSpaceId}`;
    const thumbnailSrc = thumbnailSrcFile
      ? await uploadFile(fileDirectory, thumbnailSrcFile)
      : video?.thumbnailSrc;

    const videoData: ScreeningRoomVideo = {
      ...videoSource,
      title,
      category: category.toLocaleLowerCase(),
      authorName,
      thumbnailSrc: thumbnailSrc ?? "",
      videoSrc,
      subCategory,
      introduction,
    };

    if (video) {
      await upsertScreeningRoomVideo(videoData, currentSpaceId, video.id);
    } else {
      await upsertScreeningRoomVideo(videoData, currentSpaceId);
    }

    await onDone();
  }, [currentSpaceId, getValues, onDone, video, user]);

  const [{ loading: isDeleting, error: deleteError }, deleteVideo] = useAsyncFn(
    async () => {
      if (!currentSpaceId || !video) return;

      await deleteScreeningRoomVideo(video.id, currentSpaceId);
      await onDone();
    }
  );

  return (
    <Form
      className="ScreeningRoomVideoAddEditForm__form"
      onSubmit={handleSubmit(addVideo)}
    >
      <div className="ScreeningRoomVideoAddEditForm__title">{title}</div>
      <AdminInput
        name="title"
        type="text"
        autoComplete="off"
        placeholder="Name your video"
        label="Title (required)"
        errors={errors}
        register={register}
        disabled={isLoading}
      />

      <AdminInput
        name="authorName"
        type="text"
        autoComplete="off"
        placeholder="Esmerelda Diamond"
        label="Author of video (required)"
        errors={errors}
        register={register}
        disabled={isLoading}
      />

      <AdminInput
        name="videoSrc"
        type="text"
        autoComplete="off"
        placeholder="https://"
        label="Embed URL (required)"
        errors={errors}
        register={register}
        disabled={isLoading}
      />

      <AdminInput
        name="category"
        type="text"
        autoComplete="off"
        placeholder="Add category"
        label="Category (required)"
        errors={errors}
        register={register}
        disabled={isLoading}
      />

      <ImageInput
        onChange={changeRoomImageUrl}
        name="thumbnailSrc"
        setValue={setValue}
        register={register}
        small
        imgUrl={video?.thumbnailSrc}
        error={errors?.thumbnailSrcUrl}
        text="Change thumbnail"
      />

      <AdminInput
        name="subCategory"
        type="text"
        autoComplete="off"
        placeholder="Add subcategory"
        label="Subcategory"
        errors={errors}
        register={register}
        disabled={isLoading}
      />

      <AdminInput
        name="introduction"
        type="text"
        autoComplete="off"
        placeholder="Add introduction"
        label="Introduction"
        errors={errors}
        register={register}
        disabled={isLoading}
      />

      <SubmitError error={submitError || deleteError} />
      <div className="ScreeningRoomVideoAddEditForm__buttons">
        {isEditMode && (
          <ButtonNG
            variant="danger"
            disabled={isLoading || isDeleting}
            onClick={deleteVideo}
          >
            Delete
          </ButtonNG>
        )}
        <ButtonNG
          variant="primary"
          disabled={isLoading || isDeleting}
          title={title}
          type="submit"
        >
          Save
        </ButtonNG>
      </div>
    </Form>
  );
};