@oneblink/apps-react 13.0.0-beta.4 → 13.0.0-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/OneBlinkFormBase.js +331 -205
  2. package/dist/OneBlinkFormBase.js.map +1 -1
  3. package/dist/components/renderer/LookupNotification.js +7 -4
  4. package/dist/components/renderer/LookupNotification.js.map +1 -1
  5. package/dist/components/renderer/PageFormElements.js +8 -3
  6. package/dist/components/renderer/PageFormElements.js.map +1 -1
  7. package/dist/components/renderer/ReverseGeocode.js +2 -0
  8. package/dist/components/renderer/ReverseGeocode.js.map +1 -1
  9. package/dist/form-elements/FormElementCalculation.js +1 -0
  10. package/dist/form-elements/FormElementCalculation.js.map +1 -1
  11. package/dist/form-elements/FormElementForm.d.ts +2 -2
  12. package/dist/form-elements/FormElementForm.js +4 -3
  13. package/dist/form-elements/FormElementForm.js.map +1 -1
  14. package/dist/form-elements/FormElementLookupButton.js +3 -2
  15. package/dist/form-elements/FormElementLookupButton.js.map +1 -1
  16. package/dist/form-elements/FormElementRepeatableSet.js +6 -4
  17. package/dist/form-elements/FormElementRepeatableSet.js.map +1 -1
  18. package/dist/form-elements/FormElementSection.js +2 -2
  19. package/dist/form-elements/FormElementSection.js.map +1 -1
  20. package/dist/form-elements/FormElementSummary.js +2 -0
  21. package/dist/form-elements/FormElementSummary.js.map +1 -1
  22. package/dist/hooks/useFormElementOptions.js +2 -0
  23. package/dist/hooks/useFormElementOptions.js.map +1 -1
  24. package/dist/hooks/useFormIsDirty.d.ts +38 -0
  25. package/dist/hooks/useFormIsDirty.js +78 -0
  26. package/dist/hooks/useFormIsDirty.js.map +1 -0
  27. package/dist/hooks/useFormSubmissionAutoSaveState.d.ts +2 -9
  28. package/dist/hooks/useFormSubmissionAutoSaveState.js +4 -2
  29. package/dist/hooks/useFormSubmissionAutoSaveState.js.map +1 -1
  30. package/dist/hooks/useInjectPages.d.ts +2 -1
  31. package/dist/hooks/useInjectPages.js.map +1 -1
  32. package/dist/hooks/useLookupNotification.d.ts +1 -0
  33. package/dist/hooks/useLookupNotification.js.map +1 -1
  34. package/dist/hooks/useLookups.d.ts +3 -3
  35. package/dist/hooks/useLookups.js +7 -4
  36. package/dist/hooks/useLookups.js.map +1 -1
  37. package/dist/index.d.ts +1 -0
  38. package/dist/index.js +1 -0
  39. package/dist/index.js.map +1 -1
  40. package/dist/types/form.d.ts +17 -3
  41. package/dist/types/form.js.map +1 -1
  42. package/package.json +2 -2
@@ -47,6 +47,37 @@ import { ValidationIconConfigurationContext } from './hooks/useValidationIconCon
47
47
  import { Clickable } from './components/Clickable';
48
48
  import { EditableFormElementIdsContext } from './hooks/useEditableFormElementIds';
49
49
  import { useRegisterFormSubmissionAttempt } from './hooks/useFormSubmissionAttempt';
50
+ import { useRegisterFormIsDirty, FormMarkDirtyContextProvider, } from './hooks/useFormIsDirty';
51
+ var AttachmentUploadStatus;
52
+ (function (AttachmentUploadStatus) {
53
+ AttachmentUploadStatus["ATTACHMENTS_UPLOADED"] = "ATTACHMENTS_UPLOADED";
54
+ AttachmentUploadStatus["ATTACHMENTS_UPLOAD_BLOCKING"] = "ATTACHMENTS_UPLOAD_BLOCKING";
55
+ AttachmentUploadStatus["ATTACHMENTS_UPLOAD_NON_BLOCKING"] = "ATTACHMENTS_UPLOAD_NON_BLOCKING";
56
+ })(AttachmentUploadStatus || (AttachmentUploadStatus = {}));
57
+ var SubmissionPreparationStatus;
58
+ (function (SubmissionPreparationStatus) {
59
+ SubmissionPreparationStatus["OFFLINE_SUBMISSION"] = "OFFLINE_SUBMISSION";
60
+ SubmissionPreparationStatus["SUBMISSION_READY"] = "SUBMISSION_READY";
61
+ })(SubmissionPreparationStatus || (SubmissionPreparationStatus = {}));
62
+ const idlePhase = { status: 'idle' };
63
+ function HostPreparationEffect({ continueWithAttachments, prepareSubmission, onResult, }) {
64
+ // prepareSubmission is in the dep array so that an environment change
65
+ // (e.g. going offline) that recreates prepareSubmission will re-trigger
66
+ // preparation with the updated closure. The cleanup function cancels
67
+ // the prior in-flight call before the new one starts.
68
+ React.useEffect(() => {
69
+ let cancelled = false;
70
+ prepareSubmission(continueWithAttachments).then((result) => {
71
+ if (!cancelled) {
72
+ onResult(result);
73
+ }
74
+ });
75
+ return () => {
76
+ cancelled = true;
77
+ };
78
+ }, [continueWithAttachments, onResult, prepareSubmission]);
79
+ return null;
80
+ }
50
81
  function OneBlinkFormBase({ googleMapsApiKey, abnLookupAuthenticationGuid, captchaSiteKey, definition, disabled, isPreview, submission, isReadOnly, onCancel, onSubmit, onSaveDraft, setFormSubmission, buttons, validationIcon, primaryColour, attachmentRetentionInDays, isPendingQueueEnabled, handleNavigateAway, isInfoPage: isInfoPageProp, lastElementUpdated, executedLookups, task, taskGroup, taskGroupInstance, onUploadAttachment, captchaType, shouldUseNavigableValidationErrorsNotification = true, navigableValidationErrorsNotificationSettings, replaceInjectablesOverrides, sectionState, scrollToTopOfPage, getCurrentSubmissionDuration, onBeforeUnload, audience, editableFormElementIds, }) {
51
82
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
52
83
  const isOffline = useIsOffline();
@@ -145,6 +176,8 @@ function OneBlinkFormBase({ googleMapsApiKey, abnLookupAuthenticationGuid, captc
145
176
  });
146
177
  const [promptOfflineSubmissionAttempt, setPromptOfflineSubmissionAttempt] = React.useState(false);
147
178
  const [promptUploadingAttachments, setPromptUploadingAttachments] = React.useState(false);
179
+ const [hostAttemptPhase, setHostAttemptPhase] = React.useState(idlePhase);
180
+ const [hostAttemptResolver, setHostAttemptResolver] = React.useState(null);
148
181
  const handleBlockedNavigation = React.useCallback((location) => {
149
182
  setUnsavedChangesState((current) => ({
150
183
  ...current,
@@ -323,7 +356,7 @@ function OneBlinkFormBase({ googleMapsApiKey, abnLookupAuthenticationGuid, captc
323
356
  // be taken care of by a pending queue if enabled, otherwise
324
357
  // the user will be prompted to try again or save a draft.
325
358
  if (isOffline) {
326
- return true;
359
+ return AttachmentUploadStatus.ATTACHMENTS_UPLOADED;
327
360
  }
328
361
  const attachmentsAreUploading = attachmentsService.checkIfAttachmentsAreUploading(definition, submission);
329
362
  if (attachmentsAreUploading) {
@@ -336,14 +369,13 @@ function OneBlinkFormBase({ googleMapsApiKey, abnLookupAuthenticationGuid, captc
336
369
  pauseOnHover: true,
337
370
  closeOnClick: true,
338
371
  });
339
- return false;
372
+ return AttachmentUploadStatus.ATTACHMENTS_UPLOAD_BLOCKING;
340
373
  }
341
374
  else {
342
- setPromptUploadingAttachments(true);
343
- return false;
375
+ return AttachmentUploadStatus.ATTACHMENTS_UPLOAD_NON_BLOCKING;
344
376
  }
345
377
  }
346
- return true;
378
+ return AttachmentUploadStatus.ATTACHMENTS_UPLOADED;
347
379
  }, [definition, isOffline, isPendingQueueEnabled, isUsingFormsKey]);
348
380
  const checkBsbsCanBeSubmitted = React.useCallback((submission) => {
349
381
  return !checkBsbsAreInvalid(definition, submission);
@@ -416,15 +448,29 @@ function OneBlinkFormBase({ googleMapsApiKey, abnLookupAuthenticationGuid, captc
416
448
  if (!checkBsbsCanBeSubmitted(submissionData.submission)) {
417
449
  return;
418
450
  }
419
- if (!continueWhilstAttachmentsAreUploading &&
420
- !checkAttachmentsCanBeSubmitted(submissionData.submission)) {
421
- return;
451
+ if (!continueWhilstAttachmentsAreUploading) {
452
+ const attachmentStatus = checkAttachmentsCanBeSubmitted(submissionData.submission);
453
+ switch (attachmentStatus) {
454
+ case AttachmentUploadStatus.ATTACHMENTS_UPLOAD_BLOCKING:
455
+ // The submitter cannot upload attachments in the background and must wait for them to upload before submitting
456
+ return;
457
+ case AttachmentUploadStatus.ATTACHMENTS_UPLOAD_NON_BLOCKING:
458
+ // We can display a prompt allowing the submitter to upload attachments in the background
459
+ return {
460
+ status: attachmentStatus,
461
+ };
462
+ case AttachmentUploadStatus.ATTACHMENTS_UPLOADED:
463
+ break;
464
+ default:
465
+ return;
466
+ }
422
467
  }
423
468
  if (captchaType === 'INVISIBLE') {
424
469
  if (captchasRef.current.length) {
425
470
  if (isOffline) {
426
- setPromptOfflineSubmissionAttempt(true);
427
- return;
471
+ return {
472
+ status: SubmissionPreparationStatus.OFFLINE_SUBMISSION,
473
+ };
428
474
  }
429
475
  const tokenResults = await Promise.allSettled(captchasRef.current.map((captcha) => captcha.executeAsync()));
430
476
  const captchaTokens = [];
@@ -465,10 +511,14 @@ function OneBlinkFormBase({ googleMapsApiKey, abnLookupAuthenticationGuid, captc
465
511
  }
466
512
  if (isOffline && !isPendingQueueEnabled) {
467
513
  console.log('User is offline and form does not support a pending queue');
468
- setPromptOfflineSubmissionAttempt(true);
469
- return;
514
+ return {
515
+ status: SubmissionPreparationStatus.OFFLINE_SUBMISSION,
516
+ };
470
517
  }
471
- return submissionData;
518
+ return {
519
+ status: SubmissionPreparationStatus.SUBMISSION_READY,
520
+ submissionData: submissionData,
521
+ };
472
522
  }, [
473
523
  attachmentRetentionInDays,
474
524
  captchaType,
@@ -483,23 +533,54 @@ function OneBlinkFormBase({ googleMapsApiKey, abnLookupAuthenticationGuid, captc
483
533
  setFormSubmission,
484
534
  shouldUseNavigableValidationErrorsNotification,
485
535
  ]);
486
- const attemptFormSubmission = React.useCallback(async () => {
487
- setHasAttemptedSubmit(true);
488
- setIsPreparingToSubmit(true);
489
- try {
490
- if (!(await prepareSubmission(false))) {
491
- return false;
536
+ const handleHostPreparationResult = React.useCallback((result) => {
537
+ if (!result) {
538
+ setHostAttemptPhase({ status: 'resolved', result: false });
539
+ return;
540
+ }
541
+ switch (result.status) {
542
+ case AttachmentUploadStatus.ATTACHMENTS_UPLOAD_NON_BLOCKING: {
543
+ setPromptUploadingAttachments(true);
544
+ setHostAttemptPhase({ status: 'prompt-attachments' });
545
+ break;
546
+ }
547
+ case SubmissionPreparationStatus.OFFLINE_SUBMISSION: {
548
+ setPromptOfflineSubmissionAttempt(true);
549
+ setHostAttemptPhase((current) => ({
550
+ status: 'prompt-offline',
551
+ continueWithAttachments: current.status === 'preparing'
552
+ ? current.continueWithAttachments
553
+ : false,
554
+ }));
555
+ break;
556
+ }
557
+ case SubmissionPreparationStatus.SUBMISSION_READY: {
558
+ setHostAttemptPhase({
559
+ status: 'resolved',
560
+ result: allowNavigationAfterHostAction,
561
+ });
562
+ break;
492
563
  }
493
- // The host must call this after it has persisted the edits. Calling it
494
- // here would let the user cancel a later confirmation dialog and leave
495
- // without being prompted.
496
- return allowNavigationAfterHostAction;
497
564
  }
498
- finally {
565
+ }, [allowNavigationAfterHostAction]);
566
+ const attemptFormSubmission = React.useCallback(() => {
567
+ setHasAttemptedSubmit(true);
568
+ setIsPreparingToSubmit(true);
569
+ setHostAttemptPhase({ status: 'preparing', continueWithAttachments: false });
570
+ return new Promise((resolve) => {
571
+ setHostAttemptResolver({ resolve });
572
+ });
573
+ }, []);
574
+ React.useEffect(() => {
575
+ if (hostAttemptPhase.status === 'resolved') {
499
576
  setIsPreparingToSubmit(false);
577
+ hostAttemptResolver === null || hostAttemptResolver === void 0 ? void 0 : hostAttemptResolver.resolve(hostAttemptPhase.result);
578
+ setHostAttemptResolver(null);
579
+ setHostAttemptPhase(idlePhase);
500
580
  }
501
- }, [allowNavigationAfterHostAction, prepareSubmission]);
581
+ }, [hostAttemptPhase, hostAttemptResolver]);
502
582
  useRegisterFormSubmissionAttempt(editableFormElementIds === undefined ? undefined : attemptFormSubmission);
583
+ useRegisterFormIsDirty(definition.id, isDirty);
503
584
  const handleSubmit = React.useCallback(async (event, continueWhilstAttachmentsAreUploading) => {
504
585
  event.preventDefault();
505
586
  // Approvers are not shown a submit button, so reaching here means the
@@ -510,39 +591,60 @@ function OneBlinkFormBase({ googleMapsApiKey, abnLookupAuthenticationGuid, captc
510
591
  return;
511
592
  setHasAttemptedSubmit(true);
512
593
  setIsPreparingToSubmit(true);
513
- const submissionData = await prepareSubmission(continueWhilstAttachmentsAreUploading);
514
- if (!submissionData) {
594
+ const submissionResult = await prepareSubmission(continueWhilstAttachmentsAreUploading);
595
+ if (!submissionResult) {
515
596
  setIsPreparingToSubmit(false);
516
597
  return;
517
598
  }
518
- allowNavigation();
519
- // transplant injected options on the definition
520
- const elementsWithInjectedOptions = injectOptionsAcrossAllElements({
521
- contextElements: definition.elements,
522
- elements: definition.elements,
523
- submission: submissionData.submission,
524
- taskContext: taskContextValue,
525
- userProfile: userProfileForInjectables,
526
- });
527
- setIsPreparingToSubmit(false);
528
- resetRecaptchas();
529
- onSubmit({
530
- definition: {
531
- ...definition,
532
- elements: elementsWithInjectedOptions,
533
- },
534
- submission: submissionData.submission,
535
- recaptchas: submissionData.captchaTokens.map((token) => ({
536
- token,
537
- siteKey: captchaSiteKey,
538
- })),
539
- });
540
- sendGoogleAnalyticsEvent('oneblink_form_submit', {
541
- formId: definition.id,
542
- formName: definition.name,
543
- lastElementUpdated: getElementDisplayNameForAnalyticsEvent(lastElementUpdated),
544
- durationUntilSubmission: getCurrentSubmissionDuration === null || getCurrentSubmissionDuration === void 0 ? void 0 : getCurrentSubmissionDuration(),
545
- });
599
+ switch (submissionResult.status) {
600
+ case AttachmentUploadStatus.ATTACHMENTS_UPLOAD_NON_BLOCKING: {
601
+ setPromptUploadingAttachments(true);
602
+ setIsPreparingToSubmit(false);
603
+ return;
604
+ }
605
+ case SubmissionPreparationStatus.OFFLINE_SUBMISSION: {
606
+ setPromptOfflineSubmissionAttempt(true);
607
+ setIsPreparingToSubmit(false);
608
+ return;
609
+ }
610
+ case SubmissionPreparationStatus.SUBMISSION_READY: {
611
+ allowNavigation();
612
+ const submissionData = submissionResult.submissionData;
613
+ // transplant injected options on the definition
614
+ const elementsWithInjectedOptions = injectOptionsAcrossAllElements({
615
+ contextElements: definition.elements,
616
+ elements: definition.elements,
617
+ submission: submissionData.submission,
618
+ taskContext: taskContextValue,
619
+ userProfile: userProfileForInjectables,
620
+ });
621
+ setIsPreparingToSubmit(false);
622
+ resetRecaptchas();
623
+ onSubmit({
624
+ definition: {
625
+ ...definition,
626
+ elements: elementsWithInjectedOptions,
627
+ },
628
+ submission: submissionData.submission,
629
+ recaptchas: submissionData.captchaTokens.map((token) => ({
630
+ token,
631
+ siteKey: captchaSiteKey,
632
+ })),
633
+ });
634
+ sendGoogleAnalyticsEvent('oneblink_form_submit', {
635
+ formId: definition.id,
636
+ formName: definition.name,
637
+ lastElementUpdated: getElementDisplayNameForAnalyticsEvent(lastElementUpdated),
638
+ durationUntilSubmission: getCurrentSubmissionDuration === null || getCurrentSubmissionDuration === void 0 ? void 0 : getCurrentSubmissionDuration(),
639
+ });
640
+ return;
641
+ }
642
+ default: {
643
+ const never = submissionResult;
644
+ setIsPreparingToSubmit(false);
645
+ return never;
646
+ }
647
+ }
546
648
  }, [
547
649
  disabled,
548
650
  isReadOnly,
@@ -569,9 +671,18 @@ function OneBlinkFormBase({ googleMapsApiKey, abnLookupAuthenticationGuid, captc
569
671
  if (!checkBsbAreValidating(submission)) {
570
672
  return;
571
673
  }
572
- if (!continueWhilstAttachmentsAreUploading &&
573
- !checkAttachmentsCanBeSubmitted(submission)) {
574
- return;
674
+ if (!continueWhilstAttachmentsAreUploading) {
675
+ const attachmentCheckResult = checkAttachmentsCanBeSubmitted(submission);
676
+ if (attachmentCheckResult ===
677
+ AttachmentUploadStatus.ATTACHMENTS_UPLOAD_NON_BLOCKING) {
678
+ setPromptUploadingAttachments(true);
679
+ return;
680
+ }
681
+ if (attachmentCheckResult ===
682
+ AttachmentUploadStatus.ATTACHMENTS_UPLOAD_BLOCKING) {
683
+ // The submitter cannot upload attachments in the background and must wait for them to upload before saving draft
684
+ return;
685
+ }
575
686
  }
576
687
  onSaveDraft({
577
688
  definition,
@@ -596,6 +707,13 @@ function OneBlinkFormBase({ googleMapsApiKey, abnLookupAuthenticationGuid, captc
596
707
  ]);
597
708
  const handleContinueWithAttachments = React.useCallback((e) => {
598
709
  setPromptUploadingAttachments(false);
710
+ if (hostAttemptPhase.status === 'prompt-attachments') {
711
+ setHostAttemptPhase({
712
+ status: 'preparing',
713
+ continueWithAttachments: true,
714
+ });
715
+ return;
716
+ }
599
717
  if (hasAttemptedSubmit) {
600
718
  handleSubmit(e, true);
601
719
  }
@@ -604,121 +722,129 @@ function OneBlinkFormBase({ googleMapsApiKey, abnLookupAuthenticationGuid, captc
604
722
  }
605
723
  }, [
606
724
  handleSubmit,
607
- setPromptUploadingAttachments,
725
+ hostAttemptPhase.status,
608
726
  hasAttemptedSubmit,
609
727
  handleSaveDraft,
610
728
  ]);
611
729
  const handleWaitForAttachments = React.useCallback(() => {
612
730
  setPromptUploadingAttachments(false);
613
- }, [setPromptUploadingAttachments]);
731
+ if (hostAttemptPhase.status === 'prompt-attachments') {
732
+ setHostAttemptPhase({ status: 'resolved', result: false });
733
+ }
734
+ }, [hostAttemptPhase.status]);
735
+ const handleCancelOfflineSubmission = React.useCallback(() => {
736
+ setPromptOfflineSubmissionAttempt(false);
737
+ if (hostAttemptPhase.status === 'prompt-offline') {
738
+ setHostAttemptPhase({ status: 'resolved', result: false });
739
+ }
740
+ }, [hostAttemptPhase.status]);
741
+ const handleRetryOfflineSubmission = React.useCallback((e) => {
742
+ setPromptOfflineSubmissionAttempt(false);
743
+ if (hostAttemptPhase.status === 'prompt-offline') {
744
+ setHostAttemptPhase({
745
+ status: 'preparing',
746
+ continueWithAttachments: hostAttemptPhase.continueWithAttachments,
747
+ });
748
+ }
749
+ else {
750
+ handleSubmit(e, false);
751
+ }
752
+ }, [
753
+ handleSubmit,
754
+ hostAttemptPhase,
755
+ ]);
614
756
  // #endregion
615
757
  //
616
758
  //
617
759
  //
618
760
  //
619
- // #region Lookups
620
- const { handlePagesLookupResult } = useLookups(definition.id, setFormSubmission);
621
- // #endregion
761
+ // #region Submission/Definition Changes
762
+ const markFormDirty = React.useCallback(() => {
763
+ setUnsavedChangesState((current) => ({
764
+ ...current,
765
+ isDirty: true,
766
+ }));
767
+ }, []);
622
768
  //
623
769
  //
770
+ // #region Lookups
771
+ const { handlePagesLookupResult } = useLookups(definition.id, setFormSubmission, markFormDirty);
772
+ // #endregion
624
773
  //
625
774
  //
626
- // #region Submission/Definition Changes
627
- const handleChange = React.useCallback((element, { value, executedLookups, deleteSection, sectionState }) => {
775
+ const handleChange = React.useCallback((element, { value, executedLookups, deleteSection, sectionState, isDerivedChange }) => {
628
776
  if (
629
- //This will ensure on a read only form that the summary and calculation elements
630
- //can still be displayed as it needs handleChange so it can render
631
- //due to the dynamic nature of the summary element.
632
- (disabled &&
633
- element.type !== 'summary' &&
634
- element.type !== 'calculation') ||
777
+ // Disabled forms still need derived writers (calculation, summary, …)
778
+ // so those elements can recompute and display from the current model.
779
+ (disabled && !isDerivedChange) ||
635
780
  element.type === 'page') {
636
781
  return;
637
782
  }
638
- switch (element.type) {
639
- case 'section': {
640
- setFormSubmission((currentFormSubmission) => {
641
- const currentSectionState = currentFormSubmission.sectionState || [];
642
- const existingSectionIndex = currentSectionState.findIndex((section) => section.id === element.id);
643
- const sectionIsInState = existingSectionIndex >= 0;
644
- let newSectionState;
645
- if (sectionIsInState && deleteSection) {
646
- newSectionState = currentSectionState.filter((section) => section.id !== element.id);
647
- }
648
- else if (sectionIsInState) {
649
- // Update state of the section
650
- newSectionState = currentSectionState.map((section, index) => index === existingSectionIndex
651
- ? {
652
- ...section,
653
- state: section.state === 'COLLAPSED'
654
- ? 'EXPANDED'
655
- : 'COLLAPSED',
656
- }
657
- : section);
658
- }
659
- else {
660
- // Add the section to state
661
- newSectionState = [
662
- ...currentSectionState,
663
- {
664
- id: element.id,
665
- state: element.isCollapsed ? 'EXPANDED' : 'COLLAPSED',
666
- },
667
- ];
668
- }
669
- return {
670
- ...currentFormSubmission,
671
- sectionState: newSectionState,
672
- };
673
- });
674
- break;
675
- }
676
- // Don't update the last element updated for elements the user cannot set the value of
677
- case 'summary':
678
- case 'calculation': {
679
- setFormSubmission((currentFormSubmission) => ({
680
- ...currentFormSubmission,
681
- submission: {
682
- ...currentFormSubmission.submission,
683
- [element.name]: typeof value === 'function'
684
- ? value(currentFormSubmission.submission[element.name])
685
- : value,
686
- },
687
- }));
688
- break;
689
- }
690
- default: {
691
- setUnsavedChangesState((current) => ({
692
- ...current,
693
- isDirty: true,
694
- }));
695
- setFormSubmission((currentFormSubmission) => {
696
- var _a;
697
- return {
698
- ...currentFormSubmission,
699
- submission: {
700
- ...currentFormSubmission.submission,
701
- [element.name]: typeof value === 'function'
702
- ? value(currentFormSubmission.submission[element.name])
703
- : value,
704
- },
705
- lastElementUpdated: element,
706
- executedLookups: {
707
- ...currentFormSubmission.executedLookups,
708
- [element.name]: typeof executedLookups === 'function'
709
- ? executedLookups((_a = currentFormSubmission.executedLookups) === null || _a === void 0 ? void 0 : _a[element.name])
710
- : executedLookups,
783
+ if (element.type === 'section') {
784
+ setFormSubmission((currentFormSubmission) => {
785
+ const currentSectionState = currentFormSubmission.sectionState || [];
786
+ const existingSectionIndex = currentSectionState.findIndex((section) => section.id === element.id);
787
+ const sectionIsInState = existingSectionIndex >= 0;
788
+ let newSectionState;
789
+ if (sectionIsInState && deleteSection) {
790
+ newSectionState = currentSectionState.filter((section) => section.id !== element.id);
791
+ }
792
+ else if (sectionIsInState) {
793
+ // Update state of the section
794
+ newSectionState = currentSectionState.map((section, index) => index === existingSectionIndex
795
+ ? {
796
+ ...section,
797
+ state: section.state === 'COLLAPSED' ? 'EXPANDED' : 'COLLAPSED',
798
+ }
799
+ : section);
800
+ }
801
+ else {
802
+ // Add the section to state
803
+ newSectionState = [
804
+ ...currentSectionState,
805
+ {
806
+ id: element.id,
807
+ state: element.isCollapsed ? 'EXPANDED' : 'COLLAPSED',
711
808
  },
712
- sectionState: sectionState
713
- ? typeof sectionState === 'function'
714
- ? sectionState(currentFormSubmission.sectionState)
715
- : sectionState
716
- : currentFormSubmission.sectionState,
717
- };
718
- });
719
- }
809
+ ];
810
+ }
811
+ return {
812
+ ...currentFormSubmission,
813
+ sectionState: newSectionState,
814
+ };
815
+ });
816
+ return;
817
+ }
818
+ if (!isDerivedChange) {
819
+ markFormDirty();
720
820
  }
721
- }, [disabled, setFormSubmission]);
821
+ setFormSubmission((currentFormSubmission) => {
822
+ var _a;
823
+ return {
824
+ ...currentFormSubmission,
825
+ submission: {
826
+ ...currentFormSubmission.submission,
827
+ [element.name]: typeof value === 'function'
828
+ ? value(currentFormSubmission.submission[element.name])
829
+ : value,
830
+ },
831
+ lastElementUpdated: isDerivedChange
832
+ ? currentFormSubmission.lastElementUpdated
833
+ : element,
834
+ executedLookups: {
835
+ ...currentFormSubmission.executedLookups,
836
+ [element.name]: typeof executedLookups === 'function'
837
+ ? executedLookups((_a = currentFormSubmission.executedLookups) === null || _a === void 0 ? void 0 : _a[element.name])
838
+ : executedLookups,
839
+ },
840
+ sectionState: sectionState
841
+ ? typeof sectionState === 'function'
842
+ ? sectionState(currentFormSubmission.sectionState)
843
+ : sectionState
844
+ : currentFormSubmission.sectionState,
845
+ };
846
+ }, { isDerivedChange });
847
+ }, [disabled, markFormDirty, setFormSubmission]);
722
848
  // #endregion
723
849
  //
724
850
  //
@@ -768,58 +894,58 @@ function OneBlinkFormBase({ googleMapsApiKey, abnLookupAuthenticationGuid, captc
768
894
  if (conditionalLogicError) {
769
895
  return (_jsx(_Fragment, { children: _jsxs("div", { className: "has-text-centered", children: [_jsx(MaterialIcon, { className: "has-text-warning icon-x-large", children: "error" }), _jsx("h3", { className: "title is-3", children: "Bad Form Configuration" }), _jsx("p", { className: "cypress-conditional-logic-error-message", children: conditionalLogicError.message }), _jsx("p", { className: "has-text-grey", children: localisationService.formatDatetimeLong(new Date()) })] }) }));
770
896
  }
771
- return (_jsx(ThemeProvider, { theme: theme, children: _jsx(LocalizationProvider, { dateAdapter: AdapterDateFns, children: _jsx(ReplaceInjectablesOverridesContext.Provider, { value: replaceInjectablesOverrides, children: _jsx(FormDefinitionContext.Provider, { value: definition, children: _jsx(FormElementOptionsContextProvider, { formIsReadOnly: isReadOnly, children: _jsx(FormElementLookupsContextProvider, { children: _jsx(OneBlinkFormContainerContext.Provider, { value: obFormContainerHTMLElementRef, children: _jsxs("div", { className: clsx('ob-form-container', {
772
- 'is-showing-pages': isShowingMultiplePages,
773
- }), ref: obFormContainerHTMLElementRef, children: [_jsx("form", { name: "obForm", className: `ob-form cypress-ob-form ob-form__page-${currentPageIndex + 1}`, noValidate: true, onSubmit: (e) => handleSubmit(e, false), children: _jsxs("div", { children: [_jsx("div", { ref: scrollToTopOfPageHTMLElementRef }), isShowingMultiplePages && (_jsxs("div", { className: clsx('ob-steps-navigation', {
774
- 'is-active': isStepsHeaderActive,
775
- }), children: [_jsxs(Clickable, { className: clsx('ob-steps-navigation__header', {
776
- 'is-active': isStepsHeaderActive,
777
- }), onClick: toggleStepsNavigation, children: [_jsx("span", { className: "icon is-invisible", children: _jsx(MaterialIcon, { children: "keyboard_arrow_down" }) }), _jsxs("div", { className: "steps-header-active-page", children: [isDisplayingCurrentPageError ? (_jsx("span", { className: "icon", children: _jsx(MaterialIcon, { className: "has-text-danger is-size-4", children: "warning" }) })) : (_jsx("span", { className: "steps-header-active-page-icon", children: currentPageNumber })), _jsx("span", { className: "steps-header-active-page-label cypress-tablet-step-title", children: currentPage ? currentPage.label : '' })] }), _jsx("span", { className: "dropdown icon", children: _jsx(MaterialIcon, { children: "keyboard_arrow_down" }) })] }), _jsx("div", { role: "navigation", className: clsx('ob-steps-navigation__steps', {
778
- 'is-active': isStepsHeaderActive,
779
- }), children: _jsx("div", { className: "steps is-small is-horizontal-tablet cypress-steps", children: visiblePages.map((page, index) => {
780
- const hasErrors = checkDisplayPageError(page);
781
- return (_jsxs(Clickable, { id: `steps-navigation-step-${page.id}`, "aria-label": `${page.label}, page ${index + 1} of ${visiblePages.length}`, "aria-current": currentPage.id === page.id
782
- ? 'step'
783
- : undefined, className: clsx('step-item cypress-step-item', {
784
- 'is-active': currentPage.id === page.id,
785
- 'is-completed': currentPageIndex > index,
786
- 'is-error': hasErrors,
787
- }), onClick: (e) => {
788
- e.stopPropagation();
789
- if (page.id !== currentPage.id) {
790
- setPageId(page.id);
791
- }
792
- }, children: [_jsx("div", { className: "step-marker step-marker-error ob-step-marker cypress-step-marker",
793
- // @ts-expect-error ???
794
- name: `cypress-page-stepper-${index + 1}`, value: index + 1, children: hasErrors ? (_jsx(Tooltip, { title: "Page has errors", children: _jsx("span", { className: "icon tooltip has-tooltip-top cypress-page-error", children: _jsx(MaterialIcon, { className: "has-text-danger is-size-3", children: "warning" }) }) })) : (_jsx("span", { children: index + 1 })) }), _jsx("div", { className: "step-details ob-step-details", children: _jsx("p", { className: "step-title ob-step-title cypress-desktop-step-title", id: `steps-navigation-step-label-${page.id}`, children: page.label }) })] }, page.id));
795
- }) }) })] })), _jsx("div", { className: clsx('ob-steps-navigation__background', {
796
- 'is-active': isStepsHeaderActive,
797
- }), onClick: toggleStepsNavigation }), _jsxs("div", { className: "steps", children: [_jsx("div", { className: clsx('steps-content', {
798
- 'is-single-step': !isShowingMultiplePages,
799
- }), children: _jsx(InjectPagesContext.Provider, { value: handlePagesLookupResult, children: _jsx(GoogleMapsApiKeyContext.Provider, { value: googleMapsApiKey, children: _jsx(AbnLookupAuthenticationGuidContext.Provider, { value: abnLookupAuthenticationGuid, children: _jsx(ValidationIconConfigurationContext.Provider, { value: validationIcon, children: _jsx(CaptchaContext.Provider, { value: captchaContextValue, children: _jsx(AttachmentBlobsProvider, { children: _jsx(FormIsReadOnlyContext.Provider, { value: isReadOnly, children: _jsx(EditableFormElementIdsContext.Provider, { value: editableFormElementIds, children: _jsx(FormAudienceContext.Provider, { value: audience, children: _jsx(TaskContext.Provider, { value: taskContextValue, children: _jsx(OnUploadAttachmentContext.Provider, { value: onUploadAttachment, children: visiblePages.map((pageElement) => (_jsx(PageFormElements, { isActive: pageElement.id ===
800
- currentPage.id, formId: definition.id, formElementsConditionallyShown: formElementsConditionallyShown, formElementsValidation: formElementsValidation, displayValidationMessages: hasAttemptedSubmit ||
801
- isDisplayingCurrentPageError, pageElement: pageElement, onChange: handleChange, model: submission, setFormSubmission: setFormSubmission, sectionState: sectionState }, pageElement.id))) }) }) }) }) }) }) }) }) }) }) }) }), isShowingMultiplePages && (_jsxs("div", { className: "steps-actions", children: [_jsx("div", { className: "steps-action", children: _jsxs("button", { type: "button", onClick: goToPreviousPage, disabled: isFirstVisiblePage, className: "button is-light cypress-pages-previous", children: [_jsx("span", { className: "icon", children: _jsx(MaterialIcon, { children: "keyboard_arrow_left" }) }), _jsx("span", { children: "Back" })] }) }), _jsx("div", { className: "step-progress-mobile cypress-steps-mobile", children: visiblePages.map((page, index) => (_jsx("div", { className: clsx('step-progress-mobile-dot', {
802
- 'is-active': currentPage.id === page.id,
803
- 'is-completed': currentPageIndex > index,
804
- 'has-background-danger': currentPage.id !== page.id &&
805
- checkDisplayPageError(page),
806
- }) }, page.id))) }), _jsx("div", { className: "steps-action", children: _jsxs("button", { type: "button", onClick: goToNextPage, disabled: isLastVisiblePage, className: "button is-light cypress-pages-next", children: [_jsx("span", { children: "Next" }), _jsx("span", { className: "icon", children: _jsx(MaterialIcon, { children: "keyboard_arrow_right" }) })] }) })] }))] }), !isReadOnly && audience !== 'APPROVER' && (_jsxs("div", { className: "buttons ob-buttons ob-buttons-submit", children: [onSaveDraft && !isInfoPage && (_jsx("button", { type: "button", className: "button ob-button is-primary ob-button-save-draft cypress-save-draft-form", onClick: () => handleSaveDraft(false), disabled: isPreview || disabled, children: _jsx(CustomisableButtonInner, { label: ((_a = buttons === null || buttons === void 0 ? void 0 : buttons.saveDraft) === null || _a === void 0 ? void 0 : _a.label) || 'Save Draft', icon: (_b = buttons === null || buttons === void 0 ? void 0 : buttons.saveDraft) === null || _b === void 0 ? void 0 : _b.icon }) })), _jsx("span", { className: "ob-buttons-submit__spacer" }), !isInfoPage && (_jsx("button", { type: "button", className: "button ob-button is-light ob-button-submit-cancel cypress-cancel-form", onClick: handleCancel, disabled: isPreview || disabled, children: _jsx(CustomisableButtonInner, { label: ((_c = buttons === null || buttons === void 0 ? void 0 : buttons.cancel) === null || _c === void 0 ? void 0 : _c.label) || 'Cancel', icon: (_d = buttons === null || buttons === void 0 ? void 0 : buttons.cancel) === null || _d === void 0 ? void 0 : _d.icon }) })), isLastVisiblePage && (_jsx(Tooltip, { title: submissionConditionallyEnabled
807
- ? ''
808
- : 'Submission disabled: Your inputs have not met the criteria for submission', children: _jsx("span", { children: _jsx("button", { type: "submit", className: clsx('button ob-button is-success ob-button-submit cypress-submit-form-button cypress-submit-form', { 'is-loading': isPreparingToSubmit }, {
809
- 'ob-button-submit-is-disabled': submissionConditionallyEnabled,
810
- }), disabled: isPreview ||
811
- disabled ||
812
- isPreparingToSubmit ||
813
- !submissionConditionallyEnabled, children: _jsx(CustomisableButtonInner, { label: isInfoPage
814
- ? 'Done'
815
- : ((_e = buttons === null || buttons === void 0 ? void 0 : buttons.submit) === null || _e === void 0 ? void 0 : _e.label) || 'Submit', icon: (_f = buttons === null || buttons === void 0 ? void 0 : buttons.submit) === null || _f === void 0 ? void 0 : _f.icon }) }) }) }))] }))] }) }), !isPreview &&
816
- (editableFormElementIds !== undefined || !isReadOnly) && (_jsxs(React.Fragment, { children: [_jsx(Prompt, { when: isDirty && !isNavigationAllowed, message: handleBlockedNavigation }), _jsx(Modal, { isOpen: hasConfirmedNavigation === false, title: "Unsaved Changes", cardClassName: "cypress-cancel-confirm", titleClassName: "cypress-cancel-confirm-title", bodyClassName: "cypress-cancel-confirm-body", actions: _jsxs(_Fragment, { children: [onSaveDraft && (_jsx("button", { type: "button", className: "button ob-button is-success cypress-cancel-confirm-save-draft", onClick: () => handleSaveDraft(false), children: _jsx(CustomisableButtonInner, { label: ((_g = buttons === null || buttons === void 0 ? void 0 : buttons.saveDraft) === null || _g === void 0 ? void 0 : _g.label) ||
817
- 'Save Draft', icon: (_h = buttons === null || buttons === void 0 ? void 0 : buttons.saveDraft) === null || _h === void 0 ? void 0 : _h.icon }) })), _jsx("span", { style: { flex: 1 } }), _jsx("button", { type: "button", className: "button ob-button is-light cypress-cancel-confirm-back", onClick: handleKeepGoing, children: _jsx(CustomisableButtonInner, { label: ((_j = buttons === null || buttons === void 0 ? void 0 : buttons.cancelPromptNo) === null || _j === void 0 ? void 0 : _j.label) || 'Back', icon: (_k = buttons === null || buttons === void 0 ? void 0 : buttons.cancelPromptNo) === null || _k === void 0 ? void 0 : _k.icon }) }), _jsx("button", { type: "button", className: "button ob-button is-primary cypress-cancel-confirm-discard", onClick: handleDiscardUnsavedChanges, autoFocus: true, children: _jsx(CustomisableButtonInner, { label: ((_l = buttons === null || buttons === void 0 ? void 0 : buttons.cancelPromptYes) === null || _l === void 0 ? void 0 : _l.label) ||
818
- 'Discard', icon: (_m = buttons === null || buttons === void 0 ? void 0 : buttons.cancelPromptYes) === null || _m === void 0 ? void 0 : _m.icon }) })] }), children: _jsx("p", { children: "You have unsaved changes, are you sure you want discard them?" }) })] })), !isReadOnly && !isPreview && audience !== 'APPROVER' && (_jsxs(React.Fragment, { children: [_jsx(Modal, { isOpen: promptUploadingAttachments === true, title: "Attachment upload in progress", cardClassName: "cypress-attachments-wait-continue", titleClassName: "cypress-attachments-confirm-wait-title", bodyClassName: "cypress-attachments-confirm-wait-body", actions: _jsxs(_Fragment, { children: [_jsx("span", { style: { flex: 1 } }), _jsx("button", { type: "button", className: "button ob-button is-light cypress-attachments-confirm-wait", onClick: handleWaitForAttachments, children: "Wait" }), _jsx("button", { type: "button", className: "button ob-button is-primary cypress-attachments-confirm-continue", onClick: handleContinueWithAttachments, autoFocus: true, children: "Continue" })] }), children: _jsx("p", { children: "Your attachments are still uploading, do you want to wait for the uploads to complete or continue using the app? If you click continue the attachments will upload in the background. Do not close the app until the upload has been completed." }) }), _jsxs(Modal, { isOpen: promptOfflineSubmissionAttempt, title: "It looks like you're Offline", className: "ob-modal__offline-submission-attempt", cardClassName: "cypress-submission-offline has-text-centered", titleClassName: "cypress-offline-title", bodyClassName: "cypress-offline-body", actions: _jsxs(_Fragment, { children: [onSaveDraft && (_jsx("button", { type: "button", className: "button ob-button ob-button__offline-submission-attempt-save-draft is-success", onClick: () => handleSaveDraft(false), children: _jsx(CustomisableButtonInner, { label: ((_o = buttons === null || buttons === void 0 ? void 0 : buttons.saveDraft) === null || _o === void 0 ? void 0 : _o.label) || 'Save Draft', icon: (_p = buttons === null || buttons === void 0 ? void 0 : buttons.saveDraft) === null || _p === void 0 ? void 0 : _p.icon }) })), _jsx("span", { style: { flex: 1 } }), _jsx("button", { className: "button ob-button ob-button__offline-submission-attempt-cancel is-light", onClick: () => setPromptOfflineSubmissionAttempt(false), children: "Cancel" }), _jsx("button", { className: "button ob-button ob-button__offline-submission-attempt-try-again is-primary", onClick: (e) => {
819
- setPromptOfflineSubmissionAttempt(false);
820
- handleSubmit(e, false);
821
- }, autoFocus: true, children: "Try Again" })] }), children: [_jsxs("p", { className: "ob-modal__offline-submission-attempt-message", children: ["You cannot submit this form while offline, please try again when connectivity is restored.", onSaveDraft && (_jsxs("span", { className: "ob-modal__offline-submission-attempt-save-draft-message", children: [' ', "Alternatively, click the", ' ', _jsx("b", { children: ((_q = buttons === null || buttons === void 0 ? void 0 : buttons.saveDraft) === null || _q === void 0 ? void 0 : _q.label) || 'Save Draft' }), ' ', "button below to come back to this later."] }))] }), _jsx(MaterialIcon, { className: "has-text-warning icon-x-large ob-modal__offline-submission-attempt-icon", children: "wifi_off" })] })] })), shouldUseNavigableValidationErrorsNotification &&
822
- isShowingValidationErrorsCard && (_jsx(ValidationErrorsCard, { visiblePages: visiblePages, formElementsValidation: formElementsValidation, setPageId: setPageId, currentPage: currentPage, navigationTopOffset: (_r = navigableValidationErrorsNotificationSettings === null || navigableValidationErrorsNotificationSettings === void 0 ? void 0 : navigableValidationErrorsNotificationSettings.navigationTopOffset) !== null && _r !== void 0 ? _r : 'CALCULATE', scrollableContainerId: navigableValidationErrorsNotificationSettings === null || navigableValidationErrorsNotificationSettings === void 0 ? void 0 : navigableValidationErrorsNotificationSettings.scrollableContainerId, validationErrorToastFocusElementRef: validationErrorToastFocusElementRef }))] }) }) }) }) }) }) }) }));
897
+ return (_jsx(FormMarkDirtyContextProvider, { markDirty: markFormDirty, children: _jsx(ThemeProvider, { theme: theme, children: _jsx(LocalizationProvider, { dateAdapter: AdapterDateFns, children: _jsx(ReplaceInjectablesOverridesContext.Provider, { value: replaceInjectablesOverrides, children: _jsx(FormDefinitionContext.Provider, { value: definition, children: _jsx(FormElementOptionsContextProvider, { formIsReadOnly: isReadOnly, children: _jsx(FormElementLookupsContextProvider, { children: _jsx(OneBlinkFormContainerContext.Provider, { value: obFormContainerHTMLElementRef, children: _jsxs("div", { className: clsx('ob-form-container', {
898
+ 'is-showing-pages': isShowingMultiplePages,
899
+ }), ref: obFormContainerHTMLElementRef, children: [_jsx("form", { name: "obForm", className: `ob-form cypress-ob-form ob-form__page-${currentPageIndex + 1}`, noValidate: true, onSubmit: (e) => handleSubmit(e, false), children: _jsxs("div", { children: [_jsx("div", { ref: scrollToTopOfPageHTMLElementRef }), isShowingMultiplePages && (_jsxs("div", { className: clsx('ob-steps-navigation', {
900
+ 'is-active': isStepsHeaderActive,
901
+ }), children: [_jsxs(Clickable, { className: clsx('ob-steps-navigation__header', {
902
+ 'is-active': isStepsHeaderActive,
903
+ }), onClick: toggleStepsNavigation, children: [_jsx("span", { className: "icon is-invisible", children: _jsx(MaterialIcon, { children: "keyboard_arrow_down" }) }), _jsxs("div", { className: "steps-header-active-page", children: [isDisplayingCurrentPageError ? (_jsx("span", { className: "icon", children: _jsx(MaterialIcon, { className: "has-text-danger is-size-4", children: "warning" }) })) : (_jsx("span", { className: "steps-header-active-page-icon", children: currentPageNumber })), _jsx("span", { className: "steps-header-active-page-label cypress-tablet-step-title", children: currentPage ? currentPage.label : '' })] }), _jsx("span", { className: "dropdown icon", children: _jsx(MaterialIcon, { children: "keyboard_arrow_down" }) })] }), _jsx("div", { role: "navigation", className: clsx('ob-steps-navigation__steps', {
904
+ 'is-active': isStepsHeaderActive,
905
+ }), children: _jsx("div", { className: "steps is-small is-horizontal-tablet cypress-steps", children: visiblePages.map((page, index) => {
906
+ const hasErrors = checkDisplayPageError(page);
907
+ return (_jsxs(Clickable, { id: `steps-navigation-step-${page.id}`, "aria-label": `${page.label}, page ${index + 1} of ${visiblePages.length}`, "aria-current": currentPage.id === page.id
908
+ ? 'step'
909
+ : undefined, className: clsx('step-item cypress-step-item', {
910
+ 'is-active': currentPage.id === page.id,
911
+ 'is-completed': currentPageIndex > index,
912
+ 'is-error': hasErrors,
913
+ }), onClick: (e) => {
914
+ e.stopPropagation();
915
+ if (page.id !== currentPage.id) {
916
+ setPageId(page.id);
917
+ }
918
+ }, children: [_jsx("div", { className: "step-marker step-marker-error ob-step-marker cypress-step-marker",
919
+ // @ts-expect-error ???
920
+ name: `cypress-page-stepper-${index + 1}`, value: index + 1, children: hasErrors ? (_jsx(Tooltip, { title: "Page has errors", children: _jsx("span", { className: "icon tooltip has-tooltip-top cypress-page-error", children: _jsx(MaterialIcon, { className: "has-text-danger is-size-3", children: "warning" }) }) })) : (_jsx("span", { children: index + 1 })) }), _jsx("div", { className: "step-details ob-step-details", children: _jsx("p", { className: "step-title ob-step-title cypress-desktop-step-title", id: `steps-navigation-step-label-${page.id}`, children: page.label }) })] }, page.id));
921
+ }) }) })] })), _jsx("div", { className: clsx('ob-steps-navigation__background', {
922
+ 'is-active': isStepsHeaderActive,
923
+ }), onClick: toggleStepsNavigation }), _jsxs("div", { className: "steps", children: [_jsx("div", { className: clsx('steps-content', {
924
+ 'is-single-step': !isShowingMultiplePages,
925
+ }), children: _jsx(InjectPagesContext.Provider, { value: handlePagesLookupResult, children: _jsx(GoogleMapsApiKeyContext.Provider, { value: googleMapsApiKey, children: _jsx(AbnLookupAuthenticationGuidContext.Provider, { value: abnLookupAuthenticationGuid, children: _jsx(ValidationIconConfigurationContext.Provider, { value: validationIcon, children: _jsx(CaptchaContext.Provider, { value: captchaContextValue, children: _jsx(AttachmentBlobsProvider, { children: _jsx(FormIsReadOnlyContext.Provider, { value: isReadOnly, children: _jsx(EditableFormElementIdsContext.Provider, { value: editableFormElementIds, children: _jsx(FormAudienceContext.Provider, { value: audience, children: _jsx(TaskContext.Provider, { value: taskContextValue, children: _jsx(OnUploadAttachmentContext.Provider, { value: onUploadAttachment, children: visiblePages.map((pageElement) => (_jsx(PageFormElements, { isActive: pageElement.id ===
926
+ currentPage.id, formId: definition.id, formElementsConditionallyShown: formElementsConditionallyShown, formElementsValidation: formElementsValidation, displayValidationMessages: hasAttemptedSubmit ||
927
+ isDisplayingCurrentPageError, pageElement: pageElement, onChange: handleChange, model: submission, setFormSubmission: setFormSubmission, sectionState: sectionState }, pageElement.id))) }) }) }) }) }) }) }) }) }) }) }) }), isShowingMultiplePages && (_jsxs("div", { className: "steps-actions", children: [_jsx("div", { className: "steps-action", children: _jsxs("button", { type: "button", onClick: goToPreviousPage, disabled: isFirstVisiblePage, className: "button is-light cypress-pages-previous", children: [_jsx("span", { className: "icon", children: _jsx(MaterialIcon, { children: "keyboard_arrow_left" }) }), _jsx("span", { children: "Back" })] }) }), _jsx("div", { className: "step-progress-mobile cypress-steps-mobile", children: visiblePages.map((page, index) => (_jsx("div", { className: clsx('step-progress-mobile-dot', {
928
+ 'is-active': currentPage.id === page.id,
929
+ 'is-completed': currentPageIndex > index,
930
+ 'has-background-danger': currentPage.id !== page.id &&
931
+ checkDisplayPageError(page),
932
+ }) }, page.id))) }), _jsx("div", { className: "steps-action", children: _jsxs("button", { type: "button", onClick: goToNextPage, disabled: isLastVisiblePage, className: "button is-light cypress-pages-next", children: [_jsx("span", { children: "Next" }), _jsx("span", { className: "icon", children: _jsx(MaterialIcon, { children: "keyboard_arrow_right" }) })] }) })] }))] }), !isReadOnly && audience !== 'APPROVER' && (_jsxs("div", { className: "buttons ob-buttons ob-buttons-submit", children: [onSaveDraft && !isInfoPage && (_jsx("button", { type: "button", className: "button ob-button is-primary ob-button-save-draft cypress-save-draft-form", onClick: () => handleSaveDraft(false), disabled: isPreview || disabled, children: _jsx(CustomisableButtonInner, { label: ((_a = buttons === null || buttons === void 0 ? void 0 : buttons.saveDraft) === null || _a === void 0 ? void 0 : _a.label) || 'Save Draft', icon: (_b = buttons === null || buttons === void 0 ? void 0 : buttons.saveDraft) === null || _b === void 0 ? void 0 : _b.icon }) })), _jsx("span", { className: "ob-buttons-submit__spacer" }), !isInfoPage && (_jsx("button", { type: "button", className: "button ob-button is-light ob-button-submit-cancel cypress-cancel-form", onClick: handleCancel, disabled: isPreview || disabled, children: _jsx(CustomisableButtonInner, { label: ((_c = buttons === null || buttons === void 0 ? void 0 : buttons.cancel) === null || _c === void 0 ? void 0 : _c.label) || 'Cancel', icon: (_d = buttons === null || buttons === void 0 ? void 0 : buttons.cancel) === null || _d === void 0 ? void 0 : _d.icon }) })), isLastVisiblePage && (_jsx(Tooltip, { title: submissionConditionallyEnabled
933
+ ? ''
934
+ : 'Submission disabled: Your inputs have not met the criteria for submission', children: _jsx("span", { children: _jsx("button", { type: "submit", className: clsx('button ob-button is-success ob-button-submit cypress-submit-form-button cypress-submit-form', { 'is-loading': isPreparingToSubmit }, {
935
+ 'ob-button-submit-is-disabled': submissionConditionallyEnabled,
936
+ }), disabled: isPreview ||
937
+ disabled ||
938
+ isPreparingToSubmit ||
939
+ !submissionConditionallyEnabled, children: _jsx(CustomisableButtonInner, { label: isInfoPage
940
+ ? 'Done'
941
+ : ((_e = buttons === null || buttons === void 0 ? void 0 : buttons.submit) === null || _e === void 0 ? void 0 : _e.label) || 'Submit', icon: (_f = buttons === null || buttons === void 0 ? void 0 : buttons.submit) === null || _f === void 0 ? void 0 : _f.icon }) }) }) }))] }))] }) }), !isPreview &&
942
+ (editableFormElementIds !== undefined ||
943
+ !isReadOnly) && (_jsxs(React.Fragment, { children: [_jsx(Prompt, { when: isDirty && !isNavigationAllowed, message: handleBlockedNavigation }), _jsx(Modal, { isOpen: hasConfirmedNavigation === false, title: "Unsaved Changes", cardClassName: "cypress-cancel-confirm", titleClassName: "cypress-cancel-confirm-title", bodyClassName: "cypress-cancel-confirm-body", actions: _jsxs(_Fragment, { children: [onSaveDraft && (_jsx("button", { type: "button", className: "button ob-button is-success cypress-cancel-confirm-save-draft", onClick: () => handleSaveDraft(false), children: _jsx(CustomisableButtonInner, { label: ((_g = buttons === null || buttons === void 0 ? void 0 : buttons.saveDraft) === null || _g === void 0 ? void 0 : _g.label) ||
944
+ 'Save Draft', icon: (_h = buttons === null || buttons === void 0 ? void 0 : buttons.saveDraft) === null || _h === void 0 ? void 0 : _h.icon }) })), _jsx("span", { style: { flex: 1 } }), _jsx("button", { type: "button", className: "button ob-button is-light cypress-cancel-confirm-back", onClick: handleKeepGoing, children: _jsx(CustomisableButtonInner, { label: ((_j = buttons === null || buttons === void 0 ? void 0 : buttons.cancelPromptNo) === null || _j === void 0 ? void 0 : _j.label) || 'Back', icon: (_k = buttons === null || buttons === void 0 ? void 0 : buttons.cancelPromptNo) === null || _k === void 0 ? void 0 : _k.icon }) }), _jsx("button", { type: "button", className: "button ob-button is-primary cypress-cancel-confirm-discard", onClick: handleDiscardUnsavedChanges, autoFocus: true, children: _jsx(CustomisableButtonInner, { label: ((_l = buttons === null || buttons === void 0 ? void 0 : buttons.cancelPromptYes) === null || _l === void 0 ? void 0 : _l.label) ||
945
+ 'Discard', icon: (_m = buttons === null || buttons === void 0 ? void 0 : buttons.cancelPromptYes) === null || _m === void 0 ? void 0 : _m.icon }) })] }), children: _jsx("p", { children: "You have unsaved changes, are you sure you want discard them?" }) }), hostAttemptPhase.status === 'preparing' && (_jsx(HostPreparationEffect, { continueWithAttachments: hostAttemptPhase.continueWithAttachments, prepareSubmission: prepareSubmission, onResult: handleHostPreparationResult })), _jsx(Modal, { isOpen: promptUploadingAttachments === true, title: "Attachment upload in progress", cardClassName: "cypress-attachments-wait-continue", titleClassName: "cypress-attachments-confirm-wait-title", bodyClassName: "cypress-attachments-confirm-wait-body", actions: _jsxs(_Fragment, { children: [_jsx("span", { style: { flex: 1 } }), _jsx("button", { type: "button", className: "button ob-button is-light cypress-attachments-confirm-wait", onClick: handleWaitForAttachments, children: "Wait" }), _jsx("button", { type: "button", className: "button ob-button is-primary cypress-attachments-confirm-continue", onClick: handleContinueWithAttachments, autoFocus: true, children: "Continue" })] }), children: _jsx("p", { children: "Your attachments are still uploading, do you want to wait for the uploads to complete or continue using the app? If you click continue the attachments will upload in the background. Do not close the app until the upload has been completed." }) }), _jsxs(Modal, { isOpen: promptOfflineSubmissionAttempt, title: "It looks like you're Offline", className: "ob-modal__offline-submission-attempt", cardClassName: "cypress-submission-offline has-text-centered", titleClassName: "cypress-offline-title", bodyClassName: "cypress-offline-body", actions: _jsxs(_Fragment, { children: [onSaveDraft && (_jsx("button", { type: "button", className: "button ob-button ob-button__offline-submission-attempt-save-draft is-success", onClick: () => handleSaveDraft(false), children: _jsx(CustomisableButtonInner, { label: ((_o = buttons === null || buttons === void 0 ? void 0 : buttons.saveDraft) === null || _o === void 0 ? void 0 : _o.label) ||
946
+ 'Save Draft', icon: (_p = buttons === null || buttons === void 0 ? void 0 : buttons.saveDraft) === null || _p === void 0 ? void 0 : _p.icon }) })), _jsx("span", { style: { flex: 1 } }), _jsx("button", { className: "button ob-button ob-button__offline-submission-attempt-cancel is-light cypress-offline-submission-cancel", onClick: handleCancelOfflineSubmission, children: "Cancel" }), _jsx("button", { className: "button ob-button ob-button__offline-submission-attempt-try-again is-primary cypress-offline-submission-try-again", onClick: handleRetryOfflineSubmission, autoFocus: true, children: "Try Again" })] }), children: [_jsxs("p", { className: "ob-modal__offline-submission-attempt-message", children: ["You cannot submit this form while offline, please try again when connectivity is restored.", onSaveDraft && (_jsxs("span", { className: "ob-modal__offline-submission-attempt-save-draft-message", children: [' ', "Alternatively, click the", ' ', _jsx("b", { children: ((_q = buttons === null || buttons === void 0 ? void 0 : buttons.saveDraft) === null || _q === void 0 ? void 0 : _q.label) ||
947
+ 'Save Draft' }), ' ', "button below to come back to this later."] }))] }), _jsx(MaterialIcon, { className: "has-text-warning icon-x-large ob-modal__offline-submission-attempt-icon", children: "wifi_off" })] })] })), shouldUseNavigableValidationErrorsNotification &&
948
+ isShowingValidationErrorsCard && (_jsx(ValidationErrorsCard, { visiblePages: visiblePages, formElementsValidation: formElementsValidation, setPageId: setPageId, currentPage: currentPage, navigationTopOffset: (_r = navigableValidationErrorsNotificationSettings === null || navigableValidationErrorsNotificationSettings === void 0 ? void 0 : navigableValidationErrorsNotificationSettings.navigationTopOffset) !== null && _r !== void 0 ? _r : 'CALCULATE', scrollableContainerId: navigableValidationErrorsNotificationSettings === null || navigableValidationErrorsNotificationSettings === void 0 ? void 0 : navigableValidationErrorsNotificationSettings.scrollableContainerId, validationErrorToastFocusElementRef: validationErrorToastFocusElementRef }))] }) }) }) }) }) }) }) }) }));
823
949
  }
824
950
  export default React.memo(OneBlinkFormBase);
825
951
  //# sourceMappingURL=OneBlinkFormBase.js.map