Passed
Push — feature/application-skill-info... ( 9c1770...3584f9 )
by Chris
05:42 queued 15s
created

resources/assets/js/components/Application/MyFit/MyFit.tsx   A

Complexity

Total Complexity 6
Complexity/F 0

Size

Lines of Code 182
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 6
eloc 142
mnd 6
bc 6
fnc 0
dl 0
loc 182
rs 10
bpm 0
cpm 0
noi 0
c 0
b 0
f 0
1
/* eslint-disable @typescript-eslint/camelcase */
2
import React, { createRef, useState, MutableRefObject } from "react";
3
import { FormattedMessage } from "react-intl";
4
import { FormikProps } from "formik";
5
import { JobPosterQuestion, JobApplicationAnswer } from "../../../models/types";
6
import Question, { QuestionValues } from "./Question";
7
import {
8
  validateAllForms,
9
  submitAllForms,
10
  focusOnElement,
11
} from "../../../helpers/forms";
12
13
interface MyFitProps {
14
  /** List of job poster questions. */
15
  jobQuestions: JobPosterQuestion[];
16
  jobApplicationAnswers: JobApplicationAnswer[];
17
  handleSubmit: (values: JobApplicationAnswer) => Promise<void>;
18
  handleContinue: () => void;
19
  handleQuit: () => void;
20
  handleReturn: () => void;
21
}
22
23
export const MyFit: React.FunctionComponent<MyFitProps> = ({
24
  jobQuestions,
25
  jobApplicationAnswers,
26
  handleSubmit,
27
  handleContinue,
28
  handleQuit,
29
  handleReturn,
30
}) => {
31
  const [isSubmitting, setIsSubmitting] = useState(false);
32
33
  /**
34
   *
35
   * @param refMap A map of question id to formik Form ref
36
   * @returns A promise that resolves if submission succeeds, and rejects if validation or submission fails.
37
   */
38
  const validateAndSubmit = async (
39
    refMap: Map<number, React.MutableRefObject<FormikProps<QuestionValues>>>,
40
  ): Promise<void> => {
41
    setIsSubmitting(true);
42
    const refs = Array.from(refMap.values());
43
    const formsAreValid = await validateAllForms(refs);
44
    if (formsAreValid) {
45
      try {
46
        await submitAllForms(refs);
47
        setIsSubmitting(false);
48
        return Promise.resolve();
49
      } catch {
50
        setIsSubmitting(false);
51
        return Promise.reject();
52
      }
53
    } else {
54
      Array.from(refMap.entries()).some((ref) => {
55
        const [questionId, formRef] = ref;
56
        if (!formRef.current.isValid) {
57
          focusOnElement(`answer-${questionId}`);
58
          return true;
59
        }
60
        return false;
61
      });
62
      setIsSubmitting(false);
63
      return Promise.reject();
64
    }
65
  };
66
67
  const formRefs = React.useRef<
68
    Map<number, React.MutableRefObject<FormikProps<QuestionValues>>>
69
  >(new Map());
70
71
  return (
72
    <section data-c-container="medium">
73
      <h2 data-c-heading="h2" data-c-margin="top(3) bottom(1)">
74
        <FormattedMessage
75
          id="application.myfit.heading"
76
          defaultMessage="My Fit"
77
          description="Heading for the My Fit step in the Application Timeline"
78
        />
79
      </h2>
80
      <p>
81
        <FormattedMessage
82
          id="application.myfit.firstParagraph"
83
          defaultMessage="The manager has included a few further questions that they'd like you to answer in order to be considered for this position. Questions that require an answer are marked, while all others are optional."
84
          description="Paragraph for the My Fit step in the Application Timeline"
85
        />
86
      </p>
87
      {jobQuestions.map((question, index) => {
88
        if (!formRefs.current.has(question.id)) {
89
          const ref = createRef() as MutableRefObject<
90
            FormikProps<QuestionValues>
91
          >;
92
          formRefs.current.set(question.id, ref);
93
        }
94
95
        return (
96
          <Question
97
            key={question.id}
98
            jobApplicationAnswer={
99
              jobApplicationAnswers.find(
100
                (appAnswer) =>
101
                  appAnswer.job_poster_questions_id === question.id,
102
              ) ?? {
103
                id: 0,
104
                job_application_id: 0,
105
                answer: "",
106
                job_poster_questions_id: 0,
107
              }
108
            }
109
            index={index}
110
            question={question}
111
            handleSubmit={handleSubmit}
112
            formRef={formRefs.current.get(question.id)}
113
          />
114
        );
115
      })}
116
      <div data-c-container="medium" data-c-padding="tb(2)">
117
        <hr data-c-hr="thin(c1)" data-c-margin="bottom(2)" />
118
        <div data-c-grid="gutter">
119
          <div
120
            data-c-alignment="base(centre) tp(left)"
121
            data-c-grid-item="tp(1of2)"
122
          >
123
            <button
124
              data-c-button="outline(c2)"
125
              data-c-radius="rounded"
126
              type="button"
127
              disabled={isSubmitting}
128
              onClick={(): Promise<void> =>
129
                validateAndSubmit(formRefs.current).then(handleReturn)
130
              }
131
            >
132
              <FormattedMessage
133
                id="application.returnButtonLabel"
134
                defaultMessage="Save & Return to Previous Step"
135
                description="The text displayed on the Save & Return button of the Applicant Timeline form."
136
              />
137
            </button>
138
          </div>
139
          <div
140
            data-c-alignment="base(centre) tp(right)"
141
            data-c-grid-item="tp(1of2)"
142
          >
143
            <button
144
              data-c-button="outline(c2)"
145
              data-c-radius="rounded"
146
              type="button"
147
              disabled={isSubmitting}
148
              onClick={(): Promise<void> =>
149
                validateAndSubmit(formRefs.current).then(handleQuit)
150
              }
151
            >
152
              <FormattedMessage
153
                id="application.quitButtonLabel"
154
                defaultMessage="Save & Quit"
155
                description="The text displayed on the Save & Return button of the Applicant Timeline form."
156
              />
157
            </button>
158
            <button
159
              data-c-button="solid(c1)"
160
              data-c-radius="rounded"
161
              data-c-margin="left(1)"
162
              type="button"
163
              disabled={isSubmitting}
164
              onClick={(): Promise<void> =>
165
                validateAndSubmit(formRefs.current).then(handleContinue)
166
              }
167
            >
168
              <FormattedMessage
169
                id="application.submitButtonLabel"
170
                defaultMessage="Save & Continue"
171
                description="The text displayed on the submit button for the Job Details form."
172
              />
173
            </button>
174
          </div>
175
        </div>
176
      </div>
177
    </section>
178
  );
179
};
180
181
export default MyFit;
182