sparkletown/sparkle

View on GitHub
src/pages/Account/ProfileQuestions.tsx

Summary

Maintainability
C
1 day
Test Coverage
import React, { useCallback, useEffect } from "react";
import { useForm } from "react-hook-form";
import { useHistory } from "react-router-dom";
import { useAsyncFn } from "react-use";

import { ACCOUNT_CODE_QUESTIONS_URL } from "settings";

import { Question } from "types/Question";

import { generateUrl } from "utils/url";

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

import { updateTheme } from "pages/VenuePage/helpers";

import { Loading } from "components/molecules/Loading";
import { LoadingPage } from "components/molecules/LoadingPage";

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

import { updateUserProfile } from "./helpers";

// @debt refactor the questions related styles from Account.scss into Questions.scss
import "./ProfileQuestions.scss";

export interface QuestionsFormData {
  islandCompanion: string;
  gratefulFor: string;
  likeAboutParties: string;
}

export const ProfileQuestions: React.FC = () => {
  const history = useHistory();

  const { user } = useUser();

  const { worldSlug, spaceSlug } = useSpaceParams();
  const { world, space, isLoaded } = useWorldAndSpaceBySlug(
    worldSlug,
    spaceSlug
  );

  const { register, handleSubmit, formState } = useForm<QuestionsFormData>({
    mode: "onChange",
  });

  const proceed = useCallback(
    () =>
      history.push(
        generateUrl({
          route: ACCOUNT_CODE_QUESTIONS_URL,
          required: ["worldSlug"],
          params: { worldSlug, spaceSlug },
        })
      ),
    [history, worldSlug, spaceSlug]
  );

  useEffect(() => {
    if (!isLoaded) return;

    // Skip this screen if there are no profile questions for the world
    if (!world?.questions?.profile?.length) {
      proceed();
    }
  }, [isLoaded, proceed, world]);

  const [{ loading: isUpdating, error: httpError }, onSubmit] = useAsyncFn(
    async (data: QuestionsFormData) => {
      if (!user) return;

      await updateUserProfile(user.uid, data);

      proceed();
    },
    [proceed, user]
  );

  useEffect(() => {
    if (!space) return;

    // @debt replace this with useCss?
    updateTheme(space);
  }, [space]);

  // @debt Maybe add something more pretty for UX here, in the vein of NotFound (with custom message)
  if (!spaceSlug) {
    return <>Error: Missing required spaceSlug param</>;
  }

  if (isLoaded && !space) {
    return <NotFound />;
  }

  if (!isLoaded) {
    return <LoadingPage />;
  }

  const profileQuestions = world?.questions?.profile;
  const numberOfQuestions = profileQuestions?.length ?? 0;
  const headerMessage = `Now complete your profile by answering ${
    numberOfQuestions === 1 ? "this question" : "some short questions"
  }`;

  return (
    <div className="ProfileQuestions">
      <div className="hero-logo sparkle" />
      <div className="ProfileQuestions__container">
        <h2 className="header-message">{headerMessage}</h2>

        <p className="subheader-message">
          This will help your fellow partygoers break the ice
        </p>

        <form onSubmit={handleSubmit(onSubmit)} className="form">
          {profileQuestions?.map((question: Question) => (
            <div
              key={question.name}
              className="ProfileQuestions__question form-group"
            >
              <label className="input-block input-centered">
                <strong>{question.text}</strong>
                <textarea
                  className="input-block input-centered"
                  name={question.name}
                  placeholder={question.text}
                  ref={register()}
                />
              </label>
            </div>
          ))}

          <div>
            <ButtonNG
              variant="primary"
              type="submit"
              disabled={!formState.isValid || isUpdating}
            >
              Save answers and continue
            </ButtonNG>
            {isUpdating && <Loading />}
            {httpError && (
              <span className="input-error">{httpError.message}</span>
            )}
          </div>
        </form>
      </div>
    </div>
  );
};