Passed
Push — task/ci-test-actions ( c65219...22dff7 )
by Tristan
04:25 queued 13s
created

resources/assets/js/components/StrategicTalentResponse/ResponseScreening/ResponseScreeningPage.tsx   A

Complexity

Total Complexity 16
Complexity/F 0

Size

Lines of Code 218
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 16
eloc 172
c 0
b 0
f 0
dl 0
loc 218
rs 10
mnd 16
bc 16
fnc 0
bpm 0
cpm 0
noi 0
1
/* eslint camelcase: "off", @typescript-eslint/camelcase: "off" */
2
import React, { useEffect, useMemo } from "react";
3
import ReactDOM from "react-dom";
4
import { useDispatch, useSelector } from "react-redux";
5
import RootContainer from "../../RootContainer";
6
import {
7
  ResponseScreeningBuckets as BucketTypes,
8
  ResponseReviewStatusId,
9
  ExcludedDepartments,
10
} from "../../../models/lookupConstants";
11
import { ResponseScreeningBuckets } from "../../../models/localizedConstants";
12
import { getDepartments as getDepartmentsAction } from "../../../store/Department/deptActions";
13
import {
14
  Application,
15
  Department,
16
  ApplicationReview,
17
  Email,
18
} from "../../../models/types";
19
import ApplicantBucket from "./ApplicantBucket";
20
import { Portal } from "../../../models/app";
21
import {
22
  fetchApplicationsForJob,
23
  updateApplicationReview as updateApplicationReviewAction,
24
  fetchReferenceEmails,
25
  sendReferenceEmail as sendReferenceEmailAction,
26
  fetchApplication,
27
} from "../../../store/Application/applicationActions";
28
import {
29
  getApplicationsByJob,
30
  allIsFetchingReferenceEmailsByApplication,
31
  getAllReferenceEmails,
32
} from "../../../store/Application/applicationSelector";
33
import { RootState } from "../../../store/store";
34
import { getDepartments } from "../../../store/Department/deptSelector";
35
import { fakeReferenceEmail } from "../../../fakeData/fakeApplications";
36
import { hasKey } from "../../../helpers/queries";
37
38
interface ResponseScreeningPageProps {
39
  applications: Application[];
40
  departments: Department[];
41
  handleUpdateReview: (review: ApplicationReview) => Promise<ApplicationReview>;
42
  portal: Portal;
43
  referenceEmails: {
44
    director: {
45
      byApplicationId: {
46
        [applicationId: number]: Email;
47
      };
48
    };
49
    secondary: {
50
      byApplicationId: {
51
        [applicationId: number]: Email;
52
      };
53
    };
54
  };
55
  requestReferenceEmails: (applicationId: number) => void;
56
  sendReferenceEmail: (
57
    applicationId: number,
58
    referenceType: "director" | "secondary",
59
  ) => Promise<void>;
60
}
61
62
const ResponseScreeningPage: React.FC<ResponseScreeningPageProps> = ({
63
  applications,
64
  departments,
65
  handleUpdateReview,
66
  portal,
67
  referenceEmails,
68
  requestReferenceEmails,
69
  sendReferenceEmail,
70
}): React.ReactElement => (
71
  <>
72
    {Object.keys(ResponseScreeningBuckets).map((bucket) => {
73
      const bucketApplications = applications.filter((application) => {
74
        if (bucket === BucketTypes.ReadyToAllocate) {
75
          return (
76
            application.application_review?.review_status_id ===
77
            ResponseReviewStatusId.ReadyToAllocate
78
          );
79
        }
80
        if (bucket === BucketTypes.Allocated) {
81
          return (
82
            application.application_review?.review_status_id ===
83
            ResponseReviewStatusId.Allocated
84
          );
85
        }
86
        if (bucket === BucketTypes.Unavailable) {
87
          return (
88
            application.application_review?.review_status_id ===
89
            ResponseReviewStatusId.NotAvailable
90
          );
91
        }
92
        if (bucket === BucketTypes.DoesNotQualify) {
93
          return (
94
            application.application_review?.review_status_id ===
95
            ResponseReviewStatusId.ScreenedOut
96
          );
97
        }
98
        // Multiple statuses appear in the "Under Consideration" bucket
99
        return (
100
          application.application_review === undefined ||
101
          application.application_review?.review_status_id === null ||
102
          application.application_review?.review_status_id ===
103
            ResponseReviewStatusId.AssessmentRequired ||
104
          application.application_review?.review_status_id ===
105
            ResponseReviewStatusId.ReadyForReference
106
        );
107
      });
108
109
      return (
110
        <ApplicantBucket
111
          key={bucket}
112
          applications={bucketApplications}
113
          bucket={bucket}
114
          departments={departments}
115
          handleUpdateReview={handleUpdateReview}
116
          portal={portal}
117
          referenceEmails={referenceEmails}
118
          requestReferenceEmails={requestReferenceEmails}
119
          sendReferenceEmail={sendReferenceEmail}
120
        />
121
      );
122
    })}
123
  </>
124
);
125
126
interface ResponseScreeningDataFetcherProps {
127
  jobId: number;
128
  portal: Portal;
129
}
130
131
const ResponseScreeningDataFetcher: React.FC<ResponseScreeningDataFetcherProps> = ({
132
  jobId,
133
  portal,
134
}) => {
135
  const dispatch = useDispatch();
136
137
  // Load Applications for provided Job
138
  useEffect(() => {
139
    dispatch(fetchApplicationsForJob(jobId));
140
  }, [dispatch, jobId]);
141
  const applications = useSelector((state: RootState) =>
142
    getApplicationsByJob(state, { jobId }),
143
  );
144
145
  // Load all departments
146
  useEffect(() => {
147
    dispatch(getDepartmentsAction());
148
  }, [dispatch]);
149
  const departments = useSelector(getDepartments).filter(
150
    (department) =>
151
      department.id !== ExcludedDepartments.StrategicTalentResponse,
152
  );
153
154
  const updateApplicationReview = async (
155
    review: ApplicationReview,
156
  ): Promise<ApplicationReview> => {
157
    const result = await dispatch(updateApplicationReviewAction(review));
158
    if (!result.error) {
159
      const resultReview = await result.payload;
160
      return resultReview;
161
    }
162
    return Promise.reject(result.payload);
163
  };
164
165
  // Load micro-reference emails
166
  const referenceEmails = useSelector(getAllReferenceEmails);
167
  const isFetchingReferenceEmails = useSelector(
168
    allIsFetchingReferenceEmailsByApplication,
169
  );
170
  const requestReferenceEmails = (applicationId: number): void => {
171
    if (isFetchingReferenceEmails[applicationId]) {
172
      return;
173
    }
174
    if (
175
      hasKey(referenceEmails.director.byApplicationId, applicationId) &&
176
      hasKey(referenceEmails.secondary.byApplicationId, applicationId)
177
    ) {
178
      return;
179
    }
180
    dispatch(fetchReferenceEmails(applicationId));
181
  };
182
  // Sending Emails
183
  const sendReferenceEmail = async (
184
    applicationId: number,
185
    refernceType: "director" | "secondary",
186
  ): Promise<void> => {
187
    await dispatch(sendReferenceEmailAction(applicationId, refernceType));
188
    // Reload application after sending email to sync the "email_sent" fields of the ApplicationReview.
189
    return dispatch(fetchApplication(applicationId));
190
  };
191
192
  return (
193
    <ResponseScreeningPage
194
      applications={applications}
195
      departments={departments}
196
      handleUpdateReview={updateApplicationReview}
197
      portal={portal}
198
      referenceEmails={referenceEmails}
199
      requestReferenceEmails={requestReferenceEmails}
200
      sendReferenceEmail={sendReferenceEmail}
201
    />
202
  );
203
};
204
205
const container = document.getElementById("response-screening-wrapper");
206
if (container !== null) {
207
  if ("jobId" in container.dataset && "portal" in container.dataset) {
208
    const jobId = Number(container.dataset.jobId as string);
209
    const portal = container.dataset.portal as Portal;
210
    ReactDOM.render(
211
      <RootContainer>
212
        <ResponseScreeningDataFetcher jobId={jobId} portal={portal} />
213
      </RootContainer>,
214
      container,
215
    );
216
  }
217
}
218