Passed
Push — task/explore-skills-ui ( d41a63...af1244 )
by Yonathan
06:51 queued 10s
created

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

Complexity

Total Complexity 16
Complexity/F 0

Size

Lines of Code 217
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

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