Passed
Push — feature/application-fit-functi... ( 2528fc )
by Yonathan
09:03
created

resources/assets/js/components/ApplicationReview/ReviewCategory.tsx   A

Complexity

Total Complexity 3
Complexity/F 0

Size

Lines of Code 238
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 3
eloc 184
mnd 3
bc 3
fnc 0
dl 0
loc 238
rs 10
bpm 0
cpm 0
noi 0
c 0
b 0
f 0
1
import React, { useState } from "react";
2
import { FormattedMessage, defineMessages, useIntl } from "react-intl";
3
import Swal, { SweetAlertResult } from "sweetalert2";
4
import { Application } from "../../models/types";
5
import { SelectOption } from "../Select";
6
import { applicationBucket } from "./helpers";
7
import ApplicantBucket from "./ApplicantBucket";
8
import { ReviewStatusId } from "../../models/lookupConstants";
9
import { copyToClipboard } from "../../helpers/clipboard";
10
import { Portal } from "../../models/app";
11
12
interface ReviewCategoryProps {
13
  title: string;
14
  description: string;
15
  showScreenOutAll: boolean;
16
  applications: Application[];
17
  reviewStatusOptions: SelectOption[];
18
  onStatusChange: (applicationId: number, statusId: number | null) => void;
19
  onBulkStatusChange: (
20
    applicationIds: number[],
21
    statusId: number | null,
22
  ) => void;
23
  onNotesChange: (applicationId: number, notes: string | null) => void;
24
  savingStatuses: { applicationId: number; isSaving: boolean }[];
25
  prioritizeVeterans: boolean;
26
  portal: Portal;
27
}
28
29
const messages = defineMessages({
30
  priorityApplicantsTitle: {
31
    id: "review.applications.priorityApplicants.title",
32
    defaultMessage: "Priority Applicants",
33
    description: "title of list of priority applicants",
34
  },
35
  priorityApplicantsDescription: {
36
    id: "review.applications.priorityApplicants.description",
37
    defaultMessage:
38
      "These are priority applicants for this position. They must be reviewed and considered first.",
39
    description: "description of list of priority applicants",
40
  },
41
  veteransAndCitizensTitle: {
42
    id: "review.applications.veteransAndCitizens.title",
43
    defaultMessage: "Veterans and Canadian Citizens",
44
    description: "title of list of Veterans and Canadian citizens",
45
  },
46
  veteransAndCitizensDescriptions: {
47
    id: "review.applications.veteransAndCitizens.description",
48
    defaultMessage: " ",
49
    description: "description of list of Veterans and Canadian citizens",
50
  },
51
  nonCitizensTitle: {
52
    id: "review.applications.nonCitizens.title",
53
    defaultMessage: "Non-Canadian Citizens",
54
    description: "title of list of non-citizen applicants",
55
  },
56
  nonCitizensDescription: {
57
    id: "review.applications.nonCitizens.description",
58
    defaultMessage: " ",
59
    description: "description of list of non-citizen applicants",
60
  },
61
  unqualifiedTitle: {
62
    id: "review.applications.unqualified.title",
63
    defaultMessage: "Don't Meet Essential Criteria",
64
    description:
65
      "title of list of applicants who do not meet the essential criteria",
66
  },
67
  unqualifiedDescription: {
68
    id: "review.applications.unqualified.description",
69
    defaultMessage: " ",
70
    description:
71
      "description of list of applicants who do not meet the essential criteria",
72
  },
73
  confirmButton: {
74
    id: "review.applications.button.confirm",
75
    defaultMessage: "Confirm",
76
    description: "Confirm button for modal dialogue boxes",
77
  },
78
  screenOutAllConfirm: {
79
    id: "review.applications.screenOutAll.confirm",
80
    defaultMessage:
81
      "Are you sure you want to screen out all Optional candidates?",
82
    description:
83
      "Confirm dialogue text for screening out all optional candidates.",
84
  },
85
});
86
87
const ReviewCategory: React.StatelessComponent<ReviewCategoryProps> = ({
88
  title,
89
  description,
90
  showScreenOutAll,
91
  applications,
92
  reviewStatusOptions,
93
  onStatusChange,
94
  onBulkStatusChange,
95
  onNotesChange,
96
  savingStatuses,
97
  prioritizeVeterans,
98
  portal,
99
}: ReviewCategoryProps): React.ReactElement | null => {
100
  const intl = useIntl();
101
  const [justCopied, setJustCopied] = useState(false);
102
  if (applications.length === 0) {
103
    return null;
104
  }
105
106
  const screenOutAll = (): void => {
107
    const applicationIds = applications.map((application) => application.id);
108
    onBulkStatusChange(applicationIds, ReviewStatusId.ScreenedOut);
109
  };
110
111
  const handleScreenOutAllClick = (): void => {
112
    Swal.fire({
113
      title: intl.formatMessage(messages.screenOutAllConfirm),
114
      icon: "question",
115
      showCancelButton: true,
116
      confirmButtonColor: "#0A6CBC",
117
      cancelButtonColor: "#F94D4D",
118
      confirmButtonText: intl.formatMessage(messages.confirmButton),
119
    }).then((result: SweetAlertResult) => {
120
      if (result.value) {
121
        screenOutAll();
122
      }
123
    });
124
  };
125
126
  const buckets = [
127
    {
128
      id: messages.priorityApplicantsTitle.id,
129
      title: intl.formatMessage(messages.priorityApplicantsTitle),
130
      description: intl.formatMessage(messages.priorityApplicantsDescription),
131
      applications: applications.filter(
132
        (application) => applicationBucket(application) === "priority",
133
      ),
134
    },
135
    {
136
      id: messages.veteransAndCitizensTitle.id,
137
      title: intl.formatMessage(messages.veteransAndCitizensTitle),
138
      description: intl.formatMessage(messages.veteransAndCitizensDescriptions),
139
      applications: applications.filter(
140
        (application) => applicationBucket(application) === "citizen",
141
      ),
142
    },
143
    {
144
      id: messages.nonCitizensTitle.id,
145
      title: intl.formatMessage(messages.nonCitizensTitle),
146
      description: intl.formatMessage(messages.nonCitizensDescription),
147
      applications: applications.filter(
148
        (application) => applicationBucket(application) === "non-citizen",
149
      ),
150
    },
151
    {
152
      id: messages.unqualifiedTitle.id,
153
      title: intl.formatMessage(messages.unqualifiedTitle),
154
      description: intl.formatMessage(messages.unqualifiedDescription),
155
      applications: applications.filter(
156
        (application) => applicationBucket(application) === "unqualified",
157
      ),
158
    },
159
  ];
160
161
  /* Code related to copying emails to clipboard */
162
  const nameEmails = applications.map((application) => {
163
    const { first_name, last_name, email } = application.applicant.user; // eslint-disable-line
164
    return `${first_name} ${last_name} <${email}>`; // eslint-disable-line
165
  });
166
  const emailList = nameEmails.join(",");
167
  const handleCopyClick = (event): void => {
168
    copyToClipboard(event, emailList).then(() => {
169
      setJustCopied(true);
170
      setTimeout(() => setJustCopied(false), 2000);
171
    });
172
  };
173
174
  return (
175
    <div className="applicant-category">
176
      <h2 className="heading--03">{title}</h2>
177
178
      <p>{description}</p>
179
180
      <div className="flex-grid middle category-actions">
181
        <div className="box med-1of2">
182
          <button
183
            className="button--outline"
184
            type="button"
185
            onClick={handleCopyClick}
186
          >
187
            {justCopied ? (
188
              <FormattedMessage
189
                id="button.copied"
190
                defaultMessage="Copied!"
191
                description="Confirmation for Button to copy all applicant emails in screening category"
192
              />
193
            ) : (
194
              <FormattedMessage
195
                id="button.copyEmails"
196
                defaultMessage="Copy Emails"
197
                description="Button to copy all applicant emails in screening category"
198
              />
199
            )}
200
          </button>
201
        </div>
202
        <div className="box med-1of2">
203
          {showScreenOutAll && (
204
            <button
205
              className="button--outline"
206
              type="button"
207
              onClick={handleScreenOutAllClick}
208
            >
209
              <i className="fas fa-ban" />
210
              &nbsp;
211
              <FormattedMessage
212
                id="review.applications.screenOutAll"
213
                defaultMessage="Screen All Optional Candidates Out"
214
                description="Button to screen out all optional candidates from competition with one click"
215
              />
216
            </button>
217
          )}
218
        </div>
219
      </div>
220
221
      {buckets.map((bucket) => (
222
        <ApplicantBucket
223
          key={bucket.id}
224
          {...bucket}
225
          reviewStatusOptions={reviewStatusOptions}
226
          onStatusChange={onStatusChange}
227
          onNotesChange={onNotesChange}
228
          savingStatuses={savingStatuses}
229
          prioritizeVeterans={prioritizeVeterans}
230
          portal={portal}
231
        />
232
      ))}
233
    </div>
234
  );
235
};
236
237
export default ReviewCategory;
238