Passed
Push — feature/experience-form-modals ( ac040e...10a0f1 )
by Tristan
03:59
created

JobWorkEnv.tsx ➔ convertSliderIdToJob   A

Complexity

Conditions 2

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 7
dl 0
loc 9
rs 10
c 0
b 0
f 0
cc 2
1
/* eslint-disable jsx-a11y/label-has-associated-control, camelcase, @typescript-eslint/camelcase */
2
import React, { useState, useRef } from "react";
3
import {
4
  Form,
5
  Formik,
6
  FormikTouched,
7
  FormikErrors,
8
  FastField,
9
  Field,
10
} from "formik";
11
import * as Yup from "yup";
12
import nprogress from "nprogress";
13
import {
14
  FormattedMessage,
15
  MessageDescriptor,
16
  IntlShape,
17
  useIntl,
18
} from "react-intl";
19
import CheckboxGroup from "../../Form/CheckboxGroup";
20
import RadioGroup from "../../Form/RadioGroup";
21
import ContextBlock from "../../ContextBlock/ContextBlock";
22
import ContextBlockItem from "../../ContextBlock/ContextBlockItem";
23
import CopyToClipboardButton from "../../CopyToClipboardButton";
24
import JobWorkEnvModal from "./JobWorkEnvModal";
25
import RadioInput from "../../Form/RadioInput";
26
import NumberInput from "../../Form/NumberInput";
27
import CheckboxInput from "../../Form/CheckboxInput";
28
import TextAreaInput from "../../Form/TextAreaInput";
29
import { validationMessages } from "../../Form/Messages";
30
import { Job } from "../../../models/types";
31
import { emptyJob } from "../../../models/jobUtil";
32
import {
33
  notEmpty,
34
  hasKey,
35
  mapToObjectTrans,
36
  identity,
37
} from "../../../helpers/queries";
38
import {
39
  physEnvOptions,
40
  techOptions,
41
  amenitiesOptions,
42
  phyEnvDescriptions,
43
  techDescriptions,
44
  amenitiesDescriptions,
45
} from "./WorkEnvFeatures";
46
import { localizeField, getLocale } from "../../../helpers/localize";
47
import {
48
  formMessages,
49
  culturePaceMessages,
50
  mgmtStyleMessages,
51
  experimentalMessages,
52
  facingMessages,
53
  collaborativenessMessages,
54
} from "./JobWorkEnvMessages";
55
56
type CulturePaceId =
57
  | "culturePace01"
58
  | "culturePace02"
59
  | "culturePace03"
60
  | "culturePace04";
61
const culturePaceList: {
62
  id: CulturePaceId;
63
  title: MessageDescriptor;
64
  subtext: MessageDescriptor;
65
}[] = [
66
  {
67
    id: "culturePace01",
68
    title: culturePaceMessages.pace01Title,
69
    subtext: culturePaceMessages.pace01Description,
70
  },
71
  {
72
    id: "culturePace02",
73
    title: culturePaceMessages.pace02Title,
74
    subtext: culturePaceMessages.pace02Description,
75
  },
76
  {
77
    id: "culturePace03",
78
    title: culturePaceMessages.pace03Title,
79
    subtext: culturePaceMessages.pace03Description,
80
  },
81
  {
82
    id: "culturePace04",
83
    title: culturePaceMessages.pace04Title,
84
    subtext: culturePaceMessages.pace04Description,
85
  },
86
];
87
88
type MgmtStyleId =
89
  | "mgmtStyle01"
90
  | "mgmtStyle02"
91
  | "mgmtStyle03"
92
  | "mgmtStyle04";
93
const managementList: {
94
  id: MgmtStyleId;
95
  title: MessageDescriptor;
96
  subtext: MessageDescriptor;
97
}[] = [
98
  {
99
    id: "mgmtStyle01",
100
    title: mgmtStyleMessages.style01Title,
101
    subtext: mgmtStyleMessages.style01Description,
102
  },
103
  {
104
    id: "mgmtStyle02",
105
    title: mgmtStyleMessages.style02Title,
106
    subtext: mgmtStyleMessages.style02Description,
107
  },
108
  {
109
    id: "mgmtStyle03",
110
    title: mgmtStyleMessages.style03Title,
111
    subtext: mgmtStyleMessages.style03Description,
112
  },
113
  {
114
    id: "mgmtStyle04",
115
    title: mgmtStyleMessages.style04Title,
116
    subtext: mgmtStyleMessages.style04Description,
117
  },
118
];
119
120
type ExperiementalId =
121
  | "experimental01"
122
  | "experimental02"
123
  | "experimental03"
124
  | "experimental04";
125
const experimentalList: {
126
  id: ExperiementalId;
127
  title: MessageDescriptor;
128
  subtext: MessageDescriptor;
129
}[] = [
130
  {
131
    id: "experimental01",
132
    title: experimentalMessages.experimental01Title,
133
    subtext: experimentalMessages.experimental01Description,
134
  },
135
  {
136
    id: "experimental02",
137
    title: experimentalMessages.experimental02Title,
138
    subtext: experimentalMessages.experimental02Description,
139
  },
140
  {
141
    id: "experimental03",
142
    title: experimentalMessages.experimental03Title,
143
    subtext: experimentalMessages.experimental03Description,
144
  },
145
  {
146
    id: "experimental04",
147
    title: experimentalMessages.experimental04Title,
148
    subtext: experimentalMessages.experimental04Description,
149
  },
150
];
151
152
type FacingId = "facing01" | "facing02" | "facing03" | "facing04";
153
const facingList: {
154
  id: FacingId;
155
  title: MessageDescriptor;
156
  subtext: MessageDescriptor;
157
}[] = [
158
  {
159
    id: "facing01",
160
    title: facingMessages.facing01Title,
161
    subtext: facingMessages.facing01Description,
162
  },
163
  {
164
    id: "facing02",
165
    title: facingMessages.facing02Title,
166
    subtext: facingMessages.facing02Description,
167
  },
168
  {
169
    id: "facing03",
170
    title: facingMessages.facing03Title,
171
    subtext: facingMessages.facing03Description,
172
  },
173
  {
174
    id: "facing04",
175
    title: facingMessages.facing04Title,
176
    subtext: facingMessages.facing04Description,
177
  },
178
];
179
180
type CollaborativenessId =
181
  | "collaborativeness01"
182
  | "collaborativeness02"
183
  | "collaborativeness03"
184
  | "collaborativeness04";
185
const collaborativenessList: {
186
  id: CollaborativenessId;
187
  title: MessageDescriptor;
188
  subtext: MessageDescriptor;
189
}[] = [
190
  {
191
    id: "collaborativeness01",
192
    title: collaborativenessMessages.collaborativeness01Title,
193
    subtext: collaborativenessMessages.collaborativeness01Description,
194
  },
195
  {
196
    id: "collaborativeness02",
197
    title: collaborativenessMessages.collaborativeness02Title,
198
    subtext: collaborativenessMessages.collaborativeness02Description,
199
  },
200
  {
201
    id: "collaborativeness03",
202
    title: collaborativenessMessages.collaborativeness03Title,
203
    subtext: collaborativenessMessages.collaborativeness03Description,
204
  },
205
  {
206
    id: "collaborativeness04",
207
    title: collaborativenessMessages.collaborativeness04Title,
208
    subtext: collaborativenessMessages.collaborativeness04Description,
209
  },
210
];
211
212
// shape of values used in Form
213
export interface JobWorkEnvValues {
214
  teamSize: number | "";
215
  physicalEnv: string[];
216
  technology: string[];
217
  amenities: string[];
218
  envDescription: string;
219
  culturePace?: CulturePaceId;
220
  management?: MgmtStyleId;
221
  experimental?: ExperiementalId;
222
  facing?: FacingId;
223
  collaborativeness?: CollaborativenessId;
224
  cultureSummary: string;
225
  moreCultureSummary: string;
226
}
227
228
function convertSliderIdFromJob<T>(
229
  key: string,
230
  formSliderArray: { id: T }[],
231
  jobSliderId: number | null,
232
): { [key: string]: T } | {} {
233
  return jobSliderId && jobSliderId > 0 && jobSliderId <= formSliderArray.length
234
    ? {
235
        [key]: formSliderArray[jobSliderId - 1].id,
236
      }
237
    : { [key]: undefined };
238
}
239
240
const jobToValues = (
241
  {
242
    team_size,
243
    fast_vs_steady,
244
    horizontal_vs_vertical,
245
    experimental_vs_ongoing,
246
    citizen_facing_vs_back_office,
247
    collaborative_vs_independent,
248
    work_env_features,
249
    ...job
250
  }: Job,
251
  locale: "en" | "fr",
252
): JobWorkEnvValues => {
253
  const isTrueInEnvFeatures = (option: string): boolean =>
254
    work_env_features !== null &&
255
    hasKey(work_env_features, option) &&
256
    work_env_features[option];
257
258
  return {
259
    teamSize: team_size || "",
260
    physicalEnv: physEnvOptions.filter(isTrueInEnvFeatures),
261
    technology: techOptions.filter(isTrueInEnvFeatures),
262
    amenities: amenitiesOptions.filter(isTrueInEnvFeatures),
263
    ...convertSliderIdFromJob("culturePace", culturePaceList, fast_vs_steady),
264
    ...convertSliderIdFromJob(
265
      "management",
266
      managementList,
267
      horizontal_vs_vertical,
268
    ),
269
    ...convertSliderIdFromJob(
270
      "experimental",
271
      experimentalList,
272
      experimental_vs_ongoing,
273
    ),
274
    ...convertSliderIdFromJob(
275
      "facing",
276
      facingList,
277
      citizen_facing_vs_back_office,
278
    ),
279
    ...convertSliderIdFromJob(
280
      "collaborativeness",
281
      collaborativenessList,
282
      collaborative_vs_independent,
283
    ),
284
    envDescription: localizeField(locale, job, "work_env_description") || "",
285
    cultureSummary: localizeField(locale, job, "culture_summary") || "",
286
    moreCultureSummary: localizeField(locale, job, "culture_special") || "",
287
  };
288
};
289
290
function convertSliderIdToJob(
291
  formSliderArray: { id: string }[],
292
  id: string | undefined,
293
): number | null {
294
  if (id === undefined) {
295
    return null;
296
  }
297
  return formSliderArray.map((item): string => item.id).indexOf(id) + 1;
298
}
299
300
const updateJobWithValues = (
301
  job: Job,
302
  locale: "en" | "fr",
303
  {
304
    teamSize,
305
    physicalEnv,
306
    technology,
307
    amenities,
308
    envDescription,
309
    culturePace,
310
    management,
311
    experimental,
312
    facing,
313
    collaborativeness,
314
    cultureSummary,
315
    moreCultureSummary,
316
  }: JobWorkEnvValues,
317
): Job => {
318
  const physFeatures = mapToObjectTrans(
319
    physEnvOptions,
320
    identity,
321
    (option): boolean => physicalEnv.includes(option),
322
  );
323
  const techFeatures = mapToObjectTrans(
324
    techOptions,
325
    identity,
326
    (option): boolean => technology.includes(option),
327
  );
328
  const amenityFeatures = mapToObjectTrans(
329
    amenitiesOptions,
330
    identity,
331
    (option): boolean => amenities.includes(option),
332
  );
333
  const workEnvFeatures = {
334
    ...physFeatures,
335
    ...techFeatures,
336
    ...amenityFeatures,
337
  };
338
  return {
339
    ...job,
340
    team_size: teamSize || null,
341
    fast_vs_steady: convertSliderIdToJob(culturePaceList, culturePace),
342
    horizontal_vs_vertical: convertSliderIdToJob(managementList, management),
343
    experimental_vs_ongoing: convertSliderIdToJob(
344
      experimentalList,
345
      experimental,
346
    ),
347
    citizen_facing_vs_back_office: convertSliderIdToJob(facingList, facing),
348
    collaborative_vs_independent: convertSliderIdToJob(
349
      collaborativenessList,
350
      collaborativeness,
351
    ),
352
    work_env_features: workEnvFeatures,
353
    work_env_description: {
354
      ...job.work_env_description,
355
      [locale]: envDescription || null,
356
    },
357
    culture_summary: {
358
      ...job.culture_summary,
359
      [locale]: cultureSummary || null,
360
    },
361
    culture_special: {
362
      ...job.culture_special,
363
      [locale]: moreCultureSummary || null,
364
    },
365
  };
366
};
367
368
const renderRadioWithContext = (
369
  intl: IntlShape,
370
  touched: FormikTouched<JobWorkEnvValues>,
371
  errors: FormikErrors<JobWorkEnvValues>,
372
  values: JobWorkEnvValues,
373
  fieldName: string,
374
  label: string,
375
  sliderList: {
376
    id: string;
377
    title: MessageDescriptor;
378
    subtext: MessageDescriptor;
379
  }[],
380
): React.ReactElement => {
381
  return (
382
    <div className="job-builder-culture-block" data-c-grid-item="base(1of1)">
383
      <div data-c-grid="gutter">
384
        <RadioGroup
385
          id={fieldName}
386
          label={label}
387
          required
388
          touched={touched[fieldName]}
389
          error={errors[fieldName]}
390
          value={values[fieldName]}
391
          grid="base(1of1) tl(1of3)"
392
        >
393
          {sliderList.map(
394
            ({ id, title }): React.ReactElement => {
395
              return (
396
                <FastField
397
                  key={id}
398
                  name={fieldName}
399
                  component={RadioInput}
400
                  id={id}
401
                  label={intl.formatMessage(title)}
402
                  value={id}
403
                  trigger
404
                  required
405
                />
406
              );
407
            },
408
          )}
409
        </RadioGroup>
410
        <ContextBlock
411
          className="job-builder-context-block"
412
          grid="base(1of1) tl(2of3)"
413
        >
414
          {sliderList.map(
415
            ({ id, title, subtext }): React.ReactElement => {
416
              return (
417
                <ContextBlockItem
418
                  key={id}
419
                  contextId={id}
420
                  title={intl.formatMessage(title)}
421
                  subtext={intl.formatMessage(subtext)}
422
                  className="job-builder-context-item"
423
                  active={values[fieldName] === id}
424
                />
425
              );
426
            },
427
          )}
428
        </ContextBlock>
429
      </div>
430
    </div>
431
  );
432
};
433
434
interface JobWorkEnvProps {
435
  // Optional Job to prepopulate form values from.
436
  job: Job | null;
437
  // A boolean that gives you the state of the request for the job data.
438
  jobIsComplete: boolean;
439
  // Submit function that runs after successful validation.
440
  // It must return the submitted job, if successful.
441
  handleSubmit: (values: Job) => Promise<Job>;
442
  // The function to run when user clicks Prev Page
443
  handleReturn: () => void;
444
  // Function to run when modal cancel is clicked.
445
  handleModalCancel: () => void;
446
  // Function to run when modal confirm is clicked.
447
  handleModalConfirm: () => void;
448
  handleSkipToReview: () => Promise<void>;
449
}
450
451
const JobWorkEnv = ({
452
  job,
453
  handleSubmit,
454
  handleReturn,
455
  handleModalCancel,
456
  handleModalConfirm,
457
  jobIsComplete,
458
  handleSkipToReview,
459
}: JobWorkEnvProps): React.ReactElement => {
460
  const intl = useIntl();
461
  const locale = getLocale(intl.locale);
462
  const [isModalVisible, setIsModalVisible] = useState(false);
463
464
  const initialValues: JobWorkEnvValues = job
465
    ? jobToValues(job, locale)
466
    : {
467
        teamSize: "",
468
        physicalEnv: [],
469
        technology: [],
470
        amenities: [],
471
        culturePace: undefined,
472
        management: undefined,
473
        experimental: undefined,
474
        facing: undefined,
475
        collaborativeness: undefined,
476
        envDescription: "",
477
        cultureSummary: "",
478
        moreCultureSummary: "",
479
      };
480
481
  const phyEnvData: { name: string; label: string }[] = phyEnvDescriptions(
482
    intl,
483
  );
484
  const techData: { name: string; label: string }[] = techDescriptions(intl);
485
  const amenitiesData: {
486
    name: string;
487
    label: string;
488
  }[] = amenitiesDescriptions(intl);
489
490
  const modalParentRef = useRef<HTMLDivElement>(null);
491
  const workEnvSchema = Yup.object().shape({
492
    teamSize: Yup.number()
493
      .min(1, intl.formatMessage(validationMessages.required))
494
      .required(intl.formatMessage(validationMessages.required)),
495
    physicalEnv: Yup.array(),
496
    technology: Yup.array(),
497
    amenities: Yup.array(),
498
    envDescription: Yup.string(),
499
    culturePace: Yup.string()
500
      .oneOf(culturePaceList.map((item): string => item.id))
501
      .required(intl.formatMessage(validationMessages.checkboxRequired)),
502
    management: Yup.string()
503
      .oneOf(managementList.map((item): string => item.id))
504
      .required(intl.formatMessage(validationMessages.checkboxRequired)),
505
    experimental: Yup.string()
506
      .oneOf(experimentalList.map((item): string => item.id))
507
      .required(intl.formatMessage(validationMessages.checkboxRequired)),
508
    facing: Yup.string()
509
      .oneOf(facingList.map((item): string => item.id))
510
      .required(intl.formatMessage(validationMessages.checkboxRequired)),
511
    collaborativeness: Yup.string()
512
      .oneOf(collaborativenessList.map((item): string => item.id))
513
      .required(intl.formatMessage(validationMessages.checkboxRequired)),
514
  });
515
516
  /** Compiles and returns all the active radio buttons corresponding context box values within the culture section  */
517
  const buildCultureSummary = (values: JobWorkEnvValues): string => {
518
    const pace = culturePaceList.find(
519
      ({ id }): boolean => id === values.culturePace,
520
    );
521
    const management = managementList.find(
522
      ({ id }): boolean => id === values.management,
523
    );
524
    const experimental = experimentalList.find(
525
      ({ id }): boolean => id === values.experimental,
526
    );
527
    const facing = facingList.find(({ id }): boolean => id === values.facing);
528
    const collaborativeness = collaborativenessList.find(
529
      ({ id }): boolean => id === values.collaborativeness,
530
    );
531
532
    const cultureSummary: string = [
533
      pace,
534
      management,
535
      experimental,
536
      facing,
537
      collaborativeness,
538
    ]
539
      .filter(notEmpty)
540
      .map((item): string => intl.formatMessage(item.subtext))
541
      .join(" ");
542
    return cultureSummary;
543
  };
544
545
  const updateValuesAndReturn = (values: JobWorkEnvValues): void => {
546
    nprogress.start();
547
    // If custom summary textbox is length is zero, set cultureSummary to generated text
548
    const cultureSummary =
549
      values.cultureSummary.length === 0
550
        ? buildCultureSummary(values)
551
        : values.cultureSummary;
552
    const formValues: JobWorkEnvValues = { ...values, cultureSummary };
553
    const oldJob = job || emptyJob();
554
    const updatedJob = updateJobWithValues(oldJob, locale, formValues);
555
    handleSubmit(updatedJob).then((): void => {
556
      nprogress.done();
557
      handleReturn();
558
    });
559
  };
560
561
  return (
562
    <div
563
      data-c-container="form"
564
      data-c-padding="top(triple) bottom(triple)"
565
      ref={modalParentRef}
566
    >
567
      <h3
568
        data-c-font-size="h3"
569
        data-c-font-weight="bold"
570
        data-c-margin="bottom(double)"
571
      >
572
        <FormattedMessage
573
          id="jobBuilder.workEnv.title"
574
          defaultMessage="Work Environment"
575
          description="Header of job poster builder work environment step."
576
        />
577
      </h3>
578
      <p>
579
        <FormattedMessage
580
          id="jobBuilder.workEnv.stepDescription"
581
          defaultMessage={`Applicants care a lot about the team they'll be working with and the physical workspace as well. Sharing information about these things help applicants determine if they'll be a good fit, and can reduce the number of "wishful thinking" applications that slow down the screening process.`}
582
          description="Description of job poster builder work environment step."
583
        />
584
      </p>
585
      <div data-c-grid-item="base(1of1)">
586
        <h4 data-c-font-size="h4" data-c-margin="top(triple) bottom(normal)">
587
          <FormattedMessage
588
            id="jobBuilder.workEnv.ourWorkEnv"
589
            defaultMessage="Our Work Environment"
590
            description="Section 1 of Job Poster Builder Work Environment Step"
591
          />
592
        </h4>
593
        <p data-c-margin="bottom(normal)">
594
          {intl.formatMessage(formMessages.ourWorkEnvDesc)}
595
        </p>
596
      </div>
597
598
      <Formik
599
        enableReinitialize
600
        initialValues={initialValues}
601
        validationSchema={workEnvSchema}
602
        onSubmit={(values, { setSubmitting }): void => {
603
          // If custom summary textbox is length is zero, set cultureSummary to generated text
604
          const cultureSummary =
605
            values.cultureSummary.length === 0
606
              ? buildCultureSummary(values)
607
              : values.cultureSummary;
608
          const formValues: JobWorkEnvValues = { ...values, cultureSummary };
609
          const oldJob = job || emptyJob();
610
          const updatedJob = updateJobWithValues(oldJob, locale, formValues);
611
612
          nprogress.start();
613
          handleSubmit(updatedJob)
614
            .then((): void => {
615
              nprogress.done();
616
              setIsModalVisible(true);
617
            })
618
            .finally((): void => {
619
              setSubmitting(false);
620
            });
621
        }}
622
      >
623
        {({
624
          errors,
625
          touched,
626
          isSubmitting,
627
          values,
628
          setFieldValue,
629
          setFieldTouched,
630
        }): React.ReactElement => (
631
          <>
632
            <Form id="form" data-c-margin="bottom(normal)">
633
              <FastField
634
                id="teamSize"
635
                type="number"
636
                name="teamSize"
637
                component={NumberInput}
638
                required
639
                min={1}
640
                grid="tl(1of2)"
641
                label={intl.formatMessage(formMessages.teamSizeLabel)}
642
                placeholder={intl.formatMessage(
643
                  formMessages.teamSizePlaceholder,
644
                )}
645
              />
646
              <CheckboxGroup
647
                id="physicalEnv"
648
                label={intl.formatMessage(formMessages.physicalEnvLabel)}
649
                grid="base(1of1)"
650
                value={values.physicalEnv}
651
                error={errors.physicalEnv}
652
                touched={touched.physicalEnv}
653
                onChange={setFieldValue}
654
                onBlur={setFieldTouched}
655
              >
656
                {phyEnvData &&
657
                  phyEnvData.map(
658
                    ({ name, label }): React.ReactElement => {
659
                      return (
660
                        <Field
661
                          key={name}
662
                          id={name}
663
                          name={name}
664
                          label={label}
665
                          component={CheckboxInput}
666
                          grid="base(1of2)"
667
                        />
668
                      );
669
                    },
670
                  )}
671
              </CheckboxGroup>
672
              <CheckboxGroup
673
                id="technology"
674
                label={intl.formatMessage(formMessages.technologyLabel)}
675
                grid="base(1of1)"
676
                value={values.technology}
677
                error={errors.technology}
678
                touched={touched.technology}
679
                onChange={setFieldValue}
680
                onBlur={setFieldTouched}
681
              >
682
                {techData &&
683
                  techData.map(
684
                    ({ name, label }): React.ReactElement => {
685
                      return (
686
                        <Field
687
                          key={name}
688
                          id={name}
689
                          name={name}
690
                          label={label}
691
                          component={CheckboxInput}
692
                          grid="base(1of2)"
693
                        />
694
                      );
695
                    },
696
                  )}
697
              </CheckboxGroup>
698
              <CheckboxGroup
699
                id="amenities"
700
                label={intl.formatMessage(formMessages.amenitiesLabel)}
701
                grid="base(1of1)"
702
                value={values.amenities}
703
                error={errors.amenities}
704
                touched={touched.amenities}
705
                onChange={setFieldValue}
706
                onBlur={setFieldTouched}
707
              >
708
                {amenitiesData &&
709
                  amenitiesData.map(
710
                    ({ name, label }): React.ReactElement => {
711
                      return (
712
                        <Field
713
                          key={name}
714
                          id={name}
715
                          name={name}
716
                          label={label}
717
                          component={CheckboxInput}
718
                          grid="base(1of2)"
719
                        />
720
                      );
721
                    },
722
                  )}
723
              </CheckboxGroup>
724
              <p
725
                data-c-margin="bottom(normal) top(normal)"
726
                data-c-font-weight="bold"
727
              >
728
                {intl.formatMessage(formMessages.moreOnWorkEnv)}
729
              </p>
730
              <p data-c-margin="bottom(normal)">
731
                {intl.formatMessage(formMessages.thisIsOptional)}
732
              </p>
733
              <p data-c-margin="bottom(normal)">
734
                {intl.formatMessage(formMessages.moreOnWorkEnvSubtext)}
735
              </p>
736
              <FastField
737
                type="textarea"
738
                id="environment_description"
739
                name="envDescription"
740
                label={intl.formatMessage(formMessages.moreOnWorkEnvLabel)}
741
                placeholder={intl.formatMessage(
742
                  formMessages.moreOnWorkEnvPlaceholder,
743
                )}
744
                component={TextAreaInput}
745
                grid="base(1of2)"
746
              />
747
              <div data-c-grid-item="base(1of1)">
748
                <h4
749
                  data-c-font-size="h4"
750
                  data-c-margin="top(double) bottom(normal)"
751
                >
752
                  {intl.formatMessage(formMessages.culture)}
753
                </h4>
754
                <p data-c-margin="bottom(normal)">
755
                  <FormattedMessage
756
                    id="jobBuilder.workEnv.cultureSubtext1"
757
                    defaultMessage="Now let applicants know more about the personality of your team and the type of work that you usually do."
758
                    description="Subtext 1 displayed of the our culture section."
759
                  />
760
                </p>
761
                <p data-c-margin="bottom(normal)">
762
                  {intl.formatMessage(formMessages.cultureSubtext2)}
763
                </p>
764
              </div>
765
              {renderRadioWithContext(
766
                intl,
767
                touched,
768
                errors,
769
                values,
770
                "culturePace",
771
                intl.formatMessage(formMessages.fastPacedSteadyLabel),
772
                culturePaceList,
773
              )}
774
              {renderRadioWithContext(
775
                intl,
776
                touched,
777
                errors,
778
                values,
779
                "management",
780
                intl.formatMessage(formMessages.managementLabel),
781
                managementList,
782
              )}
783
              {renderRadioWithContext(
784
                intl,
785
                touched,
786
                errors,
787
                values,
788
                "experimental",
789
                intl.formatMessage(formMessages.experimentalLabel),
790
                experimentalList,
791
              )}
792
              {renderRadioWithContext(
793
                intl,
794
                touched,
795
                errors,
796
                values,
797
                "facing",
798
                intl.formatMessage(formMessages.facingLabel),
799
                facingList,
800
              )}
801
              {renderRadioWithContext(
802
                intl,
803
                touched,
804
                errors,
805
                values,
806
                "collaborativeness",
807
                intl.formatMessage(formMessages.collaborativeLabel),
808
                collaborativenessList,
809
              )}
810
              <div data-c-grid-item="base(1of1)">
811
                <p
812
                  data-c-margin="bottom(normal) top(normal)"
813
                  data-c-font-weight="bold"
814
                >
815
                  {intl.formatMessage(formMessages.cultureSummary)}
816
                </p>
817
                <p data-c-margin="bottom(normal)">
818
                  {intl.formatMessage(formMessages.cultureSummarySubtext)}
819
                </p>
820
                <ContextBlockItem subtext={buildCultureSummary(values)} />
821
                <div
822
                  data-c-alignment="base(centre) tl(right)"
823
                  data-c-margin="top(normal)"
824
                >
825
                  <CopyToClipboardButton
826
                    actionText={
827
                      <FormattedMessage
828
                        id="button.copyToClipboard"
829
                        defaultMessage="Copy to Clipboard"
830
                        description="Button to copy text to clipboard."
831
                      />
832
                    }
833
                    postActionText={
834
                      <FormattedMessage
835
                        id="button.copied"
836
                        defaultMessage="Copied!"
837
                        description="Confirmation for Button to copy text to clipboard."
838
                      />
839
                    }
840
                    textToCopy={buildCultureSummary(values)}
841
                  />
842
                </div>
843
              </div>
844
              <FastField
845
                type="textarea"
846
                id="custom_culture_summary"
847
                name="cultureSummary"
848
                label={intl.formatMessage(
849
                  formMessages.customCultureSummaryLabel,
850
                )}
851
                placeholder={intl.formatMessage(
852
                  formMessages.customCultureSummaryPlaceholder,
853
                )}
854
                component={TextAreaInput}
855
                grid="base(1of1)"
856
              />
857
              <p data-c-margin="bottom(normal)" data-c-font-weight="bold">
858
                {intl.formatMessage(formMessages.specialWorkCulture)}
859
              </p>
860
              <p data-c-margin="bottom(normal)">
861
                {intl.formatMessage(formMessages.thisIsOptional)}
862
              </p>
863
              <p data-c-margin="bottom(normal)">
864
                {intl.formatMessage(formMessages.specialWorkCultureSubtext)}
865
              </p>
866
              <FastField
867
                type="textarea"
868
                id="more_culture_summary"
869
                name="moreCultureSummary"
870
                label={intl.formatMessage(formMessages.specialWorkCultureLabel)}
871
                placeholder={intl.formatMessage(
872
                  formMessages.textAreaPlaceholder1,
873
                )}
874
                component={TextAreaInput}
875
                grid="base(1of1)"
876
              />
877
              <div data-c-grid="gutter" data-c-grid-item="base(1of1)">
878
                <div data-c-grid-item="base(1of1)">
879
                  <hr data-c-margin="top(normal) bottom(normal)" />
880
                </div>
881
                <div
882
                  data-c-alignment="base(centre) tp(left)"
883
                  data-c-grid-item="tp(1of2)"
884
                >
885
                  <button
886
                    data-c-button="outline(c2)"
887
                    data-c-radius="rounded"
888
                    type="button"
889
                    disabled={isSubmitting}
890
                    onClick={(): void => {
891
                      updateValuesAndReturn(values);
892
                    }}
893
                  >
894
                    <FormattedMessage
895
                      id="jobBuilder.workEnv.saveAndReturnButtonLabel"
896
                      defaultMessage="Save & Return to Job Details"
897
                      description="Label for Save & Return button on Work Environment form."
898
                    />
899
                  </button>
900
                </div>
901
                <div
902
                  data-c-alignment="base(centre) tp(right)"
903
                  data-c-grid-item="tp(1of2)"
904
                >
905
                  <button
906
                    data-c-button="solid(c1)"
907
                    data-c-radius="rounded"
908
                    type="submit"
909
                    disabled={isSubmitting}
910
                  >
911
                    <FormattedMessage
912
                      id="jobBuilder.workEnv.submitButtonLabel"
913
                      defaultMessage="Save & Preview"
914
                      description="Label for work environment submit button."
915
                    />
916
                  </button>
917
                </div>
918
              </div>
919
            </Form>
920
            <JobWorkEnvModal
921
              modalConfirm={(): void => {
922
                setIsModalVisible(false);
923
                handleModalConfirm();
924
              }}
925
              modalCancel={(): void => {
926
                setIsModalVisible(false);
927
                handleModalCancel();
928
              }}
929
              isVisible={isModalVisible}
930
              parentElement={modalParentRef.current}
931
              values={values}
932
              cultureSummary={
933
                values.cultureSummary || buildCultureSummary(values)
934
              }
935
              jobIsComplete={jobIsComplete}
936
              handleSkipToReview={(): void => {
937
                handleSkipToReview().finally((): void => {
938
                  setIsModalVisible(false);
939
                });
940
              }}
941
            />
942
          </>
943
        )}
944
      </Formik>
945
    </div>
946
  );
947
};
948
949
export default JobWorkEnv;
950