Passed
Push — task/refactor-application-data... ( 64ba97 )
by Tristan
06:26
created

applicationHooks.tsx ➔ useFetchSkills   A

Complexity

Conditions 2

Size

Total Lines 10
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 9
dl 0
loc 10
rs 9.95
c 0
b 0
f 0
cc 2
1
/* eslint-disable camelcase */
2
import { useCallback, useEffect, useState } from "react";
3
import { useSelector } from "react-redux";
4
import { DispatchType } from "../../configureStore";
5
import { RootState } from "../../store/store";
6
import { getAwardRecipientTypes as fetchAwardRecipientTypes } from "../../store/AwardRecipientType/awardRecipientTypeActions";
7
import { getAwardRecipientTypes } from "../../store/AwardRecipientType/awardRecipientTypeSelector";
8
import { getAwardRecognitionTypes as fetchAwardRecognitionTypes } from "../../store/AwardRecognitionType/awardRecognitionTypeActions";
9
import { getAwardRecognitionTypes } from "../../store/AwardRecognitionType/awardRecognitionTypeSelector";
10
import { getEducationTypes as fetchEducationTypes } from "../../store/EducationType/educationTypeActions";
11
import { getEducationTypes } from "../../store/EducationType/educationTypeSelector";
12
import { getEducationStatuses as fetchEducationStatuses } from "../../store/EducationStatus/educationStatusActions";
13
import { getEducationStatuses } from "../../store/EducationStatus/educationStatusSelector";
14
import {
15
  AwardRecipientType,
16
  AwardRecognitionType,
17
  EducationType,
18
  EducationStatus,
19
  Application,
20
  Job,
21
  Experience as ExperienceType,, Skill, ExperienceSkill
22
} from "../../models/types";
23
import { RSAActionTemplate } from "../../store/asyncAction";
24
import {
25
  getApplicationById,
26
  getApplicationIsUpdating,
27
} from "../../store/Application/applicationSelector";
28
import { fetchApplication } from "../../store/Application/applicationActions";
29
import { getJob, getJobIsUpdating } from "../../store/Job/jobSelector";
30
import { fetchJob } from "../../store/Job/jobActions";
31
import { ApplicationStatusId } from "../../models/lookupConstants";
32
import {
33
  getExperienceByApplicant,
34
  getExperienceByApplication,
35
  getExperienceSkillsByApplicant,
36
  getExperienceSkillsByApplication,
37
  getUpdatingByApplicant,
38
  getUpdatingByApplication,
39
} from "../../store/Experience/experienceSelector";
40
import {
41
  fetchExperienceByApplicant,
42
  fetchExperienceByApplication,
43
} from "../../store/Experience/experienceActions";
44
import { getSkills, getSkillsUpdating } from "../../store/Skill/skillSelector";
45
import { fetchSkills } from "../../store/Skill/skillActions";
46
47
export function useFetchSkills(dispatch: DispatchType): Skill[] {
48
  const skills = useSelector(getSkills);
49
  const skillsUpdating = useSelector(getSkillsUpdating);
50
  useEffect(() => {
51
    if (skills.length === 0 && !skillsUpdating) {
52
      dispatch(fetchSkills());
53
    }
54
  }, [skills.length, skillsUpdating, dispatch]);
55
  return skills;
56
}
57
58
export function useFetchExperienceConstants(
59
  dispatch: DispatchType,
60
): {
61
  awardRecipientTypes: AwardRecipientType[];
62
  awardRecognitionTypes: AwardRecognitionType[];
63
  educationTypes: EducationType[];
64
  educationStatuses: EducationStatus[];
65
} {
66
  const awardRecipientTypes = useSelector(getAwardRecipientTypes);
67
  const awardRecipientTypesLoading = useSelector(
68
    (state: RootState) => state.awardRecipientType.loading,
69
  );
70
  useEffect(() => {
71
    if (awardRecipientTypes.length === 0 && !awardRecipientTypesLoading) {
72
      dispatch(fetchAwardRecipientTypes());
73
    }
74
  }, [awardRecipientTypes, awardRecipientTypesLoading, dispatch]);
75
76
  const awardRecognitionTypes = useSelector(getAwardRecognitionTypes);
77
  const awardRecognitionTypesLoading = useSelector(
78
    (state: RootState) => state.awardRecognitionType.loading,
79
  );
80
  useEffect(() => {
81
    if (awardRecognitionTypes.length === 0 && !awardRecognitionTypesLoading) {
82
      dispatch(fetchAwardRecognitionTypes());
83
    }
84
  }, [awardRecognitionTypes, awardRecognitionTypesLoading, dispatch]);
85
86
  const educationTypes = useSelector(getEducationTypes);
87
  const educationTypesLoading = useSelector(
88
    (state: RootState) => state.educationType.loading,
89
  );
90
  useEffect(() => {
91
    if (educationTypes.length === 0 && !educationTypesLoading) {
92
      dispatch(fetchEducationTypes());
93
    }
94
  }, [educationTypes, educationTypesLoading, dispatch]);
95
96
  const educationStatuses = useSelector(getEducationStatuses);
97
  const educationStatusesLoading = useSelector(
98
    (state: RootState) => state.educationStatus.loading,
99
  );
100
  useEffect(() => {
101
    if (educationStatuses.length === 0 && !educationStatusesLoading) {
102
      dispatch(fetchEducationStatuses());
103
    }
104
  }, [educationStatuses, educationStatusesLoading, dispatch]);
105
106
  return {
107
    awardRecipientTypes,
108
    awardRecognitionTypes,
109
    educationTypes,
110
    educationStatuses,
111
  };
112
}
113
114
export function useFetchApplication(
115
  applicationId: number,
116
  dispatch: DispatchType,
117
): Application | null {
118
  const applicationSelector = (state: RootState) =>
119
    getApplicationById(state, { id: applicationId });
120
  const application = useSelector(applicationSelector);
121
  const applicationIsUpdating = useSelector((state: RootState) =>
122
    getApplicationIsUpdating(state, { applicationId }),
123
  );
124
  useEffect(() => {
125
    if (application === null && !applicationIsUpdating) {
126
      dispatch(fetchApplication(applicationId));
127
    }
128
  }, [application, applicationId, applicationIsUpdating, dispatch]);
129
  return application;
130
}
131
132
export function useFetchJob(
133
  jobId: number | undefined,
134
  dispatch: DispatchType,
135
): Job | null {
136
  const jobSelector = (state: RootState) =>
137
    jobId ? getJob(state, { jobId }) : null;
138
  const job = useSelector(jobSelector);
139
  const jobUpdatingSelector = (state: RootState) =>
140
    jobId ? getJobIsUpdating(state, jobId) : false;
141
  const jobIsUpdating = useSelector(jobUpdatingSelector);
142
  useEffect(() => {
143
    // If job is null and not already updating, fetch it.
144
    if (jobId && job === null && !jobIsUpdating) {
145
      dispatch(fetchJob(jobId));
146
    }
147
  }, [jobId, job, jobIsUpdating, dispatch]);
148
  return job;
149
}
150
151
export function useFetchExperience(
152
  applicationId: number,
153
  application: Application | null,
154
  dispatch: DispatchType,
155
): {
156
  experiences: ExperienceType[];
157
  experiencesUpdating: boolean;
158
  experiencesFetched: boolean;
159
} {
160
  const applicantId = application?.applicant_id ?? 0;
161
162
  // When an Application is still a draft, use Experiences associated with the applicant profile.
163
  // When an Application has been submitted and is no longer a draft, display Experience associated with the Application directly.
164
  const applicationLoaded = application !== null;
165
  const useProfileExperience =
166
    application === null ||
167
    application.application_status_id === ApplicationStatusId.draft;
168
169
  // This selector must be memoized because getExperienceByApplicant/Application uses reselect, and not re-reselect, so it needs to preserve its state.
170
  const experienceSelector = useCallback(
171
    (state: RootState) =>
172
      useProfileExperience
173
        ? getExperienceByApplicant(state, { applicantId })
174
        : getExperienceByApplication(state, { applicationId }),
175
    [applicationId, applicantId, useProfileExperience],
176
  );
177
  const experiencesByType = useSelector(experienceSelector);
178
  const experiences: ExperienceType[] = [
179
    ...experiencesByType.award,
180
    ...experiencesByType.community,
181
    ...experiencesByType.education,
182
    ...experiencesByType.personal,
183
    ...experiencesByType.work,
184
  ];
185
  const experiencesUpdating = useSelector((state: RootState) =>
186
    useProfileExperience
187
      ? getUpdatingByApplicant(state, { applicantId })
188
      : getUpdatingByApplication(state, { applicationId }),
189
  );
190
  const [experiencesFetched, setExperiencesFetched] = useState(false);
191
  useEffect(() => {
192
    // Only load experiences if they have never been fetched by this component (!experiencesFetched),
193
    //  have never been fetched by another component (length === 0),
194
    //  and are not currently being fetched (!experiencesUpdating).
195
    // Also, wait until application has been loaded so the correct source can be determined.
196
    if (
197
      applicationLoaded &&
198
      !experiencesFetched &&
199
      !experiencesUpdating &&
200
      experiences.length === 0
201
    ) {
202
      setExperiencesFetched(true);
203
      if (useProfileExperience) {
204
        dispatch(fetchExperienceByApplicant(applicantId));
205
      } else {
206
        dispatch(fetchExperienceByApplication(applicationId));
207
      }
208
    }
209
  }, [
210
    applicantId,
211
    applicationId,
212
    applicationLoaded,
213
    dispatch,
214
    experiences.length,
215
    experiencesFetched,
216
    experiencesUpdating,
217
    useProfileExperience,
218
  ]);
219
  return {
220
    experiences,
221
    experiencesUpdating,
222
    experiencesFetched,
223
  };
224
}
225
226
/**
227
 * Unlike most other hooks in this file, this will never trigger any fetches.
228
 * It is assumed experience skills will be fetched when Experiences are.
229
 */
230
export function useExperienceSkills(applicationId: number, application: Application|null): ExperienceSkill[] {
231
  // ExperienceSkills don't need to be fetched because they are returned in the Experiences API calls.
232
  const applicantId = application?.applicant_id ?? 0;
233
  const useProfileExperience =
234
    application === null ||
235
    application.application_status_id === ApplicationStatusId.draft;
236
  const expSkillSelector = (state: RootState) =>
237
    useProfileExperience
238
      ? getExperienceSkillsByApplicant(state, { applicantId })
239
      : getExperienceSkillsByApplication(state, { applicationId });
240
  const experienceSkills = useSelector(expSkillSelector);
241
  return experienceSkills;
242
}
243