udp-stencil-component-library 25.18.2-beta.7 → 25.18.2-beta.9

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 (100) hide show
  1. package/dist/cjs/date-time-renderer_7.cjs.entry.js +2 -2
  2. package/dist/cjs/{enums-CgcTuQjC.js → enums-B3aaCQaV.js} +3 -3
  3. package/dist/cjs/{enums-CgcTuQjC.js.map → enums-B3aaCQaV.js.map} +1 -1
  4. package/dist/cjs/form-metadata-display_8.cjs.entry.js +1 -1
  5. package/dist/cjs/loader.cjs.js +1 -1
  6. package/dist/cjs/question-configs-renderer_4.cjs.entry.js +2 -2
  7. package/dist/cjs/stencil-library.cjs.js +1 -1
  8. package/dist/cjs/{udp-forms-builder-question-template-BMMpObLX.js → udp-forms-builder-question-template-BS5ijef_.js} +3 -3
  9. package/dist/cjs/{udp-forms-builder-question-template-BMMpObLX.js.map → udp-forms-builder-question-template-BS5ijef_.js.map} +1 -1
  10. package/dist/cjs/udp-forms-builder.cjs.entry.js +2 -2
  11. package/dist/cjs/udp-forms-follow-up-list-card.cjs.entry.js +1 -1
  12. package/dist/cjs/udp-forms-list-card.cjs.entry.js +1 -1
  13. package/dist/cjs/udp-forms-list.cjs.entry.js +1 -1
  14. package/dist/cjs/udp-forms-renderer.cjs.entry.js +592 -604
  15. package/dist/cjs/udp-forms-renderer.entry.cjs.js.map +1 -1
  16. package/dist/cjs/udp-forms-ui.cjs.entry.js +2 -5
  17. package/dist/cjs/udp-forms-ui.entry.cjs.js.map +1 -1
  18. package/dist/collection/components/forms/udp-forms/udp-forms-renderer/udp-forms-renderer-ui/udp-forms-ui.js +1 -4
  19. package/dist/collection/components/forms/udp-forms/udp-forms-renderer/udp-forms-renderer-ui/udp-forms-ui.js.map +1 -1
  20. package/dist/collection/components/forms/udp-forms/udp-forms-renderer/udp-forms-renderer-utils/comments-crud-utils.js +153 -0
  21. package/dist/collection/components/forms/udp-forms/udp-forms-renderer/udp-forms-renderer-utils/comments-crud-utils.js.map +1 -0
  22. package/dist/collection/components/forms/udp-forms/udp-forms-renderer/udp-forms-renderer-utils/repeated-section-utils.js +104 -0
  23. package/dist/collection/components/forms/udp-forms/udp-forms-renderer/udp-forms-renderer-utils/repeated-section-utils.js.map +1 -0
  24. package/dist/collection/components/forms/udp-forms/udp-forms-renderer/{udp-forms-renderer-utils.js → udp-forms-renderer-utils/utils.js} +48 -2
  25. package/dist/collection/components/forms/udp-forms/udp-forms-renderer/udp-forms-renderer-utils/utils.js.map +1 -0
  26. package/dist/collection/components/forms/udp-forms/udp-forms-renderer/udp-forms-renderer.js +187 -310
  27. package/dist/collection/components/forms/udp-forms/udp-forms-renderer/udp-forms-renderer.js.map +1 -1
  28. package/dist/collection/components/forms/udp-forms/udp-forms-utils/enums.js +1 -1
  29. package/dist/collection/components/forms/udp-forms/udp-forms-utils/enums.js.map +1 -1
  30. package/dist/collection/components/forms/udp-forms/udp-forms-utils/form-handler/UdpFormHandler.js +13 -13
  31. package/dist/collection/components/forms/udp-forms/udp-forms-utils/form-handler/UdpFormHandler.js.map +1 -1
  32. package/dist/collection/components/forms/udp-forms/udp-forms-utils/form-submission-handler/FormSubmissionHandler.js +142 -0
  33. package/dist/collection/components/forms/udp-forms/udp-forms-utils/form-submission-handler/FormSubmissionHandler.js.map +1 -0
  34. package/dist/collection/components/forms/udp-forms/udp-forms-utils/form-submission-handler/FormSubmissionHandlerFactory.js +3 -10
  35. package/dist/collection/components/forms/udp-forms/udp-forms-utils/form-submission-handler/FormSubmissionHandlerFactory.js.map +1 -1
  36. package/dist/collection/components/forms/udp-forms/udp-forms-utils/form-submission-handler/IFormSubmissionHandler.js.map +1 -1
  37. package/dist/collection/components/forms/udp-forms/udp-forms-utils/types.js.map +1 -1
  38. package/dist/components/enums.js +1 -1
  39. package/dist/components/enums.js.map +1 -1
  40. package/dist/components/udp-forms-renderer.js +593 -608
  41. package/dist/components/udp-forms-renderer.js.map +1 -1
  42. package/dist/components/udp-forms-ui2.js +1 -4
  43. package/dist/components/udp-forms-ui2.js.map +1 -1
  44. package/dist/docs.json +1 -1
  45. package/dist/esm/date-time-renderer_7.entry.js +2 -2
  46. package/dist/esm/{enums-DHT5wSnX.js → enums-D5dod6Ie.js} +3 -3
  47. package/dist/esm/{enums-DHT5wSnX.js.map → enums-D5dod6Ie.js.map} +1 -1
  48. package/dist/esm/form-metadata-display_8.entry.js +1 -1
  49. package/dist/esm/loader.js +1 -1
  50. package/dist/esm/question-configs-renderer_4.entry.js +2 -2
  51. package/dist/esm/stencil-library.js +1 -1
  52. package/dist/esm/{udp-forms-builder-question-template-D6ADNZEG.js → udp-forms-builder-question-template-BsYOju9V.js} +3 -3
  53. package/dist/esm/{udp-forms-builder-question-template-D6ADNZEG.js.map → udp-forms-builder-question-template-BsYOju9V.js.map} +1 -1
  54. package/dist/esm/udp-forms-builder.entry.js +2 -2
  55. package/dist/esm/udp-forms-follow-up-list-card.entry.js +1 -1
  56. package/dist/esm/udp-forms-list-card.entry.js +1 -1
  57. package/dist/esm/udp-forms-list.entry.js +1 -1
  58. package/dist/esm/udp-forms-renderer.entry.js +592 -604
  59. package/dist/esm/udp-forms-renderer.entry.js.map +1 -1
  60. package/dist/esm/udp-forms-ui.entry.js +2 -5
  61. package/dist/esm/udp-forms-ui.entry.js.map +1 -1
  62. package/dist/stencil-library/date-time-renderer_7.entry.js +1 -1
  63. package/dist/stencil-library/enums-D5dod6Ie.js +2 -0
  64. package/dist/stencil-library/{enums-DHT5wSnX.js.map → enums-D5dod6Ie.js.map} +1 -1
  65. package/dist/stencil-library/form-metadata-display_8.entry.js +1 -1
  66. package/dist/stencil-library/question-configs-renderer_4.entry.js +1 -1
  67. package/dist/stencil-library/stencil-library.esm.js +1 -1
  68. package/dist/stencil-library/{udp-forms-builder-question-template-D6ADNZEG.js → udp-forms-builder-question-template-BsYOju9V.js} +2 -2
  69. package/dist/stencil-library/{udp-forms-builder-question-template-D6ADNZEG.js.map → udp-forms-builder-question-template-BsYOju9V.js.map} +1 -1
  70. package/dist/stencil-library/udp-forms-builder.entry.js +1 -1
  71. package/dist/stencil-library/udp-forms-follow-up-list-card.entry.js +1 -1
  72. package/dist/stencil-library/udp-forms-follow-up-list-card.entry.js.map +1 -1
  73. package/dist/stencil-library/udp-forms-list-card.entry.js +1 -1
  74. package/dist/stencil-library/udp-forms-list-card.entry.js.map +1 -1
  75. package/dist/stencil-library/udp-forms-list.entry.js +1 -1
  76. package/dist/stencil-library/udp-forms-renderer.entry.esm.js.map +1 -1
  77. package/dist/stencil-library/udp-forms-renderer.entry.js +1 -1
  78. package/dist/stencil-library/udp-forms-renderer.entry.js.map +1 -1
  79. package/dist/stencil-library/udp-forms-ui.entry.esm.js.map +1 -1
  80. package/dist/stencil-library/udp-forms-ui.entry.js +1 -1
  81. package/dist/stencil-library/udp-forms-ui.entry.js.map +1 -1
  82. package/dist/types/components/forms/udp-forms/udp-forms-renderer/udp-forms-renderer-utils/comments-crud-utils.d.ts +31 -0
  83. package/dist/types/components/forms/udp-forms/udp-forms-renderer/udp-forms-renderer-utils/repeated-section-utils.d.ts +17 -0
  84. package/dist/types/components/forms/udp-forms/udp-forms-renderer/{udp-forms-renderer-utils.d.ts → udp-forms-renderer-utils/utils.d.ts} +4 -0
  85. package/dist/types/components/forms/udp-forms/udp-forms-renderer/udp-forms-renderer.d.ts +6 -10
  86. package/dist/types/components/forms/udp-forms/udp-forms-utils/enums.d.ts +1 -1
  87. package/dist/types/components/forms/udp-forms/udp-forms-utils/form-handler/UdpFormHandler.d.ts +5 -6
  88. package/dist/types/components/forms/udp-forms/udp-forms-utils/form-submission-handler/FormSubmissionHandler.d.ts +42 -0
  89. package/dist/types/components/forms/udp-forms/udp-forms-utils/form-submission-handler/FormSubmissionHandlerFactory.d.ts +1 -1
  90. package/dist/types/components/forms/udp-forms/udp-forms-utils/form-submission-handler/IFormSubmissionHandler.d.ts +44 -5
  91. package/dist/types/components/forms/udp-forms/udp-forms-utils/types.d.ts +16 -0
  92. package/package.json +1 -1
  93. package/dist/collection/components/forms/udp-forms/udp-forms-renderer/udp-forms-renderer-utils.js.map +0 -1
  94. package/dist/collection/components/forms/udp-forms/udp-forms-utils/form-submission-handler/PrivateFormSubmissionHandler.js +0 -264
  95. package/dist/collection/components/forms/udp-forms/udp-forms-utils/form-submission-handler/PrivateFormSubmissionHandler.js.map +0 -1
  96. package/dist/collection/components/forms/udp-forms/udp-forms-utils/form-submission-handler/PublicFormSubmissionHandler.js +0 -63
  97. package/dist/collection/components/forms/udp-forms/udp-forms-utils/form-submission-handler/PublicFormSubmissionHandler.js.map +0 -1
  98. package/dist/stencil-library/enums-DHT5wSnX.js +0 -2
  99. package/dist/types/components/forms/udp-forms/udp-forms-utils/form-submission-handler/PrivateFormSubmissionHandler.d.ts +0 -131
  100. package/dist/types/components/forms/udp-forms/udp-forms-utils/form-submission-handler/PublicFormSubmissionHandler.d.ts +0 -15
@@ -2,31 +2,29 @@ import { h } from "@stencil/core";
2
2
  import { throttle } from "lodash";
3
3
  import { getCurrentTenantId } from "../../../../udp-utilities/tenant/tenantUtils";
4
4
  import { fetchLatestForms } from "../udp-forms-list/udp-form-api-utils";
5
- import { UdpFormsTypeEnum, UdpFormsPageIdEnum, UdpFormsSubmissionStatusEnum, UdpFormsFieldTypeEnum } from "../udp-forms-utils/enums";
5
+ import { UdpFormsTypeEnum, UdpFormsPageIdEnum, UdpFormsSubmissionStatusEnum } from "../udp-forms-utils/enums";
6
6
  import { buildEmptyCurrentValues } from "../udp-forms-utils/utils";
7
7
  import { FormSubmissionHandlerFactory } from "../udp-forms-utils/form-submission-handler/FormSubmissionHandlerFactory";
8
8
  import { UdpFormHandler } from "../udp-forms-utils/form-handler/UdpFormHandler";
9
9
  import { UdpFormSubmission } from "../udp-forms-utils/classes/UdpFormSubmission";
10
10
  import { UdpForm } from "../udp-forms-utils/classes/UdpForm";
11
- import { v4 as uuidv4 } from "uuid";
12
- import { applyUrlSeedValuesForAll, initializeDynamicSections, initializeDynamicSectionsWithUrlContext, findRepeatGroupKeys } from "./udp-forms-renderer-utils";
11
+ import { applyUrlSeedValuesForAll, initializeDynamicSections, initializeDynamicSectionsWithUrlContext, replaceUrlWithSubmissionId, enqueueSnackbarSuccess, enqueueSnackbarError } from "./udp-forms-renderer-utils/utils";
12
+ import { computeDeleteRepeatableSection, computeDuplicateRepeatableSection } from "./udp-forms-renderer-utils/repeated-section-utils";
13
+ import { applyQuestionCommentCrud } from "./udp-forms-renderer-utils/comments-crud-utils";
13
14
  export class UdpFormsRenderer {
14
15
  constructor() {
15
16
  this.isPublic = false;
16
17
  this.autoSaveDelay = 2000; // Debounce delay for auto-save in milliseconds (currently disabled)
17
18
  this.urlContext = {}; // additional context from URL if needed, eg. generic1, gernic2, generic3, or any initial prepopulated values for form inputs. eg section1.question1 = 'some value'
18
19
  this.currentValues = {}; // values of the current form state
19
- this.formInputSeedValues = {}; // support for a initial set of values to seed the form with
20
20
  this.submitSuccessful = false;
21
21
  this.isLoading = false;
22
22
  this.isSaving = false;
23
23
  this.isSubmitted = false;
24
- this.saveErrorMessage = null;
25
24
  this.dynamicSections = [];
26
25
  this.isUpdatingSections = false;
27
26
  this.reRenderKey = 0;
28
- this.isFormDirty = false;
29
- this.isUserUpdatedSections = false;
27
+ this.hasUnsavedChanges = false;
30
28
  this.sideSheetFollowUpFormsList = []; // used for follow up forms.
31
29
  this.followUpSideSheetTotalItems = 0; // used for follow up forms.
32
30
  this.isFollowUpFormsSideSheetOpen = false; // used for follow up forms.
@@ -46,9 +44,19 @@ export class UdpFormsRenderer {
46
44
  };
47
45
  this.followUpParentSectionKey = ''; // used for follow up forms.
48
46
  this.followUpParentQuestionKey = ''; // used for follow up forms.
47
+ // Feature flags for public mode. Keep capabilities in the handlers,
48
+ // but disable UX / automatic flows for now.
49
+ this.publicFeatures = {
50
+ allowDraftSave: false, // public cannot save and return later
51
+ allowComments: true, // public can add comments locally; persistence handled by backend rules
52
+ allowFollowUpForms: false, // public does not support follow-up forms
53
+ };
49
54
  this.handleLaunchFollowUpFormSideSheet = async (e) => {
50
55
  try {
51
- await this.performBackgroundSaveAndUpdateLocalSubmissionState(this.udpFormSubmission.data.submissionResponseData);
56
+ // Public forms do not support follow-up forms.
57
+ if (this.isPublic) {
58
+ return;
59
+ }
52
60
  this.followUpParentSectionKey = e.detail.sectionKey;
53
61
  this.followUpParentQuestionKey = e.detail.questionKey;
54
62
  await this.loadFollowUpForms(this.followUpParentSectionKey, this.followUpParentQuestionKey);
@@ -67,75 +75,20 @@ export class UdpFormsRenderer {
67
75
  this.isUpdatingSections = true;
68
76
  this.isLoading = true;
69
77
  try {
70
- const sectionToClone = this.dynamicSections[index];
71
- if (!sectionToClone)
72
- return;
73
- const cloningSectionName = sectionToClone.name;
74
- // Find existing repeat group indices
75
- const repeatKeys = findRepeatGroupKeys(cloningSectionName, this.currentValues);
76
- const nextRepeatIndex = repeatKeys.length > 0 ? Math.max(...repeatKeys) + 1 : 2;
77
- const clonedSection = Object.assign(Object.assign({}, structuredClone(sectionToClone)), { formQuestions: sectionToClone.formQuestions.map(q => {
78
- const newQuestionObj = structuredClone(q);
79
- newQuestionObj.questionIdentifierKey = `${cloningSectionName}_${nextRepeatIndex}.${q.name}`;
80
- return newQuestionObj;
81
- }), isOriginalSection: false, sectionPositionSuffix: nextRepeatIndex });
82
- // Find the last index of this section group
83
- let insertAtIndex = index;
84
- for (let i = index + 1; i < this.dynamicSections.length; i++) {
85
- const s = this.dynamicSections[i];
86
- if (s.name === cloningSectionName) {
87
- insertAtIndex = i;
88
- }
89
- else {
90
- break;
91
- }
92
- }
93
- // Insert after the last repeat of the section group
94
- this.dynamicSections = [
95
- ...this.dynamicSections.slice(0, insertAtIndex + 1),
96
- clonedSection,
97
- ...this.dynamicSections.slice(insertAtIndex + 1),
98
- ];
99
- // Create new initial values structure
100
- const newCurrentValues = structuredClone(this.udpFormSubmission.data.submissionResponseData);
101
- clonedSection.formQuestions.forEach(q => {
102
- var _a, _b, _c, _d;
103
- const newSectionNameWithSuffix = `${cloningSectionName}_${nextRepeatIndex}`;
104
- const newQuestionName = q.name;
105
- if (!newCurrentValues[newSectionNameWithSuffix]) {
106
- newCurrentValues[newSectionNameWithSuffix] = {};
107
- }
108
- // Preserve only Paragraph values from the source section; clear others
109
- let value = '';
110
- if (q.fieldTypeId === UdpFormsFieldTypeEnum.Paragraph) {
111
- // Determine source section key (the section being duplicated)
112
- const sourceSectionKey = sectionToClone.isOriginalSection
113
- ? cloningSectionName
114
- : `${cloningSectionName}_${sectionToClone.sectionPositionSuffix}`;
115
- const sourceVal = (_c = (_b = (_a = this.udpFormSubmission.data.submissionResponseData) === null || _a === void 0 ? void 0 : _a[sourceSectionKey]) === null || _b === void 0 ? void 0 : _b[newQuestionName]) === null || _c === void 0 ? void 0 : _c.value;
116
- let fieldProps = q === null || q === void 0 ? void 0 : q.fieldProperties;
117
- if (typeof fieldProps === 'string') {
118
- try {
119
- fieldProps = JSON.parse(fieldProps || '{}');
120
- }
121
- catch (_e) {
122
- fieldProps = {};
123
- }
124
- }
125
- const paragraphDefault = (_d = fieldProps === null || fieldProps === void 0 ? void 0 : fieldProps.paragraphText) !== null && _d !== void 0 ? _d : '';
126
- value = sourceVal !== null && sourceVal !== void 0 ? sourceVal : paragraphDefault;
127
- }
128
- newCurrentValues[newSectionNameWithSuffix][newQuestionName] = { value, comments: [], metadata: {} };
78
+ const { nextDynamicSections, nextValues } = computeDuplicateRepeatableSection({
79
+ dynamicSections: this.dynamicSections,
80
+ values: structuredClone(this.udpFormSubmission.data.submissionResponseData || {}),
81
+ index,
129
82
  });
130
- // This will trigger a complete form re-render
131
- this.currentValues = Object.assign({}, newCurrentValues);
132
- this.udpFormSubmission.data.submissionResponseData = Object.assign({}, newCurrentValues);
83
+ this.dynamicSections = nextDynamicSections;
84
+ this.currentValues = Object.assign({}, nextValues);
85
+ this.udpFormSubmission.data.submissionResponseData = Object.assign({}, nextValues);
133
86
  this.triggerFormRerender();
134
87
  }
135
88
  finally {
136
89
  this.isUpdatingSections = false;
137
90
  this.isLoading = false;
138
- this.isUserUpdatedSections = true;
91
+ this.hasUnsavedChanges = true;
139
92
  }
140
93
  };
141
94
  /**
@@ -150,137 +103,90 @@ export class UdpFormsRenderer {
150
103
  this.isUpdatingSections = true;
151
104
  this.isLoading = true;
152
105
  try {
153
- const deleteSectionName = sectionToDelete.name;
154
- const deleteSuffix = sectionToDelete.sectionPositionSuffix;
155
- const sectionKeyToDelete = `${deleteSectionName}_${deleteSuffix}`;
156
- const newCurrentValues = Object.assign({}, this.udpFormSubmission.data.submissionResponseData);
157
- delete newCurrentValues[sectionKeyToDelete];
158
- // Remove the section from dynamicSections
159
- const updatedSections = structuredClone(this.dynamicSections);
160
- updatedSections.splice(index, 1);
161
- // Shift all later repeatable sections backward by 1
162
- updatedSections.forEach(section => {
163
- if (section.name !== deleteSectionName ||
164
- section.isOriginalSection ||
165
- section.sectionPositionSuffix <= deleteSuffix) {
166
- return;
167
- }
168
- const oldSuffix = section.sectionPositionSuffix;
169
- const oldSectionKey = `${deleteSectionName}_${oldSuffix}`;
170
- const newSuffix = oldSuffix - 1;
171
- const newSectionKey = `${deleteSectionName}_${newSuffix}`;
172
- // Update suffix
173
- section.sectionPositionSuffix = newSuffix;
174
- // Update questionIdentifierKeys
175
- section.formQuestions = section.formQuestions.map(q => {
176
- const newSectionQuestion = structuredClone(q);
177
- newSectionQuestion.questionIdentifierKey = `${newSectionKey}.${q.name}`;
178
- return newSectionQuestion;
179
- });
180
- // Move data in initial values
181
- if (newCurrentValues[oldSectionKey]) {
182
- newCurrentValues[newSectionKey] = structuredClone(newCurrentValues[oldSectionKey]);
183
- delete newCurrentValues[oldSectionKey];
184
- }
106
+ const { nextDynamicSections, nextValues } = computeDeleteRepeatableSection({
107
+ dynamicSections: this.dynamicSections,
108
+ values: Object.assign({}, (this.udpFormSubmission.data.submissionResponseData || {})),
109
+ index,
185
110
  });
186
- this.dynamicSections = updatedSections;
187
- this.currentValues = Object.assign({}, newCurrentValues);
188
- this.udpFormSubmission.data.submissionResponseData = Object.assign({}, newCurrentValues);
111
+ this.dynamicSections = nextDynamicSections;
112
+ this.currentValues = Object.assign({}, nextValues);
113
+ this.udpFormSubmission.data.submissionResponseData = Object.assign({}, nextValues);
189
114
  this.triggerFormRerender();
190
115
  }
191
116
  finally {
192
117
  this.isUpdatingSections = false;
193
118
  this.isLoading = false;
194
- this.isUserUpdatedSections = true;
119
+ this.hasUnsavedChanges = true;
195
120
  }
196
121
  };
197
122
  /**
198
123
  * Auto save (background save)
199
124
  */
200
125
  this.performBackgroundSaveAndUpdateLocalSubmissionState = async (values) => {
201
- var _a;
202
- this.saveErrorMessage = null;
126
+ return this.performBackgroundSaveAndUpdateLocalSubmissionStateInternal(values);
127
+ };
128
+ this.performBackgroundSaveAndUpdateLocalSubmissionStateInternal = async (values, opts) => {
129
+ var _a, _b;
130
+ const allowUrlReplace = (_a = opts === null || opts === void 0 ? void 0 : opts.allowUrlReplace) !== null && _a !== void 0 ? _a : !this.isPublic;
131
+ const forceCreateDraftIfMissingId = (_b = opts === null || opts === void 0 ? void 0 : opts.forceCreateDraftIfMissingId) !== null && _b !== void 0 ? _b : false;
132
+ // Public mode: disable draft save flows by default
133
+ if (this.isPublic && !this.publicFeatures.allowDraftSave && !forceCreateDraftIfMissingId) {
134
+ return;
135
+ }
203
136
  try {
204
- const updatedUdpFormSubmission = await this.formSubmissionHandler.saveCurrentFormSubmissionState(values, this.udpFormSubmission);
205
- this.udpFormSubmission = updatedUdpFormSubmission;
206
- this.currentValues = Object.assign({}, (((_a = updatedUdpFormSubmission.data) === null || _a === void 0 ? void 0 : _a.submissionResponseData) || {}));
207
- if (!new URLSearchParams(window.location.search).has('udpf_submissionId')) {
137
+ await this.formSubmissionHandler.saveCurrentFormSubmissionState(values, this.udpFormSubmission);
138
+ await this.refreshSubmissionAndSyncState();
139
+ if (allowUrlReplace && !new URLSearchParams(window.location.search).has('udpf_submissionId')) {
208
140
  // replace the current entry's query string with udpf_submissionId without needing to know the path
209
- this.replaceUrlWithSubmissionId(updatedUdpFormSubmission.id);
141
+ replaceUrlWithSubmissionId(this.udpFormSubmission.id, this.history);
210
142
  }
211
143
  }
212
144
  catch (error) {
213
- this.saveErrorMessage = 'Failed to save form data';
214
145
  }
215
146
  finally {
216
147
  this.isSaving = false;
217
- this.isUserUpdatedSections = false;
218
- this.isFormDirty = false;
148
+ this.hasUnsavedChanges = false;
219
149
  }
220
150
  };
151
+ this.refreshSubmissionAndSyncState = async () => {
152
+ var _a, _b;
153
+ if (!((_a = this.udpFormSubmission) === null || _a === void 0 ? void 0 : _a.id))
154
+ return;
155
+ const updated = await this.formSubmissionHandler.fetchAndPopulateUdpFormSubmissionObj(this.udpFormSubmission);
156
+ this.udpFormSubmission = updated;
157
+ this.currentValues = Object.assign({}, (((_b = updated.data) === null || _b === void 0 ? void 0 : _b.submissionResponseData) || {}));
158
+ this.isSubmitted = updated.status === UdpFormsSubmissionStatusEnum.Submitted;
159
+ };
221
160
  /**
222
- * Handle the user saving or deleting a comment
161
+ * Handle the user saving or deleting a comment (pre-submit, private forms only)
223
162
  */
224
- this.handleCommmentUpdate = async (values) => {
225
- var _a;
226
- this.isSaving = true;
227
- this.saveErrorMessage = null;
228
- try {
229
- const updatedUdpFormSubmission = await this.formSubmissionHandler.saveFormSubmissionComments(values, this.udpFormSubmission);
230
- this.udpFormSubmission = updatedUdpFormSubmission;
231
- this.currentValues = Object.assign({}, (((_a = updatedUdpFormSubmission.data) === null || _a === void 0 ? void 0 : _a.submissionResponseData) || {}));
232
- this.enqueueSnackbar('Saved sucessfully.', {
233
- variant: 'success',
234
- anchorOrigin: { vertical: 'top', horizontal: 'center' },
235
- });
236
- }
237
- catch (error) {
238
- this.enqueueSnackbar('There was an error saving.', {
239
- variant: 'error',
240
- anchorOrigin: { vertical: 'top', horizontal: 'center' },
241
- });
242
- }
243
- finally {
244
- this.isSaving = false;
245
- this.isUserUpdatedSections = false;
246
- this.isFormDirty = false;
247
- }
248
- };
163
+ // NOTE: comment saves for non-submitted owner flows are now handled by the standard
164
+ // draft save path (manual/background save). Dedicated comment endpoints are used
165
+ // only for:
166
+ // 1) submitted submissions, OR
167
+ // 2) non-owner viewers adding/updating/deleting comments.
249
168
  /**
250
- * Manual save function - debounced to 5 seconds
169
+ * Manual save function - debounced to 5 seconds (private forms only)
251
170
  */
252
171
  this.handleManualSave = async (values) => {
253
- // Only save if handler supports it and user is authenticated
254
- // if (!this.formSubmissionHandler.supportsAutoSave() || !this.userId || !this.formSubmissionHandler.saveCurrentFormSubmissionState) {
255
- // return;
256
- // }
257
- var _a;
172
+ if (this.isPublic && !this.publicFeatures.allowDraftSave)
173
+ return;
258
174
  this.isSaving = true;
259
- this.saveErrorMessage = null;
260
175
  try {
261
- const updatedUdpFormSubmission = await this.formSubmissionHandler.saveCurrentFormSubmissionState(values, this.udpFormSubmission);
262
- this.udpFormSubmission = updatedUdpFormSubmission;
263
- this.currentValues = Object.assign({}, (((_a = updatedUdpFormSubmission.data) === null || _a === void 0 ? void 0 : _a.submissionResponseData) || {}));
176
+ await this.formSubmissionHandler.saveCurrentFormSubmissionState(values, this.udpFormSubmission);
177
+ await this.refreshSubmissionAndSyncState();
264
178
  if (!new URLSearchParams(window.location.search).has('udpf_submissionId')) {
265
179
  // replace the current entry's query string with udpf_submissionId without needing to know the path
266
- this.replaceUrlWithSubmissionId(updatedUdpFormSubmission.id);
180
+ replaceUrlWithSubmissionId(this.udpFormSubmission.id, this.history);
267
181
  }
268
- this.enqueueSnackbar('Form saved successfully.', {
269
- variant: 'success',
270
- anchorOrigin: { vertical: 'top', horizontal: 'center' },
271
- });
182
+ enqueueSnackbarSuccess('Form saved successfully.', this.enqueueSnackbar);
272
183
  }
273
184
  catch (error) {
274
- this.enqueueSnackbar('There was an error saving this form', {
275
- variant: 'error',
276
- anchorOrigin: { vertical: 'top', horizontal: 'center' },
277
- });
278
- this.saveErrorMessage = 'Failed to save form data';
185
+ enqueueSnackbarError('There was an error saving this form', this.enqueueSnackbar);
279
186
  }
280
187
  finally {
281
188
  this.isSaving = false;
282
- this.isUserUpdatedSections = false;
283
- this.isFormDirty = false;
189
+ this.hasUnsavedChanges = false;
284
190
  }
285
191
  };
286
192
  this.handleFormChange = (values) => {
@@ -347,7 +253,9 @@ export class UdpFormsRenderer {
347
253
  // Listen for launchFollowUpFormSideSheet event from udp-question
348
254
  this.el.addEventListener('launchFollowUpFormSideSheet', (e) => this.handleLaunchFollowUpFormSideSheet(e));
349
255
  this.el.addEventListener('formDirtyChange', (e) => {
350
- this.isFormDirty = e.detail;
256
+ // Preserve any previously-detected unsaved changes (e.g. repeatable section add/delete)
257
+ // so a later false emission doesn't hide the save icon.
258
+ this.hasUnsavedChanges = this.hasUnsavedChanges || e.detail;
351
259
  });
352
260
  }
353
261
  }
@@ -356,17 +264,24 @@ export class UdpFormsRenderer {
356
264
  this.isLoading = true;
357
265
  try {
358
266
  // Get client user info if available
359
- const user = (_a = this.getUserCallback) === null || _a === void 0 ? void 0 : _a.call(this);
360
- if (user) {
361
- this.clientUserInfo.id = user.id || null;
362
- this.clientUserInfo.displayName = user.name || null;
363
- this.clientUserInfo.email = user.email || null;
267
+ if (this.isPublic) {
268
+ this.clientUserInfo.id = '00000000-0000-0000-0000-000000000001';
269
+ this.clientUserInfo.displayName = 'Anonymous';
270
+ }
271
+ else {
272
+ const user = (_a = this.getUserCallback) === null || _a === void 0 ? void 0 : _a.call(this);
273
+ if (user) {
274
+ this.clientUserInfo.id = user.id || null;
275
+ this.clientUserInfo.displayName = user.name || null;
276
+ this.clientUserInfo.email = user.email || null;
277
+ }
364
278
  }
365
279
  this.formSubmissionHandler = FormSubmissionHandlerFactory.create(this.isPublic, this.clientUserInfo.id);
366
280
  this.udpFormSubmission = new UdpFormSubmission({ id: this.submissionId, formId: this.formId, formVersion: this.version, unityUserId: this.clientUserInfo.id, generic1: this.urlContext.generic1, generic2: this.urlContext.generic2, generic3: this.urlContext.generic3 });
367
281
  // fetch existing submission from Udp.FormSubmission if submissionId is provided
368
282
  // take exisitng object, and populate with db values, and return new obj with updated values
369
283
  if (this.submissionId) {
284
+ // Public users should not open private forms; we rely on backend auth to block.
370
285
  this.udpFormSubmission = await this.formSubmissionHandler.fetchAndPopulateUdpFormSubmissionObj(this.udpFormSubmission);
371
286
  }
372
287
  // get the master form from Udp.Form
@@ -425,157 +340,117 @@ export class UdpFormsRenderer {
425
340
  async handleSubmit(values) {
426
341
  this.isLoading = true;
427
342
  try {
428
- this.udpFormSubmission = await this.formSubmissionHandler.finalizeFormSubmissionState(values, this.udpFormSubmission);
343
+ await this.formSubmissionHandler.finalizeFormSubmissionState(values, this.udpFormSubmission);
344
+ await this.refreshSubmissionAndSyncState();
429
345
  this.submitSuccessful = true;
430
346
  }
431
347
  catch (error) {
432
- this.enqueueSnackbar('There was an error submitting this form', {
433
- variant: 'error',
434
- anchorOrigin: { vertical: 'top', horizontal: 'center' },
435
- });
348
+ enqueueSnackbarError('There was an error submitting this form', this.enqueueSnackbar);
436
349
  throw error;
437
350
  }
438
351
  finally {
439
352
  this.isLoading = false;
440
353
  }
441
354
  }
442
- replaceUrlWithSubmissionId(submissionId) {
443
- // build a URL that preserves the current pathname + hash but replaces the query string
444
- const pathname = typeof window !== 'undefined' ? window.location.pathname : `/page/${UdpFormsPageIdEnum.FormRendererPageId}`;
445
- const hash = typeof window !== 'undefined' ? window.location.hash : '';
446
- const newUrl = `${pathname}?udpf_submissionId=${submissionId}${hash}`;
447
- const h = this.history;
448
- // Prefer history.replace when available, handle react-router v6 navigate function, fallback to push or native replaceState
449
- if (h) {
450
- if (typeof h.replace === 'function') {
451
- h.replace(newUrl);
452
- return;
453
- }
454
- if (typeof h.push === 'function') {
455
- h.push(newUrl);
456
- return;
457
- }
458
- // react-router v6 exposes a navigate function
459
- if (typeof h === 'function') {
460
- try {
461
- h(newUrl, { replace: true });
462
- }
463
- catch (_a) {
464
- h(newUrl);
465
- }
466
- return;
467
- }
468
- }
469
- if (typeof window !== 'undefined' && window.history && typeof window.history.replaceState === 'function') {
470
- window.history.replaceState({}, '', newUrl);
471
- }
472
- else if (typeof window !== 'undefined') {
473
- window.location.href = newUrl;
474
- }
475
- }
476
355
  async handleQuestionCommentLiveCRUD(e) {
477
- var _a, _b, _c;
356
+ var _a, _b, _c, _d, _e, _f;
357
+ if (this.isPublic && !this.publicFeatures.allowComments)
358
+ return;
478
359
  try {
479
360
  const { type, questionIdentifierKey, commentId } = e.detail;
480
- const [sectionName, questionName] = questionIdentifierKey.split('.');
481
- let newCurrentValues = structuredClone(this.udpFormSubmission.data.submissionResponseData || {});
482
- // ensure structure exists WITHOUT overwriting existing data
483
- if (!newCurrentValues[sectionName])
484
- newCurrentValues[sectionName] = {};
485
- if (!newCurrentValues[sectionName][questionName]) {
486
- // create defaults but do not clobber any existing saved shape from submissionResponseData
487
- newCurrentValues[sectionName][questionName] = {
488
- value: '',
489
- comments: [],
490
- draftComments: [],
491
- metadata: {},
492
- };
493
- }
494
- else {
495
- // ensure arrays/objects exist so later code can safely push/filter
496
- newCurrentValues[sectionName][questionName].comments = (_a = newCurrentValues[sectionName][questionName].comments) !== null && _a !== void 0 ? _a : [];
497
- newCurrentValues[sectionName][questionName].draftComments = (_b = newCurrentValues[sectionName][questionName].draftComments) !== null && _b !== void 0 ? _b : [];
498
- newCurrentValues[sectionName][questionName].metadata = (_c = newCurrentValues[sectionName][questionName].metadata) !== null && _c !== void 0 ? _c : {};
499
- }
500
- // normalize draftComments to array if needed (back-compat)
501
- const maybeDraft = newCurrentValues[sectionName][questionName].draftComments;
502
- if (maybeDraft && !Array.isArray(maybeDraft)) {
503
- newCurrentValues[sectionName][questionName].draftComments = [maybeDraft];
504
- }
505
- else if (!maybeDraft) {
506
- newCurrentValues[sectionName][questionName].draftComments = [];
361
+ const result = applyQuestionCommentCrud({
362
+ actionType: type,
363
+ questionIdentifierKey,
364
+ commentId,
365
+ currentSubmissionResponseData: this.udpFormSubmission.data.submissionResponseData || {},
366
+ clientUserInfo: this.clientUserInfo,
367
+ });
368
+ const newCurrentValues = result.nextSubmissionResponseData;
369
+ // keep submission state in sync
370
+ this.udpFormSubmission.data.submissionResponseData = Object.assign({}, newCurrentValues);
371
+ // Edit-ish actions are UI-only (open/close draft editor). They must update currentValues
372
+ // even though they don't persist.
373
+ if (type === 'edit' || type === 'editClose' || type === 'add') {
374
+ this.currentValues = Object.assign({}, newCurrentValues);
507
375
  }
508
- const commentsArr = newCurrentValues[sectionName][questionName].comments || [];
509
- const draftsArr = newCurrentValues[sectionName][questionName].draftComments || [];
510
- switch (type) {
511
- case 'add': {
512
- const newDraft = {
513
- value: '',
514
- commentId: uuidv4(),
515
- isTempComment: true,
516
- timestamp: null,
517
- };
518
- // put new draft first so activeDraft === draftComments[0] matches UX
519
- newCurrentValues[sectionName][questionName].draftComments = [newDraft, ...draftsArr];
520
- break;
521
- }
522
- case 'save': {
523
- // find draft by id
524
- const draftIdx = draftsArr.findIndex(d => d.commentId === commentId);
525
- if (draftIdx === -1)
526
- return;
527
- const draft = draftsArr[draftIdx];
528
- const saveTimestamp = draft.timestamp || new Date().toISOString();
529
- const savedComment = Object.assign(Object.assign({}, draft), { timestamp: saveTimestamp, editedTimestamp: new Date().toISOString(), userId: this.clientUserInfo.id, userDisplayName: this.clientUserInfo.displayName, isDraftComment: false });
530
- // If a saved comment with same id exists, replace it. Otherwise append.
531
- const existingIdx = commentsArr.findIndex(c => c.commentId === commentId);
532
- if (existingIdx !== -1) {
533
- const newComments = [...commentsArr];
534
- newComments[existingIdx] = Object.assign({}, savedComment);
535
- newCurrentValues[sectionName][questionName].comments = newComments;
376
+ // if it's a save or delete action, persist immediately
377
+ if (result.shouldPersist) {
378
+ const submissionIsSubmitted = ((_a = this.udpFormSubmission) === null || _a === void 0 ? void 0 : _a.status) === UdpFormsSubmissionStatusEnum.Submitted;
379
+ const submissionIsOwnedByCurrentUser = ((_b = this.udpFormSubmission) === null || _b === void 0 ? void 0 : _b.unityUserId) === this.clientUserInfo.id;
380
+ // Detect whether this save is updating an existing saved comment vs creating a new one.
381
+ // IMPORTANT: check against the *previous* persisted state (before applyQuestionCommentCrud),
382
+ // because once we apply 'save' locally the comment will exist locally even if it's new.
383
+ const existingSavedComment = (((_e = (_d = (_c = ((this.currentValues || {}))) === null || _c === void 0 ? void 0 : _c[result.sectionKey]) === null || _d === void 0 ? void 0 : _d[result.questionKey]) === null || _e === void 0 ? void 0 : _e.comments) || [])
384
+ .find((c) => (c === null || c === void 0 ? void 0 : c.commentId) === result.commentId && !(c === null || c === void 0 ? void 0 : c.isDeleted));
385
+ // Use dedicated comment APIs in 2 scenarios:
386
+ // 1) Once submitted (public+private) to avoid overwriting submission data.
387
+ // 2) When viewed by a non-owner (read-only mode), since they can't save the whole submission.
388
+ if (submissionIsSubmitted || !submissionIsOwnedByCurrentUser) {
389
+ if (!((_f = this.udpFormSubmission) === null || _f === void 0 ? void 0 : _f.id)) {
390
+ // can't persist without an ID; keep local only
391
+ this.currentValues = Object.assign({}, newCurrentValues);
536
392
  }
537
- else {
538
- newCurrentValues[sectionName][questionName].comments = [...commentsArr, savedComment];
393
+ else if (type === 'save') {
394
+ const valueToPersist = result.valueToPersist;
395
+ if (valueToPersist) {
396
+ try {
397
+ // If this comment already exists, update it; otherwise add it.
398
+ if (existingSavedComment) {
399
+ await this.formSubmissionHandler.updateComment(this.udpFormSubmission, {
400
+ sectionKey: result.sectionKey,
401
+ questionKey: result.questionKey,
402
+ value: valueToPersist,
403
+ commentId: result.commentId,
404
+ });
405
+ }
406
+ else {
407
+ await this.formSubmissionHandler.addComment(this.udpFormSubmission, {
408
+ sectionKey: result.sectionKey,
409
+ questionKey: result.questionKey,
410
+ value: valueToPersist,
411
+ commentId: result.commentId,
412
+ });
413
+ }
414
+ await this.refreshSubmissionAndSyncState();
415
+ enqueueSnackbarSuccess(existingSavedComment ? 'Comment updated.' : 'Comment added.', this.enqueueSnackbar);
416
+ }
417
+ catch (error) {
418
+ enqueueSnackbarError(existingSavedComment ? 'Failed to update comment.' : 'Failed to add comment.', this.enqueueSnackbar);
419
+ throw error;
420
+ }
421
+ }
539
422
  }
540
- // remove that draft
541
- newCurrentValues[sectionName][questionName].draftComments = draftsArr.filter(d => d.commentId !== commentId);
542
- break;
543
- }
544
- case 'edit': {
545
- // create a draft copy of the saved comment but DO NOT remove the saved comment from the list.
546
- const saved = commentsArr.find(c => c.commentId === commentId);
547
- if (!saved)
548
- return;
549
- const draftFromSaved = Object.assign(Object.assign({}, saved), { isDraftComment: true, timestamp: null });
550
- // Add this draft at the front; keep saved comment intact so content doesn't disappear.
551
- newCurrentValues[sectionName][questionName].draftComments = [draftFromSaved, ...draftsArr];
552
- newCurrentValues[sectionName][questionName].comments = commentsArr;
553
- break;
554
- }
555
- case 'delete': {
556
- // mark the comment as deleted and clear its value, then persist.
557
- newCurrentValues[sectionName][questionName].comments = commentsArr.map(c => {
558
- if (c.commentId === commentId) {
559
- return Object.assign(Object.assign({}, c), { isDeleted: true, value: '', editedTimestamp: new Date().toISOString() });
423
+ else if (type === 'delete') {
424
+ try {
425
+ await this.formSubmissionHandler.deleteComment(this.udpFormSubmission, {
426
+ sectionKey: result.sectionKey,
427
+ questionKey: result.questionKey,
428
+ commentId: result.commentId,
429
+ });
430
+ await this.refreshSubmissionAndSyncState();
431
+ enqueueSnackbarSuccess('Comment deleted.', this.enqueueSnackbar);
432
+ }
433
+ catch (error) {
434
+ enqueueSnackbarError('Failed to delete comment.', this.enqueueSnackbar);
435
+ throw error;
560
436
  }
561
- return c;
562
- });
563
- break;
437
+ }
564
438
  }
565
- case 'editClose': {
566
- // Cancel edit: remove the draft only, do NOT restore/alter saved comments.
567
- newCurrentValues[sectionName][questionName].draftComments = draftsArr.filter(d => d.commentId !== commentId);
568
- break;
439
+ else {
440
+ // Not submitted yet:
441
+ // - public: persist nothing beyond local state (submission is created on submit)
442
+ // - private + owner: comment edits are persisted via standard submission save
443
+ if (this.isPublic) {
444
+ this.currentValues = Object.assign({}, newCurrentValues);
445
+ }
446
+ else {
447
+ await this.handleManualSave(newCurrentValues);
448
+ }
569
449
  }
570
450
  }
571
- // if it's a save or delete action, persist immediately
572
- if (type === 'save' || type === 'delete') {
573
- this.udpFormSubmission.data.submissionResponseData = Object.assign({}, newCurrentValues);
574
- await this.handleCommmentUpdate(newCurrentValues);
575
- }
576
451
  else {
452
+ // Non-persisting actions update UI state only
577
453
  this.currentValues = Object.assign({}, newCurrentValues);
578
- this.udpFormSubmission.data.submissionResponseData = Object.assign({}, newCurrentValues);
579
454
  }
580
455
  }
581
456
  catch (error) {
@@ -588,7 +463,6 @@ export class UdpFormsRenderer {
588
463
  async loadFollowUpForms(sectionKey, questionKey) {
589
464
  var _a;
590
465
  this.isLoading = true;
591
- this.saveErrorMessage = '';
592
466
  try {
593
467
  const response = await fetchLatestForms(this.followUpSideSheetListPageNumber, this.FOLLOW_UP_SIDE_SHEET_PAGE_SIZE, [{ searchField: 'type', searchOperator: '=', searchValue: UdpFormsTypeEnum.FollowUp }], { sortDirection: 'DESC', sortColumn: 'lastModifiedOn' });
594
468
  const data = response.data;
@@ -600,7 +474,6 @@ export class UdpFormsRenderer {
600
474
  }
601
475
  catch (err) {
602
476
  console.error('Failed to follow up form.', err);
603
- this.saveErrorMessage = 'Failed to follow up forms.';
604
477
  }
605
478
  finally {
606
479
  this.isLoading = false;
@@ -618,11 +491,17 @@ export class UdpFormsRenderer {
618
491
  await this.loadFollowUpForms(this.followUpParentSectionKey, this.followUpParentQuestionKey);
619
492
  }
620
493
  renderFollowUpSideSheet() {
494
+ if (this.isPublic)
495
+ return null;
621
496
  return (h("udp-side-sheet", { title: "Link a Follow Up Form", open: this.isFollowUpFormsSideSheetOpen, onUdpSideSheetClose: () => this.handleSideSheetClose(), position: "right", width: "md" }, this.isLoading && this.isFollowUpFormsSideSheetOpen && h("udp-linear-loader", null), h("udp-list-renderer", { itemComponent: "udp-forms-follow-up-list-card", data: this.sideSheetFollowUpFormsList, pagination: true, isServerSide: true, isLoading: this.isLoading, itemsPerPage: this.FOLLOW_UP_SIDE_SHEET_PAGE_SIZE, currentPage: this.followUpSideSheetListPageNumber, totalItems: this.followUpSideSheetTotalItems, onPageChange: e => this.handleSideSheetPageChange(e.detail), componentDataMap: this.componentMap, spacing: 'md' })));
622
497
  }
623
498
  isShowManualSaveIcon() {
624
- // return (this.isFormDirty || this.isUserUpdatedSections) && !this.isSubmitted && !!this.userId;
625
- const showSaveIcon = (this.isFormDirty || this.isUserUpdatedSections) && !!this.clientUserInfo.id;
499
+ if (this.isPublic)
500
+ return false; // cannot save a form in public mode. can only submit.
501
+ // NOTE: repeatable section add/delete sets hasUnsavedChanges=true, but udp-forms-ui likely
502
+ // also emits a formDirtyChange event that can override the value back to false.
503
+ // Keep the save icon sticky once we've detected any unsaved change.
504
+ const showSaveIcon = !!this.clientUserInfo.id && (this.hasUnsavedChanges);
626
505
  return showSaveIcon;
627
506
  }
628
507
  ;
@@ -630,7 +509,8 @@ export class UdpFormsRenderer {
630
509
  return this.isSubmitted || this.udpFormSubmission.unityUserId !== this.clientUserInfo.id;
631
510
  }
632
511
  render() {
633
- return (h("div", { key: 'd073bfa6145e449c59dc722723ac82d09730d885', class: "forms-renderer-container", style: this.isLoading ? { minHeight: '100vh' } : {} }, this.renderFollowUpSideSheet(), h("udp-forms-ui", { udpForm: this.udpForm, currentValues: this.currentValues, udpFormSubmission: this.udpFormSubmission, submitSuccessful: this.submitSuccessful, isSaving: this.isSaving, saveErrorMessage: this.saveErrorMessage,
512
+ return (h("div", { key: '37ec47fc7f3ecec70ba7ca3e12717789285be5d8', class: "forms-renderer-container", style: this.isLoading ? { minHeight: '100vh' } : {} }, this.renderFollowUpSideSheet(), h("udp-forms-ui", { udpForm: this.udpForm, currentValues: this.currentValues, udpFormSubmission: this.udpFormSubmission, submitSuccessful: this.submitSuccessful, isSaving: this.isSaving,
513
+ // saveErrorMessage={this.saveErrorMessage}
634
514
  // showAutoSaveStatus={this.formSubmissionHandler.supportsAutoSave() && !!this.userId}
635
515
  readonly: this.isReadOnlyMode, handleSubmit: this.handleSubmit.bind(this), handleSave: values => Promise.resolve(this.debouncedManualSave(values)), handleChange: this.handleFormChange, handleAction: this.triggerAction, handleFinish: this.handleFinish, clientUserInfo: this.clientUserInfo, isSubmitted: this.isSubmitted, dynamicSections: this.dynamicSections, duplicateRepeatableSection: this.duplicateRepeatableSection, deleteRepeatableSection: this.deleteRepeatableSection, key: `form-rerender-key-${this.reRenderKey}`, isShowManualSaveIcon: this.isShowManualSaveIcon(), isLoading: this.isLoading, performBackgroundSaveAndUpdateLocalSubmissionState: this.performBackgroundSaveAndUpdateLocalSubmissionState })));
636
516
  }
@@ -906,17 +786,14 @@ export class UdpFormsRenderer {
906
786
  static get states() {
907
787
  return {
908
788
  "currentValues": {},
909
- "formInputSeedValues": {},
910
789
  "submitSuccessful": {},
911
790
  "isLoading": {},
912
791
  "isSaving": {},
913
792
  "isSubmitted": {},
914
- "saveErrorMessage": {},
915
793
  "dynamicSections": {},
916
794
  "isUpdatingSections": {},
917
795
  "reRenderKey": {},
918
- "isFormDirty": {},
919
- "isUserUpdatedSections": {},
796
+ "hasUnsavedChanges": {},
920
797
  "sideSheetFollowUpFormsList": {},
921
798
  "followUpSideSheetTotalItems": {},
922
799
  "isFollowUpFormsSideSheetOpen": {},