Passed
Push — feature/timeline-experience-st... ( a18b2e )
by Yonathan
05:54
created

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

Complexity

Total Complexity 75
Complexity/F 0

Size

Lines of Code 743
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 75
eloc 633
mnd 75
bc 75
fnc 0
dl 0
loc 743
bpm 0
cpm 0
noi 0
c 0
b 0
f 0
rs 2.367

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