@abgov/jsonforms-components 2.81.3 → 2.81.5

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.
package/index.esm.js CHANGED
@@ -14091,1301 +14091,1195 @@ const BackButton = ({
14091
14091
  });
14092
14092
  };
14093
14093
 
14094
- const GoAInputBaseTableReview = props => {
14095
- var _uischema$options, _uischema$scope2, _jsonForms$core, _uischema$options4, _uischema$options5, _uischema$options6;
14094
+ var $$5 = _export;
14095
+ var flattenIntoArray = flattenIntoArray_1;
14096
+ var toObject$1 = toObject$d;
14097
+ var lengthOfArrayLike$1 = lengthOfArrayLike$d;
14098
+ var toIntegerOrInfinity = toIntegerOrInfinity$9;
14099
+ var arraySpeciesCreate = arraySpeciesCreate$3;
14100
+
14101
+ // `Array.prototype.flat` method
14102
+ // https://tc39.es/ecma262/#sec-array.prototype.flat
14103
+ $$5({ target: 'Array', proto: true }, {
14104
+ flat: function flat(/* depthArg = 1 */) {
14105
+ var depthArg = arguments.length ? arguments[0] : undefined;
14106
+ var O = toObject$1(this);
14107
+ var sourceLen = lengthOfArrayLike$1(O);
14108
+ var A = arraySpeciesCreate(O, 0);
14109
+ A.length = flattenIntoArray(A, O, O, sourceLen, 0, depthArg === undefined ? 1 : toIntegerOrInfinity(depthArg));
14110
+ return A;
14111
+ }
14112
+ });
14113
+
14114
+ // this method was added to unscopables after implementation
14115
+ // in popular engines, so it's moved to a separate module
14116
+ var addToUnscopables = addToUnscopables$5;
14117
+
14118
+ // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
14119
+ addToUnscopables('flat');
14120
+
14121
+ let _$6 = t => t,
14122
+ _t$7;
14123
+ const GoAContextMenuIcon = props => {
14124
+ return jsx(GoabIconButton, {
14125
+ icon: props.type,
14126
+ onClick: props.onClick,
14127
+ title: props.title,
14128
+ testId: props.testId,
14129
+ size: "small",
14130
+ disabled: props.disabled
14131
+ });
14132
+ };
14133
+ const GoAContextMenu = styled.div(_t$7 || (_t$7 = _$6`
14134
+ display: flex;
14135
+ align-items: center;
14136
+ background-color: #fff;
14137
+ gap: var(--goa-space-2xs);
14138
+
14139
+ > .goa-icon-button {
14140
+ cursor: pointer;
14141
+ border-radius: var(--goa-border-radius-m);
14142
+ padding: var(--goa-space-2xs);
14143
+ }
14144
+ > .goa-icon-button + .goa-icon-button {
14145
+ margin-left: var(--goa-space-none);
14146
+ }
14147
+ `));
14148
+
14149
+ const DeleteFileModal = ({
14150
+ isOpen,
14151
+ title,
14152
+ content,
14153
+ onDelete,
14154
+ onCancel
14155
+ }) => {
14156
+ return jsx(GoabModal, {
14157
+ testId: "delete-confirmation",
14158
+ open: isOpen,
14159
+ heading: title,
14160
+ maxWidth: "640px",
14161
+ actions: jsxs(GoabButtonGroup, {
14162
+ alignment: "end",
14163
+ children: [jsx(GoabButton, {
14164
+ type: "secondary",
14165
+ testId: "delete-cancel",
14166
+ onClick: onCancel,
14167
+ children: "Cancel"
14168
+ }), jsx(GoabButton, {
14169
+ type: "primary",
14170
+ variant: "destructive",
14171
+ testId: "delete-confirm",
14172
+ onClick: onDelete,
14173
+ children: "Delete"
14174
+ })]
14175
+ }),
14176
+ children: content
14177
+ });
14178
+ };
14179
+
14180
+ let _2 = t => t,
14181
+ _t$6,
14182
+ _t2$3,
14183
+ _t3$2,
14184
+ _t4$2;
14185
+ const _excluded$4 = ["data", "path", "handleChange", "uischema"];
14186
+ const FileUploaderReview = props => {
14187
+ return FileUploader(Object.assign({}, props, {
14188
+ isStepperReview: true
14189
+ }));
14190
+ };
14191
+ const FileUploader = _ref => {
14192
+ var _enumerators$function, _enumerators$function2, _enumerators$function3, _uischema$options, _uischema$options2, _uischema$options3, _uischema$options4, _props$schema, _uischema$options$com, _uischema$options5, _uischema$options6, _uischema$options$com2, _uischema$options7, _uischema$options$com3, _uischema$options8, _uischema$options9;
14193
+ let {
14194
+ data,
14195
+ path,
14196
+ handleChange,
14197
+ uischema
14198
+ } = _ref,
14199
+ props = _objectWithoutPropertiesLoose(_ref, _excluded$4);
14200
+ const enumerators = useContext(JsonFormContext);
14201
+ const uploadTriggerFunction = enumerators == null || (_enumerators$function = enumerators.functions) == null ? void 0 : _enumerators$function.get('upload-file');
14202
+ const uploadTrigger = uploadTriggerFunction && uploadTriggerFunction();
14203
+ const downloadTriggerFunction = enumerators == null || (_enumerators$function2 = enumerators.functions) == null ? void 0 : _enumerators$function2.get('download-file');
14204
+ const downloadTrigger = downloadTriggerFunction && downloadTriggerFunction();
14205
+ const deleteTriggerFunction = enumerators == null || (_enumerators$function3 = enumerators.functions) == null ? void 0 : _enumerators$function3.get('delete-file');
14206
+ const deleteTrigger = deleteTriggerFunction && deleteTriggerFunction();
14207
+ const fileListValue = enumerators == null ? void 0 : enumerators.data.get('file-list');
14208
+ const [loadingFileName, setLoadingFileName] = useState(undefined);
14209
+ const [uploadError, setUploadError] = useState(undefined);
14210
+ const countries = ['Argentina', 'Brazil', 'Canada', 'Denmark', 'Egypt', 'France', 'Greece', 'India', 'Japan', 'Kenya'];
14211
+ enumerators == null || enumerators.addFormContextData('countries', countries);
14212
+ const user = enumerators == null ? void 0 : enumerators.getFormContextData('user');
14213
+ // eslint-disable-next-line
14214
+ const fileList = fileListValue && fileListValue();
14096
14215
  const {
14097
- data,
14098
- uischema,
14099
- label,
14100
- schema,
14101
- rootSchema,
14102
- path,
14103
- errors,
14104
- enabled,
14105
- cells,
14106
14216
  required,
14217
+ label,
14218
+ i18nKeyPrefix,
14107
14219
  visible
14108
14220
  } = props;
14109
- const reportChange = useReviewChange();
14110
- const {
14111
- noAnswerMessage
14112
- } = useStepperPageOptions();
14113
- const showChangeButtons = useShowChangeButtons();
14114
- const jsonForms = useJsonForms();
14115
- const reviewLabel = typeof ((_uischema$options = uischema.options) == null ? void 0 : _uischema$options.reviewLabel) === 'string' ? uischema.options.reviewLabel : '';
14116
- const propLabel = typeof label === 'string' ? label : '';
14117
- if (visible === false) {
14118
- return null;
14119
- }
14120
- let labelToUpdate = '';
14121
- if (reviewLabel.trim() !== '') {
14122
- labelToUpdate = reviewLabel;
14123
- } else if (typeof (schema == null ? void 0 : schema.title) === 'string' && schema.title.trim()) {
14124
- labelToUpdate = schema.title;
14125
- } else if (propLabel.trim() !== '') {
14126
- var _uischema$scope;
14127
- if ((_uischema$scope = uischema.scope) != null && _uischema$scope.startsWith('#/') && controlScopeMatchesLabel(uischema.scope, propLabel)) {
14128
- labelToUpdate = getLabelText(uischema.scope, propLabel);
14129
- } else {
14130
- labelToUpdate = propLabel;
14221
+ const propertyId = i18nKeyPrefix;
14222
+ const rootPath = typeof path === 'string' ? path.replace(/(\.\d+|\[\d+\])$/, '') : path;
14223
+ const variant = (uischema == null || (_uischema$options = uischema.options) == null ? void 0 : _uischema$options.variant) || 'button';
14224
+ const noDownloadButton = uischema == null || (_uischema$options2 = uischema.options) == null || (_uischema$options2 = _uischema$options2.format) == null ? void 0 : _uischema$options2.noDownloadButton;
14225
+ const noDownloadButtonInReview = uischema == null || (_uischema$options3 = uischema.options) == null || (_uischema$options3 = _uischema$options3.format) == null || (_uischema$options3 = _uischema$options3.review) == null ? void 0 : _uischema$options3.noDownloadButton;
14226
+ const noDeleteButton = uischema == null || (_uischema$options4 = uischema.options) == null || (_uischema$options4 = _uischema$options4.format) == null || (_uischema$options4 = _uischema$options4.review) == null ? void 0 : _uischema$options4.noDeleteButton;
14227
+ const isArraySchema = (props == null || (_props$schema = props.schema) == null ? void 0 : _props$schema.type) === 'array' || Array.isArray(data);
14228
+ const maxFiles = (_uischema$options$com = uischema == null || (_uischema$options5 = uischema.options) == null || (_uischema$options5 = _uischema$options5.componentProps) == null ? void 0 : _uischema$options5.maximum) != null ? _uischema$options$com : isArraySchema ? Number.MAX_SAFE_INTEGER : 1;
14229
+ const isMultiFile = maxFiles > 1 || isArraySchema;
14230
+ const metadataKey = path;
14231
+ const [deleteHide, setDeleteHide] = useState(false);
14232
+ const [deleteConfirmIndex, setDeleteConfirmIndex] = useState(null);
14233
+ const pendingUploadIndexRef = useRef(null);
14234
+ const uploadQueueRef = useRef(Promise.resolve());
14235
+ const filesForDisplay = useMemo(() => {
14236
+ if (!fileList) return [];
14237
+ if (isMultiFile) {
14238
+ const files = fileList[metadataKey] || fileList[rootPath] || fileList[propertyId] || [];
14239
+ const dataUrns = Array.isArray(data) ? data : data ? [data] : [];
14240
+ if (dataUrns.length > 0) {
14241
+ const urnSet = new Set(dataUrns);
14242
+ const scopedFiles = files.filter(f => urnSet.has(f.urn));
14243
+ if (scopedFiles.length > 0) {
14244
+ return scopedFiles.filter((file, index, all) => all.findIndex(f => f.urn === file.urn) === index);
14245
+ }
14246
+ const allFiles = Object.values(fileList).flat();
14247
+ const filesByUrn = dataUrns.map(urn => allFiles.find(f => (f == null ? void 0 : f.urn) === urn)).filter(f => !!f);
14248
+ if (filesByUrn.length > 0) {
14249
+ return filesByUrn.filter((file, index, all) => all.findIndex(f => f.urn === file.urn) === index);
14250
+ }
14251
+ }
14252
+ // Keep a stable list even if upstream metadata briefly duplicates entries.
14253
+ return files.filter((file, index, all) => all.findIndex(f => f.urn === file.urn) === index);
14131
14254
  }
14132
- } else if ((_uischema$scope2 = uischema.scope) != null && _uischema$scope2.startsWith('#/')) {
14133
- labelToUpdate = getGeneratedLabelFromScope(uischema.scope);
14134
- } else {
14135
- labelToUpdate = propLabel;
14136
- }
14137
- let reviewText = data;
14138
- const isBoolean = typeof data === 'boolean';
14139
- const getArrayDisplayValues = () => {
14140
- var _itemSchema$oneOf;
14141
- if (!Array.isArray(data)) {
14142
- return [];
14255
+ return fileList[metadataKey] || fileList[propertyId] || [];
14256
+ }, [fileList, isMultiFile, metadataKey, rootPath, propertyId, data]);
14257
+ const fileListLength = filesForDisplay.length;
14258
+ useEffect(() => {
14259
+ // Clear pending upload index when rendered file list catches up.
14260
+ pendingUploadIndexRef.current = null;
14261
+ }, [fileListLength, metadataKey, rootPath]);
14262
+ const getNextUploadIndex = () => {
14263
+ const baseIndex = filesForDisplay.length;
14264
+ if (pendingUploadIndexRef.current === null || pendingUploadIndexRef.current < baseIndex) {
14265
+ pendingUploadIndexRef.current = baseIndex;
14143
14266
  }
14144
- const itemSchema = schema == null ? void 0 : schema.items;
14145
- const oneOf = (_itemSchema$oneOf = itemSchema == null ? void 0 : itemSchema.oneOf) != null ? _itemSchema$oneOf : [];
14146
- const titleByConst = new Map();
14147
- oneOf.forEach(option => {
14148
- var _option$title;
14149
- if (!(option != null && option.const)) return;
14150
- titleByConst.set(option.const, (_option$title = option.title) != null ? _option$title : option.const);
14151
- });
14152
- return data.map(value => {
14153
- const raw = typeof value === 'string' ? value : String(value);
14154
- return titleByConst.get(raw) || raw;
14155
- });
14267
+ const nextIndex = pendingUploadIndexRef.current;
14268
+ pendingUploadIndexRef.current += 1;
14269
+ return nextIndex;
14156
14270
  };
14157
- if (isBoolean) {
14158
- var _uischema$options2, _uischema$options3;
14159
- let checkboxLabel = '';
14160
- if ((_uischema$options2 = uischema.options) != null && (_uischema$options2 = _uischema$options2.text) != null && _uischema$options2.trim()) {
14161
- checkboxLabel = uischema.options.text.trim();
14162
- } else if (uischema.scope && uischema.scope.startsWith('#/')) {
14163
- checkboxLabel = getGeneratedLabelFromScope(uischema.scope);
14164
- }
14165
- if (((_uischema$options3 = uischema.options) == null ? void 0 : _uischema$options3.radio) === true) {
14166
- reviewText = data ? `Yes` : `No`;
14167
- } else {
14168
- if (label !== '' || typeof label === 'boolean') {
14169
- reviewText = data ? `Yes` : `No`;
14170
- } else {
14171
- reviewText = data ? `Yes (${checkboxLabel})` : `No (${checkboxLabel})`;
14172
- }
14271
+ async function uploadFile(file, requestedIndex) {
14272
+ if (!uploadTrigger) return;
14273
+ const fileListLength = requestedIndex != null ? requestedIndex : isMultiFile ? getNextUploadIndex() : filesForDisplay.length;
14274
+ // Single-file controls should allow selecting a new file to replace the current one.
14275
+ if (isMultiFile && fileListLength >= maxFiles) {
14276
+ setUploadError(`You can only upload up to ${maxFiles} file${maxFiles > 1 ? 's' : ''}.`);
14277
+ return;
14173
14278
  }
14279
+ setUploadError(undefined);
14280
+ setLoadingFileName(file == null ? void 0 : file.name);
14281
+ await Promise.resolve(uploadTrigger(file, isMultiFile ? `${rootPath}.${fileListLength}` : path));
14282
+ setDeleteHide(false);
14174
14283
  }
14175
- if (Array.isArray(data) && data.length > 0) {
14176
- const displayValues = getArrayDisplayValues();
14177
- reviewText = jsx("ul", {
14178
- style: {
14179
- margin: 0,
14180
- paddingLeft: '1.25rem'
14181
- },
14182
- children: displayValues.map((value, index) => jsx("li", {
14183
- children: value
14184
- }, `${value}-${index}`))
14284
+ function queueUpload(file, requestedIndex) {
14285
+ uploadQueueRef.current = uploadQueueRef.current.then(() => uploadFile(file, requestedIndex)).catch(() => {
14286
+ // Keep queue alive after an individual upload failure.
14185
14287
  });
14186
14288
  }
14187
- // Helper to extract errors manually from global state, bypassing "touched" filter
14188
- const normalizePath = p => p.replace(/\[(\d+)\]/g, '.$1').replace(/\//g, '.').replace(/^\./, '');
14189
- const findMatchingError = currentErrors => {
14190
- if (!currentErrors) return undefined;
14191
- const normalizedPropPath = normalizePath(path || '');
14192
- for (const e of currentErrors) {
14193
- var _e$params2;
14194
- const errorPath = normalizePath(e.dataPath || e.instancePath || '');
14195
- if (errorPath === normalizedPropPath) {
14196
- return e;
14197
- }
14198
- if (e.keyword === 'required') {
14199
- var _e$params;
14200
- const missing = (_e$params = e.params) == null ? void 0 : _e$params.missingProperty;
14201
- if (missing) {
14202
- const missingPath = errorPath ? `${errorPath}.${missing}` : missing;
14203
- if (missingPath === normalizedPropPath) {
14204
- return e;
14205
- }
14206
- }
14207
- }
14208
- if (e.keyword === 'errorMessage' && (_e$params2 = e.params) != null && _e$params2.errors) {
14209
- const nested = findMatchingError(e.params.errors);
14210
- if (nested) return nested;
14211
- }
14212
- }
14213
- return undefined;
14214
- };
14215
- const matchedError = findMatchingError((_jsonForms$core = jsonForms.core) == null ? void 0 : _jsonForms$core.errors);
14216
- let activeError;
14217
- if (matchedError) {
14218
- try {
14219
- if (matchedError.keyword === 'errorMessage' && matchedError.message) {
14220
- activeError = matchedError.message;
14221
- } else if (matchedError.keyword === 'minItems') {
14222
- var _schema$errorMessage;
14223
- const minItemsError = (_schema$errorMessage = schema.errorMessage) == null ? void 0 : _schema$errorMessage.minItems;
14224
- activeError = minItemsError || humanizeAjvError(matchedError, schema, uischema);
14225
- } else {
14226
- activeError = humanizeAjvError(matchedError, rootSchema != null ? rootSchema : schema, uischema);
14227
- }
14228
- } catch (_unused) {
14229
- var _matchedError$params;
14230
- // Fallback: try to extract missing property name and create a friendly message
14231
- if (matchedError.keyword === 'required' && (_matchedError$params = matchedError.params) != null && _matchedError$params.missingProperty) {
14232
- const missing = matchedError.params.missingProperty;
14233
- const missingPropertyLabel = convertToReadableFormat(missing);
14234
- activeError = `${missingPropertyLabel} is required`;
14235
- } else if (matchedError.keyword === 'minItems') {
14236
- var _schema$errorMessage2;
14237
- activeError = (_schema$errorMessage2 = schema.errorMessage) == null ? void 0 : _schema$errorMessage2.minItems;
14238
- } else {
14239
- var _matchedError$message;
14240
- const propertyMatch = (_matchedError$message = matchedError.message) == null ? void 0 : _matchedError$message.match(/'([^']+)'/);
14241
- if (propertyMatch && propertyMatch[1]) {
14242
- const missingPropertyLabel = convertToReadableFormat(propertyMatch[1]);
14243
- activeError = `${missingPropertyLabel} is required`;
14244
- } else {
14245
- activeError = matchedError.message;
14246
- }
14247
- }
14289
+ function downloadFile(file) {
14290
+ if (downloadTrigger && file) {
14291
+ downloadTrigger(file, propertyId);
14248
14292
  }
14249
14293
  }
14250
- if (!activeError && typeof errors === 'string' && errors.trim() !== '') {
14251
- activeError = errors;
14252
- }
14253
- // A required field with no user-entered value should always show the required error, even when
14254
- // another AJV rule (e.g. minLength) also fires against the empty value — required takes priority
14255
- // over any other validation message. isNilOrEmptyValue deliberately doesn't treat boolean `false`
14256
- // as empty, so an unchecked required checkbox still falls through to the boolean-specific handling
14257
- // below instead of being clobbered here.
14258
- if (required && isNilOrEmptyValue(data, true)) {
14259
- // clean-code-ignore: 2.18
14260
- activeError = `${labelToUpdate} is required`;
14261
- }
14262
- const isRegisterBackedEnumFalsePositive = (uischema == null || (_uischema$options4 = uischema.options) == null ? void 0 : _uischema$options4.register) !== undefined && !isNilOrEmptyValue(data, true) && typeof activeError === 'string' && activeError.toLowerCase().includes('must be equal to one of the allowed values');
14263
- if (isRegisterBackedEnumFalsePositive) {
14264
- activeError = undefined;
14265
- }
14266
- if (activeError && /\sis required$/i.test(activeError)) {
14267
- activeError = `${labelToUpdate} is required`;
14294
+ function deleteFile(file) {
14295
+ if (deleteTrigger && file) {
14296
+ deleteTrigger(file, propertyId);
14297
+ }
14268
14298
  }
14269
- // For required boolean fields (e.g. anyOf: [{enum: [true]}]), suppress the raw AJV
14270
- // "must be equal to one of the allowed values" error and show a friendly message instead.
14271
- if ((schema == null ? void 0 : schema.type) === 'boolean' && activeError && activeError.toLowerCase().includes('must be equal')) {
14272
- activeError = data === false ? `${labelToUpdate} is required` : undefined;
14299
+ function getFileName(index) {
14300
+ var _getFile;
14301
+ return (_getFile = getFile(index)) == null ? void 0 : _getFile.filename;
14273
14302
  }
14274
- // If a required checkbox is unchecked, show only the validation message in
14275
- // review mode (not a contradictory "No (...)" value line).
14276
- let isBooleanRequiredError = false;
14277
- if ((schema == null ? void 0 : schema.type) === 'boolean' && data === false && activeError && /\sis required$/i.test(activeError)) {
14278
- reviewText = '';
14279
- isBooleanRequiredError = true;
14303
+ function getFile(index) {
14304
+ return filesForDisplay == null ? void 0 : filesForDisplay[index];
14280
14305
  }
14281
- const stepId = (_uischema$options5 = uischema.options) == null ? void 0 : _uischema$options5.stepId;
14282
- function handleChangeClick() {
14283
- reportChange(stepId, uischema.scope);
14306
+ useEffect(() => {
14307
+ if (loadingFileName !== undefined) {
14308
+ setLoadingFileName(undefined);
14309
+ }
14310
+ const delayedFunction = () => {
14311
+ if (!fileList) return;
14312
+ const filesForControl = filesForDisplay || [];
14313
+ const hasFileListEntryForPath = Object.prototype.hasOwnProperty.call(fileList, metadataKey) || Object.prototype.hasOwnProperty.call(fileList, rootPath) || !isMultiFile && Object.prototype.hasOwnProperty.call(fileList, propertyId);
14314
+ const urns = filesForControl.map(f => f.urn);
14315
+ if (urns.length === 0) {
14316
+ if (hasFileListEntryForPath && data !== undefined && data !== null && data !== '') {
14317
+ handleChange(isMultiFile ? rootPath : path, undefined);
14318
+ }
14319
+ } else if (isMultiFile) {
14320
+ handleChange(rootPath, urns);
14321
+ } else {
14322
+ // Single-file replacement appends metadata; keep the latest selection as the current value.
14323
+ handleChange(path, urns[urns.length - 1]);
14324
+ }
14325
+ };
14326
+ const timeoutId = setTimeout(delayedFunction, 1);
14327
+ return () => clearTimeout(timeoutId);
14328
+ }, [data, fileList, filesForDisplay, rootPath, path, propertyId, metadataKey, isMultiFile, handleChange, loadingFileName]);
14329
+ const readOnly = (uischema == null || (_uischema$options6 = uischema.options) == null || (_uischema$options6 = _uischema$options6.componentProps) == null ? void 0 : _uischema$options6.readOnly) === true || (props == null ? void 0 : props.isStepperReview) === true || user === null;
14330
+ const maxFileSize = (_uischema$options$com2 = uischema == null || (_uischema$options7 = uischema.options) == null || (_uischema$options7 = _uischema$options7.componentProps) == null ? void 0 : _uischema$options7.maxFileSize) != null ? _uischema$options$com2 : '';
14331
+ const accept = (_uischema$options$com3 = uischema == null || (_uischema$options8 = uischema.options) == null || (_uischema$options8 = _uischema$options8.componentProps) == null ? void 0 : _uischema$options8.accept) != null ? _uischema$options$com3 : '';
14332
+ if (!enumerators) {
14333
+ //eslint-disable-next-line
14334
+ return jsx(Fragment, {});
14284
14335
  }
14285
- const showInlineValue = reviewText === null || reviewText === undefined || typeof reviewText === 'string' || typeof reviewText === 'number' || /*#__PURE__*/React.isValidElement(reviewText) || Array.isArray(reviewText) && reviewText.length === 0;
14286
- const isValueEmpty = !isBooleanRequiredError && (reviewText === null || reviewText === undefined || reviewText === '' || Array.isArray(reviewText) && reviewText.length === 0);
14287
- return jsx("tr", {
14288
- "data-testid": `input-base-table-${label}-row`,
14289
- children: jsxs(PageReviewContainer, {
14290
- colSpan: 3,
14291
- children: [jsxs(ReviewHeader, {
14292
- children: [jsxs(ReviewLabel, {
14293
- children: [labelToUpdate, required && jsx(RequiredTextLabel, {
14294
- children: " (required)"
14295
- })]
14296
- }), showChangeButtons && stepId !== undefined && !((_uischema$options6 = uischema.options) != null && (_uischema$options6 = _uischema$options6.componentProps) != null && _uischema$options6.readOnly) && jsx(BackButton, {
14297
- text: "Change",
14298
- link: handleChangeClick,
14299
- showBackIcon: false
14336
+ const helpText = uischema == null || (_uischema$options9 = uischema.options) == null ? void 0 : _uischema$options9.help;
14337
+ const sentenceCaseLabel = label;
14338
+ const renderFileItem = index => {
14339
+ var _getFile2;
14340
+ const showFileDeleteConfirmation = deleteConfirmIndex === index;
14341
+ return jsx("div", {
14342
+ children: readOnly ? jsxs(AttachmentBorderDisabled, {
14343
+ children: [getFileName(index), noDownloadButtonInReview !== true && jsx(GoAContextMenuIcon, {
14344
+ testId: "download-icon",
14345
+ title: "Download",
14346
+ type: "download",
14347
+ onClick: () => downloadFile(getFile(index))
14300
14348
  })]
14301
- }), jsxs(ReviewValue, {
14302
- children: [showInlineValue ? jsx("div", {
14303
- "data-testid": `review-value-${label}`,
14304
- children: isValueEmpty ? jsx(NoneGivenText, {
14305
- children: noAnswerMessage
14306
- }) : reviewText != null ? reviewText : ''
14307
- }) : jsx(JsonFormsDispatch, {
14308
- "data-testid": `jsonforms-object-list-defined-elements-dispatch`,
14309
- schema: schema,
14310
- uischema: uischema,
14311
- enabled: enabled,
14312
- renderers: jsonForms.renderers,
14313
- cells: cells
14314
- }), activeError && jsx(GoabFormItem, {
14315
- error: activeError,
14316
- label: ""
14349
+ }) : jsxs(AttachmentBorder, {
14350
+ children: [jsx("div", {
14351
+ children: getFileName(index)
14352
+ }), jsxs(GoAContextMenu, {
14353
+ children: [noDownloadButton !== true && jsx(GoAContextMenuIcon, {
14354
+ testId: "download-icon",
14355
+ title: "Download",
14356
+ type: "download",
14357
+ onClick: () => downloadFile(getFile(index))
14358
+ }), noDeleteButton !== true && jsx(GoAContextMenuIcon, {
14359
+ "data-testid": "delete-icon",
14360
+ title: "Delete",
14361
+ type: "trash",
14362
+ onClick: () => {
14363
+ setDeleteConfirmIndex(index);
14364
+ }
14365
+ })]
14366
+ }), jsx(DeleteFileModal, {
14367
+ isOpen: showFileDeleteConfirmation,
14368
+ title: "Delete file",
14369
+ content: `Delete file ${(_getFile2 = getFile(index)) == null ? void 0 : _getFile2.filename} ?`,
14370
+ onCancel: () => setDeleteConfirmIndex(null),
14371
+ onDelete: () => {
14372
+ setDeleteConfirmIndex(null);
14373
+ deleteFile(getFile(index));
14374
+ if (!isMultiFile) {
14375
+ setDeleteHide(true);
14376
+ }
14377
+ setUploadError(undefined);
14378
+ }
14317
14379
  })]
14318
- })]
14319
- })
14320
- });
14321
- };
14322
- const GoAInputBaseTableReviewControl = withJsonFormsControlProps(GoAInputBaseTableReview);
14323
-
14324
- const defaultLabel = 'Email address';
14325
- const GoAEmailInput = props => {
14326
- var _uischema$options$com, _uischema$options, _uischema$options$com2, _uischema$options2, _stepperState$categor;
14327
- const {
14328
- data,
14329
- config,
14330
- id,
14331
- enabled,
14332
- visible,
14333
- uischema,
14334
- errors,
14335
- schema,
14336
- required,
14337
- label,
14338
- handleChange
14339
- } = props;
14340
- const defaultSchema = schema;
14341
- const appliedUiSchemaOptions = Object.assign({}, config, uischema == null ? void 0 : uischema.options);
14342
- const readOnly = (_uischema$options$com = uischema == null || (_uischema$options = uischema.options) == null || (_uischema$options = _uischema$options.componentProps) == null ? void 0 : _uischema$options.readOnly) != null ? _uischema$options$com : false;
14343
- const width = (_uischema$options$com2 = uischema == null || (_uischema$options2 = uischema.options) == null || (_uischema$options2 = _uischema$options2.componentProps) == null ? void 0 : _uischema$options2.width) != null ? _uischema$options$com2 : '100%';
14344
- const formStepperCtx = useContext(JsonFormsStepperContext);
14345
- const stepperState = formStepperCtx == null || formStepperCtx.selectStepperState == null ? void 0 : formStepperCtx.selectStepperState();
14346
- const currentCategory = stepperState == null || (_stepperState$categor = stepperState.categories) == null ? void 0 : _stepperState$categor[stepperState == null ? void 0 : stepperState.activeId];
14347
- const showReviewLink = currentCategory == null ? void 0 : currentCategory.showReviewPageLink;
14348
- const [localValue, setLocalValue] = useState(data);
14349
- const debouncedValue = useDebounce(localValue, 300);
14350
- useEffect(() => {
14351
- if (data === undefined || data === null) {
14352
- return;
14353
- }
14354
- setLocalValue(data);
14355
- }, [data]);
14356
- /* istanbul ignore next */
14357
- useEffect(() => {
14358
- if (debouncedValue === data) return;
14359
- // Only sync if debouncedValue differs from data and is not initial empty state
14360
- if (debouncedValue !== data && (debouncedValue !== '' || data !== undefined)) {
14361
- onChangeForInputControl({
14362
- value: debouncedValue,
14363
- controlProps: props
14364
- });
14365
- }
14366
- }, [debouncedValue]);
14367
- const [isVisited, setIsVisited] = useState(false);
14368
- useEffect(() => {
14369
- if (showReviewLink === true) {
14370
- setIsVisited(true);
14371
- }
14372
- }, [showReviewLink]);
14373
- const splitErrors = (errors != null ? errors : '').split(/\r?\n/).map(e => e.trim()).filter(Boolean);
14374
- const primaryLabel = (defaultSchema == null ? void 0 : defaultSchema.label) || defaultLabel;
14375
- const splintIndex = splitErrors.findIndex(e => e === REQUIRED_PROPERTY_ERROR);
14376
- splitErrors[splintIndex] = `${primaryLabel} is required`;
14377
- const finalErrors = splitErrors.join('\n');
14378
- useEffect(() => {
14379
- if (typeof handleChange === 'function' && (schema == null ? void 0 : schema.default) !== undefined && data === undefined) {
14380
- handleChange(props.path, schema.default);
14381
- setLocalValue(schema.default);
14382
- }
14383
- // eslint-disable-next-line react-hooks/exhaustive-deps
14384
- }, [schema.default, data]);
14380
+ })
14381
+ });
14382
+ };
14385
14383
  return jsx(Visible, {
14386
14384
  "$visible": visible,
14387
- children: jsx(JsonFormRegisterProvider, {
14388
- defaultRegisters: undefined,
14389
- children: jsx(FormFieldWrapper$1, {
14390
- children: jsx(GoabFormItem, {
14391
- error: isVisited && finalErrors,
14392
- testId: "form-email-input-wrapper",
14393
- requirement: required ? 'required' : undefined,
14394
- label: primaryLabel,
14395
- children: jsx(GoabInput, {
14396
- error: isVisited && finalErrors.length > 0,
14397
- type: 'email',
14398
- width: width,
14399
- name: "Email address",
14400
- value: data,
14401
- testId: (appliedUiSchemaOptions == null ? void 0 : appliedUiSchemaOptions.testId) || `${id}-input`,
14402
- disabled: !enabled,
14403
- readonly: readOnly,
14404
- onChange: detail => {
14405
- if (!isVisited) {
14406
- setIsVisited(true);
14407
- }
14408
- setLocalValue(detail.value);
14409
- },
14410
- onBlur: detail => {
14411
- if (!isVisited) {
14412
- setIsVisited(true);
14385
+ children: jsxs(FileUploaderStyle, {
14386
+ className: "FileUploader",
14387
+ children: [jsx(GoabFormItem, {
14388
+ label: sentenceCaseLabel,
14389
+ requirement: required ? 'required' : undefined,
14390
+ error: uploadError
14391
+ }), !readOnly && jsx("div", {
14392
+ className: "file-upload",
14393
+ children: jsx(GoabFileUploadInput, {
14394
+ variant: variant,
14395
+ onSelectFile: detail => {
14396
+ var _detail$files;
14397
+ const selectedFiles = detail != null && (_detail$files = detail.files) != null && _detail$files.length ? detail.files : detail != null && detail.file ? [detail.file] : [];
14398
+ if (selectedFiles.length === 0) {
14399
+ return;
14400
+ }
14401
+ if (isMultiFile) {
14402
+ for (const selectedFile of selectedFiles) {
14403
+ const nextIndex = getNextUploadIndex();
14404
+ if (nextIndex >= maxFiles) {
14405
+ setUploadError(`You can only upload up to ${maxFiles} file${maxFiles > 1 ? 's' : ''}.`);
14406
+ break;
14407
+ }
14408
+ queueUpload(selectedFile, nextIndex);
14413
14409
  }
14414
- onBlurForTextControl({
14415
- name: detail.name,
14416
- value: detail.value,
14417
- controlProps: props
14418
- });
14410
+ } else {
14411
+ queueUpload(selectedFiles[0]);
14419
14412
  }
14413
+ },
14414
+ maxFileSize: maxFileSize,
14415
+ accept: accept
14416
+ })
14417
+ }), helpText && jsx(HelpText, {
14418
+ children: helpText
14419
+ }), jsx("div", {
14420
+ children: loadingFileName !== undefined ? jsx(GoabModal, {
14421
+ open: loadingFileName !== undefined,
14422
+ children: jsx("div", {
14423
+ className: "align-center",
14424
+ children: jsx(GoabCircularProgress, {
14425
+ visible: true,
14426
+ message: `Uploading ${loadingFileName}`,
14427
+ size: "large"
14428
+ })
14420
14429
  })
14430
+ }) : jsx("div", {
14431
+ children: (fileList && isMultiFile ? filesForDisplay.map((_, i) => i) : !deleteHide && getFile(fileListLength - 1) && fileListLength >= 0 ? [fileListLength - 1] : []).map(index => jsx(React.Fragment, {
14432
+ children: renderFileItem(index)
14433
+ }, index))
14421
14434
  })
14422
- })
14435
+ })]
14423
14436
  })
14424
14437
  });
14425
14438
  };
14426
- const GoAEmailControl = props => jsx(GoAEmailInput, Object.assign({}, props));
14427
- const GoAEmailControlTester = rankWith(4, and(isControl$1, schemaTypeIs('string'), formatIs('email')));
14428
- const GoAInputEmailControl = withJsonFormsControlProps(GoAEmailControl);
14439
+ const HelpText = styled.div(_t$6 || (_t$6 = _2`
14440
+ margin-top: var(--goa-space-xs);
14441
+ font-size: var(--goa-font-size-3);
14442
+ color: var(--goa-color-text-secondary);
14443
+ `));
14444
+ const AttachmentBorderDisabled = styled.div(_t2$3 || (_t2$3 = _2`
14445
+ display: flex;
14446
+ flex-direction: row;
14447
+ border: var(--goa-border-width-s) solid #dcdcdc;
14448
+ border-radius: var(--goa-border-radius-m);
14449
+ padding: var(--goa-space-xs);
14450
+ width: fit-content;
14451
+ background-color: #f1f1f1;
14452
+ `));
14453
+ const AttachmentBorder = styled.div(_t3$2 || (_t3$2 = _2`
14454
+ display: flex;
14455
+ flex-direction: row;
14456
+ border: var(--goa-border-width-s) solid #dcdcdc;
14457
+ border-radius: var(--goa-border-radius-m);
14458
+ padding: var(--goa-space-xs);
14459
+ width: fit-content;
14460
+ margin-top: var(--goa-space-2xs);
14461
+ `));
14462
+ const FileUploaderStyle = styled.div(_t4$2 || (_t4$2 = _2`
14463
+ margin-bottom: var(--goa-space-l);
14464
+ .label {
14465
+ display: block;
14466
+ font-weight: var(--goa-font-weight-bold);
14467
+ color: var(--goa-color-text-default);
14468
+ font-size: var(--goa-font-size-4);
14469
+ padding: 0 0 var(--goa-space-xs) 0;
14470
+ }
14429
14471
 
14430
- let _$6 = t => t,
14431
- _t$7;
14432
- const renderLayoutElements = (elements, schema, path, enabled, renderers, cells) => {
14433
- return elements.map((child, index) => jsx(JsonFormsDispatch, {
14434
- uischema: child,
14435
- schema: schema,
14436
- path: path,
14437
- enabled: enabled,
14438
- renderers: renderers,
14439
- cells: cells
14440
- }, `review-${path}_${index}`));
14441
- };
14442
- const withAjvProps = Component => function WithAjvProps(props) {
14443
- const ctx = useJsonForms();
14444
- const ajv = getAjv({
14445
- jsonforms: Object.assign({}, ctx)
14446
- });
14447
- return jsx(Component, Object.assign({}, props, {
14448
- ajv: ajv
14449
- }));
14450
- };
14451
- const LayoutRenderer = ({
14452
- elements,
14453
- schema,
14454
- path,
14455
- enabled,
14456
- direction,
14457
- renderers,
14458
- cells,
14459
- visible,
14460
- width
14461
- }) => {
14462
- if (isEmpty$1(elements)) {
14463
- return null;
14464
- } else {
14465
- if (direction === 'row') {
14466
- return jsx(Visible, {
14467
- "$visible": visible,
14468
- children: jsx(GoabGrid$1, {
14469
- minChildWidth: width || '10ch',
14470
- children: renderLayoutElements(elements, schema, path, enabled, renderers, cells)
14471
- })
14472
- });
14473
- } else {
14474
- return jsx(Visible, {
14475
- "$visible": visible,
14476
- children: renderLayoutElements(elements, schema, path, enabled, renderers, cells)
14477
- });
14478
- }
14472
+ .align-center {
14473
+ text-align-last: center;
14474
+ }
14475
+
14476
+ .file-upload {
14477
+ margin-bottom: var(--goa-space-xs);
14479
14478
  }
14479
+ `));
14480
+
14481
+ const isFileUrnSchema = schema => {
14482
+ if ((schema == null ? void 0 : schema.format) === 'file-urn') return true;
14483
+ const items = schema == null ? void 0 : schema.items;
14484
+ return (schema == null ? void 0 : schema.type) === 'array' && !Array.isArray(items) && (items == null ? void 0 : items.format) === 'file-urn';
14480
14485
  };
14481
- const ReviewLayoutRenderer = ({
14482
- elements,
14483
- schema,
14484
- path,
14485
- enabled,
14486
- direction,
14487
- renderers,
14488
- cells,
14489
- visible,
14490
- width
14491
- }) => {
14492
- if (isEmpty$1(elements)) {
14486
+ const GoAInputBaseTableReview = props => {
14487
+ var _uischema$options, _uischema$scope2, _jsonForms$core, _uischema$options4, _uischema$options5, _uischema$options6;
14488
+ const {
14489
+ data,
14490
+ uischema,
14491
+ label,
14492
+ schema,
14493
+ rootSchema,
14494
+ path,
14495
+ errors,
14496
+ enabled,
14497
+ cells,
14498
+ required,
14499
+ visible
14500
+ } = props;
14501
+ const reportChange = useReviewChange();
14502
+ const {
14503
+ noAnswerMessage
14504
+ } = useStepperPageOptions();
14505
+ const showChangeButtons = useShowChangeButtons();
14506
+ const jsonForms = useJsonForms();
14507
+ const reviewLabel = typeof ((_uischema$options = uischema.options) == null ? void 0 : _uischema$options.reviewLabel) === 'string' ? uischema.options.reviewLabel : '';
14508
+ const propLabel = typeof label === 'string' ? label : '';
14509
+ if (visible === false) {
14493
14510
  return null;
14494
- } else {
14495
- if (direction === 'row') {
14496
- return jsx(Visible, {
14497
- "$visible": visible,
14498
- children: jsx(ReviewGrid, {
14499
- children: renderLayoutElements(elements, schema, path, enabled, renderers, cells)
14500
- })
14501
- });
14511
+ }
14512
+ let labelToUpdate = '';
14513
+ if (reviewLabel.trim() !== '') {
14514
+ labelToUpdate = reviewLabel;
14515
+ } else if (typeof (schema == null ? void 0 : schema.title) === 'string' && schema.title.trim()) {
14516
+ labelToUpdate = schema.title;
14517
+ } else if (propLabel.trim() !== '') {
14518
+ var _uischema$scope;
14519
+ if ((_uischema$scope = uischema.scope) != null && _uischema$scope.startsWith('#/') && controlScopeMatchesLabel(uischema.scope, propLabel)) {
14520
+ labelToUpdate = getLabelText(uischema.scope, propLabel);
14502
14521
  } else {
14503
- return jsx(Visible, {
14504
- "$visible": visible,
14505
- children: renderLayoutElements(elements, schema, path, enabled, renderers, cells)
14506
- });
14522
+ labelToUpdate = propLabel;
14507
14523
  }
14524
+ } else if ((_uischema$scope2 = uischema.scope) != null && _uischema$scope2.startsWith('#/')) {
14525
+ labelToUpdate = getGeneratedLabelFromScope(uischema.scope);
14526
+ } else {
14527
+ labelToUpdate = propLabel;
14508
14528
  }
14509
- };
14510
- const ReviewGrid = styled.div(_t$7 || (_t$7 = _$6`
14511
- display: grid;
14512
- grid-template-columns: repeat(auto-fit, minmax(250px, calc(50% - 8px)));
14513
- gap: 16px;
14514
- `));
14515
-
14516
- let _$5 = t => t,
14517
- _t$6,
14518
- _t2$3,
14519
- _t3$2,
14520
- _t4$2,
14521
- _t5$1,
14522
- _t6$1,
14523
- _t7,
14524
- _t8,
14525
- _t9,
14526
- _t0,
14527
- _t1,
14528
- _t10,
14529
- _t11,
14530
- _t12,
14531
- _t13,
14532
- _t14,
14533
- _t15,
14534
- _t16,
14535
- _t17,
14536
- _t18,
14537
- _t19,
14538
- _t20,
14539
- _t21,
14540
- _t22,
14541
- _t23,
14542
- _t24,
14543
- _t25,
14544
- _t26,
14545
- _t27,
14546
- _t28,
14547
- _t29;
14548
- const ReviewItem = styled.div(_t$6 || (_t$6 = _$5`
14549
- display: flex;
14550
- flex-direction: column;
14551
- `));
14552
- const CompletionStatus = styled.div(_t2$3 || (_t2$3 = _$5`
14553
- padding: 0;
14554
- margin: 0;
14555
- padding-top: var(--goa-space-xl);
14556
-
14557
- display: flex;
14558
- flex-direction: column;
14559
- `));
14560
- const BarTop = styled.div(_t3$2 || (_t3$2 = _$5`
14561
- display: flex;
14562
-
14563
- .progress-text {
14564
- margin-left: auto;
14529
+ let reviewText = data;
14530
+ const isBoolean = typeof data === 'boolean';
14531
+ const getArrayDisplayValues = () => {
14532
+ var _itemSchema$oneOf;
14533
+ if (!Array.isArray(data)) {
14534
+ return [];
14535
+ }
14536
+ const itemSchema = schema == null ? void 0 : schema.items;
14537
+ const oneOf = (_itemSchema$oneOf = itemSchema == null ? void 0 : itemSchema.oneOf) != null ? _itemSchema$oneOf : [];
14538
+ const titleByConst = new Map();
14539
+ oneOf.forEach(option => {
14540
+ var _option$title;
14541
+ if (!(option != null && option.const)) return;
14542
+ titleByConst.set(option.const, (_option$title = option.title) != null ? _option$title : option.const);
14543
+ });
14544
+ return data.map(value => {
14545
+ const raw = typeof value === 'string' ? value : String(value);
14546
+ return titleByConst.get(raw) || raw;
14547
+ });
14548
+ };
14549
+ if (isBoolean) {
14550
+ var _uischema$options2, _uischema$options3;
14551
+ let checkboxLabel = '';
14552
+ if ((_uischema$options2 = uischema.options) != null && (_uischema$options2 = _uischema$options2.text) != null && _uischema$options2.trim()) {
14553
+ checkboxLabel = uischema.options.text.trim();
14554
+ } else if (uischema.scope && uischema.scope.startsWith('#/')) {
14555
+ checkboxLabel = getGeneratedLabelFromScope(uischema.scope);
14556
+ }
14557
+ if (((_uischema$options3 = uischema.options) == null ? void 0 : _uischema$options3.radio) === true) {
14558
+ reviewText = data ? `Yes` : `No`;
14559
+ } else {
14560
+ if (label !== '' || typeof label === 'boolean') {
14561
+ reviewText = data ? `Yes` : `No`;
14562
+ } else {
14563
+ reviewText = data ? `Yes (${checkboxLabel})` : `No (${checkboxLabel})`;
14564
+ }
14565
+ }
14565
14566
  }
14566
- `));
14567
- const Bar = styled.div(_t4$2 || (_t4$2 = _$5`
14568
- display: flex;
14569
- flex-direction: row;
14570
-
14571
- .progress-container {
14572
- align-items: flex-start;
14573
- width: 100%;
14574
-
14575
- height: 4px;
14576
- background-color: #e0e0e0;
14577
- border-radius: 4;
14578
- overflow: hidden;
14579
- position: relative;
14580
- border: 1px solid #ccc;
14581
- margin-bottom: 20px;
14567
+ if (Array.isArray(data) && data.length > 0) {
14568
+ const displayValues = getArrayDisplayValues();
14569
+ reviewText = jsx("ul", {
14570
+ style: {
14571
+ margin: 0,
14572
+ paddingLeft: '1.25rem'
14573
+ },
14574
+ children: displayValues.map((value, index) => jsx("li", {
14575
+ children: value
14576
+ }, `${value}-${index}`))
14577
+ });
14582
14578
  }
14583
-
14584
- .progress-bar {
14585
- width: 60%;
14586
- height: 100%;
14587
- background-color: #004abf;
14588
- border-radius: 4;
14589
- position: relative;
14590
- display: flex;
14591
- align-items: center;
14592
- justify-content: flex-end;
14593
-
14594
- box-sizing: border-box;
14579
+ // Helper to extract errors manually from global state, bypassing "touched" filter
14580
+ const normalizePath = p => p.replace(/\[(\d+)\]/g, '.$1').replace(/\//g, '.').replace(/^\./, '');
14581
+ const findMatchingError = currentErrors => {
14582
+ if (!currentErrors) return undefined;
14583
+ const normalizedPropPath = normalizePath(path || '');
14584
+ for (const e of currentErrors) {
14585
+ var _e$params2;
14586
+ const errorPath = normalizePath(e.dataPath || e.instancePath || '');
14587
+ if (errorPath === normalizedPropPath) {
14588
+ return e;
14589
+ }
14590
+ if (e.keyword === 'required') {
14591
+ var _e$params;
14592
+ const missing = (_e$params = e.params) == null ? void 0 : _e$params.missingProperty;
14593
+ if (missing) {
14594
+ const missingPath = errorPath ? `${errorPath}.${missing}` : missing;
14595
+ if (missingPath === normalizedPropPath) {
14596
+ return e;
14597
+ }
14598
+ }
14599
+ }
14600
+ if (e.keyword === 'errorMessage' && (_e$params2 = e.params) != null && _e$params2.errors) {
14601
+ const nested = findMatchingError(e.params.errors);
14602
+ if (nested) return nested;
14603
+ }
14604
+ }
14605
+ return undefined;
14606
+ };
14607
+ const matchedError = findMatchingError((_jsonForms$core = jsonForms.core) == null ? void 0 : _jsonForms$core.errors);
14608
+ let activeError;
14609
+ if (matchedError) {
14610
+ try {
14611
+ if (matchedError.keyword === 'errorMessage' && matchedError.message) {
14612
+ activeError = matchedError.message;
14613
+ } else if (matchedError.keyword === 'minItems') {
14614
+ var _schema$errorMessage;
14615
+ const minItemsError = (_schema$errorMessage = schema.errorMessage) == null ? void 0 : _schema$errorMessage.minItems;
14616
+ activeError = minItemsError || humanizeAjvError(matchedError, schema, uischema);
14617
+ } else {
14618
+ activeError = humanizeAjvError(matchedError, rootSchema != null ? rootSchema : schema, uischema);
14619
+ }
14620
+ } catch (_unused) {
14621
+ var _matchedError$params;
14622
+ // Fallback: try to extract missing property name and create a friendly message
14623
+ if (matchedError.keyword === 'required' && (_matchedError$params = matchedError.params) != null && _matchedError$params.missingProperty) {
14624
+ const missing = matchedError.params.missingProperty;
14625
+ const missingPropertyLabel = convertToReadableFormat(missing);
14626
+ activeError = `${missingPropertyLabel} is required`;
14627
+ } else if (matchedError.keyword === 'minItems') {
14628
+ var _schema$errorMessage2;
14629
+ activeError = (_schema$errorMessage2 = schema.errorMessage) == null ? void 0 : _schema$errorMessage2.minItems;
14630
+ } else {
14631
+ var _matchedError$message;
14632
+ const propertyMatch = (_matchedError$message = matchedError.message) == null ? void 0 : _matchedError$message.match(/'([^']+)'/);
14633
+ if (propertyMatch && propertyMatch[1]) {
14634
+ const missingPropertyLabel = convertToReadableFormat(propertyMatch[1]);
14635
+ activeError = `${missingPropertyLabel} is required`;
14636
+ } else {
14637
+ activeError = matchedError.message;
14638
+ }
14639
+ }
14640
+ }
14595
14641
  }
14596
- `));
14597
- styled.div(_t5$1 || (_t5$1 = _$5``));
14598
- const BadgeWrapper = styled.div(_t6$1 || (_t6$1 = _$5`
14599
- margin-left: 10px;
14600
- margin-top: 7px;
14601
- `));
14602
- const CompletionTextHeader = styled.h3(_t7 || (_t7 = _$5`
14603
- display: flex;
14604
- `));
14605
- const ReviewItemSection = styled.div(_t8 || (_t8 = _$5`
14606
- margin-bottom: var(--goa-space-m);
14607
- padding: var(--goa-space-xl) var(--goa-space-2xl);
14608
- border: 1px solid var(--goa-color-greyscale-300);
14609
- border-radius: var(--goa-border-radius-xl);
14610
-
14611
- .element-style {
14612
- max-width: 1600px;
14642
+ if (!activeError && typeof errors === 'string' && errors.trim() !== '') {
14643
+ activeError = errors;
14613
14644
  }
14614
-
14615
- @media (max-width: 639px) {
14616
- padding: var(--goa-space-l) var(--goa-space-m);
14645
+ // A required field with no user-entered value should always show the required error, even when
14646
+ // another AJV rule (e.g. minLength) also fires against the empty value — required takes priority
14647
+ // over any other validation message. isNilOrEmptyValue deliberately doesn't treat boolean `false`
14648
+ // as empty, so an unchecked required checkbox still falls through to the boolean-specific handling
14649
+ // below instead of being clobbered here.
14650
+ if (required && isNilOrEmptyValue(data, true)) {
14651
+ // clean-code-ignore: 2.18
14652
+ activeError = `${labelToUpdate} is required`;
14617
14653
  }
14618
- `));
14619
- const ReviewSectionTitle = styled.h3(_t9 || (_t9 = _$5`
14620
- margin-bottom: var(--goa-space-m);
14621
- overflow-wrap: anywhere;
14622
- `));
14623
- const ReviewItemHeader = styled.div(_t0 || (_t0 = _$5`
14624
- display: flex;
14625
- align-items: center;
14626
- justify-content: space-between;
14627
- margin-bottom: var(--goa-space-xl);
14628
- `));
14629
- const ReviewItemTitle = styled.div(_t1 || (_t1 = _$5`
14630
- font-size: var(--goa-space-l);
14631
- line-height: var(--goa-space-xl);
14632
- font-weight: 300;
14633
- `));
14634
- styled.div(_t10 || (_t10 = _$5`
14635
- color: #0070c4;
14636
- text-decoration: underline;
14637
- outline: none;
14638
- cursor: pointer;
14639
-
14640
- &:focus {
14641
- outline: 2px solid #0070c4;
14642
- background-color: #e6f7ff;
14654
+ const isRegisterBackedEnumFalsePositive = (uischema == null || (_uischema$options4 = uischema.options) == null ? void 0 : _uischema$options4.register) !== undefined && !isNilOrEmptyValue(data, true) && typeof activeError === 'string' && activeError.toLowerCase().includes('must be equal to one of the allowed values');
14655
+ if (isRegisterBackedEnumFalsePositive) {
14656
+ activeError = undefined;
14643
14657
  }
14644
- `));
14645
- styled.div(_t11 || (_t11 = _$5`
14646
- margin-left: var(--goa-space-m);
14647
- `));
14648
- styled.div(_t12 || (_t12 = _$5`
14649
- margin-bottom: var(--goa-space-m);
14650
- `));
14651
- styled.div(_t13 || (_t13 = _$5`
14652
- margin: var(--goa-space-s);
14653
- width: 100%;
14654
- `));
14655
- styled.h3(_t14 || (_t14 = _$5`
14656
- text-transform: capitalize;
14657
- `));
14658
- const RightAlignmentDiv = styled.div(_t15 || (_t15 = _$5`
14659
- @media screen and (max-width: 767px) {
14660
- margin-bottom: var(--goa-space-l);
14658
+ if (activeError && /\sis required$/i.test(activeError)) {
14659
+ activeError = `${labelToUpdate} is required`;
14661
14660
  }
14662
- @media screen and (min-width: 768px) {
14663
- display: flex;
14664
- justify-content: flex-end;
14665
- margin-bottom: var(--goa-space-l);
14666
- }
14667
- `));
14668
- const FormStepperSummaryH3 = styled.h3(_t16 || (_t16 = _$5`
14669
- flex: 1;
14670
- max-width: 100%;
14671
- margin-bottom: var(--goa-space-m);
14672
- font-size: var(--goa-font-size-7);
14673
- line-height: var(--goa-line-height-4);
14674
- font-weight: var(--goa-font-weight-bold);
14675
- overflow-wrap: anywhere;
14676
- `));
14677
- const PageRenderPadding = styled.div(_t17 || (_t17 = _$5`
14678
- margin-top: var(--goa-space-2xl);
14679
- `));
14680
- styled.div(_t18 || (_t18 = _$5`
14681
- margin-bottom: var(--goa-space-2xl);
14682
- `));
14683
- const PageBorder = styled.div(_t19 || (_t19 = _$5`
14684
- padding: var(--goa-space-m) var(--goa-space-3xl);
14685
-
14686
- @media (max-width: 639px) {
14687
- padding: var(--goa-space-m) var(--goa-space-xs);
14688
- }
14689
- `));
14690
- styled.div(_t20 || (_t20 = _$5`
14691
- .element-style {
14692
- max-width: 1600px;
14693
- }
14694
- `));
14695
- styled.div(_t21 || (_t21 = _$5`
14696
- padding: var(--goa-space-xl) var(--goa-space-2xl);
14697
- border: 1px solid var(--goa-color-greyscale-300);
14698
- border-radius: var(--goa-border-radius-xl);
14699
- `));
14700
- styled.div(_t22 || (_t22 = _$5`
14701
- margin-top: var(--goa-space-xl);
14702
- display: flex;
14703
- justify-content: space-between;
14704
- `));
14705
- styled.h3(_t23 || (_t23 = _$5`
14706
- color: var(--goa-color-text-secondary) !important;
14707
- margin-bottom: var(--goa-space-l);
14708
- `));
14709
- const CategoryStatus = styled.td(_t24 || (_t24 = _$5`
14710
- width: var(--goa-space-xl);
14711
- padding-right: var(--goa-space-xl);
14712
- align-content: center;
14713
- `));
14714
- const Center = styled.div(_t25 || (_t25 = _$5`
14715
- padding-top: 5px;
14716
- `));
14717
- const PageStepperRow = styled.tr(_t26 || (_t26 = _$5`
14718
- ${0}
14719
- `), ({
14720
- disabled
14721
- }) => disabled ? `
14722
- pointer-events: none;
14723
- opacity: 0.5;
14724
- cursor: not-allowed;
14725
- ` : `
14726
- cursor: pointer;
14727
-
14728
- &:hover td {
14729
- background-color: var(--goa-color-greyscale-100);
14730
- }
14731
-
14732
- td {
14733
- transition: background-color 0.2s ease-in-out;
14734
- }
14735
-
14736
-
14737
- &:focus-visible {
14738
- border-radius: 0.25rem;
14739
- outline: 3px solid var(--goa-color-interactive-focus);
14740
- }
14741
- `);
14742
- const SectionHeaderRowTr = styled.tr(_t27 || (_t27 = _$5`
14743
- & > td {
14744
- border: 0 !important;
14745
- padding-top: var(--goa-space-l);
14746
- padding-bottom: var(--goa-space-s);
14747
- padding-left: 0 !important;
14748
- }
14749
-
14750
- & + tr > td {
14751
- border-top: none !important;
14752
- }
14753
- `));
14754
- const SummaryRowLink = styled.a(_t28 || (_t28 = _$5`
14755
- position: relative;
14756
- top: var(--goa-space-xs);
14757
- &:focus-visible {
14758
- border-radius: 0.25rem;
14759
- outline: 3px solid var(--goa-color-interactive-focus);
14661
+ // For required boolean fields (e.g. anyOf: [{enum: [true]}]), suppress the raw AJV
14662
+ // "must be equal to one of the allowed values" error and show a friendly message instead.
14663
+ if ((schema == null ? void 0 : schema.type) === 'boolean' && activeError && activeError.toLowerCase().includes('must be equal')) {
14664
+ activeError = data === false ? `${labelToUpdate} is required` : undefined;
14760
14665
  }
14761
- padding: 0 var(--goa-space-s) var(--goa-space-xs); var(--goa-space-s);
14762
- `));
14763
- const SummaryTd = styled.td(_t29 || (_t29 = _$5`
14764
- border: 0 !important;
14765
- padding: 0 !important;
14766
- `));
14767
-
14768
- const RenderStepElements = props => {
14769
- var _props$category;
14770
- // Passing the schema straight through matters for performance. This used to hand down a shallow
14771
- // copy, and because the copy is made in a hook it is a brand new object every time the step
14772
- // changes — which invalidates every identity-keyed cache downstream, including the renderer
14773
- // lookup JsonForms memoizes on the schema it is given.
14774
- const memoizedSchema = props.schema;
14775
- return jsx(Visible, {
14776
- "$visible": props.visible,
14777
- "data-testid": `${(props == null ? void 0 : props.path) || ((_props$category = props.category) == null ? void 0 : _props$category.label)}-categories-${props.categoryIndex}`,
14778
- children: props.category.elements.map((uiSchema, index) => {
14779
- var _props$category2;
14780
- return jsx(JsonFormsDispatch, {
14781
- schema: memoizedSchema,
14782
- uischema: uiSchema,
14783
- renderers: props.renderers,
14784
- cells: props.cells,
14785
- path: props.path,
14786
- visible: props.visible,
14787
- enabled: props.enabled
14788
- }, `${(props == null ? void 0 : props.path) || ((_props$category2 = props.category) == null ? void 0 : _props$category2.label)}-category-page-${index}`);
14789
- })
14790
- });
14791
- };
14792
-
14793
- var $$5 = _export;
14794
- var flattenIntoArray = flattenIntoArray_1;
14795
- var toObject$1 = toObject$d;
14796
- var lengthOfArrayLike$1 = lengthOfArrayLike$d;
14797
- var toIntegerOrInfinity = toIntegerOrInfinity$9;
14798
- var arraySpeciesCreate = arraySpeciesCreate$3;
14799
-
14800
- // `Array.prototype.flat` method
14801
- // https://tc39.es/ecma262/#sec-array.prototype.flat
14802
- $$5({ target: 'Array', proto: true }, {
14803
- flat: function flat(/* depthArg = 1 */) {
14804
- var depthArg = arguments.length ? arguments[0] : undefined;
14805
- var O = toObject$1(this);
14806
- var sourceLen = lengthOfArrayLike$1(O);
14807
- var A = arraySpeciesCreate(O, 0);
14808
- A.length = flattenIntoArray(A, O, O, sourceLen, 0, depthArg === undefined ? 1 : toIntegerOrInfinity(depthArg));
14809
- return A;
14666
+ // If a required checkbox is unchecked, show only the validation message in
14667
+ // review mode (not a contradictory "No (...)" value line).
14668
+ let isBooleanRequiredError = false;
14669
+ if ((schema == null ? void 0 : schema.type) === 'boolean' && data === false && activeError && /\sis required$/i.test(activeError)) {
14670
+ reviewText = '';
14671
+ isBooleanRequiredError = true;
14810
14672
  }
14811
- });
14812
-
14813
- // this method was added to unscopables after implementation
14814
- // in popular engines, so it's moved to a separate module
14815
- var addToUnscopables = addToUnscopables$5;
14816
-
14817
- // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
14818
- addToUnscopables('flat');
14819
-
14820
- const isPropertiesMatch = (obj, props, isExactMatch) => {
14821
- if (isObject$o(obj)) {
14822
- const keys = Object.keys(obj);
14823
- if (isExactMatch) {
14824
- return props.every(attr => keys.includes(attr)) && keys.length === props.length;
14825
- } else {
14826
- return props.every(attr => keys.includes(attr));
14827
- }
14673
+ const stepId = (_uischema$options5 = uischema.options) == null ? void 0 : _uischema$options5.stepId;
14674
+ function handleChangeClick() {
14675
+ reportChange(stepId, uischema.scope);
14828
14676
  }
14829
- return false;
14830
- };
14831
- const createSchemaMatchTester = (props, isExactMatch = false) => {
14832
- return schemaMatches(schema => {
14833
- return schema && isPropertiesMatch(schema.properties, props, isExactMatch);
14834
- });
14835
- };
14836
-
14837
- const isFullName = createSchemaMatchTester(['firstName', 'middleName', 'lastName'], true);
14838
- const FullNameTester = rankWith(4, isFullName);
14839
-
14840
- const FullNameControlReview = props => {
14841
- var _props$uischema, _props$schema$require, _props$schema;
14842
- const reportChange = useReviewChange();
14843
- const showChangeButtons = useShowChangeButtons();
14844
- const stepId = (_props$uischema = props.uischema) == null || (_props$uischema = _props$uischema.options) == null ? void 0 : _props$uischema.stepId;
14845
- const {
14846
- uischema,
14847
- data,
14848
- id
14849
- } = props;
14850
- const requiredFields = (_props$schema$require = (_props$schema = props.schema) == null ? void 0 : _props$schema.required) != null ? _props$schema$require : [];
14851
- const isMissing = value => isNilOrEmptyString(value);
14852
- const renderRow = (fieldLabel, value, fieldName, testId) => {
14853
- var _uischema$options;
14854
- return jsx("tr", {
14855
- children: jsxs(PageReviewContainer, {
14856
- colSpan: 3,
14857
- children: [jsxs(ReviewHeader, {
14858
- children: [jsxs(ReviewLabel, {
14859
- children: [fieldLabel, requiredFields.includes(fieldName) && jsx(RequiredTextLabel, {
14860
- children: " (required)"
14861
- })]
14862
- }), showChangeButtons && stepId !== undefined && !((_uischema$options = uischema.options) != null && (_uischema$options = _uischema$options.componentProps) != null && _uischema$options.readOnly) && jsx(BackButton, {
14863
- text: "Change",
14864
- link: () => reportChange(stepId, uischema.scope),
14865
- testId: `${fieldName}-change-btn`,
14866
- showBackIcon: false
14867
- })]
14868
- }), jsxs(ReviewValue, {
14869
- children: [jsx("div", {
14870
- "data-testid": testId,
14871
- children: value != null ? value : ''
14872
- }), requiredFields.includes(fieldName) && isMissing(value) && jsx(GoabFormItem, {
14873
- error: `${fieldLabel} is required`,
14874
- label: ""
14677
+ const showInlineValue = reviewText === null || reviewText === undefined || typeof reviewText === 'string' || typeof reviewText === 'number' || /*#__PURE__*/React.isValidElement(reviewText) || Array.isArray(reviewText) && reviewText.length === 0;
14678
+ const isValueEmpty = !isBooleanRequiredError && (reviewText === null || reviewText === undefined || reviewText === '' || Array.isArray(reviewText) && reviewText.length === 0);
14679
+ return jsx("tr", {
14680
+ "data-testid": `input-base-table-${label}-row`,
14681
+ children: jsxs(PageReviewContainer, {
14682
+ colSpan: 3,
14683
+ children: [jsxs(ReviewHeader, {
14684
+ children: [jsxs(ReviewLabel, {
14685
+ children: [labelToUpdate, required && jsx(RequiredTextLabel, {
14686
+ children: " (required)"
14875
14687
  })]
14688
+ }), showChangeButtons && stepId !== undefined && !((_uischema$options6 = uischema.options) != null && (_uischema$options6 = _uischema$options6.componentProps) != null && _uischema$options6.readOnly) && jsx(BackButton, {
14689
+ text: "Change",
14690
+ link: handleChangeClick,
14691
+ showBackIcon: false
14876
14692
  })]
14877
- })
14878
- }, testId);
14879
- };
14880
- return jsxs(Fragment, {
14881
- children: [renderRow('First name', data == null ? void 0 : data.firstName, 'firstName', `firstName-control-${id}`), renderRow('Middle name', data == null ? void 0 : data.middleName, 'middleName', `middleName-control-${id}`), renderRow('Last name', data == null ? void 0 : data.lastName, 'lastName', `lastName-control-${id}`)]
14693
+ }), jsxs(ReviewValue, {
14694
+ children: [isFileUrnSchema(schema) && !isNilOrEmptyValue(data, true) ? jsx("div", {
14695
+ "data-testid": `review-value-${label}`,
14696
+ children: jsx(FileUploaderReview, Object.assign({}, props, {
14697
+ label: "",
14698
+ required: false
14699
+ }))
14700
+ }) : showInlineValue ? jsx("div", {
14701
+ "data-testid": `review-value-${label}`,
14702
+ children: isValueEmpty ? jsx(NoneGivenText, {
14703
+ children: noAnswerMessage
14704
+ }) : reviewText != null ? reviewText : ''
14705
+ }) : jsx(JsonFormsDispatch, {
14706
+ "data-testid": `jsonforms-object-list-defined-elements-dispatch`,
14707
+ schema: schema,
14708
+ uischema: uischema,
14709
+ enabled: enabled,
14710
+ renderers: jsonForms.renderers,
14711
+ cells: cells
14712
+ }), activeError && jsx(GoabFormItem, {
14713
+ error: activeError,
14714
+ label: ""
14715
+ })]
14716
+ })]
14717
+ })
14882
14718
  });
14883
14719
  };
14884
- const GoAInputBaseFullNameControlReview = withJsonFormsAllOfProps(FullNameControlReview);
14885
-
14886
- const isFullNameDoB = createSchemaMatchTester(['firstName', 'middleName', 'lastName', 'dateOfBirth'], true);
14887
- const FullNameDobTester = rankWith(4, isFullNameDoB);
14720
+ const GoAInputBaseTableReviewControl = withJsonFormsControlProps(GoAInputBaseTableReview);
14888
14721
 
14889
- const FullNameDobReviewControl = props => {
14890
- var _uischema$options, _props$schema$require, _props$schema;
14722
+ const defaultLabel = 'Email address';
14723
+ const GoAEmailInput = props => {
14724
+ var _uischema$options$com, _uischema$options, _uischema$options$com2, _uischema$options2, _stepperState$categor;
14891
14725
  const {
14892
14726
  data,
14727
+ config,
14893
14728
  id,
14894
- uischema
14729
+ enabled,
14730
+ visible,
14731
+ uischema,
14732
+ errors,
14733
+ schema,
14734
+ required,
14735
+ label,
14736
+ handleChange
14895
14737
  } = props;
14896
- const reportChange = useReviewChange();
14897
- const showChangeButtons = useShowChangeButtons();
14898
- const stepId = uischema == null || (_uischema$options = uischema.options) == null ? void 0 : _uischema$options.stepId;
14899
- const requiredFields = (_props$schema$require = (_props$schema = props.schema) == null ? void 0 : _props$schema.required) != null ? _props$schema$require : [];
14900
- const isMissing = value => isNilOrEmptyString(value);
14901
- const renderRow = (fieldLabel, value, fieldName, testId) => {
14902
- var _uischema$options2;
14903
- return jsx("tr", {
14904
- children: jsxs(PageReviewContainer, {
14905
- colSpan: 3,
14906
- children: [jsxs(ReviewHeader, {
14907
- children: [jsxs(ReviewLabel, {
14908
- children: [fieldLabel, requiredFields.includes(fieldName) && jsx(RequiredTextLabel, {
14909
- children: " (required)"
14910
- })]
14911
- }), showChangeButtons && stepId !== undefined && !((_uischema$options2 = uischema.options) != null && (_uischema$options2 = _uischema$options2.componentProps) != null && _uischema$options2.readOnly) && jsx(BackButton, {
14912
- text: "Change",
14913
- link: () => reportChange(stepId, uischema.scope),
14914
- testId: `${fieldName}-change-btn`,
14915
- showBackIcon: false
14916
- })]
14917
- }), jsxs(ReviewValue, {
14918
- children: [jsx("div", {
14919
- "data-testid": testId,
14920
- children: value != null ? value : ''
14921
- }), requiredFields.includes(fieldName) && isMissing(value) && jsx(GoabFormItem, {
14922
- error: `${fieldLabel} is required`,
14923
- label: ""
14924
- })]
14925
- })]
14926
- })
14927
- }, testId);
14928
- };
14929
- return jsxs(Fragment, {
14930
- children: [renderRow('First name', data == null ? void 0 : data.firstName, 'firstName', `firstName-control-${id}`), renderRow('Middle name', data == null ? void 0 : data.middleName, 'middleName', `middleName-control-${id}`), renderRow('Last name', data == null ? void 0 : data.lastName, 'lastName', `lastName-control-${id}`), renderRow('Date of birth', data == null ? void 0 : data.dateOfBirth, 'dateOfBirth', `dob-control-${id}`)]
14931
- });
14932
- };
14933
- const GoAInputBaseFullNameDobControlReview = withJsonFormsAllOfProps(FullNameDobReviewControl);
14934
-
14935
- // Encapsulates masked-input state for a GoA input: display value, mount reflection, and change/keypress handling.
14936
- const resetMaskedValue = (detail, nextValue) => {
14937
- const target = getMaskInputTarget(detail);
14938
- if (target) {
14939
- target.value = nextValue;
14940
- }
14941
- };
14942
- const useMaskedInput = ({
14943
- mask,
14944
- inPlace,
14945
- data,
14946
- allowedKeys,
14947
- onCommit
14948
- }) => {
14949
- const format = value => inPlace ? toMaskTemplate(value, mask) : formatWithPattern(value, mask);
14950
- const initialDisplay = format(typeof data === 'string' ? data : '');
14951
- // In-place mounts empty then sets the template so the web component reflects it (a value change forces the paint).
14952
- const [value, setValue] = useState(inPlace ? '' : initialDisplay);
14738
+ const defaultSchema = schema;
14739
+ const appliedUiSchemaOptions = Object.assign({}, config, uischema == null ? void 0 : uischema.options);
14740
+ const readOnly = (_uischema$options$com = uischema == null || (_uischema$options = uischema.options) == null || (_uischema$options = _uischema$options.componentProps) == null ? void 0 : _uischema$options.readOnly) != null ? _uischema$options$com : false;
14741
+ const width = (_uischema$options$com2 = uischema == null || (_uischema$options2 = uischema.options) == null || (_uischema$options2 = _uischema$options2.componentProps) == null ? void 0 : _uischema$options2.width) != null ? _uischema$options$com2 : '100%';
14742
+ const formStepperCtx = useContext(JsonFormsStepperContext);
14743
+ const stepperState = formStepperCtx == null || formStepperCtx.selectStepperState == null ? void 0 : formStepperCtx.selectStepperState();
14744
+ const currentCategory = stepperState == null || (_stepperState$categor = stepperState.categories) == null ? void 0 : _stepperState$categor[stepperState == null ? void 0 : stepperState.activeId];
14745
+ const showReviewLink = currentCategory == null ? void 0 : currentCategory.showReviewPageLink;
14746
+ const [localValue, setLocalValue] = useState(data);
14747
+ const debouncedValue = useDebounce(localValue, 300);
14953
14748
  useEffect(() => {
14954
- setValue(format(typeof data === 'string' ? data : ''));
14955
- // eslint-disable-next-line react-hooks/exhaustive-deps
14956
- }, [mask, inPlace]);
14957
- const handleChange = detail => {
14958
- var _target$selectionStar;
14959
- const rawValue = detail.value;
14960
- const cleaned = allowedKeys ? filterAllowedKeys(rawValue, allowedKeys) : rawValue;
14961
- if (!inPlace) {
14962
- const stored = cleaned === '' ? '' : formatWithPattern(cleaned, mask);
14963
- if (allowedKeys && cleaned !== rawValue) {
14964
- resetMaskedValue(detail, stored);
14965
- }
14966
- setValue(stored);
14967
- onCommit(stored);
14968
- return;
14969
- }
14970
- const target = getMaskInputTarget(detail);
14971
- const caretIndex = (_target$selectionStar = target == null ? void 0 : target.selectionStart) != null ? _target$selectionStar : cleaned.length;
14972
- const overflow = overflowMaskEdit(value, cleaned, caretIndex, mask);
14973
- if (overflow) {
14974
- applyInPlaceEdit(target, overflow);
14975
- return;
14976
- }
14977
- const edit = computeMaskEdit(cleaned, caretIndex, mask);
14978
- applyInPlaceEdit(target, edit);
14979
- setValue(edit.display);
14980
- onCommit(edit.stored);
14981
- };
14982
- // In-place has no maxLength (the template is already full length) and GoA keyPress is keyup, so restore on overflow.
14983
- const handleKeyPress = detail => {
14984
- var _detail$event, _target$value, _target$selectionStar2;
14985
- const blockDisallowed = shouldBlockKey(detail.key, allowedKeys);
14986
- const blockOverflow = inPlace && /^[A-Za-z0-9]$/.test(detail.key) && isMaskFilled(value, mask);
14987
- if (!blockDisallowed && !blockOverflow) {
14749
+ if (data === undefined || data === null) {
14988
14750
  return;
14989
14751
  }
14990
- (_detail$event = detail.event) == null || _detail$event.preventDefault();
14991
- if (!blockOverflow) {
14992
- return;
14752
+ setLocalValue(data);
14753
+ }, [data]);
14754
+ /* istanbul ignore next */
14755
+ useEffect(() => {
14756
+ if (debouncedValue === data) return;
14757
+ // Only sync if debouncedValue differs from data and is not initial empty state
14758
+ if (debouncedValue !== data && (debouncedValue !== '' || data !== undefined)) {
14759
+ onChangeForInputControl({
14760
+ value: debouncedValue,
14761
+ controlProps: props
14762
+ });
14993
14763
  }
14994
- const target = getMaskInputTarget(detail);
14995
- const rawValue = (_target$value = target == null ? void 0 : target.value) != null ? _target$value : value;
14996
- const overflow = overflowMaskEdit(value, rawValue, (_target$selectionStar2 = target == null ? void 0 : target.selectionStart) != null ? _target$selectionStar2 : value.length, mask);
14997
- if (overflow) {
14998
- applyInPlaceEdit(target, overflow);
14764
+ }, [debouncedValue]);
14765
+ const [isVisited, setIsVisited] = useState(false);
14766
+ useEffect(() => {
14767
+ if (showReviewLink === true) {
14768
+ setIsVisited(true);
14999
14769
  }
15000
- };
15001
- return {
15002
- value,
15003
- handleChange,
15004
- handleKeyPress
15005
- };
15006
- };
15007
-
15008
- const PhoneNumberControl = props => {
15009
- var _uischema$options, _uischema$options2;
15010
- const {
15011
- data,
15012
- path,
15013
- schema,
15014
- uischema,
15015
- handleChange,
15016
- enabled,
15017
- visible,
15018
- required
15019
- } = props;
15020
- // Default mask can be overridden per field via the UI schema options.
15021
- const phoneMask = (uischema == null || (_uischema$options = uischema.options) == null ? void 0 : _uischema$options.phoneMask) || DEFAULT_PATTERNS.phone.mask;
15022
- // When in-place, the field shows the fill-in template and edits keep the caret in place.
15023
- const inPlace = (uischema == null || (_uischema$options2 = uischema.options) == null ? void 0 : _uischema$options2.inPlace) === true;
15024
- const [error, setError] = useState('');
15025
- const {
15026
- value,
15027
- handleChange: handleMaskChange,
15028
- handleKeyPress
15029
- } = useMaskedInput({
15030
- mask: phoneMask,
15031
- inPlace,
15032
- data,
15033
- allowedKeys: DEFAULT_PATTERNS.phone.allowedKeys,
15034
- onCommit: stored => {
15035
- setError(stored && !DEFAULT_PATTERNS.phone.pattern.test(stored) ? DEFAULT_PATTERNS.phone.error : '');
15036
- handleChange(path, stored);
14770
+ }, [showReviewLink]);
14771
+ const splitErrors = (errors != null ? errors : '').split(/\r?\n/).map(e => e.trim()).filter(Boolean);
14772
+ const primaryLabel = (defaultSchema == null ? void 0 : defaultSchema.label) || defaultLabel;
14773
+ const splintIndex = splitErrors.findIndex(e => e === REQUIRED_PROPERTY_ERROR);
14774
+ splitErrors[splintIndex] = `${primaryLabel} is required`;
14775
+ const finalErrors = splitErrors.join('\n');
14776
+ useEffect(() => {
14777
+ if (typeof handleChange === 'function' && (schema == null ? void 0 : schema.default) !== undefined && data === undefined) {
14778
+ handleChange(props.path, schema.default);
14779
+ setLocalValue(schema.default);
15037
14780
  }
15038
- });
14781
+ // eslint-disable-next-line react-hooks/exhaustive-deps
14782
+ }, [schema.default, data]);
15039
14783
  return jsx(Visible, {
15040
14784
  "$visible": visible,
15041
- children: jsx(GoabFormItem, {
15042
- label: (schema == null ? void 0 : schema.title) || 'Phone number',
15043
- requirement: required ? 'required' : undefined,
15044
- error: error,
15045
- testId: `form-item-${path}`,
15046
- children: jsx(GoabInput, {
15047
- type: "tel",
15048
- name: path,
15049
- disabled: !enabled,
15050
- "aria-label": "phone number input",
15051
- testId: `phone-input-${path}`,
15052
- value: value,
15053
- maxLength: inPlace ? undefined : phoneMask.length,
15054
- placeholder: inPlace ? undefined : maskPlaceholder(phoneMask),
15055
- onChange: detail => handleMaskChange(detail),
15056
- onKeyPress: detail => handleKeyPress(detail),
15057
- width: "100%"
15058
- }, `${phoneMask}:${inPlace}`)
14785
+ children: jsx(JsonFormRegisterProvider, {
14786
+ defaultRegisters: undefined,
14787
+ children: jsx(FormFieldWrapper$1, {
14788
+ children: jsx(GoabFormItem, {
14789
+ error: isVisited && finalErrors,
14790
+ testId: "form-email-input-wrapper",
14791
+ requirement: required ? 'required' : undefined,
14792
+ label: primaryLabel,
14793
+ children: jsx(GoabInput, {
14794
+ error: isVisited && finalErrors.length > 0,
14795
+ type: 'email',
14796
+ width: width,
14797
+ name: "Email address",
14798
+ value: data,
14799
+ testId: (appliedUiSchemaOptions == null ? void 0 : appliedUiSchemaOptions.testId) || `${id}-input`,
14800
+ disabled: !enabled,
14801
+ readonly: readOnly,
14802
+ onChange: detail => {
14803
+ if (!isVisited) {
14804
+ setIsVisited(true);
14805
+ }
14806
+ setLocalValue(detail.value);
14807
+ },
14808
+ onBlur: detail => {
14809
+ if (!isVisited) {
14810
+ setIsVisited(true);
14811
+ }
14812
+ onBlurForTextControl({
14813
+ name: detail.name,
14814
+ value: detail.value,
14815
+ controlProps: props
14816
+ });
14817
+ }
14818
+ })
14819
+ })
14820
+ })
15059
14821
  })
15060
14822
  });
15061
14823
  };
15062
- const GoAPhoneNumberControl = withJsonFormsControlProps(PhoneNumberControl);
15063
-
15064
- const PhoneNumberTester = rankWith(4, and(isControl$1, schemaTypeIs('string'), formatIs('phone')));
15065
-
15066
- let _$4 = t => t,
15067
- _t$5,
15068
- _t2$2,
15069
- _t3$1,
15070
- _t4$1,
15071
- _t5,
15072
- _t6;
15073
- const SearchBox = styled.div(_t$5 || (_t$5 = _$4`
15074
- position: relative;
14824
+ const GoAEmailControl = props => jsx(GoAEmailInput, Object.assign({}, props));
14825
+ const GoAEmailControlTester = rankWith(4, and(isControl$1, schemaTypeIs('string'), formatIs('email')));
14826
+ const GoAInputEmailControl = withJsonFormsControlProps(GoAEmailControl);
15075
14827
 
15076
- .suggestions {
15077
- width: 100%;
15078
- margin-top: 3px;
15079
- border-top-width: 0;
15080
- list-style: none;
15081
- max-height: 15.5rem;
15082
- width: 100%;
15083
- position: absolute;
15084
-
15085
- background: var(--goa-color-greyscale-white);
15086
- box-shadow: 0 8px 8px rgb(0 0 0 / 20%), 0 4px 4px rgb(0 0 0 / 10%);
15087
- z-index: 99;
15088
- overflow: hidden auto;
15089
- padding-left: 0;
14828
+ let _$5 = t => t,
14829
+ _t$5;
14830
+ const renderLayoutElements = (elements, schema, path, enabled, renderers, cells) => {
14831
+ return elements.map((child, index) => jsx(JsonFormsDispatch, {
14832
+ uischema: child,
14833
+ schema: schema,
14834
+ path: path,
14835
+ enabled: enabled,
14836
+ renderers: renderers,
14837
+ cells: cells
14838
+ }, `review-${path}_${index}`));
14839
+ };
14840
+ const withAjvProps = Component => function WithAjvProps(props) {
14841
+ const ctx = useJsonForms();
14842
+ const ajv = getAjv({
14843
+ jsonforms: Object.assign({}, ctx)
14844
+ });
14845
+ return jsx(Component, Object.assign({}, props, {
14846
+ ajv: ajv
14847
+ }));
14848
+ };
14849
+ const LayoutRenderer = ({
14850
+ elements,
14851
+ schema,
14852
+ path,
14853
+ enabled,
14854
+ direction,
14855
+ renderers,
14856
+ cells,
14857
+ visible,
14858
+ width
14859
+ }) => {
14860
+ if (isEmpty$1(elements)) {
14861
+ return null;
14862
+ } else {
14863
+ if (direction === 'row') {
14864
+ return jsx(Visible, {
14865
+ "$visible": visible,
14866
+ children: jsx(GoabGrid$1, {
14867
+ minChildWidth: width || '10ch',
14868
+ children: renderLayoutElements(elements, schema, path, enabled, renderers, cells)
14869
+ })
14870
+ });
14871
+ } else {
14872
+ return jsx(Visible, {
14873
+ "$visible": visible,
14874
+ children: renderLayoutElements(elements, schema, path, enabled, renderers, cells)
14875
+ });
14876
+ }
15090
14877
  }
15091
- .suggestions li {
14878
+ };
14879
+ const ReviewLayoutRenderer = ({
14880
+ elements,
14881
+ schema,
14882
+ path,
14883
+ enabled,
14884
+ direction,
14885
+ renderers,
14886
+ cells,
14887
+ visible,
14888
+ width
14889
+ }) => {
14890
+ if (isEmpty$1(elements)) {
14891
+ return null;
14892
+ } else {
14893
+ if (direction === 'row') {
14894
+ return jsx(Visible, {
14895
+ "$visible": visible,
14896
+ children: jsx(ReviewGrid, {
14897
+ children: renderLayoutElements(elements, schema, path, enabled, renderers, cells)
14898
+ })
14899
+ });
14900
+ } else {
14901
+ return jsx(Visible, {
14902
+ "$visible": visible,
14903
+ children: renderLayoutElements(elements, schema, path, enabled, renderers, cells)
14904
+ });
14905
+ }
15092
14906
  }
15093
- .suggestion-active,
15094
- .suggestions li:hover {
15095
- background-color: var(--goa-color-interactive-default);
15096
- color: var(--goa-color-greyscale-white);
15097
- cursor: pointer;
15098
- font-weight: 600;
14907
+ };
14908
+ const ReviewGrid = styled.div(_t$5 || (_t$5 = _$5`
14909
+ display: grid;
14910
+ grid-template-columns: repeat(auto-fit, minmax(250px, calc(50% - 8px)));
14911
+ gap: 16px;
14912
+ `));
14913
+
14914
+ let _$4 = t => t,
14915
+ _t$4,
14916
+ _t2$2,
14917
+ _t3$1,
14918
+ _t4$1,
14919
+ _t5$1,
14920
+ _t6$1,
14921
+ _t7,
14922
+ _t8,
14923
+ _t9,
14924
+ _t0,
14925
+ _t1,
14926
+ _t10,
14927
+ _t11,
14928
+ _t12,
14929
+ _t13,
14930
+ _t14,
14931
+ _t15,
14932
+ _t16,
14933
+ _t17,
14934
+ _t18,
14935
+ _t19,
14936
+ _t20,
14937
+ _t21,
14938
+ _t22,
14939
+ _t23,
14940
+ _t24,
14941
+ _t25,
14942
+ _t26,
14943
+ _t27,
14944
+ _t28,
14945
+ _t29;
14946
+ const ReviewItem = styled.div(_t$4 || (_t$4 = _$4`
14947
+ display: flex;
14948
+ flex-direction: column;
14949
+ `));
14950
+ const CompletionStatus = styled.div(_t2$2 || (_t2$2 = _$4`
14951
+ padding: 0;
14952
+ margin: 0;
14953
+ padding-top: var(--goa-space-xl);
14954
+
14955
+ display: flex;
14956
+ flex-direction: column;
14957
+ `));
14958
+ const BarTop = styled.div(_t3$1 || (_t3$1 = _$4`
14959
+ display: flex;
14960
+
14961
+ .progress-text {
14962
+ margin-left: auto;
15099
14963
  }
15100
- .input-container {
14964
+ `));
14965
+ const Bar = styled.div(_t4$1 || (_t4$1 = _$4`
14966
+ display: flex;
14967
+ flex-direction: row;
14968
+
14969
+ .progress-container {
14970
+ align-items: flex-start;
14971
+ width: 100%;
14972
+
14973
+ height: 4px;
14974
+ background-color: #e0e0e0;
14975
+ border-radius: 4;
14976
+ overflow: hidden;
15101
14977
  position: relative;
15102
- display: inline-block;
15103
- width: 100%; /* Ensures it spans the parent container */
14978
+ border: 1px solid #ccc;
14979
+ margin-bottom: 20px;
15104
14980
  }
15105
14981
 
15106
- .input-container .input-spinner {
15107
- position: absolute;
15108
- top: 50%;
15109
- right: 8px; /* Adjust based on padding or margin of the input field */
15110
- transform: translateY(-50%);
15111
- z-index: 1; /* Ensure it appears above the input */
15112
- pointer-events: none; /* Prevent spinner from interfering with clicks */
14982
+ .progress-bar {
14983
+ width: 60%;
14984
+ height: 100%;
14985
+ background-color: #004abf;
14986
+ border-radius: 4;
14987
+ position: relative;
14988
+ display: flex;
14989
+ align-items: center;
14990
+ justify-content: flex-end;
14991
+
14992
+ box-sizing: border-box;
15113
14993
  }
15114
14994
  `));
15115
- const AddressIndent = styled.div(_t2$2 || (_t2$2 = _$4`
15116
- margin: 0 0 var(--goa-space-m) 0;
15117
- text-wrap: wrap;
15118
- word-break: break-word;
14995
+ styled.div(_t5$1 || (_t5$1 = _$4``));
14996
+ const BadgeWrapper = styled.div(_t6$1 || (_t6$1 = _$4`
14997
+ margin-left: 10px;
14998
+ margin-top: 7px;
14999
+ `));
15000
+ const CompletionTextHeader = styled.h3(_t7 || (_t7 = _$4`
15001
+ display: flex;
15002
+ `));
15003
+ const ReviewItemSection = styled.div(_t8 || (_t8 = _$4`
15004
+ margin-bottom: var(--goa-space-m);
15005
+ padding: var(--goa-space-xl) var(--goa-space-2xl);
15119
15006
  border: 1px solid var(--goa-color-greyscale-300);
15120
15007
  border-radius: var(--goa-border-radius-xl);
15121
- padding: var(--goa-space-l);
15122
- `));
15123
- const TextWrap = styled.p(_t3$1 || (_t3$1 = _$4`
15124
- text-wrap: auto;
15125
- word-break: break-word;
15008
+
15009
+ .element-style {
15010
+ max-width: 1600px;
15011
+ }
15012
+
15013
+ @media (max-width: 639px) {
15014
+ padding: var(--goa-space-l) var(--goa-space-m);
15015
+ }
15126
15016
  `));
15127
- const TextWrapDiv = styled.div(_t4$1 || (_t4$1 = _$4`
15128
- text-wrap: auto;
15129
- word-break: break-word;
15017
+ const ReviewSectionTitle = styled.h3(_t9 || (_t9 = _$4`
15018
+ margin-bottom: var(--goa-space-m);
15019
+ overflow-wrap: anywhere;
15130
15020
  `));
15131
- const LabelDiv = styled.div(_t5 || (_t5 = _$4`
15132
- color: var(--goa-color-text-default);
15133
- font: var(--goa-typography-body-m);
15134
- min-height: 2.625rem;
15021
+ const ReviewItemHeader = styled.div(_t0 || (_t0 = _$4`
15135
15022
  display: flex;
15136
15023
  align-items: center;
15137
- text-wrap: auto;
15138
- word-break: break-word;
15024
+ justify-content: space-between;
15025
+ margin-bottom: var(--goa-space-xl);
15139
15026
  `));
15140
- /* istanbul ignore next */
15141
- const ListItem = styled.li(_t6 || (_t6 = _$4`
15142
- background-color: ${0};
15143
- color: ${0};
15144
- font-weight: ${0};
15145
- padding: var(--goa-space-xs) var(--goa-space-2xs) var(--goa-space-xs) var(--goa-space-xs);
15146
- margin-left: 0.25rem;
15147
- `), ({
15148
- selected,
15149
- index
15150
- }) => selected === index ? 'var(--goa-color-interactive-default)' : '', ({
15151
- selected,
15152
- index
15153
- }) => selected === index ? 'var(--goa-color-greyscale-white) !important' : '', ({
15154
- selected,
15155
- index
15156
- }) => selected === index ? '600' : '');
15157
-
15158
- const PhoneNumberReviewControl = props => {
15159
- const {
15160
- data,
15161
- id,
15162
- required
15163
- } = props;
15164
- return jsx(GoabFormItem, {
15165
- label: "Phone number",
15166
- error: required && !data ? 'Phone number is required' : '',
15167
- requirement: required ? 'required' : undefined,
15168
- children: jsx(TextWrapDiv, {
15169
- children: jsx("div", {
15170
- "data-testid": `phone-control-${id}`,
15171
- children: data || ''
15172
- })
15173
- })
15174
- });
15175
- };
15176
- const GoabInputBasePhoneNumberReviewControl = withJsonFormsAllOfProps(PhoneNumberReviewControl);
15027
+ const ReviewItemTitle = styled.div(_t1 || (_t1 = _$4`
15028
+ font-size: var(--goa-space-l);
15029
+ line-height: var(--goa-space-xl);
15030
+ font-weight: 300;
15031
+ `));
15032
+ styled.div(_t10 || (_t10 = _$4`
15033
+ color: #0070c4;
15034
+ text-decoration: underline;
15035
+ outline: none;
15036
+ cursor: pointer;
15177
15037
 
15178
- let _$3 = t => t,
15179
- _t$4;
15180
- const PhoneGrid = styled.div(_t$4 || (_t$4 = _$3`
15181
- display: grid;
15182
- grid-template-columns: 1fr 2fr;
15183
- gap: 0.2rem;
15184
- align-items: start;
15185
- margin-bottom: var(--goa-space-l) !important;
15038
+ &:focus {
15039
+ outline: 2px solid #0070c4;
15040
+ background-color: #e6f7ff;
15041
+ }
15042
+ `));
15043
+ styled.div(_t11 || (_t11 = _$4`
15044
+ margin-left: var(--goa-space-m);
15045
+ `));
15046
+ styled.div(_t12 || (_t12 = _$4`
15047
+ margin-bottom: var(--goa-space-m);
15048
+ `));
15049
+ styled.div(_t13 || (_t13 = _$4`
15050
+ margin: var(--goa-space-s);
15051
+ width: 100%;
15052
+ `));
15053
+ styled.h3(_t14 || (_t14 = _$4`
15054
+ text-transform: capitalize;
15055
+ `));
15056
+ const RightAlignmentDiv = styled.div(_t15 || (_t15 = _$4`
15057
+ @media screen and (max-width: 767px) {
15058
+ margin-bottom: var(--goa-space-l);
15059
+ }
15060
+ @media screen and (min-width: 768px) {
15061
+ display: flex;
15062
+ justify-content: flex-end;
15063
+ margin-bottom: var(--goa-space-l);
15064
+ }
15065
+ `));
15066
+ const FormStepperSummaryH3 = styled.h3(_t16 || (_t16 = _$4`
15067
+ flex: 1;
15068
+ max-width: 100%;
15069
+ margin-bottom: var(--goa-space-m);
15070
+ font-size: var(--goa-font-size-7);
15071
+ line-height: var(--goa-line-height-4);
15072
+ font-weight: var(--goa-font-weight-bold);
15073
+ overflow-wrap: anywhere;
15074
+ `));
15075
+ const PageRenderPadding = styled.div(_t17 || (_t17 = _$4`
15076
+ margin-top: var(--goa-space-2xl);
15077
+ `));
15078
+ styled.div(_t18 || (_t18 = _$4`
15079
+ margin-bottom: var(--goa-space-2xl);
15080
+ `));
15081
+ const PageBorder = styled.div(_t19 || (_t19 = _$4`
15082
+ padding: var(--goa-space-m) var(--goa-space-3xl);
15186
15083
 
15187
- goa-form-item {
15188
- margin-right: 0 !important;
15084
+ @media (max-width: 639px) {
15085
+ padding: var(--goa-space-m) var(--goa-space-xs);
15189
15086
  }
15190
15087
  `));
15191
- const PHONE_REGEX = /^\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$/;
15192
- const normalizePhoneData = value => ({
15193
- type: (value == null ? void 0 : value.type) || '',
15194
- number: (value == null ? void 0 : value.number) || ''
15195
- });
15196
- const PhoneNumberWithTypeControl = props => {
15197
- const {
15198
- data,
15199
- path,
15200
- handleChange,
15201
- enabled,
15202
- visible,
15203
- required
15204
- } = props;
15205
- const [formData, setFormData] = useState(normalizePhoneData(data));
15206
- const [error, setError] = useState(undefined);
15207
- useEffect(() => {
15208
- const nextData = normalizePhoneData(data);
15209
- setFormData(currentData => currentData.type === nextData.type && currentData.number === nextData.number ? currentData : nextData);
15210
- }, [data]);
15211
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
15212
- const updateFormData = updated => {
15213
- setFormData(updated);
15214
- if (updated.number && !PHONE_REGEX.test(updated.number)) {
15215
- setError('Enter a valid phone number (e.g., (780) 123-4567)');
15216
- } else {
15217
- setError(undefined);
15218
- }
15219
- handleChange(path, updated);
15220
- };
15088
+ styled.div(_t20 || (_t20 = _$4`
15089
+ .element-style {
15090
+ max-width: 1600px;
15091
+ }
15092
+ `));
15093
+ styled.div(_t21 || (_t21 = _$4`
15094
+ padding: var(--goa-space-xl) var(--goa-space-2xl);
15095
+ border: 1px solid var(--goa-color-greyscale-300);
15096
+ border-radius: var(--goa-border-radius-xl);
15097
+ `));
15098
+ styled.div(_t22 || (_t22 = _$4`
15099
+ margin-top: var(--goa-space-xl);
15100
+ display: flex;
15101
+ justify-content: space-between;
15102
+ `));
15103
+ styled.h3(_t23 || (_t23 = _$4`
15104
+ color: var(--goa-color-text-secondary) !important;
15105
+ margin-bottom: var(--goa-space-l);
15106
+ `));
15107
+ const CategoryStatus = styled.td(_t24 || (_t24 = _$4`
15108
+ width: var(--goa-space-xl);
15109
+ padding-right: var(--goa-space-xl);
15110
+ align-content: center;
15111
+ `));
15112
+ const Center = styled.div(_t25 || (_t25 = _$4`
15113
+ padding-top: 5px;
15114
+ `));
15115
+ const PageStepperRow = styled.tr(_t26 || (_t26 = _$4`
15116
+ ${0}
15117
+ `), ({
15118
+ disabled
15119
+ }) => disabled ? `
15120
+ pointer-events: none;
15121
+ opacity: 0.5;
15122
+ cursor: not-allowed;
15123
+ ` : `
15124
+ cursor: pointer;
15125
+
15126
+ &:hover td {
15127
+ background-color: var(--goa-color-greyscale-100);
15128
+ }
15129
+
15130
+ td {
15131
+ transition: background-color 0.2s ease-in-out;
15132
+ }
15133
+
15134
+
15135
+ &:focus-visible {
15136
+ border-radius: 0.25rem;
15137
+ outline: 3px solid var(--goa-color-interactive-focus);
15138
+ }
15139
+ `);
15140
+ const SectionHeaderRowTr = styled.tr(_t27 || (_t27 = _$4`
15141
+ & > td {
15142
+ border: 0 !important;
15143
+ padding-top: var(--goa-space-l);
15144
+ padding-bottom: var(--goa-space-s);
15145
+ padding-left: 0 !important;
15146
+ }
15147
+
15148
+ & + tr > td {
15149
+ border-top: none !important;
15150
+ }
15151
+ `));
15152
+ const SummaryRowLink = styled.a(_t28 || (_t28 = _$4`
15153
+ position: relative;
15154
+ top: var(--goa-space-xs);
15155
+ &:focus-visible {
15156
+ border-radius: 0.25rem;
15157
+ outline: 3px solid var(--goa-color-interactive-focus);
15158
+ }
15159
+ padding: 0 var(--goa-space-s) var(--goa-space-xs); var(--goa-space-s);
15160
+ `));
15161
+ const SummaryTd = styled.td(_t29 || (_t29 = _$4`
15162
+ border: 0 !important;
15163
+ padding: 0 !important;
15164
+ `));
15165
+
15166
+ const RenderStepElements = props => {
15167
+ var _props$category;
15168
+ // Passing the schema straight through matters for performance. This used to hand down a shallow
15169
+ // copy, and because the copy is made in a hook it is a brand new object every time the step
15170
+ // changes — which invalidates every identity-keyed cache downstream, including the renderer
15171
+ // lookup JsonForms memoizes on the schema it is given.
15172
+ const memoizedSchema = props.schema;
15221
15173
  return jsx(Visible, {
15222
- "$visible": visible,
15223
- children: jsxs(PhoneGrid, {
15224
- children: [jsx(GoabFormItem, {
15225
- label: "Phone type",
15226
- requirement: required ? 'required' : undefined,
15227
- children: jsxs(GoabDropdown, {
15228
- name: "type",
15229
- value: formData.type || '',
15230
- disabled: !enabled,
15231
- onChange: detail => updateFormData(Object.assign({}, formData, {
15232
- type: detail.value
15233
- })),
15234
- children: [jsx(GoabDropdownItem, {
15235
- value: "Mobile"
15236
- }), jsx(GoabDropdownItem, {
15237
- value: "Landline"
15238
- })]
15239
- })
15240
- }), jsx(GoabFormItem, {
15241
- label: "Phone number",
15242
- error: error,
15243
- requirement: required ? 'required' : undefined,
15244
- children: jsx(GoabInput, {
15245
- type: "tel",
15246
- name: "number",
15247
- placeholder: "(000) 000-0000",
15248
- value: formData.number || '',
15249
- disabled: !enabled,
15250
- onChange: detail => updateFormData(Object.assign({}, formData, {
15251
- number: detail.value
15252
- }))
15253
- })
15254
- })]
15174
+ "$visible": props.visible,
15175
+ "data-testid": `${(props == null ? void 0 : props.path) || ((_props$category = props.category) == null ? void 0 : _props$category.label)}-categories-${props.categoryIndex}`,
15176
+ children: props.category.elements.map((uiSchema, index) => {
15177
+ var _props$category2;
15178
+ return jsx(JsonFormsDispatch, {
15179
+ schema: memoizedSchema,
15180
+ uischema: uiSchema,
15181
+ renderers: props.renderers,
15182
+ cells: props.cells,
15183
+ path: props.path,
15184
+ visible: props.visible,
15185
+ enabled: props.enabled
15186
+ }, `${(props == null ? void 0 : props.path) || ((_props$category2 = props.category) == null ? void 0 : _props$category2.label)}-category-page-${index}`);
15255
15187
  })
15256
15188
  });
15257
15189
  };
15258
- const GoAPhoneNumberWithTypeControl = withJsonFormsControlProps(PhoneNumberWithTypeControl);
15259
-
15260
- const isPhoneNumberWithType = createSchemaMatchTester(['number', 'type'], true);
15261
- const PhoneNumberWithTypeTester = rankWith(4, isPhoneNumberWithType);
15262
15190
 
15263
- const PhoneNumberWithTypeReviewControl = props => {
15264
- const {
15265
- data,
15266
- id,
15267
- required
15268
- } = props;
15269
- return jsxs(PhoneGrid, {
15270
- children: [jsx(GoabFormItem, {
15271
- label: "Phone number",
15272
- error: required && !(data != null && data.number) ? 'Phone number is required' : '',
15273
- requirement: required ? 'required' : undefined,
15274
- children: jsx(TextWrapDiv, {
15275
- children: jsx("div", {
15276
- "data-testid": `phone-number-control-${id}`,
15277
- children: (data == null ? void 0 : data.number) || ''
15278
- })
15279
- })
15280
- }), jsx(GoabFormItem, {
15281
- label: "Phone type",
15282
- error: required && !(data != null && data.type) ? 'Phone type is required' : '',
15283
- requirement: required ? 'required' : undefined,
15284
- children: jsx(TextWrapDiv, {
15285
- children: jsx("div", {
15286
- "data-testid": `phone-type-control-${id}`,
15287
- children: (data == null ? void 0 : data.type) || ''
15288
- })
15289
- })
15290
- })]
15191
+ const isPropertiesMatch = (obj, props, isExactMatch) => {
15192
+ if (isObject$o(obj)) {
15193
+ const keys = Object.keys(obj);
15194
+ if (isExactMatch) {
15195
+ return props.every(attr => keys.includes(attr)) && keys.length === props.length;
15196
+ } else {
15197
+ return props.every(attr => keys.includes(attr));
15198
+ }
15199
+ }
15200
+ return false;
15201
+ };
15202
+ const createSchemaMatchTester = (props, isExactMatch = false) => {
15203
+ return schemaMatches(schema => {
15204
+ return schema && isPropertiesMatch(schema.properties, props, isExactMatch);
15291
15205
  });
15292
15206
  };
15293
- const GoabInputBasePhoneNumberWithTypeReviewControl = withJsonFormsAllOfProps(PhoneNumberWithTypeReviewControl);
15294
15207
 
15295
- let _$2 = t => t,
15296
- _t$3;
15297
- const FormFieldWrapper = styled.div(_t$3 || (_t$3 = _$2`
15298
- margin-bottom: var(--goa-space-l);
15299
- `));
15208
+ const isFullName = createSchemaMatchTester(['firstName', 'middleName', 'lastName'], true);
15209
+ const FullNameTester = rankWith(4, isFullName);
15300
15210
 
15301
- const ContractInfoControl = props => {
15302
- var _options$enableEmail, _options$enablePhone, _options$emailFirst;
15211
+ const FullNameControlReview = props => {
15212
+ var _props$uischema, _props$schema$require, _props$schema;
15213
+ const reportChange = useReviewChange();
15214
+ const showChangeButtons = useShowChangeButtons();
15215
+ const stepId = (_props$uischema = props.uischema) == null || (_props$uischema = _props$uischema.options) == null ? void 0 : _props$uischema.stepId;
15303
15216
  const {
15304
- data = {},
15305
- path,
15306
- handleChange,
15307
- enabled,
15308
- visible,
15309
- required,
15310
- uischema
15217
+ uischema,
15218
+ data,
15219
+ id
15311
15220
  } = props;
15312
- const handleFieldChange = (field, value) => {
15313
- handleChange(`${path}.${field}`, value);
15314
- };
15315
- const emailProps = Object.assign({}, props, {
15316
- data: data == null ? void 0 : data.email,
15317
- path: `${path}.email`
15318
- });
15319
- const phoneProps = Object.assign({}, props, {
15320
- data: data == null ? void 0 : data.phone,
15321
- path: `${path}.phone`
15322
- });
15323
- const {
15324
- options
15325
- } = uischema;
15326
- const enableEmail = (_options$enableEmail = options == null ? void 0 : options.enableEmail) != null ? _options$enableEmail : true;
15327
- const enablePhone = (_options$enablePhone = options == null ? void 0 : options.enablePhone) != null ? _options$enablePhone : true;
15328
- const emailFirst = (_options$emailFirst = options == null ? void 0 : options.emailFirst) != null ? _options$emailFirst : false;
15329
- if (!enableEmail && !enablePhone) {
15330
- throw new Error('At least one contact method must be enabled');
15331
- }
15332
- return jsxs("div", {
15333
- style: {
15334
- display: visible ? 'block' : 'none'
15335
- },
15336
- children: [enableEmail && emailFirst && jsx(GoAEmailInput, Object.assign({}, emailProps)), enablePhone && jsx(FormFieldWrapper, {
15337
- children: jsx(PhoneNumberControl, Object.assign({}, phoneProps))
15338
- }), enableEmail && !emailFirst && jsx(GoAEmailInput, Object.assign({}, emailProps)), enableEmail && enablePhone && jsx(FormFieldWrapper, {
15339
- children: jsx(GoabFormItem, {
15340
- label: "Preferred Contact Method",
15341
- requirement: required ? 'required' : undefined,
15342
- children: jsxs(GoabDropdown, {
15343
- testId: `preferred-contact-${path}`,
15344
- disabled: !enabled,
15345
- value: data.preferredContactMethod || '',
15346
- onChange: detail => handleFieldChange('preferredContactMethod', detail.value || ''),
15347
- width: "250px",
15348
- children: [jsx(GoabDropdownItem, {
15349
- value: "",
15350
- label: "Select a Contact Method"
15351
- }), emailFirst && jsx(GoabDropdownItem, {
15352
- value: "Email",
15353
- label: "Email"
15354
- }), jsx(GoabDropdownItem, {
15355
- value: "Phone",
15356
- label: "Phone"
15357
- }), !emailFirst && jsx(GoabDropdownItem, {
15358
- value: "Email",
15359
- label: "Email"
15221
+ const requiredFields = (_props$schema$require = (_props$schema = props.schema) == null ? void 0 : _props$schema.required) != null ? _props$schema$require : [];
15222
+ const isMissing = value => isNilOrEmptyString(value);
15223
+ const renderRow = (fieldLabel, value, fieldName, testId) => {
15224
+ var _uischema$options;
15225
+ return jsx("tr", {
15226
+ children: jsxs(PageReviewContainer, {
15227
+ colSpan: 3,
15228
+ children: [jsxs(ReviewHeader, {
15229
+ children: [jsxs(ReviewLabel, {
15230
+ children: [fieldLabel, requiredFields.includes(fieldName) && jsx(RequiredTextLabel, {
15231
+ children: " (required)"
15232
+ })]
15233
+ }), showChangeButtons && stepId !== undefined && !((_uischema$options = uischema.options) != null && (_uischema$options = _uischema$options.componentProps) != null && _uischema$options.readOnly) && jsx(BackButton, {
15234
+ text: "Change",
15235
+ link: () => reportChange(stepId, uischema.scope),
15236
+ testId: `${fieldName}-change-btn`,
15237
+ showBackIcon: false
15360
15238
  })]
15361
- })
15239
+ }), jsxs(ReviewValue, {
15240
+ children: [jsx("div", {
15241
+ "data-testid": testId,
15242
+ children: value != null ? value : ''
15243
+ }), requiredFields.includes(fieldName) && isMissing(value) && jsx(GoabFormItem, {
15244
+ error: `${fieldLabel} is required`,
15245
+ label: ""
15246
+ })]
15247
+ })]
15362
15248
  })
15363
- })]
15249
+ }, testId);
15250
+ };
15251
+ return jsxs(Fragment, {
15252
+ children: [renderRow('First name', data == null ? void 0 : data.firstName, 'firstName', `firstName-control-${id}`), renderRow('Middle name', data == null ? void 0 : data.middleName, 'middleName', `middleName-control-${id}`), renderRow('Last name', data == null ? void 0 : data.lastName, 'lastName', `lastName-control-${id}`)]
15364
15253
  });
15365
15254
  };
15255
+ const GoAInputBaseFullNameControlReview = withJsonFormsAllOfProps(FullNameControlReview);
15366
15256
 
15367
- const ContractInfoControlReview = props => {
15368
- var _props$uischema, _schema$required, _options$enableEmail, _options$enablePhone, _options$emailFirst;
15369
- const reportChange = useReviewChange();
15370
- const showChangeButtons = useShowChangeButtons();
15371
- const stepId = (_props$uischema = props.uischema) == null || (_props$uischema = _props$uischema.options) == null ? void 0 : _props$uischema.stepId;
15257
+ const isFullNameDoB = createSchemaMatchTester(['firstName', 'middleName', 'lastName', 'dateOfBirth'], true);
15258
+ const FullNameDobTester = rankWith(4, isFullNameDoB);
15259
+
15260
+ const FullNameDobReviewControl = props => {
15261
+ var _uischema$options, _props$schema$require, _props$schema;
15372
15262
  const {
15373
- uischema,
15374
- data = {},
15263
+ data,
15375
15264
  id,
15376
- schema
15265
+ uischema
15377
15266
  } = props;
15378
- const requiredFields = (_schema$required = schema == null ? void 0 : schema.required) != null ? _schema$required : [];
15379
- const isMissing = value => value === undefined || value === null || value === '';
15267
+ const reportChange = useReviewChange();
15268
+ const showChangeButtons = useShowChangeButtons();
15269
+ const stepId = uischema == null || (_uischema$options = uischema.options) == null ? void 0 : _uischema$options.stepId;
15270
+ const requiredFields = (_props$schema$require = (_props$schema = props.schema) == null ? void 0 : _props$schema.required) != null ? _props$schema$require : [];
15271
+ const isMissing = value => isNilOrEmptyString(value);
15380
15272
  const renderRow = (fieldLabel, value, fieldName, testId) => {
15381
- var _uischema$options;
15273
+ var _uischema$options2;
15382
15274
  return jsx("tr", {
15383
15275
  children: jsxs(PageReviewContainer, {
15384
15276
  colSpan: 3,
15385
15277
  children: [jsxs(ReviewHeader, {
15386
- children: [jsx(ReviewLabel, {
15387
- children: fieldLabel
15388
- }), showChangeButtons && stepId !== undefined && !((_uischema$options = uischema.options) != null && (_uischema$options = _uischema$options.componentProps) != null && _uischema$options.readOnly) && jsx(BackButton, {
15278
+ children: [jsxs(ReviewLabel, {
15279
+ children: [fieldLabel, requiredFields.includes(fieldName) && jsx(RequiredTextLabel, {
15280
+ children: " (required)"
15281
+ })]
15282
+ }), showChangeButtons && stepId !== undefined && !((_uischema$options2 = uischema.options) != null && (_uischema$options2 = _uischema$options2.componentProps) != null && _uischema$options2.readOnly) && jsx(BackButton, {
15389
15283
  text: "Change",
15390
15284
  link: () => reportChange(stepId, uischema.scope),
15391
15285
  testId: `${fieldName}-change-btn`,
@@ -15403,1228 +15297,1345 @@ const ContractInfoControlReview = props => {
15403
15297
  })
15404
15298
  }, testId);
15405
15299
  };
15406
- const {
15407
- options
15408
- } = uischema;
15409
- const enableEmail = (_options$enableEmail = options == null ? void 0 : options.enableEmail) != null ? _options$enableEmail : true;
15410
- const enablePhone = (_options$enablePhone = options == null ? void 0 : options.enablePhone) != null ? _options$enablePhone : true;
15411
- const emailFirst = (_options$emailFirst = options == null ? void 0 : options.emailFirst) != null ? _options$emailFirst : false;
15412
- if (!enableEmail && !enablePhone) {
15413
- throw new Error('At least one contact method must be enabled');
15414
- }
15415
15300
  return jsxs(Fragment, {
15416
- children: [enableEmail && emailFirst && renderRow('Email', data == null ? void 0 : data.email, 'email', `email-control-${id}`), enablePhone && renderRow('Phone number', data == null ? void 0 : data.phone, 'phone', `phone-control-${id}`), enableEmail && !emailFirst && renderRow('Email', data == null ? void 0 : data.email, 'email', `email-control-${id}`), enableEmail && enablePhone && renderRow('Preferred contact method', (data == null ? void 0 : data.preferredContactMethod) || 'Email', 'preferredContactMethod', `preferred-contact-${id}`)]
15301
+ children: [renderRow('First name', data == null ? void 0 : data.firstName, 'firstName', `firstName-control-${id}`), renderRow('Middle name', data == null ? void 0 : data.middleName, 'middleName', `middleName-control-${id}`), renderRow('Last name', data == null ? void 0 : data.lastName, 'lastName', `lastName-control-${id}`), renderRow('Date of birth', data == null ? void 0 : data.dateOfBirth, 'dateOfBirth', `dob-control-${id}`)]
15417
15302
  });
15418
15303
  };
15419
- const GoAContractInfoControlReview = withJsonFormsAllOfProps(ContractInfoControlReview);
15420
-
15421
- const isContactInformation = createSchemaMatchTester(['email', 'phone', 'preferredContactMethod']);
15422
- const ContactInformationTester = rankWith(4, isContactInformation);
15423
-
15424
- var $$4 = _export;
15425
- var iterate = iterate$c;
15426
- var createProperty$1 = createProperty$4;
15304
+ const GoAInputBaseFullNameDobControlReview = withJsonFormsAllOfProps(FullNameDobReviewControl);
15427
15305
 
15428
- // `Object.fromEntries` method
15429
- // https://github.com/tc39/proposal-object-from-entries
15430
- $$4({ target: 'Object', stat: true }, {
15431
- fromEntries: function fromEntries(iterable) {
15432
- var obj = {};
15433
- iterate(iterable, function (k, v) {
15434
- createProperty$1(obj, k, v);
15435
- }, { AS_ENTRIES: true });
15436
- return obj;
15306
+ // Encapsulates masked-input state for a GoA input: display value, mount reflection, and change/keypress handling.
15307
+ const resetMaskedValue = (detail, nextValue) => {
15308
+ const target = getMaskInputTarget(detail);
15309
+ if (target) {
15310
+ target.value = nextValue;
15437
15311
  }
15438
- });
15439
-
15440
- var global$2 = global$v;
15441
- var fails = fails$D;
15442
- var uncurryThis$3 = functionUncurryThis;
15443
- var toString$2 = toString$n;
15444
- var trim = stringTrim.trim;
15445
- var whitespaces = whitespaces$3;
15446
-
15447
- var $parseInt$1 = global$2.parseInt;
15448
- var Symbol$1 = global$2.Symbol;
15449
- var ITERATOR = Symbol$1 && Symbol$1.iterator;
15450
- var hex = /^[+-]?0x/i;
15451
- var exec$2 = uncurryThis$3(hex.exec);
15452
- var FORCED = $parseInt$1(whitespaces + '08') !== 8 || $parseInt$1(whitespaces + '0x16') !== 22
15453
- // MS Edge 18- broken with boxed symbols
15454
- || (ITERATOR && !fails(function () { $parseInt$1(Object(ITERATOR)); }));
15455
-
15456
- // `parseInt` method
15457
- // https://tc39.es/ecma262/#sec-parseint-string-radix
15458
- var numberParseInt = FORCED ? function parseInt(string, radix) {
15459
- var S = trim(toString$2(string));
15460
- return $parseInt$1(S, (radix >>> 0) || (exec$2(hex, S) ? 16 : 10));
15461
- } : $parseInt$1;
15462
-
15463
- var $$3 = _export;
15464
- var $parseInt = numberParseInt;
15465
-
15466
- // `parseInt` method
15467
- // https://tc39.es/ecma262/#sec-parseint-string-radix
15468
- $$3({ global: true, forced: parseInt !== $parseInt }, {
15469
- parseInt: $parseInt
15470
- });
15471
-
15472
- const ADD_DATA_ACTION = 'jsonforms/register/add_data_action';
15473
- const SET_DATA_ACTION = 'jsonforms/register/set_data_action';
15474
- const INCREMENT_ACTION = 'jsonforms/register/increment_action';
15475
- const DELETE_ACTION = 'jsonforms/register/delete_action';
15476
- const initialState = {
15477
- categories: {}
15478
15312
  };
15479
-
15480
- function objectListReducer(state, action) {
15481
- switch (action.type) {
15482
- case ADD_DATA_ACTION:
15483
- {
15484
- //ok so we're assuming we're already getting the updated category data
15485
- const {
15486
- categories
15487
- } = state;
15488
- const {
15489
- name,
15490
- category
15491
- } = action.payload;
15492
- const newCategories = Object.assign({}, categories);
15493
- if (!newCategories[name]) {
15494
- newCategories[name] = {
15495
- data: category
15496
- };
15497
- } else {
15498
- newCategories[name].data = category;
15499
- }
15500
- return Object.assign({}, state, {
15501
- categories: newCategories
15502
- });
15503
- }
15504
- case SET_DATA_ACTION:
15505
- {
15506
- const CategoriesStateData = action.payload;
15507
- return Object.assign({}, state, {
15508
- categories: CategoriesStateData
15509
- });
15510
- }
15511
- case INCREMENT_ACTION:
15512
- {
15513
- const {
15514
- categories
15515
- } = state;
15516
- const name = action.payload;
15517
- const newCategories = Object.assign({}, categories);
15518
- // Assuming you want to increment the count of a category:
15519
- if (newCategories[name]) {
15520
- const updatedCategory = Object.assign({}, categories[name], {
15521
- count: (categories[name].count || 0) + 1
15522
- });
15523
- return Object.assign({}, state, {
15524
- categories: Object.assign({}, categories, {
15525
- [name]: updatedCategory
15526
- })
15527
- });
15528
- } else {
15529
- newCategories[name] = {
15530
- count: 1,
15531
- data: {}
15532
- };
15533
- }
15534
- return Object.assign({}, state, {
15535
- categories: newCategories
15536
- });
15537
- }
15538
- case DELETE_ACTION:
15539
- {
15540
- const {
15541
- name,
15542
- category
15543
- } = action.payload;
15544
- const {
15545
- categories
15546
- } = state;
15547
- const newCategories = Object.assign({}, categories);
15548
- newCategories[name] = category;
15549
- return Object.assign({}, state, {
15550
- categories: newCategories
15551
- });
15552
- }
15553
- default:
15554
- return state;
15555
- }
15556
- }
15557
-
15558
- const DeleteDialog = /*#__PURE__*/React.memo(function DeleteDialog({
15559
- open,
15560
- onConfirm,
15561
- onCancel,
15562
- title,
15563
- message
15564
- }) {
15565
- useEffect(() => {
15566
- if (open) {
15567
- const deleteBtn = document.querySelector('[data-testId="object-array-confirm-button"]');
15568
- if (deleteBtn) {
15569
- setTimeout(() => {
15570
- var _deleteBtn$shadowRoot;
15571
- (_deleteBtn$shadowRoot = deleteBtn.shadowRoot) == null || (_deleteBtn$shadowRoot = _deleteBtn$shadowRoot.querySelector('button')) == null || _deleteBtn$shadowRoot.focus();
15572
- }, 200);
15313
+ const useMaskedInput = ({
15314
+ mask,
15315
+ inPlace,
15316
+ data,
15317
+ allowedKeys,
15318
+ onCommit
15319
+ }) => {
15320
+ const format = value => inPlace ? toMaskTemplate(value, mask) : formatWithPattern(value, mask);
15321
+ const initialDisplay = format(typeof data === 'string' ? data : '');
15322
+ // In-place mounts empty then sets the template so the web component reflects it (a value change forces the paint).
15323
+ const [value, setValue] = useState(inPlace ? '' : initialDisplay);
15324
+ useEffect(() => {
15325
+ setValue(format(typeof data === 'string' ? data : ''));
15326
+ // eslint-disable-next-line react-hooks/exhaustive-deps
15327
+ }, [mask, inPlace]);
15328
+ const handleChange = detail => {
15329
+ var _target$selectionStar;
15330
+ const rawValue = detail.value;
15331
+ const cleaned = allowedKeys ? filterAllowedKeys(rawValue, allowedKeys) : rawValue;
15332
+ if (!inPlace) {
15333
+ const stored = cleaned === '' ? '' : formatWithPattern(cleaned, mask);
15334
+ if (allowedKeys && cleaned !== rawValue) {
15335
+ resetMaskedValue(detail, stored);
15573
15336
  }
15337
+ setValue(stored);
15338
+ onCommit(stored);
15339
+ return;
15574
15340
  }
15575
- }, [open]);
15576
- return jsxs(GoabModal, {
15577
- open: open,
15578
- testId: "object-array-modal",
15579
- heading: title,
15580
- children: [jsx(DeleteDialogContent, {
15581
- "data-testid": "object-array-modal-content",
15582
- children: `${message}?`
15583
- }), jsxs(GoabButtonGroup, {
15584
- alignment: "end",
15585
- children: [jsx(GoabButton, {
15586
- type: "secondary",
15587
- testId: "object-array-modal-button",
15588
- onClick: () => {
15589
- onCancel();
15590
- },
15591
- children: "Cancel"
15592
- }), jsx(GoabButton, {
15593
- type: "primary",
15594
- variant: "destructive",
15595
- testId: "object-array-confirm-button",
15596
- onClick: () => {
15597
- onConfirm();
15598
- },
15599
- children: "Delete"
15600
- })]
15601
- })]
15602
- }, 1);
15603
- });
15604
-
15605
- const _excluded$4 = ["label", "path", "schema", "rootSchema", "uischema", "errors", "visible", "enabled", "cells", "data", "config", "isStepperReview", "handleChange", "removeItems"];
15606
- const GenerateRows = (Cell, schema, rowPath, enabled, openDeleteDialog, handleChange, cells, uischema, isInReview, count, data, errors) => {
15607
- if ((schema == null ? void 0 : schema.type) === 'object') {
15608
- const props = {
15609
- schema,
15610
- rowPath,
15611
- enabled,
15612
- cells,
15613
- uischema,
15614
- isInReview,
15615
- openDeleteDialog,
15616
- data,
15617
- handleChange,
15618
- errors
15619
- };
15620
- return jsx(ListWithDetailsReviewCellDiv, {
15621
- children: jsx(Cell, Object.assign({}, props, {
15622
- count: count || 0
15623
- }))
15624
- });
15625
- } else {
15626
- const props = {
15627
- schema,
15628
- rowPath,
15629
- cellPath: rowPath,
15630
- enabled,
15631
- uischema,
15632
- isInReview,
15633
- openDeleteDialog,
15634
- handleChange,
15635
- data
15636
- };
15637
- return jsx(ListWithDetailsReviewCellDiv, {
15638
- children: jsx(Cell, Object.assign({}, props, {
15639
- count: count || 0
15640
- }), rowPath)
15641
- });
15642
- }
15643
- };
15644
- const getValidColumnProps = scopedSchema => {
15645
- if (scopedSchema.type === 'object' && typeof scopedSchema.properties === 'object') {
15646
- return Object.keys(scopedSchema.properties);
15647
- }
15648
- // primitives
15649
- return [''];
15650
- };
15651
- const EmptyList = ({
15652
- numColumns,
15653
- noDataMessage,
15654
- translations
15655
- }) => jsx("div", {
15656
- style: {
15657
- width: '100%',
15658
- padding: '1rem 0'
15659
- },
15660
- children: jsx(TextCenter, {
15661
- children: jsx("b", {
15662
- children: noDataMessage
15663
- })
15664
- })
15665
- });
15666
- const ctxToNonEmptyCellProps = (ctx, ownProps) => {
15667
- var _ctx$core, _ctx$core2;
15341
+ const target = getMaskInputTarget(detail);
15342
+ const caretIndex = (_target$selectionStar = target == null ? void 0 : target.selectionStart) != null ? _target$selectionStar : cleaned.length;
15343
+ const overflow = overflowMaskEdit(value, cleaned, caretIndex, mask);
15344
+ if (overflow) {
15345
+ applyInPlaceEdit(target, overflow);
15346
+ return;
15347
+ }
15348
+ const edit = computeMaskEdit(cleaned, caretIndex, mask);
15349
+ applyInPlaceEdit(target, edit);
15350
+ setValue(edit.display);
15351
+ onCommit(edit.stored);
15352
+ };
15353
+ // In-place has no maxLength (the template is already full length) and GoA keyPress is keyup, so restore on overflow.
15354
+ const handleKeyPress = detail => {
15355
+ var _detail$event, _target$value, _target$selectionStar2;
15356
+ const blockDisallowed = shouldBlockKey(detail.key, allowedKeys);
15357
+ const blockOverflow = inPlace && /^[A-Za-z0-9]$/.test(detail.key) && isMaskFilled(value, mask);
15358
+ if (!blockDisallowed && !blockOverflow) {
15359
+ return;
15360
+ }
15361
+ (_detail$event = detail.event) == null || _detail$event.preventDefault();
15362
+ if (!blockOverflow) {
15363
+ return;
15364
+ }
15365
+ const target = getMaskInputTarget(detail);
15366
+ const rawValue = (_target$value = target == null ? void 0 : target.value) != null ? _target$value : value;
15367
+ const overflow = overflowMaskEdit(value, rawValue, (_target$selectionStar2 = target == null ? void 0 : target.selectionStart) != null ? _target$selectionStar2 : value.length, mask);
15368
+ if (overflow) {
15369
+ applyInPlaceEdit(target, overflow);
15370
+ }
15371
+ };
15668
15372
  return {
15669
- uischema: ownProps.uischema,
15670
- rowPath: ownProps.rowPath,
15671
- schema: ownProps.schema,
15672
- rootSchema: (_ctx$core = ctx.core) == null ? void 0 : _ctx$core.schema,
15673
- errors: ((_ctx$core2 = ctx.core) == null ? void 0 : _ctx$core2.errors) || undefined,
15674
- enabled: ownProps.enabled,
15675
- cells: ownProps.cells || ctx.cells,
15676
- renderers: ownProps.renderers || ctx.renderers,
15677
- handleChange: ownProps.handleChange
15373
+ value,
15374
+ handleChange,
15375
+ handleKeyPress
15678
15376
  };
15679
15377
  };
15680
- const NonEmptyCellComponent = /*#__PURE__*/React.memo(function NonEmptyCellComponent(props) {
15681
- var _schema$properties, _uischema$options, _uischema$options2, _errors$filter, _uischema$elements;
15378
+
15379
+ const PhoneNumberControl = props => {
15380
+ var _uischema$options, _uischema$options2;
15682
15381
  const {
15382
+ data,
15383
+ path,
15683
15384
  schema,
15684
- enabled,
15685
- renderers,
15686
- cells,
15687
- rowPath,
15688
15385
  uischema,
15689
- isInReview,
15690
- data,
15691
- count,
15692
- openDeleteDialog,
15693
15386
  handleChange,
15694
- errors
15387
+ enabled,
15388
+ visible,
15389
+ required
15695
15390
  } = props;
15391
+ // Default mask can be overridden per field via the UI schema options.
15392
+ const phoneMask = (uischema == null || (_uischema$options = uischema.options) == null ? void 0 : _uischema$options.phoneMask) || DEFAULT_PATTERNS.phone.mask;
15393
+ // When in-place, the field shows the fill-in template and edits keep the caret in place.
15394
+ const inPlace = (uischema == null || (_uischema$options2 = uischema.options) == null ? void 0 : _uischema$options2.inPlace) === true;
15395
+ const [error, setError] = useState('');
15696
15396
  const {
15697
- noAnswerMessage
15698
- } = useStepperPageOptions();
15699
- const element = (schema == null ? void 0 : schema.items) || (schema == null || (_schema$properties = schema.properties) == null || (_schema$properties = _schema$properties[rowPath]) == null ? void 0 : _schema$properties.items) || schema;
15700
- const required = (element == null ? void 0 : element.required) || [];
15701
- const properties = element == null ? void 0 : element.properties;
15702
- let tableKeys = extractNames(uischema == null || (_uischema$options = uischema.options) == null ? void 0 : _uischema$options.detail);
15703
- if (Object.keys(tableKeys).length === 0) {
15704
- properties && Object.keys(properties).forEach(item => {
15705
- tableKeys[item] = item;
15706
- });
15707
- }
15708
- if (properties && Object.keys(properties).length !== Object.keys(tableKeys).length) {
15709
- const tempTableKeys = {};
15710
- //For nested objects to display only the top level column.
15711
- properties && Object.keys(properties).forEach(item => {
15712
- if (Object.keys(tableKeys).includes(item)) {
15713
- tempTableKeys[item] = tableKeys[item];
15714
- } else {
15715
- // If the property is not in the tableKeys (e.g. it was a nested object in the UI schema),
15716
- // we still need a header for it to maintain alignment.
15717
- // Use the property title from the schema, or capitalize the property name.
15718
- tempTableKeys[item] = properties[item].title || capitalizeFirstLetter(item);
15719
- }
15720
- });
15721
- tableKeys = tempTableKeys;
15722
- }
15723
- // Review only shows properties that have a control in the detail UI schema.
15724
- const detailProperties = extractScopedProperties(uischema == null || (_uischema$options2 = uischema.options) == null ? void 0 : _uischema$options2.detail);
15725
- const reviewKeys = detailProperties.size > 0 ? Object.fromEntries(Object.entries(tableKeys).filter(([key]) => detailProperties.has(key))) : tableKeys;
15726
- const hasAnyErrors = Array.isArray(errors) ? (errors == null || (_errors$filter = errors.filter(err => {
15727
- return err.instancePath.includes(rowPath);
15728
- })) == null ? void 0 : _errors$filter.length) > 0 : false;
15729
- return jsxs(NonEmptyCellStyle, {
15730
- "data-testid": `${rowPath}-ObjectListOuterWrapper`,
15731
- children: [!isInReview && (uischema == null || (_uischema$elements = uischema.elements) == null ? void 0 : _uischema$elements.map(element => {
15732
- return jsx(JsonFormsDispatch, {
15733
- "data-testid": `jsonforms-object-list-defined-elements-dispatch`,
15734
- schema: schema,
15735
- uischema: element,
15736
- path: rowPath,
15737
- enabled: enabled,
15738
- renderers: renderers,
15739
- cells: cells
15740
- }, rowPath);
15741
- })), properties && Object.keys(properties).length > 0 && jsxs(Fragment, {
15742
- children: [isInReview ? jsx("div", {
15743
- style: {
15744
- padding: '0.75rem 0'
15745
- },
15746
- "data-testid": `${rowPath}.objectListWrapper`,
15747
- children: range(count || 0).map((i, key) => {
15748
- const rowData = data && data[i];
15749
- if (!rowData) return null;
15750
- const hasAnyValue = Object.keys(reviewKeys).some(key => {
15751
- const value = rowData[key];
15752
- return value !== undefined && value !== null && value !== '';
15753
- });
15754
- const hasRowErrors = (errors || []).some(e => e.instancePath.includes(`/${props.rowPath.replace(/\./g, '/')}/${i}`));
15755
- if (!hasAnyValue && !hasRowErrors) return null;
15756
- return jsx(ReviewItemFrame, {
15757
- "data-testid": `${rowPath}.objectList-${key}`,
15758
- children: Object.entries(reviewKeys).map(([key, label]) => {
15759
- var _required$includes, _properties$key;
15760
- const value = rowData[key];
15761
- const isRequiredField = (_required$includes = required == null ? void 0 : required.includes(key)) != null ? _required$includes : false;
15762
- const fieldPath = `/${props.rowPath.replace(/\./g, '/')}/${i}/${key}`;
15763
- const rowPathMatch = `/${props.rowPath.replace(/\./g, '/')}/${i}`;
15764
- const fieldError = (errors || []).find(e => {
15765
- var _msg$match;
15766
- const msg = e.message || '';
15767
- const requiredProperty = (_msg$match = msg.match(/'([^']+)'/)) == null ? void 0 : _msg$match[1];
15768
- return e.instancePath === fieldPath || e.instancePath === rowPathMatch && msg.includes(key) || e.instancePath === rowPathMatch && requiredProperty === key;
15769
- });
15770
- const isEmptyValue = value === undefined || value === null || value === '';
15771
- let reviewError = '';
15772
- if (fieldError) {
15773
- const raw = fieldError.message || '';
15774
- reviewError = raw.includes('required') ? `${capitalizeFirstLetter(label.replace(/[_-]/g, ' '))} is required` : raw;
15775
- } else if (isRequiredField && isEmptyValue) {
15776
- reviewError = `${capitalizeFirstLetter(label.replace(/[_-]/g, ' '))} is required`;
15777
- }
15778
- return jsxs(ReviewRow, {
15779
- "data-testid": `#/properties/${key}-input-${i}-row`,
15780
- children: [jsxs(ReviewRowLabel, {
15781
- children: [(properties == null || (_properties$key = properties[key]) == null ? void 0 : _properties$key.title) || (label !== key ? label : key.replace(/([A-Z])/g, ' $1').replace(/[_-]/g, ' ').replace(/^./, c => c.toUpperCase())), isRequiredField && jsx(RequiredSpan, {
15782
- children: " (required)"
15783
- }), " :"]
15784
- }), jsx(ReviewRowValue, {
15785
- "data-testid": `#/properties/${key}-input-${i}-review`,
15786
- children: renderCellColumn({
15787
- data: isEmptyValue ? undefined : value,
15788
- error: reviewError,
15789
- isRequired: isRequiredField,
15790
- errors: errors !== undefined ? errors : [],
15791
- element: key,
15792
- rowPath,
15793
- index: i,
15794
- noAnswerMessage: noAnswerMessage != null ? noAnswerMessage : NO_ANSWER_MESSAGE
15795
- })
15796
- })]
15797
- }, key);
15798
- })
15799
- }, i);
15397
+ value,
15398
+ handleChange: handleMaskChange,
15399
+ handleKeyPress
15400
+ } = useMaskedInput({
15401
+ mask: phoneMask,
15402
+ inPlace,
15403
+ data,
15404
+ allowedKeys: DEFAULT_PATTERNS.phone.allowedKeys,
15405
+ onCommit: stored => {
15406
+ setError(stored && !DEFAULT_PATTERNS.phone.pattern.test(stored) ? DEFAULT_PATTERNS.phone.error : '');
15407
+ handleChange(path, stored);
15408
+ }
15409
+ });
15410
+ return jsx(Visible, {
15411
+ "$visible": visible,
15412
+ children: jsx(GoabFormItem, {
15413
+ label: (schema == null ? void 0 : schema.title) || 'Phone number',
15414
+ requirement: required ? 'required' : undefined,
15415
+ error: error,
15416
+ testId: `form-item-${path}`,
15417
+ children: jsx(GoabInput, {
15418
+ type: "tel",
15419
+ name: path,
15420
+ disabled: !enabled,
15421
+ "aria-label": "phone number input",
15422
+ testId: `phone-input-${path}`,
15423
+ value: value,
15424
+ maxLength: inPlace ? undefined : phoneMask.length,
15425
+ placeholder: inPlace ? undefined : maskPlaceholder(phoneMask),
15426
+ onChange: detail => handleMaskChange(detail),
15427
+ onKeyPress: detail => handleKeyPress(detail),
15428
+ width: "100%"
15429
+ }, `${phoneMask}:${inPlace}`)
15430
+ })
15431
+ });
15432
+ };
15433
+ const GoAPhoneNumberControl = withJsonFormsControlProps(PhoneNumberControl);
15434
+
15435
+ const PhoneNumberTester = rankWith(4, and(isControl$1, schemaTypeIs('string'), formatIs('phone')));
15436
+
15437
+ let _$3 = t => t,
15438
+ _t$3,
15439
+ _t2$1,
15440
+ _t3,
15441
+ _t4,
15442
+ _t5,
15443
+ _t6;
15444
+ const SearchBox = styled.div(_t$3 || (_t$3 = _$3`
15445
+ position: relative;
15446
+
15447
+ .suggestions {
15448
+ width: 100%;
15449
+ margin-top: 3px;
15450
+ border-top-width: 0;
15451
+ list-style: none;
15452
+ max-height: 15.5rem;
15453
+ width: 100%;
15454
+ position: absolute;
15455
+
15456
+ background: var(--goa-color-greyscale-white);
15457
+ box-shadow: 0 8px 8px rgb(0 0 0 / 20%), 0 4px 4px rgb(0 0 0 / 10%);
15458
+ z-index: 99;
15459
+ overflow: hidden auto;
15460
+ padding-left: 0;
15461
+ }
15462
+ .suggestions li {
15463
+ }
15464
+ .suggestion-active,
15465
+ .suggestions li:hover {
15466
+ background-color: var(--goa-color-interactive-default);
15467
+ color: var(--goa-color-greyscale-white);
15468
+ cursor: pointer;
15469
+ font-weight: 600;
15470
+ }
15471
+ .input-container {
15472
+ position: relative;
15473
+ display: inline-block;
15474
+ width: 100%; /* Ensures it spans the parent container */
15475
+ }
15476
+
15477
+ .input-container .input-spinner {
15478
+ position: absolute;
15479
+ top: 50%;
15480
+ right: 8px; /* Adjust based on padding or margin of the input field */
15481
+ transform: translateY(-50%);
15482
+ z-index: 1; /* Ensure it appears above the input */
15483
+ pointer-events: none; /* Prevent spinner from interfering with clicks */
15484
+ }
15485
+ `));
15486
+ const AddressIndent = styled.div(_t2$1 || (_t2$1 = _$3`
15487
+ margin: 0 0 var(--goa-space-m) 0;
15488
+ text-wrap: wrap;
15489
+ word-break: break-word;
15490
+ border: 1px solid var(--goa-color-greyscale-300);
15491
+ border-radius: var(--goa-border-radius-xl);
15492
+ padding: var(--goa-space-l);
15493
+ `));
15494
+ const TextWrap = styled.p(_t3 || (_t3 = _$3`
15495
+ text-wrap: auto;
15496
+ word-break: break-word;
15497
+ `));
15498
+ const TextWrapDiv = styled.div(_t4 || (_t4 = _$3`
15499
+ text-wrap: auto;
15500
+ word-break: break-word;
15501
+ `));
15502
+ const LabelDiv = styled.div(_t5 || (_t5 = _$3`
15503
+ color: var(--goa-color-text-default);
15504
+ font: var(--goa-typography-body-m);
15505
+ min-height: 2.625rem;
15506
+ display: flex;
15507
+ align-items: center;
15508
+ text-wrap: auto;
15509
+ word-break: break-word;
15510
+ `));
15511
+ /* istanbul ignore next */
15512
+ const ListItem = styled.li(_t6 || (_t6 = _$3`
15513
+ background-color: ${0};
15514
+ color: ${0};
15515
+ font-weight: ${0};
15516
+ padding: var(--goa-space-xs) var(--goa-space-2xs) var(--goa-space-xs) var(--goa-space-xs);
15517
+ margin-left: 0.25rem;
15518
+ `), ({
15519
+ selected,
15520
+ index
15521
+ }) => selected === index ? 'var(--goa-color-interactive-default)' : '', ({
15522
+ selected,
15523
+ index
15524
+ }) => selected === index ? 'var(--goa-color-greyscale-white) !important' : '', ({
15525
+ selected,
15526
+ index
15527
+ }) => selected === index ? '600' : '');
15528
+
15529
+ const PhoneNumberReviewControl = props => {
15530
+ const {
15531
+ data,
15532
+ id,
15533
+ required
15534
+ } = props;
15535
+ return jsx(GoabFormItem, {
15536
+ label: "Phone number",
15537
+ error: required && !data ? 'Phone number is required' : '',
15538
+ requirement: required ? 'required' : undefined,
15539
+ children: jsx(TextWrapDiv, {
15540
+ children: jsx("div", {
15541
+ "data-testid": `phone-control-${id}`,
15542
+ children: data || ''
15543
+ })
15544
+ })
15545
+ });
15546
+ };
15547
+ const GoabInputBasePhoneNumberReviewControl = withJsonFormsAllOfProps(PhoneNumberReviewControl);
15548
+
15549
+ let _$2 = t => t,
15550
+ _t$2;
15551
+ const PhoneGrid = styled.div(_t$2 || (_t$2 = _$2`
15552
+ display: grid;
15553
+ grid-template-columns: 1fr 2fr;
15554
+ gap: 0.2rem;
15555
+ align-items: start;
15556
+ margin-bottom: var(--goa-space-l) !important;
15557
+
15558
+ goa-form-item {
15559
+ margin-right: 0 !important;
15560
+ }
15561
+ `));
15562
+ const PHONE_REGEX = /^\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$/;
15563
+ const normalizePhoneData = value => ({
15564
+ type: (value == null ? void 0 : value.type) || '',
15565
+ number: (value == null ? void 0 : value.number) || ''
15566
+ });
15567
+ const PhoneNumberWithTypeControl = props => {
15568
+ const {
15569
+ data,
15570
+ path,
15571
+ handleChange,
15572
+ enabled,
15573
+ visible,
15574
+ required
15575
+ } = props;
15576
+ const [formData, setFormData] = useState(normalizePhoneData(data));
15577
+ const [error, setError] = useState(undefined);
15578
+ useEffect(() => {
15579
+ const nextData = normalizePhoneData(data);
15580
+ setFormData(currentData => currentData.type === nextData.type && currentData.number === nextData.number ? currentData : nextData);
15581
+ }, [data]);
15582
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
15583
+ const updateFormData = updated => {
15584
+ setFormData(updated);
15585
+ if (updated.number && !PHONE_REGEX.test(updated.number)) {
15586
+ setError('Enter a valid phone number (e.g., (780) 123-4567)');
15587
+ } else {
15588
+ setError(undefined);
15589
+ }
15590
+ handleChange(path, updated);
15591
+ };
15592
+ return jsx(Visible, {
15593
+ "$visible": visible,
15594
+ children: jsxs(PhoneGrid, {
15595
+ children: [jsx(GoabFormItem, {
15596
+ label: "Phone type",
15597
+ requirement: required ? 'required' : undefined,
15598
+ children: jsxs(GoabDropdown, {
15599
+ name: "type",
15600
+ value: formData.type || '',
15601
+ disabled: !enabled,
15602
+ onChange: detail => updateFormData(Object.assign({}, formData, {
15603
+ type: detail.value
15604
+ })),
15605
+ children: [jsx(GoabDropdownItem, {
15606
+ value: "Mobile"
15607
+ }), jsx(GoabDropdownItem, {
15608
+ value: "Landline"
15609
+ })]
15800
15610
  })
15801
- }) : jsx(FixTableHeaderAlignment, {
15802
- children: jsxs(GoabTable, {
15803
- width: "100%",
15804
- children: [jsx("thead", {
15805
- children: jsxs("tr", {
15806
- children: [Object.entries(tableKeys).map(([value, index]) => {
15807
- const currentProperty = properties[value];
15808
- return jsx("th", {
15809
- children: jsxs("p", {
15810
- children: [(currentProperty == null ? void 0 : currentProperty.title) || index, ' ', (required == null ? void 0 : required.includes(value)) && jsx(RequiredSpan, {
15811
- children: "(required)"
15812
- })]
15813
- })
15814
- }, index);
15815
- }), jsx("th", {
15816
- children: jsx("p", {
15817
- children: "Actions"
15818
- })
15819
- })]
15820
- }, 0)
15821
- }), jsx("tbody", {
15822
- children: range(count || 0).map((num, i) => {
15823
- const errorRow = errors == null ? void 0 : errors.find(error => error.instancePath.includes(`/${props.rowPath.replace(/\./g, '/')}/${i}`));
15824
- return jsxs("tr", {
15825
- children: [Object.keys(properties).map((element, ix) => {
15826
- var _error$message;
15827
- const dataObject = properties[element];
15828
- const schemaName = element;
15829
- const currentData = data && data[num] ? data[num][element] : '';
15830
- //Get out of the loop to not render extra blank columns at the end of the table
15831
- if (ix > 1 && Object.keys(tableKeys).length === ix) return null;
15832
- const error = (errors == null ? void 0 : errors.filter(e => e.instancePath === `/${props.rowPath.replace(/\./g, '/')}/${i}/${element}` || e.instancePath === `/${props.rowPath.replace(/\./g, '/')}/${i}`)).find(y => {
15833
- var _y$message;
15834
- return (y == null || (_y$message = y.message) == null ? void 0 : _y$message.includes(element)) || y.instancePath.includes(element);
15835
- });
15836
- // Create a human-friendly error message for rendering
15837
- let humanMessage = createHumanizeError(error, schema, uischema);
15838
- if (error != null && (_error$message = error.message) != null && _error$message.includes('must NOT have fewer') && required.find(r => r === schemaName) && (isEmptyBoolean(schema, currentData) || isEmptyNumber(schema, currentData))) {
15839
- humanMessage = `${capitalizeFirstLetter(schemaName)} is required`;
15840
- }
15841
- return jsx("td", {
15842
- children: jsx(GoabFormItem, {
15843
- error: humanMessage != null ? humanMessage : '',
15844
- mb: errorRow && !error && '2xl' || 'xs',
15845
- children: dataObject.enum ? jsxs(GoabDropdown, {
15846
- id: schemaName,
15847
- name: schemaName,
15848
- value: currentData != null ? String(currentData) : '',
15849
- testId: `#/properties/${schemaName}-select-${i}`,
15850
- onChange: detail => {
15851
- const selectedValue = Array.isArray(detail.value) ? detail.value[0] : detail.value;
15852
- const coerced = dataObject.type === 'number' && selectedValue !== '' ? Number(selectedValue) : selectedValue;
15853
- handleChange(rowPath, {
15854
- [num]: {
15855
- [schemaName]: coerced
15856
- }
15857
- });
15858
- },
15859
- width: "100%",
15860
- ariaLabel: schemaName,
15861
- error: !!humanMessage,
15862
- children: [!(required != null && required.includes(schemaName)) && jsx(GoabDropdownItem, {
15863
- value: "",
15864
- label: `-- Select ${schemaName} --`
15865
- }), dataObject.enum.map(opt => jsx(GoabDropdownItem, {
15866
- value: String(opt),
15867
- label: String(opt)
15868
- }, String(opt)))]
15869
- }) : dataObject.type === 'number' || dataObject.type === 'string' && !dataObject.enum ? jsx(GoabInput, {
15870
- error: humanMessage ? humanMessage.length > 0 : false,
15871
- type: dataObject.type === 'number' ? 'number' : 'text',
15872
- id: schemaName,
15873
- name: schemaName,
15874
- value: currentData,
15875
- testId: `#/properties/${schemaName}-input-${i}`,
15876
- onChange: detail => {
15877
- handleChange(rowPath, {
15878
- [num]: {
15879
- [detail.name]: dataObject.type === 'number' ? parseInt(detail.value) : detail.value
15880
- }
15881
- });
15882
- },
15883
- ariaLabel: schemaName,
15884
- width: "100%"
15885
- }) : jsx(GoabCallout, {
15886
- type: "important",
15887
- size: "medium",
15888
- testId: "form-support-callout",
15889
- heading: "Not supported",
15890
- children: "Only string, number, and enum are supported inside arrays"
15891
- })
15892
- })
15893
- }, ix);
15894
- }), !isInReview && jsx("td", {
15895
- style: {
15896
- alignContent: 'baseLine',
15897
- paddingTop: '18px'
15898
- },
15899
- children: jsx("div", {
15900
- children: jsx(GoabIconButton, {
15901
- icon: "trash",
15902
- title: "trash button",
15903
- testId: "trash-icon-button",
15904
- "aria-label": `remove-element-${num}`,
15905
- onClick: () => openDeleteDialog(num)
15906
- })
15907
- })
15908
- })]
15909
- }, `${rowPath}-${i}-${num}`);
15910
- })
15611
+ }), jsx(GoabFormItem, {
15612
+ label: "Phone number",
15613
+ error: error,
15614
+ requirement: required ? 'required' : undefined,
15615
+ children: jsx(GoabInput, {
15616
+ type: "tel",
15617
+ name: "number",
15618
+ placeholder: "(000) 000-0000",
15619
+ value: formData.number || '',
15620
+ disabled: !enabled,
15621
+ onChange: detail => updateFormData(Object.assign({}, formData, {
15622
+ number: detail.value
15623
+ }))
15624
+ })
15625
+ })]
15626
+ })
15627
+ });
15628
+ };
15629
+ const GoAPhoneNumberWithTypeControl = withJsonFormsControlProps(PhoneNumberWithTypeControl);
15630
+
15631
+ const isPhoneNumberWithType = createSchemaMatchTester(['number', 'type'], true);
15632
+ const PhoneNumberWithTypeTester = rankWith(4, isPhoneNumberWithType);
15633
+
15634
+ const PhoneNumberWithTypeReviewControl = props => {
15635
+ const {
15636
+ data,
15637
+ id,
15638
+ required
15639
+ } = props;
15640
+ return jsxs(PhoneGrid, {
15641
+ children: [jsx(GoabFormItem, {
15642
+ label: "Phone number",
15643
+ error: required && !(data != null && data.number) ? 'Phone number is required' : '',
15644
+ requirement: required ? 'required' : undefined,
15645
+ children: jsx(TextWrapDiv, {
15646
+ children: jsx("div", {
15647
+ "data-testid": `phone-number-control-${id}`,
15648
+ children: (data == null ? void 0 : data.number) || ''
15649
+ })
15650
+ })
15651
+ }), jsx(GoabFormItem, {
15652
+ label: "Phone type",
15653
+ error: required && !(data != null && data.type) ? 'Phone type is required' : '',
15654
+ requirement: required ? 'required' : undefined,
15655
+ children: jsx(TextWrapDiv, {
15656
+ children: jsx("div", {
15657
+ "data-testid": `phone-type-control-${id}`,
15658
+ children: (data == null ? void 0 : data.type) || ''
15659
+ })
15660
+ })
15661
+ })]
15662
+ });
15663
+ };
15664
+ const GoabInputBasePhoneNumberWithTypeReviewControl = withJsonFormsAllOfProps(PhoneNumberWithTypeReviewControl);
15665
+
15666
+ let _$1 = t => t,
15667
+ _t$1;
15668
+ const FormFieldWrapper = styled.div(_t$1 || (_t$1 = _$1`
15669
+ margin-bottom: var(--goa-space-l);
15670
+ `));
15671
+
15672
+ const ContractInfoControl = props => {
15673
+ var _options$enableEmail, _options$enablePhone, _options$emailFirst;
15674
+ const {
15675
+ data = {},
15676
+ path,
15677
+ handleChange,
15678
+ enabled,
15679
+ visible,
15680
+ required,
15681
+ uischema
15682
+ } = props;
15683
+ const handleFieldChange = (field, value) => {
15684
+ handleChange(`${path}.${field}`, value);
15685
+ };
15686
+ const emailProps = Object.assign({}, props, {
15687
+ data: data == null ? void 0 : data.email,
15688
+ path: `${path}.email`
15689
+ });
15690
+ const phoneProps = Object.assign({}, props, {
15691
+ data: data == null ? void 0 : data.phone,
15692
+ path: `${path}.phone`
15693
+ });
15694
+ const {
15695
+ options
15696
+ } = uischema;
15697
+ const enableEmail = (_options$enableEmail = options == null ? void 0 : options.enableEmail) != null ? _options$enableEmail : true;
15698
+ const enablePhone = (_options$enablePhone = options == null ? void 0 : options.enablePhone) != null ? _options$enablePhone : true;
15699
+ const emailFirst = (_options$emailFirst = options == null ? void 0 : options.emailFirst) != null ? _options$emailFirst : false;
15700
+ if (!enableEmail && !enablePhone) {
15701
+ throw new Error('At least one contact method must be enabled');
15702
+ }
15703
+ return jsxs("div", {
15704
+ style: {
15705
+ display: visible ? 'block' : 'none'
15706
+ },
15707
+ children: [enableEmail && emailFirst && jsx(GoAEmailInput, Object.assign({}, emailProps)), enablePhone && jsx(FormFieldWrapper, {
15708
+ children: jsx(PhoneNumberControl, Object.assign({}, phoneProps))
15709
+ }), enableEmail && !emailFirst && jsx(GoAEmailInput, Object.assign({}, emailProps)), enableEmail && enablePhone && jsx(FormFieldWrapper, {
15710
+ children: jsx(GoabFormItem, {
15711
+ label: "Preferred Contact Method",
15712
+ requirement: required ? 'required' : undefined,
15713
+ children: jsxs(GoabDropdown, {
15714
+ testId: `preferred-contact-${path}`,
15715
+ disabled: !enabled,
15716
+ value: data.preferredContactMethod || '',
15717
+ onChange: detail => handleFieldChange('preferredContactMethod', detail.value || ''),
15718
+ width: "250px",
15719
+ children: [jsx(GoabDropdownItem, {
15720
+ value: "",
15721
+ label: "Select a Contact Method"
15722
+ }), emailFirst && jsx(GoabDropdownItem, {
15723
+ value: "Email",
15724
+ label: "Email"
15725
+ }), jsx(GoabDropdownItem, {
15726
+ value: "Phone",
15727
+ label: "Phone"
15728
+ }), !emailFirst && jsx(GoabDropdownItem, {
15729
+ value: "Email",
15730
+ label: "Email"
15911
15731
  })]
15912
15732
  })
15913
- }), hasAnyErrors && isInReview && jsx(GoabFormItem, {
15914
- error: `There are validation errors for '${capitalizeFirstLetter(rowPath)}'`
15915
- })]
15733
+ })
15916
15734
  })]
15917
15735
  });
15918
- });
15919
- const NonEmptyCell = ownProps => {
15920
- const data = ownProps.data || {};
15921
- const ctx = useJsonForms();
15922
- const emptyCellProps = ctxToNonEmptyCellProps(ctx, Object.assign({}, ownProps, {
15923
- data
15924
- }));
15925
- const isValid = isEmpty$1(emptyCellProps.errors);
15926
- return jsx(NonEmptyCellComponent, Object.assign({}, emptyCellProps, {
15927
- handleChange: ownProps == null ? void 0 : ownProps.handleChange,
15928
- isInReview: ownProps == null ? void 0 : ownProps.isInReview,
15929
- isValid: isValid,
15930
- openDeleteDialog: ownProps == null ? void 0 : ownProps.openDeleteDialog,
15931
- data: data,
15932
- count: ownProps == null ? void 0 : ownProps.count
15933
- }));
15934
15736
  };
15935
- const NonEmptyRowComponent = ({
15936
- childPath,
15937
- schema,
15938
- openDeleteDialog,
15939
- enabled,
15940
- cells,
15941
- uischema,
15942
- isInReview,
15943
- data,
15944
- count,
15945
- handleChange
15946
- }) => {
15947
- return jsx("div", {
15948
- children: enabled ? isInReview ? jsx("div", {
15949
- children: jsx("div", {
15950
- children: GenerateRows(NonEmptyCell, schema, childPath, enabled, openDeleteDialog, handleChange, cells, uischema, isInReview, count, data)
15951
- })
15952
- }) : jsx(GoabContainer, {
15953
- children: jsx("div", {
15954
- children: jsx("div", {
15955
- children: GenerateRows(NonEmptyCell, schema, childPath, enabled, openDeleteDialog, handleChange, cells, uischema, isInReview, count, data)
15956
- })
15737
+
15738
+ const ContractInfoControlReview = props => {
15739
+ var _props$uischema, _schema$required, _options$enableEmail, _options$enablePhone, _options$emailFirst;
15740
+ const reportChange = useReviewChange();
15741
+ const showChangeButtons = useShowChangeButtons();
15742
+ const stepId = (_props$uischema = props.uischema) == null || (_props$uischema = _props$uischema.options) == null ? void 0 : _props$uischema.stepId;
15743
+ const {
15744
+ uischema,
15745
+ data = {},
15746
+ id,
15747
+ schema
15748
+ } = props;
15749
+ const requiredFields = (_schema$required = schema == null ? void 0 : schema.required) != null ? _schema$required : [];
15750
+ const isMissing = value => value === undefined || value === null || value === '';
15751
+ const renderRow = (fieldLabel, value, fieldName, testId) => {
15752
+ var _uischema$options;
15753
+ return jsx("tr", {
15754
+ children: jsxs(PageReviewContainer, {
15755
+ colSpan: 3,
15756
+ children: [jsxs(ReviewHeader, {
15757
+ children: [jsx(ReviewLabel, {
15758
+ children: fieldLabel
15759
+ }), showChangeButtons && stepId !== undefined && !((_uischema$options = uischema.options) != null && (_uischema$options = _uischema$options.componentProps) != null && _uischema$options.readOnly) && jsx(BackButton, {
15760
+ text: "Change",
15761
+ link: () => reportChange(stepId, uischema.scope),
15762
+ testId: `${fieldName}-change-btn`,
15763
+ showBackIcon: false
15764
+ })]
15765
+ }), jsxs(ReviewValue, {
15766
+ children: [jsx("div", {
15767
+ "data-testid": testId,
15768
+ children: value != null ? value : ''
15769
+ }), requiredFields.includes(fieldName) && isMissing(value) && jsx(GoabFormItem, {
15770
+ error: `${fieldLabel} is required`,
15771
+ label: ""
15772
+ })]
15773
+ })]
15957
15774
  })
15958
- }) : null
15959
- }, childPath);
15775
+ }, testId);
15776
+ };
15777
+ const {
15778
+ options
15779
+ } = uischema;
15780
+ const enableEmail = (_options$enableEmail = options == null ? void 0 : options.enableEmail) != null ? _options$enableEmail : true;
15781
+ const enablePhone = (_options$enablePhone = options == null ? void 0 : options.enablePhone) != null ? _options$enablePhone : true;
15782
+ const emailFirst = (_options$emailFirst = options == null ? void 0 : options.emailFirst) != null ? _options$emailFirst : false;
15783
+ if (!enableEmail && !enablePhone) {
15784
+ throw new Error('At least one contact method must be enabled');
15785
+ }
15786
+ return jsxs(Fragment, {
15787
+ children: [enableEmail && emailFirst && renderRow('Email', data == null ? void 0 : data.email, 'email', `email-control-${id}`), enablePhone && renderRow('Phone number', data == null ? void 0 : data.phone, 'phone', `phone-control-${id}`), enableEmail && !emailFirst && renderRow('Email', data == null ? void 0 : data.email, 'email', `email-control-${id}`), enableEmail && enablePhone && renderRow('Preferred contact method', (data == null ? void 0 : data.preferredContactMethod) || 'Email', 'preferredContactMethod', `preferred-contact-${id}`)]
15788
+ });
15960
15789
  };
15961
- const NonEmptyList = /*#__PURE__*/React.memo(NonEmptyRowComponent);
15962
- const ObjectArrayList = ({
15963
- data,
15964
- path,
15965
- schema,
15966
- openDeleteDialog,
15967
- uischema,
15968
- config,
15969
- enabled,
15970
- cells,
15971
- translations,
15972
- count,
15973
- isInReview,
15974
- handleChange
15975
- }) => {
15976
- const isEmptyList = count === 0;
15977
- if (isEmptyList) {
15978
- var _uischema$options$noD, _uischema$options3;
15979
- const noDataMessage = (_uischema$options$noD = (_uischema$options3 = uischema.options) == null ? void 0 : _uischema$options3.noDataMessage) != null ? _uischema$options$noD : 'No data';
15980
- return jsx(EmptyList, {
15981
- noDataMessage: noDataMessage,
15982
- numColumns: getValidColumnProps(schema).length + 1,
15983
- translations: translations
15984
- });
15790
+ const GoAContractInfoControlReview = withJsonFormsAllOfProps(ContractInfoControlReview);
15791
+
15792
+ const isContactInformation = createSchemaMatchTester(['email', 'phone', 'preferredContactMethod']);
15793
+ const ContactInformationTester = rankWith(4, isContactInformation);
15794
+
15795
+ var $$4 = _export;
15796
+ var iterate = iterate$c;
15797
+ var createProperty$1 = createProperty$4;
15798
+
15799
+ // `Object.fromEntries` method
15800
+ // https://github.com/tc39/proposal-object-from-entries
15801
+ $$4({ target: 'Object', stat: true }, {
15802
+ fromEntries: function fromEntries(iterable) {
15803
+ var obj = {};
15804
+ iterate(iterable, function (k, v) {
15805
+ createProperty$1(obj, k, v);
15806
+ }, { AS_ENTRIES: true });
15807
+ return obj;
15808
+ }
15809
+ });
15810
+
15811
+ var global$2 = global$v;
15812
+ var fails = fails$D;
15813
+ var uncurryThis$3 = functionUncurryThis;
15814
+ var toString$2 = toString$n;
15815
+ var trim = stringTrim.trim;
15816
+ var whitespaces = whitespaces$3;
15817
+
15818
+ var $parseInt$1 = global$2.parseInt;
15819
+ var Symbol$1 = global$2.Symbol;
15820
+ var ITERATOR = Symbol$1 && Symbol$1.iterator;
15821
+ var hex = /^[+-]?0x/i;
15822
+ var exec$2 = uncurryThis$3(hex.exec);
15823
+ var FORCED = $parseInt$1(whitespaces + '08') !== 8 || $parseInt$1(whitespaces + '0x16') !== 22
15824
+ // MS Edge 18- broken with boxed symbols
15825
+ || (ITERATOR && !fails(function () { $parseInt$1(Object(ITERATOR)); }));
15826
+
15827
+ // `parseInt` method
15828
+ // https://tc39.es/ecma262/#sec-parseint-string-radix
15829
+ var numberParseInt = FORCED ? function parseInt(string, radix) {
15830
+ var S = trim(toString$2(string));
15831
+ return $parseInt$1(S, (radix >>> 0) || (exec$2(hex, S) ? 16 : 10));
15832
+ } : $parseInt$1;
15833
+
15834
+ var $$3 = _export;
15835
+ var $parseInt = numberParseInt;
15836
+
15837
+ // `parseInt` method
15838
+ // https://tc39.es/ecma262/#sec-parseint-string-radix
15839
+ $$3({ global: true, forced: parseInt !== $parseInt }, {
15840
+ parseInt: $parseInt
15841
+ });
15842
+
15843
+ const ADD_DATA_ACTION = 'jsonforms/register/add_data_action';
15844
+ const SET_DATA_ACTION = 'jsonforms/register/set_data_action';
15845
+ const INCREMENT_ACTION = 'jsonforms/register/increment_action';
15846
+ const DELETE_ACTION = 'jsonforms/register/delete_action';
15847
+ const initialState = {
15848
+ categories: {}
15849
+ };
15850
+
15851
+ function objectListReducer(state, action) {
15852
+ switch (action.type) {
15853
+ case ADD_DATA_ACTION:
15854
+ {
15855
+ //ok so we're assuming we're already getting the updated category data
15856
+ const {
15857
+ categories
15858
+ } = state;
15859
+ const {
15860
+ name,
15861
+ category
15862
+ } = action.payload;
15863
+ const newCategories = Object.assign({}, categories);
15864
+ if (!newCategories[name]) {
15865
+ newCategories[name] = {
15866
+ data: category
15867
+ };
15868
+ } else {
15869
+ newCategories[name].data = category;
15870
+ }
15871
+ return Object.assign({}, state, {
15872
+ categories: newCategories
15873
+ });
15874
+ }
15875
+ case SET_DATA_ACTION:
15876
+ {
15877
+ const CategoriesStateData = action.payload;
15878
+ return Object.assign({}, state, {
15879
+ categories: CategoriesStateData
15880
+ });
15881
+ }
15882
+ case INCREMENT_ACTION:
15883
+ {
15884
+ const {
15885
+ categories
15886
+ } = state;
15887
+ const name = action.payload;
15888
+ const newCategories = Object.assign({}, categories);
15889
+ // Assuming you want to increment the count of a category:
15890
+ if (newCategories[name]) {
15891
+ const updatedCategory = Object.assign({}, categories[name], {
15892
+ count: (categories[name].count || 0) + 1
15893
+ });
15894
+ return Object.assign({}, state, {
15895
+ categories: Object.assign({}, categories, {
15896
+ [name]: updatedCategory
15897
+ })
15898
+ });
15899
+ } else {
15900
+ newCategories[name] = {
15901
+ count: 1,
15902
+ data: {}
15903
+ };
15904
+ }
15905
+ return Object.assign({}, state, {
15906
+ categories: newCategories
15907
+ });
15908
+ }
15909
+ case DELETE_ACTION:
15910
+ {
15911
+ const {
15912
+ name,
15913
+ category
15914
+ } = action.payload;
15915
+ const {
15916
+ categories
15917
+ } = state;
15918
+ const newCategories = Object.assign({}, categories);
15919
+ newCategories[name] = category;
15920
+ return Object.assign({}, state, {
15921
+ categories: newCategories
15922
+ });
15923
+ }
15924
+ default:
15925
+ return state;
15985
15926
  }
15986
- const appliedUiSchemaOptions = merge({}, config, uischema.options);
15987
- const childPath = path;
15988
- return jsx(NonEmptyList, {
15989
- childPath: childPath,
15990
- rowIndex: 0,
15991
- schema: schema,
15992
- openDeleteDialog: openDeleteDialog,
15993
- showSortButtons: appliedUiSchemaOptions.showSortButtons || appliedUiSchemaOptions.showArrayTableSortButtons,
15994
- enabled: enabled,
15995
- handleChange: handleChange,
15996
- cells: cells,
15997
- path: path,
15998
- uischema: uischema,
15999
- translations: translations,
16000
- isInReview: isInReview,
16001
- count: count,
16002
- data: data
16003
- }, 0);
16004
- };
16005
- const ObjectArrayControl = props => {
16006
- var _registers$categories, _registers$categories2, _registers$categories3, _registers$categories4, _uischema$options6;
16007
- const [registers, dispatch] = useReducer(objectListReducer, initialState);
16008
- const [open, setOpen] = useState(false);
16009
- const [rowData, setRowData] = useState(0);
16010
- const [maxItemsError, setMaxItemsError] = useState('');
16011
- const reportChange = useReviewChange();
16012
- const showChangeButtons = useShowChangeButtons();
16013
- const {
16014
- label,
16015
- path,
15927
+ }
15928
+
15929
+ const DeleteDialog = /*#__PURE__*/React.memo(function DeleteDialog({
15930
+ open,
15931
+ onConfirm,
15932
+ onCancel,
15933
+ title,
15934
+ message
15935
+ }) {
15936
+ useEffect(() => {
15937
+ if (open) {
15938
+ const deleteBtn = document.querySelector('[data-testId="object-array-confirm-button"]');
15939
+ if (deleteBtn) {
15940
+ setTimeout(() => {
15941
+ var _deleteBtn$shadowRoot;
15942
+ (_deleteBtn$shadowRoot = deleteBtn.shadowRoot) == null || (_deleteBtn$shadowRoot = _deleteBtn$shadowRoot.querySelector('button')) == null || _deleteBtn$shadowRoot.focus();
15943
+ }, 200);
15944
+ }
15945
+ }
15946
+ }, [open]);
15947
+ return jsxs(GoabModal, {
15948
+ open: open,
15949
+ testId: "object-array-modal",
15950
+ heading: title,
15951
+ children: [jsx(DeleteDialogContent, {
15952
+ "data-testid": "object-array-modal-content",
15953
+ children: `${message}?`
15954
+ }), jsxs(GoabButtonGroup, {
15955
+ alignment: "end",
15956
+ children: [jsx(GoabButton, {
15957
+ type: "secondary",
15958
+ testId: "object-array-modal-button",
15959
+ onClick: () => {
15960
+ onCancel();
15961
+ },
15962
+ children: "Cancel"
15963
+ }), jsx(GoabButton, {
15964
+ type: "primary",
15965
+ variant: "destructive",
15966
+ testId: "object-array-confirm-button",
15967
+ onClick: () => {
15968
+ onConfirm();
15969
+ },
15970
+ children: "Delete"
15971
+ })]
15972
+ })]
15973
+ }, 1);
15974
+ });
15975
+
15976
+ const _excluded$3 = ["label", "path", "schema", "rootSchema", "uischema", "errors", "visible", "enabled", "cells", "data", "config", "isStepperReview", "handleChange", "removeItems"];
15977
+ const GenerateRows = (Cell, schema, rowPath, enabled, openDeleteDialog, handleChange, cells, uischema, isInReview, count, data, errors) => {
15978
+ if ((schema == null ? void 0 : schema.type) === 'object') {
15979
+ const props = {
16016
15980
  schema,
16017
- rootSchema,
16018
- uischema,
16019
- errors,
16020
- visible,
15981
+ rowPath,
16021
15982
  enabled,
16022
15983
  cells,
15984
+ uischema,
15985
+ isInReview,
15986
+ openDeleteDialog,
16023
15987
  data,
16024
- config,
16025
- isStepperReview
16026
- } = props,
16027
- additionalProps = _objectWithoutPropertiesLoose(props, _excluded$4);
16028
- const parsedData = Array.isArray(data) ? data : [];
16029
- const hasDataRows = parsedData.length > 0;
16030
- const latestData = hasDataRows ? Object.fromEntries(parsedData.map((item, index) => [String(index), item])) : (_registers$categories = (_registers$categories2 = registers.categories[path]) == null ? void 0 : _registers$categories2.data) != null ? _registers$categories : {};
16031
- const latestCount = hasDataRows ? parsedData.length : (_registers$categories3 = (_registers$categories4 = registers.categories[path]) == null ? void 0 : _registers$categories4.count) != null ? _registers$categories3 : Object.keys(latestData).length;
16032
- const openDeleteDialog = useCallback((rowIndex, name) => {
16033
- setOpen(true);
16034
- setRowData(rowIndex);
16035
- }, [setOpen, setRowData]);
16036
- const deleteCancel = useCallback(() => setOpen(false), [setOpen]);
16037
- const deleteConfirm = () => {
16038
- if (deleteItem && path) {
16039
- deleteItem(path, rowData);
16040
- }
16041
- setOpen(false);
16042
- };
16043
- // eslint-disable-next-line
16044
- const addItem = (path, value) => {
16045
- var _uischema$options4, _uischema$options5;
16046
- const maxItems = (_uischema$options4 = uischema.options) != null && (_uischema$options4 = _uischema$options4.detail) != null && _uischema$options4.maxItems ? (_uischema$options5 = uischema.options) == null || (_uischema$options5 = _uischema$options5.detail) == null ? void 0 : _uischema$options5.maxItems : DEFAULT_MAX_ITEMS;
16047
- if (latestCount < maxItems) {
16048
- return () => {
16049
- const currentRows = hasDataRows ? parsedData : Object.keys(latestData).sort((a, b) => Number(a) - Number(b)).map(key => latestData[key]);
16050
- const nextData = [...currentRows, value];
16051
- const categoryData = Object.fromEntries(nextData.map((item, index) => [String(index), item]));
16052
- props.handleChange(path, nextData);
16053
- dispatch({
16054
- type: SET_DATA_ACTION,
16055
- payload: Object.assign({}, registers.categories, {
16056
- [path]: {
16057
- count: nextData.length,
16058
- data: categoryData
16059
- }
16060
- })
16061
- });
16062
- };
16063
- } else {
16064
- setMaxItemsError(`Maximum ${maxItems} items allowed.`);
16065
- setTimeout(() => {
16066
- setMaxItemsError('');
16067
- }, 3000);
16068
- }
16069
- };
16070
- // eslint-disable-next-line
16071
- const deleteItem = (path, value) => {
16072
- const categories = registers.categories;
16073
- const currentCategory = categories[path];
16074
- const newCategoryData = {};
16075
- if (currentCategory != null && currentCategory.data) {
16076
- delete currentCategory.data[value];
16077
- Object.keys(currentCategory.data).forEach((key, index) => {
16078
- newCategoryData[index] = currentCategory.data[key];
16079
- });
16080
- currentCategory.data = newCategoryData;
16081
- }
16082
- if (currentCategory != null && currentCategory.count && (currentCategory == null ? void 0 : currentCategory.count) > 0) currentCategory.count--;
16083
- let handleChangeData = Object.keys(newCategoryData).map(key => {
16084
- return newCategoryData[key];
15988
+ handleChange,
15989
+ errors
15990
+ };
15991
+ return jsx(ListWithDetailsReviewCellDiv, {
15992
+ children: jsx(Cell, Object.assign({}, props, {
15993
+ count: count || 0
15994
+ }))
16085
15995
  });
16086
- if (handleChangeData.length === 0) {
16087
- handleChangeData = null;
16088
- }
16089
- setMaxItemsError('');
16090
- props.handleChange(path, handleChangeData);
16091
- dispatch({
16092
- type: DELETE_ACTION,
16093
- payload: {
16094
- name: path,
16095
- category: currentCategory
16096
- }
15996
+ } else {
15997
+ const props = {
15998
+ schema,
15999
+ rowPath,
16000
+ cellPath: rowPath,
16001
+ enabled,
16002
+ uischema,
16003
+ isInReview,
16004
+ openDeleteDialog,
16005
+ handleChange,
16006
+ data
16007
+ };
16008
+ return jsx(ListWithDetailsReviewCellDiv, {
16009
+ children: jsx(Cell, Object.assign({}, props, {
16010
+ count: count || 0
16011
+ }), rowPath)
16097
16012
  });
16013
+ }
16014
+ };
16015
+ const getValidColumnProps = scopedSchema => {
16016
+ if (scopedSchema.type === 'object' && typeof scopedSchema.properties === 'object') {
16017
+ return Object.keys(scopedSchema.properties);
16018
+ }
16019
+ // primitives
16020
+ return [''];
16021
+ };
16022
+ const EmptyList = ({
16023
+ numColumns,
16024
+ noDataMessage,
16025
+ translations
16026
+ }) => jsx("div", {
16027
+ style: {
16028
+ width: '100%',
16029
+ padding: '1rem 0'
16030
+ },
16031
+ children: jsx(TextCenter, {
16032
+ children: jsx("b", {
16033
+ children: noDataMessage
16034
+ })
16035
+ })
16036
+ });
16037
+ const ctxToNonEmptyCellProps = (ctx, ownProps) => {
16038
+ var _ctx$core, _ctx$core2;
16039
+ return {
16040
+ uischema: ownProps.uischema,
16041
+ rowPath: ownProps.rowPath,
16042
+ schema: ownProps.schema,
16043
+ rootSchema: (_ctx$core = ctx.core) == null ? void 0 : _ctx$core.schema,
16044
+ errors: ((_ctx$core2 = ctx.core) == null ? void 0 : _ctx$core2.errors) || undefined,
16045
+ enabled: ownProps.enabled,
16046
+ cells: ownProps.cells || ctx.cells,
16047
+ renderers: ownProps.renderers || ctx.renderers,
16048
+ handleChange: ownProps.handleChange
16098
16049
  };
16099
- //eslint-disable-next-line
16100
- const handleChangeWithData = (path, value) => {
16101
- if (path) {
16102
- var _categories$path;
16103
- const categories = registers.categories;
16104
- const currentCategory = ((_categories$path = categories[path]) == null ? void 0 : _categories$path.data) || {};
16105
- const newData = {};
16106
- const allKeys = Object.keys(value).concat(Object.keys(currentCategory || []));
16107
- const allKeysUnique = allKeys.filter((a, b) => allKeys.indexOf(a) === b);
16108
- Object.keys(allKeysUnique).forEach(num => {
16109
- if (!newData[num]) {
16110
- newData[num] = {};
16111
- }
16112
- currentCategory[num] && Object.keys(currentCategory[num]).forEach(path => {
16113
- newData[num][path] = currentCategory[num][path];
16114
- });
16115
- value[num] && Object.keys(value[num]).forEach(path => {
16116
- newData[num][path] = value[num][path] !== undefined ? value[num][path] : currentCategory[num] && currentCategory[num][path];
16117
- });
16118
- });
16119
- const handleChangeData = Object.keys(newData).map(key => {
16120
- return newData[key];
16121
- });
16122
- props.handleChange(path, JSON.parse(JSON.stringify(handleChangeData)));
16123
- dispatch({
16124
- type: ADD_DATA_ACTION,
16125
- payload: {
16126
- name: path,
16127
- category: newData
16128
- }
16129
- });
16130
- }
16131
- };
16132
- useEffect(() => {
16133
- var _currentCategory$coun;
16134
- const updatedData = Object.fromEntries((parsedData || []).map((item, index) => [index, item]));
16135
- const count = Object.keys(updatedData).length;
16136
- const currentCategory = registers.categories[path];
16137
- if (Array.isArray(data) && data.length === 0 && ((_currentCategory$coun = currentCategory == null ? void 0 : currentCategory.count) != null ? _currentCategory$coun : 0) > 0) {
16138
- return;
16139
- }
16140
- const hasSameCount = (currentCategory == null ? void 0 : currentCategory.count) === count;
16141
- const hasSameData = JSON.stringify((currentCategory == null ? void 0 : currentCategory.data) || {}) === JSON.stringify(updatedData);
16142
- if (hasSameCount && hasSameData) {
16143
- return;
16144
- }
16145
- const dispatchData = Object.assign({}, registers.categories, {
16146
- [path]: {
16147
- count: count,
16148
- data: updatedData
16149
- }
16050
+ };
16051
+ const NonEmptyCellComponent = /*#__PURE__*/React.memo(function NonEmptyCellComponent(props) {
16052
+ var _schema$properties, _uischema$options, _uischema$options2, _errors$filter, _uischema$elements;
16053
+ const {
16054
+ schema,
16055
+ enabled,
16056
+ renderers,
16057
+ cells,
16058
+ rowPath,
16059
+ uischema,
16060
+ isInReview,
16061
+ data,
16062
+ count,
16063
+ openDeleteDialog,
16064
+ handleChange,
16065
+ errors
16066
+ } = props;
16067
+ const {
16068
+ noAnswerMessage
16069
+ } = useStepperPageOptions();
16070
+ const element = (schema == null ? void 0 : schema.items) || (schema == null || (_schema$properties = schema.properties) == null || (_schema$properties = _schema$properties[rowPath]) == null ? void 0 : _schema$properties.items) || schema;
16071
+ const required = (element == null ? void 0 : element.required) || [];
16072
+ const properties = element == null ? void 0 : element.properties;
16073
+ let tableKeys = extractNames(uischema == null || (_uischema$options = uischema.options) == null ? void 0 : _uischema$options.detail);
16074
+ if (Object.keys(tableKeys).length === 0) {
16075
+ properties && Object.keys(properties).forEach(item => {
16076
+ tableKeys[item] = item;
16150
16077
  });
16151
- dispatch({
16152
- type: SET_DATA_ACTION,
16153
- payload: dispatchData
16078
+ }
16079
+ if (properties && Object.keys(properties).length !== Object.keys(tableKeys).length) {
16080
+ const tempTableKeys = {};
16081
+ //For nested objects to display only the top level column.
16082
+ properties && Object.keys(properties).forEach(item => {
16083
+ if (Object.keys(tableKeys).includes(item)) {
16084
+ tempTableKeys[item] = tableKeys[item];
16085
+ } else {
16086
+ // If the property is not in the tableKeys (e.g. it was a nested object in the UI schema),
16087
+ // we still need a header for it to maintain alignment.
16088
+ // Use the property title from the schema, or capitalize the property name.
16089
+ tempTableKeys[item] = properties[item].title || capitalizeFirstLetter(item);
16090
+ }
16154
16091
  });
16155
- }, [parsedData, path]);
16156
- const controlElement = uischema;
16157
- const listTitle = label || ((_uischema$options6 = uischema.options) == null ? void 0 : _uischema$options6.title);
16158
- const isInReview = isStepperReview === true;
16159
- const isListWithDetail = controlElement.type === 'ListWithDetail';
16160
- if (isInReview) {
16161
- var _uischema$options7, _uischema$options8;
16162
- return jsx("tr", {
16163
- children: jsxs(PageReviewContainer, {
16164
- colSpan: 3,
16165
- children: [listTitle ? isListWithDetail && additionalProps.required && (data === null || data === undefined) ? jsx("b", {
16166
- children: jsxs(ListWithDetailWarningIconDiv, {
16167
- children: [jsx(GoabIcon, {
16168
- type: "warning",
16169
- title: "warning",
16170
- size: "small",
16171
- theme: "filled",
16172
- ml: "2xs",
16173
- mt: "2xs"
16174
- }), listTitle, " is required."]
16175
- })
16176
- }) : jsxs(ReviewHeader, {
16177
- style: {
16178
- width: '100%',
16179
- display: 'grid',
16180
- gridTemplateColumns: '1fr auto',
16181
- alignItems: 'center'
16182
- },
16183
- children: [jsxs(ReviewLabel, {
16184
- children: [listTitle, jsx("span", {
16185
- children: additionalProps.required && '(required)'
16186
- }), maxItemsError && jsx("span", {
16187
- style: {
16188
- color: 'red',
16189
- marginLeft: '1rem'
16190
- },
16191
- children: maxItemsError
16192
- })]
16193
- }), showChangeButtons && ((_uischema$options7 = uischema.options) == null ? void 0 : _uischema$options7.stepId) !== undefined && !((_uischema$options8 = uischema.options) != null && (_uischema$options8 = _uischema$options8.componentProps) != null && _uischema$options8.readOnly) && jsx(BackButton, {
16194
- text: "Change",
16195
- link: () => {
16196
- var _uischema$options9;
16197
- return reportChange((_uischema$options9 = uischema.options) == null ? void 0 : _uischema$options9.stepId, uischema.scope);
16198
- },
16199
- showBackIcon: false
16092
+ tableKeys = tempTableKeys;
16093
+ }
16094
+ // Review only shows properties that have a control in the detail UI schema.
16095
+ const detailProperties = extractScopedProperties(uischema == null || (_uischema$options2 = uischema.options) == null ? void 0 : _uischema$options2.detail);
16096
+ const reviewKeys = detailProperties.size > 0 ? Object.fromEntries(Object.entries(tableKeys).filter(([key]) => detailProperties.has(key))) : tableKeys;
16097
+ const hasAnyErrors = Array.isArray(errors) ? (errors == null || (_errors$filter = errors.filter(err => {
16098
+ return err.instancePath.includes(rowPath);
16099
+ })) == null ? void 0 : _errors$filter.length) > 0 : false;
16100
+ return jsxs(NonEmptyCellStyle, {
16101
+ "data-testid": `${rowPath}-ObjectListOuterWrapper`,
16102
+ children: [!isInReview && (uischema == null || (_uischema$elements = uischema.elements) == null ? void 0 : _uischema$elements.map(element => {
16103
+ return jsx(JsonFormsDispatch, {
16104
+ "data-testid": `jsonforms-object-list-defined-elements-dispatch`,
16105
+ schema: schema,
16106
+ uischema: element,
16107
+ path: rowPath,
16108
+ enabled: enabled,
16109
+ renderers: renderers,
16110
+ cells: cells
16111
+ }, rowPath);
16112
+ })), properties && Object.keys(properties).length > 0 && jsxs(Fragment, {
16113
+ children: [isInReview ? jsx("div", {
16114
+ style: {
16115
+ padding: '0.75rem 0'
16116
+ },
16117
+ "data-testid": `${rowPath}.objectListWrapper`,
16118
+ children: range(count || 0).map((i, key) => {
16119
+ const rowData = data && data[i];
16120
+ if (!rowData) return null;
16121
+ const hasAnyValue = Object.keys(reviewKeys).some(key => {
16122
+ const value = rowData[key];
16123
+ return value !== undefined && value !== null && value !== '';
16124
+ });
16125
+ const hasRowErrors = (errors || []).some(e => e.instancePath.includes(`/${props.rowPath.replace(/\./g, '/')}/${i}`));
16126
+ if (!hasAnyValue && !hasRowErrors) return null;
16127
+ return jsx(ReviewItemFrame, {
16128
+ "data-testid": `${rowPath}.objectList-${key}`,
16129
+ children: Object.entries(reviewKeys).map(([key, label]) => {
16130
+ var _required$includes, _properties$key;
16131
+ const value = rowData[key];
16132
+ const isRequiredField = (_required$includes = required == null ? void 0 : required.includes(key)) != null ? _required$includes : false;
16133
+ const fieldPath = `/${props.rowPath.replace(/\./g, '/')}/${i}/${key}`;
16134
+ const rowPathMatch = `/${props.rowPath.replace(/\./g, '/')}/${i}`;
16135
+ const fieldError = (errors || []).find(e => {
16136
+ var _msg$match;
16137
+ const msg = e.message || '';
16138
+ const requiredProperty = (_msg$match = msg.match(/'([^']+)'/)) == null ? void 0 : _msg$match[1];
16139
+ return e.instancePath === fieldPath || e.instancePath === rowPathMatch && msg.includes(key) || e.instancePath === rowPathMatch && requiredProperty === key;
16140
+ });
16141
+ const isEmptyValue = value === undefined || value === null || value === '';
16142
+ let reviewError = '';
16143
+ if (fieldError) {
16144
+ const raw = fieldError.message || '';
16145
+ reviewError = raw.includes('required') ? `${capitalizeFirstLetter(label.replace(/[_-]/g, ' '))} is required` : raw;
16146
+ } else if (isRequiredField && isEmptyValue) {
16147
+ reviewError = `${capitalizeFirstLetter(label.replace(/[_-]/g, ' '))} is required`;
16148
+ }
16149
+ return jsxs(ReviewRow, {
16150
+ "data-testid": `#/properties/${key}-input-${i}-row`,
16151
+ children: [jsxs(ReviewRowLabel, {
16152
+ children: [(properties == null || (_properties$key = properties[key]) == null ? void 0 : _properties$key.title) || (label !== key ? label : key.replace(/([A-Z])/g, ' $1').replace(/[_-]/g, ' ').replace(/^./, c => c.toUpperCase())), isRequiredField && jsx(RequiredSpan, {
16153
+ children: " (required)"
16154
+ }), " :"]
16155
+ }), jsx(ReviewRowValue, {
16156
+ "data-testid": `#/properties/${key}-input-${i}-review`,
16157
+ children: renderCellColumn({
16158
+ data: isEmptyValue ? undefined : value,
16159
+ error: reviewError,
16160
+ isRequired: isRequiredField,
16161
+ errors: errors !== undefined ? errors : [],
16162
+ element: key,
16163
+ rowPath,
16164
+ index: i,
16165
+ noAnswerMessage: noAnswerMessage != null ? noAnswerMessage : NO_ANSWER_MESSAGE
16166
+ })
16167
+ })]
16168
+ }, key);
16169
+ })
16170
+ }, i);
16171
+ })
16172
+ }) : jsx(FixTableHeaderAlignment, {
16173
+ children: jsxs(GoabTable, {
16174
+ width: "100%",
16175
+ children: [jsx("thead", {
16176
+ children: jsxs("tr", {
16177
+ children: [Object.entries(tableKeys).map(([value, index]) => {
16178
+ const currentProperty = properties[value];
16179
+ return jsx("th", {
16180
+ children: jsxs("p", {
16181
+ children: [(currentProperty == null ? void 0 : currentProperty.title) || index, ' ', (required == null ? void 0 : required.includes(value)) && jsx(RequiredSpan, {
16182
+ children: "(required)"
16183
+ })]
16184
+ })
16185
+ }, index);
16186
+ }), jsx("th", {
16187
+ children: jsx("p", {
16188
+ children: "Actions"
16189
+ })
16190
+ })]
16191
+ }, 0)
16192
+ }), jsx("tbody", {
16193
+ children: range(count || 0).map((num, i) => {
16194
+ const errorRow = errors == null ? void 0 : errors.find(error => error.instancePath.includes(`/${props.rowPath.replace(/\./g, '/')}/${i}`));
16195
+ return jsxs("tr", {
16196
+ children: [Object.keys(properties).map((element, ix) => {
16197
+ var _error$message;
16198
+ const dataObject = properties[element];
16199
+ const schemaName = element;
16200
+ const currentData = data && data[num] ? data[num][element] : '';
16201
+ //Get out of the loop to not render extra blank columns at the end of the table
16202
+ if (ix > 1 && Object.keys(tableKeys).length === ix) return null;
16203
+ const error = (errors == null ? void 0 : errors.filter(e => e.instancePath === `/${props.rowPath.replace(/\./g, '/')}/${i}/${element}` || e.instancePath === `/${props.rowPath.replace(/\./g, '/')}/${i}`)).find(y => {
16204
+ var _y$message;
16205
+ return (y == null || (_y$message = y.message) == null ? void 0 : _y$message.includes(element)) || y.instancePath.includes(element);
16206
+ });
16207
+ // Create a human-friendly error message for rendering
16208
+ let humanMessage = createHumanizeError(error, schema, uischema);
16209
+ if (error != null && (_error$message = error.message) != null && _error$message.includes('must NOT have fewer') && required.find(r => r === schemaName) && (isEmptyBoolean(schema, currentData) || isEmptyNumber(schema, currentData))) {
16210
+ humanMessage = `${capitalizeFirstLetter(schemaName)} is required`;
16211
+ }
16212
+ return jsx("td", {
16213
+ children: jsx(GoabFormItem, {
16214
+ error: humanMessage != null ? humanMessage : '',
16215
+ mb: errorRow && !error && '2xl' || 'xs',
16216
+ children: dataObject.enum ? jsxs(GoabDropdown, {
16217
+ id: schemaName,
16218
+ name: schemaName,
16219
+ value: currentData != null ? String(currentData) : '',
16220
+ testId: `#/properties/${schemaName}-select-${i}`,
16221
+ onChange: detail => {
16222
+ const selectedValue = Array.isArray(detail.value) ? detail.value[0] : detail.value;
16223
+ const coerced = dataObject.type === 'number' && selectedValue !== '' ? Number(selectedValue) : selectedValue;
16224
+ handleChange(rowPath, {
16225
+ [num]: {
16226
+ [schemaName]: coerced
16227
+ }
16228
+ });
16229
+ },
16230
+ width: "100%",
16231
+ ariaLabel: schemaName,
16232
+ error: !!humanMessage,
16233
+ children: [!(required != null && required.includes(schemaName)) && jsx(GoabDropdownItem, {
16234
+ value: "",
16235
+ label: `-- Select ${schemaName} --`
16236
+ }), dataObject.enum.map(opt => jsx(GoabDropdownItem, {
16237
+ value: String(opt),
16238
+ label: String(opt)
16239
+ }, String(opt)))]
16240
+ }) : dataObject.type === 'number' || dataObject.type === 'string' && !dataObject.enum ? jsx(GoabInput, {
16241
+ error: humanMessage ? humanMessage.length > 0 : false,
16242
+ type: dataObject.type === 'number' ? 'number' : 'text',
16243
+ id: schemaName,
16244
+ name: schemaName,
16245
+ value: currentData,
16246
+ testId: `#/properties/${schemaName}-input-${i}`,
16247
+ onChange: detail => {
16248
+ handleChange(rowPath, {
16249
+ [num]: {
16250
+ [detail.name]: dataObject.type === 'number' ? parseInt(detail.value) : detail.value
16251
+ }
16252
+ });
16253
+ },
16254
+ ariaLabel: schemaName,
16255
+ width: "100%"
16256
+ }) : jsx(GoabCallout, {
16257
+ type: "important",
16258
+ size: "medium",
16259
+ testId: "form-support-callout",
16260
+ heading: "Not supported",
16261
+ children: "Only string, number, and enum are supported inside arrays"
16262
+ })
16263
+ })
16264
+ }, ix);
16265
+ }), !isInReview && jsx("td", {
16266
+ style: {
16267
+ alignContent: 'baseLine',
16268
+ paddingTop: '18px'
16269
+ },
16270
+ children: jsx("div", {
16271
+ children: jsx(GoabIconButton, {
16272
+ icon: "trash",
16273
+ title: "trash button",
16274
+ testId: "trash-icon-button",
16275
+ "aria-label": `remove-element-${num}`,
16276
+ onClick: () => openDeleteDialog(num)
16277
+ })
16278
+ })
16279
+ })]
16280
+ }, `${rowPath}-${i}-${num}`);
16281
+ })
16200
16282
  })]
16201
- }) : null, jsx(ObjectArrayList, Object.assign({
16202
- path: path,
16203
- schema: schema,
16204
- uischema: uischema,
16205
- enabled: enabled,
16206
- openDeleteDialog: openDeleteDialog,
16207
- translations: {},
16208
- count: latestCount,
16209
- data: latestData,
16210
- cells: cells,
16211
- config: config,
16212
- isInReview: isInReview,
16213
- handleChange: handleChangeWithData
16214
- }, additionalProps))]
16215
- })
16216
- });
16217
- }
16218
- const content = jsxs(Visible, {
16219
- "$visible": visible,
16220
- "data-testid": "jsonforms-object-list-wrapper",
16221
- children: [jsxs(ToolBarHeader, {
16222
- children: [listTitle && jsxs(ObjectArrayTitle, {
16223
- children: [listTitle, additionalProps.required && jsx(RequiredSpan, {
16224
- children: "(required)"
16225
- }), maxItemsError && jsx("span", {
16226
- style: {
16227
- color: 'red',
16228
- marginLeft: '1rem'
16229
- },
16230
- children: maxItemsError
16231
- })]
16232
- }), jsx(ObjectArrayToolBar, {
16233
- errors: errors,
16234
- label: label,
16235
- addItem: addItem,
16236
- numColumns: 0,
16237
- path: path,
16238
- uischema: controlElement,
16239
- schema: schema,
16240
- rootSchema: rootSchema,
16241
- enabled: enabled
16242
- })]
16243
- }), jsxs("div", {
16244
- children: [jsx(ObjectArrayList, Object.assign({
16245
- path: path,
16246
- schema: schema,
16247
- uischema: uischema,
16248
- enabled: enabled,
16249
- openDeleteDialog: openDeleteDialog,
16250
- translations: {},
16251
- count: latestCount,
16252
- data: latestData,
16253
- cells: cells,
16254
- config: config,
16255
- isInReview: isInReview,
16256
- handleChange: handleChangeWithData
16257
- }, additionalProps)), jsx(DeleteDialog, {
16258
- open: open,
16259
- onCancel: deleteCancel,
16260
- onConfirm: deleteConfirm,
16261
- title: 'Remove item',
16262
- message: 'Are you sure you wish to remove the selected item'
16283
+ })
16284
+ }), hasAnyErrors && isInReview && jsx(GoabFormItem, {
16285
+ error: `There are validation errors for '${capitalizeFirstLetter(rowPath)}'`
16263
16286
  })]
16264
16287
  })]
16265
16288
  });
16266
- return content;
16267
- };
16268
-
16269
- let _$1 = t => t,
16270
- _t$2;
16271
- const GoAContextMenuIcon = props => {
16272
- return jsx(GoabIconButton, {
16273
- icon: props.type,
16274
- onClick: props.onClick,
16275
- title: props.title,
16276
- testId: props.testId,
16277
- size: "small",
16278
- disabled: props.disabled
16279
- });
16289
+ });
16290
+ const NonEmptyCell = ownProps => {
16291
+ const data = ownProps.data || {};
16292
+ const ctx = useJsonForms();
16293
+ const emptyCellProps = ctxToNonEmptyCellProps(ctx, Object.assign({}, ownProps, {
16294
+ data
16295
+ }));
16296
+ const isValid = isEmpty$1(emptyCellProps.errors);
16297
+ return jsx(NonEmptyCellComponent, Object.assign({}, emptyCellProps, {
16298
+ handleChange: ownProps == null ? void 0 : ownProps.handleChange,
16299
+ isInReview: ownProps == null ? void 0 : ownProps.isInReview,
16300
+ isValid: isValid,
16301
+ openDeleteDialog: ownProps == null ? void 0 : ownProps.openDeleteDialog,
16302
+ data: data,
16303
+ count: ownProps == null ? void 0 : ownProps.count
16304
+ }));
16280
16305
  };
16281
- const GoAContextMenu = styled.div(_t$2 || (_t$2 = _$1`
16282
- display: flex;
16283
- align-items: center;
16284
- background-color: #fff;
16285
- gap: var(--goa-space-2xs);
16286
-
16287
- > .goa-icon-button {
16288
- cursor: pointer;
16289
- border-radius: var(--goa-border-radius-m);
16290
- padding: var(--goa-space-2xs);
16291
- }
16292
- > .goa-icon-button + .goa-icon-button {
16293
- margin-left: var(--goa-space-none);
16294
- }
16295
- `));
16296
-
16297
- const DeleteFileModal = ({
16298
- isOpen,
16299
- title,
16300
- content,
16301
- onDelete,
16302
- onCancel
16306
+ const NonEmptyRowComponent = ({
16307
+ childPath,
16308
+ schema,
16309
+ openDeleteDialog,
16310
+ enabled,
16311
+ cells,
16312
+ uischema,
16313
+ isInReview,
16314
+ data,
16315
+ count,
16316
+ handleChange
16303
16317
  }) => {
16304
- return jsx(GoabModal, {
16305
- testId: "delete-confirmation",
16306
- open: isOpen,
16307
- heading: title,
16308
- maxWidth: "640px",
16309
- actions: jsxs(GoabButtonGroup, {
16310
- alignment: "end",
16311
- children: [jsx(GoabButton, {
16312
- type: "secondary",
16313
- testId: "delete-cancel",
16314
- onClick: onCancel,
16315
- children: "Cancel"
16316
- }), jsx(GoabButton, {
16317
- type: "primary",
16318
- variant: "destructive",
16319
- testId: "delete-confirm",
16320
- onClick: onDelete,
16321
- children: "Delete"
16322
- })]
16323
- }),
16324
- children: content
16325
- });
16318
+ return jsx("div", {
16319
+ children: enabled ? isInReview ? jsx("div", {
16320
+ children: jsx("div", {
16321
+ children: GenerateRows(NonEmptyCell, schema, childPath, enabled, openDeleteDialog, handleChange, cells, uischema, isInReview, count, data)
16322
+ })
16323
+ }) : jsx(GoabContainer, {
16324
+ children: jsx("div", {
16325
+ children: jsx("div", {
16326
+ children: GenerateRows(NonEmptyCell, schema, childPath, enabled, openDeleteDialog, handleChange, cells, uischema, isInReview, count, data)
16327
+ })
16328
+ })
16329
+ }) : null
16330
+ }, childPath);
16326
16331
  };
16327
-
16328
- let _2 = t => t,
16329
- _t$1,
16330
- _t2$1,
16331
- _t3,
16332
- _t4;
16333
- const _excluded$3 = ["data", "path", "handleChange", "uischema"];
16334
- const FileUploaderReview = props => {
16335
- return FileUploader(Object.assign({}, props, {
16336
- isStepperReview: true
16337
- }));
16332
+ const NonEmptyList = /*#__PURE__*/React.memo(NonEmptyRowComponent);
16333
+ const ObjectArrayList = ({
16334
+ data,
16335
+ path,
16336
+ schema,
16337
+ openDeleteDialog,
16338
+ uischema,
16339
+ config,
16340
+ enabled,
16341
+ cells,
16342
+ translations,
16343
+ count,
16344
+ isInReview,
16345
+ handleChange
16346
+ }) => {
16347
+ const isEmptyList = count === 0;
16348
+ if (isEmptyList) {
16349
+ var _uischema$options$noD, _uischema$options3;
16350
+ const noDataMessage = (_uischema$options$noD = (_uischema$options3 = uischema.options) == null ? void 0 : _uischema$options3.noDataMessage) != null ? _uischema$options$noD : 'No data';
16351
+ return jsx(EmptyList, {
16352
+ noDataMessage: noDataMessage,
16353
+ numColumns: getValidColumnProps(schema).length + 1,
16354
+ translations: translations
16355
+ });
16356
+ }
16357
+ const appliedUiSchemaOptions = merge({}, config, uischema.options);
16358
+ const childPath = path;
16359
+ return jsx(NonEmptyList, {
16360
+ childPath: childPath,
16361
+ rowIndex: 0,
16362
+ schema: schema,
16363
+ openDeleteDialog: openDeleteDialog,
16364
+ showSortButtons: appliedUiSchemaOptions.showSortButtons || appliedUiSchemaOptions.showArrayTableSortButtons,
16365
+ enabled: enabled,
16366
+ handleChange: handleChange,
16367
+ cells: cells,
16368
+ path: path,
16369
+ uischema: uischema,
16370
+ translations: translations,
16371
+ isInReview: isInReview,
16372
+ count: count,
16373
+ data: data
16374
+ }, 0);
16338
16375
  };
16339
- const FileUploader = _ref => {
16340
- var _enumerators$function, _enumerators$function2, _enumerators$function3, _uischema$options, _uischema$options2, _uischema$options3, _uischema$options4, _props$schema, _uischema$options$com, _uischema$options5, _uischema$options6, _uischema$options$com2, _uischema$options7, _uischema$options$com3, _uischema$options8, _uischema$options9;
16341
- let {
16342
- data,
16343
- path,
16344
- handleChange,
16345
- uischema
16346
- } = _ref,
16347
- props = _objectWithoutPropertiesLoose(_ref, _excluded$3);
16348
- const enumerators = useContext(JsonFormContext);
16349
- const uploadTriggerFunction = enumerators == null || (_enumerators$function = enumerators.functions) == null ? void 0 : _enumerators$function.get('upload-file');
16350
- const uploadTrigger = uploadTriggerFunction && uploadTriggerFunction();
16351
- const downloadTriggerFunction = enumerators == null || (_enumerators$function2 = enumerators.functions) == null ? void 0 : _enumerators$function2.get('download-file');
16352
- const downloadTrigger = downloadTriggerFunction && downloadTriggerFunction();
16353
- const deleteTriggerFunction = enumerators == null || (_enumerators$function3 = enumerators.functions) == null ? void 0 : _enumerators$function3.get('delete-file');
16354
- const deleteTrigger = deleteTriggerFunction && deleteTriggerFunction();
16355
- const fileListValue = enumerators == null ? void 0 : enumerators.data.get('file-list');
16356
- const [loadingFileName, setLoadingFileName] = useState(undefined);
16357
- const [uploadError, setUploadError] = useState(undefined);
16358
- const countries = ['Argentina', 'Brazil', 'Canada', 'Denmark', 'Egypt', 'France', 'Greece', 'India', 'Japan', 'Kenya'];
16359
- enumerators == null || enumerators.addFormContextData('countries', countries);
16360
- const user = enumerators == null ? void 0 : enumerators.getFormContextData('user');
16361
- // eslint-disable-next-line
16362
- const fileList = fileListValue && fileListValue();
16376
+ const ObjectArrayControl = props => {
16377
+ var _registers$categories, _registers$categories2, _registers$categories3, _registers$categories4, _uischema$options6;
16378
+ const [registers, dispatch] = useReducer(objectListReducer, initialState);
16379
+ const [open, setOpen] = useState(false);
16380
+ const [rowData, setRowData] = useState(0);
16381
+ const [maxItemsError, setMaxItemsError] = useState('');
16382
+ const reportChange = useReviewChange();
16383
+ const showChangeButtons = useShowChangeButtons();
16363
16384
  const {
16364
- required,
16365
- label,
16366
- i18nKeyPrefix,
16367
- visible
16368
- } = props;
16369
- const propertyId = i18nKeyPrefix;
16370
- const rootPath = typeof path === 'string' ? path.replace(/(\.\d+|\[\d+\])$/, '') : path;
16371
- const variant = (uischema == null || (_uischema$options = uischema.options) == null ? void 0 : _uischema$options.variant) || 'button';
16372
- const noDownloadButton = uischema == null || (_uischema$options2 = uischema.options) == null || (_uischema$options2 = _uischema$options2.format) == null ? void 0 : _uischema$options2.noDownloadButton;
16373
- const noDownloadButtonInReview = uischema == null || (_uischema$options3 = uischema.options) == null || (_uischema$options3 = _uischema$options3.format) == null || (_uischema$options3 = _uischema$options3.review) == null ? void 0 : _uischema$options3.noDownloadButton;
16374
- const noDeleteButton = uischema == null || (_uischema$options4 = uischema.options) == null || (_uischema$options4 = _uischema$options4.format) == null || (_uischema$options4 = _uischema$options4.review) == null ? void 0 : _uischema$options4.noDeleteButton;
16375
- const isArraySchema = (props == null || (_props$schema = props.schema) == null ? void 0 : _props$schema.type) === 'array' || Array.isArray(data);
16376
- const maxFiles = (_uischema$options$com = uischema == null || (_uischema$options5 = uischema.options) == null || (_uischema$options5 = _uischema$options5.componentProps) == null ? void 0 : _uischema$options5.maximum) != null ? _uischema$options$com : isArraySchema ? Number.MAX_SAFE_INTEGER : 1;
16377
- const isMultiFile = maxFiles > 1 || isArraySchema;
16378
- const metadataKey = path;
16379
- const [deleteHide, setDeleteHide] = useState(false);
16380
- const [deleteConfirmIndex, setDeleteConfirmIndex] = useState(null);
16381
- const pendingUploadIndexRef = useRef(null);
16382
- const uploadQueueRef = useRef(Promise.resolve());
16383
- const filesForDisplay = useMemo(() => {
16384
- if (!fileList) return [];
16385
- if (isMultiFile) {
16386
- const files = fileList[metadataKey] || fileList[rootPath] || fileList[propertyId] || [];
16387
- const dataUrns = Array.isArray(data) ? data : data ? [data] : [];
16388
- if (dataUrns.length > 0) {
16389
- const urnSet = new Set(dataUrns);
16390
- const scopedFiles = files.filter(f => urnSet.has(f.urn));
16391
- if (scopedFiles.length > 0) {
16392
- return scopedFiles.filter((file, index, all) => all.findIndex(f => f.urn === file.urn) === index);
16393
- }
16394
- const allFiles = Object.values(fileList).flat();
16395
- const filesByUrn = dataUrns.map(urn => allFiles.find(f => (f == null ? void 0 : f.urn) === urn)).filter(f => !!f);
16396
- if (filesByUrn.length > 0) {
16397
- return filesByUrn.filter((file, index, all) => all.findIndex(f => f.urn === file.urn) === index);
16398
- }
16399
- }
16400
- // Keep a stable list even if upstream metadata briefly duplicates entries.
16401
- return files.filter((file, index, all) => all.findIndex(f => f.urn === file.urn) === index);
16385
+ label,
16386
+ path,
16387
+ schema,
16388
+ rootSchema,
16389
+ uischema,
16390
+ errors,
16391
+ visible,
16392
+ enabled,
16393
+ cells,
16394
+ data,
16395
+ config,
16396
+ isStepperReview
16397
+ } = props,
16398
+ additionalProps = _objectWithoutPropertiesLoose(props, _excluded$3);
16399
+ const parsedData = Array.isArray(data) ? data : [];
16400
+ const hasDataRows = parsedData.length > 0;
16401
+ const latestData = hasDataRows ? Object.fromEntries(parsedData.map((item, index) => [String(index), item])) : (_registers$categories = (_registers$categories2 = registers.categories[path]) == null ? void 0 : _registers$categories2.data) != null ? _registers$categories : {};
16402
+ const latestCount = hasDataRows ? parsedData.length : (_registers$categories3 = (_registers$categories4 = registers.categories[path]) == null ? void 0 : _registers$categories4.count) != null ? _registers$categories3 : Object.keys(latestData).length;
16403
+ const openDeleteDialog = useCallback((rowIndex, name) => {
16404
+ setOpen(true);
16405
+ setRowData(rowIndex);
16406
+ }, [setOpen, setRowData]);
16407
+ const deleteCancel = useCallback(() => setOpen(false), [setOpen]);
16408
+ const deleteConfirm = () => {
16409
+ if (deleteItem && path) {
16410
+ deleteItem(path, rowData);
16402
16411
  }
16403
- return fileList[metadataKey] || fileList[propertyId] || [];
16404
- }, [fileList, isMultiFile, metadataKey, rootPath, propertyId, data]);
16405
- const fileListLength = filesForDisplay.length;
16406
- useEffect(() => {
16407
- // Clear pending upload index when rendered file list catches up.
16408
- pendingUploadIndexRef.current = null;
16409
- }, [fileListLength, metadataKey, rootPath]);
16410
- const getNextUploadIndex = () => {
16411
- const baseIndex = filesForDisplay.length;
16412
- if (pendingUploadIndexRef.current === null || pendingUploadIndexRef.current < baseIndex) {
16413
- pendingUploadIndexRef.current = baseIndex;
16412
+ setOpen(false);
16413
+ };
16414
+ // eslint-disable-next-line
16415
+ const addItem = (path, value) => {
16416
+ var _uischema$options4, _uischema$options5;
16417
+ const maxItems = (_uischema$options4 = uischema.options) != null && (_uischema$options4 = _uischema$options4.detail) != null && _uischema$options4.maxItems ? (_uischema$options5 = uischema.options) == null || (_uischema$options5 = _uischema$options5.detail) == null ? void 0 : _uischema$options5.maxItems : DEFAULT_MAX_ITEMS;
16418
+ if (latestCount < maxItems) {
16419
+ return () => {
16420
+ const currentRows = hasDataRows ? parsedData : Object.keys(latestData).sort((a, b) => Number(a) - Number(b)).map(key => latestData[key]);
16421
+ const nextData = [...currentRows, value];
16422
+ const categoryData = Object.fromEntries(nextData.map((item, index) => [String(index), item]));
16423
+ props.handleChange(path, nextData);
16424
+ dispatch({
16425
+ type: SET_DATA_ACTION,
16426
+ payload: Object.assign({}, registers.categories, {
16427
+ [path]: {
16428
+ count: nextData.length,
16429
+ data: categoryData
16430
+ }
16431
+ })
16432
+ });
16433
+ };
16434
+ } else {
16435
+ setMaxItemsError(`Maximum ${maxItems} items allowed.`);
16436
+ setTimeout(() => {
16437
+ setMaxItemsError('');
16438
+ }, 3000);
16414
16439
  }
16415
- const nextIndex = pendingUploadIndexRef.current;
16416
- pendingUploadIndexRef.current += 1;
16417
- return nextIndex;
16418
16440
  };
16419
- async function uploadFile(file, requestedIndex) {
16420
- if (!uploadTrigger) return;
16421
- const fileListLength = requestedIndex != null ? requestedIndex : isMultiFile ? getNextUploadIndex() : filesForDisplay.length;
16422
- // Single-file controls should allow selecting a new file to replace the current one.
16423
- if (isMultiFile && fileListLength >= maxFiles) {
16424
- setUploadError(`You can only upload up to ${maxFiles} file${maxFiles > 1 ? 's' : ''}.`);
16425
- return;
16441
+ // eslint-disable-next-line
16442
+ const deleteItem = (path, value) => {
16443
+ const categories = registers.categories;
16444
+ const currentCategory = categories[path];
16445
+ const newCategoryData = {};
16446
+ if (currentCategory != null && currentCategory.data) {
16447
+ delete currentCategory.data[value];
16448
+ Object.keys(currentCategory.data).forEach((key, index) => {
16449
+ newCategoryData[index] = currentCategory.data[key];
16450
+ });
16451
+ currentCategory.data = newCategoryData;
16426
16452
  }
16427
- setUploadError(undefined);
16428
- setLoadingFileName(file == null ? void 0 : file.name);
16429
- await Promise.resolve(uploadTrigger(file, isMultiFile ? `${rootPath}.${fileListLength}` : path));
16430
- setDeleteHide(false);
16431
- }
16432
- function queueUpload(file, requestedIndex) {
16433
- uploadQueueRef.current = uploadQueueRef.current.then(() => uploadFile(file, requestedIndex)).catch(() => {
16434
- // Keep queue alive after an individual upload failure.
16453
+ if (currentCategory != null && currentCategory.count && (currentCategory == null ? void 0 : currentCategory.count) > 0) currentCategory.count--;
16454
+ let handleChangeData = Object.keys(newCategoryData).map(key => {
16455
+ return newCategoryData[key];
16435
16456
  });
16436
- }
16437
- function downloadFile(file) {
16438
- if (downloadTrigger && file) {
16439
- downloadTrigger(file, propertyId);
16457
+ if (handleChangeData.length === 0) {
16458
+ handleChangeData = null;
16440
16459
  }
16441
- }
16442
- function deleteFile(file) {
16443
- if (deleteTrigger && file) {
16444
- deleteTrigger(file, propertyId);
16460
+ setMaxItemsError('');
16461
+ props.handleChange(path, handleChangeData);
16462
+ dispatch({
16463
+ type: DELETE_ACTION,
16464
+ payload: {
16465
+ name: path,
16466
+ category: currentCategory
16467
+ }
16468
+ });
16469
+ };
16470
+ //eslint-disable-next-line
16471
+ const handleChangeWithData = (path, value) => {
16472
+ if (path) {
16473
+ var _categories$path;
16474
+ const categories = registers.categories;
16475
+ const currentCategory = ((_categories$path = categories[path]) == null ? void 0 : _categories$path.data) || {};
16476
+ const newData = {};
16477
+ const allKeys = Object.keys(value).concat(Object.keys(currentCategory || []));
16478
+ const allKeysUnique = allKeys.filter((a, b) => allKeys.indexOf(a) === b);
16479
+ Object.keys(allKeysUnique).forEach(num => {
16480
+ if (!newData[num]) {
16481
+ newData[num] = {};
16482
+ }
16483
+ currentCategory[num] && Object.keys(currentCategory[num]).forEach(path => {
16484
+ newData[num][path] = currentCategory[num][path];
16485
+ });
16486
+ value[num] && Object.keys(value[num]).forEach(path => {
16487
+ newData[num][path] = value[num][path] !== undefined ? value[num][path] : currentCategory[num] && currentCategory[num][path];
16488
+ });
16489
+ });
16490
+ const handleChangeData = Object.keys(newData).map(key => {
16491
+ return newData[key];
16492
+ });
16493
+ props.handleChange(path, JSON.parse(JSON.stringify(handleChangeData)));
16494
+ dispatch({
16495
+ type: ADD_DATA_ACTION,
16496
+ payload: {
16497
+ name: path,
16498
+ category: newData
16499
+ }
16500
+ });
16445
16501
  }
16446
- }
16447
- function getFileName(index) {
16448
- var _getFile;
16449
- return (_getFile = getFile(index)) == null ? void 0 : _getFile.filename;
16450
- }
16451
- function getFile(index) {
16452
- return filesForDisplay == null ? void 0 : filesForDisplay[index];
16453
- }
16502
+ };
16454
16503
  useEffect(() => {
16455
- if (loadingFileName !== undefined) {
16456
- setLoadingFileName(undefined);
16504
+ var _currentCategory$coun;
16505
+ const updatedData = Object.fromEntries((parsedData || []).map((item, index) => [index, item]));
16506
+ const count = Object.keys(updatedData).length;
16507
+ const currentCategory = registers.categories[path];
16508
+ if (Array.isArray(data) && data.length === 0 && ((_currentCategory$coun = currentCategory == null ? void 0 : currentCategory.count) != null ? _currentCategory$coun : 0) > 0) {
16509
+ return;
16457
16510
  }
16458
- const delayedFunction = () => {
16459
- if (!fileList) return;
16460
- const filesForControl = filesForDisplay || [];
16461
- const hasFileListEntryForPath = Object.prototype.hasOwnProperty.call(fileList, metadataKey) || Object.prototype.hasOwnProperty.call(fileList, rootPath) || !isMultiFile && Object.prototype.hasOwnProperty.call(fileList, propertyId);
16462
- const urns = filesForControl.map(f => f.urn);
16463
- if (urns.length === 0) {
16464
- if (hasFileListEntryForPath && data !== undefined && data !== null && data !== '') {
16465
- handleChange(isMultiFile ? rootPath : path, undefined);
16466
- }
16467
- } else if (isMultiFile) {
16468
- handleChange(rootPath, urns);
16469
- } else {
16470
- // Single-file replacement appends metadata; keep the latest selection as the current value.
16471
- handleChange(path, urns[urns.length - 1]);
16511
+ const hasSameCount = (currentCategory == null ? void 0 : currentCategory.count) === count;
16512
+ const hasSameData = JSON.stringify((currentCategory == null ? void 0 : currentCategory.data) || {}) === JSON.stringify(updatedData);
16513
+ if (hasSameCount && hasSameData) {
16514
+ return;
16515
+ }
16516
+ const dispatchData = Object.assign({}, registers.categories, {
16517
+ [path]: {
16518
+ count: count,
16519
+ data: updatedData
16472
16520
  }
16473
- };
16474
- const timeoutId = setTimeout(delayedFunction, 1);
16475
- return () => clearTimeout(timeoutId);
16476
- }, [data, fileList, filesForDisplay, rootPath, path, propertyId, metadataKey, isMultiFile, handleChange, loadingFileName]);
16477
- const readOnly = (uischema == null || (_uischema$options6 = uischema.options) == null || (_uischema$options6 = _uischema$options6.componentProps) == null ? void 0 : _uischema$options6.readOnly) === true || (props == null ? void 0 : props.isStepperReview) === true || user === null;
16478
- const maxFileSize = (_uischema$options$com2 = uischema == null || (_uischema$options7 = uischema.options) == null || (_uischema$options7 = _uischema$options7.componentProps) == null ? void 0 : _uischema$options7.maxFileSize) != null ? _uischema$options$com2 : '';
16479
- const accept = (_uischema$options$com3 = uischema == null || (_uischema$options8 = uischema.options) == null || (_uischema$options8 = _uischema$options8.componentProps) == null ? void 0 : _uischema$options8.accept) != null ? _uischema$options$com3 : '';
16480
- if (!enumerators) {
16481
- //eslint-disable-next-line
16482
- return jsx(Fragment, {});
16483
- }
16484
- const helpText = uischema == null || (_uischema$options9 = uischema.options) == null ? void 0 : _uischema$options9.help;
16485
- const sentenceCaseLabel = label;
16486
- const renderFileItem = index => {
16487
- var _getFile2;
16488
- const showFileDeleteConfirmation = deleteConfirmIndex === index;
16489
- return jsx("div", {
16490
- children: readOnly ? jsxs(AttachmentBorderDisabled, {
16491
- children: [getFileName(index), noDownloadButtonInReview !== true && jsx(GoAContextMenuIcon, {
16492
- testId: "download-icon",
16493
- title: "Download",
16494
- type: "download",
16495
- onClick: () => downloadFile(getFile(index))
16496
- })]
16497
- }) : jsxs(AttachmentBorder, {
16498
- children: [jsx("div", {
16499
- children: getFileName(index)
16500
- }), jsxs(GoAContextMenu, {
16501
- children: [noDownloadButton !== true && jsx(GoAContextMenuIcon, {
16502
- testId: "download-icon",
16503
- title: "Download",
16504
- type: "download",
16505
- onClick: () => downloadFile(getFile(index))
16506
- }), noDeleteButton !== true && jsx(GoAContextMenuIcon, {
16507
- "data-testid": "delete-icon",
16508
- title: "Delete",
16509
- type: "trash",
16510
- onClick: () => {
16511
- setDeleteConfirmIndex(index);
16512
- }
16521
+ });
16522
+ dispatch({
16523
+ type: SET_DATA_ACTION,
16524
+ payload: dispatchData
16525
+ });
16526
+ }, [parsedData, path]);
16527
+ const controlElement = uischema;
16528
+ const listTitle = label || ((_uischema$options6 = uischema.options) == null ? void 0 : _uischema$options6.title);
16529
+ const isInReview = isStepperReview === true;
16530
+ const isListWithDetail = controlElement.type === 'ListWithDetail';
16531
+ if (isInReview) {
16532
+ var _uischema$options7, _uischema$options8;
16533
+ return jsx("tr", {
16534
+ children: jsxs(PageReviewContainer, {
16535
+ colSpan: 3,
16536
+ children: [listTitle ? isListWithDetail && additionalProps.required && (data === null || data === undefined) ? jsx("b", {
16537
+ children: jsxs(ListWithDetailWarningIconDiv, {
16538
+ children: [jsx(GoabIcon, {
16539
+ type: "warning",
16540
+ title: "warning",
16541
+ size: "small",
16542
+ theme: "filled",
16543
+ ml: "2xs",
16544
+ mt: "2xs"
16545
+ }), listTitle, " is required."]
16546
+ })
16547
+ }) : jsxs(ReviewHeader, {
16548
+ style: {
16549
+ width: '100%',
16550
+ display: 'grid',
16551
+ gridTemplateColumns: '1fr auto',
16552
+ alignItems: 'center'
16553
+ },
16554
+ children: [jsxs(ReviewLabel, {
16555
+ children: [listTitle, jsx("span", {
16556
+ children: additionalProps.required && '(required)'
16557
+ }), maxItemsError && jsx("span", {
16558
+ style: {
16559
+ color: 'red',
16560
+ marginLeft: '1rem'
16561
+ },
16562
+ children: maxItemsError
16563
+ })]
16564
+ }), showChangeButtons && ((_uischema$options7 = uischema.options) == null ? void 0 : _uischema$options7.stepId) !== undefined && !((_uischema$options8 = uischema.options) != null && (_uischema$options8 = _uischema$options8.componentProps) != null && _uischema$options8.readOnly) && jsx(BackButton, {
16565
+ text: "Change",
16566
+ link: () => {
16567
+ var _uischema$options9;
16568
+ return reportChange((_uischema$options9 = uischema.options) == null ? void 0 : _uischema$options9.stepId, uischema.scope);
16569
+ },
16570
+ showBackIcon: false
16513
16571
  })]
16514
- }), jsx(DeleteFileModal, {
16515
- isOpen: showFileDeleteConfirmation,
16516
- title: "Delete file",
16517
- content: `Delete file ${(_getFile2 = getFile(index)) == null ? void 0 : _getFile2.filename} ?`,
16518
- onCancel: () => setDeleteConfirmIndex(null),
16519
- onDelete: () => {
16520
- setDeleteConfirmIndex(null);
16521
- deleteFile(getFile(index));
16522
- if (!isMultiFile) {
16523
- setDeleteHide(true);
16524
- }
16525
- setUploadError(undefined);
16526
- }
16527
- })]
16572
+ }) : null, jsx(ObjectArrayList, Object.assign({
16573
+ path: path,
16574
+ schema: schema,
16575
+ uischema: uischema,
16576
+ enabled: enabled,
16577
+ openDeleteDialog: openDeleteDialog,
16578
+ translations: {},
16579
+ count: latestCount,
16580
+ data: latestData,
16581
+ cells: cells,
16582
+ config: config,
16583
+ isInReview: isInReview,
16584
+ handleChange: handleChangeWithData
16585
+ }, additionalProps))]
16528
16586
  })
16529
16587
  });
16530
- };
16531
- return jsx(Visible, {
16588
+ }
16589
+ const content = jsxs(Visible, {
16532
16590
  "$visible": visible,
16533
- children: jsxs(FileUploaderStyle, {
16534
- className: "FileUploader",
16535
- children: [jsx(GoabFormItem, {
16536
- label: sentenceCaseLabel,
16537
- requirement: required ? 'required' : undefined,
16538
- error: uploadError
16539
- }), !readOnly && jsx("div", {
16540
- className: "file-upload",
16541
- children: jsx(GoabFileUploadInput, {
16542
- variant: variant,
16543
- onSelectFile: detail => {
16544
- var _detail$files;
16545
- const selectedFiles = detail != null && (_detail$files = detail.files) != null && _detail$files.length ? detail.files : detail != null && detail.file ? [detail.file] : [];
16546
- if (selectedFiles.length === 0) {
16547
- return;
16548
- }
16549
- if (isMultiFile) {
16550
- for (const selectedFile of selectedFiles) {
16551
- const nextIndex = getNextUploadIndex();
16552
- if (nextIndex >= maxFiles) {
16553
- setUploadError(`You can only upload up to ${maxFiles} file${maxFiles > 1 ? 's' : ''}.`);
16554
- break;
16555
- }
16556
- queueUpload(selectedFile, nextIndex);
16557
- }
16558
- } else {
16559
- queueUpload(selectedFiles[0]);
16560
- }
16591
+ "data-testid": "jsonforms-object-list-wrapper",
16592
+ children: [jsxs(ToolBarHeader, {
16593
+ children: [listTitle && jsxs(ObjectArrayTitle, {
16594
+ children: [listTitle, additionalProps.required && jsx(RequiredSpan, {
16595
+ children: "(required)"
16596
+ }), maxItemsError && jsx("span", {
16597
+ style: {
16598
+ color: 'red',
16599
+ marginLeft: '1rem'
16561
16600
  },
16562
- maxFileSize: maxFileSize,
16563
- accept: accept
16564
- })
16565
- }), helpText && jsx(HelpText, {
16566
- children: helpText
16567
- }), jsx("div", {
16568
- children: loadingFileName !== undefined ? jsx(GoabModal, {
16569
- open: loadingFileName !== undefined,
16570
- children: jsx("div", {
16571
- className: "align-center",
16572
- children: jsx(GoabCircularProgress, {
16573
- visible: true,
16574
- message: `Uploading ${loadingFileName}`,
16575
- size: "large"
16576
- })
16577
- })
16578
- }) : jsx("div", {
16579
- children: (fileList && isMultiFile ? filesForDisplay.map((_, i) => i) : !deleteHide && getFile(fileListLength - 1) && fileListLength >= 0 ? [fileListLength - 1] : []).map(index => jsx(React.Fragment, {
16580
- children: renderFileItem(index)
16581
- }, index))
16582
- })
16601
+ children: maxItemsError
16602
+ })]
16603
+ }), jsx(ObjectArrayToolBar, {
16604
+ errors: errors,
16605
+ label: label,
16606
+ addItem: addItem,
16607
+ numColumns: 0,
16608
+ path: path,
16609
+ uischema: controlElement,
16610
+ schema: schema,
16611
+ rootSchema: rootSchema,
16612
+ enabled: enabled
16583
16613
  })]
16584
- })
16614
+ }), jsxs("div", {
16615
+ children: [jsx(ObjectArrayList, Object.assign({
16616
+ path: path,
16617
+ schema: schema,
16618
+ uischema: uischema,
16619
+ enabled: enabled,
16620
+ openDeleteDialog: openDeleteDialog,
16621
+ translations: {},
16622
+ count: latestCount,
16623
+ data: latestData,
16624
+ cells: cells,
16625
+ config: config,
16626
+ isInReview: isInReview,
16627
+ handleChange: handleChangeWithData
16628
+ }, additionalProps)), jsx(DeleteDialog, {
16629
+ open: open,
16630
+ onCancel: deleteCancel,
16631
+ onConfirm: deleteConfirm,
16632
+ title: 'Remove item',
16633
+ message: 'Are you sure you wish to remove the selected item'
16634
+ })]
16635
+ })]
16585
16636
  });
16637
+ return content;
16586
16638
  };
16587
- const HelpText = styled.div(_t$1 || (_t$1 = _2`
16588
- margin-top: var(--goa-space-xs);
16589
- font-size: var(--goa-font-size-3);
16590
- color: var(--goa-color-text-secondary);
16591
- `));
16592
- const AttachmentBorderDisabled = styled.div(_t2$1 || (_t2$1 = _2`
16593
- display: flex;
16594
- flex-direction: row;
16595
- border: var(--goa-border-width-s) solid #dcdcdc;
16596
- border-radius: var(--goa-border-radius-m);
16597
- padding: var(--goa-space-xs);
16598
- width: fit-content;
16599
- background-color: #f1f1f1;
16600
- `));
16601
- const AttachmentBorder = styled.div(_t3 || (_t3 = _2`
16602
- display: flex;
16603
- flex-direction: row;
16604
- border: var(--goa-border-width-s) solid #dcdcdc;
16605
- border-radius: var(--goa-border-radius-m);
16606
- padding: var(--goa-space-xs);
16607
- width: fit-content;
16608
- margin-top: var(--goa-space-2xs);
16609
- `));
16610
- const FileUploaderStyle = styled.div(_t4 || (_t4 = _2`
16611
- margin-bottom: var(--goa-space-l);
16612
- .label {
16613
- display: block;
16614
- font-weight: var(--goa-font-weight-bold);
16615
- color: var(--goa-color-text-default);
16616
- font-size: var(--goa-font-size-4);
16617
- padding: 0 0 var(--goa-space-xs) 0;
16618
- }
16619
-
16620
- .align-center {
16621
- text-align-last: center;
16622
- }
16623
-
16624
- .file-upload {
16625
- margin-bottom: var(--goa-space-xs);
16626
- }
16627
- `));
16628
16639
 
16629
16640
  const ArrayControl = props => {
16630
16641
  const {
@@ -18009,12 +18020,16 @@ const FormStepperReviewer = props => {
18009
18020
  children: [summaryPageTitle && !jsonForms.readonly && jsx(FormStepperSummaryH3, {
18010
18021
  children: summaryPageTitle
18011
18022
  }), categories.map((category, categoryIndex) => {
18012
- var _category$options, _category$options$sec, _category$options2;
18023
+ var _category$options, _category$options2, _category$options$sec, _category$options3;
18013
18024
  // Preserve index stability
18014
18025
  if (!isVisible(category, data, '', ajv, undefined)) {
18015
18026
  return null;
18016
18027
  }
18017
18028
  const categoryLabel = category.label || category.i18n || 'Unknown Category';
18029
+ const isInTaskList = cat => {
18030
+ var _cat$options;
18031
+ return (cat == null || (_cat$options = cat.options) == null ? void 0 : _cat$options.showInTaskList) !== false;
18032
+ };
18018
18033
  // Build visible elements list
18019
18034
  const elementsToRender = category.elements.filter(field => hasVisibleContent(field)).map(e => {
18020
18035
  const layout = e;
@@ -18026,12 +18041,12 @@ const FormStepperReviewer = props => {
18026
18041
  }
18027
18042
  return e;
18028
18043
  }).flat();
18029
- // Do not render empty categories
18030
- if (elementsToRender.length === 0) {
18044
+ // Do not render empty categories or showInTaskList is false
18045
+ if (elementsToRender.length === 0 || !isInTaskList(category)) {
18031
18046
  return null;
18032
18047
  }
18033
18048
  //The tasklist can have a parent section title, we want to display if it exists
18034
- const sectionTitle = ((_category$options = category.options) == null ? void 0 : _category$options.showInTaskList) === true ? String((_category$options$sec = (_category$options2 = category.options) == null ? void 0 : _category$options2.sectionTitle) != null ? _category$options$sec : '').trim() : '';
18049
+ const sectionTitle = ((_category$options = category.options) == null ? void 0 : _category$options.showInTaskList) === true || ((_category$options2 = category.options) == null ? void 0 : _category$options2.showInTaskList) === undefined ? String((_category$options$sec = (_category$options3 = category.options) == null ? void 0 : _category$options3.sectionTitle) != null ? _category$options$sec : '').trim() : '';
18035
18050
  const showSectionTitle = sectionTitle !== '' && sectionTitle !== lastShownSectionTitle;
18036
18051
  if (showSectionTitle) {
18037
18052
  lastShownSectionTitle = sectionTitle;
@@ -18474,7 +18489,7 @@ function updateCompletion(group, index) {
18474
18489
  endIndex++;
18475
18490
  }
18476
18491
  const relevant = group.slice(index, endIndex + 1);
18477
- // A task is "completed" iff:
18492
+ // A task is "completed" if:
18478
18493
  // - the main row itself isCompleted, AND
18479
18494
  // - every detail page that is currently visible is also completed.
18480
18495
  const newIsCompleted = category.isCompleted && relevant.every(cat => !cat.visible || cat.isCompleted);