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

resources/assets/js/components/Application/Experience/Experience.tsx   F

Complexity

Total Complexity 67
Complexity/F 0

Size

Lines of Code 747
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 67
eloc 635
mnd 67
bc 67
fnc 0
dl 0
loc 747
rs 3.005
bpm 0
cpm 0
noi 0
c 0
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like resources/assets/js/components/Application/Experience/Experience.tsx often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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