Passed
Push — dependabot/npm_and_yarn/dev/st... ( 790070...2dbd00 )
by
unknown
17:44 queued 12:22
created

resources/assets/js/components/CommentForm.tsx   A

Complexity

Total Complexity 6
Complexity/F 0

Size

Lines of Code 250
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 6
eloc 190
mnd 6
bc 6
fnc 0
dl 0
loc 250
rs 10
bpm 0
cpm 0
noi 0
c 0
b 0
f 0
1
/* eslint-disable @typescript-eslint/camelcase, camelcase */
2
import * as React from "react";
3
import { connect } from "react-redux";
4
import { Formik, Form, Field } from "formik";
5
import * as Yup from "yup";
6
import { useIntl, defineMessages, FormattedMessage } from "react-intl";
7
import { validationMessages } from "./Form/Messages";
8
import { CommentTypeId, LocationId } from "../models/lookupConstants";
9
import TextAreaInput from "./Form/TextAreaInput";
10
import SelectInput from "./Form/SelectInput";
11
import { Comment } from "../models/types";
12
import { DispatchType } from "../configureStore";
13
import { createComment } from "../store/Job/jobActions";
14
import { emptyComment } from "../models/jobUtil";
15
16
const formMessages = defineMessages({
17
  commentLabel: {
18
    id: "commentForm.comment.label",
19
    defaultMessage: "Add a Comment",
20
    description: "The label displayed for the comment input field.",
21
  },
22
  commentPlaceholder: {
23
    id: "commentForm.comment.placeholder",
24
    defaultMessage: "eg. Enter your question, recommendation, etc.",
25
    description: "The placeholder displayed for the comment input field.",
26
  },
27
  commentTypeLabel: {
28
    id: "commentForm.commentType.label",
29
    defaultMessage: "Type of Comment",
30
    description: "The label displayed for the comment type select box.",
31
  },
32
  commentTypeNullSelection: {
33
    id: "commentForm.commentType.nullSelection",
34
    defaultMessage: "Select a comment type...",
35
    description: "Null selection from list of comment types",
36
  },
37
  commentLocationLabel: {
38
    id: "commentForm.commentLocation.label",
39
    defaultMessage: "Location of Comment",
40
    description: "The label displayed for the location select box.",
41
  },
42
  commentLocationNullSelection: {
43
    id: "commentForm.commentLocation.nullSelection",
44
    defaultMessage: "Select a location...",
45
    description: "Null selection from list of comment locations",
46
  },
47
});
48
49
export const commentTypeMessages = defineMessages({
50
  question: {
51
    id: "commentType.question",
52
    defaultMessage: "Question",
53
    description: "Comment type from list of comment types",
54
  },
55
  recommendation: {
56
    id: "commentType.recommendation",
57
    defaultMessage: "Recommendation",
58
    description: "Comment type from list of comment types",
59
  },
60
  requiredAction: {
61
    id: "commentType.requiredAction",
62
    defaultMessage: "Required Action",
63
    description: "Comment type from list of comment types",
64
  },
65
  comment: {
66
    id: "commentType.comment",
67
    defaultMessage: "Comment",
68
    description: "Comment type from list of comment types",
69
  },
70
});
71
72
interface CommentFormProps {
73
  jobId: number;
74
  isHrAdviser: boolean;
75
  location: string;
76
  locationOptions?: { value: string; label: string }[];
77
  handleCreateComment: (jobId: number, newComment: Comment) => Promise<Comment>;
78
}
79
80
interface CommentFormValues {
81
  comment: string;
82
  commentType: number | "";
83
  commentLocation?: string | "";
84
}
85
86
const CommentForm: React.FunctionComponent<CommentFormProps> = ({
87
  isHrAdviser,
88
  handleCreateComment,
89
  jobId,
90
  location,
91
  locationOptions,
92
}: CommentFormProps): React.ReactElement => {
93
  const intl = useIntl();
94
  const initialValues: CommentFormValues = {
95
    comment: "",
96
    commentType: "",
97
    commentLocation: "",
98
  };
99
100
  const commentSchema = Yup.object().shape({
101
    comment: Yup.string().required(
102
      intl.formatMessage(validationMessages.required),
103
    ),
104
    ...(isHrAdviser && {
105
      commentType: Yup.number()
106
        .oneOf(
107
          Object.values(CommentTypeId),
108
          intl.formatMessage(validationMessages.invalidSelection),
109
        )
110
        .required(intl.formatMessage(validationMessages.required)),
111
    }),
112
    ...(locationOptions && {
113
      commentLocation: Yup.string()
114
        .oneOf(
115
          Object.values(LocationId),
116
          intl.formatMessage(validationMessages.invalidSelection),
117
        )
118
        .required(intl.formatMessage(validationMessages.required)),
119
    }),
120
  });
121
122
  return (
123
    <section>
124
      <Formik
125
        initialValues={initialValues}
126
        validationSchema={commentSchema}
127
        onSubmit={(values, { setSubmitting, resetForm }): void => {
128
          const newComment: Comment = {
129
            ...emptyComment(),
130
            location: values.commentLocation
131
              ? values.commentLocation
132
              : location,
133
            comment: values.comment,
134
            type_id: isHrAdviser ? Number(values.commentType) : null,
135
          };
136
          handleCreateComment(jobId, newComment)
137
            .then(() => {
138
              setSubmitting(false);
139
              resetForm();
140
            })
141
            .catch(() => {
142
              setSubmitting(false);
143
            });
144
        }}
145
        render={({ isSubmitting }): React.ReactElement => (
146
          <Form data-c-grid="gutter(all, 1) middle">
147
            <Field
148
              id="comment_form_input"
149
              type="text"
150
              name="comment"
151
              component={TextAreaInput}
152
              required
153
              grid="tl(1of1)"
154
              label={intl.formatMessage(formMessages.commentLabel)}
155
              placeholder={intl.formatMessage(formMessages.commentPlaceholder)}
156
            />
157
            {locationOptions && (
158
              <Field
159
                name="commentLocation"
160
                id="comment_form_location"
161
                label={intl.formatMessage(formMessages.commentLocationLabel)}
162
                grid={locationOptions && isHrAdviser ? "tl(1of2)" : "tl(1of3)"}
163
                component={SelectInput}
164
                required
165
                nullSelection={intl.formatMessage(
166
                  formMessages.commentLocationNullSelection,
167
                )}
168
                options={locationOptions.map(({ value, label }) => ({
169
                  value,
170
                  label,
171
                }))}
172
              />
173
            )}
174
            {isHrAdviser && (
175
              <Field
176
                id="comment_form_type"
177
                name="commentType"
178
                component={SelectInput}
179
                required
180
                grid={locationOptions && isHrAdviser ? "tl(1of2)" : "tl(2of3)"}
181
                nullSelection={intl.formatMessage(
182
                  formMessages.commentTypeNullSelection,
183
                )}
184
                label={intl.formatMessage(formMessages.commentTypeLabel)}
185
                options={[
186
                  {
187
                    value: CommentTypeId.question,
188
                    label: intl.formatMessage(commentTypeMessages.question),
189
                  },
190
                  {
191
                    value: CommentTypeId.recommendation,
192
                    label: intl.formatMessage(
193
                      commentTypeMessages.recommendation,
194
                    ),
195
                  },
196
                  {
197
                    value: CommentTypeId.requiredAction,
198
                    label: intl.formatMessage(
199
                      commentTypeMessages.requiredAction,
200
                    ),
201
                  },
202
                ]}
203
              />
204
            )}
205
            <div
206
              data-c-grid-item={
207
                locationOptions && isHrAdviser ? "tl(1of1)" : "tl(1of3)"
208
              }
209
              data-c-align="base(center) tl(right)"
210
            >
211
              <button
212
                type="submit"
213
                disabled={isSubmitting}
214
                data-c-button="solid(c1)"
215
                data-c-radius="rounded"
216
              >
217
                <FormattedMessage
218
                  id="commentForm.submitButton.label"
219
                  defaultMessage="Submit Comment"
220
                  description="The text displayed on the submit button in the comment form."
221
                />
222
              </button>
223
            </div>
224
          </Form>
225
        )}
226
      />
227
    </section>
228
  );
229
};
230
231
const mapDispatchToProps = (
232
  dispatch: DispatchType,
233
): {
234
  handleCreateComment: (jobId: number, newComment: Comment) => Promise<Comment>;
235
} => ({
236
  handleCreateComment: async (
237
    jobId: number,
238
    newComment: Comment,
239
  ): Promise<Comment> => {
240
    const result = await dispatch(createComment(jobId, newComment));
241
    if (!result.error) {
242
      const resultComment = await result.payload;
243
      return resultComment;
244
    }
245
    return Promise.reject(result.payload);
246
  },
247
});
248
249
export default connect(() => ({}), mapDispatchToProps)(CommentForm);
250