@defra/forms-engine-plugin 5.0.0-alpha.7 → 5.0.0-alpha.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.public/javascripts/application.min.js.map +1 -1
- package/.public/javascripts/shared.min.js +1 -1
- package/.public/javascripts/shared.min.js.map +1 -1
- package/.public/stylesheets/application.min.css.map +1 -1
- package/.server/client/javascripts/maps.d.ts +5 -0
- package/.server/client/javascripts/maps.js +6 -0
- package/.server/client/javascripts/maps.js.map +1 -0
- package/.server/client/javascripts/shared.d.ts +1 -4
- package/.server/client/javascripts/shared.js +1 -4
- package/.server/client/javascripts/shared.js.map +1 -1
- package/.server/client/stylesheets/maps.scss +4 -0
- package/.server/client/stylesheets/shared.scss +1 -5
- package/.server/server/constants.d.ts +1 -0
- package/.server/server/constants.js +2 -1
- package/.server/server/constants.js.map +1 -1
- package/.server/server/plugins/engine/components/ComponentCollection.js +10 -6
- package/.server/server/plugins/engine/components/ComponentCollection.js.map +1 -1
- package/.server/server/plugins/engine/components/DatePartsField.d.ts +4 -2
- package/.server/server/plugins/engine/components/DatePartsField.js +14 -11
- package/.server/server/plugins/engine/components/DatePartsField.js.map +1 -1
- package/.server/server/plugins/engine/components/DeclarationField.d.ts +4 -2
- package/.server/server/plugins/engine/components/DeclarationField.js +5 -3
- package/.server/server/plugins/engine/components/DeclarationField.js.map +1 -1
- package/.server/server/plugins/engine/components/EastingNorthingField.d.ts +24 -2
- package/.server/server/plugins/engine/components/EastingNorthingField.js +93 -52
- package/.server/server/plugins/engine/components/EastingNorthingField.js.map +1 -1
- package/.server/server/plugins/engine/components/FormComponent.d.ts +4 -1
- package/.server/server/plugins/engine/components/FormComponent.js +3 -0
- package/.server/server/plugins/engine/components/FormComponent.js.map +1 -1
- package/.server/server/plugins/engine/components/LatLongField.d.ts +24 -2
- package/.server/server/plugins/engine/components/LatLongField.js +85 -46
- package/.server/server/plugins/engine/components/LatLongField.js.map +1 -1
- package/.server/server/plugins/engine/components/LocationFieldHelpers.d.ts +3 -2
- package/.server/server/plugins/engine/components/LocationFieldHelpers.js +10 -11
- package/.server/server/plugins/engine/components/LocationFieldHelpers.js.map +1 -1
- package/.server/server/plugins/engine/components/MonthYearField.d.ts +4 -2
- package/.server/server/plugins/engine/components/MonthYearField.js +16 -13
- package/.server/server/plugins/engine/components/MonthYearField.js.map +1 -1
- package/.server/server/plugins/engine/components/PaymentField.d.ts +1 -0
- package/.server/server/plugins/engine/components/PaymentField.js +9 -5
- package/.server/server/plugins/engine/components/PaymentField.js.map +1 -1
- package/.server/server/plugins/engine/components/UkAddressField.js +22 -7
- package/.server/server/plugins/engine/components/UkAddressField.js.map +1 -1
- package/.server/server/plugins/engine/components/YesNoField.d.ts +3 -2
- package/.server/server/plugins/engine/components/YesNoField.js +5 -3
- package/.server/server/plugins/engine/components/YesNoField.js.map +1 -1
- package/.server/server/plugins/engine/components/helpers/components.js +1 -2
- package/.server/server/plugins/engine/components/helpers/components.js.map +1 -1
- package/.server/server/plugins/engine/components/helpers/index.d.ts +7 -0
- package/.server/server/plugins/engine/components/helpers/index.js +13 -1
- package/.server/server/plugins/engine/components/helpers/index.js.map +1 -1
- package/.server/server/plugins/engine/helpers.d.ts +21 -2
- package/.server/server/plugins/engine/helpers.js +43 -5
- package/.server/server/plugins/engine/helpers.js.map +1 -1
- package/.server/server/plugins/engine/i18n/createFormTranslator.d.ts +4 -4
- package/.server/server/plugins/engine/i18n/createFormTranslator.js +27 -5
- package/.server/server/plugins/engine/i18n/createFormTranslator.js.map +1 -1
- package/.server/server/plugins/engine/i18n/extractBaseTranslations.d.ts +1 -1
- package/.server/server/plugins/engine/i18n/extractBaseTranslations.js +9 -0
- package/.server/server/plugins/engine/i18n/extractBaseTranslations.js.map +1 -1
- package/.server/server/plugins/engine/i18n/form.d.ts +13 -0
- package/.server/server/plugins/engine/i18n/form.js +35 -0
- package/.server/server/plugins/engine/i18n/form.js.map +1 -0
- package/.server/server/plugins/engine/i18n/languages.d.ts +10 -0
- package/.server/server/plugins/engine/i18n/languages.js +19 -0
- package/.server/server/plugins/engine/i18n/languages.js.map +1 -0
- package/.server/server/plugins/engine/i18n/translations/cy.json +3 -1
- package/.server/server/plugins/engine/i18n/translations/en-GB.json +3 -1
- package/.server/server/plugins/engine/index.d.ts +3 -0
- package/.server/server/plugins/engine/index.js +3 -0
- package/.server/server/plugins/engine/index.js.map +1 -1
- package/.server/server/plugins/engine/models/FormModel.d.ts +0 -4
- package/.server/server/plugins/engine/models/FormModel.js +9 -15
- package/.server/server/plugins/engine/models/FormModel.js.map +1 -1
- package/.server/server/plugins/engine/models/SummaryViewModel.js +2 -1
- package/.server/server/plugins/engine/models/SummaryViewModel.js.map +1 -1
- package/.server/server/plugins/engine/outputFormatters/human/v1.js +2 -1
- package/.server/server/plugins/engine/outputFormatters/human/v1.js.map +1 -1
- package/.server/server/plugins/engine/outputFormatters/machine/v2.d.ts +2 -0
- package/.server/server/plugins/engine/outputFormatters/machine/v2.js +2 -0
- package/.server/server/plugins/engine/outputFormatters/machine/v2.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/FileUploadPageController.d.ts +1 -1
- package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js +2 -2
- package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/QuestionPageController.d.ts +1 -1
- package/.server/server/plugins/engine/pageControllers/QuestionPageController.js +2 -2
- package/.server/server/plugins/engine/pageControllers/QuestionPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +6 -3
- package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/helpers/submission.d.ts +1 -1
- package/.server/server/plugins/engine/pageControllers/helpers/submission.js +3 -3
- package/.server/server/plugins/engine/pageControllers/helpers/submission.js.map +1 -1
- package/.server/server/plugins/engine/types/schema.js +1 -0
- package/.server/server/plugins/engine/types/schema.js.map +1 -1
- package/.server/server/plugins/engine/types.d.ts +1 -0
- package/.server/server/plugins/engine/types.js.map +1 -1
- package/.server/server/plugins/engine/views/components/ukaddressfield.html +1 -1
- package/.server/server/plugins/nunjucks/filters/applyUrlParam.d.ts +9 -0
- package/.server/server/plugins/nunjucks/filters/applyUrlParam.js +17 -0
- package/.server/server/plugins/nunjucks/filters/applyUrlParam.js.map +1 -0
- package/.server/server/plugins/nunjucks/filters/applyUrlParam.test.js +17 -0
- package/.server/server/plugins/nunjucks/filters/applyUrlParam.test.js.map +1 -0
- package/.server/server/plugins/nunjucks/filters/field.d.ts +1 -1
- package/.server/server/plugins/nunjucks/filters/index.d.ts +1 -0
- package/.server/server/plugins/nunjucks/filters/index.js +1 -0
- package/.server/server/plugins/nunjucks/filters/index.js.map +1 -1
- package/.server/server/plugins/payment/helper.d.ts +11 -1
- package/.server/server/plugins/payment/helper.js +18 -2
- package/.server/server/plugins/payment/helper.js.map +1 -1
- package/.server/server/plugins/payment/helper.test.js +2 -1
- package/.server/server/plugins/payment/helper.test.js.map +1 -1
- package/.server/server/plugins/payment/service.d.ts +2 -1
- package/.server/server/plugins/payment/service.js +5 -2
- package/.server/server/plugins/payment/service.js.map +1 -1
- package/.server/server/plugins/payment/service.test.js +7 -3
- package/.server/server/plugins/payment/service.test.js.map +1 -1
- package/.server/server/plugins/payment/types.d.ts +4 -0
- package/.server/server/plugins/payment/types.js +1 -0
- package/.server/server/plugins/payment/types.js.map +1 -1
- package/.server/server/plugins/postcode-lookup/models/index.d.ts +247 -3
- package/.server/server/plugins/postcode-lookup/models/index.js +86 -33
- package/.server/server/plugins/postcode-lookup/models/index.js.map +1 -1
- package/.server/server/plugins/postcode-lookup/routes/index.d.ts +15 -1
- package/.server/server/plugins/postcode-lookup/routes/index.js +47 -15
- package/.server/server/plugins/postcode-lookup/routes/index.js.map +1 -1
- package/.server/server/plugins/postcode-lookup/routes/index.test.js +84 -0
- package/.server/server/plugins/postcode-lookup/routes/index.test.js.map +1 -0
- package/.server/server/plugins/postcode-lookup/types.d.ts +12 -0
- package/.server/server/plugins/postcode-lookup/types.js +6 -1
- package/.server/server/plugins/postcode-lookup/types.js.map +1 -1
- package/.server/server/plugins/postcode-lookup/views/postcode-lookup-details.html +3 -3
- package/package.json +7 -1
- package/src/client/javascripts/maps.js +5 -0
- package/src/client/javascripts/shared.js +1 -4
- package/src/client/stylesheets/maps.scss +4 -0
- package/src/client/stylesheets/shared.scss +1 -5
- package/src/server/constants.js +2 -1
- package/src/server/plugins/engine/components/ComponentCollection.ts +15 -9
- package/src/server/plugins/engine/components/DatePartsField.ts +16 -12
- package/src/server/plugins/engine/components/DeclarationField.ts +6 -4
- package/src/server/plugins/engine/components/EastingNorthingField.ts +156 -88
- package/src/server/plugins/engine/components/FormComponent.ts +4 -1
- package/src/server/plugins/engine/components/LatLongField.ts +129 -57
- package/src/server/plugins/engine/components/LocationFieldHelpers.ts +14 -11
- package/src/server/plugins/engine/components/MonthYearField.ts +16 -11
- package/src/server/plugins/engine/components/PaymentField.ts +9 -4
- package/src/server/plugins/engine/components/UkAddressField.ts +29 -6
- package/src/server/plugins/engine/components/YesNoField.ts +6 -5
- package/src/server/plugins/engine/components/helpers/components.ts +1 -2
- package/src/server/plugins/engine/components/helpers/index.ts +19 -0
- package/src/server/plugins/engine/helpers.ts +51 -5
- package/src/server/plugins/engine/i18n/createFormTranslator.ts +43 -12
- package/src/server/plugins/engine/i18n/extractBaseTranslations.ts +7 -1
- package/src/server/plugins/engine/i18n/form.ts +54 -0
- package/src/server/plugins/engine/i18n/languages.ts +19 -0
- package/src/server/plugins/engine/i18n/translations/cy.json +3 -1
- package/src/server/plugins/engine/i18n/translations/en-GB.json +3 -1
- package/src/server/plugins/engine/index.ts +6 -0
- package/src/server/plugins/engine/models/FormModel.ts +9 -15
- package/src/server/plugins/engine/models/SummaryViewModel.ts +2 -1
- package/src/server/plugins/engine/outputFormatters/human/v1.ts +2 -1
- package/src/server/plugins/engine/outputFormatters/machine/v2.ts +3 -0
- package/src/server/plugins/engine/pageControllers/FileUploadPageController.ts +2 -2
- package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +2 -2
- package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +9 -3
- package/src/server/plugins/engine/pageControllers/helpers/submission.ts +6 -3
- package/src/server/plugins/engine/types/schema.ts +1 -0
- package/src/server/plugins/engine/types.ts +1 -0
- package/src/server/plugins/engine/views/components/ukaddressfield.html +1 -1
- package/src/server/plugins/nunjucks/filters/applyUrlParam.js +17 -0
- package/src/server/plugins/nunjucks/filters/index.js +1 -0
- package/src/server/plugins/payment/helper.js +22 -2
- package/src/server/plugins/payment/service.js +6 -2
- package/src/server/plugins/payment/types.js +1 -0
- package/src/server/plugins/postcode-lookup/models/index.js +75 -43
- package/src/server/plugins/postcode-lookup/routes/index.js +73 -16
- package/src/server/plugins/postcode-lookup/types.js +6 -1
- package/src/server/plugins/postcode-lookup/views/postcode-lookup-details.html +3 -3
|
@@ -114,7 +114,7 @@ export class SummaryPageController extends QuestionPageController {
|
|
|
114
114
|
viewModel.paymentDetails = this.buildPaymentDetails(
|
|
115
115
|
paymentField,
|
|
116
116
|
paymentState,
|
|
117
|
-
|
|
117
|
+
translator
|
|
118
118
|
)
|
|
119
119
|
}
|
|
120
120
|
|
|
@@ -151,8 +151,9 @@ export class SummaryPageController extends QuestionPageController {
|
|
|
151
151
|
paymentState: NonNullable<
|
|
152
152
|
ReturnType<PaymentField['getPaymentStateFromState']>
|
|
153
153
|
>,
|
|
154
|
-
|
|
154
|
+
translator: Translator
|
|
155
155
|
) {
|
|
156
|
+
const { t } = translator
|
|
156
157
|
const rows = [
|
|
157
158
|
{
|
|
158
159
|
key: { text: t('pages.summary.paymentFor') },
|
|
@@ -171,7 +172,12 @@ export class SummaryPageController extends QuestionPageController {
|
|
|
171
172
|
if (paymentState.preAuth?.createdAt) {
|
|
172
173
|
rows.push({
|
|
173
174
|
key: { text: t('pages.summary.dateOfPayment') },
|
|
174
|
-
value: {
|
|
175
|
+
value: {
|
|
176
|
+
text: formatPaymentDate(
|
|
177
|
+
paymentState.preAuth.createdAt,
|
|
178
|
+
translator.language
|
|
179
|
+
)
|
|
180
|
+
}
|
|
175
181
|
})
|
|
176
182
|
}
|
|
177
183
|
|
|
@@ -36,7 +36,7 @@ export function buildMainRecords(
|
|
|
36
36
|
|
|
37
37
|
for (const item of fieldItems) {
|
|
38
38
|
if (item.field instanceof PaymentField) {
|
|
39
|
-
records.push(...buildPaymentRecords(item))
|
|
39
|
+
records.push(...buildPaymentRecords(item, translator))
|
|
40
40
|
} else if (item.field instanceof GeospatialField) {
|
|
41
41
|
// Stringify of GeoJSON is done here rather than inside `getContextValueFromState`
|
|
42
42
|
// so we don't incur the overhead of JSON.stringify on every request when building context
|
|
@@ -67,7 +67,10 @@ export function buildMainRecords(
|
|
|
67
67
|
*
|
|
68
68
|
* Returns an empty array if no payment state exists.
|
|
69
69
|
*/
|
|
70
|
-
export function buildPaymentRecords(
|
|
70
|
+
export function buildPaymentRecords(
|
|
71
|
+
item: DetailItemField,
|
|
72
|
+
translator: Translator
|
|
73
|
+
): SubmitRecord[] {
|
|
71
74
|
const paymentState = (item.field as PaymentField).getPaymentStateFromState(
|
|
72
75
|
item.state
|
|
73
76
|
)
|
|
@@ -96,7 +99,7 @@ export function buildPaymentRecords(item: DetailItemField): SubmitRecord[] {
|
|
|
96
99
|
name: `${item.name}_paymentDate`,
|
|
97
100
|
title: 'Payment date',
|
|
98
101
|
value: paymentState.preAuth?.createdAt
|
|
99
|
-
? formatPaymentDate(paymentState.preAuth.createdAt)
|
|
102
|
+
? formatPaymentDate(paymentState.preAuth.createdAt, translator.language)
|
|
100
103
|
: ''
|
|
101
104
|
}
|
|
102
105
|
]
|
|
@@ -50,6 +50,7 @@ export const formAdapterSubmissionMessageDataSchema =
|
|
|
50
50
|
reference: Joi.string().required(),
|
|
51
51
|
amount: Joi.number().required(),
|
|
52
52
|
description: Joi.string().required(),
|
|
53
|
+
descriptionInEng: Joi.string().optional(),
|
|
53
54
|
createdAt: Joi.string().required()
|
|
54
55
|
})
|
|
55
56
|
.optional(),
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
},
|
|
62
62
|
classes: "govuk-button--secondary govuk-!-margin-right-1 govuk-!-margin-bottom-0"
|
|
63
63
|
}) }}
|
|
64
|
-
<p class="govuk-body govuk-!-margin-bottom-0">or <button class="govuk-link govuk-button--link govuk-!-margin-right-1 govuk-!-margin-bottom-0" name="action" value="external-{{component.model.name}}--step:manual">{{ t('components.addressField.enterManually') }}</button></p>
|
|
64
|
+
<p class="govuk-body govuk-!-margin-bottom-0">{{ t('common.or')}} <button class="govuk-link govuk-button--link govuk-!-margin-right-1 govuk-!-margin-bottom-0" name="action" value="external-{{component.model.name}}--step:manual">{{ t('components.addressField.enterManually') }}</button></p>
|
|
65
65
|
</div>
|
|
66
66
|
{# Include a line break if this is the last component #}
|
|
67
67
|
{% if components[components.length - 1] == component %}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nunjucks filter to add/replace a parameter on a query string of a url.
|
|
3
|
+
* Currently only used in forms-runner.
|
|
4
|
+
* @param {string} urlPath - existing relative url with query string
|
|
5
|
+
* @param {string} paramName - name of parameter
|
|
6
|
+
* @param {string} paramValue - value of parameter
|
|
7
|
+
* @returns {string}
|
|
8
|
+
*/
|
|
9
|
+
export function applyUrlParam(urlPath, paramName, paramValue) {
|
|
10
|
+
if (typeof urlPath !== 'string') {
|
|
11
|
+
return ''
|
|
12
|
+
}
|
|
13
|
+
const url = new URL(urlPath, 'https://dummy')
|
|
14
|
+
url.searchParams.set(paramName, paramValue)
|
|
15
|
+
|
|
16
|
+
return url.pathname + url.search
|
|
17
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { format } from 'date-fns'
|
|
2
2
|
|
|
3
|
+
import { toLanguageLocale } from '../engine/helpers.js'
|
|
3
4
|
import { PaymentService } from './service.js'
|
|
4
5
|
|
|
5
6
|
export const DEFAULT_PAYMENT_HELP_URL =
|
|
@@ -28,10 +29,29 @@ export async function createPaymentService(
|
|
|
28
29
|
/**
|
|
29
30
|
* Formats a payment date for display
|
|
30
31
|
* @param {string} isoString - ISO date string
|
|
32
|
+
* @param {string} language - the target language
|
|
31
33
|
* @returns {string} Formatted date string (e.g., "26 January 2026 5:01pm")
|
|
32
34
|
*/
|
|
33
|
-
export function formatPaymentDate(isoString) {
|
|
34
|
-
return
|
|
35
|
+
export function formatPaymentDate(isoString, language) {
|
|
36
|
+
return formatDateForLanguage(
|
|
37
|
+
new Date(isoString),
|
|
38
|
+
'd MMMM yyyy h:mmaaa',
|
|
39
|
+
language
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Formats a date for display in a specific language.
|
|
45
|
+
* To use additional languages, the appropriate module must be imported from 'date-fns/locale'
|
|
46
|
+
* @param { Date | string } date - the date
|
|
47
|
+
* @param {string} formatMask - the format mask
|
|
48
|
+
* @param {string} language - the target language
|
|
49
|
+
* @returns {string} Formatted date string (e.g., "26 January 2026 5:01pm")
|
|
50
|
+
*/
|
|
51
|
+
export function formatDateForLanguage(date, formatMask, language) {
|
|
52
|
+
return format(date, formatMask, {
|
|
53
|
+
locale: toLanguageLocale(language)
|
|
54
|
+
})
|
|
35
55
|
}
|
|
36
56
|
|
|
37
57
|
/**
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { StatusCodes } from 'http-status-codes'
|
|
2
2
|
|
|
3
3
|
import { logger } from '../../common/helpers/logging/logger.js'
|
|
4
|
+
import { toPayLanguageCode } from '../engine/helpers.js'
|
|
4
5
|
import {
|
|
5
6
|
buildPaymentInfo,
|
|
6
7
|
convertPenceToPounds
|
|
@@ -38,7 +39,7 @@ export class PaymentService {
|
|
|
38
39
|
* @param {string} returnUrl
|
|
39
40
|
* @param {string} reference
|
|
40
41
|
* @param {boolean} isLivePayment
|
|
41
|
-
* @param {{ formId: string, slug: string } | undefined } metadata
|
|
42
|
+
* @param {{ formId: string, slug: string, language: string } | undefined } metadata
|
|
42
43
|
* @param {string} [email] - optional email to prepopulate on GOV.UK Pay
|
|
43
44
|
*/
|
|
44
45
|
async createPayment(
|
|
@@ -50,6 +51,8 @@ export class PaymentService {
|
|
|
50
51
|
metadata,
|
|
51
52
|
email
|
|
52
53
|
) {
|
|
54
|
+
const language = toPayLanguageCode(metadata?.language)
|
|
55
|
+
|
|
53
56
|
try {
|
|
54
57
|
/** @type {CreatePaymentRequest} */
|
|
55
58
|
const payload = {
|
|
@@ -58,7 +61,8 @@ export class PaymentService {
|
|
|
58
61
|
reference,
|
|
59
62
|
metadata,
|
|
60
63
|
return_url: returnUrl,
|
|
61
|
-
delayed_capture: true
|
|
64
|
+
delayed_capture: true,
|
|
65
|
+
language
|
|
62
66
|
}
|
|
63
67
|
|
|
64
68
|
// Prepopulate email on GOV.UK Pay if provided
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* @property {string} reference - Unique reference for the payment
|
|
19
19
|
* @property {string} description - Human-readable description of the payment
|
|
20
20
|
* @property {string} return_url - URL to redirect the user to after payment
|
|
21
|
+
* @property {string} language - the desired language for translations
|
|
21
22
|
* @property {boolean} [delayed_capture] - Whether to delay capturing the payment
|
|
22
23
|
* @property {{ formId: string, slug: string }} [metadata] - Additional metadata for the payment
|
|
23
24
|
* @property {string} [email] - Email to prepopulate on GOV.UK Pay (max 254 chars)
|
|
@@ -16,6 +16,7 @@ const countyFieldName = 'county'
|
|
|
16
16
|
const postcodeFieldName = 'postcode'
|
|
17
17
|
|
|
18
18
|
const GOVUK_MARGIN_RIGHT_1 = 'govuk-!-margin-right-1'
|
|
19
|
+
const COMMON_BACK = 'common.back'
|
|
19
20
|
|
|
20
21
|
export const steps = {
|
|
21
22
|
// Step 1: Postcode/building name input
|
|
@@ -403,19 +404,20 @@ function getHref(step) {
|
|
|
403
404
|
/**
|
|
404
405
|
* The postcode lookup details form view model
|
|
405
406
|
* @param {PostcodeLookupSessionData} data
|
|
407
|
+
* @param {Translator} translator
|
|
406
408
|
* @param {PostcodeLookupDetailsData} [payload]
|
|
407
409
|
* @param {Error} [err]
|
|
408
410
|
*/
|
|
409
|
-
export function detailsViewModel(data, payload, err) {
|
|
410
|
-
const {
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
} = data.initial
|
|
411
|
+
export function detailsViewModel(data, translator, payload, err) {
|
|
412
|
+
const { componentId, componentHint, sourceUrl, languages } = data.initial
|
|
413
|
+
|
|
414
|
+
const { t, tComponent, tForm } = translator
|
|
415
|
+
|
|
416
|
+
const component = /** @type {ComponentDef} */ ({ id: componentId })
|
|
416
417
|
|
|
417
418
|
const backLink = {
|
|
418
|
-
href: sourceUrl
|
|
419
|
+
href: sourceUrl,
|
|
420
|
+
text: t(COMMON_BACK)
|
|
419
421
|
}
|
|
420
422
|
|
|
421
423
|
const { errors, postcodeQueryError, buildingNameQueryError } =
|
|
@@ -425,42 +427,54 @@ export function detailsViewModel(data, payload, err) {
|
|
|
425
427
|
payload ?? data.details,
|
|
426
428
|
postcodeQueryError,
|
|
427
429
|
buildingNameQueryError,
|
|
428
|
-
language
|
|
430
|
+
translator.language
|
|
429
431
|
)
|
|
430
432
|
|
|
433
|
+
const hint = componentHint && {
|
|
434
|
+
text: tComponent(component, 'hint')
|
|
435
|
+
}
|
|
436
|
+
|
|
431
437
|
const continueButton = {
|
|
432
|
-
text:
|
|
438
|
+
text: t('postcodeLookup.findAddress'),
|
|
433
439
|
classes: GOVUK_MARGIN_RIGHT_1
|
|
434
440
|
}
|
|
435
441
|
const manualLink = {
|
|
436
|
-
text:
|
|
442
|
+
text: t('postcodeLookup.enterManually'),
|
|
437
443
|
href: getHref(steps.manual)
|
|
438
444
|
}
|
|
439
445
|
|
|
446
|
+
const selector = languages?.length ? { languages } : {}
|
|
447
|
+
|
|
440
448
|
return {
|
|
441
449
|
step: steps.details,
|
|
442
450
|
showTitle: true,
|
|
443
|
-
name:
|
|
451
|
+
name: tForm('title'),
|
|
444
452
|
serviceUrl: sourceUrl,
|
|
445
|
-
pageTitle,
|
|
453
|
+
pageTitle: tComponent(component, 'title'),
|
|
454
|
+
hint,
|
|
446
455
|
backLink,
|
|
447
456
|
errors,
|
|
448
457
|
fields,
|
|
449
|
-
buttons: { continueButton, manualLink }
|
|
458
|
+
buttons: { continueButton, manualLink },
|
|
459
|
+
t,
|
|
460
|
+
language: translator.language,
|
|
461
|
+
...selector
|
|
450
462
|
}
|
|
451
463
|
}
|
|
452
464
|
|
|
453
465
|
/**
|
|
454
466
|
* The postcode lookup select form view model
|
|
455
467
|
* @param {{ session: PostcodeLookupSessionData, apiKey: string }} data
|
|
468
|
+
* @param {Translator} translator
|
|
456
469
|
* @param {PostcodeLookupSelectPayload} [payload]
|
|
457
470
|
* @param {Error} [err]
|
|
458
471
|
*/
|
|
459
|
-
export async function selectViewModel(data, payload, err) {
|
|
472
|
+
export async function selectViewModel(data, translator, payload, err) {
|
|
460
473
|
const { session, apiKey } = data
|
|
461
474
|
const { details, initial } = session
|
|
462
475
|
const { postcodeQuery, buildingNameQuery } = details
|
|
463
|
-
const language =
|
|
476
|
+
const language = translator.language
|
|
477
|
+
const { t, tComponent, tForm } = translator
|
|
464
478
|
|
|
465
479
|
const {
|
|
466
480
|
hasAddresses,
|
|
@@ -471,12 +485,18 @@ export async function selectViewModel(data, payload, err) {
|
|
|
471
485
|
} = await getAddresses(postcodeQuery, buildingNameQuery, apiKey)
|
|
472
486
|
|
|
473
487
|
const title = hasAddresses
|
|
474
|
-
?
|
|
475
|
-
|
|
488
|
+
? tComponent(
|
|
489
|
+
/** @type {ComponentDef} */ ({ id: initial.componentId }),
|
|
490
|
+
'title'
|
|
491
|
+
)
|
|
492
|
+
: t('postcodeLookup.noAddressFoundTitle')
|
|
476
493
|
const formPath = initial.sourceUrl
|
|
477
494
|
const href = getHref()
|
|
478
495
|
|
|
479
|
-
const backLink = {
|
|
496
|
+
const backLink = {
|
|
497
|
+
href,
|
|
498
|
+
text: t(COMMON_BACK)
|
|
499
|
+
}
|
|
480
500
|
|
|
481
501
|
const { errors, uprnError } = buildErrors(err)
|
|
482
502
|
|
|
@@ -490,7 +510,7 @@ export async function selectViewModel(data, payload, err) {
|
|
|
490
510
|
language
|
|
491
511
|
)
|
|
492
512
|
|
|
493
|
-
const searchAgainText =
|
|
513
|
+
const searchAgainText = t('postcodeLookup.searchAgain')
|
|
494
514
|
|
|
495
515
|
const searchAgainLink = {
|
|
496
516
|
text: searchAgainText,
|
|
@@ -499,27 +519,29 @@ export async function selectViewModel(data, payload, err) {
|
|
|
499
519
|
|
|
500
520
|
const continueButton = {
|
|
501
521
|
href: hasAddresses ? undefined : href,
|
|
502
|
-
text: hasAddresses
|
|
503
|
-
? i18nT('postcodeLookup.useThisAddress', language)
|
|
504
|
-
: searchAgainText,
|
|
522
|
+
text: hasAddresses ? t('postcodeLookup.useThisAddress') : searchAgainText,
|
|
505
523
|
classes: GOVUK_MARGIN_RIGHT_1
|
|
506
524
|
}
|
|
507
525
|
const manualLink = {
|
|
508
|
-
text:
|
|
526
|
+
text: t('postcodeLookup.enterManually'),
|
|
509
527
|
href: `${href}?step=${steps.manual}`
|
|
510
528
|
}
|
|
511
529
|
|
|
512
530
|
const addressesFoundText = hasAddresses
|
|
513
|
-
?
|
|
531
|
+
? t('postcodeLookup.addressFound', { count: addressCount })
|
|
514
532
|
: undefined
|
|
515
533
|
const noAddressFoundText = !hasAddresses
|
|
516
|
-
?
|
|
534
|
+
? t('postcodeLookup.noAddressFoundBody')
|
|
517
535
|
: undefined
|
|
518
536
|
|
|
537
|
+
const selector = initial.languages?.length
|
|
538
|
+
? { languages: initial.languages }
|
|
539
|
+
: {}
|
|
540
|
+
|
|
519
541
|
return {
|
|
520
542
|
step: steps.select,
|
|
521
543
|
showTitle: true,
|
|
522
|
-
name: title,
|
|
544
|
+
name: tForm('title'),
|
|
523
545
|
serviceUrl: formPath,
|
|
524
546
|
pageTitle: title,
|
|
525
547
|
backLink,
|
|
@@ -533,28 +555,31 @@ export async function selectViewModel(data, payload, err) {
|
|
|
533
555
|
hasMultipleAddresses,
|
|
534
556
|
addressesFoundText,
|
|
535
557
|
noAddressFoundText,
|
|
536
|
-
buttons: { continueButton, manualLink }
|
|
558
|
+
buttons: { continueButton, manualLink },
|
|
559
|
+
language,
|
|
560
|
+
...selector
|
|
537
561
|
}
|
|
538
562
|
}
|
|
539
563
|
|
|
540
564
|
/**
|
|
541
565
|
* The postcode lookup manual form view model
|
|
542
566
|
* @param {PostcodeLookupSessionData} data
|
|
567
|
+
* @param {Translator} translator
|
|
543
568
|
* @param {PostcodeLookupManualPayload} [payload]
|
|
544
569
|
* @param {Error} [err]
|
|
545
570
|
*/
|
|
546
|
-
export function manualViewModel(data, payload, err) {
|
|
547
|
-
const {
|
|
548
|
-
componentTitle,
|
|
549
|
-
sourceUrl,
|
|
550
|
-
componentHint,
|
|
551
|
-
language = 'en-GB'
|
|
552
|
-
} = data.initial
|
|
571
|
+
export function manualViewModel(data, translator, payload, err) {
|
|
572
|
+
const { componentId, sourceUrl, componentHint, languages } = data.initial
|
|
553
573
|
const formPath = sourceUrl
|
|
554
574
|
const href = getHref()
|
|
555
575
|
|
|
576
|
+
const { t, tComponent, tForm } = translator
|
|
577
|
+
|
|
578
|
+
const component = /** @type {ComponentDef} */ ({ id: componentId })
|
|
579
|
+
|
|
556
580
|
const backLink = {
|
|
557
|
-
href
|
|
581
|
+
href,
|
|
582
|
+
text: t(COMMON_BACK)
|
|
558
583
|
}
|
|
559
584
|
|
|
560
585
|
const {
|
|
@@ -567,7 +592,7 @@ export function manualViewModel(data, payload, err) {
|
|
|
567
592
|
} = buildErrors(err)
|
|
568
593
|
|
|
569
594
|
const hint = componentHint && {
|
|
570
|
-
text:
|
|
595
|
+
text: tComponent(component, 'hint')
|
|
571
596
|
}
|
|
572
597
|
|
|
573
598
|
const fields = getManualFields(
|
|
@@ -577,29 +602,34 @@ export function manualViewModel(data, payload, err) {
|
|
|
577
602
|
townError,
|
|
578
603
|
countyError,
|
|
579
604
|
postcodeError,
|
|
580
|
-
language
|
|
605
|
+
translator.language
|
|
581
606
|
)
|
|
582
607
|
|
|
583
608
|
const continueButton = {
|
|
584
|
-
text:
|
|
609
|
+
text: t('postcodeLookup.useThisAddress'),
|
|
585
610
|
classes: GOVUK_MARGIN_RIGHT_1
|
|
586
611
|
}
|
|
587
612
|
const detailsLink = {
|
|
588
|
-
text:
|
|
613
|
+
text: t('postcodeLookup.findAnAddressInstead'),
|
|
589
614
|
href
|
|
590
615
|
}
|
|
591
616
|
|
|
617
|
+
const selector = languages?.length ? { languages } : {}
|
|
618
|
+
|
|
592
619
|
return {
|
|
593
620
|
step: steps.manual,
|
|
594
621
|
showTitle: true,
|
|
595
|
-
name:
|
|
622
|
+
name: tForm('title'),
|
|
596
623
|
serviceUrl: formPath,
|
|
597
|
-
pageTitle:
|
|
624
|
+
pageTitle: tComponent(component, 'title'),
|
|
598
625
|
backLink,
|
|
599
626
|
errors,
|
|
600
627
|
hint,
|
|
601
628
|
fields,
|
|
602
|
-
buttons: { continueButton, detailsLink }
|
|
629
|
+
buttons: { continueButton, detailsLink },
|
|
630
|
+
t,
|
|
631
|
+
language: translator.language,
|
|
632
|
+
...selector
|
|
603
633
|
}
|
|
604
634
|
}
|
|
605
635
|
|
|
@@ -607,5 +637,7 @@ export function manualViewModel(data, payload, err) {
|
|
|
607
637
|
|
|
608
638
|
/**
|
|
609
639
|
* @import { ObjectSchema, ValidationErrorItem } from 'joi'
|
|
640
|
+
* @import { ComponentDef } from '@defra/forms-model'
|
|
610
641
|
* @import { Address, PostcodeLookupDetailsData, PostcodeLookupDetailsPayload, PostcodeLookupManualPayload, PostcodeLookupSelectPayload, PostcodeLookupSessionData } from '../types.js'
|
|
642
|
+
* @import { Translator } from '../../engine/i18n/types.js'
|
|
611
643
|
*/
|
|
@@ -3,6 +3,7 @@ import { StatusCodes } from 'http-status-codes'
|
|
|
3
3
|
import Joi from 'joi'
|
|
4
4
|
|
|
5
5
|
import { EXTERNAL_STATE_APPENDAGE } from '../../../constants.js'
|
|
6
|
+
import { getCachedPluginTranslator } from '../../engine/i18n/form.js'
|
|
6
7
|
import {
|
|
7
8
|
JOURNEY_BASE_URL,
|
|
8
9
|
createDetailsPayloadSchema,
|
|
@@ -15,6 +16,7 @@ import {
|
|
|
15
16
|
steps
|
|
16
17
|
} from '../models/index.js'
|
|
17
18
|
import * as service from '../service.js'
|
|
19
|
+
import { resolveLanguage } from '../../../utils/utils.js'
|
|
18
20
|
|
|
19
21
|
const viewName = 'postcode-lookup-details'
|
|
20
22
|
|
|
@@ -22,7 +24,7 @@ const viewName = 'postcode-lookup-details'
|
|
|
22
24
|
* Get the session state associated with this journey
|
|
23
25
|
* @param {PostcodeLookupRequest} request
|
|
24
26
|
*/
|
|
25
|
-
function getSessionState(request) {
|
|
27
|
+
export function getSessionState(request) {
|
|
26
28
|
/**
|
|
27
29
|
* @type {PostcodeLookupSessionData | null | undefined}
|
|
28
30
|
*/
|
|
@@ -63,6 +65,32 @@ function flashComponentState(request, componentName, address) {
|
|
|
63
65
|
|
|
64
66
|
request.yar.flash(EXTERNAL_STATE_APPENDAGE, appendage, true)
|
|
65
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Get a cached translator, or create a new one if not in the cache
|
|
70
|
+
* @param {PostcodeLookupRequest} request
|
|
71
|
+
* @param {PostcodeLookupDispatchData} initial
|
|
72
|
+
* @param { string | string[] | undefined } language
|
|
73
|
+
*/
|
|
74
|
+
export async function getDispatchTranslator(request, initial, language) {
|
|
75
|
+
const { formId, formStatus } = initial
|
|
76
|
+
|
|
77
|
+
// Override language if passed as a query param
|
|
78
|
+
if (language) {
|
|
79
|
+
request.yar.set('language', language)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const typedReq = /** @type {AnyFormRequest} */ (/** @type {any} */ (request))
|
|
83
|
+
const lang = resolveLanguage(typedReq)
|
|
84
|
+
|
|
85
|
+
const translator = await getCachedPluginTranslator(
|
|
86
|
+
typedReq,
|
|
87
|
+
/** @type {FormMetadata} */ ({ id: formId }),
|
|
88
|
+
formStatus,
|
|
89
|
+
lang
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
return translator
|
|
93
|
+
}
|
|
66
94
|
|
|
67
95
|
/**
|
|
68
96
|
* Initialises and dispatches the request to the postcode lookup journey
|
|
@@ -101,15 +129,21 @@ function getRoute() {
|
|
|
101
129
|
return {
|
|
102
130
|
method: 'GET',
|
|
103
131
|
path: JOURNEY_BASE_URL,
|
|
104
|
-
handler(request, h) {
|
|
132
|
+
async handler(request, h) {
|
|
105
133
|
const { query } = request
|
|
106
|
-
const { step } = query
|
|
134
|
+
const { step, language } = query
|
|
107
135
|
const session = getSessionState(request)
|
|
108
136
|
|
|
137
|
+
const translator = await getDispatchTranslator(
|
|
138
|
+
request,
|
|
139
|
+
session.initial,
|
|
140
|
+
language
|
|
141
|
+
)
|
|
142
|
+
|
|
109
143
|
const model =
|
|
110
144
|
step === steps.manual
|
|
111
|
-
? manualViewModel(session)
|
|
112
|
-
: detailsViewModel(session)
|
|
145
|
+
? manualViewModel(session, translator)
|
|
146
|
+
: detailsViewModel(session, translator)
|
|
113
147
|
|
|
114
148
|
return h.view(viewName, model)
|
|
115
149
|
},
|
|
@@ -117,7 +151,8 @@ function getRoute() {
|
|
|
117
151
|
validate: {
|
|
118
152
|
query: Joi.object()
|
|
119
153
|
.keys({
|
|
120
|
-
step: Joi.string().allow(steps.details, steps.manual).optional()
|
|
154
|
+
step: Joi.string().allow(steps.details, steps.manual).optional(),
|
|
155
|
+
language: Joi.string().allow('en-GB', 'cy').optional()
|
|
121
156
|
})
|
|
122
157
|
.optional()
|
|
123
158
|
}
|
|
@@ -172,7 +207,13 @@ function postRoute(options) {
|
|
|
172
207
|
async function detailsPostHandler(request, h, options) {
|
|
173
208
|
const session = getSessionState(request)
|
|
174
209
|
const { ordnanceSurveyApiKey: apiKey } = options
|
|
175
|
-
const
|
|
210
|
+
const translator = await getDispatchTranslator(
|
|
211
|
+
request,
|
|
212
|
+
session.initial,
|
|
213
|
+
request.query.language
|
|
214
|
+
)
|
|
215
|
+
const language = translator.language
|
|
216
|
+
|
|
176
217
|
const { value: details, error } = createDetailsPayloadSchema(
|
|
177
218
|
language
|
|
178
219
|
).validate(request.payload)
|
|
@@ -180,7 +221,7 @@ async function detailsPostHandler(request, h, options) {
|
|
|
180
221
|
let model
|
|
181
222
|
|
|
182
223
|
if (error) {
|
|
183
|
-
model = detailsViewModel(session, details, error)
|
|
224
|
+
model = detailsViewModel(session, translator, details, error)
|
|
184
225
|
|
|
185
226
|
return h.view(viewName, model)
|
|
186
227
|
}
|
|
@@ -191,7 +232,7 @@ async function detailsPostHandler(request, h, options) {
|
|
|
191
232
|
// Store the updated session
|
|
192
233
|
request.yar.set(JOURNEY_BASE_URL, session)
|
|
193
234
|
|
|
194
|
-
model = await selectViewModel({ session, apiKey })
|
|
235
|
+
model = await selectViewModel({ session, apiKey }, translator)
|
|
195
236
|
|
|
196
237
|
return h.view(viewName, model)
|
|
197
238
|
}
|
|
@@ -205,13 +246,23 @@ async function detailsPostHandler(request, h, options) {
|
|
|
205
246
|
async function selectPostHandler(request, h, options) {
|
|
206
247
|
const session = getSessionState(request)
|
|
207
248
|
const { ordnanceSurveyApiKey: apiKey } = options
|
|
208
|
-
const
|
|
249
|
+
const translator = await getDispatchTranslator(
|
|
250
|
+
request,
|
|
251
|
+
session.initial,
|
|
252
|
+
request.query.language
|
|
253
|
+
)
|
|
254
|
+
const language = translator.language
|
|
209
255
|
const { value: select, error } = createSelectPayloadSchema(language).validate(
|
|
210
256
|
request.payload
|
|
211
257
|
)
|
|
212
258
|
|
|
213
259
|
if (error) {
|
|
214
|
-
const model = await selectViewModel(
|
|
260
|
+
const model = await selectViewModel(
|
|
261
|
+
{ session, apiKey },
|
|
262
|
+
translator,
|
|
263
|
+
select,
|
|
264
|
+
error
|
|
265
|
+
)
|
|
215
266
|
|
|
216
267
|
return h.view(viewName, model)
|
|
217
268
|
}
|
|
@@ -235,9 +286,14 @@ async function selectPostHandler(request, h, options) {
|
|
|
235
286
|
* @param {PostcodeLookupPostRequest} request
|
|
236
287
|
* @param {ResponseToolkit<PostcodeLookupPostRequestRefs>} h
|
|
237
288
|
*/
|
|
238
|
-
function manualPostHandler(request, h) {
|
|
289
|
+
async function manualPostHandler(request, h) {
|
|
239
290
|
const session = getSessionState(request)
|
|
240
|
-
const
|
|
291
|
+
const translator = await getDispatchTranslator(
|
|
292
|
+
request,
|
|
293
|
+
session.initial,
|
|
294
|
+
request.query.language
|
|
295
|
+
)
|
|
296
|
+
const language = translator.language
|
|
241
297
|
|
|
242
298
|
const { value: manual, error } = createManualPayloadSchema(language).validate(
|
|
243
299
|
request.payload,
|
|
@@ -247,7 +303,7 @@ function manualPostHandler(request, h) {
|
|
|
247
303
|
)
|
|
248
304
|
|
|
249
305
|
if (error) {
|
|
250
|
-
const model = manualViewModel(session, manual, error)
|
|
306
|
+
const model = manualViewModel(session, translator, manual, error)
|
|
251
307
|
|
|
252
308
|
return h.view(viewName, model)
|
|
253
309
|
}
|
|
@@ -261,7 +317,8 @@ function manualPostHandler(request, h) {
|
|
|
261
317
|
|
|
262
318
|
/**
|
|
263
319
|
* @import { ResponseToolkit, ServerRoute } from '@hapi/hapi'
|
|
264
|
-
* @import {
|
|
320
|
+
* @import { FormMetadata } from '@defra/forms-model'
|
|
321
|
+
* @import { PostcodeLookupManualPayload, Address, PostcodeLookupGetRequestRefs, PostcodeLookupPostRequestRefs, PostcodeLookupRequest, PostcodeLookupPostRequest, PostcodeLookupConfiguration, PostcodeLookupDispatchData, PostcodeLookupSessionData } from '../types.js'
|
|
265
322
|
* @import { FormRequestPayload, FormResponseToolkit } from '../../../routes/types.js'
|
|
266
|
-
* @import { ExternalStateAppendage } from '../../engine/types.js'
|
|
323
|
+
* @import { AnyFormRequest, ExternalStateAppendage } from '../../engine/types.js'
|
|
267
324
|
*/
|
|
@@ -14,12 +14,16 @@
|
|
|
14
14
|
/**
|
|
15
15
|
* @typedef {{
|
|
16
16
|
* sourceUrl: string,
|
|
17
|
+
* formId: string
|
|
17
18
|
* formName: string
|
|
19
|
+
* formStatus: FormStatus
|
|
20
|
+
* componentId: string
|
|
18
21
|
* componentName: string
|
|
19
22
|
* componentTitle: string,
|
|
20
23
|
* componentHint?: string
|
|
21
24
|
* step?: string
|
|
22
25
|
* language?: string
|
|
26
|
+
* languages?: { name: string, code: string}[]
|
|
23
27
|
* }} PostcodeLookupDispatchData
|
|
24
28
|
*/
|
|
25
29
|
|
|
@@ -49,6 +53,7 @@
|
|
|
49
53
|
* Postcode lookup query params
|
|
50
54
|
* @typedef {object} PostcodeLookupQuery
|
|
51
55
|
* @property {string} [step] - step
|
|
56
|
+
* @property {string} [language] - language
|
|
52
57
|
*/
|
|
53
58
|
|
|
54
59
|
/**
|
|
@@ -140,5 +145,5 @@
|
|
|
140
145
|
|
|
141
146
|
/**
|
|
142
147
|
* @import { Request } from '@hapi/hapi'
|
|
143
|
-
* @import {
|
|
148
|
+
* @import { FormStatus } from '@defra/forms-model'
|
|
144
149
|
*/
|