Passed
Push — dev ( 9a8b11...b418b1 )
by
unknown
03:57
created

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

Complexity

Total Complexity 3
Complexity/F 0

Size

Lines of Code 239
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 3
eloc 186
c 0
b 0
f 0
dl 0
loc 239
rs 10
mnd 3
bc 3
fnc 0
bpm 0
cpm 0
noi 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
  buttonCopied: {
86
    id: "review.applications.button.copied",
87
    defaultMessage: "Copied!",
88
    description:
89
      "Confirmation for Button to copy all applicant emails in screening category.",
90
  },
91
  buttonCopyEmails: {
92
    id: "review.applications.button.copyEmails",
93
    defaultMessage: "Copy Emails",
94
    description: "Button to copy all applicant emails in screening category",
95
  },
96
});
97
98
const ReviewCategory: React.StatelessComponent<ReviewCategoryProps> = ({
99
  title,
100
  description,
101
  showScreenOutAll,
102
  applications,
103
  reviewStatusOptions,
104
  onStatusChange,
105
  onBulkStatusChange,
106
  onNotesChange,
107
  savingStatuses,
108
  prioritizeVeterans,
109
  portal,
110
}: ReviewCategoryProps): React.ReactElement | null => {
111
  const intl = useIntl();
112
  const [justCopied, setJustCopied] = useState(false);
113
  if (applications.length === 0) {
114
    return null;
115
  }
116
117
  const screenOutAll = (): void => {
118
    const applicationIds = applications.map((application) => application.id);
119
    onBulkStatusChange(applicationIds, ReviewStatusId.ScreenedOut);
120
  };
121
122
  const handleScreenOutAllClick = (): void => {
123
    Swal.fire({
124
      title: intl.formatMessage(messages.screenOutAllConfirm),
125
      icon: "question",
126
      showCancelButton: true,
127
      confirmButtonColor: "#0A6CBC",
128
      cancelButtonColor: "#F94D4D",
129
      confirmButtonText: intl.formatMessage(messages.confirmButton),
130
    }).then((result: SweetAlertResult) => {
131
      if (result.value) {
132
        screenOutAll();
133
      }
134
    });
135
  };
136
137
  const buckets = [
138
    {
139
      id: messages.priorityApplicantsTitle.id,
140
      title: intl.formatMessage(messages.priorityApplicantsTitle),
141
      description: intl.formatMessage(messages.priorityApplicantsDescription),
142
      applications: applications.filter(
143
        (application) => applicationBucket(application) === "priority",
144
      ),
145
    },
146
    {
147
      id: messages.veteransAndCitizensTitle.id,
148
      title: intl.formatMessage(messages.veteransAndCitizensTitle),
149
      description: intl.formatMessage(messages.veteransAndCitizensDescriptions),
150
      applications: applications.filter(
151
        (application) => applicationBucket(application) === "citizen",
152
      ),
153
    },
154
    {
155
      id: messages.nonCitizensTitle.id,
156
      title: intl.formatMessage(messages.nonCitizensTitle),
157
      description: intl.formatMessage(messages.nonCitizensDescription),
158
      applications: applications.filter(
159
        (application) => applicationBucket(application) === "non-citizen",
160
      ),
161
    },
162
    {
163
      id: messages.unqualifiedTitle.id,
164
      title: intl.formatMessage(messages.unqualifiedTitle),
165
      description: intl.formatMessage(messages.unqualifiedDescription),
166
      applications: applications.filter(
167
        (application) => applicationBucket(application) === "unqualified",
168
      ),
169
    },
170
  ];
171
172
  /* Code related to copying emails to clipboard */
173
  const nameEmails = applications.map((application) => {
174
    const { first_name, last_name, email } = application.applicant.user; // eslint-disable-line
175
    return `${first_name} ${last_name} <${email}>`; // eslint-disable-line
176
  });
177
  const emailList = nameEmails.join(",");
178
  const handleCopyClick = (event): void => {
179
    copyToClipboard(event, emailList).then(() => {
180
      setJustCopied(true);
181
      setTimeout(() => setJustCopied(false), 2000);
182
    });
183
  };
184
185
  return (
186
    <div className="applicant-category">
187
      <h2 className="heading--03">{title}</h2>
188
189
      <p>{description}</p>
190
191
      <div className="flex-grid middle category-actions">
192
        <div className="box med-1of2">
193
          <button
194
            className="button--outline"
195
            type="button"
196
            onClick={handleCopyClick}
197
          >
198
            {justCopied
199
              ? intl.formatMessage(messages.buttonCopied)
200
              : intl.formatMessage(messages.buttonCopyEmails)}
201
          </button>
202
        </div>
203
        <div className="box med-1of2">
204
          {showScreenOutAll && (
205
            <button
206
              className="button--outline"
207
              type="button"
208
              onClick={handleScreenOutAllClick}
209
            >
210
              <i className="fas fa-ban" />
211
              &nbsp;
212
              <FormattedMessage
213
                id="review.applications.screenOutAll"
214
                defaultMessage="Screen All Optional Candidates Out"
215
                description="Button to screen out all optional candidates from competition with one click"
216
              />
217
            </button>
218
          )}
219
        </div>
220
      </div>
221
222
      {buckets.map((bucket) => (
223
        <ApplicantBucket
224
          key={bucket.id}
225
          {...bucket}
226
          reviewStatusOptions={reviewStatusOptions}
227
          onStatusChange={onStatusChange}
228
          onNotesChange={onNotesChange}
229
          savingStatuses={savingStatuses}
230
          prioritizeVeterans={prioritizeVeterans}
231
          portal={portal}
232
        />
233
      ))}
234
    </div>
235
  );
236
};
237
238
export default ReviewCategory;
239