@defra/forms-engine-plugin 5.0.0-alpha.5 → 5.0.0-alpha.7
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/.server/server/constants.d.ts +1 -0
- package/.server/server/constants.js +1 -0
- package/.server/server/constants.js.map +1 -1
- package/.server/server/plugins/engine/components/ComponentBase.d.ts +1 -0
- package/.server/server/plugins/engine/components/ComponentBase.js +2 -0
- package/.server/server/plugins/engine/components/ComponentBase.js.map +1 -1
- package/.server/server/plugins/engine/components/ComponentCollection.js +2 -1
- package/.server/server/plugins/engine/components/ComponentCollection.js.map +1 -1
- package/.server/server/plugins/engine/components/DeclarationField.js +1 -1
- package/.server/server/plugins/engine/components/DeclarationField.js.map +1 -1
- package/.server/server/plugins/engine/components/FormComponent.js +2 -2
- package/.server/server/plugins/engine/components/FormComponent.js.map +1 -1
- package/.server/server/plugins/engine/components/Markdown.js +1 -1
- package/.server/server/plugins/engine/components/Markdown.js.map +1 -1
- package/.server/server/plugins/engine/i18n/types.d.ts +1 -0
- package/.server/server/plugins/engine/i18n/types.js.map +1 -1
- package/.server/server/plugins/engine/models/SummaryViewModel.js +7 -3
- package/.server/server/plugins/engine/models/SummaryViewModel.js.map +1 -1
- package/.server/server/plugins/engine/outputFormatters/adapter/v1.js +3 -5
- package/.server/server/plugins/engine/outputFormatters/adapter/v1.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/RepeatPageController.js +3 -4
- package/.server/server/plugins/engine/pageControllers/RepeatPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +4 -1
- package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -1
- package/package.json +2 -2
- package/src/server/constants.js +1 -0
- package/src/server/plugins/engine/components/ComponentBase.ts +2 -0
- package/src/server/plugins/engine/components/ComponentCollection.ts +4 -5
- package/src/server/plugins/engine/components/DeclarationField.ts +1 -2
- package/src/server/plugins/engine/components/FormComponent.ts +2 -4
- package/src/server/plugins/engine/components/Markdown.ts +2 -3
- package/src/server/plugins/engine/i18n/types.ts +1 -0
- package/src/server/plugins/engine/models/SummaryViewModel.ts +4 -4
- package/src/server/plugins/engine/outputFormatters/adapter/v1.ts +3 -6
- package/src/server/plugins/engine/pageControllers/RepeatPageController.ts +2 -2
- package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +6 -1
|
@@ -5,3 +5,4 @@ export const EXTERNAL_STATE_PAYLOAD: "EXTERNAL_STATE_PAYLOAD";
|
|
|
5
5
|
export const EXTERNAL_STATE_APPENDAGE: "EXTERNAL_STATE_APPENDAGE";
|
|
6
6
|
export const COMPONENT_STATE_ERROR: "COMPONENT_STATE_ERROR";
|
|
7
7
|
export const PAYMENT_EXPIRED_NOTIFICATION: "PAYMENT_EXPIRED_NOTIFICATION";
|
|
8
|
+
export const EN_GB: "en-GB";
|
|
@@ -5,4 +5,5 @@ export const EXTERNAL_STATE_PAYLOAD = 'EXTERNAL_STATE_PAYLOAD';
|
|
|
5
5
|
export const EXTERNAL_STATE_APPENDAGE = 'EXTERNAL_STATE_APPENDAGE';
|
|
6
6
|
export const COMPONENT_STATE_ERROR = 'COMPONENT_STATE_ERROR';
|
|
7
7
|
export const PAYMENT_EXPIRED_NOTIFICATION = 'PAYMENT_EXPIRED_NOTIFICATION';
|
|
8
|
+
export const EN_GB = 'en-GB';
|
|
8
9
|
//# sourceMappingURL=constants.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","names":["FORM_VERSION_METADATA_KEY","PREVIEW_PATH_PREFIX","FORM_PREFIX","EXTERNAL_STATE_PAYLOAD","EXTERNAL_STATE_APPENDAGE","COMPONENT_STATE_ERROR","PAYMENT_EXPIRED_NOTIFICATION"],"sources":["../../src/server/constants.js"],"sourcesContent":["export const FORM_VERSION_METADATA_KEY = '$$__formVersion'\nexport const PREVIEW_PATH_PREFIX = '/preview'\nexport const FORM_PREFIX = ''\nexport const EXTERNAL_STATE_PAYLOAD = 'EXTERNAL_STATE_PAYLOAD'\nexport const EXTERNAL_STATE_APPENDAGE = 'EXTERNAL_STATE_APPENDAGE'\nexport const COMPONENT_STATE_ERROR = 'COMPONENT_STATE_ERROR'\nexport const PAYMENT_EXPIRED_NOTIFICATION = 'PAYMENT_EXPIRED_NOTIFICATION'\n"],"mappings":"AAAA,OAAO,MAAMA,yBAAyB,GAAG,iBAAiB;AAC1D,OAAO,MAAMC,mBAAmB,GAAG,UAAU;AAC7C,OAAO,MAAMC,WAAW,GAAG,EAAE;AAC7B,OAAO,MAAMC,sBAAsB,GAAG,wBAAwB;AAC9D,OAAO,MAAMC,wBAAwB,GAAG,0BAA0B;AAClE,OAAO,MAAMC,qBAAqB,GAAG,uBAAuB;AAC5D,OAAO,MAAMC,4BAA4B,GAAG,8BAA8B","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"constants.js","names":["FORM_VERSION_METADATA_KEY","PREVIEW_PATH_PREFIX","FORM_PREFIX","EXTERNAL_STATE_PAYLOAD","EXTERNAL_STATE_APPENDAGE","COMPONENT_STATE_ERROR","PAYMENT_EXPIRED_NOTIFICATION","EN_GB"],"sources":["../../src/server/constants.js"],"sourcesContent":["export const FORM_VERSION_METADATA_KEY = '$$__formVersion'\nexport const PREVIEW_PATH_PREFIX = '/preview'\nexport const FORM_PREFIX = ''\nexport const EXTERNAL_STATE_PAYLOAD = 'EXTERNAL_STATE_PAYLOAD'\nexport const EXTERNAL_STATE_APPENDAGE = 'EXTERNAL_STATE_APPENDAGE'\nexport const COMPONENT_STATE_ERROR = 'COMPONENT_STATE_ERROR'\nexport const PAYMENT_EXPIRED_NOTIFICATION = 'PAYMENT_EXPIRED_NOTIFICATION'\nexport const EN_GB = 'en-GB'\n"],"mappings":"AAAA,OAAO,MAAMA,yBAAyB,GAAG,iBAAiB;AAC1D,OAAO,MAAMC,mBAAmB,GAAG,UAAU;AAC7C,OAAO,MAAMC,WAAW,GAAG,EAAE;AAC7B,OAAO,MAAMC,sBAAsB,GAAG,wBAAwB;AAC9D,OAAO,MAAMC,wBAAwB,GAAG,0BAA0B;AAClE,OAAO,MAAMC,qBAAqB,GAAG,uBAAuB;AAC5D,OAAO,MAAMC,4BAA4B,GAAG,8BAA8B;AAC1E,OAAO,MAAMC,KAAK,GAAG,OAAO","ignoreList":[]}
|
|
@@ -21,6 +21,7 @@ export declare class ComponentBase {
|
|
|
21
21
|
}>['options'];
|
|
22
22
|
isFormComponent: boolean;
|
|
23
23
|
model: FormModel;
|
|
24
|
+
def: ComponentDef;
|
|
24
25
|
/** joi schemas based on a component defined in the form JSON. This validates a user's answer and is generated from {@link ComponentDef} */
|
|
25
26
|
formSchema: ComponentSchema;
|
|
26
27
|
stateSchema: ComponentSchema;
|
|
@@ -12,6 +12,7 @@ export class ComponentBase {
|
|
|
12
12
|
options;
|
|
13
13
|
isFormComponent = false;
|
|
14
14
|
model;
|
|
15
|
+
def;
|
|
15
16
|
|
|
16
17
|
/** joi schemas based on a component defined in the form JSON. This validates a user's answer and is generated from {@link ComponentDef} */
|
|
17
18
|
formSchema = joi.string();
|
|
@@ -21,6 +22,7 @@ export class ComponentBase {
|
|
|
21
22
|
this.type = def.type;
|
|
22
23
|
this.name = def.name;
|
|
23
24
|
this.title = def.title;
|
|
25
|
+
this.def = def;
|
|
24
26
|
if ('schema' in def) {
|
|
25
27
|
this.schema = def.schema;
|
|
26
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComponentBase.js","names":["isConditionalRevealType","joi","ComponentBase","id","page","parent","collection","type","name","title","schema","options","isFormComponent","model","formSchema","string","stateSchema","constructor","
|
|
1
|
+
{"version":3,"file":"ComponentBase.js","names":["isConditionalRevealType","joi","ComponentBase","id","page","parent","collection","type","name","title","schema","options","isFormComponent","model","def","formSchema","string","stateSchema","constructor","props","viewModel","attributes","autocomplete","classes","condition"],"sources":["../../../../../src/server/plugins/engine/components/ComponentBase.ts"],"sourcesContent":["import { isConditionalRevealType, type ComponentDef } from '@defra/forms-model'\nimport joi, {\n type ArraySchema,\n type BooleanSchema,\n type DateSchema,\n type NumberSchema,\n type ObjectSchema,\n type StringSchema\n} from 'joi'\n\nimport { type ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'\nimport { type Component } from '~/src/server/plugins/engine/components/helpers/components.js'\nimport { type ViewModel } from '~/src/server/plugins/engine/components/types.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'\n\nexport class ComponentBase {\n id?: string\n page?: PageControllerClass\n parent: Component | undefined\n collection: ComponentCollection | undefined\n\n type: ComponentDef['type']\n name: ComponentDef['name']\n title: ComponentDef['title']\n schema?: Extract<ComponentDef, { schema?: object }>['schema']\n options?: Extract<ComponentDef, { options: object }>['options']\n\n isFormComponent = false\n model: FormModel\n def: ComponentDef\n\n /** joi schemas based on a component defined in the form JSON. This validates a user's answer and is generated from {@link ComponentDef} */\n formSchema: ComponentSchema = joi.string()\n stateSchema: ComponentSchema = joi.string()\n\n constructor(\n def: ComponentDef,\n props: {\n page?: PageControllerClass\n parent?: Component\n model: FormModel\n }\n ) {\n this.id = def.id\n this.type = def.type\n this.name = def.name\n this.title = def.title\n this.def = def\n\n if ('schema' in def) {\n this.schema = def.schema\n }\n\n if ('options' in def) {\n this.options = def.options\n }\n\n this.page = props.page\n this.parent = props.parent\n this.model = props.model\n }\n\n get viewModel() {\n const { options, type } = this\n\n const viewModel: ViewModel = {\n attributes: {}\n }\n\n if (!options) {\n return viewModel\n }\n\n if ('autocomplete' in options) {\n viewModel.attributes.autocomplete = options.autocomplete\n }\n\n if ('classes' in options) {\n viewModel.classes = options.classes\n }\n\n if ('condition' in options && isConditionalRevealType(type)) {\n viewModel.condition = options.condition\n }\n\n return viewModel\n }\n}\n\nexport type ComponentSchema =\n | ArraySchema<string>\n | ArraySchema<number>\n | ArraySchema<boolean>\n | ArraySchema<object>\n | BooleanSchema<string>\n | BooleanSchema\n | DateSchema\n | NumberSchema<string>\n | NumberSchema\n | ObjectSchema\n | StringSchema\n"],"mappings":"AAAA,SAASA,uBAAuB,QAA2B,oBAAoB;AAC/E,OAAOC,GAAG,MAOH,KAAK;AAQZ,OAAO,MAAMC,aAAa,CAAC;EACzBC,EAAE;EACFC,IAAI;EACJC,MAAM;EACNC,UAAU;EAEVC,IAAI;EACJC,IAAI;EACJC,KAAK;EACLC,MAAM;EACNC,OAAO;EAEPC,eAAe,GAAG,KAAK;EACvBC,KAAK;EACLC,GAAG;;EAEH;EACAC,UAAU,GAAoBd,GAAG,CAACe,MAAM,CAAC,CAAC;EAC1CC,WAAW,GAAoBhB,GAAG,CAACe,MAAM,CAAC,CAAC;EAE3CE,WAAWA,CACTJ,GAAiB,EACjBK,KAIC,EACD;IACA,IAAI,CAAChB,EAAE,GAAGW,GAAG,CAACX,EAAE;IAChB,IAAI,CAACI,IAAI,GAAGO,GAAG,CAACP,IAAI;IACpB,IAAI,CAACC,IAAI,GAAGM,GAAG,CAACN,IAAI;IACpB,IAAI,CAACC,KAAK,GAAGK,GAAG,CAACL,KAAK;IACtB,IAAI,CAACK,GAAG,GAAGA,GAAG;IAEd,IAAI,QAAQ,IAAIA,GAAG,EAAE;MACnB,IAAI,CAACJ,MAAM,GAAGI,GAAG,CAACJ,MAAM;IAC1B;IAEA,IAAI,SAAS,IAAII,GAAG,EAAE;MACpB,IAAI,CAACH,OAAO,GAAGG,GAAG,CAACH,OAAO;IAC5B;IAEA,IAAI,CAACP,IAAI,GAAGe,KAAK,CAACf,IAAI;IACtB,IAAI,CAACC,MAAM,GAAGc,KAAK,CAACd,MAAM;IAC1B,IAAI,CAACQ,KAAK,GAAGM,KAAK,CAACN,KAAK;EAC1B;EAEA,IAAIO,SAASA,CAAA,EAAG;IACd,MAAM;MAAET,OAAO;MAAEJ;IAAK,CAAC,GAAG,IAAI;IAE9B,MAAMa,SAAoB,GAAG;MAC3BC,UAAU,EAAE,CAAC;IACf,CAAC;IAED,IAAI,CAACV,OAAO,EAAE;MACZ,OAAOS,SAAS;IAClB;IAEA,IAAI,cAAc,IAAIT,OAAO,EAAE;MAC7BS,SAAS,CAACC,UAAU,CAACC,YAAY,GAAGX,OAAO,CAACW,YAAY;IAC1D;IAEA,IAAI,SAAS,IAAIX,OAAO,EAAE;MACxBS,SAAS,CAACG,OAAO,GAAGZ,OAAO,CAACY,OAAO;IACrC;IAEA,IAAI,WAAW,IAAIZ,OAAO,IAAIX,uBAAuB,CAACO,IAAI,CAAC,EAAE;MAC3Da,SAAS,CAACI,SAAS,GAAGb,OAAO,CAACa,SAAS;IACzC;IAEA,OAAOJ,SAAS;EAClB;AACF","ignoreList":[]}
|
|
@@ -210,7 +210,8 @@ export class ComponentCollection {
|
|
|
210
210
|
labelOverrides[subField.name] = patchedSchema;
|
|
211
211
|
}
|
|
212
212
|
} else {
|
|
213
|
-
const
|
|
213
|
+
const fieldDef = field.def;
|
|
214
|
+
const translatedLabel = translator.tComponent(fieldDef, 'errorDescription') || translator.tComponent(fieldDef, 'shortDescription') || translator.tComponent(fieldDef, 'title');
|
|
214
215
|
const messagesOverride = field.getValidationMessagesOverride(translator);
|
|
215
216
|
let patchedSchema = field.formSchema;
|
|
216
217
|
if (translatedLabel && translatedLabel !== field.label) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComponentCollection.js","names":["joi","isFormState","isFormValue","createComponent","getErrors","buildLanguageMessages","validationOptions","opts","ComponentCollection","page","parent","components","fields","guidance","formSchema","stateSchema","constructor","defs","props","schema","map","def","filter","component","isFormComponent","object","required","field","collection","name","concat","keys","peers","and","isPresent","custom","flatMap","getFormDataFromState","state","payload","forEach","Object","assign","getFormValueFromState","value","entries","key","split","pop","getStateFromValidForm","getContextValueFromState","context","translator","errors","getFieldErrors","getViewErrors","getViewModel","result","type","model","overrideParentTitle","error","isErrorContext","local","title","missing","path","find","item","shift","child","label","length","tComponent","validate","messages","t","undefined","labelOverrides","messagesOverride","getValidationMessagesOverride","subField","translatedSubLabel","patchedSchema","translatedLabel","details","callback","list","fieldErrors","push"],"sources":["../../../../../src/server/plugins/engine/components/ComponentCollection.ts"],"sourcesContent":["import { type ComponentDef } from '@defra/forms-model'\nimport joi, {\n type CustomValidator,\n type ErrorReportCollection,\n type ObjectSchema\n} from 'joi'\n\nimport {\n isFormState,\n isFormValue\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport {\n createComponent,\n type Component,\n type Field,\n type Guidance\n} from '~/src/server/plugins/engine/components/helpers/components.js'\nimport {\n type ComponentViewModel,\n type RenderContext\n} from '~/src/server/plugins/engine/components/types.js'\nimport { getErrors } from '~/src/server/plugins/engine/helpers.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'\nimport {\n buildLanguageMessages,\n validationOptions as opts\n} from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\nimport {\n type FormPayload,\n type FormState,\n type FormSubmissionError,\n type FormSubmissionState,\n type FormValidationResult\n} from '~/src/server/plugins/engine/types.js'\n\nexport class ComponentCollection {\n page?: PageControllerClass\n parent?: Component\n\n components: Component[]\n fields: Field[]\n guidance: Guidance[]\n\n formSchema: ObjectSchema<FormPayload>\n stateSchema: ObjectSchema<FormSubmissionState>\n\n constructor(\n defs: ComponentDef[],\n props: {\n page?: PageControllerClass\n parent?: Component\n model: FormModel\n },\n schema?: {\n /**\n * Defines an all-or-nothing relationship between keys where if one\n * of the peers is present, all of them are required as well\n */\n peers?: string[]\n\n /**\n * Defines a custom validation rule for the object schema\n */\n custom?: CustomValidator\n }\n ) {\n const components = defs.map((def) => createComponent(def, props))\n\n const fields = components.filter(\n (component): component is Field => component.isFormComponent\n )\n\n const guidance = components.filter(\n (component): component is Guidance => !component.isFormComponent\n )\n\n let formSchema = joi.object<FormPayload>().required()\n let stateSchema = joi.object<FormSubmissionState>().required()\n\n // Add each field or concat collection\n for (const field of fields) {\n const { collection, name } = field\n\n formSchema = collection\n ? formSchema.concat(collection.formSchema)\n : formSchema.keys({ [name]: field.formSchema })\n\n stateSchema = collection\n ? stateSchema.concat(collection.stateSchema)\n : stateSchema.keys({ [name]: field.stateSchema })\n }\n\n if (schema?.peers) {\n formSchema = formSchema.and(...schema.peers, {\n isPresent: isFormValue\n })\n }\n\n if (schema?.custom) {\n formSchema = formSchema.custom(schema.custom)\n }\n\n this.page = props.page\n this.parent = props.parent\n\n this.components = components\n this.fields = fields\n this.guidance = guidance\n\n this.formSchema = formSchema\n this.stateSchema = stateSchema\n }\n\n get keys() {\n return this.fields.flatMap((field) => {\n const { name, collection } = field\n\n if (collection) {\n const { fields } = collection\n return [name, ...fields.map(({ name }) => name)]\n }\n\n return [name]\n })\n }\n\n getFormDataFromState(state: FormSubmissionState) {\n const payload: FormPayload = {}\n\n this.fields.forEach((component) => {\n Object.assign(payload, component.getFormDataFromState(state))\n })\n\n return payload\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const payload: FormPayload = {}\n\n // Remove name prefix for formatted value\n for (const [name, value] of Object.entries(\n this.getFormDataFromState(state)\n )) {\n const key = name.split('__').pop()\n if (!key) {\n continue\n }\n\n payload[key] = value\n }\n\n return payload\n }\n\n getStateFromValidForm(payload: FormPayload) {\n const state: FormState = {}\n\n this.fields.forEach((component) => {\n Object.assign(state, component.getStateFromValidForm(payload))\n })\n\n return state\n }\n\n getContextValueFromState(state: FormSubmissionState) {\n const context: FormState = {}\n\n for (const component of this.fields) {\n context[component.name] = component.getContextValueFromState(state)\n }\n\n return context\n }\n\n /**\n * Get all errors for all fields in this collection\n */\n getErrors(\n translator: Translator,\n errors?: FormSubmissionError[]\n ): FormSubmissionError[] | undefined {\n return this.getFieldErrors(\n (field) => field.getErrors(translator, errors),\n errors\n )\n }\n\n /**\n * Get view errors for all fields in this collection.\n * For most fields this means filtering to the first error in the list.\n * Composite fields like UKAddress can choose to return more than one error.\n */\n getViewErrors(\n translator: Translator,\n errors?: FormSubmissionError[]\n ): FormSubmissionError[] | undefined {\n return this.getFieldErrors(\n (field) => field.getViewErrors(translator, errors),\n errors\n )\n }\n\n getViewModel(context: RenderContext) {\n const { components } = this\n\n const result: ComponentViewModel[] = components.map((component) => {\n const { isFormComponent, type } = component\n\n const model = component.getViewModel(context)\n\n return { type, isFormComponent, model }\n })\n\n return result\n }\n\n overrideParentTitle(\n formSchema: joi.ObjectSchema<FormPayload>,\n translator: Translator | undefined\n ) {\n // Add parent field title to collection field errors\n return formSchema.error((errors) => {\n return errors.flatMap((error) => {\n if (!isErrorContext(error.local) || error.local.title) {\n return error\n }\n\n // Use field key or first missing child field\n let { missing, key = missing?.[0] } = error.local\n\n // But avoid numeric key used by array payloads\n if (typeof key === 'number') {\n key = error.path[0]\n }\n\n // Find the parent field\n const parent = this.fields.find(\n (item) => item.name === key?.split('__').shift()\n )\n\n // Find the child field\n const child = (parent?.collection?.fields ?? this.fields).find(\n (item) => item.name === key\n )\n\n // Update error with child label\n if (child && (!error.local.label || error.local.label === 'value')) {\n error.local.label = child.title\n }\n\n // Fix error summary links for missing fields\n if (missing?.length) {\n error.path = missing\n error.local.key = missing[0]\n }\n\n // Update error with parent title\n if (translator && parent) {\n error.local.title ??= translator.tComponent(\n parent as ComponentDef,\n 'title'\n )\n } else {\n error.local.title ??= parent?.label\n }\n\n return error\n })\n })\n }\n\n /**\n * Validate form payload\n */\n validate(\n value: FormPayload = {},\n translator?: Translator\n ): FormValidationResult<FormPayload> {\n const messages = translator\n ? buildLanguageMessages(translator.t)\n : undefined\n\n // When translating, override Joi labels (and custom schema messages where\n // needed) so #label/#title in message templates resolve in the correct language.\n let schema = this.formSchema\n // Add parent field title to collection field errors\n schema = this.overrideParentTitle(schema, translator)\n\n if (translator) {\n const { t } = translator\n const labelOverrides: Record<string, joi.Schema> = {}\n\n for (const field of this.fields) {\n if (field.collection) {\n // Composite field: translate each sub-field's label using the key constant\n // (e.g. 'components.addressField.line1' → \"Llinell cyfeiriad 1\") and apply\n // any field-type-specific message overrides (e.g. objectMissing for dates).\n const messagesOverride =\n field.getValidationMessagesOverride(translator)\n for (const subField of field.collection.fields) {\n const translatedSubLabel = t(subField.title) || subField.label\n let patchedSchema = subField.formSchema.label(translatedSubLabel)\n if (messagesOverride) {\n patchedSchema = patchedSchema.messages(messagesOverride)\n }\n labelOverrides[subField.name] = patchedSchema\n }\n } else {\n const translatedLabel =\n translator.tComponent(\n field as unknown as ComponentDef,\n 'shortDescription'\n ) ||\n translator.tComponent(field as unknown as ComponentDef, 'title')\n const messagesOverride =\n field.getValidationMessagesOverride(translator)\n let patchedSchema = field.formSchema\n if (translatedLabel && translatedLabel !== field.label) {\n patchedSchema = patchedSchema.label(translatedLabel)\n }\n if (messagesOverride) {\n patchedSchema = patchedSchema.messages(messagesOverride)\n }\n if (patchedSchema !== field.formSchema) {\n labelOverrides[field.name] = patchedSchema\n }\n }\n }\n\n if (Object.keys(labelOverrides).length) {\n schema = schema.keys(labelOverrides)\n }\n }\n\n const result = schema.validate(value, {\n ...opts,\n ...(messages && { messages })\n })\n\n const details = result.error?.details\n\n return {\n value: (result.value ?? {}) as typeof value,\n errors: this.page?.getErrors(details) ?? getErrors(details)\n }\n }\n\n /**\n * Helper to get errors from all fields\n */\n private getFieldErrors(\n callback: (field: Field) => FormSubmissionError[] | undefined,\n errors?: FormSubmissionError[]\n ): FormSubmissionError[] | undefined {\n const { fields } = this\n\n if (!errors?.length) {\n return\n }\n\n const list: FormSubmissionError[] = []\n\n for (const field of fields) {\n const fieldErrors = callback(field)\n\n if (fieldErrors?.length) {\n list.push(...fieldErrors)\n }\n }\n\n if (!list.length) {\n return\n }\n\n return list\n }\n}\n\n/**\n * Check for field local state\n */\nexport function isErrorContext(\n value?: unknown\n): value is ErrorReportCollection['local'] {\n return isFormState(value) && typeof value.label === 'string'\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"ComponentCollection.js","names":["joi","isFormState","isFormValue","createComponent","getErrors","buildLanguageMessages","validationOptions","opts","ComponentCollection","page","parent","components","fields","guidance","formSchema","stateSchema","constructor","defs","props","schema","map","def","filter","component","isFormComponent","object","required","field","collection","name","concat","keys","peers","and","isPresent","custom","flatMap","getFormDataFromState","state","payload","forEach","Object","assign","getFormValueFromState","value","entries","key","split","pop","getStateFromValidForm","getContextValueFromState","context","translator","errors","getFieldErrors","getViewErrors","getViewModel","result","type","model","overrideParentTitle","error","isErrorContext","local","title","missing","path","find","item","shift","child","label","length","tComponent","validate","messages","t","undefined","labelOverrides","messagesOverride","getValidationMessagesOverride","subField","translatedSubLabel","patchedSchema","fieldDef","translatedLabel","details","callback","list","fieldErrors","push"],"sources":["../../../../../src/server/plugins/engine/components/ComponentCollection.ts"],"sourcesContent":["import { type ComponentDef } from '@defra/forms-model'\nimport joi, {\n type CustomValidator,\n type ErrorReportCollection,\n type ObjectSchema\n} from 'joi'\n\nimport {\n isFormState,\n isFormValue\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport {\n createComponent,\n type Component,\n type Field,\n type Guidance\n} from '~/src/server/plugins/engine/components/helpers/components.js'\nimport {\n type ComponentViewModel,\n type RenderContext\n} from '~/src/server/plugins/engine/components/types.js'\nimport { getErrors } from '~/src/server/plugins/engine/helpers.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'\nimport {\n buildLanguageMessages,\n validationOptions as opts\n} from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\nimport {\n type FormPayload,\n type FormState,\n type FormSubmissionError,\n type FormSubmissionState,\n type FormValidationResult\n} from '~/src/server/plugins/engine/types.js'\n\nexport class ComponentCollection {\n page?: PageControllerClass\n parent?: Component\n\n components: Component[]\n fields: Field[]\n guidance: Guidance[]\n\n formSchema: ObjectSchema<FormPayload>\n stateSchema: ObjectSchema<FormSubmissionState>\n\n constructor(\n defs: ComponentDef[],\n props: {\n page?: PageControllerClass\n parent?: Component\n model: FormModel\n },\n schema?: {\n /**\n * Defines an all-or-nothing relationship between keys where if one\n * of the peers is present, all of them are required as well\n */\n peers?: string[]\n\n /**\n * Defines a custom validation rule for the object schema\n */\n custom?: CustomValidator\n }\n ) {\n const components = defs.map((def) => createComponent(def, props))\n\n const fields = components.filter(\n (component): component is Field => component.isFormComponent\n )\n\n const guidance = components.filter(\n (component): component is Guidance => !component.isFormComponent\n )\n\n let formSchema = joi.object<FormPayload>().required()\n let stateSchema = joi.object<FormSubmissionState>().required()\n\n // Add each field or concat collection\n for (const field of fields) {\n const { collection, name } = field\n\n formSchema = collection\n ? formSchema.concat(collection.formSchema)\n : formSchema.keys({ [name]: field.formSchema })\n\n stateSchema = collection\n ? stateSchema.concat(collection.stateSchema)\n : stateSchema.keys({ [name]: field.stateSchema })\n }\n\n if (schema?.peers) {\n formSchema = formSchema.and(...schema.peers, {\n isPresent: isFormValue\n })\n }\n\n if (schema?.custom) {\n formSchema = formSchema.custom(schema.custom)\n }\n\n this.page = props.page\n this.parent = props.parent\n\n this.components = components\n this.fields = fields\n this.guidance = guidance\n\n this.formSchema = formSchema\n this.stateSchema = stateSchema\n }\n\n get keys() {\n return this.fields.flatMap((field) => {\n const { name, collection } = field\n\n if (collection) {\n const { fields } = collection\n return [name, ...fields.map(({ name }) => name)]\n }\n\n return [name]\n })\n }\n\n getFormDataFromState(state: FormSubmissionState) {\n const payload: FormPayload = {}\n\n this.fields.forEach((component) => {\n Object.assign(payload, component.getFormDataFromState(state))\n })\n\n return payload\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const payload: FormPayload = {}\n\n // Remove name prefix for formatted value\n for (const [name, value] of Object.entries(\n this.getFormDataFromState(state)\n )) {\n const key = name.split('__').pop()\n if (!key) {\n continue\n }\n\n payload[key] = value\n }\n\n return payload\n }\n\n getStateFromValidForm(payload: FormPayload) {\n const state: FormState = {}\n\n this.fields.forEach((component) => {\n Object.assign(state, component.getStateFromValidForm(payload))\n })\n\n return state\n }\n\n getContextValueFromState(state: FormSubmissionState) {\n const context: FormState = {}\n\n for (const component of this.fields) {\n context[component.name] = component.getContextValueFromState(state)\n }\n\n return context\n }\n\n /**\n * Get all errors for all fields in this collection\n */\n getErrors(\n translator: Translator,\n errors?: FormSubmissionError[]\n ): FormSubmissionError[] | undefined {\n return this.getFieldErrors(\n (field) => field.getErrors(translator, errors),\n errors\n )\n }\n\n /**\n * Get view errors for all fields in this collection.\n * For most fields this means filtering to the first error in the list.\n * Composite fields like UKAddress can choose to return more than one error.\n */\n getViewErrors(\n translator: Translator,\n errors?: FormSubmissionError[]\n ): FormSubmissionError[] | undefined {\n return this.getFieldErrors(\n (field) => field.getViewErrors(translator, errors),\n errors\n )\n }\n\n getViewModel(context: RenderContext) {\n const { components } = this\n\n const result: ComponentViewModel[] = components.map((component) => {\n const { isFormComponent, type } = component\n\n const model = component.getViewModel(context)\n\n return { type, isFormComponent, model }\n })\n\n return result\n }\n\n overrideParentTitle(\n formSchema: joi.ObjectSchema<FormPayload>,\n translator: Translator | undefined\n ) {\n // Add parent field title to collection field errors\n return formSchema.error((errors) => {\n return errors.flatMap((error) => {\n if (!isErrorContext(error.local) || error.local.title) {\n return error\n }\n\n // Use field key or first missing child field\n let { missing, key = missing?.[0] } = error.local\n\n // But avoid numeric key used by array payloads\n if (typeof key === 'number') {\n key = error.path[0]\n }\n\n // Find the parent field\n const parent = this.fields.find(\n (item) => item.name === key?.split('__').shift()\n )\n\n // Find the child field\n const child = (parent?.collection?.fields ?? this.fields).find(\n (item) => item.name === key\n )\n\n // Update error with child label\n if (child && (!error.local.label || error.local.label === 'value')) {\n error.local.label = child.title\n }\n\n // Fix error summary links for missing fields\n if (missing?.length) {\n error.path = missing\n error.local.key = missing[0]\n }\n\n // Update error with parent title\n if (translator && parent) {\n error.local.title ??= translator.tComponent(\n parent as ComponentDef,\n 'title'\n )\n } else {\n error.local.title ??= parent?.label\n }\n\n return error\n })\n })\n }\n\n /**\n * Validate form payload\n */\n validate(\n value: FormPayload = {},\n translator?: Translator\n ): FormValidationResult<FormPayload> {\n const messages = translator\n ? buildLanguageMessages(translator.t)\n : undefined\n\n // When translating, override Joi labels (and custom schema messages where\n // needed) so #label/#title in message templates resolve in the correct language.\n let schema = this.formSchema\n // Add parent field title to collection field errors\n schema = this.overrideParentTitle(schema, translator)\n\n if (translator) {\n const { t } = translator\n const labelOverrides: Record<string, joi.Schema> = {}\n\n for (const field of this.fields) {\n if (field.collection) {\n // Composite field: translate each sub-field's label using the key constant\n // (e.g. 'components.addressField.line1' → \"Llinell cyfeiriad 1\") and apply\n // any field-type-specific message overrides (e.g. objectMissing for dates).\n const messagesOverride =\n field.getValidationMessagesOverride(translator)\n for (const subField of field.collection.fields) {\n const translatedSubLabel = t(subField.title) || subField.label\n let patchedSchema = subField.formSchema.label(translatedSubLabel)\n if (messagesOverride) {\n patchedSchema = patchedSchema.messages(messagesOverride)\n }\n labelOverrides[subField.name] = patchedSchema\n }\n } else {\n const fieldDef = field.def\n const translatedLabel =\n translator.tComponent(fieldDef, 'errorDescription') ||\n translator.tComponent(fieldDef, 'shortDescription') ||\n translator.tComponent(fieldDef, 'title')\n const messagesOverride =\n field.getValidationMessagesOverride(translator)\n let patchedSchema = field.formSchema\n if (translatedLabel && translatedLabel !== field.label) {\n patchedSchema = patchedSchema.label(translatedLabel)\n }\n if (messagesOverride) {\n patchedSchema = patchedSchema.messages(messagesOverride)\n }\n if (patchedSchema !== field.formSchema) {\n labelOverrides[field.name] = patchedSchema\n }\n }\n }\n\n if (Object.keys(labelOverrides).length) {\n schema = schema.keys(labelOverrides)\n }\n }\n\n const result = schema.validate(value, {\n ...opts,\n ...(messages && { messages })\n })\n\n const details = result.error?.details\n\n return {\n value: (result.value ?? {}) as typeof value,\n errors: this.page?.getErrors(details) ?? getErrors(details)\n }\n }\n\n /**\n * Helper to get errors from all fields\n */\n private getFieldErrors(\n callback: (field: Field) => FormSubmissionError[] | undefined,\n errors?: FormSubmissionError[]\n ): FormSubmissionError[] | undefined {\n const { fields } = this\n\n if (!errors?.length) {\n return\n }\n\n const list: FormSubmissionError[] = []\n\n for (const field of fields) {\n const fieldErrors = callback(field)\n\n if (fieldErrors?.length) {\n list.push(...fieldErrors)\n }\n }\n\n if (!list.length) {\n return\n }\n\n return list\n }\n}\n\n/**\n * Check for field local state\n */\nexport function isErrorContext(\n value?: unknown\n): value is ErrorReportCollection['local'] {\n return isFormState(value) && typeof value.label === 'string'\n}\n"],"mappings":"AACA,OAAOA,GAAG,MAIH,KAAK;AAEZ,SACEC,WAAW,EACXC,WAAW;AAEb,SACEC,eAAe;AASjB,SAASC,SAAS;AAIlB,SACEC,qBAAqB,EACrBC,iBAAiB,IAAIC,IAAI;AAU3B,OAAO,MAAMC,mBAAmB,CAAC;EAC/BC,IAAI;EACJC,MAAM;EAENC,UAAU;EACVC,MAAM;EACNC,QAAQ;EAERC,UAAU;EACVC,WAAW;EAEXC,WAAWA,CACTC,IAAoB,EACpBC,KAIC,EACDC,MAWC,EACD;IACA,MAAMR,UAAU,GAAGM,IAAI,CAACG,GAAG,CAAEC,GAAG,IAAKlB,eAAe,CAACkB,GAAG,EAAEH,KAAK,CAAC,CAAC;IAEjE,MAAMN,MAAM,GAAGD,UAAU,CAACW,MAAM,CAC7BC,SAAS,IAAyBA,SAAS,CAACC,eAC/C,CAAC;IAED,MAAMX,QAAQ,GAAGF,UAAU,CAACW,MAAM,CAC/BC,SAAS,IAA4B,CAACA,SAAS,CAACC,eACnD,CAAC;IAED,IAAIV,UAAU,GAAGd,GAAG,CAACyB,MAAM,CAAc,CAAC,CAACC,QAAQ,CAAC,CAAC;IACrD,IAAIX,WAAW,GAAGf,GAAG,CAACyB,MAAM,CAAsB,CAAC,CAACC,QAAQ,CAAC,CAAC;;IAE9D;IACA,KAAK,MAAMC,KAAK,IAAIf,MAAM,EAAE;MAC1B,MAAM;QAAEgB,UAAU;QAAEC;MAAK,CAAC,GAAGF,KAAK;MAElCb,UAAU,GAAGc,UAAU,GACnBd,UAAU,CAACgB,MAAM,CAACF,UAAU,CAACd,UAAU,CAAC,GACxCA,UAAU,CAACiB,IAAI,CAAC;QAAE,CAACF,IAAI,GAAGF,KAAK,CAACb;MAAW,CAAC,CAAC;MAEjDC,WAAW,GAAGa,UAAU,GACpBb,WAAW,CAACe,MAAM,CAACF,UAAU,CAACb,WAAW,CAAC,GAC1CA,WAAW,CAACgB,IAAI,CAAC;QAAE,CAACF,IAAI,GAAGF,KAAK,CAACZ;MAAY,CAAC,CAAC;IACrD;IAEA,IAAII,MAAM,EAAEa,KAAK,EAAE;MACjBlB,UAAU,GAAGA,UAAU,CAACmB,GAAG,CAAC,GAAGd,MAAM,CAACa,KAAK,EAAE;QAC3CE,SAAS,EAAEhC;MACb,CAAC,CAAC;IACJ;IAEA,IAAIiB,MAAM,EAAEgB,MAAM,EAAE;MAClBrB,UAAU,GAAGA,UAAU,CAACqB,MAAM,CAAChB,MAAM,CAACgB,MAAM,CAAC;IAC/C;IAEA,IAAI,CAAC1B,IAAI,GAAGS,KAAK,CAACT,IAAI;IACtB,IAAI,CAACC,MAAM,GAAGQ,KAAK,CAACR,MAAM;IAE1B,IAAI,CAACC,UAAU,GAAGA,UAAU;IAC5B,IAAI,CAACC,MAAM,GAAGA,MAAM;IACpB,IAAI,CAACC,QAAQ,GAAGA,QAAQ;IAExB,IAAI,CAACC,UAAU,GAAGA,UAAU;IAC5B,IAAI,CAACC,WAAW,GAAGA,WAAW;EAChC;EAEA,IAAIgB,IAAIA,CAAA,EAAG;IACT,OAAO,IAAI,CAACnB,MAAM,CAACwB,OAAO,CAAET,KAAK,IAAK;MACpC,MAAM;QAAEE,IAAI;QAAED;MAAW,CAAC,GAAGD,KAAK;MAElC,IAAIC,UAAU,EAAE;QACd,MAAM;UAAEhB;QAAO,CAAC,GAAGgB,UAAU;QAC7B,OAAO,CAACC,IAAI,EAAE,GAAGjB,MAAM,CAACQ,GAAG,CAAC,CAAC;UAAES;QAAK,CAAC,KAAKA,IAAI,CAAC,CAAC;MAClD;MAEA,OAAO,CAACA,IAAI,CAAC;IACf,CAAC,CAAC;EACJ;EAEAQ,oBAAoBA,CAACC,KAA0B,EAAE;IAC/C,MAAMC,OAAoB,GAAG,CAAC,CAAC;IAE/B,IAAI,CAAC3B,MAAM,CAAC4B,OAAO,CAAEjB,SAAS,IAAK;MACjCkB,MAAM,CAACC,MAAM,CAACH,OAAO,EAAEhB,SAAS,CAACc,oBAAoB,CAACC,KAAK,CAAC,CAAC;IAC/D,CAAC,CAAC;IAEF,OAAOC,OAAO;EAChB;EAEAI,qBAAqBA,CAACL,KAA0B,EAAE;IAChD,MAAMC,OAAoB,GAAG,CAAC,CAAC;;IAE/B;IACA,KAAK,MAAM,CAACV,IAAI,EAAEe,KAAK,CAAC,IAAIH,MAAM,CAACI,OAAO,CACxC,IAAI,CAACR,oBAAoB,CAACC,KAAK,CACjC,CAAC,EAAE;MACD,MAAMQ,GAAG,GAAGjB,IAAI,CAACkB,KAAK,CAAC,IAAI,CAAC,CAACC,GAAG,CAAC,CAAC;MAClC,IAAI,CAACF,GAAG,EAAE;QACR;MACF;MAEAP,OAAO,CAACO,GAAG,CAAC,GAAGF,KAAK;IACtB;IAEA,OAAOL,OAAO;EAChB;EAEAU,qBAAqBA,CAACV,OAAoB,EAAE;IAC1C,MAAMD,KAAgB,GAAG,CAAC,CAAC;IAE3B,IAAI,CAAC1B,MAAM,CAAC4B,OAAO,CAAEjB,SAAS,IAAK;MACjCkB,MAAM,CAACC,MAAM,CAACJ,KAAK,EAAEf,SAAS,CAAC0B,qBAAqB,CAACV,OAAO,CAAC,CAAC;IAChE,CAAC,CAAC;IAEF,OAAOD,KAAK;EACd;EAEAY,wBAAwBA,CAACZ,KAA0B,EAAE;IACnD,MAAMa,OAAkB,GAAG,CAAC,CAAC;IAE7B,KAAK,MAAM5B,SAAS,IAAI,IAAI,CAACX,MAAM,EAAE;MACnCuC,OAAO,CAAC5B,SAAS,CAACM,IAAI,CAAC,GAAGN,SAAS,CAAC2B,wBAAwB,CAACZ,KAAK,CAAC;IACrE;IAEA,OAAOa,OAAO;EAChB;;EAEA;AACF;AACA;EACE/C,SAASA,CACPgD,UAAsB,EACtBC,MAA8B,EACK;IACnC,OAAO,IAAI,CAACC,cAAc,CACvB3B,KAAK,IAAKA,KAAK,CAACvB,SAAS,CAACgD,UAAU,EAAEC,MAAM,CAAC,EAC9CA,MACF,CAAC;EACH;;EAEA;AACF;AACA;AACA;AACA;EACEE,aAAaA,CACXH,UAAsB,EACtBC,MAA8B,EACK;IACnC,OAAO,IAAI,CAACC,cAAc,CACvB3B,KAAK,IAAKA,KAAK,CAAC4B,aAAa,CAACH,UAAU,EAAEC,MAAM,CAAC,EAClDA,MACF,CAAC;EACH;EAEAG,YAAYA,CAACL,OAAsB,EAAE;IACnC,MAAM;MAAExC;IAAW,CAAC,GAAG,IAAI;IAE3B,MAAM8C,MAA4B,GAAG9C,UAAU,CAACS,GAAG,CAAEG,SAAS,IAAK;MACjE,MAAM;QAAEC,eAAe;QAAEkC;MAAK,CAAC,GAAGnC,SAAS;MAE3C,MAAMoC,KAAK,GAAGpC,SAAS,CAACiC,YAAY,CAACL,OAAO,CAAC;MAE7C,OAAO;QAAEO,IAAI;QAAElC,eAAe;QAAEmC;MAAM,CAAC;IACzC,CAAC,CAAC;IAEF,OAAOF,MAAM;EACf;EAEAG,mBAAmBA,CACjB9C,UAAyC,EACzCsC,UAAkC,EAClC;IACA;IACA,OAAOtC,UAAU,CAAC+C,KAAK,CAAER,MAAM,IAAK;MAClC,OAAOA,MAAM,CAACjB,OAAO,CAAEyB,KAAK,IAAK;QAC/B,IAAI,CAACC,cAAc,CAACD,KAAK,CAACE,KAAK,CAAC,IAAIF,KAAK,CAACE,KAAK,CAACC,KAAK,EAAE;UACrD,OAAOH,KAAK;QACd;;QAEA;QACA,IAAI;UAAEI,OAAO;UAAEnB,GAAG,GAAGmB,OAAO,GAAG,CAAC;QAAE,CAAC,GAAGJ,KAAK,CAACE,KAAK;;QAEjD;QACA,IAAI,OAAOjB,GAAG,KAAK,QAAQ,EAAE;UAC3BA,GAAG,GAAGe,KAAK,CAACK,IAAI,CAAC,CAAC,CAAC;QACrB;;QAEA;QACA,MAAMxD,MAAM,GAAG,IAAI,CAACE,MAAM,CAACuD,IAAI,CAC5BC,IAAI,IAAKA,IAAI,CAACvC,IAAI,KAAKiB,GAAG,EAAEC,KAAK,CAAC,IAAI,CAAC,CAACsB,KAAK,CAAC,CACjD,CAAC;;QAED;QACA,MAAMC,KAAK,GAAG,CAAC5D,MAAM,EAAEkB,UAAU,EAAEhB,MAAM,IAAI,IAAI,CAACA,MAAM,EAAEuD,IAAI,CAC3DC,IAAI,IAAKA,IAAI,CAACvC,IAAI,KAAKiB,GAC1B,CAAC;;QAED;QACA,IAAIwB,KAAK,KAAK,CAACT,KAAK,CAACE,KAAK,CAACQ,KAAK,IAAIV,KAAK,CAACE,KAAK,CAACQ,KAAK,KAAK,OAAO,CAAC,EAAE;UAClEV,KAAK,CAACE,KAAK,CAACQ,KAAK,GAAGD,KAAK,CAACN,KAAK;QACjC;;QAEA;QACA,IAAIC,OAAO,EAAEO,MAAM,EAAE;UACnBX,KAAK,CAACK,IAAI,GAAGD,OAAO;UACpBJ,KAAK,CAACE,KAAK,CAACjB,GAAG,GAAGmB,OAAO,CAAC,CAAC,CAAC;QAC9B;;QAEA;QACA,IAAIb,UAAU,IAAI1C,MAAM,EAAE;UACxBmD,KAAK,CAACE,KAAK,CAACC,KAAK,KAAKZ,UAAU,CAACqB,UAAU,CACzC/D,MAAM,EACN,OACF,CAAC;QACH,CAAC,MAAM;UACLmD,KAAK,CAACE,KAAK,CAACC,KAAK,KAAKtD,MAAM,EAAE6D,KAAK;QACrC;QAEA,OAAOV,KAAK;MACd,CAAC,CAAC;IACJ,CAAC,CAAC;EACJ;;EAEA;AACF;AACA;EACEa,QAAQA,CACN9B,KAAkB,GAAG,CAAC,CAAC,EACvBQ,UAAuB,EACY;IACnC,MAAMuB,QAAQ,GAAGvB,UAAU,GACvB/C,qBAAqB,CAAC+C,UAAU,CAACwB,CAAC,CAAC,GACnCC,SAAS;;IAEb;IACA;IACA,IAAI1D,MAAM,GAAG,IAAI,CAACL,UAAU;IAC5B;IACAK,MAAM,GAAG,IAAI,CAACyC,mBAAmB,CAACzC,MAAM,EAAEiC,UAAU,CAAC;IAErD,IAAIA,UAAU,EAAE;MACd,MAAM;QAAEwB;MAAE,CAAC,GAAGxB,UAAU;MACxB,MAAM0B,cAA0C,GAAG,CAAC,CAAC;MAErD,KAAK,MAAMnD,KAAK,IAAI,IAAI,CAACf,MAAM,EAAE;QAC/B,IAAIe,KAAK,CAACC,UAAU,EAAE;UACpB;UACA;UACA;UACA,MAAMmD,gBAAgB,GACpBpD,KAAK,CAACqD,6BAA6B,CAAC5B,UAAU,CAAC;UACjD,KAAK,MAAM6B,QAAQ,IAAItD,KAAK,CAACC,UAAU,CAAChB,MAAM,EAAE;YAC9C,MAAMsE,kBAAkB,GAAGN,CAAC,CAACK,QAAQ,CAACjB,KAAK,CAAC,IAAIiB,QAAQ,CAACV,KAAK;YAC9D,IAAIY,aAAa,GAAGF,QAAQ,CAACnE,UAAU,CAACyD,KAAK,CAACW,kBAAkB,CAAC;YACjE,IAAIH,gBAAgB,EAAE;cACpBI,aAAa,GAAGA,aAAa,CAACR,QAAQ,CAACI,gBAAgB,CAAC;YAC1D;YACAD,cAAc,CAACG,QAAQ,CAACpD,IAAI,CAAC,GAAGsD,aAAa;UAC/C;QACF,CAAC,MAAM;UACL,MAAMC,QAAQ,GAAGzD,KAAK,CAACN,GAAG;UAC1B,MAAMgE,eAAe,GACnBjC,UAAU,CAACqB,UAAU,CAACW,QAAQ,EAAE,kBAAkB,CAAC,IACnDhC,UAAU,CAACqB,UAAU,CAACW,QAAQ,EAAE,kBAAkB,CAAC,IACnDhC,UAAU,CAACqB,UAAU,CAACW,QAAQ,EAAE,OAAO,CAAC;UAC1C,MAAML,gBAAgB,GACpBpD,KAAK,CAACqD,6BAA6B,CAAC5B,UAAU,CAAC;UACjD,IAAI+B,aAAa,GAAGxD,KAAK,CAACb,UAAU;UACpC,IAAIuE,eAAe,IAAIA,eAAe,KAAK1D,KAAK,CAAC4C,KAAK,EAAE;YACtDY,aAAa,GAAGA,aAAa,CAACZ,KAAK,CAACc,eAAe,CAAC;UACtD;UACA,IAAIN,gBAAgB,EAAE;YACpBI,aAAa,GAAGA,aAAa,CAACR,QAAQ,CAACI,gBAAgB,CAAC;UAC1D;UACA,IAAII,aAAa,KAAKxD,KAAK,CAACb,UAAU,EAAE;YACtCgE,cAAc,CAACnD,KAAK,CAACE,IAAI,CAAC,GAAGsD,aAAa;UAC5C;QACF;MACF;MAEA,IAAI1C,MAAM,CAACV,IAAI,CAAC+C,cAAc,CAAC,CAACN,MAAM,EAAE;QACtCrD,MAAM,GAAGA,MAAM,CAACY,IAAI,CAAC+C,cAAc,CAAC;MACtC;IACF;IAEA,MAAMrB,MAAM,GAAGtC,MAAM,CAACuD,QAAQ,CAAC9B,KAAK,EAAE;MACpC,GAAGrC,IAAI;MACP,IAAIoE,QAAQ,IAAI;QAAEA;MAAS,CAAC;IAC9B,CAAC,CAAC;IAEF,MAAMW,OAAO,GAAG7B,MAAM,CAACI,KAAK,EAAEyB,OAAO;IAErC,OAAO;MACL1C,KAAK,EAAGa,MAAM,CAACb,KAAK,IAAI,CAAC,CAAkB;MAC3CS,MAAM,EAAE,IAAI,CAAC5C,IAAI,EAAEL,SAAS,CAACkF,OAAO,CAAC,IAAIlF,SAAS,CAACkF,OAAO;IAC5D,CAAC;EACH;;EAEA;AACF;AACA;EACUhC,cAAcA,CACpBiC,QAA6D,EAC7DlC,MAA8B,EACK;IACnC,MAAM;MAAEzC;IAAO,CAAC,GAAG,IAAI;IAEvB,IAAI,CAACyC,MAAM,EAAEmB,MAAM,EAAE;MACnB;IACF;IAEA,MAAMgB,IAA2B,GAAG,EAAE;IAEtC,KAAK,MAAM7D,KAAK,IAAIf,MAAM,EAAE;MAC1B,MAAM6E,WAAW,GAAGF,QAAQ,CAAC5D,KAAK,CAAC;MAEnC,IAAI8D,WAAW,EAAEjB,MAAM,EAAE;QACvBgB,IAAI,CAACE,IAAI,CAAC,GAAGD,WAAW,CAAC;MAC3B;IACF;IAEA,IAAI,CAACD,IAAI,CAAChB,MAAM,EAAE;MAChB;IACF;IAEA,OAAOgB,IAAI;EACb;AACF;;AAEA;AACA;AACA;AACA,OAAO,SAAS1B,cAAcA,CAC5BlB,KAAe,EAC0B;EACzC,OAAO3C,WAAW,CAAC2C,KAAK,CAAC,IAAI,OAAOA,KAAK,CAAC2B,KAAK,KAAK,QAAQ;AAC9D","ignoreList":[]}
|
|
@@ -93,7 +93,7 @@ export class DeclarationField extends FormComponent {
|
|
|
93
93
|
hint,
|
|
94
94
|
declarationConfirmationLabel = t('components.declarationField.defaultLabel')
|
|
95
95
|
} = this;
|
|
96
|
-
const content = tComponent(this, 'content');
|
|
96
|
+
const content = tComponent(this.def, 'content');
|
|
97
97
|
const viewModel = super.getViewModel(context);
|
|
98
98
|
let {
|
|
99
99
|
fieldset,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeclarationField.js","names":["ComponentType","hasFormComponents","isFormType","joi","FormComponent","isFormValue","buildValidationMessages","messageTemplate","DeclarationField","headerStartLevel","constructor","def","props","options","content","checkboxSchema","string","valid","required","formSchema","array","items","strip","label","single","messages","declarationRequired","stateSchema","boolean","cast","declarationConfirmationLabel","formComponents","page","pageDef","components","numOfQuestionsOnPage","filter","q","type","length","hasGuidance","some","comp","idx","Markdown","getFormValueFromState","state","name","getFormDataFromState","getStateFromValidForm","payload","payloadValue","value","isValue","every","v","getContextValueFromFormValue","getFormValue","undefined","getValidationMessagesOverride","translator","t","msg","getDisplayStringFromFormValue","getViewModel","context","tComponent","hint","viewModel","fieldset","legend","text","classes","isChecked","Array","isArray","x","checked","getAllPossibleErrors","baseErrors","template","advancedSettingsErrors","isBool"],"sources":["../../../../../src/server/plugins/engine/components/DeclarationField.ts"],"sourcesContent":["import {\n ComponentType,\n hasFormComponents,\n isFormType,\n type ComponentDef,\n type DeclarationFieldComponent,\n type Item\n} from '@defra/forms-model'\nimport joi, {\n type ArraySchema,\n type BooleanSchema,\n type LanguageMessages,\n type StringSchema\n} from 'joi'\n\nimport {\n FormComponent,\n isFormValue\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { type RenderContext } from '~/src/server/plugins/engine/components/types.js'\nimport { buildValidationMessages } from '~/src/server/plugins/engine/i18n/buildValidationMessages.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport { messageTemplate } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\nimport {\n type ErrorMessageTemplateList,\n type FormPayload,\n type FormState,\n type FormStateValue,\n type FormSubmissionState,\n type FormValue\n} from '~/src/server/plugins/engine/types.js'\n\nexport class DeclarationField extends FormComponent {\n declare options: DeclarationFieldComponent['options']\n\n declare declarationConfirmationLabel: string | undefined\n\n declare formSchema: ArraySchema<StringSchema[]>\n declare stateSchema: BooleanSchema\n declare content: string\n headerStartLevel: number\n\n constructor(\n def: DeclarationFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n const { options, content } = def\n\n let checkboxSchema = joi.string().valid('true')\n\n if (options.required !== false) {\n checkboxSchema = checkboxSchema.required()\n }\n\n const formSchema = joi\n .array()\n .items(checkboxSchema, joi.string().valid('unchecked').strip())\n .label(this.label)\n .single()\n .messages({\n 'any.required': messageTemplate.declarationRequired as string,\n 'any.unknown': messageTemplate.declarationRequired as string,\n 'array.includesRequiredUnknowns':\n messageTemplate.declarationRequired as string\n }) as ArraySchema<StringSchema[]>\n\n this.formSchema = formSchema\n this.stateSchema = joi.boolean().cast('string').label(this.label).required()\n\n this.options = options\n this.content = content\n // Store only the form-authored label (if provided). If absent, getViewModel\n // resolves the default via t() at render time so the correct language is used.\n this.declarationConfirmationLabel = options.declarationConfirmationLabel\n const formComponents = hasFormComponents(props.page?.pageDef)\n ? props.page.pageDef.components\n : []\n const numOfQuestionsOnPage = formComponents.filter((q) =>\n isFormType(q.type)\n ).length\n const hasGuidance = formComponents.some(\n (comp, idx) => comp.type === ComponentType.Markdown && idx === 0\n )\n this.headerStartLevel = numOfQuestionsOnPage < 2 && !hasGuidance ? 2 : 3\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const { name } = this\n return state[name] === true ? 'true' : 'false'\n }\n\n getFormDataFromState(state: FormSubmissionState): FormPayload {\n const { name } = this\n return { [name]: state[name] === true ? 'true' : 'false' }\n }\n\n getStateFromValidForm(payload: FormPayload): FormState {\n const { name } = this\n const payloadValue = payload[name]\n const value =\n this.isValue(payloadValue) &&\n payloadValue.length > 0 &&\n payloadValue.every((v) => {\n return v === 'true'\n })\n\n return { [name]: value }\n }\n\n getContextValueFromFormValue(value: FormValue | FormPayload): boolean {\n return value === 'true'\n }\n\n getFormValue(value?: FormStateValue | FormState) {\n return this.isValue(value) ? value : undefined\n }\n\n getValidationMessagesOverride(translator: Translator) {\n const { declarationRequired } = buildValidationMessages(translator.t)\n const msg = declarationRequired as unknown as string\n return {\n 'any.required': msg,\n 'any.unknown': msg,\n 'array.includesRequiredUnknowns': msg\n } as unknown as LanguageMessages\n }\n\n getDisplayStringFromFormValue(\n value: FormValue | FormPayload,\n translator: Translator\n ): string {\n const { t } = translator\n return value === 'true'\n ? (this.declarationConfirmationLabel ??\n t('components.declarationField.defaultLabel'))\n : t('components.declarationField.notProvided')\n }\n\n getViewModel(context: RenderContext) {\n const { payload } = context\n const { t, tComponent } = context.translator\n\n const {\n hint,\n declarationConfirmationLabel = t(\n 'components.declarationField.defaultLabel'\n )\n } = this\n const content = tComponent(this as unknown as ComponentDef, 'content')\n\n const viewModel = super.getViewModel(context)\n let { fieldset, label } = viewModel\n\n fieldset ??= {\n legend: {\n text: label.text,\n classes: 'govuk-fieldset__legend--m'\n }\n }\n\n const payloadValue = payload[this.name]\n const isChecked =\n payloadValue === 'true' ||\n payloadValue === true ||\n (Array.isArray(payloadValue) && payloadValue.some((x) => x === 'true'))\n\n return {\n ...viewModel,\n hint: hint ? { text: hint } : undefined,\n fieldset,\n content,\n items: [\n {\n text: declarationConfirmationLabel,\n value: 'true',\n checked: isChecked\n }\n ],\n headerStartLevel: this.headerStartLevel\n }\n }\n\n isValue(value?: FormStateValue | FormState): value is Item['value'][] {\n if (!Array.isArray(value)) {\n return false\n }\n\n // Skip checks when empty\n if (!value.length) {\n return true\n }\n\n return value.every(isFormValue)\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return DeclarationField.getAllPossibleErrors()\n }\n\n /**\n * Static version of getAllPossibleErrors that doesn't require a component instance.\n */\n static getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [\n { type: 'required', template: messageTemplate.declarationRequired }\n ],\n advancedSettingsErrors: []\n }\n }\n\n static isBool(value?: FormStateValue | FormState): value is boolean {\n return isFormValue(value) && typeof value === 'boolean'\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"DeclarationField.js","names":["ComponentType","hasFormComponents","isFormType","joi","FormComponent","isFormValue","buildValidationMessages","messageTemplate","DeclarationField","headerStartLevel","constructor","def","props","options","content","checkboxSchema","string","valid","required","formSchema","array","items","strip","label","single","messages","declarationRequired","stateSchema","boolean","cast","declarationConfirmationLabel","formComponents","page","pageDef","components","numOfQuestionsOnPage","filter","q","type","length","hasGuidance","some","comp","idx","Markdown","getFormValueFromState","state","name","getFormDataFromState","getStateFromValidForm","payload","payloadValue","value","isValue","every","v","getContextValueFromFormValue","getFormValue","undefined","getValidationMessagesOverride","translator","t","msg","getDisplayStringFromFormValue","getViewModel","context","tComponent","hint","viewModel","fieldset","legend","text","classes","isChecked","Array","isArray","x","checked","getAllPossibleErrors","baseErrors","template","advancedSettingsErrors","isBool"],"sources":["../../../../../src/server/plugins/engine/components/DeclarationField.ts"],"sourcesContent":["import {\n ComponentType,\n hasFormComponents,\n isFormType,\n type DeclarationFieldComponent,\n type Item\n} from '@defra/forms-model'\nimport joi, {\n type ArraySchema,\n type BooleanSchema,\n type LanguageMessages,\n type StringSchema\n} from 'joi'\n\nimport {\n FormComponent,\n isFormValue\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { type RenderContext } from '~/src/server/plugins/engine/components/types.js'\nimport { buildValidationMessages } from '~/src/server/plugins/engine/i18n/buildValidationMessages.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport { messageTemplate } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\nimport {\n type ErrorMessageTemplateList,\n type FormPayload,\n type FormState,\n type FormStateValue,\n type FormSubmissionState,\n type FormValue\n} from '~/src/server/plugins/engine/types.js'\n\nexport class DeclarationField extends FormComponent {\n declare options: DeclarationFieldComponent['options']\n\n declare declarationConfirmationLabel: string | undefined\n\n declare formSchema: ArraySchema<StringSchema[]>\n declare stateSchema: BooleanSchema\n declare content: string\n headerStartLevel: number\n\n constructor(\n def: DeclarationFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n const { options, content } = def\n\n let checkboxSchema = joi.string().valid('true')\n\n if (options.required !== false) {\n checkboxSchema = checkboxSchema.required()\n }\n\n const formSchema = joi\n .array()\n .items(checkboxSchema, joi.string().valid('unchecked').strip())\n .label(this.label)\n .single()\n .messages({\n 'any.required': messageTemplate.declarationRequired as string,\n 'any.unknown': messageTemplate.declarationRequired as string,\n 'array.includesRequiredUnknowns':\n messageTemplate.declarationRequired as string\n }) as ArraySchema<StringSchema[]>\n\n this.formSchema = formSchema\n this.stateSchema = joi.boolean().cast('string').label(this.label).required()\n\n this.options = options\n this.content = content\n // Store only the form-authored label (if provided). If absent, getViewModel\n // resolves the default via t() at render time so the correct language is used.\n this.declarationConfirmationLabel = options.declarationConfirmationLabel\n const formComponents = hasFormComponents(props.page?.pageDef)\n ? props.page.pageDef.components\n : []\n const numOfQuestionsOnPage = formComponents.filter((q) =>\n isFormType(q.type)\n ).length\n const hasGuidance = formComponents.some(\n (comp, idx) => comp.type === ComponentType.Markdown && idx === 0\n )\n this.headerStartLevel = numOfQuestionsOnPage < 2 && !hasGuidance ? 2 : 3\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const { name } = this\n return state[name] === true ? 'true' : 'false'\n }\n\n getFormDataFromState(state: FormSubmissionState): FormPayload {\n const { name } = this\n return { [name]: state[name] === true ? 'true' : 'false' }\n }\n\n getStateFromValidForm(payload: FormPayload): FormState {\n const { name } = this\n const payloadValue = payload[name]\n const value =\n this.isValue(payloadValue) &&\n payloadValue.length > 0 &&\n payloadValue.every((v) => {\n return v === 'true'\n })\n\n return { [name]: value }\n }\n\n getContextValueFromFormValue(value: FormValue | FormPayload): boolean {\n return value === 'true'\n }\n\n getFormValue(value?: FormStateValue | FormState) {\n return this.isValue(value) ? value : undefined\n }\n\n getValidationMessagesOverride(translator: Translator) {\n const { declarationRequired } = buildValidationMessages(translator.t)\n const msg = declarationRequired as unknown as string\n return {\n 'any.required': msg,\n 'any.unknown': msg,\n 'array.includesRequiredUnknowns': msg\n } as unknown as LanguageMessages\n }\n\n getDisplayStringFromFormValue(\n value: FormValue | FormPayload,\n translator: Translator\n ): string {\n const { t } = translator\n return value === 'true'\n ? (this.declarationConfirmationLabel ??\n t('components.declarationField.defaultLabel'))\n : t('components.declarationField.notProvided')\n }\n\n getViewModel(context: RenderContext) {\n const { payload } = context\n const { t, tComponent } = context.translator\n\n const {\n hint,\n declarationConfirmationLabel = t(\n 'components.declarationField.defaultLabel'\n )\n } = this\n const content = tComponent(this.def, 'content')\n\n const viewModel = super.getViewModel(context)\n let { fieldset, label } = viewModel\n\n fieldset ??= {\n legend: {\n text: label.text,\n classes: 'govuk-fieldset__legend--m'\n }\n }\n\n const payloadValue = payload[this.name]\n const isChecked =\n payloadValue === 'true' ||\n payloadValue === true ||\n (Array.isArray(payloadValue) && payloadValue.some((x) => x === 'true'))\n\n return {\n ...viewModel,\n hint: hint ? { text: hint } : undefined,\n fieldset,\n content,\n items: [\n {\n text: declarationConfirmationLabel,\n value: 'true',\n checked: isChecked\n }\n ],\n headerStartLevel: this.headerStartLevel\n }\n }\n\n isValue(value?: FormStateValue | FormState): value is Item['value'][] {\n if (!Array.isArray(value)) {\n return false\n }\n\n // Skip checks when empty\n if (!value.length) {\n return true\n }\n\n return value.every(isFormValue)\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return DeclarationField.getAllPossibleErrors()\n }\n\n /**\n * Static version of getAllPossibleErrors that doesn't require a component instance.\n */\n static getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [\n { type: 'required', template: messageTemplate.declarationRequired }\n ],\n advancedSettingsErrors: []\n }\n }\n\n static isBool(value?: FormStateValue | FormState): value is boolean {\n return isFormValue(value) && typeof value === 'boolean'\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -128,12 +128,12 @@ export class FormComponent extends ComponentBase {
|
|
|
128
128
|
} = translator;
|
|
129
129
|
const isRequired = !('required' in options) || options.required !== false;
|
|
130
130
|
const hideOptional = 'optionalText' in options && options.optionalText;
|
|
131
|
-
const resolvedTitle = tComponent(this, 'title') || title;
|
|
131
|
+
const resolvedTitle = tComponent(this.def, 'title') || title;
|
|
132
132
|
const optionalTag = !isRequired && !hideOptional ? ` ${t('common.optional')}` : '';
|
|
133
133
|
const label = `${resolvedTitle}${optionalTag}`;
|
|
134
134
|
if (hint) {
|
|
135
135
|
viewModel.hint = {
|
|
136
|
-
text: tComponent(this, 'hint') || hint
|
|
136
|
+
text: tComponent(this.def, 'hint') || hint
|
|
137
137
|
};
|
|
138
138
|
}
|
|
139
139
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormComponent.js","names":["ComponentBase","FormComponent","type","hint","label","summaryLabel","isFormComponent","isAppendageStateSingleObject","constructor","def","props","getLabel","getSummaryLabel","errorDescription","shortDescription","title","keys","collection","name","fields","map","getFormDataFromState","state","getFormValue","getFormValueFromState","value","isValue","undefined","getStateFromValidForm","payload","getErrors","_translator","errors","list","filter","error","path","includes","length","getFirstError","translator","getViewErrors","firstError","getValidationMessagesOverride","getViewModel","isForceAccess","_isForceAccess","options","viewModel","t","tComponent","isRequired","required","hideOptional","optionalText","resolvedTitle","optionalTag","text","componentErrors","componentError","errorMessage","id","getDisplayStringFromFormValue","toString","getDisplayStringFromState","getContextValueFromFormValue","isState","values","Object","isFormValue","Array","isArray","getContextValueFromState","isFormState","getAllPossibleErrors","baseErrors","advancedSettingsErrors","onSubmit","_request","_metadata","_context","Promise","resolve","isRepeatState","every","isRepeatValue","itemId","isUploadState","isUploadValue","isGeospatialState","isGeospatialValue","uploadId"],"sources":["../../../../../src/server/plugins/engine/components/FormComponent.ts"],"sourcesContent":["import {\n type ComponentDef,\n type FormComponentsDef,\n type FormMetadata,\n type Item\n} from '@defra/forms-model'\nimport { type LanguageMessages } from 'joi'\n\nimport { ComponentBase } from '~/src/server/plugins/engine/components/ComponentBase.js'\nimport { type RenderContext } from '~/src/server/plugins/engine/components/types.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport {\n type FormContext,\n type FormRequestPayload\n} from '~/src/server/plugins/engine/types/index.js'\nimport {\n type ErrorMessageTemplateList,\n type Feature,\n type FileState,\n type FormPayload,\n type FormState,\n type FormStateValue,\n type FormSubmissionError,\n type FormSubmissionState,\n type FormValue,\n type GeospatialState,\n type RepeatItemState,\n type RepeatListState,\n type UploadState\n} from '~/src/server/plugins/engine/types.js'\n\nexport class FormComponent extends ComponentBase {\n type: FormComponentsDef['type']\n hint: FormComponentsDef['hint']\n label: string\n summaryLabel: string\n\n isFormComponent = true\n isAppendageStateSingleObject = false\n\n constructor(\n def: FormComponentsDef,\n props: ConstructorParameters<typeof ComponentBase>[1]\n ) {\n super(def, props)\n\n const { hint, type } = def\n\n this.type = type\n this.hint = hint\n\n this.label = this.getLabel(def)\n this.summaryLabel = this.getSummaryLabel(def)\n }\n\n getLabel(def: FormComponentsDef) {\n if ('errorDescription' in def && def.errorDescription) {\n return def.errorDescription\n }\n\n return this.getSummaryLabel(def)\n }\n\n getSummaryLabel(def: FormComponentsDef) {\n if ('shortDescription' in def && def.shortDescription) {\n return def.shortDescription\n }\n\n return def.title\n }\n\n get keys() {\n const { collection, name } = this\n\n if (collection) {\n const { fields } = collection\n return [name, ...fields.map(({ name }) => name)]\n }\n\n return [name]\n }\n\n getFormDataFromState(state: FormSubmissionState): FormPayload {\n const { collection, name } = this\n\n if (collection) {\n return collection.getFormDataFromState(state)\n }\n\n return {\n [name]: this.getFormValue(state[name])\n }\n }\n\n getFormValueFromState(state: FormSubmissionState): FormValue | FormPayload {\n const { collection, name } = this\n\n if (collection) {\n return collection.getFormValueFromState(state)\n }\n\n return this.getFormValue(state[name])\n }\n\n getFormValue(value?: FormStateValue | FormState) {\n return this.isValue(value) ? value : undefined\n }\n\n getStateFromValidForm(payload: FormPayload): FormState {\n const { collection, name } = this\n\n if (collection) {\n return collection.getStateFromValidForm(payload)\n }\n\n return {\n [name]: this.getFormValue(payload[name]) ?? null\n }\n }\n\n getErrors(\n _translator: Translator,\n errors?: FormSubmissionError[]\n ): FormSubmissionError[] | undefined {\n const { name } = this\n\n // Filter component and child errors only\n const list = errors?.filter(\n (error) =>\n error.name === name ||\n error.path.includes(name) ||\n this.keys.includes(error.name)\n )\n\n if (!list?.length) {\n return\n }\n\n return list\n }\n\n getFirstError(\n translator: Translator,\n errors?: FormSubmissionError[]\n ): FormSubmissionError | undefined {\n return this.getErrors(translator, errors)?.[0]\n }\n\n getViewErrors(\n translator: Translator,\n errors?: FormSubmissionError[]\n ): FormSubmissionError[] | undefined {\n const firstError = this.getFirstError(translator, errors)\n return firstError && [firstError]\n }\n\n /**\n * Override in composite fields to return translated Joi message overrides for\n * their sub-fields, applied at validation time so schema-level English messages\n * are replaced with the correct language. Return null to skip message patching.\n */\n getValidationMessagesOverride(\n _translator: Translator\n ): LanguageMessages | null {\n return null\n }\n\n getViewModel({\n payload,\n errors,\n translator,\n isForceAccess: _isForceAccess = false\n }: RenderContext) {\n const { hint, name, options = {}, title, viewModel } = this\n\n const { t, tComponent } = translator\n\n const isRequired = !('required' in options) || options.required !== false\n const hideOptional = 'optionalText' in options && options.optionalText\n\n const resolvedTitle =\n tComponent(this as unknown as ComponentDef, 'title') || title\n const optionalTag =\n !isRequired && !hideOptional ? ` ${t('common.optional')}` : ''\n const label = `${resolvedTitle}${optionalTag}`\n\n if (hint) {\n viewModel.hint = {\n text: tComponent(this as unknown as ComponentDef, 'hint') || hint\n }\n }\n\n // Filter component errors only\n const componentErrors = this.getErrors(translator, errors)\n const componentError = this.getFirstError(translator, componentErrors)\n\n if (componentErrors) {\n viewModel.errors = componentErrors\n }\n\n if (componentError) {\n viewModel.errorMessage = {\n text: componentError.text\n }\n }\n\n return {\n ...viewModel,\n label: {\n text: label\n },\n id: name,\n name,\n value: payload[name]\n }\n }\n\n getDisplayStringFromFormValue(\n value: FormValue | FormPayload,\n _translator: Translator\n ): string {\n // Map selected values to text\n // eslint-disable-next-line @typescript-eslint/no-base-to-string\n return this.isValue(value) ? value.toString() : ''\n }\n\n getDisplayStringFromState(\n state: FormSubmissionState,\n translator: Translator\n ): string {\n const value = this.getFormValueFromState(state)\n return this.getDisplayStringFromFormValue(value, translator)\n }\n\n getContextValueFromFormValue(\n value: FormValue | FormPayload\n ): Item['value'] | Item['value'][] | null {\n // Filter object field values\n if (this.isState(value)) {\n const values = Object.values(value).filter(isFormValue)\n return values.length ? values : null\n }\n\n // Filter array field values\n if (this.isValue(value) && Array.isArray(value)) {\n return value.filter(isFormValue)\n }\n\n return this.isValue(value) ? value : null\n }\n\n getContextValueFromState(\n state: FormSubmissionState\n ): Item['value'] | Item['value'][] | null {\n const value = this.getFormValueFromState(state)\n\n return this.getContextValueFromFormValue(value)\n }\n\n isValue(\n value?: FormStateValue | FormState\n ): value is NonNullable<FormStateValue> {\n return isFormValue(value)\n }\n\n isState(value?: FormStateValue | FormState): value is FormState {\n return isFormState(value)\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return FormComponent.getAllPossibleErrors()\n }\n\n /**\n * Static version of getAllPossibleErrors that doesn't require a component instance.\n */\n static getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [],\n advancedSettingsErrors: []\n }\n }\n\n onSubmit(\n _request: FormRequestPayload,\n _metadata: FormMetadata,\n _context: FormContext\n ): Promise<void> {\n return Promise.resolve()\n }\n}\n\n/**\n * Check for form value\n */\nexport function isFormValue(\n value?: unknown\n): value is string | number | boolean {\n return (\n (typeof value === 'string' && value.length > 0) ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n )\n}\n\n/**\n * Check for form state with nested values\n */\nexport function isFormState(value?: unknown): value is FormState {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n return false\n }\n\n // Skip empty objects\n return !!Object.values(value).length\n}\n\n/**\n * Check for repeat list state\n */\nexport function isRepeatState(value?: unknown): value is RepeatListState {\n if (!Array.isArray(value)) {\n return false\n }\n\n // Skip checks when empty\n if (!value.length) {\n return true\n }\n\n return value.every(isRepeatValue)\n}\n\n/**\n * Check for repeat list value\n */\nexport function isRepeatValue(value?: unknown): value is RepeatItemState {\n return isFormState(value) && typeof value.itemId === 'string'\n}\n\n/**\n * Check for upload state\n */\nexport function isUploadState(value?: unknown): value is UploadState {\n if (!Array.isArray(value)) {\n return false\n }\n\n // Skip checks when empty\n if (!value.length) {\n return true\n }\n\n return value.every(isUploadValue)\n}\n\n/**\n * Check for geospatial state\n */\nexport function isGeospatialState(value?: unknown): value is GeospatialState {\n if (!Array.isArray(value)) {\n return false\n }\n\n // Skip checks when empty\n if (!value.length) {\n return true\n }\n\n return value.every(isGeospatialValue)\n}\n\n/**\n * Check for upload state value\n */\nexport function isUploadValue(value?: unknown): value is FileState {\n return isFormState(value) && typeof value.uploadId === 'string'\n}\n\n/**\n * Check for geospatial state value\n */\nexport function isGeospatialValue(value?: unknown): value is Feature {\n return (\n isFormState(value) &&\n typeof value.type === 'string' &&\n value.type === 'Feature'\n )\n}\n"],"mappings":"AAQA,SAASA,aAAa;AAuBtB,OAAO,MAAMC,aAAa,SAASD,aAAa,CAAC;EAC/CE,IAAI;EACJC,IAAI;EACJC,KAAK;EACLC,YAAY;EAEZC,eAAe,GAAG,IAAI;EACtBC,4BAA4B,GAAG,KAAK;EAEpCC,WAAWA,CACTC,GAAsB,EACtBC,KAAqD,EACrD;IACA,KAAK,CAACD,GAAG,EAAEC,KAAK,CAAC;IAEjB,MAAM;MAAEP,IAAI;MAAED;IAAK,CAAC,GAAGO,GAAG;IAE1B,IAAI,CAACP,IAAI,GAAGA,IAAI;IAChB,IAAI,CAACC,IAAI,GAAGA,IAAI;IAEhB,IAAI,CAACC,KAAK,GAAG,IAAI,CAACO,QAAQ,CAACF,GAAG,CAAC;IAC/B,IAAI,CAACJ,YAAY,GAAG,IAAI,CAACO,eAAe,CAACH,GAAG,CAAC;EAC/C;EAEAE,QAAQA,CAACF,GAAsB,EAAE;IAC/B,IAAI,kBAAkB,IAAIA,GAAG,IAAIA,GAAG,CAACI,gBAAgB,EAAE;MACrD,OAAOJ,GAAG,CAACI,gBAAgB;IAC7B;IAEA,OAAO,IAAI,CAACD,eAAe,CAACH,GAAG,CAAC;EAClC;EAEAG,eAAeA,CAACH,GAAsB,EAAE;IACtC,IAAI,kBAAkB,IAAIA,GAAG,IAAIA,GAAG,CAACK,gBAAgB,EAAE;MACrD,OAAOL,GAAG,CAACK,gBAAgB;IAC7B;IAEA,OAAOL,GAAG,CAACM,KAAK;EAClB;EAEA,IAAIC,IAAIA,CAAA,EAAG;IACT,MAAM;MAAEC,UAAU;MAAEC;IAAK,CAAC,GAAG,IAAI;IAEjC,IAAID,UAAU,EAAE;MACd,MAAM;QAAEE;MAAO,CAAC,GAAGF,UAAU;MAC7B,OAAO,CAACC,IAAI,EAAE,GAAGC,MAAM,CAACC,GAAG,CAAC,CAAC;QAAEF;MAAK,CAAC,KAAKA,IAAI,CAAC,CAAC;IAClD;IAEA,OAAO,CAACA,IAAI,CAAC;EACf;EAEAG,oBAAoBA,CAACC,KAA0B,EAAe;IAC5D,MAAM;MAAEL,UAAU;MAAEC;IAAK,CAAC,GAAG,IAAI;IAEjC,IAAID,UAAU,EAAE;MACd,OAAOA,UAAU,CAACI,oBAAoB,CAACC,KAAK,CAAC;IAC/C;IAEA,OAAO;MACL,CAACJ,IAAI,GAAG,IAAI,CAACK,YAAY,CAACD,KAAK,CAACJ,IAAI,CAAC;IACvC,CAAC;EACH;EAEAM,qBAAqBA,CAACF,KAA0B,EAA2B;IACzE,MAAM;MAAEL,UAAU;MAAEC;IAAK,CAAC,GAAG,IAAI;IAEjC,IAAID,UAAU,EAAE;MACd,OAAOA,UAAU,CAACO,qBAAqB,CAACF,KAAK,CAAC;IAChD;IAEA,OAAO,IAAI,CAACC,YAAY,CAACD,KAAK,CAACJ,IAAI,CAAC,CAAC;EACvC;EAEAK,YAAYA,CAACE,KAAkC,EAAE;IAC/C,OAAO,IAAI,CAACC,OAAO,CAACD,KAAK,CAAC,GAAGA,KAAK,GAAGE,SAAS;EAChD;EAEAC,qBAAqBA,CAACC,OAAoB,EAAa;IACrD,MAAM;MAAEZ,UAAU;MAAEC;IAAK,CAAC,GAAG,IAAI;IAEjC,IAAID,UAAU,EAAE;MACd,OAAOA,UAAU,CAACW,qBAAqB,CAACC,OAAO,CAAC;IAClD;IAEA,OAAO;MACL,CAACX,IAAI,GAAG,IAAI,CAACK,YAAY,CAACM,OAAO,CAACX,IAAI,CAAC,CAAC,IAAI;IAC9C,CAAC;EACH;EAEAY,SAASA,CACPC,WAAuB,EACvBC,MAA8B,EACK;IACnC,MAAM;MAAEd;IAAK,CAAC,GAAG,IAAI;;IAErB;IACA,MAAMe,IAAI,GAAGD,MAAM,EAAEE,MAAM,CACxBC,KAAK,IACJA,KAAK,CAACjB,IAAI,KAAKA,IAAI,IACnBiB,KAAK,CAACC,IAAI,CAACC,QAAQ,CAACnB,IAAI,CAAC,IACzB,IAAI,CAACF,IAAI,CAACqB,QAAQ,CAACF,KAAK,CAACjB,IAAI,CACjC,CAAC;IAED,IAAI,CAACe,IAAI,EAAEK,MAAM,EAAE;MACjB;IACF;IAEA,OAAOL,IAAI;EACb;EAEAM,aAAaA,CACXC,UAAsB,EACtBR,MAA8B,EACG;IACjC,OAAO,IAAI,CAACF,SAAS,CAACU,UAAU,EAAER,MAAM,CAAC,GAAG,CAAC,CAAC;EAChD;EAEAS,aAAaA,CACXD,UAAsB,EACtBR,MAA8B,EACK;IACnC,MAAMU,UAAU,GAAG,IAAI,CAACH,aAAa,CAACC,UAAU,EAAER,MAAM,CAAC;IACzD,OAAOU,UAAU,IAAI,CAACA,UAAU,CAAC;EACnC;;EAEA;AACF;AACA;AACA;AACA;EACEC,6BAA6BA,CAC3BZ,WAAuB,EACE;IACzB,OAAO,IAAI;EACb;EAEAa,YAAYA,CAAC;IACXf,OAAO;IACPG,MAAM;IACNQ,UAAU;IACVK,aAAa,EAAEC,cAAc,GAAG;EACnB,CAAC,EAAE;IAChB,MAAM;MAAE3C,IAAI;MAAEe,IAAI;MAAE6B,OAAO,GAAG,CAAC,CAAC;MAAEhC,KAAK;MAAEiC;IAAU,CAAC,GAAG,IAAI;IAE3D,MAAM;MAAEC,CAAC;MAAEC;IAAW,CAAC,GAAGV,UAAU;IAEpC,MAAMW,UAAU,GAAG,EAAE,UAAU,IAAIJ,OAAO,CAAC,IAAIA,OAAO,CAACK,QAAQ,KAAK,KAAK;IACzE,MAAMC,YAAY,GAAG,cAAc,IAAIN,OAAO,IAAIA,OAAO,CAACO,YAAY;IAEtE,MAAMC,aAAa,GACjBL,UAAU,CAAC,IAAI,EAA6B,OAAO,CAAC,IAAInC,KAAK;IAC/D,MAAMyC,WAAW,GACf,CAACL,UAAU,IAAI,CAACE,YAAY,GAAG,IAAIJ,CAAC,CAAC,iBAAiB,CAAC,EAAE,GAAG,EAAE;IAChE,MAAM7C,KAAK,GAAG,GAAGmD,aAAa,GAAGC,WAAW,EAAE;IAE9C,IAAIrD,IAAI,EAAE;MACR6C,SAAS,CAAC7C,IAAI,GAAG;QACfsD,IAAI,EAAEP,UAAU,CAAC,IAAI,EAA6B,MAAM,CAAC,IAAI/C;MAC/D,CAAC;IACH;;IAEA;IACA,MAAMuD,eAAe,GAAG,IAAI,CAAC5B,SAAS,CAACU,UAAU,EAAER,MAAM,CAAC;IAC1D,MAAM2B,cAAc,GAAG,IAAI,CAACpB,aAAa,CAACC,UAAU,EAAEkB,eAAe,CAAC;IAEtE,IAAIA,eAAe,EAAE;MACnBV,SAAS,CAAChB,MAAM,GAAG0B,eAAe;IACpC;IAEA,IAAIC,cAAc,EAAE;MAClBX,SAAS,CAACY,YAAY,GAAG;QACvBH,IAAI,EAAEE,cAAc,CAACF;MACvB,CAAC;IACH;IAEA,OAAO;MACL,GAAGT,SAAS;MACZ5C,KAAK,EAAE;QACLqD,IAAI,EAAErD;MACR,CAAC;MACDyD,EAAE,EAAE3C,IAAI;MACRA,IAAI;MACJO,KAAK,EAAEI,OAAO,CAACX,IAAI;IACrB,CAAC;EACH;EAEA4C,6BAA6BA,CAC3BrC,KAA8B,EAC9BM,WAAuB,EACf;IACR;IACA;IACA,OAAO,IAAI,CAACL,OAAO,CAACD,KAAK,CAAC,GAAGA,KAAK,CAACsC,QAAQ,CAAC,CAAC,GAAG,EAAE;EACpD;EAEAC,yBAAyBA,CACvB1C,KAA0B,EAC1BkB,UAAsB,EACd;IACR,MAAMf,KAAK,GAAG,IAAI,CAACD,qBAAqB,CAACF,KAAK,CAAC;IAC/C,OAAO,IAAI,CAACwC,6BAA6B,CAACrC,KAAK,EAAEe,UAAU,CAAC;EAC9D;EAEAyB,4BAA4BA,CAC1BxC,KAA8B,EACU;IACxC;IACA,IAAI,IAAI,CAACyC,OAAO,CAACzC,KAAK,CAAC,EAAE;MACvB,MAAM0C,MAAM,GAAGC,MAAM,CAACD,MAAM,CAAC1C,KAAK,CAAC,CAACS,MAAM,CAACmC,WAAW,CAAC;MACvD,OAAOF,MAAM,CAAC7B,MAAM,GAAG6B,MAAM,GAAG,IAAI;IACtC;;IAEA;IACA,IAAI,IAAI,CAACzC,OAAO,CAACD,KAAK,CAAC,IAAI6C,KAAK,CAACC,OAAO,CAAC9C,KAAK,CAAC,EAAE;MAC/C,OAAOA,KAAK,CAACS,MAAM,CAACmC,WAAW,CAAC;IAClC;IAEA,OAAO,IAAI,CAAC3C,OAAO,CAACD,KAAK,CAAC,GAAGA,KAAK,GAAG,IAAI;EAC3C;EAEA+C,wBAAwBA,CACtBlD,KAA0B,EACc;IACxC,MAAMG,KAAK,GAAG,IAAI,CAACD,qBAAqB,CAACF,KAAK,CAAC;IAE/C,OAAO,IAAI,CAAC2C,4BAA4B,CAACxC,KAAK,CAAC;EACjD;EAEAC,OAAOA,CACLD,KAAkC,EACI;IACtC,OAAO4C,WAAW,CAAC5C,KAAK,CAAC;EAC3B;EAEAyC,OAAOA,CAACzC,KAAkC,EAAsB;IAC9D,OAAOgD,WAAW,CAAChD,KAAK,CAAC;EAC3B;;EAEA;AACF;AACA;EACEiD,oBAAoBA,CAAA,EAA6B;IAC/C,OAAOzE,aAAa,CAACyE,oBAAoB,CAAC,CAAC;EAC7C;;EAEA;AACF;AACA;EACE,OAAOA,oBAAoBA,CAAA,EAA6B;IACtD,OAAO;MACLC,UAAU,EAAE,EAAE;MACdC,sBAAsB,EAAE;IAC1B,CAAC;EACH;EAEAC,QAAQA,CACNC,QAA4B,EAC5BC,SAAuB,EACvBC,QAAqB,EACN;IACf,OAAOC,OAAO,CAACC,OAAO,CAAC,CAAC;EAC1B;AACF;;AAEA;AACA;AACA;AACA,OAAO,SAASb,WAAWA,CACzB5C,KAAe,EACqB;EACpC,OACG,OAAOA,KAAK,KAAK,QAAQ,IAAIA,KAAK,CAACa,MAAM,GAAG,CAAC,IAC9C,OAAOb,KAAK,KAAK,QAAQ,IACzB,OAAOA,KAAK,KAAK,SAAS;AAE9B;;AAEA;AACA;AACA;AACA,OAAO,SAASgD,WAAWA,CAAChD,KAAe,EAAsB;EAC/D,IAAIA,KAAK,KAAK,IAAI,IAAI,OAAOA,KAAK,KAAK,QAAQ,IAAI6C,KAAK,CAACC,OAAO,CAAC9C,KAAK,CAAC,EAAE;IACvE,OAAO,KAAK;EACd;;EAEA;EACA,OAAO,CAAC,CAAC2C,MAAM,CAACD,MAAM,CAAC1C,KAAK,CAAC,CAACa,MAAM;AACtC;;AAEA;AACA;AACA;AACA,OAAO,SAAS6C,aAAaA,CAAC1D,KAAe,EAA4B;EACvE,IAAI,CAAC6C,KAAK,CAACC,OAAO,CAAC9C,KAAK,CAAC,EAAE;IACzB,OAAO,KAAK;EACd;;EAEA;EACA,IAAI,CAACA,KAAK,CAACa,MAAM,EAAE;IACjB,OAAO,IAAI;EACb;EAEA,OAAOb,KAAK,CAAC2D,KAAK,CAACC,aAAa,CAAC;AACnC;;AAEA;AACA;AACA;AACA,OAAO,SAASA,aAAaA,CAAC5D,KAAe,EAA4B;EACvE,OAAOgD,WAAW,CAAChD,KAAK,CAAC,IAAI,OAAOA,KAAK,CAAC6D,MAAM,KAAK,QAAQ;AAC/D;;AAEA;AACA;AACA;AACA,OAAO,SAASC,aAAaA,CAAC9D,KAAe,EAAwB;EACnE,IAAI,CAAC6C,KAAK,CAACC,OAAO,CAAC9C,KAAK,CAAC,EAAE;IACzB,OAAO,KAAK;EACd;;EAEA;EACA,IAAI,CAACA,KAAK,CAACa,MAAM,EAAE;IACjB,OAAO,IAAI;EACb;EAEA,OAAOb,KAAK,CAAC2D,KAAK,CAACI,aAAa,CAAC;AACnC;;AAEA;AACA;AACA;AACA,OAAO,SAASC,iBAAiBA,CAAChE,KAAe,EAA4B;EAC3E,IAAI,CAAC6C,KAAK,CAACC,OAAO,CAAC9C,KAAK,CAAC,EAAE;IACzB,OAAO,KAAK;EACd;;EAEA;EACA,IAAI,CAACA,KAAK,CAACa,MAAM,EAAE;IACjB,OAAO,IAAI;EACb;EAEA,OAAOb,KAAK,CAAC2D,KAAK,CAACM,iBAAiB,CAAC;AACvC;;AAEA;AACA;AACA;AACA,OAAO,SAASF,aAAaA,CAAC/D,KAAe,EAAsB;EACjE,OAAOgD,WAAW,CAAChD,KAAK,CAAC,IAAI,OAAOA,KAAK,CAACkE,QAAQ,KAAK,QAAQ;AACjE;;AAEA;AACA;AACA;AACA,OAAO,SAASD,iBAAiBA,CAACjE,KAAe,EAAoB;EACnE,OACEgD,WAAW,CAAChD,KAAK,CAAC,IAClB,OAAOA,KAAK,CAACvB,IAAI,KAAK,QAAQ,IAC9BuB,KAAK,CAACvB,IAAI,KAAK,SAAS;AAE5B","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"FormComponent.js","names":["ComponentBase","FormComponent","type","hint","label","summaryLabel","isFormComponent","isAppendageStateSingleObject","constructor","def","props","getLabel","getSummaryLabel","errorDescription","shortDescription","title","keys","collection","name","fields","map","getFormDataFromState","state","getFormValue","getFormValueFromState","value","isValue","undefined","getStateFromValidForm","payload","getErrors","_translator","errors","list","filter","error","path","includes","length","getFirstError","translator","getViewErrors","firstError","getValidationMessagesOverride","getViewModel","isForceAccess","_isForceAccess","options","viewModel","t","tComponent","isRequired","required","hideOptional","optionalText","resolvedTitle","optionalTag","text","componentErrors","componentError","errorMessage","id","getDisplayStringFromFormValue","toString","getDisplayStringFromState","getContextValueFromFormValue","isState","values","Object","isFormValue","Array","isArray","getContextValueFromState","isFormState","getAllPossibleErrors","baseErrors","advancedSettingsErrors","onSubmit","_request","_metadata","_context","Promise","resolve","isRepeatState","every","isRepeatValue","itemId","isUploadState","isUploadValue","isGeospatialState","isGeospatialValue","uploadId"],"sources":["../../../../../src/server/plugins/engine/components/FormComponent.ts"],"sourcesContent":["import {\n type FormComponentsDef,\n type FormMetadata,\n type Item\n} from '@defra/forms-model'\nimport { type LanguageMessages } from 'joi'\n\nimport { ComponentBase } from '~/src/server/plugins/engine/components/ComponentBase.js'\nimport { type RenderContext } from '~/src/server/plugins/engine/components/types.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport {\n type FormContext,\n type FormRequestPayload\n} from '~/src/server/plugins/engine/types/index.js'\nimport {\n type ErrorMessageTemplateList,\n type Feature,\n type FileState,\n type FormPayload,\n type FormState,\n type FormStateValue,\n type FormSubmissionError,\n type FormSubmissionState,\n type FormValue,\n type GeospatialState,\n type RepeatItemState,\n type RepeatListState,\n type UploadState\n} from '~/src/server/plugins/engine/types.js'\n\nexport class FormComponent extends ComponentBase {\n type: FormComponentsDef['type']\n hint: FormComponentsDef['hint']\n label: string\n summaryLabel: string\n\n isFormComponent = true\n isAppendageStateSingleObject = false\n\n constructor(\n def: FormComponentsDef,\n props: ConstructorParameters<typeof ComponentBase>[1]\n ) {\n super(def, props)\n\n const { hint, type } = def\n\n this.type = type\n this.hint = hint\n\n this.label = this.getLabel(def)\n this.summaryLabel = this.getSummaryLabel(def)\n }\n\n getLabel(def: FormComponentsDef) {\n if ('errorDescription' in def && def.errorDescription) {\n return def.errorDescription\n }\n\n return this.getSummaryLabel(def)\n }\n\n getSummaryLabel(def: FormComponentsDef) {\n if ('shortDescription' in def && def.shortDescription) {\n return def.shortDescription\n }\n\n return def.title\n }\n\n get keys() {\n const { collection, name } = this\n\n if (collection) {\n const { fields } = collection\n return [name, ...fields.map(({ name }) => name)]\n }\n\n return [name]\n }\n\n getFormDataFromState(state: FormSubmissionState): FormPayload {\n const { collection, name } = this\n\n if (collection) {\n return collection.getFormDataFromState(state)\n }\n\n return {\n [name]: this.getFormValue(state[name])\n }\n }\n\n getFormValueFromState(state: FormSubmissionState): FormValue | FormPayload {\n const { collection, name } = this\n\n if (collection) {\n return collection.getFormValueFromState(state)\n }\n\n return this.getFormValue(state[name])\n }\n\n getFormValue(value?: FormStateValue | FormState) {\n return this.isValue(value) ? value : undefined\n }\n\n getStateFromValidForm(payload: FormPayload): FormState {\n const { collection, name } = this\n\n if (collection) {\n return collection.getStateFromValidForm(payload)\n }\n\n return {\n [name]: this.getFormValue(payload[name]) ?? null\n }\n }\n\n getErrors(\n _translator: Translator,\n errors?: FormSubmissionError[]\n ): FormSubmissionError[] | undefined {\n const { name } = this\n\n // Filter component and child errors only\n const list = errors?.filter(\n (error) =>\n error.name === name ||\n error.path.includes(name) ||\n this.keys.includes(error.name)\n )\n\n if (!list?.length) {\n return\n }\n\n return list\n }\n\n getFirstError(\n translator: Translator,\n errors?: FormSubmissionError[]\n ): FormSubmissionError | undefined {\n return this.getErrors(translator, errors)?.[0]\n }\n\n getViewErrors(\n translator: Translator,\n errors?: FormSubmissionError[]\n ): FormSubmissionError[] | undefined {\n const firstError = this.getFirstError(translator, errors)\n return firstError && [firstError]\n }\n\n /**\n * Override in composite fields to return translated Joi message overrides for\n * their sub-fields, applied at validation time so schema-level English messages\n * are replaced with the correct language. Return null to skip message patching.\n */\n getValidationMessagesOverride(\n _translator: Translator\n ): LanguageMessages | null {\n return null\n }\n\n getViewModel({\n payload,\n errors,\n translator,\n isForceAccess: _isForceAccess = false\n }: RenderContext) {\n const { hint, name, options = {}, title, viewModel } = this\n\n const { t, tComponent } = translator\n\n const isRequired = !('required' in options) || options.required !== false\n const hideOptional = 'optionalText' in options && options.optionalText\n\n const resolvedTitle = tComponent(this.def, 'title') || title\n const optionalTag =\n !isRequired && !hideOptional ? ` ${t('common.optional')}` : ''\n const label = `${resolvedTitle}${optionalTag}`\n\n if (hint) {\n viewModel.hint = {\n text: tComponent(this.def, 'hint') || hint\n }\n }\n\n // Filter component errors only\n const componentErrors = this.getErrors(translator, errors)\n const componentError = this.getFirstError(translator, componentErrors)\n\n if (componentErrors) {\n viewModel.errors = componentErrors\n }\n\n if (componentError) {\n viewModel.errorMessage = {\n text: componentError.text\n }\n }\n\n return {\n ...viewModel,\n label: {\n text: label\n },\n id: name,\n name,\n value: payload[name]\n }\n }\n\n getDisplayStringFromFormValue(\n value: FormValue | FormPayload,\n _translator: Translator\n ): string {\n // Map selected values to text\n // eslint-disable-next-line @typescript-eslint/no-base-to-string\n return this.isValue(value) ? value.toString() : ''\n }\n\n getDisplayStringFromState(\n state: FormSubmissionState,\n translator: Translator\n ): string {\n const value = this.getFormValueFromState(state)\n return this.getDisplayStringFromFormValue(value, translator)\n }\n\n getContextValueFromFormValue(\n value: FormValue | FormPayload\n ): Item['value'] | Item['value'][] | null {\n // Filter object field values\n if (this.isState(value)) {\n const values = Object.values(value).filter(isFormValue)\n return values.length ? values : null\n }\n\n // Filter array field values\n if (this.isValue(value) && Array.isArray(value)) {\n return value.filter(isFormValue)\n }\n\n return this.isValue(value) ? value : null\n }\n\n getContextValueFromState(\n state: FormSubmissionState\n ): Item['value'] | Item['value'][] | null {\n const value = this.getFormValueFromState(state)\n\n return this.getContextValueFromFormValue(value)\n }\n\n isValue(\n value?: FormStateValue | FormState\n ): value is NonNullable<FormStateValue> {\n return isFormValue(value)\n }\n\n isState(value?: FormStateValue | FormState): value is FormState {\n return isFormState(value)\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return FormComponent.getAllPossibleErrors()\n }\n\n /**\n * Static version of getAllPossibleErrors that doesn't require a component instance.\n */\n static getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [],\n advancedSettingsErrors: []\n }\n }\n\n onSubmit(\n _request: FormRequestPayload,\n _metadata: FormMetadata,\n _context: FormContext\n ): Promise<void> {\n return Promise.resolve()\n }\n}\n\n/**\n * Check for form value\n */\nexport function isFormValue(\n value?: unknown\n): value is string | number | boolean {\n return (\n (typeof value === 'string' && value.length > 0) ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n )\n}\n\n/**\n * Check for form state with nested values\n */\nexport function isFormState(value?: unknown): value is FormState {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n return false\n }\n\n // Skip empty objects\n return !!Object.values(value).length\n}\n\n/**\n * Check for repeat list state\n */\nexport function isRepeatState(value?: unknown): value is RepeatListState {\n if (!Array.isArray(value)) {\n return false\n }\n\n // Skip checks when empty\n if (!value.length) {\n return true\n }\n\n return value.every(isRepeatValue)\n}\n\n/**\n * Check for repeat list value\n */\nexport function isRepeatValue(value?: unknown): value is RepeatItemState {\n return isFormState(value) && typeof value.itemId === 'string'\n}\n\n/**\n * Check for upload state\n */\nexport function isUploadState(value?: unknown): value is UploadState {\n if (!Array.isArray(value)) {\n return false\n }\n\n // Skip checks when empty\n if (!value.length) {\n return true\n }\n\n return value.every(isUploadValue)\n}\n\n/**\n * Check for geospatial state\n */\nexport function isGeospatialState(value?: unknown): value is GeospatialState {\n if (!Array.isArray(value)) {\n return false\n }\n\n // Skip checks when empty\n if (!value.length) {\n return true\n }\n\n return value.every(isGeospatialValue)\n}\n\n/**\n * Check for upload state value\n */\nexport function isUploadValue(value?: unknown): value is FileState {\n return isFormState(value) && typeof value.uploadId === 'string'\n}\n\n/**\n * Check for geospatial state value\n */\nexport function isGeospatialValue(value?: unknown): value is Feature {\n return (\n isFormState(value) &&\n typeof value.type === 'string' &&\n value.type === 'Feature'\n )\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -22,7 +22,7 @@ export class Markdown extends ComponentBase {
|
|
|
22
22
|
} = context.translator;
|
|
23
23
|
return {
|
|
24
24
|
...viewModel,
|
|
25
|
-
content: tComponent(this, 'content') || content,
|
|
25
|
+
content: tComponent(this.def, 'content') || content,
|
|
26
26
|
headerStartLevel: this.headerStartLevel
|
|
27
27
|
};
|
|
28
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Markdown.js","names":["ComponentBase","Markdown","content","headerStartLevel","constructor","def","props","options","getViewModel","context","viewModel","tComponent","translator"],"sources":["../../../../../src/server/plugins/engine/components/Markdown.ts"],"sourcesContent":["import { type
|
|
1
|
+
{"version":3,"file":"Markdown.js","names":["ComponentBase","Markdown","content","headerStartLevel","constructor","def","props","options","getViewModel","context","viewModel","tComponent","translator"],"sources":["../../../../../src/server/plugins/engine/components/Markdown.ts"],"sourcesContent":["import { type MarkdownComponent } from '@defra/forms-model'\n\nimport { ComponentBase } from '~/src/server/plugins/engine/components/ComponentBase.js'\nimport { type RenderContext } from '~/src/server/plugins/engine/components/types.js'\n\nexport class Markdown extends ComponentBase {\n declare options: MarkdownComponent['options']\n content: MarkdownComponent['content']\n headerStartLevel: number\n\n constructor(\n def: MarkdownComponent,\n props: ConstructorParameters<typeof ComponentBase>[1]\n ) {\n super(def, props)\n\n const { content, options } = def\n\n this.content = content\n this.options = options\n this.headerStartLevel = 2\n }\n\n getViewModel(context: RenderContext) {\n const { content, viewModel } = this\n\n const { tComponent } = context.translator\n\n return {\n ...viewModel,\n content: tComponent(this.def, 'content') || content,\n headerStartLevel: this.headerStartLevel\n }\n }\n}\n"],"mappings":"AAEA,SAASA,aAAa;AAGtB,OAAO,MAAMC,QAAQ,SAASD,aAAa,CAAC;EAE1CE,OAAO;EACPC,gBAAgB;EAEhBC,WAAWA,CACTC,GAAsB,EACtBC,KAAqD,EACrD;IACA,KAAK,CAACD,GAAG,EAAEC,KAAK,CAAC;IAEjB,MAAM;MAAEJ,OAAO;MAAEK;IAAQ,CAAC,GAAGF,GAAG;IAEhC,IAAI,CAACH,OAAO,GAAGA,OAAO;IACtB,IAAI,CAACK,OAAO,GAAGA,OAAO;IACtB,IAAI,CAACJ,gBAAgB,GAAG,CAAC;EAC3B;EAEAK,YAAYA,CAACC,OAAsB,EAAE;IACnC,MAAM;MAAEP,OAAO;MAAEQ;IAAU,CAAC,GAAG,IAAI;IAEnC,MAAM;MAAEC;IAAW,CAAC,GAAGF,OAAO,CAACG,UAAU;IAEzC,OAAO;MACL,GAAGF,SAAS;MACZR,OAAO,EAAES,UAAU,CAAC,IAAI,CAACN,GAAG,EAAE,SAAS,CAAC,IAAIH,OAAO;MACnDC,gBAAgB,EAAE,IAAI,CAACA;IACzB,CAAC;EACH;AACF","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["../../../../../src/server/plugins/engine/i18n/types.ts"],"sourcesContent":["import {\n type ComponentDef,\n type Item,\n type Page,\n type Section\n} from '@defra/forms-model'\n\n/**\n * Structure of the `translations` block in a form definition.\n * Also used to derive the valid property keys for the typed tX functions.\n */\nexport type FormDefinitionTranslations = Record<\n string,\n {\n pages: Record<string, Partial<{ title: string; repeatTitle: string }>>\n // ComponentDef is a discriminated union; Pick across the full union is not feasible.\n // The four keys below are the complete set of translatable component properties.\n components: Record<\n string,\n Partial<{\n title: string\n hint: string\n content: string\n shortDescription: string\n paymentDescription: string\n }>\n >\n sections: Record<string, Partial<Pick<Section, 'title'>>>\n listItems: Record<string, Partial<Pick<Item, 'text' | 'hint'>>>\n form: Record<string, string>\n }\n>\n\ntype EntityTranslations = FormDefinitionTranslations[string]\n\n/**\n * Scoped translator returned by model.createTranslator(language).\n * t — plugin namespace (UI strings, buttons, errors, sub-field labels)\n * tForm — form namespace: form attributes, currently only form name\n * tPage — form namespace: page titles\n * tComponent — form namespace: component titles, hints, shortDescriptions\n * tSection — form namespace: section titles\n * tListItem — form namespace: list item text\n * language - current language\n */\nexport interface Translator {\n t: (key: string, opts?: Record<string, unknown>) => string\n tForm: (prop: string) => string\n tPage: (page: Page, prop: keyof EntityTranslations['pages'][string]) => string\n tComponent: (\n component: ComponentDef,\n prop: keyof EntityTranslations['components'][string]\n ) => string\n tSection: (\n section: Section,\n prop: keyof EntityTranslations['sections'][string]\n ) => string\n tListItem: (\n item: Item,\n prop: keyof EntityTranslations['listItems'][string]\n ) => string\n language: string\n}\n"],"mappings":"","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../../../../../src/server/plugins/engine/i18n/types.ts"],"sourcesContent":["import {\n type ComponentDef,\n type Item,\n type Page,\n type Section\n} from '@defra/forms-model'\n\n/**\n * Structure of the `translations` block in a form definition.\n * Also used to derive the valid property keys for the typed tX functions.\n */\nexport type FormDefinitionTranslations = Record<\n string,\n {\n pages: Record<string, Partial<{ title: string; repeatTitle: string }>>\n // ComponentDef is a discriminated union; Pick across the full union is not feasible.\n // The four keys below are the complete set of translatable component properties.\n components: Record<\n string,\n Partial<{\n title: string\n hint: string\n content: string\n shortDescription: string\n errorDescription: string\n paymentDescription: string\n }>\n >\n sections: Record<string, Partial<Pick<Section, 'title'>>>\n listItems: Record<string, Partial<Pick<Item, 'text' | 'hint'>>>\n form: Record<string, string>\n }\n>\n\ntype EntityTranslations = FormDefinitionTranslations[string]\n\n/**\n * Scoped translator returned by model.createTranslator(language).\n * t — plugin namespace (UI strings, buttons, errors, sub-field labels)\n * tForm — form namespace: form attributes, currently only form name\n * tPage — form namespace: page titles\n * tComponent — form namespace: component titles, hints, shortDescriptions\n * tSection — form namespace: section titles\n * tListItem — form namespace: list item text\n * language - current language\n */\nexport interface Translator {\n t: (key: string, opts?: Record<string, unknown>) => string\n tForm: (prop: string) => string\n tPage: (page: Page, prop: keyof EntityTranslations['pages'][string]) => string\n tComponent: (\n component: ComponentDef,\n prop: keyof EntityTranslations['components'][string]\n ) => string\n tSection: (\n section: Section,\n prop: keyof EntityTranslations['sections'][string]\n ) => string\n tListItem: (\n item: Item,\n prop: keyof EntityTranslations['listItems'][string]\n ) => string\n language: string\n}\n"],"mappings":"","ignoreList":[]}
|
|
@@ -164,12 +164,16 @@ function ItemRepeat(page, state, options, translator) {
|
|
|
164
164
|
repeat
|
|
165
165
|
} = page;
|
|
166
166
|
const {
|
|
167
|
-
name
|
|
168
|
-
title
|
|
167
|
+
name
|
|
169
168
|
} = repeat.options;
|
|
169
|
+
const {
|
|
170
|
+
t,
|
|
171
|
+
tPage
|
|
172
|
+
} = translator;
|
|
173
|
+
const title = tPage(page.pageDef, 'repeatTitle') || repeat.options.title;
|
|
170
174
|
const values = page.getListFromState(state);
|
|
171
175
|
const count = values.length;
|
|
172
|
-
const value = count === 0 ? '' :
|
|
176
|
+
const value = count === 0 ? '' : t('pages.repeater.pageTitle', {
|
|
173
177
|
count
|
|
174
178
|
});
|
|
175
179
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SummaryViewModel.js","names":["SchemaVersion","PaymentField","getAnswer","evaluateTemplate","getError","getPageHref","RepeatPageController","validationOptions","opts","SummaryViewModel","page","pageTitle","declaration","details","checkAnswers","context","name","backLink","feedbackLink","phaseTag","errors","serviceUrl","hasMissingNotificationEmail","components","allowSaveAndExit","paymentState","paymentDetails","t","_translator","paymentRequired","paymentPreAuthorized","constructor","request","translator","model","basePath","def","sections","isForceAccess","title","schema","V2","result","makeFilteredSchema","relevantPages","validate","relevantState","stripUnknown","error","map","summaryDetails","detail","rows","items","item","push","href","text","classes","visuallyHiddenText","label","key","value","html","actions","undefined","summaryList","state","forEach","section","sectionPages","filter","collection","path","ItemRepeat","getSummaryPath","field","fields","ItemField","length","sectionTitle","tSection","options","repeat","values","getListFromState","count","returnUrl","subItems","repeatState","fieldDef","id","type","shortDescription","rawLabel","tComponent","translatedLabel","rawTitle","translatedTitle","optional","required","getFirstError","format"],"sources":["../../../../../src/server/plugins/engine/models/SummaryViewModel.ts"],"sourcesContent":["import {\n SchemaVersion,\n type ComponentDef,\n type Section\n} from '@defra/forms-model'\n\nimport { PaymentField } from '~/src/server/plugins/engine/components/PaymentField.js'\nimport { type PaymentState } from '~/src/server/plugins/engine/components/PaymentField.types.js'\nimport {\n getAnswer,\n type Field\n} from '~/src/server/plugins/engine/components/helpers/components.js'\nimport {\n type BackLink,\n type ComponentViewModel\n} from '~/src/server/plugins/engine/components/types.js'\nimport {\n evaluateTemplate,\n getError,\n getPageHref\n} from '~/src/server/plugins/engine/helpers.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport {\n type Detail,\n type DetailItem,\n type DetailItemField,\n type DetailItemRepeat\n} from '~/src/server/plugins/engine/models/types.js'\nimport { RepeatPageController } from '~/src/server/plugins/engine/pageControllers/RepeatPageController.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'\nimport { validationOptions as opts } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\nimport {\n type CheckAnswers,\n type FormContext,\n type FormContextRequest,\n type FormState,\n type FormSubmissionError,\n type SummaryListAction,\n type SummaryListRow\n} from '~/src/server/plugins/engine/types.js'\n\nexport class SummaryViewModel {\n /**\n * Responsible for parsing state values to the govuk-frontend summary list template\n */\n\n page: PageControllerClass\n pageTitle: string\n declaration?: string\n details: Detail[]\n checkAnswers: CheckAnswers[]\n context: FormContext\n name: string | undefined\n backLink?: BackLink\n feedbackLink?: string\n phaseTag?: string\n errors?: FormSubmissionError[]\n serviceUrl: string\n hasMissingNotificationEmail?: boolean\n components?: ComponentViewModel[]\n allowSaveAndExit = false\n paymentState?: PaymentState\n paymentDetails?: CheckAnswers\n t: (key: string, opts?: Record<string, unknown>) => string\n private readonly _translator!: Translator\n paymentRequired?: boolean\n paymentPreAuthorized?: boolean\n\n constructor(\n request: FormContextRequest,\n page: PageControllerClass,\n context: FormContext,\n translator: Translator\n ) {\n const { model } = page\n const { basePath, def, sections } = model\n const { isForceAccess } = context\n\n const { t } = translator\n this.t = t\n this._translator = translator\n\n this.page = page\n this.pageTitle = page.title\n if (def.schema === SchemaVersion.V2 && !page.title) {\n this.pageTitle = t('pages.summary.title')\n }\n\n this.serviceUrl = `/${basePath}`\n this.name = def.name\n this.declaration = def.declaration\n this.context = context\n\n const result = model\n .makeFilteredSchema(this.context.relevantPages)\n .validate(this.context.relevantState, { ...opts, stripUnknown: true })\n\n // Format errors\n this.errors = result.error?.details.map(getError)\n this.details = this.summaryDetails(request, sections, translator)\n\n // Format check answers\n this.checkAnswers = this.details.map((detail): CheckAnswers => {\n const { title } = detail\n\n const rows = detail.items.map((item): SummaryListRow => {\n const items: SummaryListAction[] = []\n\n // Remove summary list actions from previews\n if (!isForceAccess) {\n items.push({\n href: item.href,\n text: t('pages.summary.change'),\n classes: 'govuk-link--no-visited-state',\n visuallyHiddenText: item.label\n })\n }\n\n return {\n key: {\n text: evaluateTemplate(item.title, context)\n },\n value: {\n classes: 'app-prose-scope',\n html: item.value || t('pages.summary.notProvided')\n },\n actions: {\n items\n }\n }\n })\n\n return {\n title: title ? { text: title } : undefined,\n summaryList: { rows }\n }\n })\n }\n\n private summaryDetails(\n request: FormContextRequest,\n sections: Section[],\n translator: Translator\n ) {\n const { context, errors } = this\n const { relevantPages, state } = context\n\n const details: Detail[] = []\n\n ;[...sections, undefined].forEach((section) => {\n const items: DetailItem[] = []\n\n const sectionPages = relevantPages.filter(\n (page) => page.section === section\n )\n\n sectionPages.forEach((page) => {\n const { collection, path } = page\n\n if (page instanceof RepeatPageController) {\n items.push(\n ItemRepeat(\n page,\n state,\n {\n path: page.getSummaryPath(request),\n errors\n },\n translator\n )\n )\n } else {\n for (const field of collection.fields) {\n // PaymentField is rendered in its own section, skip it here\n if (field instanceof PaymentField) {\n continue\n }\n items.push(\n ItemField(page, state, field, { path, errors }, translator)\n )\n }\n }\n })\n\n if (items.length) {\n const sectionTitle = section\n ? translator.tSection(section, 'title') || section.title\n : undefined\n details.push({\n name: section?.name,\n title: sectionTitle,\n items\n })\n }\n })\n\n return details\n }\n}\n\n/**\n * Creates a repeater detail item\n * @see {@link DetailItemField}\n */\nfunction ItemRepeat(\n page: RepeatPageController,\n state: FormState,\n options: {\n path: string\n errors?: FormSubmissionError[]\n },\n translator: Translator\n): DetailItemRepeat {\n const { collection, repeat } = page\n const { name, title } = repeat.options\n\n const values = page.getListFromState(state)\n const count = values.length\n const value =\n count === 0 ? '' : translator.t('pages.repeater.pageTitle', { count })\n\n return {\n name,\n label: title,\n title,\n value,\n href: getPageHref(page, options.path, {\n returnUrl: getPageHref(page, page.getSummaryPath())\n }),\n state,\n page,\n\n // Repeater field detail items\n subItems: values.map((repeatState) =>\n collection.fields.map((field) =>\n ItemField(page, repeatState, field, options, translator)\n )\n )\n }\n}\n\n/**\n * Creates a form field detail item\n * @see {@link DetailItemField}\n */\nexport function ItemField(\n page: PageControllerClass,\n state: FormState,\n field: Field,\n options: {\n path: string\n errors?: FormSubmissionError[]\n },\n translator: Translator\n): DetailItemField {\n // FormComponent doesn't expose shortDescription/title as raw def properties,\n // so build a lookup object with English values to let tComponent's GUID lookup fire.\n const fieldDef = {\n id: field.id,\n type: field.type,\n shortDescription: field.label,\n title: field.title\n } as unknown as ComponentDef\n const rawLabel = translator.tComponent(fieldDef, 'shortDescription')\n const translatedLabel = rawLabel !== '' ? rawLabel : field.label\n const rawTitle = translator.tComponent(fieldDef, 'title')\n const translatedTitle = rawTitle !== '' ? rawTitle : field.title\n const optional =\n field.options.required === false\n ? ` ${translator.t('common.optional')}`\n : ''\n return {\n name: field.name,\n label: translatedTitle,\n title: `${translatedLabel}${optional}`,\n error: field.getFirstError(translator, options.errors),\n value: getAnswer(field, state, translator, { format: 'summary' }),\n href: getPageHref(page, options.path, {\n returnUrl: getPageHref(page, page.getSummaryPath())\n }),\n state,\n page,\n field\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"SummaryViewModel.js","names":["SchemaVersion","PaymentField","getAnswer","evaluateTemplate","getError","getPageHref","RepeatPageController","validationOptions","opts","SummaryViewModel","page","pageTitle","declaration","details","checkAnswers","context","name","backLink","feedbackLink","phaseTag","errors","serviceUrl","hasMissingNotificationEmail","components","allowSaveAndExit","paymentState","paymentDetails","t","_translator","paymentRequired","paymentPreAuthorized","constructor","request","translator","model","basePath","def","sections","isForceAccess","title","schema","V2","result","makeFilteredSchema","relevantPages","validate","relevantState","stripUnknown","error","map","summaryDetails","detail","rows","items","item","push","href","text","classes","visuallyHiddenText","label","key","value","html","actions","undefined","summaryList","state","forEach","section","sectionPages","filter","collection","path","ItemRepeat","getSummaryPath","field","fields","ItemField","length","sectionTitle","tSection","options","repeat","tPage","pageDef","values","getListFromState","count","returnUrl","subItems","repeatState","fieldDef","id","type","shortDescription","rawLabel","tComponent","translatedLabel","rawTitle","translatedTitle","optional","required","getFirstError","format"],"sources":["../../../../../src/server/plugins/engine/models/SummaryViewModel.ts"],"sourcesContent":["import {\n SchemaVersion,\n type ComponentDef,\n type Section\n} from '@defra/forms-model'\n\nimport { PaymentField } from '~/src/server/plugins/engine/components/PaymentField.js'\nimport { type PaymentState } from '~/src/server/plugins/engine/components/PaymentField.types.js'\nimport {\n getAnswer,\n type Field\n} from '~/src/server/plugins/engine/components/helpers/components.js'\nimport {\n type BackLink,\n type ComponentViewModel\n} from '~/src/server/plugins/engine/components/types.js'\nimport {\n evaluateTemplate,\n getError,\n getPageHref\n} from '~/src/server/plugins/engine/helpers.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport {\n type Detail,\n type DetailItem,\n type DetailItemField,\n type DetailItemRepeat\n} from '~/src/server/plugins/engine/models/types.js'\nimport { RepeatPageController } from '~/src/server/plugins/engine/pageControllers/RepeatPageController.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'\nimport { validationOptions as opts } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\nimport {\n type CheckAnswers,\n type FormContext,\n type FormContextRequest,\n type FormState,\n type FormSubmissionError,\n type SummaryListAction,\n type SummaryListRow\n} from '~/src/server/plugins/engine/types.js'\n\nexport class SummaryViewModel {\n /**\n * Responsible for parsing state values to the govuk-frontend summary list template\n */\n\n page: PageControllerClass\n pageTitle: string\n declaration?: string\n details: Detail[]\n checkAnswers: CheckAnswers[]\n context: FormContext\n name: string | undefined\n backLink?: BackLink\n feedbackLink?: string\n phaseTag?: string\n errors?: FormSubmissionError[]\n serviceUrl: string\n hasMissingNotificationEmail?: boolean\n components?: ComponentViewModel[]\n allowSaveAndExit = false\n paymentState?: PaymentState\n paymentDetails?: CheckAnswers\n t: (key: string, opts?: Record<string, unknown>) => string\n private readonly _translator!: Translator\n paymentRequired?: boolean\n paymentPreAuthorized?: boolean\n\n constructor(\n request: FormContextRequest,\n page: PageControllerClass,\n context: FormContext,\n translator: Translator\n ) {\n const { model } = page\n const { basePath, def, sections } = model\n const { isForceAccess } = context\n\n const { t } = translator\n this.t = t\n this._translator = translator\n\n this.page = page\n this.pageTitle = page.title\n if (def.schema === SchemaVersion.V2 && !page.title) {\n this.pageTitle = t('pages.summary.title')\n }\n\n this.serviceUrl = `/${basePath}`\n this.name = def.name\n this.declaration = def.declaration\n this.context = context\n\n const result = model\n .makeFilteredSchema(this.context.relevantPages)\n .validate(this.context.relevantState, { ...opts, stripUnknown: true })\n\n // Format errors\n this.errors = result.error?.details.map(getError)\n this.details = this.summaryDetails(request, sections, translator)\n\n // Format check answers\n this.checkAnswers = this.details.map((detail): CheckAnswers => {\n const { title } = detail\n\n const rows = detail.items.map((item): SummaryListRow => {\n const items: SummaryListAction[] = []\n\n // Remove summary list actions from previews\n if (!isForceAccess) {\n items.push({\n href: item.href,\n text: t('pages.summary.change'),\n classes: 'govuk-link--no-visited-state',\n visuallyHiddenText: item.label\n })\n }\n\n return {\n key: {\n text: evaluateTemplate(item.title, context)\n },\n value: {\n classes: 'app-prose-scope',\n html: item.value || t('pages.summary.notProvided')\n },\n actions: {\n items\n }\n }\n })\n\n return {\n title: title ? { text: title } : undefined,\n summaryList: { rows }\n }\n })\n }\n\n private summaryDetails(\n request: FormContextRequest,\n sections: Section[],\n translator: Translator\n ) {\n const { context, errors } = this\n const { relevantPages, state } = context\n\n const details: Detail[] = []\n\n ;[...sections, undefined].forEach((section) => {\n const items: DetailItem[] = []\n\n const sectionPages = relevantPages.filter(\n (page) => page.section === section\n )\n\n sectionPages.forEach((page) => {\n const { collection, path } = page\n\n if (page instanceof RepeatPageController) {\n items.push(\n ItemRepeat(\n page,\n state,\n {\n path: page.getSummaryPath(request),\n errors\n },\n translator\n )\n )\n } else {\n for (const field of collection.fields) {\n // PaymentField is rendered in its own section, skip it here\n if (field instanceof PaymentField) {\n continue\n }\n items.push(\n ItemField(page, state, field, { path, errors }, translator)\n )\n }\n }\n })\n\n if (items.length) {\n const sectionTitle = section\n ? translator.tSection(section, 'title') || section.title\n : undefined\n details.push({\n name: section?.name,\n title: sectionTitle,\n items\n })\n }\n })\n\n return details\n }\n}\n\n/**\n * Creates a repeater detail item\n * @see {@link DetailItemField}\n */\nfunction ItemRepeat(\n page: RepeatPageController,\n state: FormState,\n options: {\n path: string\n errors?: FormSubmissionError[]\n },\n translator: Translator\n): DetailItemRepeat {\n const { collection, repeat } = page\n const { name } = repeat.options\n const { t, tPage } = translator\n const title = tPage(page.pageDef, 'repeatTitle') || repeat.options.title\n const values = page.getListFromState(state)\n const count = values.length\n const value = count === 0 ? '' : t('pages.repeater.pageTitle', { count })\n\n return {\n name,\n label: title,\n title,\n value,\n href: getPageHref(page, options.path, {\n returnUrl: getPageHref(page, page.getSummaryPath())\n }),\n state,\n page,\n\n // Repeater field detail items\n subItems: values.map((repeatState) =>\n collection.fields.map((field) =>\n ItemField(page, repeatState, field, options, translator)\n )\n )\n }\n}\n\n/**\n * Creates a form field detail item\n * @see {@link DetailItemField}\n */\nexport function ItemField(\n page: PageControllerClass,\n state: FormState,\n field: Field,\n options: {\n path: string\n errors?: FormSubmissionError[]\n },\n translator: Translator\n): DetailItemField {\n // FormComponent doesn't expose shortDescription/title as raw def properties,\n // so build a lookup object with English values to let tComponent's GUID lookup fire.\n const fieldDef = {\n id: field.id,\n type: field.type,\n shortDescription: field.label,\n title: field.title\n } as unknown as ComponentDef\n const rawLabel = translator.tComponent(fieldDef, 'shortDescription')\n const translatedLabel = rawLabel !== '' ? rawLabel : field.label\n const rawTitle = translator.tComponent(fieldDef, 'title')\n const translatedTitle = rawTitle !== '' ? rawTitle : field.title\n const optional =\n field.options.required === false\n ? ` ${translator.t('common.optional')}`\n : ''\n return {\n name: field.name,\n label: translatedTitle,\n title: `${translatedLabel}${optional}`,\n error: field.getFirstError(translator, options.errors),\n value: getAnswer(field, state, translator, { format: 'summary' }),\n href: getPageHref(page, options.path, {\n returnUrl: getPageHref(page, page.getSummaryPath())\n }),\n state,\n page,\n field\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { EN_GB } from "../../../../constants.js";
|
|
1
2
|
import { getFormVersion } from "../../helpers.js";
|
|
2
3
|
import { categoriseData } from "../machine/v2.js";
|
|
3
4
|
import { FormAdapterSubmissionSchemaVersion } from "../../types/enums.js";
|
|
@@ -17,15 +18,12 @@ export function format(context, items, model, submitResponse, formStatus, formMe
|
|
|
17
18
|
formSlug: formMetadata?.slug ?? '',
|
|
18
19
|
status: formStatus.state,
|
|
19
20
|
isPreview: formStatus.isPreview,
|
|
20
|
-
notificationEmail: formMetadata?.notificationEmail ?? ''
|
|
21
|
+
notificationEmail: formMetadata?.notificationEmail ?? '',
|
|
22
|
+
language: context.translator?.language ?? EN_GB
|
|
21
23
|
};
|
|
22
24
|
if (versionMetadata) {
|
|
23
25
|
meta.versionMetadata = versionMetadata;
|
|
24
26
|
}
|
|
25
|
-
const definitionLanguage = model.def.metadata?.language;
|
|
26
|
-
if (typeof definitionLanguage === 'string') {
|
|
27
|
-
meta.language = definitionLanguage;
|
|
28
|
-
}
|
|
29
27
|
const main = Object.fromEntries(Object.entries(v2Main).map(([key, value]) => {
|
|
30
28
|
if (value === undefined) {
|
|
31
29
|
return [key, null];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"v1.js","names":["getFormVersion","categoriseData","FormAdapterSubmissionSchemaVersion","format","context","items","model","submitResponse","formStatus","formMetadata","csvFiles","extractCsvFiles","main","v2Main","v2Data","versionMetadata","def","meta","schemaVersion","V1","timestamp","Date","referenceNumber","formName","name","formId","id","formSlug","slug","status","state","isPreview","notificationEmail","
|
|
1
|
+
{"version":3,"file":"v1.js","names":["EN_GB","getFormVersion","categoriseData","FormAdapterSubmissionSchemaVersion","format","context","items","model","submitResponse","formStatus","formMetadata","csvFiles","extractCsvFiles","main","v2Main","v2Data","versionMetadata","def","meta","schemaVersion","V1","timestamp","Date","referenceNumber","formName","name","formId","id","formSlug","slug","status","state","isPreview","notificationEmail","language","translator","Object","fromEntries","entries","map","key","value","undefined","data","result","files","payload","JSON","stringify","repeaters"],"sources":["../../../../../../src/server/plugins/engine/outputFormatters/adapter/v1.ts"],"sourcesContent":["import {\n type FormMetadata,\n type SubmitResponsePayload\n} from '@defra/forms-model'\n\nimport { EN_GB } from '~/src/server/constants.js'\nimport {\n getFormVersion,\n type checkFormStatus\n} from '~/src/server/plugins/engine/helpers.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/FormModel.js'\nimport { type DetailItem } from '~/src/server/plugins/engine/models/types.js'\nimport { categoriseData } from '~/src/server/plugins/engine/outputFormatters/machine/v2.js'\nimport { FormAdapterSubmissionSchemaVersion } from '~/src/server/plugins/engine/types/enums.js'\nimport {\n type FormAdapterSubmissionMessageData,\n type FormAdapterSubmissionMessageMeta,\n type FormAdapterSubmissionMessagePayload,\n type FormAdapterSubmissionMessageResult,\n type FormContext\n} from '~/src/server/plugins/engine/types.js'\n\nexport function format(\n context: FormContext,\n items: DetailItem[],\n model: FormModel,\n submitResponse: SubmitResponsePayload,\n formStatus: ReturnType<typeof checkFormStatus>,\n formMetadata?: FormMetadata\n): string {\n const csvFiles = extractCsvFiles(submitResponse)\n\n const { main: v2Main, ...v2Data } = categoriseData(items)\n\n const versionMetadata = getFormVersion(model.def)\n\n const meta: FormAdapterSubmissionMessageMeta = {\n schemaVersion: FormAdapterSubmissionSchemaVersion.V1,\n timestamp: new Date(),\n referenceNumber: context.referenceNumber,\n formName: model.name,\n formId: formMetadata?.id ?? '',\n formSlug: formMetadata?.slug ?? '',\n status: formStatus.state,\n isPreview: formStatus.isPreview,\n notificationEmail: formMetadata?.notificationEmail ?? '',\n language: context.translator?.language ?? EN_GB\n }\n\n if (versionMetadata) {\n meta.versionMetadata = versionMetadata\n }\n\n const main = Object.fromEntries(\n Object.entries(v2Main).map(([key, value]) => {\n if (value === undefined) {\n return [key, null]\n }\n\n return [key, value]\n })\n )\n\n const data: FormAdapterSubmissionMessageData = {\n main,\n ...v2Data\n }\n\n const result: FormAdapterSubmissionMessageResult = {\n files: csvFiles\n }\n\n const payload: FormAdapterSubmissionMessagePayload = {\n meta,\n data,\n result\n }\n\n return JSON.stringify(payload)\n}\n\nfunction extractCsvFiles(\n submitResponse: SubmitResponsePayload\n): FormAdapterSubmissionMessageResult['files'] {\n const result =\n submitResponse.result as Partial<FormAdapterSubmissionMessageResult>\n\n return {\n main: result.files?.main ?? '',\n repeaters: result.files?.repeaters ?? {}\n }\n}\n"],"mappings":"AAKA,SAASA,KAAK;AACd,SACEC,cAAc;AAKhB,SAASC,cAAc;AACvB,SAASC,kCAAkC;AAS3C,OAAO,SAASC,MAAMA,CACpBC,OAAoB,EACpBC,KAAmB,EACnBC,KAAgB,EAChBC,cAAqC,EACrCC,UAA8C,EAC9CC,YAA2B,EACnB;EACR,MAAMC,QAAQ,GAAGC,eAAe,CAACJ,cAAc,CAAC;EAEhD,MAAM;IAAEK,IAAI,EAAEC,MAAM;IAAE,GAAGC;EAAO,CAAC,GAAGb,cAAc,CAACI,KAAK,CAAC;EAEzD,MAAMU,eAAe,GAAGf,cAAc,CAACM,KAAK,CAACU,GAAG,CAAC;EAEjD,MAAMC,IAAsC,GAAG;IAC7CC,aAAa,EAAEhB,kCAAkC,CAACiB,EAAE;IACpDC,SAAS,EAAE,IAAIC,IAAI,CAAC,CAAC;IACrBC,eAAe,EAAElB,OAAO,CAACkB,eAAe;IACxCC,QAAQ,EAAEjB,KAAK,CAACkB,IAAI;IACpBC,MAAM,EAAEhB,YAAY,EAAEiB,EAAE,IAAI,EAAE;IAC9BC,QAAQ,EAAElB,YAAY,EAAEmB,IAAI,IAAI,EAAE;IAClCC,MAAM,EAAErB,UAAU,CAACsB,KAAK;IACxBC,SAAS,EAAEvB,UAAU,CAACuB,SAAS;IAC/BC,iBAAiB,EAAEvB,YAAY,EAAEuB,iBAAiB,IAAI,EAAE;IACxDC,QAAQ,EAAE7B,OAAO,CAAC8B,UAAU,EAAED,QAAQ,IAAIlC;EAC5C,CAAC;EAED,IAAIgB,eAAe,EAAE;IACnBE,IAAI,CAACF,eAAe,GAAGA,eAAe;EACxC;EAEA,MAAMH,IAAI,GAAGuB,MAAM,CAACC,WAAW,CAC7BD,MAAM,CAACE,OAAO,CAACxB,MAAM,CAAC,CAACyB,GAAG,CAAC,CAAC,CAACC,GAAG,EAAEC,KAAK,CAAC,KAAK;IAC3C,IAAIA,KAAK,KAAKC,SAAS,EAAE;MACvB,OAAO,CAACF,GAAG,EAAE,IAAI,CAAC;IACpB;IAEA,OAAO,CAACA,GAAG,EAAEC,KAAK,CAAC;EACrB,CAAC,CACH,CAAC;EAED,MAAME,IAAsC,GAAG;IAC7C9B,IAAI;IACJ,GAAGE;EACL,CAAC;EAED,MAAM6B,MAA0C,GAAG;IACjDC,KAAK,EAAElC;EACT,CAAC;EAED,MAAMmC,OAA4C,GAAG;IACnD5B,IAAI;IACJyB,IAAI;IACJC;EACF,CAAC;EAED,OAAOG,IAAI,CAACC,SAAS,CAACF,OAAO,CAAC;AAChC;AAEA,SAASlC,eAAeA,CACtBJ,cAAqC,EACQ;EAC7C,MAAMoC,MAAM,GACVpC,cAAc,CAACoC,MAAqD;EAEtE,OAAO;IACL/B,IAAI,EAAE+B,MAAM,CAACC,KAAK,EAAEhC,IAAI,IAAI,EAAE;IAC9BoC,SAAS,EAAEL,MAAM,CAACC,KAAK,EAAEI,SAAS,IAAI,CAAC;EACzC,CAAC;AACH","ignoreList":[]}
|
|
@@ -326,11 +326,10 @@ export class RepeatPageController extends QuestionPageController {
|
|
|
326
326
|
errors
|
|
327
327
|
} = context;
|
|
328
328
|
const {
|
|
329
|
-
t
|
|
329
|
+
t,
|
|
330
|
+
tPage
|
|
330
331
|
} = translator;
|
|
331
|
-
const
|
|
332
|
-
title
|
|
333
|
-
} = repeat.options;
|
|
332
|
+
const title = tPage(this.pageDef, 'repeatTitle') || repeat.options.title;
|
|
334
333
|
const summaryList = {
|
|
335
334
|
classes: 'govuk-summary-list--long-actions',
|
|
336
335
|
rows: []
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RepeatPageController.js","names":["randomUUID","Boom","Joi","isRepeatState","redirectPath","QuestionPageController","FormAction","RepeatPageController","listSummaryViewName","listDeleteViewName","repeat","allowSaveAndExit","constructor","model","pageDef","options","schema","itemId","string","uuid","required","collection","formSchema","append","stateSchema","object","keys","name","array","items","min","max","label","title","getFormParams","request","params","payload","getFormDataFromState","state","list","getListFromState","getItemId","item","getItemFromList","getStateFromValidForm","badRequest","itemState","updated","newList","push","indexOf","proceed","h","nextPath","getSummaryPath","find","values","makeGetRouteHandler","context","path","query","summaryPath","returnUrl","force","length","makeGetListSummaryRouteHandler","translator","getTranslator","t","viewModel","getListSummaryViewModel","view","makePostListSummaryRouteHandler","action","hasErrorMin","Continue","hasErrorMax","AddAnother","count","errors","href","text","SaveAndExit","handleSaveAndExit","getNextPath","makeGetItemDeleteRouteHandler","notFound","backLink","getBackLink","pageTitle","itemTitle","buttonConfirm","buttonCancel","makePostItemDeleteRouteHandler","confirm","splice","update","mergeState","getViewModel","tPage","itemNumber","repeatCaption","sectionTitle","isForceAccess","summaryList","classes","rows","Array","isArray","forEach","index","getHref","visuallyHiddenText","itemDisplayText","fields","getDisplayStringFromState","key","value","actions","repeatTitle","showTitle","checkAnswers","shouldShowSaveAndExit","server"],"sources":["../../../../../src/server/plugins/engine/pageControllers/RepeatPageController.ts"],"sourcesContent":["import { randomUUID } from 'crypto'\n\nimport { type PageRepeat, type Repeat } from '@defra/forms-model'\nimport Boom from '@hapi/boom'\nimport Joi from 'joi'\n\nimport { isRepeatState } from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { redirectPath } from '~/src/server/plugins/engine/helpers.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { QuestionPageController } from '~/src/server/plugins/engine/pageControllers/QuestionPageController.js'\nimport {\n type FormContext,\n type FormContextRequest,\n type FormPageViewModel,\n type FormPayload,\n type FormSubmissionState,\n type ItemDeletePageViewModel,\n type RepeatItemState,\n type RepeatListState,\n type RepeaterSummaryPageViewModel,\n type SummaryList,\n type SummaryListAction\n} from '~/src/server/plugins/engine/types.js'\nimport {\n FormAction,\n type FormRequest,\n type FormRequestPayload,\n type FormResponseToolkit\n} from '~/src/server/routes/types.js'\n\nexport class RepeatPageController extends QuestionPageController {\n declare pageDef: PageRepeat\n\n listSummaryViewName = 'repeat-list-summary'\n listDeleteViewName = 'item-delete'\n repeat: Repeat\n allowSaveAndExit = true\n\n constructor(model: FormModel, pageDef: PageRepeat) {\n super(model, pageDef)\n\n this.repeat = pageDef.repeat\n\n const { options, schema } = this.repeat\n const itemId = Joi.string().uuid().required()\n\n this.collection.formSchema = this.collection.formSchema.append({ itemId })\n this.collection.stateSchema = Joi.object<RepeatItemState>().keys({\n [options.name]: Joi.array()\n .items(this.collection.stateSchema.append({ itemId }))\n .min(schema.min)\n .max(schema.max)\n .label(`${options.title} list`)\n .required()\n })\n }\n\n get keys() {\n const { repeat } = this\n return [repeat.options.name, ...super.keys]\n }\n\n getFormParams(request?: FormContextRequest) {\n const params = super.getFormParams(request)\n\n // Apply an itemId to the form payload\n if (request?.payload) {\n params.itemId = request.params.itemId ?? randomUUID()\n }\n\n return params\n }\n\n getFormDataFromState(\n request: FormContextRequest | undefined,\n state: FormSubmissionState\n ) {\n const { repeat } = this\n\n const params = this.getFormParams(request)\n const list = this.getListFromState(state)\n const itemId = this.getItemId(request)\n\n // Create payload with repeater list state\n if (!itemId) {\n return {\n ...params,\n [repeat.options.name]: list\n }\n }\n\n // Create payload with repeater item state\n const item = this.getItemFromList(list, itemId)\n\n return {\n ...params,\n ...item\n }\n }\n\n getStateFromValidForm(\n request: FormContextRequest,\n state: FormSubmissionState,\n payload: FormPayload\n ) {\n const itemId = this.getItemId(request)\n\n if (!itemId) {\n throw Boom.badRequest('No item ID found')\n }\n\n const list = this.getListFromState(state)\n const item = this.getItemFromList(list, itemId)\n\n const itemState = super.getStateFromValidForm(request, state, payload)\n const updated: RepeatItemState = { ...itemState, itemId }\n const newList = [...list]\n\n if (!item) {\n // Adding a new item\n newList.push(updated)\n } else {\n // Update an existing item\n newList[list.indexOf(item)] = updated\n }\n\n return {\n [this.repeat.options.name]: newList\n }\n }\n\n proceed(request: FormContextRequest, h: FormResponseToolkit) {\n const nextPath = this.getSummaryPath(request)\n return super.proceed(request, h, nextPath)\n }\n\n getItemFromList(list: RepeatListState, itemId?: string) {\n return list.find((item) => item.itemId === itemId)\n }\n\n getListFromState(state: FormSubmissionState) {\n const { name } = this.repeat.options\n const values = state[name]\n\n return isRepeatState(values) ? values : []\n }\n\n makeGetRouteHandler() {\n return async (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { path } = this\n const { query } = request\n const { state } = context\n\n const itemId = this.getItemId(request)\n const list = this.getListFromState(state)\n\n if (!itemId) {\n const summaryPath = this.getSummaryPath(request)\n const nextPath = redirectPath(`${path}/${randomUUID()}`, {\n returnUrl: query.returnUrl,\n force: query.force\n })\n\n // Only redirect to new item when list is empty\n return super.proceed(request, h, list.length ? summaryPath : nextPath)\n }\n\n return super.makeGetRouteHandler()(request, context, h)\n }\n }\n\n makeGetListSummaryRouteHandler() {\n return (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { path } = this\n const { query } = request\n const { state } = context\n\n const list = this.getListFromState(state)\n\n if (!list.length) {\n const nextPath = redirectPath(`${path}/${randomUUID()}`, {\n returnUrl: query.returnUrl\n })\n\n return super.proceed(request, h, nextPath)\n }\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n const viewModel = this.getListSummaryViewModel(\n request,\n context,\n list,\n translator\n )\n\n return h.view(this.listSummaryViewName, {\n ...viewModel,\n t\n })\n }\n }\n\n makePostListSummaryRouteHandler() {\n return (\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { path, repeat } = this\n const { query } = request\n const { schema } = repeat\n const { state } = context\n\n const list = this.getListFromState(state)\n\n if (!list.length) {\n const nextPath = redirectPath(`${path}/${randomUUID()}`, {\n returnUrl: query.returnUrl\n })\n\n return super.proceed(request, h, nextPath)\n }\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n const { action } = this.getFormParams(request)\n\n const hasErrorMin =\n action === FormAction.Continue && list.length < schema.min\n\n const hasErrorMax =\n (action === FormAction.AddAnother && list.length >= schema.max) ||\n (action === FormAction.Continue && list.length > schema.max)\n\n // Show error if repeat limits apply\n if (hasErrorMin || hasErrorMax) {\n const count = hasErrorMax ? schema.max : schema.min\n\n context.errors = [\n {\n path: [],\n href: '',\n name: '',\n text: hasErrorMax\n ? t('pages.repeater.tooMany', { count })\n : t('pages.repeater.tooFew', { count })\n }\n ]\n\n const viewModel = this.getListSummaryViewModel(\n request,\n context,\n list,\n translator\n )\n\n return h.view(this.listSummaryViewName, {\n ...viewModel,\n t\n })\n }\n\n if (action === FormAction.AddAnother) {\n const nextPath = redirectPath(`${path}/${randomUUID()}`, {\n returnUrl: query.returnUrl\n })\n\n return super.proceed(request, h, nextPath)\n }\n\n // Check if this is a save-and-exit action\n if (action === FormAction.SaveAndExit) {\n return this.handleSaveAndExit(request, context, h)\n }\n\n const nextPath = this.getNextPath(context)\n return super.proceed(request, h, nextPath)\n }\n }\n\n makeGetItemDeleteRouteHandler() {\n return (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { viewModel } = this\n const { state } = context\n\n const list = this.getListFromState(state)\n const itemId = this.getItemId(request)\n const item = this.getItemFromList(list, itemId)\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n if (!item || list.length === 1) {\n throw Boom.notFound(\n item\n ? t('pages.repeater.lastItemCannotBeRemoved')\n : t('pages.repeater.itemToRemoveNotFound')\n )\n }\n\n const { title } = this.repeat.options\n\n return h.view(this.listDeleteViewName, {\n ...viewModel,\n context,\n backLink: this.getBackLink(request, context, t),\n pageTitle: t('pages.repeater.removeAnswer'),\n itemTitle: `${title} ${list.indexOf(item) + 1}`,\n buttonConfirm: { text: t('pages.repeater.remove') },\n buttonCancel: { text: t('pages.repeater.cancel') },\n t\n } satisfies ItemDeletePageViewModel)\n }\n }\n\n makePostItemDeleteRouteHandler() {\n return async (\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { repeat } = this\n const { state } = context\n\n const { confirm } = this.getFormParams(request)\n\n const list = this.getListFromState(state)\n const itemId = this.getItemId(request)\n const item = this.getItemFromList(list, itemId)\n\n const { t } = this.getTranslator(request)\n\n if (!item || list.length === 1) {\n throw Boom.notFound(\n item\n ? t('pages.repeater.lastItemCannotBeRemoved')\n : t('pages.repeater.itemToRemoveNotFound')\n )\n }\n\n // Remove the item from the list\n if (confirm) {\n list.splice(list.indexOf(item), 1)\n\n const update = {\n [repeat.options.name]: list\n }\n\n await this.mergeState(request, state, update)\n }\n\n return this.proceed(request, h)\n }\n }\n\n getViewModel(\n request: FormContextRequest,\n context: FormContext,\n translator: Translator\n ): FormPageViewModel {\n const { state } = context\n const { tPage } = translator\n\n const list = this.getListFromState(state)\n const itemId = this.getItemId(request)\n const item = this.getItemFromList(list, itemId)\n\n const viewModel = super.getViewModel(request, context, translator)\n const itemNumber = item ? list.indexOf(item) + 1 : list.length + 1\n const title =\n tPage(this.pageDef, 'repeatTitle') || this.pageDef.repeat.options.title\n const repeatCaption = `${title} ${itemNumber}`\n\n return {\n ...viewModel,\n\n sectionTitle: viewModel.sectionTitle\n ? `${viewModel.sectionTitle}: ${repeatCaption}`\n : repeatCaption\n }\n }\n\n getListSummaryViewModel(\n request: FormContextRequest,\n context: FormContext,\n list: RepeatListState,\n translator: Translator\n ): RepeaterSummaryPageViewModel {\n const { collection, href, repeat } = this\n const { query } = request\n const { isForceAccess, errors } = context\n\n const { t } = translator\n\n const { title } = repeat.options\n\n const summaryList: SummaryList = {\n classes: 'govuk-summary-list--long-actions',\n rows: []\n }\n\n let count = 0\n\n if (Array.isArray(list)) {\n count = list.length\n\n const summaryPath = this.getSummaryPath(request)\n\n list.forEach((item, index) => {\n const items: SummaryListAction[] = []\n\n // Remove summary list actions from previews\n if (!isForceAccess) {\n items.push({\n href: redirectPath(`${href}/${item.itemId}`, {\n returnUrl: query.returnUrl ?? this.getHref(summaryPath)\n }),\n text: t('pages.repeater.change'),\n classes: 'govuk-link--no-visited-state',\n visuallyHiddenText: t('pages.repeater.visuallyHiddenItem', {\n index: index + 1\n })\n })\n\n if (count > 1) {\n items.push({\n href: redirectPath(`${href}/${item.itemId}/confirm-delete`, {\n returnUrl: query.returnUrl\n }),\n text: t('pages.repeater.remove'),\n classes: 'govuk-link--no-visited-state',\n visuallyHiddenText: t('pages.repeater.visuallyHiddenItem', {\n index: index + 1\n })\n })\n }\n }\n\n const itemDisplayText = collection.fields.length\n ? collection.fields[0].getDisplayStringFromState(item, translator)\n : ''\n\n summaryList.rows.push({\n key: {\n text: `${title} ${index + 1}`\n },\n value: {\n text: itemDisplayText || t('pages.repeater.notProvided')\n },\n actions: {\n items\n }\n })\n })\n }\n\n return {\n ...this.viewModel,\n backLink: this.getBackLink(request, context, t),\n repeatTitle: title,\n pageTitle: t('pages.repeater.pageTitle', { count }),\n showTitle: true,\n context,\n errors,\n checkAnswers: [{ summaryList }],\n allowSaveAndExit: this.shouldShowSaveAndExit(request.server)\n }\n }\n\n getSummaryPath(request?: FormContextRequest) {\n const { path } = this\n\n const summaryPath = super.getSummaryPath()\n\n if (!request) {\n return summaryPath\n }\n\n const { query } = request\n\n return redirectPath(`${path}${summaryPath}`, {\n returnUrl: query.returnUrl\n })\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"RepeatPageController.js","names":["randomUUID","Boom","Joi","isRepeatState","redirectPath","QuestionPageController","FormAction","RepeatPageController","listSummaryViewName","listDeleteViewName","repeat","allowSaveAndExit","constructor","model","pageDef","options","schema","itemId","string","uuid","required","collection","formSchema","append","stateSchema","object","keys","name","array","items","min","max","label","title","getFormParams","request","params","payload","getFormDataFromState","state","list","getListFromState","getItemId","item","getItemFromList","getStateFromValidForm","badRequest","itemState","updated","newList","push","indexOf","proceed","h","nextPath","getSummaryPath","find","values","makeGetRouteHandler","context","path","query","summaryPath","returnUrl","force","length","makeGetListSummaryRouteHandler","translator","getTranslator","t","viewModel","getListSummaryViewModel","view","makePostListSummaryRouteHandler","action","hasErrorMin","Continue","hasErrorMax","AddAnother","count","errors","href","text","SaveAndExit","handleSaveAndExit","getNextPath","makeGetItemDeleteRouteHandler","notFound","backLink","getBackLink","pageTitle","itemTitle","buttonConfirm","buttonCancel","makePostItemDeleteRouteHandler","confirm","splice","update","mergeState","getViewModel","tPage","itemNumber","repeatCaption","sectionTitle","isForceAccess","summaryList","classes","rows","Array","isArray","forEach","index","getHref","visuallyHiddenText","itemDisplayText","fields","getDisplayStringFromState","key","value","actions","repeatTitle","showTitle","checkAnswers","shouldShowSaveAndExit","server"],"sources":["../../../../../src/server/plugins/engine/pageControllers/RepeatPageController.ts"],"sourcesContent":["import { randomUUID } from 'crypto'\n\nimport { type PageRepeat, type Repeat } from '@defra/forms-model'\nimport Boom from '@hapi/boom'\nimport Joi from 'joi'\n\nimport { isRepeatState } from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { redirectPath } from '~/src/server/plugins/engine/helpers.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { QuestionPageController } from '~/src/server/plugins/engine/pageControllers/QuestionPageController.js'\nimport {\n type FormContext,\n type FormContextRequest,\n type FormPageViewModel,\n type FormPayload,\n type FormSubmissionState,\n type ItemDeletePageViewModel,\n type RepeatItemState,\n type RepeatListState,\n type RepeaterSummaryPageViewModel,\n type SummaryList,\n type SummaryListAction\n} from '~/src/server/plugins/engine/types.js'\nimport {\n FormAction,\n type FormRequest,\n type FormRequestPayload,\n type FormResponseToolkit\n} from '~/src/server/routes/types.js'\n\nexport class RepeatPageController extends QuestionPageController {\n declare pageDef: PageRepeat\n\n listSummaryViewName = 'repeat-list-summary'\n listDeleteViewName = 'item-delete'\n repeat: Repeat\n allowSaveAndExit = true\n\n constructor(model: FormModel, pageDef: PageRepeat) {\n super(model, pageDef)\n\n this.repeat = pageDef.repeat\n\n const { options, schema } = this.repeat\n const itemId = Joi.string().uuid().required()\n\n this.collection.formSchema = this.collection.formSchema.append({ itemId })\n this.collection.stateSchema = Joi.object<RepeatItemState>().keys({\n [options.name]: Joi.array()\n .items(this.collection.stateSchema.append({ itemId }))\n .min(schema.min)\n .max(schema.max)\n .label(`${options.title} list`)\n .required()\n })\n }\n\n get keys() {\n const { repeat } = this\n return [repeat.options.name, ...super.keys]\n }\n\n getFormParams(request?: FormContextRequest) {\n const params = super.getFormParams(request)\n\n // Apply an itemId to the form payload\n if (request?.payload) {\n params.itemId = request.params.itemId ?? randomUUID()\n }\n\n return params\n }\n\n getFormDataFromState(\n request: FormContextRequest | undefined,\n state: FormSubmissionState\n ) {\n const { repeat } = this\n\n const params = this.getFormParams(request)\n const list = this.getListFromState(state)\n const itemId = this.getItemId(request)\n\n // Create payload with repeater list state\n if (!itemId) {\n return {\n ...params,\n [repeat.options.name]: list\n }\n }\n\n // Create payload with repeater item state\n const item = this.getItemFromList(list, itemId)\n\n return {\n ...params,\n ...item\n }\n }\n\n getStateFromValidForm(\n request: FormContextRequest,\n state: FormSubmissionState,\n payload: FormPayload\n ) {\n const itemId = this.getItemId(request)\n\n if (!itemId) {\n throw Boom.badRequest('No item ID found')\n }\n\n const list = this.getListFromState(state)\n const item = this.getItemFromList(list, itemId)\n\n const itemState = super.getStateFromValidForm(request, state, payload)\n const updated: RepeatItemState = { ...itemState, itemId }\n const newList = [...list]\n\n if (!item) {\n // Adding a new item\n newList.push(updated)\n } else {\n // Update an existing item\n newList[list.indexOf(item)] = updated\n }\n\n return {\n [this.repeat.options.name]: newList\n }\n }\n\n proceed(request: FormContextRequest, h: FormResponseToolkit) {\n const nextPath = this.getSummaryPath(request)\n return super.proceed(request, h, nextPath)\n }\n\n getItemFromList(list: RepeatListState, itemId?: string) {\n return list.find((item) => item.itemId === itemId)\n }\n\n getListFromState(state: FormSubmissionState) {\n const { name } = this.repeat.options\n const values = state[name]\n\n return isRepeatState(values) ? values : []\n }\n\n makeGetRouteHandler() {\n return async (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { path } = this\n const { query } = request\n const { state } = context\n\n const itemId = this.getItemId(request)\n const list = this.getListFromState(state)\n\n if (!itemId) {\n const summaryPath = this.getSummaryPath(request)\n const nextPath = redirectPath(`${path}/${randomUUID()}`, {\n returnUrl: query.returnUrl,\n force: query.force\n })\n\n // Only redirect to new item when list is empty\n return super.proceed(request, h, list.length ? summaryPath : nextPath)\n }\n\n return super.makeGetRouteHandler()(request, context, h)\n }\n }\n\n makeGetListSummaryRouteHandler() {\n return (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { path } = this\n const { query } = request\n const { state } = context\n\n const list = this.getListFromState(state)\n\n if (!list.length) {\n const nextPath = redirectPath(`${path}/${randomUUID()}`, {\n returnUrl: query.returnUrl\n })\n\n return super.proceed(request, h, nextPath)\n }\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n const viewModel = this.getListSummaryViewModel(\n request,\n context,\n list,\n translator\n )\n\n return h.view(this.listSummaryViewName, {\n ...viewModel,\n t\n })\n }\n }\n\n makePostListSummaryRouteHandler() {\n return (\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { path, repeat } = this\n const { query } = request\n const { schema } = repeat\n const { state } = context\n\n const list = this.getListFromState(state)\n\n if (!list.length) {\n const nextPath = redirectPath(`${path}/${randomUUID()}`, {\n returnUrl: query.returnUrl\n })\n\n return super.proceed(request, h, nextPath)\n }\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n const { action } = this.getFormParams(request)\n\n const hasErrorMin =\n action === FormAction.Continue && list.length < schema.min\n\n const hasErrorMax =\n (action === FormAction.AddAnother && list.length >= schema.max) ||\n (action === FormAction.Continue && list.length > schema.max)\n\n // Show error if repeat limits apply\n if (hasErrorMin || hasErrorMax) {\n const count = hasErrorMax ? schema.max : schema.min\n\n context.errors = [\n {\n path: [],\n href: '',\n name: '',\n text: hasErrorMax\n ? t('pages.repeater.tooMany', { count })\n : t('pages.repeater.tooFew', { count })\n }\n ]\n\n const viewModel = this.getListSummaryViewModel(\n request,\n context,\n list,\n translator\n )\n\n return h.view(this.listSummaryViewName, {\n ...viewModel,\n t\n })\n }\n\n if (action === FormAction.AddAnother) {\n const nextPath = redirectPath(`${path}/${randomUUID()}`, {\n returnUrl: query.returnUrl\n })\n\n return super.proceed(request, h, nextPath)\n }\n\n // Check if this is a save-and-exit action\n if (action === FormAction.SaveAndExit) {\n return this.handleSaveAndExit(request, context, h)\n }\n\n const nextPath = this.getNextPath(context)\n return super.proceed(request, h, nextPath)\n }\n }\n\n makeGetItemDeleteRouteHandler() {\n return (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { viewModel } = this\n const { state } = context\n\n const list = this.getListFromState(state)\n const itemId = this.getItemId(request)\n const item = this.getItemFromList(list, itemId)\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n if (!item || list.length === 1) {\n throw Boom.notFound(\n item\n ? t('pages.repeater.lastItemCannotBeRemoved')\n : t('pages.repeater.itemToRemoveNotFound')\n )\n }\n\n const { title } = this.repeat.options\n\n return h.view(this.listDeleteViewName, {\n ...viewModel,\n context,\n backLink: this.getBackLink(request, context, t),\n pageTitle: t('pages.repeater.removeAnswer'),\n itemTitle: `${title} ${list.indexOf(item) + 1}`,\n buttonConfirm: { text: t('pages.repeater.remove') },\n buttonCancel: { text: t('pages.repeater.cancel') },\n t\n } satisfies ItemDeletePageViewModel)\n }\n }\n\n makePostItemDeleteRouteHandler() {\n return async (\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { repeat } = this\n const { state } = context\n\n const { confirm } = this.getFormParams(request)\n\n const list = this.getListFromState(state)\n const itemId = this.getItemId(request)\n const item = this.getItemFromList(list, itemId)\n\n const { t } = this.getTranslator(request)\n\n if (!item || list.length === 1) {\n throw Boom.notFound(\n item\n ? t('pages.repeater.lastItemCannotBeRemoved')\n : t('pages.repeater.itemToRemoveNotFound')\n )\n }\n\n // Remove the item from the list\n if (confirm) {\n list.splice(list.indexOf(item), 1)\n\n const update = {\n [repeat.options.name]: list\n }\n\n await this.mergeState(request, state, update)\n }\n\n return this.proceed(request, h)\n }\n }\n\n getViewModel(\n request: FormContextRequest,\n context: FormContext,\n translator: Translator\n ): FormPageViewModel {\n const { state } = context\n const { tPage } = translator\n\n const list = this.getListFromState(state)\n const itemId = this.getItemId(request)\n const item = this.getItemFromList(list, itemId)\n\n const viewModel = super.getViewModel(request, context, translator)\n const itemNumber = item ? list.indexOf(item) + 1 : list.length + 1\n const title =\n tPage(this.pageDef, 'repeatTitle') || this.pageDef.repeat.options.title\n const repeatCaption = `${title} ${itemNumber}`\n\n return {\n ...viewModel,\n\n sectionTitle: viewModel.sectionTitle\n ? `${viewModel.sectionTitle}: ${repeatCaption}`\n : repeatCaption\n }\n }\n\n getListSummaryViewModel(\n request: FormContextRequest,\n context: FormContext,\n list: RepeatListState,\n translator: Translator\n ): RepeaterSummaryPageViewModel {\n const { collection, href, repeat } = this\n const { query } = request\n const { isForceAccess, errors } = context\n\n const { t, tPage } = translator\n\n const title = tPage(this.pageDef, 'repeatTitle') || repeat.options.title\n\n const summaryList: SummaryList = {\n classes: 'govuk-summary-list--long-actions',\n rows: []\n }\n\n let count = 0\n\n if (Array.isArray(list)) {\n count = list.length\n\n const summaryPath = this.getSummaryPath(request)\n\n list.forEach((item, index) => {\n const items: SummaryListAction[] = []\n\n // Remove summary list actions from previews\n if (!isForceAccess) {\n items.push({\n href: redirectPath(`${href}/${item.itemId}`, {\n returnUrl: query.returnUrl ?? this.getHref(summaryPath)\n }),\n text: t('pages.repeater.change'),\n classes: 'govuk-link--no-visited-state',\n visuallyHiddenText: t('pages.repeater.visuallyHiddenItem', {\n index: index + 1\n })\n })\n\n if (count > 1) {\n items.push({\n href: redirectPath(`${href}/${item.itemId}/confirm-delete`, {\n returnUrl: query.returnUrl\n }),\n text: t('pages.repeater.remove'),\n classes: 'govuk-link--no-visited-state',\n visuallyHiddenText: t('pages.repeater.visuallyHiddenItem', {\n index: index + 1\n })\n })\n }\n }\n\n const itemDisplayText = collection.fields.length\n ? collection.fields[0].getDisplayStringFromState(item, translator)\n : ''\n\n summaryList.rows.push({\n key: {\n text: `${title} ${index + 1}`\n },\n value: {\n text: itemDisplayText || t('pages.repeater.notProvided')\n },\n actions: {\n items\n }\n })\n })\n }\n\n return {\n ...this.viewModel,\n backLink: this.getBackLink(request, context, t),\n repeatTitle: title,\n pageTitle: t('pages.repeater.pageTitle', { count }),\n showTitle: true,\n context,\n errors,\n checkAnswers: [{ summaryList }],\n allowSaveAndExit: this.shouldShowSaveAndExit(request.server)\n }\n }\n\n getSummaryPath(request?: FormContextRequest) {\n const { path } = this\n\n const summaryPath = super.getSummaryPath()\n\n if (!request) {\n return summaryPath\n }\n\n const { query } = request\n\n return redirectPath(`${path}${summaryPath}`, {\n returnUrl: query.returnUrl\n })\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -360,7 +360,10 @@ function submitData(model, items, retrievalKey, sessionId, translator, reference
|
|
|
360
360
|
retrievalKey,
|
|
361
361
|
referenceNumber,
|
|
362
362
|
main: buildMainRecords(items, translator),
|
|
363
|
-
repeaters: buildRepeaterRecords(items, translator)
|
|
363
|
+
repeaters: buildRepeaterRecords(items, translator),
|
|
364
|
+
// Only populate the language property if the form is multi-language enabled
|
|
365
|
+
// @ts-expect-error - dynamic language property
|
|
366
|
+
language: model.def.metadata?.translations?.cy ? translator.language : undefined
|
|
364
367
|
};
|
|
365
368
|
return submit(payload);
|
|
366
369
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SummaryPageController.js","names":["hasComponentsEvenIfNoNext","Boom","StatusCodes","COMPONENT_STATE_ERROR","PAYMENT_EXPIRED_NOTIFICATION","ComponentCollection","PaymentField","checkEmailAddressForLiveFormSubmission","checkFormStatus","createError","getCacheService","SummaryViewModel","QuestionPageController","InvalidComponentStateError","PaymentErrorTypes","PaymentPreAuthError","PaymentSubmissionError","buildMainRecords","buildRepeaterRecords","DEFAULT_PAYMENT_HELP_URL","formatCurrency","formatPaymentDate","FormAction","SummaryPageController","allowSaveAndExit","findPaymentField","model","pages","flatMap","page","collection","fields","find","field","constructor","pageDef","viewName","components","getSummaryViewModel","request","context","translator","t","viewModel","payload","errors","state","paymentField","resolvedAmount","resolveAmount","options","paymentState","getPaymentStateFromState","amount","paymentDetails","buildPaymentDetails","paymentRequired","preAuth","status","paymentPreAuthorized","getViewModel","backLink","getBackLink","feedbackLink","phaseTag","shouldShowSaveAndExit","server","rows","key","text","value","description","reference","createdAt","push","title","summaryList","makeGetRouteHandler","h","getTranslator","query","paymentComplete","handleFormSubmit","reconcilePaymentState","hasMissingNotificationEmail","view","cacheService","resetComponentStates","name","makePostRouteHandler","action","SaveAndExit","handleSaveAndExit","params","formsService","services","getFormMetadata","formMetadata","slug","notificationEmail","isPreview","submitForm","error","handleSubmissionError","setConfirmationState","confirmed","formId","referenceNumber","clearState","proceed","getStatusPath","handleInvalidComponentStateError","handlePaymentPreAuthError","handlePaymentSubmissionError","govukError","component","userMessage","yar","flash","getStateKeys","path","shouldResetState","errorType","PaymentExpired","PaymentIncomplete","redirect","getHref","code","SEE_OTHER","redirectPath","undefined","helpUrl","helpLink","contactUsLink","helpLinkHtml","postRouteOptions","ext","onPreHandler","method","continue","summaryViewModel","emailAddress","finaliseComponents","paymentWasCaptured","hasPaymentBeenCaptured","formStatus","logTags","logger","info","items","getFormSubmissionData","details","submitResponse","submitData","id","badRequest","outputService","submit","err","contact","online","url","capture","metadata","allFields","Set","relevantPages","filter","onSubmit","retrievalKey","sessionId","formSubmissionService","main","repeaters","map","href","flat","paymentItems","getPaymentFieldItems","label","summaryLabel","getDisplayStringFromState"],"sources":["../../../../../src/server/plugins/engine/pageControllers/SummaryPageController.ts"],"sourcesContent":["import {\n hasComponentsEvenIfNoNext,\n type FormMetadata,\n type Page,\n type SubmitPayload\n} from '@defra/forms-model'\nimport Boom from '@hapi/boom'\nimport { type RouteOptions } from '@hapi/hapi'\nimport { StatusCodes } from 'http-status-codes'\n\nimport {\n COMPONENT_STATE_ERROR,\n PAYMENT_EXPIRED_NOTIFICATION\n} from '~/src/server/constants.js'\nimport { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'\nimport { PaymentField } from '~/src/server/plugins/engine/components/PaymentField.js'\nimport {\n checkEmailAddressForLiveFormSubmission,\n checkFormStatus,\n createError,\n getCacheService\n} from '~/src/server/plugins/engine/helpers.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport {\n SummaryViewModel,\n type FormModel\n} from '~/src/server/plugins/engine/models/index.js'\nimport {\n type Detail,\n type DetailItem,\n type DetailItemField\n} from '~/src/server/plugins/engine/models/types.js'\nimport { QuestionPageController } from '~/src/server/plugins/engine/pageControllers/QuestionPageController.js'\nimport {\n InvalidComponentStateError,\n PaymentErrorTypes,\n PaymentPreAuthError,\n PaymentSubmissionError\n} from '~/src/server/plugins/engine/pageControllers/errors.js'\nimport {\n buildMainRecords,\n buildRepeaterRecords\n} from '~/src/server/plugins/engine/pageControllers/helpers/submission.js'\nimport {\n type FormConfirmationState,\n type FormContext,\n type FormContextRequest\n} from '~/src/server/plugins/engine/types.js'\nimport {\n DEFAULT_PAYMENT_HELP_URL,\n formatCurrency,\n formatPaymentDate\n} from '~/src/server/plugins/payment/helper.js'\nimport {\n FormAction,\n type FormRequest,\n type FormRequestPayload,\n type FormRequestPayloadRefs,\n type FormResponseToolkit\n} from '~/src/server/routes/types.js'\n\nexport class SummaryPageController extends QuestionPageController {\n declare pageDef: Page\n allowSaveAndExit = true\n\n /**\n * The controller which is used when Page[\"controller\"] is defined as \"./pages/summary.js\"\n */\n\n /**\n * Finds the PaymentField component across all pages in the model.\n * Payment pages are skipped in the normal page walk\n */\n private findPaymentField(): PaymentField | undefined {\n return this.model.pages\n .flatMap((page) => page.collection.fields)\n .find((field): field is PaymentField => field instanceof PaymentField)\n }\n\n constructor(model: FormModel, pageDef: Page) {\n super(model, pageDef)\n this.viewName = 'summary'\n\n // Components collection\n this.collection = new ComponentCollection(\n hasComponentsEvenIfNoNext(pageDef) ? pageDef.components : [],\n { model, page: this }\n )\n }\n\n getSummaryViewModel(\n request: FormContextRequest,\n context: FormContext,\n translator: Translator\n ): SummaryViewModel {\n const { t } = translator\n\n const viewModel = new SummaryViewModel(request, this, context, translator)\n\n const { payload, errors, state } = context\n\n const paymentField = this.findPaymentField()\n\n if (paymentField) {\n const resolvedAmount = PaymentField.resolveAmount(\n paymentField.options,\n this.model,\n state\n )\n const paymentState = paymentField.getPaymentStateFromState(state)\n\n if (paymentState?.amount === resolvedAmount) {\n viewModel.paymentState = paymentState\n viewModel.paymentDetails = this.buildPaymentDetails(\n paymentField,\n paymentState,\n t\n )\n }\n\n if (resolvedAmount > 0) {\n viewModel.paymentRequired = true\n }\n if (\n paymentState &&\n paymentState.preAuth?.status === 'success' &&\n paymentState.amount === resolvedAmount\n ) {\n viewModel.paymentPreAuthorized = true\n }\n }\n\n const components = this.collection.getViewModel({\n payload,\n errors,\n translator\n })\n\n viewModel.backLink = this.getBackLink(request, context, t)\n viewModel.feedbackLink = this.feedbackLink\n viewModel.phaseTag = this.phaseTag\n viewModel.components = components\n viewModel.allowSaveAndExit = this.shouldShowSaveAndExit(request.server)\n viewModel.errors = errors\n\n return viewModel\n }\n\n private buildPaymentDetails(\n paymentField: PaymentField,\n paymentState: NonNullable<\n ReturnType<PaymentField['getPaymentStateFromState']>\n >,\n t: (key: string, opts?: Record<string, unknown>) => string\n ) {\n const rows = [\n {\n key: { text: t('pages.summary.paymentFor') },\n value: { text: paymentState.description }\n },\n {\n key: { text: t('pages.summary.totalAmount') },\n value: { text: formatCurrency(paymentState.amount) }\n },\n {\n key: { text: t('pages.summary.reference') },\n value: { text: paymentState.reference }\n }\n ]\n\n if (paymentState.preAuth?.createdAt) {\n rows.push({\n key: { text: t('pages.summary.dateOfPayment') },\n value: { text: formatPaymentDate(paymentState.preAuth.createdAt) }\n })\n }\n\n return {\n title: { text: t('pages.summary.paymentDetailsTitle') },\n summaryList: { rows }\n }\n }\n\n /**\n * Returns an async function. This is called in plugin.ts when there is a GET request at `/{id}/{path*}`,\n */\n makeGetRouteHandler() {\n return async (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { viewName } = this\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n // After GOV.UK Pay callback, auto-submit the form instead of\n // showing CYA again. The payment is already pre-authorized.\n if (request.query.paymentComplete === 'true') {\n return this.handleFormSubmit(\n request as unknown as FormRequestPayload,\n context,\n h\n )\n }\n\n await this.reconcilePaymentState(request, context)\n\n const viewModel = this.getSummaryViewModel(request, context, translator)\n\n viewModel.hasMissingNotificationEmail =\n await this.hasMissingNotificationEmail(request, context)\n\n viewModel.t = t\n return h.view(viewName, viewModel)\n }\n }\n\n /**\n * Checks if the resolved payment amount has changed since pre-auth\n * and invalidates stale payment state if so.\n */\n private async reconcilePaymentState(\n request: FormRequest,\n context: FormContext\n ) {\n const paymentField = this.findPaymentField()\n\n if (!paymentField) {\n return\n }\n\n const resolvedAmount = PaymentField.resolveAmount(\n paymentField.options,\n this.model,\n context.state\n )\n const paymentState = paymentField.getPaymentStateFromState(context.state)\n\n if (paymentState && paymentState.amount !== resolvedAmount) {\n const cacheService = getCacheService(request.server)\n await cacheService.resetComponentStates(request, [paymentField.name])\n }\n }\n\n /**\n * Returns an async function. This is called in plugin.ts when there is a POST request at `/{id}/{path*}`.\n * If a form is incomplete, a user will be redirected to the start page.\n */\n makePostRouteHandler() {\n return async (\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { action } = request.payload\n if (action === FormAction.SaveAndExit) {\n return this.handleSaveAndExit(request, context, h)\n }\n\n return this.handleFormSubmit(request, context, h)\n }\n }\n\n async handleFormSubmit(\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) {\n const { model } = this\n const { params } = request\n\n const cacheService = getCacheService(request.server)\n\n const { formsService } = this.model.services\n const { getFormMetadata } = formsService\n\n const formMetadata = await getFormMetadata(params.slug)\n const { notificationEmail } = formMetadata\n const { isPreview } = checkFormStatus(request.params)\n\n checkEmailAddressForLiveFormSubmission(notificationEmail, isPreview)\n\n if (notificationEmail) {\n const translator = this.getTranslator(request)\n const viewModel = this.getSummaryViewModel(request, context, translator)\n\n try {\n await submitForm(\n context,\n formMetadata,\n request,\n viewModel,\n model,\n notificationEmail,\n translator\n )\n } catch (error) {\n return this.handleSubmissionError(error, request, h)\n }\n }\n\n await cacheService.setConfirmationState(request, {\n confirmed: true,\n formId: context.state.formId,\n referenceNumber: context.referenceNumber\n } as FormConfirmationState)\n\n await cacheService.clearState(request)\n\n return this.proceed(request, h, this.getStatusPath())\n }\n\n /**\n * Handles errors during form submission\n */\n private async handleSubmissionError(\n error: unknown,\n request: FormRequestPayload,\n h: FormResponseToolkit\n ) {\n if (error instanceof InvalidComponentStateError) {\n return this.handleInvalidComponentStateError(error, request, h)\n }\n\n if (error instanceof PaymentPreAuthError) {\n return this.handlePaymentPreAuthError(error, request, h)\n }\n\n if (error instanceof PaymentSubmissionError) {\n return this.handlePaymentSubmissionError(error, request, h)\n }\n\n throw error\n }\n\n /**\n * Handles InvalidComponentStateError during submission\n */\n private async handleInvalidComponentStateError(\n error: InvalidComponentStateError,\n request: FormRequestPayload,\n h: FormResponseToolkit\n ) {\n const cacheService = getCacheService(request.server)\n\n const govukError = createError(error.component.name, error.userMessage)\n\n request.yar.flash(COMPONENT_STATE_ERROR, govukError, true)\n\n await cacheService.resetComponentStates(request, error.getStateKeys())\n\n return this.proceed(request, h, error.component.page?.path)\n }\n\n /**\n * Handles PaymentPreAuthError during submission\n */\n private async handlePaymentPreAuthError(\n error: PaymentPreAuthError,\n request: FormRequestPayload,\n h: FormResponseToolkit\n ) {\n const cacheService = getCacheService(request.server)\n\n if (error.shouldResetState) {\n await cacheService.resetComponentStates(request, error.getStateKeys())\n\n if (error.errorType === PaymentErrorTypes.PaymentExpired) {\n request.yar.flash(PAYMENT_EXPIRED_NOTIFICATION, true, true)\n return this.proceed(request, h, error.component.page?.path)\n }\n }\n\n // Payment page is skipped in the page walk, so proceed() would redirect\n // to an earlier page. For PaymentIncomplete, redirect directly to the\n // payment page using its href.\n if (\n error.errorType === PaymentErrorTypes.PaymentIncomplete &&\n error.component.page\n ) {\n return h\n .redirect(error.component.page.getHref(error.component.page.path))\n .code(StatusCodes.SEE_OTHER)\n }\n\n const govukError = createError(error.component.name, error.userMessage)\n request.yar.flash(COMPONENT_STATE_ERROR, govukError, true)\n\n const redirectPath = error.shouldResetState\n ? error.component.page?.path\n : undefined\n\n return this.proceed(request, h, redirectPath)\n }\n\n /**\n * Handles PaymentSubmissionError during submission\n */\n private handlePaymentSubmissionError(\n error: PaymentSubmissionError,\n request: FormRequestPayload,\n h: FormResponseToolkit\n ) {\n const { t } = this.getTranslator(request)\n\n const helpUrl = error.helpLink ?? DEFAULT_PAYMENT_HELP_URL\n const contactUsLink = `<a href=\"${helpUrl}\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"govuk-link\">${t('pages.summary.contactUsLinkText')}</a>`\n const helpLinkHtml = t('pages.summary.submissionFailedContactSuffix', {\n contactUsLink\n })\n\n const govukError = createError(\n 'submission',\n `${t('pages.summary.submissionFailed')}${helpLinkHtml}.`\n )\n\n request.yar.flash(COMPONENT_STATE_ERROR, govukError, true)\n\n return this.proceed(request, h)\n }\n\n get postRouteOptions(): RouteOptions<FormRequestPayloadRefs> {\n return {\n ext: {\n onPreHandler: {\n method(request, h) {\n return h.continue\n }\n }\n }\n }\n }\n}\n\nexport async function submitForm(\n context: FormContext,\n formMetadata: FormMetadata,\n request: FormRequestPayload,\n summaryViewModel: SummaryViewModel,\n model: FormModel,\n emailAddress: string,\n translator: Translator\n) {\n await finaliseComponents(request, formMetadata, context, model)\n\n const paymentWasCaptured = hasPaymentBeenCaptured(context, model)\n\n const formStatus = checkFormStatus(request.params)\n const logTags = ['submit', 'submissionApi']\n\n request.logger.info(logTags, 'Preparing email', formStatus)\n\n const items = getFormSubmissionData(\n summaryViewModel.context,\n summaryViewModel.details,\n translator,\n model\n )\n\n try {\n request.logger.info(logTags, 'Submitting data')\n const submitResponse = await submitData(\n model,\n items,\n emailAddress,\n request.yar.id,\n translator,\n summaryViewModel.context.referenceNumber\n )\n\n if (submitResponse === undefined) {\n throw Boom.badRequest('Unexpected empty response from submit api')\n }\n\n await model.services.outputService.submit(\n context,\n request,\n model,\n emailAddress,\n items,\n submitResponse,\n formMetadata\n )\n } catch (err) {\n if (paymentWasCaptured) {\n throw new PaymentSubmissionError(\n context.referenceNumber,\n formMetadata.contact?.online?.url\n )\n }\n throw err\n }\n}\n\n/**\n * Checks if any payment component has been captured\n */\nfunction hasPaymentBeenCaptured(\n context: FormContext,\n model: FormModel\n): boolean {\n for (const page of model.pages) {\n for (const field of page.collection.fields) {\n if (field instanceof PaymentField) {\n const paymentState = field.getPaymentStateFromState(context.state)\n if (paymentState?.capture?.status === 'success') {\n return true\n }\n }\n }\n }\n return false\n}\n\n/**\n * Finalises any components that need post-processing before form submission. Candidates usually involve\n * those that have external state.\n * Examples include:\n * - file uploads which are 'persisted' before submission\n * - payments which are 'captured' before submission\n */\nasync function finaliseComponents(\n request: FormRequestPayload,\n metadata: FormMetadata,\n context: FormContext,\n model: FormModel\n) {\n // Get fields from relevant pages (normal components)\n // plus PaymentField from all pages (payment page is skipped in the page walk)\n const allFields = new Set([\n ...context.relevantPages.flatMap((page) => page.collection.fields),\n ...model.pages\n .flatMap((page) => page.collection.fields)\n .filter((field) => field instanceof PaymentField)\n ])\n\n for (const component of allFields) {\n await component.onSubmit(request, metadata, context)\n }\n}\n\nfunction submitData(\n model: FormModel,\n items: DetailItem[],\n retrievalKey: string,\n sessionId: string,\n translator: Translator,\n referenceNumber: string\n) {\n const { formSubmissionService } = model.services\n const { submit } = formSubmissionService\n\n const payload: SubmitPayload = {\n sessionId,\n retrievalKey,\n referenceNumber,\n main: buildMainRecords(items, translator),\n repeaters: buildRepeaterRecords(items, translator)\n }\n return submit(payload)\n}\n\nexport function getFormSubmissionData(\n context: FormContext,\n details: Detail[],\n translator: Translator,\n model: FormModel\n) {\n const items = context.relevantPages\n .map(({ href }) =>\n details.flatMap(({ items }) =>\n items.filter(({ page }) => page.href === href)\n )\n )\n .flat()\n\n const paymentItems = getPaymentFieldItems(context, translator, model)\n\n return [...items, ...paymentItems]\n}\n\n/**\n * Gets DetailItems for PaymentField components\n * PaymentField is excluded from summaryDetails for UI but needs to be in submission data\n */\nfunction getPaymentFieldItems(\n context: FormContext,\n translator: Translator,\n model: FormModel\n): DetailItemField[] {\n const items: DetailItemField[] = []\n\n for (const page of model.pages) {\n for (const field of page.collection.fields) {\n if (field instanceof PaymentField) {\n items.push({\n name: field.name,\n page,\n title: field.title,\n label: field.summaryLabel,\n field,\n state: context.state,\n href: page.href,\n value: field.getDisplayStringFromState(context.state, translator)\n })\n }\n }\n }\n\n return items\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"SummaryPageController.js","names":["hasComponentsEvenIfNoNext","Boom","StatusCodes","COMPONENT_STATE_ERROR","PAYMENT_EXPIRED_NOTIFICATION","ComponentCollection","PaymentField","checkEmailAddressForLiveFormSubmission","checkFormStatus","createError","getCacheService","SummaryViewModel","QuestionPageController","InvalidComponentStateError","PaymentErrorTypes","PaymentPreAuthError","PaymentSubmissionError","buildMainRecords","buildRepeaterRecords","DEFAULT_PAYMENT_HELP_URL","formatCurrency","formatPaymentDate","FormAction","SummaryPageController","allowSaveAndExit","findPaymentField","model","pages","flatMap","page","collection","fields","find","field","constructor","pageDef","viewName","components","getSummaryViewModel","request","context","translator","t","viewModel","payload","errors","state","paymentField","resolvedAmount","resolveAmount","options","paymentState","getPaymentStateFromState","amount","paymentDetails","buildPaymentDetails","paymentRequired","preAuth","status","paymentPreAuthorized","getViewModel","backLink","getBackLink","feedbackLink","phaseTag","shouldShowSaveAndExit","server","rows","key","text","value","description","reference","createdAt","push","title","summaryList","makeGetRouteHandler","h","getTranslator","query","paymentComplete","handleFormSubmit","reconcilePaymentState","hasMissingNotificationEmail","view","cacheService","resetComponentStates","name","makePostRouteHandler","action","SaveAndExit","handleSaveAndExit","params","formsService","services","getFormMetadata","formMetadata","slug","notificationEmail","isPreview","submitForm","error","handleSubmissionError","setConfirmationState","confirmed","formId","referenceNumber","clearState","proceed","getStatusPath","handleInvalidComponentStateError","handlePaymentPreAuthError","handlePaymentSubmissionError","govukError","component","userMessage","yar","flash","getStateKeys","path","shouldResetState","errorType","PaymentExpired","PaymentIncomplete","redirect","getHref","code","SEE_OTHER","redirectPath","undefined","helpUrl","helpLink","contactUsLink","helpLinkHtml","postRouteOptions","ext","onPreHandler","method","continue","summaryViewModel","emailAddress","finaliseComponents","paymentWasCaptured","hasPaymentBeenCaptured","formStatus","logTags","logger","info","items","getFormSubmissionData","details","submitResponse","submitData","id","badRequest","outputService","submit","err","contact","online","url","capture","metadata","allFields","Set","relevantPages","filter","onSubmit","retrievalKey","sessionId","formSubmissionService","main","repeaters","language","def","translations","cy","map","href","flat","paymentItems","getPaymentFieldItems","label","summaryLabel","getDisplayStringFromState"],"sources":["../../../../../src/server/plugins/engine/pageControllers/SummaryPageController.ts"],"sourcesContent":["import {\n hasComponentsEvenIfNoNext,\n type FormMetadata,\n type Page,\n type SubmitPayload\n} from '@defra/forms-model'\nimport Boom from '@hapi/boom'\nimport { type RouteOptions } from '@hapi/hapi'\nimport { StatusCodes } from 'http-status-codes'\n\nimport {\n COMPONENT_STATE_ERROR,\n PAYMENT_EXPIRED_NOTIFICATION\n} from '~/src/server/constants.js'\nimport { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'\nimport { PaymentField } from '~/src/server/plugins/engine/components/PaymentField.js'\nimport {\n checkEmailAddressForLiveFormSubmission,\n checkFormStatus,\n createError,\n getCacheService\n} from '~/src/server/plugins/engine/helpers.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport {\n SummaryViewModel,\n type FormModel\n} from '~/src/server/plugins/engine/models/index.js'\nimport {\n type Detail,\n type DetailItem,\n type DetailItemField\n} from '~/src/server/plugins/engine/models/types.js'\nimport { QuestionPageController } from '~/src/server/plugins/engine/pageControllers/QuestionPageController.js'\nimport {\n InvalidComponentStateError,\n PaymentErrorTypes,\n PaymentPreAuthError,\n PaymentSubmissionError\n} from '~/src/server/plugins/engine/pageControllers/errors.js'\nimport {\n buildMainRecords,\n buildRepeaterRecords\n} from '~/src/server/plugins/engine/pageControllers/helpers/submission.js'\nimport {\n type FormConfirmationState,\n type FormContext,\n type FormContextRequest\n} from '~/src/server/plugins/engine/types.js'\nimport {\n DEFAULT_PAYMENT_HELP_URL,\n formatCurrency,\n formatPaymentDate\n} from '~/src/server/plugins/payment/helper.js'\nimport {\n FormAction,\n type FormRequest,\n type FormRequestPayload,\n type FormRequestPayloadRefs,\n type FormResponseToolkit\n} from '~/src/server/routes/types.js'\n\nexport class SummaryPageController extends QuestionPageController {\n declare pageDef: Page\n allowSaveAndExit = true\n\n /**\n * The controller which is used when Page[\"controller\"] is defined as \"./pages/summary.js\"\n */\n\n /**\n * Finds the PaymentField component across all pages in the model.\n * Payment pages are skipped in the normal page walk\n */\n private findPaymentField(): PaymentField | undefined {\n return this.model.pages\n .flatMap((page) => page.collection.fields)\n .find((field): field is PaymentField => field instanceof PaymentField)\n }\n\n constructor(model: FormModel, pageDef: Page) {\n super(model, pageDef)\n this.viewName = 'summary'\n\n // Components collection\n this.collection = new ComponentCollection(\n hasComponentsEvenIfNoNext(pageDef) ? pageDef.components : [],\n { model, page: this }\n )\n }\n\n getSummaryViewModel(\n request: FormContextRequest,\n context: FormContext,\n translator: Translator\n ): SummaryViewModel {\n const { t } = translator\n\n const viewModel = new SummaryViewModel(request, this, context, translator)\n\n const { payload, errors, state } = context\n\n const paymentField = this.findPaymentField()\n\n if (paymentField) {\n const resolvedAmount = PaymentField.resolveAmount(\n paymentField.options,\n this.model,\n state\n )\n const paymentState = paymentField.getPaymentStateFromState(state)\n\n if (paymentState?.amount === resolvedAmount) {\n viewModel.paymentState = paymentState\n viewModel.paymentDetails = this.buildPaymentDetails(\n paymentField,\n paymentState,\n t\n )\n }\n\n if (resolvedAmount > 0) {\n viewModel.paymentRequired = true\n }\n if (\n paymentState &&\n paymentState.preAuth?.status === 'success' &&\n paymentState.amount === resolvedAmount\n ) {\n viewModel.paymentPreAuthorized = true\n }\n }\n\n const components = this.collection.getViewModel({\n payload,\n errors,\n translator\n })\n\n viewModel.backLink = this.getBackLink(request, context, t)\n viewModel.feedbackLink = this.feedbackLink\n viewModel.phaseTag = this.phaseTag\n viewModel.components = components\n viewModel.allowSaveAndExit = this.shouldShowSaveAndExit(request.server)\n viewModel.errors = errors\n\n return viewModel\n }\n\n private buildPaymentDetails(\n paymentField: PaymentField,\n paymentState: NonNullable<\n ReturnType<PaymentField['getPaymentStateFromState']>\n >,\n t: (key: string, opts?: Record<string, unknown>) => string\n ) {\n const rows = [\n {\n key: { text: t('pages.summary.paymentFor') },\n value: { text: paymentState.description }\n },\n {\n key: { text: t('pages.summary.totalAmount') },\n value: { text: formatCurrency(paymentState.amount) }\n },\n {\n key: { text: t('pages.summary.reference') },\n value: { text: paymentState.reference }\n }\n ]\n\n if (paymentState.preAuth?.createdAt) {\n rows.push({\n key: { text: t('pages.summary.dateOfPayment') },\n value: { text: formatPaymentDate(paymentState.preAuth.createdAt) }\n })\n }\n\n return {\n title: { text: t('pages.summary.paymentDetailsTitle') },\n summaryList: { rows }\n }\n }\n\n /**\n * Returns an async function. This is called in plugin.ts when there is a GET request at `/{id}/{path*}`,\n */\n makeGetRouteHandler() {\n return async (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { viewName } = this\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n // After GOV.UK Pay callback, auto-submit the form instead of\n // showing CYA again. The payment is already pre-authorized.\n if (request.query.paymentComplete === 'true') {\n return this.handleFormSubmit(\n request as unknown as FormRequestPayload,\n context,\n h\n )\n }\n\n await this.reconcilePaymentState(request, context)\n\n const viewModel = this.getSummaryViewModel(request, context, translator)\n\n viewModel.hasMissingNotificationEmail =\n await this.hasMissingNotificationEmail(request, context)\n\n viewModel.t = t\n return h.view(viewName, viewModel)\n }\n }\n\n /**\n * Checks if the resolved payment amount has changed since pre-auth\n * and invalidates stale payment state if so.\n */\n private async reconcilePaymentState(\n request: FormRequest,\n context: FormContext\n ) {\n const paymentField = this.findPaymentField()\n\n if (!paymentField) {\n return\n }\n\n const resolvedAmount = PaymentField.resolveAmount(\n paymentField.options,\n this.model,\n context.state\n )\n const paymentState = paymentField.getPaymentStateFromState(context.state)\n\n if (paymentState && paymentState.amount !== resolvedAmount) {\n const cacheService = getCacheService(request.server)\n await cacheService.resetComponentStates(request, [paymentField.name])\n }\n }\n\n /**\n * Returns an async function. This is called in plugin.ts when there is a POST request at `/{id}/{path*}`.\n * If a form is incomplete, a user will be redirected to the start page.\n */\n makePostRouteHandler() {\n return async (\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { action } = request.payload\n if (action === FormAction.SaveAndExit) {\n return this.handleSaveAndExit(request, context, h)\n }\n\n return this.handleFormSubmit(request, context, h)\n }\n }\n\n async handleFormSubmit(\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) {\n const { model } = this\n const { params } = request\n\n const cacheService = getCacheService(request.server)\n\n const { formsService } = this.model.services\n const { getFormMetadata } = formsService\n\n const formMetadata = await getFormMetadata(params.slug)\n const { notificationEmail } = formMetadata\n const { isPreview } = checkFormStatus(request.params)\n\n checkEmailAddressForLiveFormSubmission(notificationEmail, isPreview)\n\n if (notificationEmail) {\n const translator = this.getTranslator(request)\n const viewModel = this.getSummaryViewModel(request, context, translator)\n\n try {\n await submitForm(\n context,\n formMetadata,\n request,\n viewModel,\n model,\n notificationEmail,\n translator\n )\n } catch (error) {\n return this.handleSubmissionError(error, request, h)\n }\n }\n\n await cacheService.setConfirmationState(request, {\n confirmed: true,\n formId: context.state.formId,\n referenceNumber: context.referenceNumber\n } as FormConfirmationState)\n\n await cacheService.clearState(request)\n\n return this.proceed(request, h, this.getStatusPath())\n }\n\n /**\n * Handles errors during form submission\n */\n private async handleSubmissionError(\n error: unknown,\n request: FormRequestPayload,\n h: FormResponseToolkit\n ) {\n if (error instanceof InvalidComponentStateError) {\n return this.handleInvalidComponentStateError(error, request, h)\n }\n\n if (error instanceof PaymentPreAuthError) {\n return this.handlePaymentPreAuthError(error, request, h)\n }\n\n if (error instanceof PaymentSubmissionError) {\n return this.handlePaymentSubmissionError(error, request, h)\n }\n\n throw error\n }\n\n /**\n * Handles InvalidComponentStateError during submission\n */\n private async handleInvalidComponentStateError(\n error: InvalidComponentStateError,\n request: FormRequestPayload,\n h: FormResponseToolkit\n ) {\n const cacheService = getCacheService(request.server)\n\n const govukError = createError(error.component.name, error.userMessage)\n\n request.yar.flash(COMPONENT_STATE_ERROR, govukError, true)\n\n await cacheService.resetComponentStates(request, error.getStateKeys())\n\n return this.proceed(request, h, error.component.page?.path)\n }\n\n /**\n * Handles PaymentPreAuthError during submission\n */\n private async handlePaymentPreAuthError(\n error: PaymentPreAuthError,\n request: FormRequestPayload,\n h: FormResponseToolkit\n ) {\n const cacheService = getCacheService(request.server)\n\n if (error.shouldResetState) {\n await cacheService.resetComponentStates(request, error.getStateKeys())\n\n if (error.errorType === PaymentErrorTypes.PaymentExpired) {\n request.yar.flash(PAYMENT_EXPIRED_NOTIFICATION, true, true)\n return this.proceed(request, h, error.component.page?.path)\n }\n }\n\n // Payment page is skipped in the page walk, so proceed() would redirect\n // to an earlier page. For PaymentIncomplete, redirect directly to the\n // payment page using its href.\n if (\n error.errorType === PaymentErrorTypes.PaymentIncomplete &&\n error.component.page\n ) {\n return h\n .redirect(error.component.page.getHref(error.component.page.path))\n .code(StatusCodes.SEE_OTHER)\n }\n\n const govukError = createError(error.component.name, error.userMessage)\n request.yar.flash(COMPONENT_STATE_ERROR, govukError, true)\n\n const redirectPath = error.shouldResetState\n ? error.component.page?.path\n : undefined\n\n return this.proceed(request, h, redirectPath)\n }\n\n /**\n * Handles PaymentSubmissionError during submission\n */\n private handlePaymentSubmissionError(\n error: PaymentSubmissionError,\n request: FormRequestPayload,\n h: FormResponseToolkit\n ) {\n const { t } = this.getTranslator(request)\n\n const helpUrl = error.helpLink ?? DEFAULT_PAYMENT_HELP_URL\n const contactUsLink = `<a href=\"${helpUrl}\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"govuk-link\">${t('pages.summary.contactUsLinkText')}</a>`\n const helpLinkHtml = t('pages.summary.submissionFailedContactSuffix', {\n contactUsLink\n })\n\n const govukError = createError(\n 'submission',\n `${t('pages.summary.submissionFailed')}${helpLinkHtml}.`\n )\n\n request.yar.flash(COMPONENT_STATE_ERROR, govukError, true)\n\n return this.proceed(request, h)\n }\n\n get postRouteOptions(): RouteOptions<FormRequestPayloadRefs> {\n return {\n ext: {\n onPreHandler: {\n method(request, h) {\n return h.continue\n }\n }\n }\n }\n }\n}\n\nexport async function submitForm(\n context: FormContext,\n formMetadata: FormMetadata,\n request: FormRequestPayload,\n summaryViewModel: SummaryViewModel,\n model: FormModel,\n emailAddress: string,\n translator: Translator\n) {\n await finaliseComponents(request, formMetadata, context, model)\n\n const paymentWasCaptured = hasPaymentBeenCaptured(context, model)\n\n const formStatus = checkFormStatus(request.params)\n const logTags = ['submit', 'submissionApi']\n\n request.logger.info(logTags, 'Preparing email', formStatus)\n\n const items = getFormSubmissionData(\n summaryViewModel.context,\n summaryViewModel.details,\n translator,\n model\n )\n\n try {\n request.logger.info(logTags, 'Submitting data')\n const submitResponse = await submitData(\n model,\n items,\n emailAddress,\n request.yar.id,\n translator,\n summaryViewModel.context.referenceNumber\n )\n\n if (submitResponse === undefined) {\n throw Boom.badRequest('Unexpected empty response from submit api')\n }\n\n await model.services.outputService.submit(\n context,\n request,\n model,\n emailAddress,\n items,\n submitResponse,\n formMetadata\n )\n } catch (err) {\n if (paymentWasCaptured) {\n throw new PaymentSubmissionError(\n context.referenceNumber,\n formMetadata.contact?.online?.url\n )\n }\n throw err\n }\n}\n\n/**\n * Checks if any payment component has been captured\n */\nfunction hasPaymentBeenCaptured(\n context: FormContext,\n model: FormModel\n): boolean {\n for (const page of model.pages) {\n for (const field of page.collection.fields) {\n if (field instanceof PaymentField) {\n const paymentState = field.getPaymentStateFromState(context.state)\n if (paymentState?.capture?.status === 'success') {\n return true\n }\n }\n }\n }\n return false\n}\n\n/**\n * Finalises any components that need post-processing before form submission. Candidates usually involve\n * those that have external state.\n * Examples include:\n * - file uploads which are 'persisted' before submission\n * - payments which are 'captured' before submission\n */\nasync function finaliseComponents(\n request: FormRequestPayload,\n metadata: FormMetadata,\n context: FormContext,\n model: FormModel\n) {\n // Get fields from relevant pages (normal components)\n // plus PaymentField from all pages (payment page is skipped in the page walk)\n const allFields = new Set([\n ...context.relevantPages.flatMap((page) => page.collection.fields),\n ...model.pages\n .flatMap((page) => page.collection.fields)\n .filter((field) => field instanceof PaymentField)\n ])\n\n for (const component of allFields) {\n await component.onSubmit(request, metadata, context)\n }\n}\n\nfunction submitData(\n model: FormModel,\n items: DetailItem[],\n retrievalKey: string,\n sessionId: string,\n translator: Translator,\n referenceNumber: string\n) {\n const { formSubmissionService } = model.services\n const { submit } = formSubmissionService\n\n const payload: SubmitPayload = {\n sessionId,\n retrievalKey,\n referenceNumber,\n main: buildMainRecords(items, translator),\n repeaters: buildRepeaterRecords(items, translator),\n // Only populate the language property if the form is multi-language enabled\n // @ts-expect-error - dynamic language property\n language: model.def.metadata?.translations?.cy\n ? translator.language\n : undefined\n }\n return submit(payload)\n}\n\nexport function getFormSubmissionData(\n context: FormContext,\n details: Detail[],\n translator: Translator,\n model: FormModel\n) {\n const items = context.relevantPages\n .map(({ href }) =>\n details.flatMap(({ items }) =>\n items.filter(({ page }) => page.href === href)\n )\n )\n .flat()\n\n const paymentItems = getPaymentFieldItems(context, translator, model)\n\n return [...items, ...paymentItems]\n}\n\n/**\n * Gets DetailItems for PaymentField components\n * PaymentField is excluded from summaryDetails for UI but needs to be in submission data\n */\nfunction getPaymentFieldItems(\n context: FormContext,\n translator: Translator,\n model: FormModel\n): DetailItemField[] {\n const items: DetailItemField[] = []\n\n for (const page of model.pages) {\n for (const field of page.collection.fields) {\n if (field instanceof PaymentField) {\n items.push({\n name: field.name,\n page,\n title: field.title,\n label: field.summaryLabel,\n field,\n state: context.state,\n href: page.href,\n value: field.getDisplayStringFromState(context.state, translator)\n })\n }\n }\n }\n\n return items\n}\n"],"mappings":"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","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@defra/forms-engine-plugin",
|
|
3
|
-
"version": "5.0.0-alpha.
|
|
3
|
+
"version": "5.0.0-alpha.7",
|
|
4
4
|
"description": "Defra forms engine",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
},
|
|
88
88
|
"license": "SEE LICENSE IN LICENSE",
|
|
89
89
|
"dependencies": {
|
|
90
|
-
"@defra/forms-model": "^3.0.
|
|
90
|
+
"@defra/forms-model": "^3.0.689",
|
|
91
91
|
"@defra/hapi-tracing": "^1.29.0",
|
|
92
92
|
"@defra/interactive-map": "^0.0.33-alpha",
|
|
93
93
|
"@elastic/ecs-pino-format": "^1.5.0",
|
package/src/server/constants.js
CHANGED
|
@@ -5,3 +5,4 @@ export const EXTERNAL_STATE_PAYLOAD = 'EXTERNAL_STATE_PAYLOAD'
|
|
|
5
5
|
export const EXTERNAL_STATE_APPENDAGE = 'EXTERNAL_STATE_APPENDAGE'
|
|
6
6
|
export const COMPONENT_STATE_ERROR = 'COMPONENT_STATE_ERROR'
|
|
7
7
|
export const PAYMENT_EXPIRED_NOTIFICATION = 'PAYMENT_EXPIRED_NOTIFICATION'
|
|
8
|
+
export const EN_GB = 'en-GB'
|
|
@@ -28,6 +28,7 @@ export class ComponentBase {
|
|
|
28
28
|
|
|
29
29
|
isFormComponent = false
|
|
30
30
|
model: FormModel
|
|
31
|
+
def: ComponentDef
|
|
31
32
|
|
|
32
33
|
/** joi schemas based on a component defined in the form JSON. This validates a user's answer and is generated from {@link ComponentDef} */
|
|
33
34
|
formSchema: ComponentSchema = joi.string()
|
|
@@ -45,6 +46,7 @@ export class ComponentBase {
|
|
|
45
46
|
this.type = def.type
|
|
46
47
|
this.name = def.name
|
|
47
48
|
this.title = def.title
|
|
49
|
+
this.def = def
|
|
48
50
|
|
|
49
51
|
if ('schema' in def) {
|
|
50
52
|
this.schema = def.schema
|
|
@@ -308,12 +308,11 @@ export class ComponentCollection {
|
|
|
308
308
|
labelOverrides[subField.name] = patchedSchema
|
|
309
309
|
}
|
|
310
310
|
} else {
|
|
311
|
+
const fieldDef = field.def
|
|
311
312
|
const translatedLabel =
|
|
312
|
-
translator.tComponent(
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
) ||
|
|
316
|
-
translator.tComponent(field as unknown as ComponentDef, 'title')
|
|
313
|
+
translator.tComponent(fieldDef, 'errorDescription') ||
|
|
314
|
+
translator.tComponent(fieldDef, 'shortDescription') ||
|
|
315
|
+
translator.tComponent(fieldDef, 'title')
|
|
317
316
|
const messagesOverride =
|
|
318
317
|
field.getValidationMessagesOverride(translator)
|
|
319
318
|
let patchedSchema = field.formSchema
|
|
@@ -2,7 +2,6 @@ import {
|
|
|
2
2
|
ComponentType,
|
|
3
3
|
hasFormComponents,
|
|
4
4
|
isFormType,
|
|
5
|
-
type ComponentDef,
|
|
6
5
|
type DeclarationFieldComponent,
|
|
7
6
|
type Item
|
|
8
7
|
} from '@defra/forms-model'
|
|
@@ -148,7 +147,7 @@ export class DeclarationField extends FormComponent {
|
|
|
148
147
|
'components.declarationField.defaultLabel'
|
|
149
148
|
)
|
|
150
149
|
} = this
|
|
151
|
-
const content = tComponent(this
|
|
150
|
+
const content = tComponent(this.def, 'content')
|
|
152
151
|
|
|
153
152
|
const viewModel = super.getViewModel(context)
|
|
154
153
|
let { fieldset, label } = viewModel
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {
|
|
2
|
-
type ComponentDef,
|
|
3
2
|
type FormComponentsDef,
|
|
4
3
|
type FormMetadata,
|
|
5
4
|
type Item
|
|
@@ -178,15 +177,14 @@ export class FormComponent extends ComponentBase {
|
|
|
178
177
|
const isRequired = !('required' in options) || options.required !== false
|
|
179
178
|
const hideOptional = 'optionalText' in options && options.optionalText
|
|
180
179
|
|
|
181
|
-
const resolvedTitle =
|
|
182
|
-
tComponent(this as unknown as ComponentDef, 'title') || title
|
|
180
|
+
const resolvedTitle = tComponent(this.def, 'title') || title
|
|
183
181
|
const optionalTag =
|
|
184
182
|
!isRequired && !hideOptional ? ` ${t('common.optional')}` : ''
|
|
185
183
|
const label = `${resolvedTitle}${optionalTag}`
|
|
186
184
|
|
|
187
185
|
if (hint) {
|
|
188
186
|
viewModel.hint = {
|
|
189
|
-
text: tComponent(this
|
|
187
|
+
text: tComponent(this.def, 'hint') || hint
|
|
190
188
|
}
|
|
191
189
|
}
|
|
192
190
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type MarkdownComponent } from '@defra/forms-model'
|
|
2
2
|
|
|
3
3
|
import { ComponentBase } from './ComponentBase.js'
|
|
4
4
|
import { type RenderContext } from './types.js'
|
|
@@ -28,8 +28,7 @@ export class Markdown extends ComponentBase {
|
|
|
28
28
|
|
|
29
29
|
return {
|
|
30
30
|
...viewModel,
|
|
31
|
-
content:
|
|
32
|
-
tComponent(this as unknown as ComponentDef, 'content') || content,
|
|
31
|
+
content: tComponent(this.def, 'content') || content,
|
|
33
32
|
headerStartLevel: this.headerStartLevel
|
|
34
33
|
}
|
|
35
34
|
}
|
|
@@ -212,12 +212,12 @@ function ItemRepeat(
|
|
|
212
212
|
translator: Translator
|
|
213
213
|
): DetailItemRepeat {
|
|
214
214
|
const { collection, repeat } = page
|
|
215
|
-
const { name
|
|
216
|
-
|
|
215
|
+
const { name } = repeat.options
|
|
216
|
+
const { t, tPage } = translator
|
|
217
|
+
const title = tPage(page.pageDef, 'repeatTitle') || repeat.options.title
|
|
217
218
|
const values = page.getListFromState(state)
|
|
218
219
|
const count = values.length
|
|
219
|
-
const value =
|
|
220
|
-
count === 0 ? '' : translator.t('pages.repeater.pageTitle', { count })
|
|
220
|
+
const value = count === 0 ? '' : t('pages.repeater.pageTitle', { count })
|
|
221
221
|
|
|
222
222
|
return {
|
|
223
223
|
name,
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
type SubmitResponsePayload
|
|
4
4
|
} from '@defra/forms-model'
|
|
5
5
|
|
|
6
|
+
import { EN_GB } from '../../../../constants.js'
|
|
6
7
|
import {
|
|
7
8
|
getFormVersion,
|
|
8
9
|
type checkFormStatus
|
|
@@ -42,18 +43,14 @@ export function format(
|
|
|
42
43
|
formSlug: formMetadata?.slug ?? '',
|
|
43
44
|
status: formStatus.state,
|
|
44
45
|
isPreview: formStatus.isPreview,
|
|
45
|
-
notificationEmail: formMetadata?.notificationEmail ?? ''
|
|
46
|
+
notificationEmail: formMetadata?.notificationEmail ?? '',
|
|
47
|
+
language: context.translator?.language ?? EN_GB
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
if (versionMetadata) {
|
|
49
51
|
meta.versionMetadata = versionMetadata
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
const definitionLanguage = model.def.metadata?.language
|
|
53
|
-
if (typeof definitionLanguage === 'string') {
|
|
54
|
-
meta.language = definitionLanguage
|
|
55
|
-
}
|
|
56
|
-
|
|
57
54
|
const main = Object.fromEntries(
|
|
58
55
|
Object.entries(v2Main).map(([key, value]) => {
|
|
59
56
|
if (value === undefined) {
|
|
@@ -406,9 +406,9 @@ export class RepeatPageController extends QuestionPageController {
|
|
|
406
406
|
const { query } = request
|
|
407
407
|
const { isForceAccess, errors } = context
|
|
408
408
|
|
|
409
|
-
const { t } = translator
|
|
409
|
+
const { t, tPage } = translator
|
|
410
410
|
|
|
411
|
-
const
|
|
411
|
+
const title = tPage(this.pageDef, 'repeatTitle') || repeat.options.title
|
|
412
412
|
|
|
413
413
|
const summaryList: SummaryList = {
|
|
414
414
|
classes: 'govuk-summary-list--long-actions',
|
|
@@ -557,7 +557,12 @@ function submitData(
|
|
|
557
557
|
retrievalKey,
|
|
558
558
|
referenceNumber,
|
|
559
559
|
main: buildMainRecords(items, translator),
|
|
560
|
-
repeaters: buildRepeaterRecords(items, translator)
|
|
560
|
+
repeaters: buildRepeaterRecords(items, translator),
|
|
561
|
+
// Only populate the language property if the form is multi-language enabled
|
|
562
|
+
// @ts-expect-error - dynamic language property
|
|
563
|
+
language: model.def.metadata?.translations?.cy
|
|
564
|
+
? translator.language
|
|
565
|
+
: undefined
|
|
561
566
|
}
|
|
562
567
|
return submit(payload)
|
|
563
568
|
}
|