ws-nextjs-app/pages/[service]/send/[id]/FormScreen/index.tsx

Summary

Maintainability
A
0 mins
Test Coverage
/** @jsx jsx */
import React, { useEffect, useRef, useContext } from 'react';
import { jsx } from '@emotion/react';
import Heading from '#app/components/Heading';
import { LiveRegionContextProvider } from '#app/components/LiveRegion/LiveRegionContext';
import LiveRegion from '#app/components/LiveRegion';
import { ServiceContext } from '#app/contexts/ServiceContext';
import { useFormContext } from '../FormContext';
import { Field } from '../types';
import FormField from '../FormField';
import styles from './styles';
import Submit from '../SubmitButton';
import fallbackTranslations from '../fallbackTranslations';
import ErrorSummaryBox from '../MessageBox/ErrorSummaryBox';

type Props = {
  title: string;
  sectionTitle: string;
  description: string;
  fields: Field[];
  privacyNotice: string;
};

export default function FormScreen({
  title,
  sectionTitle,
  description,
  fields,
  privacyNotice,
}: Props) {
  const { handleSubmit, submitted, validationErrors, attemptedSubmitCount } =
    useFormContext();

  const {
    translations: {
      ugc: {
        dataPolicyHeading = fallbackTranslations.dataPolicyHeading,
        validationRequired = fallbackTranslations.validationRequired,
      } = {},
    },
  } = useContext(ServiceContext);

  const ref = useRef<HTMLElement>(null);

  const hasAttemptedSubmit = attemptedSubmitCount > 0;
  const hasValidationErrors = validationErrors.length > 0;

  useEffect(() => {
    if (hasValidationErrors && hasAttemptedSubmit) {
      document.title = `${validationRequired}: ${title}`;
      ref.current?.focus();
    } else {
      document.title = title;
    }
  }, [
    title,
    hasValidationErrors,
    hasAttemptedSubmit,
    // refocuses on error summary box after every submission attempt
    attemptedSubmitCount,
    validationRequired,
  ]);

  const formFields = fields?.map(({ id, label, htmlType }) => (
    <FormField key={id} id={id} label={label} htmlType={htmlType} />
  ));

  const labelMap: Record<string, string> = {};
  fields?.forEach(({ id, label }) => {
    labelMap[id] = label;
  });

  return (
    <>
      <Heading
        level={1}
        id="content"
        tabIndex={-1}
        css={styles.heading}
        size="trafalgar"
      >
        {title}
      </Heading>
      {description && (
        <div
          // eslint-disable-next-line react/no-danger
          dangerouslySetInnerHTML={{ __html: description }}
          css={styles.description}
        />
      )}
      {sectionTitle && (
        <Heading level={2} size="doublePica">
          {sectionTitle}
        </Heading>
      )}
      <form onSubmit={handleSubmit} noValidate>
        <LiveRegionContextProvider>
          {hasAttemptedSubmit && hasValidationErrors && (
            <ErrorSummaryBox ref={ref} labelMap={labelMap} />
          )}
          {formFields}

          {privacyNotice && (
            <div css={styles.privacyContainer}>
              <strong css={styles.privacyHeading}>{dataPolicyHeading}</strong>
              <div
                // eslint-disable-next-line react/no-danger
                dangerouslySetInnerHTML={{ __html: privacyNotice }}
                css={styles.privacyNotice}
              />
            </div>
          )}

          {!submitted && <Submit />}
          <LiveRegion />
        </LiveRegionContextProvider>
      </form>
    </>
  );
}