Passed
Push — feature/data-request-hooks ( 67d178...d0da08 )
by Tristan
07:48 queued 01:59
created

resources/assets/js/components/Application/Fit/Question.tsx   A

Complexity

Total Complexity 3
Complexity/F 0

Size

Lines of Code 151
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 3
eloc 118
c 0
b 0
f 0
dl 0
loc 151
rs 10
mnd 3
bc 3
fnc 0
bpm 0
cpm 0
noi 0
1
import * as React from "react";
2
import { Formik, Form, FastField } from "formik";
3
import * as Yup from "yup";
4
import { useIntl, FormattedMessage, defineMessages } from "react-intl";
5
import { JobPosterQuestion, JobApplicationAnswer } from "../../../models/types";
6
import { getLocale, localizeField } from "../../../helpers/localize";
7
import { validationMessages } from "../../Form/Messages";
8
import { fitMessages } from "../applicationMessages";
9
import { countNumberOfWords } from "../../WordCounter/helpers";
10
import TextAreaInput from "../../Form/TextAreaInput";
11
import AlertWhenUnsaved from "../../Form/AlertWhenUnsaved";
12
13
const saveButtonMessages = defineMessages({
14
  save: {
15
    id: "application.fit.saveAnswerButton.default",
16
    defaultMessage: "Save Answer",
17
    description: "Default message displayed on save answer button.",
18
  },
19
  saved: {
20
    id: "application.fit.saveAnswerButton.saved",
21
    defaultMessage: "Saved",
22
    description: "Message displayed on button when data is saved.",
23
  },
24
});
25
26
interface QuestionProps {
27
  jobApplicationAnswer: JobApplicationAnswer;
28
  formRef: any;
29
  index: number;
30
  question: JobPosterQuestion;
31
  handleSubmit: (data: JobApplicationAnswer) => Promise<void>;
32
}
33
34
export interface QuestionValues {
35
  answer: string;
36
}
37
38
const answerToValues = ({ answer }: JobApplicationAnswer): QuestionValues => ({
39
  answer: answer ?? "",
40
});
41
42
const updateAnswerWithValues = (
43
  applicationAnswer: JobApplicationAnswer,
44
  { answer }: QuestionValues,
45
): JobApplicationAnswer => ({
46
  ...applicationAnswer,
47
  answer,
48
});
49
50
const Question: React.FunctionComponent<QuestionProps> = ({
51
  jobApplicationAnswer,
52
  formRef,
53
  index,
54
  question,
55
  handleSubmit,
56
}) => {
57
  const intl = useIntl();
58
  const locale = getLocale(intl.locale);
59
  const ANSWER_WORD_LIMIT = 250;
60
61
  const initialValues: QuestionValues = answerToValues(jobApplicationAnswer);
62
63
  const validationSchema = Yup.object({
64
    answer: Yup.string()
65
      .test(
66
        "wordCount",
67
        intl.formatMessage(validationMessages.overMaxWords, {
68
          numberOfWords: ANSWER_WORD_LIMIT,
69
        }),
70
        (value: string) => countNumberOfWords(value) <= ANSWER_WORD_LIMIT,
71
      )
72
      .required(intl.formatMessage(validationMessages.required)),
73
  });
74
75
  return (
76
    <Formik
77
      enableReinitialize
78
      innerRef={formRef}
79
      initialValues={initialValues}
80
      validationSchema={validationSchema}
81
      onSubmit={async (values, { setSubmitting, resetForm }) => {
82
        const newjobApplicationAnswer = updateAnswerWithValues(
83
          jobApplicationAnswer,
84
          values,
85
        );
86
87
        await handleSubmit(newjobApplicationAnswer)
88
          .then(() => {
89
            resetForm();
90
            setSubmitting(false);
91
          })
92
          .catch(() => {
93
            setSubmitting(false);
94
          });
95
      }}
96
    >
97
      {({ dirty, isSubmitting }): React.ReactElement => (
98
        <Form>
99
          <AlertWhenUnsaved />
100
          <div key={question.id}>
101
            <p
102
              data-c-margin="top(3) bottom(1)"
103
              data-c-font-weight="bold"
104
              data-c-color="c2"
105
            >
106
              {intl.formatMessage(fitMessages.questionLabel, {
107
                index: index + 1,
108
              })}{" "}
109
              {localizeField(locale, question, "question")}
110
            </p>
111
            <FastField
112
              id={`answer-${question.id}`}
113
              name="answer"
114
              component={TextAreaInput}
115
              required
116
              label={
117
                <FormattedMessage
118
                  id="application.fit.answerLabel"
119
                  defaultMessage="My Answer to Question {index}"
120
                  description="Label before the users answer on the My Fit step."
121
                  values={{
122
                    index: index + 1,
123
                  }}
124
                />
125
              }
126
              wordLimit={ANSWER_WORD_LIMIT}
127
            />
128
            <div data-c-align="base(center) tl(right)">
129
              <button
130
                id={`save-button-${question.id}`}
131
                data-c-button="solid(c1)"
132
                data-c-radius="rounded"
133
                disabled={!dirty || isSubmitting}
134
                type="submit"
135
              >
136
                <span>
137
                  {dirty
138
                    ? intl.formatMessage(saveButtonMessages.save)
139
                    : intl.formatMessage(saveButtonMessages.saved)}
140
                </span>
141
              </button>
142
            </div>
143
          </div>
144
        </Form>
145
      )}
146
    </Formik>
147
  );
148
};
149
150
export default Question;
151