Passed
Push — feature/application-review-ui ( afbf92 )
by Chris
06:55
created

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

Complexity

Total Complexity 3
Complexity/F 0

Size

Lines of Code 149
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 3
eloc 116
mnd 3
bc 3
fnc 0
dl 0
loc 149
rs 10
bpm 0
cpm 0
noi 0
c 0
b 0
f 0
1
/* eslint-disable @typescript-eslint/camelcase */
2
import * as React from "react";
3
import { Formik, Form, FastField } from "formik";
4
import * as Yup from "yup";
5
import { useIntl, FormattedMessage, defineMessages } from "react-intl";
6
import { JobPosterQuestion, JobApplicationAnswer } from "../../../models/types";
7
import { getLocale, localizeField } from "../../../helpers/localize";
8
import { validationMessages } from "../../Form/Messages";
9
import { fitMessages } from "../applicationMessages";
10
import { countNumberOfWords } from "../../WordCounter/helpers";
11
import TextAreaInput from "../../Form/TextAreaInput";
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) => countNumberOfWords(value) <= ANSWER_WORD_LIMIT,
71
      )
72
      .required(intl.formatMessage(validationMessages.required)),
73
  });
74
75
  return (
76
    <Formik
77
      innerRef={formRef}
78
      initialValues={initialValues}
79
      validationSchema={validationSchema}
80
      onSubmit={async (values, { setSubmitting, resetForm }) => {
81
        const newjobApplicationAnswer = updateAnswerWithValues(
82
          jobApplicationAnswer,
83
          values,
84
        );
85
86
        await handleSubmit(newjobApplicationAnswer)
87
          .then(() => {
88
            resetForm();
89
            setSubmitting(false);
90
          })
91
          .catch(() => {
92
            setSubmitting(false);
93
          });
94
      }}
95
    >
96
      {({ dirty, isSubmitting }): React.ReactElement => (
97
        <Form>
98
          <div key={question.id}>
99
            <p
100
              data-c-margin="top(3) bottom(1)"
101
              data-c-font-weight="bold"
102
              data-c-color="c2"
103
            >
104
              {intl.formatMessage(fitMessages.questionLabel, {
105
                index: index + 1,
106
              })}{" "}
107
              {localizeField(locale, question, "question")}
108
            </p>
109
            <FastField
110
              id={`answer-${question.id}`}
111
              name="answer"
112
              component={TextAreaInput}
113
              required
114
              label={
115
                <FormattedMessage
116
                  id="application.fit.answerLabel"
117
                  defaultMessage="My Answer to Question {index}"
118
                  description="Label before the users answer on the My Fit step."
119
                  values={{
120
                    index: index + 1,
121
                  }}
122
                />
123
              }
124
              wordLimit={ANSWER_WORD_LIMIT}
125
            />
126
            <div data-c-align="base(center) tl(right)">
127
              <button
128
                id={`save-button-${question.id}`}
129
                data-c-button="solid(c1)"
130
                data-c-radius="rounded"
131
                disabled={!dirty || isSubmitting}
132
                type="submit"
133
              >
134
                <span>
135
                  {dirty
136
                    ? intl.formatMessage(saveButtonMessages.save)
137
                    : intl.formatMessage(saveButtonMessages.saved)}
138
                </span>
139
              </button>
140
            </div>
141
          </div>
142
        </Form>
143
      )}
144
    </Formik>
145
  );
146
};
147
148
export default Question;
149