1
|
|
|
/* eslint-disable camelcase */ |
2
|
|
|
/* eslint-disable @typescript-eslint/camelcase */ |
3
|
|
|
import * as React from "react"; |
4
|
|
|
import { FormattedMessage, useIntl, IntlShape } from "react-intl"; |
5
|
|
|
import { |
6
|
|
|
Skill, |
7
|
|
|
ExperienceEducation, |
8
|
|
|
ExperienceWork, |
9
|
|
|
ExperienceCommunity, |
10
|
|
|
Experience, |
11
|
|
|
ExperiencePersonal, |
12
|
|
|
ExperienceAward, |
13
|
|
|
ExperienceSkill, |
14
|
|
|
Criteria, |
15
|
|
|
} from "../../../models/types"; |
16
|
|
|
import { localizeFieldNonNull, getLocale } from "../../../helpers/localize"; |
17
|
|
|
import { |
18
|
|
|
SkillTypeId, |
19
|
|
|
CriteriaTypeId, |
20
|
|
|
getKeyByValue, |
21
|
|
|
ClassificationId, |
22
|
|
|
//ClassificationId, |
23
|
|
|
} from "../../../models/lookupConstants"; |
24
|
|
|
import EducationExperienceModal, { |
25
|
|
|
messages as educationMessages, |
26
|
|
|
EducationType, |
27
|
|
|
EducationStatus, |
28
|
|
|
EducationExperienceSubmitData, |
29
|
|
|
} from "../ExperienceModals/EducationExperienceModal"; |
30
|
|
|
|
31
|
|
|
import WorkExperienceModal, { |
32
|
|
|
messages as workMessages, |
33
|
|
|
WorkExperienceSubmitData, |
34
|
|
|
} from "../ExperienceModals/WorkExperienceModal"; |
35
|
|
|
import CommunityExperienceModal, { |
36
|
|
|
messages as communityMessages, |
37
|
|
|
CommunityExperienceSubmitData, |
38
|
|
|
} from "../ExperienceModals/CommunityExperienceModal"; |
39
|
|
|
import PersonalExperienceModal, { |
40
|
|
|
messages as personalMessages, |
41
|
|
|
PersonalExperienceSubmitData, |
42
|
|
|
} from "../ExperienceModals/PersonalExperienceModal"; |
43
|
|
|
import AwardExperienceModal, { |
44
|
|
|
messages as awardMessages, |
45
|
|
|
AwardRecipientType, |
46
|
|
|
AwardRecognitionType, |
47
|
|
|
AwardExperienceSubmitData, |
48
|
|
|
} from "../ExperienceModals/AwardExperienceModal"; |
49
|
|
|
import { ExperienceEducationAccordion } from "../ExperienceAccordions/ExperienceEducationAccordion"; |
50
|
|
|
import { ExperienceWorkAccordion } from "../ExperienceAccordions/ExperienceWorkAccordion"; |
51
|
|
|
import { ExperienceCommunityAccordion } from "../ExperienceAccordions/ExperienceCommunityAccordion"; |
52
|
|
|
import { ExperiencePersonalAccordion } from "../ExperienceAccordions/ExperiencePersonalAccordion"; |
53
|
|
|
import { ExperienceAwardAccordion } from "../ExperienceAccordions/ExperienceAwardAccordion"; |
54
|
|
|
import { |
55
|
|
|
getSkillOfCriteria, |
56
|
|
|
getSkillsOfExperience, |
57
|
|
|
getDisconnectedRequiredSkills, |
58
|
|
|
} from "../helpers"; |
59
|
|
|
import { navigationMessages, experienceMessages } from "../applicationMessages"; |
60
|
|
|
import { notEmpty, removeDuplicatesById } from "../../../helpers/queries"; |
61
|
|
|
import { useSelector } from "react-redux"; |
62
|
|
|
import { RootState } from "../../../store/store"; |
63
|
|
|
|
64
|
|
|
export function modalButtonProps( |
65
|
|
|
intl: IntlShape, |
66
|
|
|
): { [key: string]: { id: Experience["type"]; title: string; icon: string } } { |
67
|
|
|
return { |
68
|
|
|
education: { |
69
|
|
|
id: "experience_education", |
70
|
|
|
title: intl.formatMessage(educationMessages.modalTitle), |
71
|
|
|
icon: "fas fa-book", |
72
|
|
|
}, |
73
|
|
|
work: { |
74
|
|
|
id: "experience_work", |
75
|
|
|
title: intl.formatMessage(workMessages.modalTitle), |
76
|
|
|
icon: "fas fa-briefcase", |
77
|
|
|
}, |
78
|
|
|
community: { |
79
|
|
|
id: "experience_community", |
80
|
|
|
title: intl.formatMessage(communityMessages.modalTitle), |
81
|
|
|
icon: "fas fa-people-carry", |
82
|
|
|
}, |
83
|
|
|
personal: { |
84
|
|
|
id: "experience_personal", |
85
|
|
|
title: intl.formatMessage(personalMessages.modalTitle), |
86
|
|
|
icon: "fas fa-mountain", |
87
|
|
|
}, |
88
|
|
|
award: { |
89
|
|
|
id: "experience_award", |
90
|
|
|
title: intl.formatMessage(awardMessages.modalTitle), |
91
|
|
|
icon: "fas fa-trophy", |
92
|
|
|
}, |
93
|
|
|
}; |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
export const ModalButton: React.FunctionComponent<{ |
97
|
|
|
id: Experience["type"]; |
98
|
|
|
title: string; |
99
|
|
|
icon: string; |
100
|
|
|
openModal: (id: Experience["type"]) => void; |
101
|
|
|
}> = ({ id, title, icon, openModal }) => { |
102
|
|
|
return ( |
103
|
|
|
<div key={id} data-c-grid-item="base(1of2) tp(1of3) tl(1of5)"> |
104
|
|
|
<button |
105
|
|
|
className="application-experience-trigger" |
106
|
|
|
data-c-card |
107
|
|
|
data-c-background="c1(100)" |
108
|
|
|
data-c-radius="rounded" |
109
|
|
|
title={title} |
110
|
|
|
data-c-dialog-id={id} |
111
|
|
|
data-c-dialog-action="open" |
112
|
|
|
type="button" |
113
|
|
|
onClick={(): void => openModal(id)} |
114
|
|
|
> |
115
|
|
|
<i className={icon} aria-hidden="true" /> |
116
|
|
|
<span data-c-font-size="regular" data-c-font-weight="bold"> |
117
|
|
|
{title} |
118
|
|
|
</span> |
119
|
|
|
</button> |
120
|
|
|
</div> |
121
|
|
|
); |
122
|
|
|
}; |
123
|
|
|
|
124
|
|
|
const applicationExperienceAccordion = ( |
125
|
|
|
experience: Experience, |
126
|
|
|
irrelevantSkillCount: number, |
127
|
|
|
relevantSkills: ExperienceSkill[], |
128
|
|
|
skills: Skill[], |
129
|
|
|
handleEdit: () => void, |
130
|
|
|
handleDelete: () => Promise<void>, |
131
|
|
|
): React.ReactElement | null => { |
132
|
|
|
switch (experience.type) { |
133
|
|
|
case "experience_education": |
134
|
|
|
return ( |
135
|
|
|
<ExperienceEducationAccordion |
136
|
|
|
key={`${experience.id}-${experience.type}`} |
137
|
|
|
experience={experience} |
138
|
|
|
handleDelete={handleDelete} |
139
|
|
|
handleEdit={handleEdit} |
140
|
|
|
irrelevantSkillCount={irrelevantSkillCount} |
141
|
|
|
relevantSkills={relevantSkills} |
142
|
|
|
skills={skills} |
143
|
|
|
showButtons |
144
|
|
|
showSkillDetails |
145
|
|
|
/> |
146
|
|
|
); |
147
|
|
|
case "experience_work": |
148
|
|
|
return ( |
149
|
|
|
<ExperienceWorkAccordion |
150
|
|
|
key={`${experience.id}-${experience.type}`} |
151
|
|
|
experience={experience} |
152
|
|
|
handleDelete={handleDelete} |
153
|
|
|
handleEdit={handleEdit} |
154
|
|
|
irrelevantSkillCount={irrelevantSkillCount} |
155
|
|
|
relevantSkills={relevantSkills} |
156
|
|
|
skills={skills} |
157
|
|
|
showButtons |
158
|
|
|
showSkillDetails |
159
|
|
|
/> |
160
|
|
|
); |
161
|
|
|
case "experience_community": |
162
|
|
|
return ( |
163
|
|
|
<ExperienceCommunityAccordion |
164
|
|
|
key={`${experience.id}-${experience.type}`} |
165
|
|
|
experience={experience} |
166
|
|
|
handleDelete={handleDelete} |
167
|
|
|
handleEdit={handleEdit} |
168
|
|
|
irrelevantSkillCount={irrelevantSkillCount} |
169
|
|
|
relevantSkills={relevantSkills} |
170
|
|
|
skills={skills} |
171
|
|
|
showButtons |
172
|
|
|
showSkillDetails |
173
|
|
|
/> |
174
|
|
|
); |
175
|
|
|
case "experience_personal": |
176
|
|
|
return ( |
177
|
|
|
<ExperiencePersonalAccordion |
178
|
|
|
key={`${experience.id}-${experience.type}`} |
179
|
|
|
experience={experience} |
180
|
|
|
handleEdit={handleEdit} |
181
|
|
|
handleDelete={handleDelete} |
182
|
|
|
irrelevantSkillCount={irrelevantSkillCount} |
183
|
|
|
relevantSkills={relevantSkills} |
184
|
|
|
skills={skills} |
185
|
|
|
showButtons |
186
|
|
|
showSkillDetails |
187
|
|
|
/> |
188
|
|
|
); |
189
|
|
|
case "experience_award": |
190
|
|
|
return ( |
191
|
|
|
<ExperienceAwardAccordion |
192
|
|
|
key={`${experience.id}-${experience.type}`} |
193
|
|
|
experience={experience} |
194
|
|
|
handleDelete={handleDelete} |
195
|
|
|
handleEdit={handleEdit} |
196
|
|
|
irrelevantSkillCount={irrelevantSkillCount} |
197
|
|
|
relevantSkills={relevantSkills} |
198
|
|
|
skills={skills} |
199
|
|
|
showButtons |
200
|
|
|
showSkillDetails |
201
|
|
|
/> |
202
|
|
|
); |
203
|
|
|
default: |
204
|
|
|
return null; |
205
|
|
|
} |
206
|
|
|
}; |
207
|
|
|
|
208
|
|
|
export type ExperienceSubmitData = |
209
|
|
|
| EducationExperienceSubmitData |
210
|
|
|
| WorkExperienceSubmitData |
211
|
|
|
| CommunityExperienceSubmitData |
212
|
|
|
| PersonalExperienceSubmitData |
213
|
|
|
| AwardExperienceSubmitData; |
214
|
|
|
|
215
|
|
|
interface ExperienceProps { |
216
|
|
|
experiences: Experience[]; |
217
|
|
|
educationStatuses: EducationStatus[]; |
218
|
|
|
educationTypes: EducationType[]; |
219
|
|
|
experienceSkills: ExperienceSkill[]; |
220
|
|
|
criteria: Criteria[]; |
221
|
|
|
skills: Skill[]; |
222
|
|
|
jobId: number; |
223
|
|
|
jobClassificationId: number | null; |
224
|
|
|
jobEducationRequirements: string | null; |
225
|
|
|
recipientTypes: AwardRecipientType[]; |
226
|
|
|
recognitionTypes: AwardRecognitionType[]; |
227
|
|
|
handleDeleteExperience: ( |
228
|
|
|
id: number, |
229
|
|
|
type: Experience["type"], |
230
|
|
|
) => Promise<void>; |
231
|
|
|
handleSubmitExperience: (data: ExperienceSubmitData) => Promise<void>; |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
export const MyExperience: React.FunctionComponent<ExperienceProps> = ({ |
235
|
|
|
experiences, |
236
|
|
|
educationStatuses, |
237
|
|
|
educationTypes, |
238
|
|
|
experienceSkills, |
239
|
|
|
criteria, |
240
|
|
|
skills, |
241
|
|
|
handleSubmitExperience, |
242
|
|
|
handleDeleteExperience, |
243
|
|
|
jobId, |
244
|
|
|
jobClassificationId, |
245
|
|
|
jobEducationRequirements, |
246
|
|
|
recipientTypes, |
247
|
|
|
recognitionTypes, |
248
|
|
|
}) => { |
249
|
|
|
const intl = useIntl(); |
250
|
|
|
const locale = getLocale(intl.locale); |
251
|
|
|
|
252
|
|
|
const jobClassification = |
253
|
|
|
jobClassificationId !== null |
254
|
|
|
? getKeyByValue(ClassificationId, jobClassificationId) |
255
|
|
|
: ""; |
256
|
|
|
|
257
|
|
|
const [experienceData, setExperienceData] = React.useState< |
258
|
|
|
| (Experience & { |
259
|
|
|
savedOptionalSkills: Skill[]; |
260
|
|
|
savedRequiredSkills: Skill[]; |
261
|
|
|
}) |
262
|
|
|
| null |
263
|
|
|
>(null); |
264
|
|
|
|
265
|
|
|
const [isModalVisible, setIsModalVisible] = React.useState<{ |
266
|
|
|
id: Experience["type"] | ""; |
267
|
|
|
visible: boolean; |
268
|
|
|
}>({ |
269
|
|
|
id: "", |
270
|
|
|
visible: false, |
271
|
|
|
}); |
272
|
|
|
|
273
|
|
|
const filteredSkills = criteria.reduce( |
274
|
|
|
(result, criterion): { essential: Skill[]; asset: Skill[] } => { |
275
|
|
|
const skillOfCriterion = getSkillOfCriteria(criterion, skills); |
276
|
|
|
if (skillOfCriterion) { |
277
|
|
|
if (criterion.criteria_type_id === CriteriaTypeId.Essential) { |
278
|
|
|
result.essential.push(skillOfCriterion); |
279
|
|
|
} |
280
|
|
|
if (criterion.criteria_type_id === CriteriaTypeId.Asset) { |
281
|
|
|
result.asset.push(skillOfCriterion); |
282
|
|
|
} |
283
|
|
|
} |
284
|
|
|
return result; |
285
|
|
|
}, |
286
|
|
|
{ essential: [], asset: [] } as { essential: Skill[]; asset: Skill[] }, |
287
|
|
|
); |
288
|
|
|
|
289
|
|
|
const essentialSkills = removeDuplicatesById(filteredSkills.essential); |
290
|
|
|
const assetSkills = removeDuplicatesById(filteredSkills.asset); |
291
|
|
|
|
292
|
|
|
const disconnectedRequiredSkills = getDisconnectedRequiredSkills( |
293
|
|
|
experiences, |
294
|
|
|
experienceSkills, |
295
|
|
|
essentialSkills, |
296
|
|
|
); |
297
|
|
|
|
298
|
|
|
const openModal = (id: Experience["type"]): void => { |
299
|
|
|
setIsModalVisible({ id, visible: true }); |
300
|
|
|
}; |
301
|
|
|
|
302
|
|
|
const closeModal = (): void => { |
303
|
|
|
setExperienceData(null); |
304
|
|
|
setIsModalVisible({ id: "", visible: false }); |
305
|
|
|
}; |
306
|
|
|
|
307
|
|
|
const submitExperience = (data) => |
308
|
|
|
handleSubmitExperience(data).then(closeModal); |
309
|
|
|
|
310
|
|
|
const editExperience = ( |
311
|
|
|
experience: Experience, |
312
|
|
|
savedOptionalSkills: Skill[], |
313
|
|
|
savedRequiredSkills: Skill[], |
314
|
|
|
): void => { |
315
|
|
|
setExperienceData({ |
316
|
|
|
...experience, |
317
|
|
|
savedOptionalSkills, |
318
|
|
|
savedRequiredSkills, |
319
|
|
|
}); |
320
|
|
|
setIsModalVisible({ id: experience.type, visible: true }); |
321
|
|
|
}; |
322
|
|
|
|
323
|
|
|
const deleteExperience = (experience: Experience): Promise<void> => |
324
|
|
|
handleDeleteExperience(experience.id, experience.type).then(closeModal); |
325
|
|
|
|
326
|
|
|
const softSkills = removeDuplicatesById( |
327
|
|
|
[...assetSkills, ...essentialSkills].filter( |
328
|
|
|
(skill) => skill.skill_type_id === SkillTypeId.Soft, |
329
|
|
|
), |
330
|
|
|
); |
331
|
|
|
|
332
|
|
|
const modalButtons = modalButtonProps(intl); |
333
|
|
|
|
334
|
|
|
const modalRoot = document.getElementById("modal-root"); |
335
|
|
|
|
336
|
|
|
return ( |
337
|
|
|
<> |
338
|
|
|
<div data-c-container="medium"> |
339
|
|
|
<h2 data-c-heading="h2" data-c-margin="top(3) bottom(1)"> |
340
|
|
|
{intl.formatMessage(experienceMessages.heading)} |
341
|
|
|
</h2> |
342
|
|
|
<p data-c-margin="bottom(1)"> |
343
|
|
|
<FormattedMessage |
344
|
|
|
id="application.experience.preamble" |
345
|
|
|
defaultMessage="Use the buttons below to add experiences you want to share with the manager. Experiences you have added in the past also appear below, and you can edit them to link them to skills required for this job when necessary." |
346
|
|
|
description="First section of text on the experience step of the Application Timeline." |
347
|
|
|
/> |
348
|
|
|
</p> |
349
|
|
|
|
350
|
|
|
<div data-c-grid="gutter(all, 1)"> |
351
|
|
|
{essentialSkills.length > 0 && ( |
352
|
|
|
<div data-c-grid-item="tl(1of2)"> |
353
|
|
|
<p data-c-margin="bottom(.5)"> |
354
|
|
|
<FormattedMessage |
355
|
|
|
id="application.experience.essentialSkillsListIntro" |
356
|
|
|
description="Text before the list of essential skills on the experience step of the Application Timeline." |
357
|
|
|
defaultMessage="This job <span>requires</span> the following skills:" |
358
|
|
|
values={{ |
359
|
|
|
span: (chunks): React.ReactElement => ( |
360
|
|
|
<span data-c-font-weight="bold" data-c-color="c2"> |
361
|
|
|
{chunks} |
362
|
|
|
</span> |
363
|
|
|
), |
364
|
|
|
}} |
365
|
|
|
/> |
366
|
|
|
</p> |
367
|
|
|
<ul data-c-margin="bottom(1)"> |
368
|
|
|
{essentialSkills.map((skill) => ( |
369
|
|
|
<li key={skill.id}> |
370
|
|
|
{localizeFieldNonNull(locale, skill, "name")} |
371
|
|
|
</li> |
372
|
|
|
))} |
373
|
|
|
</ul> |
374
|
|
|
</div> |
375
|
|
|
)} |
376
|
|
|
{assetSkills.length > 0 && ( |
377
|
|
|
<div data-c-grid-item="tl(1of2)"> |
378
|
|
|
<p data-c-margin="bottom(.5)"> |
379
|
|
|
<FormattedMessage |
380
|
|
|
id="application.experience.assetSkillsListIntro" |
381
|
|
|
defaultMessage="These skills are beneficial, but not required:" |
382
|
|
|
description="Text before the list of asset skills on the experience step of the Application Timeline." |
383
|
|
|
/> |
384
|
|
|
</p> |
385
|
|
|
<ul data-c-margin="bottom(1)"> |
386
|
|
|
{assetSkills.map((skill) => ( |
387
|
|
|
<li key={skill.id}> |
388
|
|
|
{localizeFieldNonNull(locale, skill, "name")} |
389
|
|
|
</li> |
390
|
|
|
))} |
391
|
|
|
</ul> |
392
|
|
|
</div> |
393
|
|
|
)} |
394
|
|
|
</div> |
395
|
|
|
<p data-c-color="gray" data-c-margin="bottom(2)"> |
396
|
|
|
<FormattedMessage |
397
|
|
|
id="application.experience.softSkillsList" |
398
|
|
|
defaultMessage="Don't forget, {skill} will be evaluated later in the hiring process." |
399
|
|
|
description="List of soft skills that will be evaluated later." |
400
|
|
|
values={{ |
401
|
|
|
skill: ( |
402
|
|
|
<> |
403
|
|
|
{softSkills.map((skill, index) => { |
404
|
|
|
const and = " and "; |
405
|
|
|
const lastElement = index === softSkills.length - 1; |
406
|
|
|
return ( |
407
|
|
|
<React.Fragment key={skill.id}> |
408
|
|
|
{lastElement && softSkills.length > 1 && and} |
409
|
|
|
<span key={skill.id} data-c-font-weight="bold"> |
410
|
|
|
{localizeFieldNonNull(locale, skill, "name")} |
411
|
|
|
</span> |
412
|
|
|
{!lastElement && softSkills.length > 2 && ", "} |
413
|
|
|
</React.Fragment> |
414
|
|
|
); |
415
|
|
|
})} |
416
|
|
|
</> |
417
|
|
|
), |
418
|
|
|
}} |
419
|
|
|
/> |
420
|
|
|
</p> |
421
|
|
|
{/* Experience Modal Buttons */} |
422
|
|
|
<div data-c-grid="gutter(all, 1)"> |
423
|
|
|
{Object.values(modalButtons).map((buttonProps) => { |
424
|
|
|
const { id, title, icon } = buttonProps; |
425
|
|
|
return ( |
426
|
|
|
<ModalButton |
427
|
|
|
key={id} |
428
|
|
|
id={id} |
429
|
|
|
title={title} |
430
|
|
|
icon={icon} |
431
|
|
|
openModal={openModal} |
432
|
|
|
/> |
433
|
|
|
); |
434
|
|
|
})} |
435
|
|
|
</div> |
436
|
|
|
{/* Experience Accordion List */} |
437
|
|
|
{experiences && experiences.length > 0 ? ( |
438
|
|
|
<div className="experience-list" data-c-margin="top(2)"> |
439
|
|
|
<div data-c-accordion-group> |
440
|
|
|
{experiences.map((experience) => { |
441
|
|
|
const savedOptionalSkills = getSkillsOfExperience( |
442
|
|
|
experienceSkills, |
443
|
|
|
experience, |
444
|
|
|
assetSkills, |
445
|
|
|
); |
446
|
|
|
const savedRequiredSkills = getSkillsOfExperience( |
447
|
|
|
experienceSkills, |
448
|
|
|
experience, |
449
|
|
|
essentialSkills, |
450
|
|
|
); |
451
|
|
|
const relevantSkills: ExperienceSkill[] = savedRequiredSkills |
452
|
|
|
.map((skill) => { |
453
|
|
|
return experienceSkills.find( |
454
|
|
|
({ experience_id, experience_type, skill_id }) => |
455
|
|
|
experience_id === experience.id && |
456
|
|
|
skill_id === skill.id && |
457
|
|
|
experience_type === experience.type, |
458
|
|
|
); |
459
|
|
|
}) |
460
|
|
|
.filter(notEmpty); |
461
|
|
|
|
462
|
|
|
const handleEdit = () => |
463
|
|
|
editExperience( |
464
|
|
|
experience, |
465
|
|
|
savedOptionalSkills, |
466
|
|
|
savedRequiredSkills, |
467
|
|
|
); |
468
|
|
|
const handleDelete = () => deleteExperience(experience); |
469
|
|
|
|
470
|
|
|
const errorAccordion = () => ( |
471
|
|
|
<div |
472
|
|
|
data-c-background="gray(10)" |
473
|
|
|
data-c-radius="rounded" |
474
|
|
|
data-c-border="all(thin, solid, gray)" |
475
|
|
|
data-c-margin="top(1)" |
476
|
|
|
data-c-padding="all(1)" |
477
|
|
|
> |
478
|
|
|
<div data-c-align="base(center)"> |
479
|
|
|
<p data-c-color="stop"> |
480
|
|
|
{intl.formatMessage( |
481
|
|
|
experienceMessages.errorRenderingExperience, |
482
|
|
|
)} |
483
|
|
|
</p> |
484
|
|
|
</div> |
485
|
|
|
</div> |
486
|
|
|
); |
487
|
|
|
|
488
|
|
|
// Number of skills attached to Experience but are not part of the jobs skill criteria. |
489
|
|
|
const irrelevantSkillCount = |
490
|
|
|
experienceSkills.filter( |
491
|
|
|
(experienceSkill) => |
492
|
|
|
experienceSkill.experience_id === experience.id && |
493
|
|
|
experienceSkill.experience_type === experience.type, |
494
|
|
|
).length - |
495
|
|
|
(savedOptionalSkills.length + savedRequiredSkills.length); |
496
|
|
|
|
497
|
|
|
return ( |
498
|
|
|
applicationExperienceAccordion( |
499
|
|
|
experience, |
500
|
|
|
irrelevantSkillCount, |
501
|
|
|
relevantSkills, |
502
|
|
|
skills, |
503
|
|
|
handleEdit, |
504
|
|
|
handleDelete, |
505
|
|
|
) ?? errorAccordion() |
506
|
|
|
); |
507
|
|
|
})} |
508
|
|
|
</div> |
509
|
|
|
</div> |
510
|
|
|
) : ( |
511
|
|
|
<div |
512
|
|
|
data-c-background="gray(10)" |
513
|
|
|
data-c-radius="rounded" |
514
|
|
|
data-c-border="all(thin, solid, gray)" |
515
|
|
|
data-c-margin="top(2)" |
516
|
|
|
data-c-padding="all(1)" |
517
|
|
|
> |
518
|
|
|
<div data-c-align="base(center)"> |
519
|
|
|
<p data-c-color="gray"> |
520
|
|
|
<FormattedMessage |
521
|
|
|
id="application.experience.noExperiences" |
522
|
|
|
defaultMessage="Looks like you don't have any experience added yet. Use the buttons above to add experience. Don't forget that experience will always be saved to your profile so that you can use it on future applications!" |
523
|
|
|
description="Message displayed when application has no experiences." |
524
|
|
|
/> |
525
|
|
|
</p> |
526
|
|
|
</div> |
527
|
|
|
</div> |
528
|
|
|
)} |
529
|
|
|
{disconnectedRequiredSkills && disconnectedRequiredSkills.length > 0 && ( |
530
|
|
|
<p data-c-color="stop" data-c-margin="top(2)"> |
531
|
|
|
<FormattedMessage |
532
|
|
|
id="application.experience.unconnectedSkills" |
533
|
|
|
defaultMessage="The following required skill(s) are not connected to your experience:" |
534
|
|
|
description="Message showing list of required skills that are not connected to a experience." |
535
|
|
|
/>{" "} |
536
|
|
|
{disconnectedRequiredSkills.map((skill) => ( |
537
|
|
|
<React.Fragment key={skill.id}> |
538
|
|
|
<span |
539
|
|
|
data-c-tag="stop" |
540
|
|
|
data-c-radius="pill" |
541
|
|
|
data-c-font-size="small" |
542
|
|
|
> |
543
|
|
|
{localizeFieldNonNull(locale, skill, "name")} |
544
|
|
|
</span>{" "} |
545
|
|
|
</React.Fragment> |
546
|
|
|
))} |
547
|
|
|
</p> |
548
|
|
|
)} |
549
|
|
|
</div> |
550
|
|
|
|
551
|
|
|
<div data-c-dialog-overlay={isModalVisible.visible ? "active" : ""} /> |
552
|
|
|
<EducationExperienceModal |
553
|
|
|
educationStatuses={educationStatuses} |
554
|
|
|
educationTypes={educationTypes} |
555
|
|
|
experienceEducation={experienceData as ExperienceEducation} |
556
|
|
|
experienceableId={experienceData?.experienceable_id ?? 0} |
557
|
|
|
experienceableType={ |
558
|
|
|
experienceData?.experienceable_type ?? "application" |
559
|
|
|
} |
560
|
|
|
jobId={jobId} |
561
|
|
|
jobClassification={jobClassification} |
562
|
|
|
jobEducationRequirements={jobEducationRequirements} |
563
|
|
|
modalId={modalButtons.education.id} |
564
|
|
|
onModalCancel={closeModal} |
565
|
|
|
onModalConfirm={submitExperience} |
566
|
|
|
optionalSkills={assetSkills} |
567
|
|
|
parentElement={modalRoot} |
568
|
|
|
requiredSkills={essentialSkills} |
569
|
|
|
savedOptionalSkills={experienceData?.savedOptionalSkills ?? []} |
570
|
|
|
savedRequiredSkills={experienceData?.savedRequiredSkills ?? []} |
571
|
|
|
visible={ |
572
|
|
|
isModalVisible.visible && |
573
|
|
|
isModalVisible.id === modalButtons.education.id |
574
|
|
|
} |
575
|
|
|
/> |
576
|
|
|
<WorkExperienceModal |
577
|
|
|
experienceWork={experienceData as ExperienceWork} |
578
|
|
|
experienceableId={experienceData?.experienceable_id ?? 0} |
579
|
|
|
experienceableType={ |
580
|
|
|
experienceData?.experienceable_type ?? "application" |
581
|
|
|
} |
582
|
|
|
jobId={jobId} |
583
|
|
|
jobClassification={jobClassification} |
584
|
|
|
jobEducationRequirements={jobEducationRequirements} |
585
|
|
|
modalId={modalButtons.work.id} |
586
|
|
|
onModalCancel={closeModal} |
587
|
|
|
onModalConfirm={submitExperience} |
588
|
|
|
optionalSkills={assetSkills} |
589
|
|
|
parentElement={modalRoot} |
590
|
|
|
requiredSkills={essentialSkills} |
591
|
|
|
savedOptionalSkills={experienceData?.savedOptionalSkills ?? []} |
592
|
|
|
savedRequiredSkills={experienceData?.savedRequiredSkills ?? []} |
593
|
|
|
visible={ |
594
|
|
|
isModalVisible.visible && isModalVisible.id === modalButtons.work.id |
595
|
|
|
} |
596
|
|
|
/> |
597
|
|
|
<CommunityExperienceModal |
598
|
|
|
experienceCommunity={experienceData as ExperienceCommunity} |
599
|
|
|
experienceableId={experienceData?.experienceable_id ?? 0} |
600
|
|
|
experienceableType={ |
601
|
|
|
experienceData?.experienceable_type ?? "application" |
602
|
|
|
} |
603
|
|
|
jobId={jobId} |
604
|
|
|
jobClassification={jobClassification} |
605
|
|
|
jobEducationRequirements={jobEducationRequirements} |
606
|
|
|
modalId={modalButtons.community.id} |
607
|
|
|
onModalCancel={closeModal} |
608
|
|
|
onModalConfirm={submitExperience} |
609
|
|
|
optionalSkills={assetSkills} |
610
|
|
|
parentElement={modalRoot} |
611
|
|
|
requiredSkills={essentialSkills} |
612
|
|
|
savedOptionalSkills={experienceData?.savedOptionalSkills ?? []} |
613
|
|
|
savedRequiredSkills={experienceData?.savedRequiredSkills ?? []} |
614
|
|
|
visible={ |
615
|
|
|
isModalVisible.visible && |
616
|
|
|
isModalVisible.id === modalButtons.community.id |
617
|
|
|
} |
618
|
|
|
/> |
619
|
|
|
<PersonalExperienceModal |
620
|
|
|
experiencePersonal={experienceData as ExperiencePersonal} |
621
|
|
|
experienceableId={experienceData?.experienceable_id ?? 0} |
622
|
|
|
experienceableType={ |
623
|
|
|
experienceData?.experienceable_type ?? "application" |
624
|
|
|
} |
625
|
|
|
jobId={jobId} |
626
|
|
|
jobClassification={jobClassification} |
627
|
|
|
jobEducationRequirements={jobEducationRequirements} |
628
|
|
|
modalId={modalButtons.personal.id} |
629
|
|
|
onModalCancel={closeModal} |
630
|
|
|
onModalConfirm={submitExperience} |
631
|
|
|
optionalSkills={assetSkills} |
632
|
|
|
parentElement={modalRoot} |
633
|
|
|
requiredSkills={essentialSkills} |
634
|
|
|
savedOptionalSkills={experienceData?.savedOptionalSkills ?? []} |
635
|
|
|
savedRequiredSkills={experienceData?.savedRequiredSkills ?? []} |
636
|
|
|
visible={ |
637
|
|
|
isModalVisible.visible && |
638
|
|
|
isModalVisible.id === modalButtons.personal.id |
639
|
|
|
} |
640
|
|
|
/> |
641
|
|
|
<AwardExperienceModal |
642
|
|
|
experienceAward={experienceData as ExperienceAward} |
643
|
|
|
experienceableId={experienceData?.experienceable_id ?? 0} |
644
|
|
|
experienceableType={ |
645
|
|
|
experienceData?.experienceable_type ?? "application" |
646
|
|
|
} |
647
|
|
|
jobId={jobId} |
648
|
|
|
jobClassification={jobClassification} |
649
|
|
|
jobEducationRequirements={jobEducationRequirements} |
650
|
|
|
modalId={modalButtons.award.id} |
651
|
|
|
onModalCancel={closeModal} |
652
|
|
|
onModalConfirm={submitExperience} |
653
|
|
|
optionalSkills={assetSkills} |
654
|
|
|
parentElement={modalRoot} |
655
|
|
|
recipientTypes={recipientTypes} |
656
|
|
|
recognitionTypes={recognitionTypes} |
657
|
|
|
requiredSkills={essentialSkills} |
658
|
|
|
savedOptionalSkills={experienceData?.savedOptionalSkills ?? []} |
659
|
|
|
savedRequiredSkills={experienceData?.savedRequiredSkills ?? []} |
660
|
|
|
visible={ |
661
|
|
|
isModalVisible.visible && isModalVisible.id === modalButtons.award.id |
662
|
|
|
} |
663
|
|
|
/> |
664
|
|
|
</> |
665
|
|
|
); |
666
|
|
|
}; |
667
|
|
|
|
668
|
|
|
interface ExperienceStepProps { |
669
|
|
|
experiences: Experience[]; |
670
|
|
|
educationStatuses: EducationStatus[]; |
671
|
|
|
educationTypes: EducationType[]; |
672
|
|
|
experienceSkills: ExperienceSkill[]; |
673
|
|
|
criteria: Criteria[]; |
674
|
|
|
skills: Skill[]; |
675
|
|
|
jobId: number; |
676
|
|
|
jobClassificationId: number | null; |
677
|
|
|
jobEducationRequirements: string | null; |
678
|
|
|
recipientTypes: AwardRecipientType[]; |
679
|
|
|
recognitionTypes: AwardRecognitionType[]; |
680
|
|
|
handleDeleteExperience: ( |
681
|
|
|
id: number, |
682
|
|
|
type: Experience["type"], |
683
|
|
|
) => Promise<void>; |
684
|
|
|
handleSubmitExperience: (data: ExperienceSubmitData) => Promise<void>; |
685
|
|
|
handleContinue: () => void; |
686
|
|
|
handleQuit: () => void; |
687
|
|
|
handleReturn: () => void; |
688
|
|
|
} |
689
|
|
|
|
690
|
|
|
export const ExperienceStep: React.FunctionComponent<ExperienceStepProps> = ({ |
691
|
|
|
experiences, |
692
|
|
|
educationStatuses, |
693
|
|
|
educationTypes, |
694
|
|
|
experienceSkills, |
695
|
|
|
criteria, |
696
|
|
|
skills, |
697
|
|
|
handleSubmitExperience, |
698
|
|
|
handleDeleteExperience, |
699
|
|
|
jobId, |
700
|
|
|
jobClassificationId, |
701
|
|
|
jobEducationRequirements, |
702
|
|
|
recipientTypes, |
703
|
|
|
recognitionTypes, |
704
|
|
|
handleContinue, |
705
|
|
|
handleQuit, |
706
|
|
|
handleReturn, |
707
|
|
|
}) => { |
708
|
|
|
const intl = useIntl(); |
709
|
|
|
return ( |
710
|
|
|
<> |
711
|
|
|
<MyExperience |
712
|
|
|
experiences={experiences} |
713
|
|
|
educationStatuses={educationStatuses} |
714
|
|
|
educationTypes={educationTypes} |
715
|
|
|
experienceSkills={experienceSkills} |
716
|
|
|
criteria={criteria} |
717
|
|
|
skills={skills} |
718
|
|
|
jobId={jobId} |
719
|
|
|
jobClassificationId={jobClassificationId} |
720
|
|
|
jobEducationRequirements={jobEducationRequirements} |
721
|
|
|
recipientTypes={recipientTypes} |
722
|
|
|
recognitionTypes={recognitionTypes} |
723
|
|
|
handleSubmitExperience={handleSubmitExperience} |
724
|
|
|
handleDeleteExperience={handleDeleteExperience} |
725
|
|
|
/> |
726
|
|
|
<div data-c-container="medium" data-c-padding="tb(2)"> |
727
|
|
|
<hr data-c-hr="thin(c1)" data-c-margin="bottom(2)" /> |
728
|
|
|
<div data-c-grid="gutter"> |
729
|
|
|
<div |
730
|
|
|
data-c-alignment="base(centre) tp(left)" |
731
|
|
|
data-c-grid-item="tp(1of2)" |
732
|
|
|
> |
733
|
|
|
<button |
734
|
|
|
data-c-button="outline(c2)" |
735
|
|
|
data-c-radius="rounded" |
736
|
|
|
type="button" |
737
|
|
|
onClick={(): void => handleReturn()} |
738
|
|
|
> |
739
|
|
|
{intl.formatMessage(navigationMessages.return)} |
740
|
|
|
</button> |
741
|
|
|
</div> |
742
|
|
|
<div |
743
|
|
|
data-c-alignment="base(centre) tp(right)" |
744
|
|
|
data-c-grid-item="tp(1of2)" |
745
|
|
|
> |
746
|
|
|
<button |
747
|
|
|
data-c-button="outline(c2)" |
748
|
|
|
data-c-radius="rounded" |
749
|
|
|
type="button" |
750
|
|
|
onClick={(): void => handleQuit()} |
751
|
|
|
> |
752
|
|
|
{intl.formatMessage(navigationMessages.quit)} |
753
|
|
|
</button> |
754
|
|
|
<button |
755
|
|
|
data-c-button="solid(c1)" |
756
|
|
|
data-c-radius="rounded" |
757
|
|
|
data-c-margin="left(1)" |
758
|
|
|
type="button" |
759
|
|
|
onClick={(): void => handleContinue()} |
760
|
|
|
> |
761
|
|
|
{intl.formatMessage(navigationMessages.continue)} |
762
|
|
|
</button> |
763
|
|
|
</div> |
764
|
|
|
</div> |
765
|
|
|
</div> |
766
|
|
|
</> |
767
|
|
|
); |
768
|
|
|
}; |
769
|
|
|
|
770
|
|
|
export default ExperienceStep; |
771
|
|
|
|