@defra/forms-engine-plugin 2.0.3 → 2.1.1
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 +1 -1
- 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 +2 -2
- package/.public/stylesheets/application.min.css.map +1 -1
- package/.server/client/javascripts/file-upload.js +3 -3
- package/.server/client/javascripts/file-upload.js.map +1 -1
- package/.server/server/forms/page-events.yaml +87 -0
- package/.server/server/index.js +2 -1
- package/.server/server/index.js.map +1 -1
- package/.server/server/plugins/engine/routes/questions.d.ts +4 -2
- package/.server/server/plugins/engine/routes/questions.js +67 -43
- package/.server/server/plugins/engine/routes/questions.js.map +1 -1
- package/.server/server/plugins/engine/services/localFormsService.js +7 -9
- package/.server/server/plugins/engine/services/localFormsService.js.map +1 -1
- package/.server/server/routes/dummy-api.d.ts +38 -0
- package/.server/server/routes/dummy-api.js +33 -0
- package/.server/server/routes/dummy-api.js.map +1 -0
- package/.server/server/routes/index.d.ts +1 -0
- package/.server/server/routes/index.js +1 -0
- package/.server/server/routes/index.js.map +1 -1
- package/package.json +12 -10
- package/src/client/javascripts/file-upload.js +3 -3
- package/src/server/forms/page-events.yaml +87 -0
- package/src/server/index.ts +4 -2
- package/src/server/plugins/engine/routes/questions.test.ts +416 -0
- package/src/server/plugins/engine/routes/questions.ts +96 -40
- package/src/server/plugins/engine/services/localFormsService.js +7 -8
- package/src/server/routes/dummy-api.test.ts +96 -0
- package/src/server/routes/dummy-api.ts +62 -0
- package/src/server/routes/index.ts +1 -0
- package/.server/server/forms/register-as-a-unicorn-breeder.json +0 -393
- package/src/server/forms/register-as-a-unicorn-breeder.json +0 -393
|
@@ -57,9 +57,9 @@ function findOrCreateSummaryList(form, fileCountP) {
|
|
|
57
57
|
if (!summaryList) {
|
|
58
58
|
summaryList = document.createElement('dl');
|
|
59
59
|
summaryList.className = 'govuk-summary-list govuk-summary-list--long-key';
|
|
60
|
-
const
|
|
61
|
-
if (
|
|
62
|
-
form.insertBefore(summaryList,
|
|
60
|
+
const buttonGroup = form.querySelector('.govuk-button-group');
|
|
61
|
+
if (buttonGroup) {
|
|
62
|
+
form.insertBefore(summaryList, buttonGroup);
|
|
63
63
|
} else {
|
|
64
64
|
form.insertBefore(summaryList, fileCountP.nextSibling);
|
|
65
65
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-upload.js","names":["MAX_POLLING_DURATION","ARIA_DESCRIBEDBY","ERROR_SUMMARY_TITLE_ID","createOrUpdateStatusAnnouncer","form","fileCountP","statusAnnouncer","querySelector","document","createElement","id","className","setAttribute","addStatusAnnouncerToDOM","asHTMLElement","appendChild","body","nextSibling","parentNode","insertBefore","parentElement","findOrCreateSummaryList","summaryList","continueButton","createFileRow","selectedFile","statusText","row","name","innerHTML","renderSummary","container","getElementById","uploadForm","closest","HTMLFormElement","fileInput","existingRow","remove","firstChild","textContent","showError","message","errorSummary","topErrorSummary","titleElement","removeAttribute","formGroup","classList","add","inputId","errorMessage","element","reloadPage","window","history","replaceState","location","href","pathname","buildUploadStatusUrl","uploadId","pathSegments","split","filter","segment","prefix","length","pollUploadStatus","attempts","interval","setInterval","clearInterval","uploadStatusUrl","fetch","headers","Accept","then","response","ok","Error","json","data","uploadStatus","catch","handleStandardFormSubmission","formElement","uploadButton","focus","setTimeout","disabled","handleAjaxFormSubmission","event","action","preventDefault","formData","FormData","isLocalDev","dataset","proxyUrl","uploadUrl","fetchOptions","method","redirect","mode","initUpload","Array","from","querySelectorAll","find","button","trim","isSubmitting","addEventListener","files","initFileUpload","readyState"],"sources":["../../../src/client/javascripts/file-upload.js"],"sourcesContent":["export const MAX_POLLING_DURATION = 300 // 5 minutes\nconst ARIA_DESCRIBEDBY = 'aria-describedby'\nconst ERROR_SUMMARY_TITLE_ID = 'error-summary-title'\n\n/**\n * Creates or updates status announcer for screen readers\n * @param {HTMLElement | null} form - The form element\n * @param {HTMLElement | null} fileCountP - The file count paragraph element\n * @returns {HTMLElement} The status announcer element\n */\nfunction createOrUpdateStatusAnnouncer(form, fileCountP) {\n let statusAnnouncer = form?.querySelector('#statusInformation')\n\n if (!statusAnnouncer) {\n statusAnnouncer = document.createElement('div')\n statusAnnouncer.id = 'statusInformation'\n statusAnnouncer.className = 'govuk-visually-hidden'\n statusAnnouncer.setAttribute('aria-live', 'polite')\n\n // multiple fallbacks to ensure the status announcer is always added to the DOM\n // this helps with cross-browser compatibility and unexpected DOM structures encountered during QA\n try {\n addStatusAnnouncerToDOM(\n asHTMLElement(form),\n asHTMLElement(fileCountP),\n asHTMLElement(statusAnnouncer)\n )\n } catch {\n try {\n form?.appendChild(statusAnnouncer)\n } catch {\n document.body.appendChild(statusAnnouncer)\n }\n }\n }\n\n return /** @type {HTMLElement} */ (statusAnnouncer)\n}\n\n/**\n * Helper function to add the status announcer to the DOM\n * @param {HTMLElement} form - The form element\n * @param {HTMLElement | null} fileCountP - The file count paragraph element\n * @param {HTMLElement} statusAnnouncer - The status announcer element to add\n */\nfunction addStatusAnnouncerToDOM(form, fileCountP, statusAnnouncer) {\n if (fileCountP?.nextSibling && fileCountP.parentNode === form) {\n form.insertBefore(statusAnnouncer, fileCountP.nextSibling)\n return\n }\n\n const parentElement = fileCountP?.parentNode ?? form\n parentElement.appendChild(statusAnnouncer)\n}\n\n/**\n * Finds an existing summary list or creates a new one\n * @param {HTMLFormElement} form - The form element\n * @param {HTMLElement} fileCountP - The file count paragraph element\n * @returns {HTMLElement} The summary list element\n */\nfunction findOrCreateSummaryList(form, fileCountP) {\n let summaryList = form.querySelector('dl.govuk-summary-list')\n\n if (!summaryList) {\n summaryList = document.createElement('dl')\n summaryList.className = 'govuk-summary-list govuk-summary-list--long-key'\n\n const continueButton = form.querySelector('.govuk-button')\n\n if (continueButton) {\n form.insertBefore(summaryList, continueButton)\n } else {\n form.insertBefore(summaryList, fileCountP.nextSibling)\n }\n }\n\n return /** @type {HTMLElement} */ (summaryList)\n}\n\n/**\n * Creates a file row element for the summary list\n * @param {File | null} selectedFile - The selected file\n * @param {string} statusText - The status to display\n * @returns {HTMLElement} The created row element\n */\nfunction createFileRow(selectedFile, statusText) {\n const row = document.createElement('div')\n row.className = 'govuk-summary-list__row'\n row.setAttribute('data-filename', selectedFile?.name ?? '')\n row.innerHTML = `\n <dt class=\"govuk-summary-list__key\">\n ${selectedFile?.name ?? ''}\n </dt>\n <dd class=\"govuk-summary-list__value\">\n <strong class=\"govuk-tag govuk-tag--yellow\">${statusText}</strong>\n </dd>\n <dd class=\"govuk-summary-list__actions\">\n </dd>\n `\n return row\n}\n\n/**\n * Renders or updates the file summary box for the selected file\n * @param {File | null} selectedFile - The selected file\n * @param {string} statusText - The status to display\n * @param {HTMLElement} form - The form element\n */\nfunction renderSummary(selectedFile, statusText, form) {\n const container = document.getElementById('uploadedFilesContainer')\n const uploadForm = container ? container.closest('form') : null\n\n if (!uploadForm || !(uploadForm instanceof HTMLFormElement)) {\n return\n }\n\n const fileCountP = uploadForm.querySelector('p.govuk-body')\n\n if (!fileCountP) {\n return\n }\n\n const statusAnnouncer = createOrUpdateStatusAnnouncer(\n /** @type {HTMLElement} */ (uploadForm),\n /** @type {HTMLElement | null} */ (fileCountP)\n )\n\n const fileInput = form.querySelector('input[type=\"file\"]')\n\n if (fileInput) {\n fileInput.setAttribute(ARIA_DESCRIBEDBY, 'statusInformation')\n }\n\n const summaryList = findOrCreateSummaryList(\n /** @type {HTMLFormElement} */ (uploadForm),\n /** @type {HTMLElement} */ (fileCountP)\n )\n\n const existingRow = document.querySelector(\n `[data-filename=\"${selectedFile?.name}\"]`\n )\n\n if (existingRow) {\n existingRow.remove()\n }\n\n const row = createFileRow(selectedFile, statusText)\n summaryList.insertBefore(row, summaryList.firstChild)\n statusAnnouncer.textContent = `${selectedFile?.name ?? ''} ${statusText}`\n}\n\n/**\n * Shows an error message using the GOV.UK error summary component\n * and adds inline error styling to the file input\n * @param {string} message - The error message to display\n * @param {HTMLElement | null} errorSummary - The error summary container\n * @param {HTMLInputElement} fileInput - The file input element\n * @returns {void}\n */\nfunction showError(message, errorSummary, fileInput) {\n const topErrorSummary = document.querySelector('.govuk-error-summary')\n\n if (topErrorSummary) {\n const titleElement = document.getElementById(ERROR_SUMMARY_TITLE_ID)\n if (titleElement) {\n fileInput.setAttribute(ARIA_DESCRIBEDBY, ERROR_SUMMARY_TITLE_ID)\n } else {\n fileInput.removeAttribute(ARIA_DESCRIBEDBY)\n }\n return\n }\n\n if (errorSummary) {\n errorSummary.innerHTML = `\n <div class=\"govuk-error-summary\" data-module=\"govuk-error-summary\">\n <div role=\"alert\">\n <h2 class=\"govuk-error-summary__title\" id=\"${ERROR_SUMMARY_TITLE_ID}\">\n There is a problem\n </h2>\n <div class=\"govuk-error-summary__body\">\n <ul class=\"govuk-list govuk-error-summary__list\">\n <li>\n <a href=\"#file-upload\">${message}</a>\n </li>\n </ul>\n </div>\n </div>\n </div>\n `\n\n fileInput.setAttribute(ARIA_DESCRIBEDBY, ERROR_SUMMARY_TITLE_ID)\n }\n\n const formGroup = fileInput.closest('.govuk-form-group')\n if (formGroup) {\n formGroup.classList.add('govuk-form-group--error')\n fileInput.classList.add('govuk-file-upload--error')\n\n const inputId = fileInput.id\n let errorMessage = document.getElementById(`${inputId}-error`)\n\n if (!errorMessage) {\n errorMessage = document.createElement('p')\n errorMessage.id = `${inputId}-error`\n errorMessage.className = 'govuk-error-message'\n errorMessage.innerHTML = `<span class=\"govuk-visually-hidden\">Error:</span> ${message}`\n formGroup.insertBefore(errorMessage, fileInput)\n }\n\n fileInput.setAttribute(\n ARIA_DESCRIBEDBY,\n `error-summary-title ${inputId}-error`\n )\n }\n}\n\n/**\n * Helper to safely convert an Element to HTMLElement\n * @param {Element | null} element - The element to convert\n */\nfunction asHTMLElement(element) {\n return /** @type {HTMLElement} */ (element)\n}\n\nfunction reloadPage() {\n window.history.replaceState(null, '', window.location.href)\n window.location.href = window.location.pathname\n}\n\n/**\n * Build the upload status URL given the current pathname and the upload ID.\n * @param {string} pathname – e.g. window.location.pathname\n * @param {string} uploadId\n * @returns {string} e.g. \"/form/upload-status/abc123\"\n */\nexport function buildUploadStatusUrl(pathname, uploadId) {\n const pathSegments = pathname.split('/').filter((segment) => segment)\n const prefix = pathSegments.length > 0 ? `/${pathSegments[0]}` : ''\n return `${prefix}/upload-status/${uploadId}`\n}\n\n/**\n * Polls the upload status endpoint until the file is ready or timeout occurs\n * @param {string} uploadId - The upload ID to check\n */\nfunction pollUploadStatus(uploadId) {\n let attempts = 0\n const interval = setInterval(() => {\n attempts++\n\n if (attempts >= MAX_POLLING_DURATION) {\n clearInterval(interval)\n reloadPage()\n return\n }\n\n const uploadStatusUrl = buildUploadStatusUrl(\n window.location.pathname,\n uploadId\n )\n\n fetch(uploadStatusUrl, {\n headers: {\n Accept: 'application/json'\n }\n })\n .then((response) => {\n if (!response.ok) {\n throw new Error('Network response was not ok')\n }\n return response.json()\n })\n .then((data) => {\n if (data.uploadStatus === 'ready') {\n clearInterval(interval)\n reloadPage()\n }\n })\n .catch(() => {\n clearInterval(interval)\n reloadPage()\n })\n }, 1000)\n}\n\n/**\n * Handle standard form submission for file upload\n * @param {HTMLFormElement} formElement - The form element\n * @param {HTMLInputElement} fileInput - The file input element\n * @param {HTMLButtonElement} uploadButton - The upload button\n * @param {HTMLButtonElement} continueButton - The continue button\n * @param {File | null} selectedFile - The selected file\n */\nfunction handleStandardFormSubmission(\n formElement,\n fileInput,\n uploadButton,\n continueButton,\n selectedFile\n) {\n renderSummary(selectedFile, 'Uploading…', formElement)\n\n fileInput.focus()\n\n setTimeout(() => {\n fileInput.disabled = true\n uploadButton.disabled = true\n continueButton.disabled = true\n }, 100)\n}\n\n/**\n * Handle AJAX form submission with upload ID\n * @param {Event} event - The click event\n * @param {HTMLFormElement} formElement - The form element\n * @param {HTMLInputElement} fileInput - The file input element\n * @param {HTMLButtonElement} uploadButton - The upload button\n * @param {HTMLElement | null} errorSummary - The error summary container\n * @param {string | undefined} uploadId - The upload ID\n * @returns {boolean} Whether the event was handled\n */\nfunction handleAjaxFormSubmission(\n event,\n formElement,\n fileInput,\n uploadButton,\n errorSummary,\n uploadId\n) {\n if (!formElement.action || !uploadId) {\n return false\n }\n\n event.preventDefault()\n\n const formData = new FormData(formElement)\n const isLocalDev = !!formElement.dataset.proxyUrl\n const uploadUrl = formElement.dataset.proxyUrl ?? formElement.action\n\n const fetchOptions = /** @type {RequestInit} */ ({\n method: 'POST',\n body: formData,\n redirect: isLocalDev ? 'follow' : 'manual' // follow mode if local development with the proxy\n })\n\n // no-cors mode if needed local development with the proxy\n if (isLocalDev) {\n fetchOptions.mode = 'no-cors'\n }\n\n fetch(uploadUrl, fetchOptions)\n .then(() => {\n pollUploadStatus(uploadId)\n })\n .catch(() => {\n fileInput.disabled = false\n uploadButton.disabled = false\n\n showError(\n 'There was a problem uploading the file',\n errorSummary,\n fileInput\n )\n\n return null\n })\n\n return true\n}\n\nfunction initUpload() {\n const form = document.querySelector('form:has(input[type=\"file\"])')\n /** @type {HTMLInputElement | null} */\n const fileInput = form ? form.querySelector('input[type=\"file\"]') : null\n /** @type {HTMLButtonElement | null} */\n const uploadButton = form ? form.querySelector('.upload-file-button') : null\n const continueButton =\n /** @type {HTMLButtonElement} */ (\n Array.from(document.querySelectorAll('button.govuk-button')).find(\n (button) => button.textContent?.trim() === 'Continue'\n )\n ) ?? null\n\n const errorSummary = document.querySelector('.govuk-error-summary-container')\n\n if (!form || !fileInput || !uploadButton) {\n return\n }\n\n const formElement = /** @type {HTMLFormElement} */ (form)\n /** @type {File | null} */\n let selectedFile = null\n let isSubmitting = false\n const uploadId = formElement.dataset.uploadId\n\n fileInput.addEventListener('change', () => {\n if (errorSummary) {\n errorSummary.innerHTML = ''\n }\n\n if (fileInput.files && fileInput.files.length > 0) {\n selectedFile = fileInput.files[0]\n }\n })\n\n uploadButton.addEventListener('click', (event) => {\n if (!selectedFile) {\n event.preventDefault()\n showError(\n 'Select a file',\n /** @type {HTMLElement | null} */ (errorSummary),\n fileInput\n )\n return\n }\n\n if (isSubmitting) {\n event.preventDefault()\n return\n }\n\n isSubmitting = true\n\n handleStandardFormSubmission(\n formElement,\n fileInput,\n uploadButton,\n continueButton,\n selectedFile\n )\n\n handleAjaxFormSubmission(\n event,\n formElement,\n fileInput,\n uploadButton,\n /** @type {HTMLElement | null} */ (errorSummary),\n uploadId\n )\n })\n}\n\nexport function initFileUpload() {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', initUpload)\n } else {\n initUpload()\n }\n}\n"],"mappings":"AAAA,OAAO,MAAMA,oBAAoB,GAAG,GAAG,EAAC;AACxC,MAAMC,gBAAgB,GAAG,kBAAkB;AAC3C,MAAMC,sBAAsB,GAAG,qBAAqB;;AAEpD;AACA;AACA;AACA;AACA;AACA;AACA,SAASC,6BAA6BA,CAACC,IAAI,EAAEC,UAAU,EAAE;EACvD,IAAIC,eAAe,GAAGF,IAAI,EAAEG,aAAa,CAAC,oBAAoB,CAAC;EAE/D,IAAI,CAACD,eAAe,EAAE;IACpBA,eAAe,GAAGE,QAAQ,CAACC,aAAa,CAAC,KAAK,CAAC;IAC/CH,eAAe,CAACI,EAAE,GAAG,mBAAmB;IACxCJ,eAAe,CAACK,SAAS,GAAG,uBAAuB;IACnDL,eAAe,CAACM,YAAY,CAAC,WAAW,EAAE,QAAQ,CAAC;;IAEnD;IACA;IACA,IAAI;MACFC,uBAAuB,CACrBC,aAAa,CAACV,IAAI,CAAC,EACnBU,aAAa,CAACT,UAAU,CAAC,EACzBS,aAAa,CAACR,eAAe,CAC/B,CAAC;IACH,CAAC,CAAC,MAAM;MACN,IAAI;QACFF,IAAI,EAAEW,WAAW,CAACT,eAAe,CAAC;MACpC,CAAC,CAAC,MAAM;QACNE,QAAQ,CAACQ,IAAI,CAACD,WAAW,CAACT,eAAe,CAAC;MAC5C;IACF;EACF;EAEA,OAAO,0BAA4BA,eAAe;AACpD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,SAASO,uBAAuBA,CAACT,IAAI,EAAEC,UAAU,EAAEC,eAAe,EAAE;EAClE,IAAID,UAAU,EAAEY,WAAW,IAAIZ,UAAU,CAACa,UAAU,KAAKd,IAAI,EAAE;IAC7DA,IAAI,CAACe,YAAY,CAACb,eAAe,EAAED,UAAU,CAACY,WAAW,CAAC;IAC1D;EACF;EAEA,MAAMG,aAAa,GAAGf,UAAU,EAAEa,UAAU,IAAId,IAAI;EACpDgB,aAAa,CAACL,WAAW,CAACT,eAAe,CAAC;AAC5C;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,SAASe,uBAAuBA,CAACjB,IAAI,EAAEC,UAAU,EAAE;EACjD,IAAIiB,WAAW,GAAGlB,IAAI,CAACG,aAAa,CAAC,uBAAuB,CAAC;EAE7D,IAAI,CAACe,WAAW,EAAE;IAChBA,WAAW,GAAGd,QAAQ,CAACC,aAAa,CAAC,IAAI,CAAC;IAC1Ca,WAAW,CAACX,SAAS,GAAG,iDAAiD;IAEzE,MAAMY,cAAc,GAAGnB,IAAI,CAACG,aAAa,CAAC,eAAe,CAAC;IAE1D,IAAIgB,cAAc,EAAE;MAClBnB,IAAI,CAACe,YAAY,CAACG,WAAW,EAAEC,cAAc,CAAC;IAChD,CAAC,MAAM;MACLnB,IAAI,CAACe,YAAY,CAACG,WAAW,EAAEjB,UAAU,CAACY,WAAW,CAAC;IACxD;EACF;EAEA,OAAO,0BAA4BK,WAAW;AAChD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,SAASE,aAAaA,CAACC,YAAY,EAAEC,UAAU,EAAE;EAC/C,MAAMC,GAAG,GAAGnB,QAAQ,CAACC,aAAa,CAAC,KAAK,CAAC;EACzCkB,GAAG,CAAChB,SAAS,GAAG,yBAAyB;EACzCgB,GAAG,CAACf,YAAY,CAAC,eAAe,EAAEa,YAAY,EAAEG,IAAI,IAAI,EAAE,CAAC;EAC3DD,GAAG,CAACE,SAAS,GAAG;AAClB;AACA,UAAUJ,YAAY,EAAEG,IAAI,IAAI,EAAE;AAClC;AACA;AACA,sDAAsDF,UAAU;AAChE;AACA;AACA;AACA,KAAK;EACH,OAAOC,GAAG;AACZ;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,SAASG,aAAaA,CAACL,YAAY,EAAEC,UAAU,EAAEtB,IAAI,EAAE;EACrD,MAAM2B,SAAS,GAAGvB,QAAQ,CAACwB,cAAc,CAAC,wBAAwB,CAAC;EACnE,MAAMC,UAAU,GAAGF,SAAS,GAAGA,SAAS,CAACG,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI;EAE/D,IAAI,CAACD,UAAU,IAAI,EAAEA,UAAU,YAAYE,eAAe,CAAC,EAAE;IAC3D;EACF;EAEA,MAAM9B,UAAU,GAAG4B,UAAU,CAAC1B,aAAa,CAAC,cAAc,CAAC;EAE3D,IAAI,CAACF,UAAU,EAAE;IACf;EACF;EAEA,MAAMC,eAAe,GAAGH,6BAA6B,CACnD,0BAA4B8B,UAAU,EACtC,iCAAmC5B,UACrC,CAAC;EAED,MAAM+B,SAAS,GAAGhC,IAAI,CAACG,aAAa,CAAC,oBAAoB,CAAC;EAE1D,IAAI6B,SAAS,EAAE;IACbA,SAAS,CAACxB,YAAY,CAACX,gBAAgB,EAAE,mBAAmB,CAAC;EAC/D;EAEA,MAAMqB,WAAW,GAAGD,uBAAuB,CACzC,8BAAgCY,UAAU,EAC1C,0BAA4B5B,UAC9B,CAAC;EAED,MAAMgC,WAAW,GAAG7B,QAAQ,CAACD,aAAa,CACxC,mBAAmBkB,YAAY,EAAEG,IAAI,IACvC,CAAC;EAED,IAAIS,WAAW,EAAE;IACfA,WAAW,CAACC,MAAM,CAAC,CAAC;EACtB;EAEA,MAAMX,GAAG,GAAGH,aAAa,CAACC,YAAY,EAAEC,UAAU,CAAC;EACnDJ,WAAW,CAACH,YAAY,CAACQ,GAAG,EAAEL,WAAW,CAACiB,UAAU,CAAC;EACrDjC,eAAe,CAACkC,WAAW,GAAG,GAAGf,YAAY,EAAEG,IAAI,IAAI,EAAE,IAAIF,UAAU,EAAE;AAC3E;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASe,SAASA,CAACC,OAAO,EAAEC,YAAY,EAAEP,SAAS,EAAE;EACnD,MAAMQ,eAAe,GAAGpC,QAAQ,CAACD,aAAa,CAAC,sBAAsB,CAAC;EAEtE,IAAIqC,eAAe,EAAE;IACnB,MAAMC,YAAY,GAAGrC,QAAQ,CAACwB,cAAc,CAAC9B,sBAAsB,CAAC;IACpE,IAAI2C,YAAY,EAAE;MAChBT,SAAS,CAACxB,YAAY,CAACX,gBAAgB,EAAEC,sBAAsB,CAAC;IAClE,CAAC,MAAM;MACLkC,SAAS,CAACU,eAAe,CAAC7C,gBAAgB,CAAC;IAC7C;IACA;EACF;EAEA,IAAI0C,YAAY,EAAE;IAChBA,YAAY,CAACd,SAAS,GAAG;AAC7B;AACA;AACA,yDAAyD3B,sBAAsB;AAC/E;AACA;AACA;AACA;AACA;AACA,2CAA2CwC,OAAO;AAClD;AACA;AACA;AACA;AACA;AACA,OAAO;IAEHN,SAAS,CAACxB,YAAY,CAACX,gBAAgB,EAAEC,sBAAsB,CAAC;EAClE;EAEA,MAAM6C,SAAS,GAAGX,SAAS,CAACF,OAAO,CAAC,mBAAmB,CAAC;EACxD,IAAIa,SAAS,EAAE;IACbA,SAAS,CAACC,SAAS,CAACC,GAAG,CAAC,yBAAyB,CAAC;IAClDb,SAAS,CAACY,SAAS,CAACC,GAAG,CAAC,0BAA0B,CAAC;IAEnD,MAAMC,OAAO,GAAGd,SAAS,CAAC1B,EAAE;IAC5B,IAAIyC,YAAY,GAAG3C,QAAQ,CAACwB,cAAc,CAAC,GAAGkB,OAAO,QAAQ,CAAC;IAE9D,IAAI,CAACC,YAAY,EAAE;MACjBA,YAAY,GAAG3C,QAAQ,CAACC,aAAa,CAAC,GAAG,CAAC;MAC1C0C,YAAY,CAACzC,EAAE,GAAG,GAAGwC,OAAO,QAAQ;MACpCC,YAAY,CAACxC,SAAS,GAAG,qBAAqB;MAC9CwC,YAAY,CAACtB,SAAS,GAAG,qDAAqDa,OAAO,EAAE;MACvFK,SAAS,CAAC5B,YAAY,CAACgC,YAAY,EAAEf,SAAS,CAAC;IACjD;IAEAA,SAAS,CAACxB,YAAY,CACpBX,gBAAgB,EAChB,uBAAuBiD,OAAO,QAChC,CAAC;EACH;AACF;;AAEA;AACA;AACA;AACA;AACA,SAASpC,aAAaA,CAACsC,OAAO,EAAE;EAC9B,OAAO,0BAA4BA,OAAO;AAC5C;AAEA,SAASC,UAAUA,CAAA,EAAG;EACpBC,MAAM,CAACC,OAAO,CAACC,YAAY,CAAC,IAAI,EAAE,EAAE,EAAEF,MAAM,CAACG,QAAQ,CAACC,IAAI,CAAC;EAC3DJ,MAAM,CAACG,QAAQ,CAACC,IAAI,GAAGJ,MAAM,CAACG,QAAQ,CAACE,QAAQ;AACjD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,oBAAoBA,CAACD,QAAQ,EAAEE,QAAQ,EAAE;EACvD,MAAMC,YAAY,GAAGH,QAAQ,CAACI,KAAK,CAAC,GAAG,CAAC,CAACC,MAAM,CAAEC,OAAO,IAAKA,OAAO,CAAC;EACrE,MAAMC,MAAM,GAAGJ,YAAY,CAACK,MAAM,GAAG,CAAC,GAAG,IAAIL,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE;EACnE,OAAO,GAAGI,MAAM,kBAAkBL,QAAQ,EAAE;AAC9C;;AAEA;AACA;AACA;AACA;AACA,SAASO,gBAAgBA,CAACP,QAAQ,EAAE;EAClC,IAAIQ,QAAQ,GAAG,CAAC;EAChB,MAAMC,QAAQ,GAAGC,WAAW,CAAC,MAAM;IACjCF,QAAQ,EAAE;IAEV,IAAIA,QAAQ,IAAIrE,oBAAoB,EAAE;MACpCwE,aAAa,CAACF,QAAQ,CAAC;MACvBjB,UAAU,CAAC,CAAC;MACZ;IACF;IAEA,MAAMoB,eAAe,GAAGb,oBAAoB,CAC1CN,MAAM,CAACG,QAAQ,CAACE,QAAQ,EACxBE,QACF,CAAC;IAEDa,KAAK,CAACD,eAAe,EAAE;MACrBE,OAAO,EAAE;QACPC,MAAM,EAAE;MACV;IACF,CAAC,CAAC,CACCC,IAAI,CAAEC,QAAQ,IAAK;MAClB,IAAI,CAACA,QAAQ,CAACC,EAAE,EAAE;QAChB,MAAM,IAAIC,KAAK,CAAC,6BAA6B,CAAC;MAChD;MACA,OAAOF,QAAQ,CAACG,IAAI,CAAC,CAAC;IACxB,CAAC,CAAC,CACDJ,IAAI,CAAEK,IAAI,IAAK;MACd,IAAIA,IAAI,CAACC,YAAY,KAAK,OAAO,EAAE;QACjCX,aAAa,CAACF,QAAQ,CAAC;QACvBjB,UAAU,CAAC,CAAC;MACd;IACF,CAAC,CAAC,CACD+B,KAAK,CAAC,MAAM;MACXZ,aAAa,CAACF,QAAQ,CAAC;MACvBjB,UAAU,CAAC,CAAC;IACd,CAAC,CAAC;EACN,CAAC,EAAE,IAAI,CAAC;AACV;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASgC,4BAA4BA,CACnCC,WAAW,EACXlD,SAAS,EACTmD,YAAY,EACZhE,cAAc,EACdE,YAAY,EACZ;EACAK,aAAa,CAACL,YAAY,EAAE,YAAY,EAAE6D,WAAW,CAAC;EAEtDlD,SAAS,CAACoD,KAAK,CAAC,CAAC;EAEjBC,UAAU,CAAC,MAAM;IACfrD,SAAS,CAACsD,QAAQ,GAAG,IAAI;IACzBH,YAAY,CAACG,QAAQ,GAAG,IAAI;IAC5BnE,cAAc,CAACmE,QAAQ,GAAG,IAAI;EAChC,CAAC,EAAE,GAAG,CAAC;AACT;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASC,wBAAwBA,CAC/BC,KAAK,EACLN,WAAW,EACXlD,SAAS,EACTmD,YAAY,EACZ5C,YAAY,EACZkB,QAAQ,EACR;EACA,IAAI,CAACyB,WAAW,CAACO,MAAM,IAAI,CAAChC,QAAQ,EAAE;IACpC,OAAO,KAAK;EACd;EAEA+B,KAAK,CAACE,cAAc,CAAC,CAAC;EAEtB,MAAMC,QAAQ,GAAG,IAAIC,QAAQ,CAACV,WAAW,CAAC;EAC1C,MAAMW,UAAU,GAAG,CAAC,CAACX,WAAW,CAACY,OAAO,CAACC,QAAQ;EACjD,MAAMC,SAAS,GAAGd,WAAW,CAACY,OAAO,CAACC,QAAQ,IAAIb,WAAW,CAACO,MAAM;EAEpE,MAAMQ,YAAY,GAAG,0BAA4B;IAC/CC,MAAM,EAAE,MAAM;IACdtF,IAAI,EAAE+E,QAAQ;IACdQ,QAAQ,EAAEN,UAAU,GAAG,QAAQ,GAAG,QAAQ,CAAC;EAC7C,CAAE;;EAEF;EACA,IAAIA,UAAU,EAAE;IACdI,YAAY,CAACG,IAAI,GAAG,SAAS;EAC/B;EAEA9B,KAAK,CAAC0B,SAAS,EAAEC,YAAY,CAAC,CAC3BxB,IAAI,CAAC,MAAM;IACVT,gBAAgB,CAACP,QAAQ,CAAC;EAC5B,CAAC,CAAC,CACDuB,KAAK,CAAC,MAAM;IACXhD,SAAS,CAACsD,QAAQ,GAAG,KAAK;IAC1BH,YAAY,CAACG,QAAQ,GAAG,KAAK;IAE7BjD,SAAS,CACP,wCAAwC,EACxCE,YAAY,EACZP,SACF,CAAC;IAED,OAAO,IAAI;EACb,CAAC,CAAC;EAEJ,OAAO,IAAI;AACb;AAEA,SAASqE,UAAUA,CAAA,EAAG;EACpB,MAAMrG,IAAI,GAAGI,QAAQ,CAACD,aAAa,CAAC,8BAA8B,CAAC;EACnE;EACA,MAAM6B,SAAS,GAAGhC,IAAI,GAAGA,IAAI,CAACG,aAAa,CAAC,oBAAoB,CAAC,GAAG,IAAI;EACxE;EACA,MAAMgF,YAAY,GAAGnF,IAAI,GAAGA,IAAI,CAACG,aAAa,CAAC,qBAAqB,CAAC,GAAG,IAAI;EAC5E,MAAMgB,cAAc,GAClB,gCACEmF,KAAK,CAACC,IAAI,CAACnG,QAAQ,CAACoG,gBAAgB,CAAC,qBAAqB,CAAC,CAAC,CAACC,IAAI,CAC9DC,MAAM,IAAKA,MAAM,CAACtE,WAAW,EAAEuE,IAAI,CAAC,CAAC,KAAK,UAC7C,CAAC,IACE,IAAI;EAEX,MAAMpE,YAAY,GAAGnC,QAAQ,CAACD,aAAa,CAAC,gCAAgC,CAAC;EAE7E,IAAI,CAACH,IAAI,IAAI,CAACgC,SAAS,IAAI,CAACmD,YAAY,EAAE;IACxC;EACF;EAEA,MAAMD,WAAW,GAAG,8BAAgClF,IAAK;EACzD;EACA,IAAIqB,YAAY,GAAG,IAAI;EACvB,IAAIuF,YAAY,GAAG,KAAK;EACxB,MAAMnD,QAAQ,GAAGyB,WAAW,CAACY,OAAO,CAACrC,QAAQ;EAE7CzB,SAAS,CAAC6E,gBAAgB,CAAC,QAAQ,EAAE,MAAM;IACzC,IAAItE,YAAY,EAAE;MAChBA,YAAY,CAACd,SAAS,GAAG,EAAE;IAC7B;IAEA,IAAIO,SAAS,CAAC8E,KAAK,IAAI9E,SAAS,CAAC8E,KAAK,CAAC/C,MAAM,GAAG,CAAC,EAAE;MACjD1C,YAAY,GAAGW,SAAS,CAAC8E,KAAK,CAAC,CAAC,CAAC;IACnC;EACF,CAAC,CAAC;EAEF3B,YAAY,CAAC0B,gBAAgB,CAAC,OAAO,EAAGrB,KAAK,IAAK;IAChD,IAAI,CAACnE,YAAY,EAAE;MACjBmE,KAAK,CAACE,cAAc,CAAC,CAAC;MACtBrD,SAAS,CACP,eAAe,EACf,iCAAmCE,YAAY,EAC/CP,SACF,CAAC;MACD;IACF;IAEA,IAAI4E,YAAY,EAAE;MAChBpB,KAAK,CAACE,cAAc,CAAC,CAAC;MACtB;IACF;IAEAkB,YAAY,GAAG,IAAI;IAEnB3B,4BAA4B,CAC1BC,WAAW,EACXlD,SAAS,EACTmD,YAAY,EACZhE,cAAc,EACdE,YACF,CAAC;IAEDkE,wBAAwB,CACtBC,KAAK,EACLN,WAAW,EACXlD,SAAS,EACTmD,YAAY,EACZ,iCAAmC5C,YAAY,EAC/CkB,QACF,CAAC;EACH,CAAC,CAAC;AACJ;AAEA,OAAO,SAASsD,cAAcA,CAAA,EAAG;EAC/B,IAAI3G,QAAQ,CAAC4G,UAAU,KAAK,SAAS,EAAE;IACrC5G,QAAQ,CAACyG,gBAAgB,CAAC,kBAAkB,EAAER,UAAU,CAAC;EAC3D,CAAC,MAAM;IACLA,UAAU,CAAC,CAAC;EACd;AACF","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"file-upload.js","names":["MAX_POLLING_DURATION","ARIA_DESCRIBEDBY","ERROR_SUMMARY_TITLE_ID","createOrUpdateStatusAnnouncer","form","fileCountP","statusAnnouncer","querySelector","document","createElement","id","className","setAttribute","addStatusAnnouncerToDOM","asHTMLElement","appendChild","body","nextSibling","parentNode","insertBefore","parentElement","findOrCreateSummaryList","summaryList","buttonGroup","createFileRow","selectedFile","statusText","row","name","innerHTML","renderSummary","container","getElementById","uploadForm","closest","HTMLFormElement","fileInput","existingRow","remove","firstChild","textContent","showError","message","errorSummary","topErrorSummary","titleElement","removeAttribute","formGroup","classList","add","inputId","errorMessage","element","reloadPage","window","history","replaceState","location","href","pathname","buildUploadStatusUrl","uploadId","pathSegments","split","filter","segment","prefix","length","pollUploadStatus","attempts","interval","setInterval","clearInterval","uploadStatusUrl","fetch","headers","Accept","then","response","ok","Error","json","data","uploadStatus","catch","handleStandardFormSubmission","formElement","uploadButton","continueButton","focus","setTimeout","disabled","handleAjaxFormSubmission","event","action","preventDefault","formData","FormData","isLocalDev","dataset","proxyUrl","uploadUrl","fetchOptions","method","redirect","mode","initUpload","Array","from","querySelectorAll","find","button","trim","isSubmitting","addEventListener","files","initFileUpload","readyState"],"sources":["../../../src/client/javascripts/file-upload.js"],"sourcesContent":["export const MAX_POLLING_DURATION = 300 // 5 minutes\nconst ARIA_DESCRIBEDBY = 'aria-describedby'\nconst ERROR_SUMMARY_TITLE_ID = 'error-summary-title'\n\n/**\n * Creates or updates status announcer for screen readers\n * @param {HTMLElement | null} form - The form element\n * @param {HTMLElement | null} fileCountP - The file count paragraph element\n * @returns {HTMLElement} The status announcer element\n */\nfunction createOrUpdateStatusAnnouncer(form, fileCountP) {\n let statusAnnouncer = form?.querySelector('#statusInformation')\n\n if (!statusAnnouncer) {\n statusAnnouncer = document.createElement('div')\n statusAnnouncer.id = 'statusInformation'\n statusAnnouncer.className = 'govuk-visually-hidden'\n statusAnnouncer.setAttribute('aria-live', 'polite')\n\n // multiple fallbacks to ensure the status announcer is always added to the DOM\n // this helps with cross-browser compatibility and unexpected DOM structures encountered during QA\n try {\n addStatusAnnouncerToDOM(\n asHTMLElement(form),\n asHTMLElement(fileCountP),\n asHTMLElement(statusAnnouncer)\n )\n } catch {\n try {\n form?.appendChild(statusAnnouncer)\n } catch {\n document.body.appendChild(statusAnnouncer)\n }\n }\n }\n\n return /** @type {HTMLElement} */ (statusAnnouncer)\n}\n\n/**\n * Helper function to add the status announcer to the DOM\n * @param {HTMLElement} form - The form element\n * @param {HTMLElement | null} fileCountP - The file count paragraph element\n * @param {HTMLElement} statusAnnouncer - The status announcer element to add\n */\nfunction addStatusAnnouncerToDOM(form, fileCountP, statusAnnouncer) {\n if (fileCountP?.nextSibling && fileCountP.parentNode === form) {\n form.insertBefore(statusAnnouncer, fileCountP.nextSibling)\n return\n }\n\n const parentElement = fileCountP?.parentNode ?? form\n parentElement.appendChild(statusAnnouncer)\n}\n\n/**\n * Finds an existing summary list or creates a new one\n * @param {HTMLFormElement} form - The form element\n * @param {HTMLElement} fileCountP - The file count paragraph element\n * @returns {HTMLElement} The summary list element\n */\nfunction findOrCreateSummaryList(form, fileCountP) {\n let summaryList = form.querySelector('dl.govuk-summary-list')\n\n if (!summaryList) {\n summaryList = document.createElement('dl')\n summaryList.className = 'govuk-summary-list govuk-summary-list--long-key'\n\n const buttonGroup = form.querySelector('.govuk-button-group')\n\n if (buttonGroup) {\n form.insertBefore(summaryList, buttonGroup)\n } else {\n form.insertBefore(summaryList, fileCountP.nextSibling)\n }\n }\n\n return /** @type {HTMLElement} */ (summaryList)\n}\n\n/**\n * Creates a file row element for the summary list\n * @param {File | null} selectedFile - The selected file\n * @param {string} statusText - The status to display\n * @returns {HTMLElement} The created row element\n */\nfunction createFileRow(selectedFile, statusText) {\n const row = document.createElement('div')\n row.className = 'govuk-summary-list__row'\n row.setAttribute('data-filename', selectedFile?.name ?? '')\n row.innerHTML = `\n <dt class=\"govuk-summary-list__key\">\n ${selectedFile?.name ?? ''}\n </dt>\n <dd class=\"govuk-summary-list__value\">\n <strong class=\"govuk-tag govuk-tag--yellow\">${statusText}</strong>\n </dd>\n <dd class=\"govuk-summary-list__actions\">\n </dd>\n `\n return row\n}\n\n/**\n * Renders or updates the file summary box for the selected file\n * @param {File | null} selectedFile - The selected file\n * @param {string} statusText - The status to display\n * @param {HTMLElement} form - The form element\n */\nfunction renderSummary(selectedFile, statusText, form) {\n const container = document.getElementById('uploadedFilesContainer')\n const uploadForm = container ? container.closest('form') : null\n\n if (!uploadForm || !(uploadForm instanceof HTMLFormElement)) {\n return\n }\n\n const fileCountP = uploadForm.querySelector('p.govuk-body')\n\n if (!fileCountP) {\n return\n }\n\n const statusAnnouncer = createOrUpdateStatusAnnouncer(\n /** @type {HTMLElement} */ (uploadForm),\n /** @type {HTMLElement | null} */ (fileCountP)\n )\n\n const fileInput = form.querySelector('input[type=\"file\"]')\n\n if (fileInput) {\n fileInput.setAttribute(ARIA_DESCRIBEDBY, 'statusInformation')\n }\n\n const summaryList = findOrCreateSummaryList(\n /** @type {HTMLFormElement} */ (uploadForm),\n /** @type {HTMLElement} */ (fileCountP)\n )\n\n const existingRow = document.querySelector(\n `[data-filename=\"${selectedFile?.name}\"]`\n )\n\n if (existingRow) {\n existingRow.remove()\n }\n\n const row = createFileRow(selectedFile, statusText)\n summaryList.insertBefore(row, summaryList.firstChild)\n statusAnnouncer.textContent = `${selectedFile?.name ?? ''} ${statusText}`\n}\n\n/**\n * Shows an error message using the GOV.UK error summary component\n * and adds inline error styling to the file input\n * @param {string} message - The error message to display\n * @param {HTMLElement | null} errorSummary - The error summary container\n * @param {HTMLInputElement} fileInput - The file input element\n * @returns {void}\n */\nfunction showError(message, errorSummary, fileInput) {\n const topErrorSummary = document.querySelector('.govuk-error-summary')\n\n if (topErrorSummary) {\n const titleElement = document.getElementById(ERROR_SUMMARY_TITLE_ID)\n if (titleElement) {\n fileInput.setAttribute(ARIA_DESCRIBEDBY, ERROR_SUMMARY_TITLE_ID)\n } else {\n fileInput.removeAttribute(ARIA_DESCRIBEDBY)\n }\n return\n }\n\n if (errorSummary) {\n errorSummary.innerHTML = `\n <div class=\"govuk-error-summary\" data-module=\"govuk-error-summary\">\n <div role=\"alert\">\n <h2 class=\"govuk-error-summary__title\" id=\"${ERROR_SUMMARY_TITLE_ID}\">\n There is a problem\n </h2>\n <div class=\"govuk-error-summary__body\">\n <ul class=\"govuk-list govuk-error-summary__list\">\n <li>\n <a href=\"#file-upload\">${message}</a>\n </li>\n </ul>\n </div>\n </div>\n </div>\n `\n\n fileInput.setAttribute(ARIA_DESCRIBEDBY, ERROR_SUMMARY_TITLE_ID)\n }\n\n const formGroup = fileInput.closest('.govuk-form-group')\n if (formGroup) {\n formGroup.classList.add('govuk-form-group--error')\n fileInput.classList.add('govuk-file-upload--error')\n\n const inputId = fileInput.id\n let errorMessage = document.getElementById(`${inputId}-error`)\n\n if (!errorMessage) {\n errorMessage = document.createElement('p')\n errorMessage.id = `${inputId}-error`\n errorMessage.className = 'govuk-error-message'\n errorMessage.innerHTML = `<span class=\"govuk-visually-hidden\">Error:</span> ${message}`\n formGroup.insertBefore(errorMessage, fileInput)\n }\n\n fileInput.setAttribute(\n ARIA_DESCRIBEDBY,\n `error-summary-title ${inputId}-error`\n )\n }\n}\n\n/**\n * Helper to safely convert an Element to HTMLElement\n * @param {Element | null} element - The element to convert\n */\nfunction asHTMLElement(element) {\n return /** @type {HTMLElement} */ (element)\n}\n\nfunction reloadPage() {\n window.history.replaceState(null, '', window.location.href)\n window.location.href = window.location.pathname\n}\n\n/**\n * Build the upload status URL given the current pathname and the upload ID.\n * @param {string} pathname – e.g. window.location.pathname\n * @param {string} uploadId\n * @returns {string} e.g. \"/form/upload-status/abc123\"\n */\nexport function buildUploadStatusUrl(pathname, uploadId) {\n const pathSegments = pathname.split('/').filter((segment) => segment)\n const prefix = pathSegments.length > 0 ? `/${pathSegments[0]}` : ''\n return `${prefix}/upload-status/${uploadId}`\n}\n\n/**\n * Polls the upload status endpoint until the file is ready or timeout occurs\n * @param {string} uploadId - The upload ID to check\n */\nfunction pollUploadStatus(uploadId) {\n let attempts = 0\n const interval = setInterval(() => {\n attempts++\n\n if (attempts >= MAX_POLLING_DURATION) {\n clearInterval(interval)\n reloadPage()\n return\n }\n\n const uploadStatusUrl = buildUploadStatusUrl(\n window.location.pathname,\n uploadId\n )\n\n fetch(uploadStatusUrl, {\n headers: {\n Accept: 'application/json'\n }\n })\n .then((response) => {\n if (!response.ok) {\n throw new Error('Network response was not ok')\n }\n return response.json()\n })\n .then((data) => {\n if (data.uploadStatus === 'ready') {\n clearInterval(interval)\n reloadPage()\n }\n })\n .catch(() => {\n clearInterval(interval)\n reloadPage()\n })\n }, 1000)\n}\n\n/**\n * Handle standard form submission for file upload\n * @param {HTMLFormElement} formElement - The form element\n * @param {HTMLInputElement} fileInput - The file input element\n * @param {HTMLButtonElement} uploadButton - The upload button\n * @param {HTMLButtonElement} continueButton - The continue button\n * @param {File | null} selectedFile - The selected file\n */\nfunction handleStandardFormSubmission(\n formElement,\n fileInput,\n uploadButton,\n continueButton,\n selectedFile\n) {\n renderSummary(selectedFile, 'Uploading…', formElement)\n\n fileInput.focus()\n\n setTimeout(() => {\n fileInput.disabled = true\n uploadButton.disabled = true\n continueButton.disabled = true\n }, 100)\n}\n\n/**\n * Handle AJAX form submission with upload ID\n * @param {Event} event - The click event\n * @param {HTMLFormElement} formElement - The form element\n * @param {HTMLInputElement} fileInput - The file input element\n * @param {HTMLButtonElement} uploadButton - The upload button\n * @param {HTMLElement | null} errorSummary - The error summary container\n * @param {string | undefined} uploadId - The upload ID\n * @returns {boolean} Whether the event was handled\n */\nfunction handleAjaxFormSubmission(\n event,\n formElement,\n fileInput,\n uploadButton,\n errorSummary,\n uploadId\n) {\n if (!formElement.action || !uploadId) {\n return false\n }\n\n event.preventDefault()\n\n const formData = new FormData(formElement)\n const isLocalDev = !!formElement.dataset.proxyUrl\n const uploadUrl = formElement.dataset.proxyUrl ?? formElement.action\n\n const fetchOptions = /** @type {RequestInit} */ ({\n method: 'POST',\n body: formData,\n redirect: isLocalDev ? 'follow' : 'manual' // follow mode if local development with the proxy\n })\n\n // no-cors mode if needed local development with the proxy\n if (isLocalDev) {\n fetchOptions.mode = 'no-cors'\n }\n\n fetch(uploadUrl, fetchOptions)\n .then(() => {\n pollUploadStatus(uploadId)\n })\n .catch(() => {\n fileInput.disabled = false\n uploadButton.disabled = false\n\n showError(\n 'There was a problem uploading the file',\n errorSummary,\n fileInput\n )\n\n return null\n })\n\n return true\n}\n\nfunction initUpload() {\n const form = document.querySelector('form:has(input[type=\"file\"])')\n /** @type {HTMLInputElement | null} */\n const fileInput = form ? form.querySelector('input[type=\"file\"]') : null\n /** @type {HTMLButtonElement | null} */\n const uploadButton = form ? form.querySelector('.upload-file-button') : null\n const continueButton =\n /** @type {HTMLButtonElement} */ (\n Array.from(document.querySelectorAll('button.govuk-button')).find(\n (button) => button.textContent?.trim() === 'Continue'\n )\n ) ?? null\n\n const errorSummary = document.querySelector('.govuk-error-summary-container')\n\n if (!form || !fileInput || !uploadButton) {\n return\n }\n\n const formElement = /** @type {HTMLFormElement} */ (form)\n /** @type {File | null} */\n let selectedFile = null\n let isSubmitting = false\n const uploadId = formElement.dataset.uploadId\n\n fileInput.addEventListener('change', () => {\n if (errorSummary) {\n errorSummary.innerHTML = ''\n }\n\n if (fileInput.files && fileInput.files.length > 0) {\n selectedFile = fileInput.files[0]\n }\n })\n\n uploadButton.addEventListener('click', (event) => {\n if (!selectedFile) {\n event.preventDefault()\n showError(\n 'Select a file',\n /** @type {HTMLElement | null} */ (errorSummary),\n fileInput\n )\n return\n }\n\n if (isSubmitting) {\n event.preventDefault()\n return\n }\n\n isSubmitting = true\n\n handleStandardFormSubmission(\n formElement,\n fileInput,\n uploadButton,\n continueButton,\n selectedFile\n )\n\n handleAjaxFormSubmission(\n event,\n formElement,\n fileInput,\n uploadButton,\n /** @type {HTMLElement | null} */ (errorSummary),\n uploadId\n )\n })\n}\n\nexport function initFileUpload() {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', initUpload)\n } else {\n initUpload()\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Page events
|
|
3
|
+
engine: V2
|
|
4
|
+
schema: 2
|
|
5
|
+
startPage: '/summary'
|
|
6
|
+
pages:
|
|
7
|
+
- title: Your name
|
|
8
|
+
path: '/your-name'
|
|
9
|
+
components:
|
|
10
|
+
- type: TextField
|
|
11
|
+
title: What is your first name?
|
|
12
|
+
name: applicantFirstName
|
|
13
|
+
shortDescription: Your first name
|
|
14
|
+
hint: ''
|
|
15
|
+
options:
|
|
16
|
+
required: true
|
|
17
|
+
schema: {}
|
|
18
|
+
id: 1fb8e182-c709-4792-8f83-e01d8b1fee1a
|
|
19
|
+
- type: TextField
|
|
20
|
+
title: What is your last name?
|
|
21
|
+
name: applicantLastName
|
|
22
|
+
shortDescription: Your last name
|
|
23
|
+
hint: ''
|
|
24
|
+
options:
|
|
25
|
+
required: true
|
|
26
|
+
schema: {}
|
|
27
|
+
id: b68df7f1-d4f4-4c17-83c8-402f584906c9
|
|
28
|
+
next: []
|
|
29
|
+
id: 622a35ec-3795-418a-81f3-a45746959045
|
|
30
|
+
- title: ''
|
|
31
|
+
path: '/date-of-birth'
|
|
32
|
+
events:
|
|
33
|
+
onLoad:
|
|
34
|
+
type: http
|
|
35
|
+
options:
|
|
36
|
+
method: 'POST'
|
|
37
|
+
url: http://localhost:3009/api/example/on-load-page
|
|
38
|
+
components:
|
|
39
|
+
- type: Html
|
|
40
|
+
# technically context.data.submissionReferenceNumber is redundant as the reference number is available locally as context.referenceNumber
|
|
41
|
+
# but this is to demonstrate that the server can send data back to the client
|
|
42
|
+
content: >
|
|
43
|
+
<p class="govuk-body">
|
|
44
|
+
The backend received a full copy of the form state even though you haven't submitted the form yet.
|
|
45
|
+
</p>
|
|
46
|
+
<p class="govuk-body">
|
|
47
|
+
Your submission was received with the reference: <strong>{{ context.data.submissionReferenceNumber }}</strong>.
|
|
48
|
+
</p>
|
|
49
|
+
id: 334b10dc-3373-4928-8fed-575578a67de8
|
|
50
|
+
- type: DatePartsField
|
|
51
|
+
title: When is {{ applicantFirstName }} {{ applicantLastName }}'s birthday?
|
|
52
|
+
name: dateOfBirth
|
|
53
|
+
shortDescription: Your birthday
|
|
54
|
+
hint: ''
|
|
55
|
+
options:
|
|
56
|
+
required: true
|
|
57
|
+
schema: {}
|
|
58
|
+
id: '00738799-3489-4ab2-a57b-542eecb31bfa'
|
|
59
|
+
next: []
|
|
60
|
+
id: da0fbdb4-a2de-4650-be16-9ba552af135f
|
|
61
|
+
- id: 449a45f6-4541-4a46-91bd-8b8931b07b50
|
|
62
|
+
title: Summary
|
|
63
|
+
path: '/summary'
|
|
64
|
+
controller: SummaryPageController
|
|
65
|
+
events:
|
|
66
|
+
onLoad:
|
|
67
|
+
type: http
|
|
68
|
+
options:
|
|
69
|
+
method: 'POST'
|
|
70
|
+
url: http://localhost:3009/api/example/on-summary
|
|
71
|
+
onSave:
|
|
72
|
+
type: http
|
|
73
|
+
options:
|
|
74
|
+
method: 'POST'
|
|
75
|
+
url: http://localhost:3009/api/example/on-summary
|
|
76
|
+
components:
|
|
77
|
+
- type: Html
|
|
78
|
+
content: >
|
|
79
|
+
<h2 class="govuk-heading-m">Your age</h1>
|
|
80
|
+
<p class="govuk-body">
|
|
81
|
+
We've calculated that you are {{ context.data.calculatedAge }} years old. Only proceed if this is correct.
|
|
82
|
+
</p>
|
|
83
|
+
id: c42ea488-a38c-4b67-b8fa-4cf543a4f82d
|
|
84
|
+
next: []
|
|
85
|
+
conditions: []
|
|
86
|
+
sections: []
|
|
87
|
+
lists: []
|
package/.server/server/index.js
CHANGED
|
@@ -16,7 +16,7 @@ import pluginErrorPages from "./plugins/errorPages.js";
|
|
|
16
16
|
import { plugin as pluginViews } from "./plugins/nunjucks/index.js";
|
|
17
17
|
import pluginPulse from "./plugins/pulse.js";
|
|
18
18
|
import pluginSession from "./plugins/session.js";
|
|
19
|
-
import { publicRoutes } from "./routes/index.js";
|
|
19
|
+
import { dummyApiRoutes, publicRoutes } from "./routes/index.js";
|
|
20
20
|
import { prepareSecureContext } from "./secure-context.js";
|
|
21
21
|
const proxyAgent = new ProxyAgent();
|
|
22
22
|
Wreck.agents = {
|
|
@@ -96,6 +96,7 @@ export async function createServer(routeConfig) {
|
|
|
96
96
|
name: 'router',
|
|
97
97
|
register: server => {
|
|
98
98
|
server.route(publicRoutes);
|
|
99
|
+
server.route(dummyApiRoutes);
|
|
99
100
|
}
|
|
100
101
|
}
|
|
101
102
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["Engine","CatboxMemory","CatboxRedis","hapi","inert","Scooter","Wreck","blipp","ProxyAgent","config","requestLogger","requestTracing","buildRedisClient","configureCrumbPlugin","configureEnginePlugin","pluginErrorPages","plugin","pluginViews","pluginPulse","pluginSession","publicRoutes","prepareSecureContext","proxyAgent","agents","https","http","httpsAllowUnauthorized","serverOptions","debug","request","get","port","router","stripTrailingSlash","routes","validate","options","abortEarly","security","hsts","maxAge","includeSubDomains","preload","xss","noSniff","xframe","cache","name","engine","client","createServer","routeConfig","server","register","pluginCrumb","pluginEngine","ext","h","response","continue","header","path","startsWith","route"],"sources":["../../src/server/index.ts"],"sourcesContent":["import { Engine as CatboxMemory } from '@hapi/catbox-memory'\nimport { Engine as CatboxRedis } from '@hapi/catbox-redis'\nimport hapi, {\n type Request,\n type ResponseToolkit,\n type ServerOptions\n} from '@hapi/hapi'\nimport inert from '@hapi/inert'\nimport Scooter from '@hapi/scooter'\nimport Wreck from '@hapi/wreck'\nimport blipp from 'blipp'\nimport { ProxyAgent } from 'proxy-agent'\n\nimport { config } from '~/src/config/index.js'\nimport { requestLogger } from '~/src/server/common/helpers/logging/request-logger.js'\nimport { requestTracing } from '~/src/server/common/helpers/logging/request-tracing.js'\nimport { buildRedisClient } from '~/src/server/common/helpers/redis-client.js'\nimport { configureCrumbPlugin } from '~/src/server/plugins/crumb.js'\nimport { configureEnginePlugin } from '~/src/server/plugins/engine/configureEnginePlugin.js'\nimport pluginErrorPages from '~/src/server/plugins/errorPages.js'\nimport { plugin as pluginViews } from '~/src/server/plugins/nunjucks/index.js'\nimport pluginPulse from '~/src/server/plugins/pulse.js'\nimport pluginSession from '~/src/server/plugins/session.js'\nimport { publicRoutes } from '~/src/server/routes/index.js'\nimport { prepareSecureContext } from '~/src/server/secure-context.js'\nimport { type RouteConfig } from '~/src/server/types.js'\n\nconst proxyAgent = new ProxyAgent()\n\nWreck.agents = {\n https: proxyAgent,\n http: proxyAgent,\n httpsAllowUnauthorized: proxyAgent\n}\n\nconst serverOptions = (): ServerOptions => {\n const serverOptions: ServerOptions = {\n debug: { request: [`${config.get('isDevelopment')}`] },\n port: config.get('port'),\n router: {\n stripTrailingSlash: true\n },\n routes: {\n validate: {\n options: {\n abortEarly: false\n }\n },\n security: {\n hsts: {\n maxAge: 31536000,\n includeSubDomains: true,\n preload: false\n },\n xss: 'enabled',\n noSniff: true,\n xframe: true\n }\n },\n cache: [\n {\n name: 'session',\n engine: config.get('isTest')\n ? new CatboxMemory()\n : new CatboxRedis({\n client: buildRedisClient()\n })\n }\n ]\n }\n\n return serverOptions\n}\n\nexport async function createServer(routeConfig?: RouteConfig) {\n const server = hapi.server(serverOptions())\n\n await server.register(requestLogger)\n\n if (config.get('isProduction')) {\n prepareSecureContext(server)\n }\n\n const pluginCrumb = configureCrumbPlugin(routeConfig)\n const pluginEngine = await configureEnginePlugin(routeConfig)\n\n await server.register(pluginSession)\n await server.register(pluginPulse)\n await server.register(inert)\n await server.register(Scooter)\n await server.register(pluginCrumb)\n await server.register(pluginEngine)\n\n server.ext('onPreResponse', (request: Request, h: ResponseToolkit) => {\n const { response } = request\n\n if ('isBoom' in response) {\n return h.continue\n }\n\n // Prevent search engine indexing\n response.header('x-robots-tag', 'noindex, nofollow')\n\n // Disable cache to ensure back/foward navigation updates progress\n if (\n !request.path.startsWith('/javascripts/') &&\n !request.path.startsWith('/stylesheets/') &&\n !request.path.startsWith('/assets/')\n ) {\n response.header('cache-control', 'no-store')\n }\n\n return h.continue\n })\n\n await server.register(pluginViews)\n\n await server.register({\n plugin: {\n name: 'router',\n register: (server) => {\n server.route(publicRoutes)\n }\n }\n })\n\n await server.register(pluginErrorPages)\n\n if (config.get('cdpEnvironment') === 'local') {\n await server.register(blipp)\n }\n\n await server.register(requestTracing)\n\n return server\n}\n"],"mappings":"AAAA,SAASA,MAAM,IAAIC,YAAY,QAAQ,qBAAqB;AAC5D,SAASD,MAAM,IAAIE,WAAW,QAAQ,oBAAoB;AAC1D,OAAOC,IAAI,
|
|
1
|
+
{"version":3,"file":"index.js","names":["Engine","CatboxMemory","CatboxRedis","hapi","inert","Scooter","Wreck","blipp","ProxyAgent","config","requestLogger","requestTracing","buildRedisClient","configureCrumbPlugin","configureEnginePlugin","pluginErrorPages","plugin","pluginViews","pluginPulse","pluginSession","dummyApiRoutes","publicRoutes","prepareSecureContext","proxyAgent","agents","https","http","httpsAllowUnauthorized","serverOptions","debug","request","get","port","router","stripTrailingSlash","routes","validate","options","abortEarly","security","hsts","maxAge","includeSubDomains","preload","xss","noSniff","xframe","cache","name","engine","client","createServer","routeConfig","server","register","pluginCrumb","pluginEngine","ext","h","response","continue","header","path","startsWith","route"],"sources":["../../src/server/index.ts"],"sourcesContent":["import { Engine as CatboxMemory } from '@hapi/catbox-memory'\nimport { Engine as CatboxRedis } from '@hapi/catbox-redis'\nimport hapi, {\n type Request,\n type ResponseToolkit,\n type ServerOptions,\n type ServerRoute\n} from '@hapi/hapi'\nimport inert from '@hapi/inert'\nimport Scooter from '@hapi/scooter'\nimport Wreck from '@hapi/wreck'\nimport blipp from 'blipp'\nimport { ProxyAgent } from 'proxy-agent'\n\nimport { config } from '~/src/config/index.js'\nimport { requestLogger } from '~/src/server/common/helpers/logging/request-logger.js'\nimport { requestTracing } from '~/src/server/common/helpers/logging/request-tracing.js'\nimport { buildRedisClient } from '~/src/server/common/helpers/redis-client.js'\nimport { configureCrumbPlugin } from '~/src/server/plugins/crumb.js'\nimport { configureEnginePlugin } from '~/src/server/plugins/engine/configureEnginePlugin.js'\nimport pluginErrorPages from '~/src/server/plugins/errorPages.js'\nimport { plugin as pluginViews } from '~/src/server/plugins/nunjucks/index.js'\nimport pluginPulse from '~/src/server/plugins/pulse.js'\nimport pluginSession from '~/src/server/plugins/session.js'\nimport { dummyApiRoutes, publicRoutes } from '~/src/server/routes/index.js'\nimport { prepareSecureContext } from '~/src/server/secure-context.js'\nimport { type RouteConfig } from '~/src/server/types.js'\n\nconst proxyAgent = new ProxyAgent()\n\nWreck.agents = {\n https: proxyAgent,\n http: proxyAgent,\n httpsAllowUnauthorized: proxyAgent\n}\n\nconst serverOptions = (): ServerOptions => {\n const serverOptions: ServerOptions = {\n debug: { request: [`${config.get('isDevelopment')}`] },\n port: config.get('port'),\n router: {\n stripTrailingSlash: true\n },\n routes: {\n validate: {\n options: {\n abortEarly: false\n }\n },\n security: {\n hsts: {\n maxAge: 31536000,\n includeSubDomains: true,\n preload: false\n },\n xss: 'enabled',\n noSniff: true,\n xframe: true\n }\n },\n cache: [\n {\n name: 'session',\n engine: config.get('isTest')\n ? new CatboxMemory()\n : new CatboxRedis({\n client: buildRedisClient()\n })\n }\n ]\n }\n\n return serverOptions\n}\n\nexport async function createServer(routeConfig?: RouteConfig) {\n const server = hapi.server(serverOptions())\n\n await server.register(requestLogger)\n\n if (config.get('isProduction')) {\n prepareSecureContext(server)\n }\n\n const pluginCrumb = configureCrumbPlugin(routeConfig)\n const pluginEngine = await configureEnginePlugin(routeConfig)\n\n await server.register(pluginSession)\n await server.register(pluginPulse)\n await server.register(inert)\n await server.register(Scooter)\n await server.register(pluginCrumb)\n await server.register(pluginEngine)\n\n server.ext('onPreResponse', (request: Request, h: ResponseToolkit) => {\n const { response } = request\n\n if ('isBoom' in response) {\n return h.continue\n }\n\n // Prevent search engine indexing\n response.header('x-robots-tag', 'noindex, nofollow')\n\n // Disable cache to ensure back/foward navigation updates progress\n if (\n !request.path.startsWith('/javascripts/') &&\n !request.path.startsWith('/stylesheets/') &&\n !request.path.startsWith('/assets/')\n ) {\n response.header('cache-control', 'no-store')\n }\n\n return h.continue\n })\n\n await server.register(pluginViews)\n\n await server.register({\n plugin: {\n name: 'router',\n register: (server) => {\n server.route(publicRoutes)\n server.route(dummyApiRoutes as ServerRoute[])\n }\n }\n })\n\n await server.register(pluginErrorPages)\n\n if (config.get('cdpEnvironment') === 'local') {\n await server.register(blipp)\n }\n\n await server.register(requestTracing)\n\n return server\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { type RouteOptions, type ServerRoute } from '@hapi/hapi';
|
|
1
|
+
import { type ResponseObject, type ResponseToolkit, type RouteOptions, type ServerRoute } from '@hapi/hapi';
|
|
2
2
|
import { type PreparePageEventRequestOptions } from '~/src/server/plugins/engine/types.js';
|
|
3
|
-
import { type FormRequestPayloadRefs, type FormRequestRefs } from '~/src/server/routes/types.js';
|
|
3
|
+
import { type FormRequest, type FormRequestPayload, type FormRequestPayloadRefs, type FormRequestRefs } from '~/src/server/routes/types.js';
|
|
4
|
+
export declare function makeGetHandler(preparePageEventRequestOptions?: PreparePageEventRequestOptions): (request: FormRequest, h: Pick<ResponseToolkit, "redirect" | "view">) => ResponseObject | Promise<ResponseObject>;
|
|
5
|
+
export declare function makePostHandler(preparePageEventRequestOptions?: PreparePageEventRequestOptions): (request: FormRequestPayload, h: Pick<ResponseToolkit, "redirect" | "view">) => Promise<ResponseObject>;
|
|
4
6
|
export declare function getRoutes(getRouteOptions: RouteOptions<FormRequestRefs>, postRouteOptions: RouteOptions<FormRequestPayloadRefs>, preparePageEventRequestOptions?: PreparePageEventRequestOptions): (ServerRoute<FormRequestRefs> | ServerRoute<FormRequestPayloadRefs>)[];
|
|
@@ -8,7 +8,33 @@ import { getFormSubmissionData } from "../pageControllers/SummaryPageController.
|
|
|
8
8
|
import { dispatchHandler, redirectOrMakeHandler } from "./index.js";
|
|
9
9
|
import { actionSchema, crumbSchema, itemIdSchema, pathSchema, stateSchema } from "../../../schemas/index.js";
|
|
10
10
|
import * as httpService from "../../../services/httpService.js";
|
|
11
|
-
function
|
|
11
|
+
async function handleHttpEvent(request, page, context, event, model, preparePageEventRequestOptions) {
|
|
12
|
+
const {
|
|
13
|
+
options
|
|
14
|
+
} = event;
|
|
15
|
+
const {
|
|
16
|
+
url
|
|
17
|
+
} = options;
|
|
18
|
+
|
|
19
|
+
// TODO: Update structured data POST payload with when helper
|
|
20
|
+
// is updated to removing the dependency on `SummaryViewModel` etc.
|
|
21
|
+
const viewModel = new SummaryViewModel(request, page, context);
|
|
22
|
+
const items = getFormSubmissionData(viewModel.context, viewModel.details);
|
|
23
|
+
|
|
24
|
+
// @ts-expect-error - function signature will be refactored in the next iteration of the formatter
|
|
25
|
+
const payload = format(context, items, model, undefined, undefined);
|
|
26
|
+
const opts = {
|
|
27
|
+
payload
|
|
28
|
+
};
|
|
29
|
+
if (preparePageEventRequestOptions) {
|
|
30
|
+
preparePageEventRequestOptions(opts, event, page, context);
|
|
31
|
+
}
|
|
32
|
+
const {
|
|
33
|
+
payload: response
|
|
34
|
+
} = await httpService.postJson(url, opts);
|
|
35
|
+
Object.assign(context.data, response);
|
|
36
|
+
}
|
|
37
|
+
export function makeGetHandler(preparePageEventRequestOptions) {
|
|
12
38
|
return function getHandler(request, h) {
|
|
13
39
|
const {
|
|
14
40
|
params
|
|
@@ -29,53 +55,51 @@ function makeGetHandler(preparePageEventRequestOptions) {
|
|
|
29
55
|
throw Boom.notFound(`No model found for /${params.path}`);
|
|
30
56
|
}
|
|
31
57
|
if (events?.onLoad && events.onLoad.type === 'http') {
|
|
32
|
-
|
|
33
|
-
options
|
|
34
|
-
} = events.onLoad;
|
|
35
|
-
const {
|
|
36
|
-
url
|
|
37
|
-
} = options;
|
|
38
|
-
|
|
39
|
-
// TODO: Update structured data POST payload with when helper
|
|
40
|
-
// is updated to removing the dependency on `SummaryViewModel` etc.
|
|
41
|
-
const viewModel = new SummaryViewModel(request, page, context);
|
|
42
|
-
const items = getFormSubmissionData(viewModel.context, viewModel.details);
|
|
43
|
-
|
|
44
|
-
// @ts-expect-error - function signature will be refactored in the next iteration of the formatter
|
|
45
|
-
const payload = format(context, items, model, undefined, undefined);
|
|
46
|
-
const opts = {
|
|
47
|
-
payload
|
|
48
|
-
};
|
|
49
|
-
if (preparePageEventRequestOptions) {
|
|
50
|
-
preparePageEventRequestOptions(opts, events.onLoad, page, context);
|
|
51
|
-
}
|
|
52
|
-
const {
|
|
53
|
-
payload: response
|
|
54
|
-
} = await httpService.postJson(url, opts);
|
|
55
|
-
Object.assign(context.data, response);
|
|
58
|
+
await handleHttpEvent(request, page, context, events.onLoad, model, preparePageEventRequestOptions);
|
|
56
59
|
}
|
|
57
60
|
return page.makeGetRouteHandler()(request, context, h);
|
|
58
61
|
});
|
|
59
62
|
};
|
|
60
63
|
}
|
|
61
|
-
function
|
|
62
|
-
|
|
63
|
-
query
|
|
64
|
-
} = request;
|
|
65
|
-
return redirectOrMakeHandler(request, h, (page, context) => {
|
|
64
|
+
export function makePostHandler(preparePageEventRequestOptions) {
|
|
65
|
+
return function postHandler(request, h) {
|
|
66
66
|
const {
|
|
67
|
-
|
|
68
|
-
} =
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
query
|
|
68
|
+
} = request;
|
|
69
|
+
return redirectOrMakeHandler(request, h, async (page, context) => {
|
|
70
|
+
const {
|
|
71
|
+
pageDef
|
|
72
|
+
} = page;
|
|
73
|
+
const {
|
|
74
|
+
isForceAccess
|
|
75
|
+
} = context;
|
|
76
|
+
const {
|
|
77
|
+
model
|
|
78
|
+
} = request.app;
|
|
79
|
+
const {
|
|
80
|
+
events
|
|
81
|
+
} = page;
|
|
72
82
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
83
|
+
// Redirect to GET for preview URL direct access
|
|
84
|
+
if (isForceAccess && !hasFormComponents(pageDef)) {
|
|
85
|
+
return proceed(request, h, redirectPath(page.href, query));
|
|
86
|
+
}
|
|
87
|
+
if (!model) {
|
|
88
|
+
throw Boom.notFound(`No model found for /${request.params.path}`);
|
|
89
|
+
}
|
|
90
|
+
const response = await page.makePostRouteHandler()(request, context, h);
|
|
91
|
+
if (events?.onSave && events.onSave.type === 'http' && isSuccessful(response)) {
|
|
92
|
+
await handleHttpEvent(request, page, context, events.onSave, model, preparePageEventRequestOptions);
|
|
93
|
+
}
|
|
94
|
+
return response;
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function isSuccessful(response) {
|
|
99
|
+
const {
|
|
100
|
+
statusCode
|
|
101
|
+
} = response;
|
|
102
|
+
return !Boom.isBoom(response) && statusCode >= 200 && statusCode < 400;
|
|
79
103
|
}
|
|
80
104
|
export function getRoutes(getRouteOptions, postRouteOptions, preparePageEventRequestOptions) {
|
|
81
105
|
return [{
|
|
@@ -135,7 +159,7 @@ export function getRoutes(getRouteOptions, postRouteOptions, preparePageEventReq
|
|
|
135
159
|
}, {
|
|
136
160
|
method: 'post',
|
|
137
161
|
path: '/{slug}/{path}/{itemId?}',
|
|
138
|
-
handler:
|
|
162
|
+
handler: makePostHandler(preparePageEventRequestOptions),
|
|
139
163
|
options: {
|
|
140
164
|
...postRouteOptions,
|
|
141
165
|
validate: {
|
|
@@ -153,7 +177,7 @@ export function getRoutes(getRouteOptions, postRouteOptions, preparePageEventReq
|
|
|
153
177
|
}, {
|
|
154
178
|
method: 'post',
|
|
155
179
|
path: '/preview/{state}/{slug}/{path}/{itemId?}',
|
|
156
|
-
handler:
|
|
180
|
+
handler: makePostHandler(preparePageEventRequestOptions),
|
|
157
181
|
options: {
|
|
158
182
|
...postRouteOptions,
|
|
159
183
|
validate: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"questions.js","names":["hasFormComponents","slugSchema","Boom","Joi","normalisePath","proceed","redirectPath","SummaryViewModel","format","getFormSubmissionData","dispatchHandler","redirectOrMakeHandler","actionSchema","crumbSchema","itemIdSchema","pathSchema","stateSchema","httpService","makeGetHandler","preparePageEventRequestOptions","getHandler","request","h","params","path","page","context","events","model","app","notFound","onLoad","type","options","url","viewModel","items","details","payload","undefined","opts","response","postJson","Object","assign","data","makeGetRouteHandler","postHandler","query","pageDef","isForceAccess","href","makePostRouteHandler","getRoutes","getRouteOptions","postRouteOptions","method","handler","validate","object","keys","slug","state","itemId","optional","crumb","action","unknown","required"],"sources":["../../../../../src/server/plugins/engine/routes/questions.ts"],"sourcesContent":["import { hasFormComponents, slugSchema } from '@defra/forms-model'\nimport Boom from '@hapi/boom'\nimport {\n type ResponseToolkit,\n type RouteOptions,\n type ServerRoute\n} from '@hapi/hapi'\nimport Joi from 'joi'\n\nimport {\n normalisePath,\n proceed,\n redirectPath\n} from '~/src/server/plugins/engine/helpers.js'\nimport { SummaryViewModel } from '~/src/server/plugins/engine/models/index.js'\nimport { format } from '~/src/server/plugins/engine/outputFormatters/machine/v1.js'\nimport { getFormSubmissionData } from '~/src/server/plugins/engine/pageControllers/SummaryPageController.js'\nimport {\n dispatchHandler,\n redirectOrMakeHandler\n} from '~/src/server/plugins/engine/routes/index.js'\nimport { type PreparePageEventRequestOptions } from '~/src/server/plugins/engine/types.js'\nimport {\n type FormRequest,\n type FormRequestPayload,\n type FormRequestPayloadRefs,\n type FormRequestRefs\n} from '~/src/server/routes/types.js'\nimport {\n actionSchema,\n crumbSchema,\n itemIdSchema,\n pathSchema,\n stateSchema\n} from '~/src/server/schemas/index.js'\nimport * as httpService from '~/src/server/services/httpService.js'\n\nfunction makeGetHandler(\n preparePageEventRequestOptions?: PreparePageEventRequestOptions\n) {\n return function getHandler(\n request: FormRequest,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>\n ) {\n const { params } = request\n\n if (normalisePath(params.path) === '') {\n return dispatchHandler(request, h)\n }\n\n return redirectOrMakeHandler(request, h, async (page, context) => {\n // Check for a page onLoad HTTP event and if one exists,\n // call it and assign the response to the context data\n const { events } = page\n const { model } = request.app\n\n if (!model) {\n throw Boom.notFound(`No model found for /${params.path}`)\n }\n\n if (events?.onLoad && events.onLoad.type === 'http') {\n const { options } = events.onLoad\n const { url } = options\n\n // TODO: Update structured data POST payload with when helper\n // is updated to removing the dependency on `SummaryViewModel` etc.\n const viewModel = new SummaryViewModel(request, page, context)\n const items = getFormSubmissionData(\n viewModel.context,\n viewModel.details\n )\n\n // @ts-expect-error - function signature will be refactored in the next iteration of the formatter\n const payload = format(context, items, model, undefined, undefined)\n const opts = { payload }\n\n if (preparePageEventRequestOptions) {\n preparePageEventRequestOptions(opts, events.onLoad, page, context)\n }\n\n const { payload: response } = await httpService.postJson(url, opts)\n\n Object.assign(context.data, response)\n }\n\n return page.makeGetRouteHandler()(request, context, h)\n })\n }\n}\n\nfunction postHandler(\n request: FormRequestPayload,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>\n) {\n const { query } = request\n\n return redirectOrMakeHandler(request, h, (page, context) => {\n const { pageDef } = page\n const { isForceAccess } = context\n\n // Redirect to GET for preview URL direct access\n if (isForceAccess && !hasFormComponents(pageDef)) {\n return proceed(request, h, redirectPath(page.href, query))\n }\n\n return page.makePostRouteHandler()(request, context, h)\n })\n}\n\nexport function getRoutes(\n getRouteOptions: RouteOptions<FormRequestRefs>,\n postRouteOptions: RouteOptions<FormRequestPayloadRefs>,\n preparePageEventRequestOptions?: PreparePageEventRequestOptions\n): (ServerRoute<FormRequestRefs> | ServerRoute<FormRequestPayloadRefs>)[] {\n return [\n {\n method: 'get',\n path: '/{slug}',\n handler: makeGetHandler(preparePageEventRequestOptions),\n options: {\n ...getRouteOptions,\n validate: {\n params: Joi.object().keys({\n slug: slugSchema\n })\n }\n }\n },\n {\n method: 'get',\n path: '/preview/{state}/{slug}',\n handler: dispatchHandler,\n options: {\n ...getRouteOptions,\n validate: {\n params: Joi.object().keys({\n state: stateSchema,\n slug: slugSchema\n })\n }\n }\n },\n {\n method: 'get',\n path: '/{slug}/{path}/{itemId?}',\n handler: makeGetHandler(preparePageEventRequestOptions),\n options: {\n ...getRouteOptions,\n validate: {\n params: Joi.object().keys({\n slug: slugSchema,\n path: pathSchema,\n itemId: itemIdSchema.optional()\n })\n }\n }\n },\n {\n method: 'get',\n path: '/preview/{state}/{slug}/{path}/{itemId?}',\n handler: makeGetHandler(preparePageEventRequestOptions),\n options: {\n ...getRouteOptions,\n validate: {\n params: Joi.object().keys({\n state: stateSchema,\n slug: slugSchema,\n path: pathSchema,\n itemId: itemIdSchema.optional()\n })\n }\n }\n },\n {\n method: 'post',\n path: '/{slug}/{path}/{itemId?}',\n handler: postHandler,\n options: {\n ...postRouteOptions,\n validate: {\n params: Joi.object().keys({\n slug: slugSchema,\n path: pathSchema,\n itemId: itemIdSchema.optional()\n }),\n payload: Joi.object()\n .keys({\n crumb: crumbSchema,\n action: actionSchema\n })\n .unknown(true)\n .required()\n }\n }\n },\n {\n method: 'post',\n path: '/preview/{state}/{slug}/{path}/{itemId?}',\n handler: postHandler,\n options: {\n ...postRouteOptions,\n validate: {\n params: Joi.object().keys({\n state: stateSchema,\n slug: slugSchema,\n path: pathSchema,\n itemId: itemIdSchema.optional()\n }),\n payload: Joi.object()\n .keys({\n crumb: crumbSchema,\n action: actionSchema\n })\n .unknown(true)\n .required()\n }\n }\n }\n ]\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"questions.js","names":["hasFormComponents","slugSchema","Boom","Joi","normalisePath","proceed","redirectPath","SummaryViewModel","format","getFormSubmissionData","dispatchHandler","redirectOrMakeHandler","actionSchema","crumbSchema","itemIdSchema","pathSchema","stateSchema","httpService","handleHttpEvent","request","page","context","event","model","preparePageEventRequestOptions","options","url","viewModel","items","details","payload","undefined","opts","response","postJson","Object","assign","data","makeGetHandler","getHandler","h","params","path","events","app","notFound","onLoad","type","makeGetRouteHandler","makePostHandler","postHandler","query","pageDef","isForceAccess","href","makePostRouteHandler","onSave","isSuccessful","statusCode","isBoom","getRoutes","getRouteOptions","postRouteOptions","method","handler","validate","object","keys","slug","state","itemId","optional","crumb","action","unknown","required"],"sources":["../../../../../src/server/plugins/engine/routes/questions.ts"],"sourcesContent":["import { hasFormComponents, slugSchema, type Event } from '@defra/forms-model'\nimport Boom from '@hapi/boom'\nimport {\n type ResponseObject,\n type ResponseToolkit,\n type RouteOptions,\n type ServerRoute\n} from '@hapi/hapi'\nimport Joi from 'joi'\n\nimport {\n normalisePath,\n proceed,\n redirectPath\n} from '~/src/server/plugins/engine/helpers.js'\nimport {\n SummaryViewModel,\n type FormModel\n} from '~/src/server/plugins/engine/models/index.js'\nimport { format } from '~/src/server/plugins/engine/outputFormatters/machine/v1.js'\nimport { getFormSubmissionData } from '~/src/server/plugins/engine/pageControllers/SummaryPageController.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers.js'\nimport {\n dispatchHandler,\n redirectOrMakeHandler\n} from '~/src/server/plugins/engine/routes/index.js'\nimport {\n type FormContext,\n type PreparePageEventRequestOptions\n} from '~/src/server/plugins/engine/types.js'\nimport {\n type FormRequest,\n type FormRequestPayload,\n type FormRequestPayloadRefs,\n type FormRequestRefs\n} from '~/src/server/routes/types.js'\nimport {\n actionSchema,\n crumbSchema,\n itemIdSchema,\n pathSchema,\n stateSchema\n} from '~/src/server/schemas/index.js'\nimport * as httpService from '~/src/server/services/httpService.js'\n\nasync function handleHttpEvent(\n request: FormRequest | FormRequestPayload,\n page: PageControllerClass,\n context: FormContext,\n event: Event,\n model: FormModel,\n preparePageEventRequestOptions?: PreparePageEventRequestOptions\n) {\n const { options } = event\n const { url } = options\n\n // TODO: Update structured data POST payload with when helper\n // is updated to removing the dependency on `SummaryViewModel` etc.\n const viewModel = new SummaryViewModel(request, page, context)\n const items = getFormSubmissionData(viewModel.context, viewModel.details)\n\n // @ts-expect-error - function signature will be refactored in the next iteration of the formatter\n const payload = format(context, items, model, undefined, undefined)\n const opts = { payload }\n\n if (preparePageEventRequestOptions) {\n preparePageEventRequestOptions(opts, event, page, context)\n }\n\n const { payload: response } = await httpService.postJson(url, opts)\n\n Object.assign(context.data, response)\n}\n\nexport function makeGetHandler(\n preparePageEventRequestOptions?: PreparePageEventRequestOptions\n) {\n return function getHandler(\n request: FormRequest,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>\n ) {\n const { params } = request\n\n if (normalisePath(params.path) === '') {\n return dispatchHandler(request, h)\n }\n\n return redirectOrMakeHandler(request, h, async (page, context) => {\n // Check for a page onLoad HTTP event and if one exists,\n // call it and assign the response to the context data\n const { events } = page\n const { model } = request.app\n\n if (!model) {\n throw Boom.notFound(`No model found for /${params.path}`)\n }\n\n if (events?.onLoad && events.onLoad.type === 'http') {\n await handleHttpEvent(\n request,\n page,\n context,\n events.onLoad,\n model,\n preparePageEventRequestOptions\n )\n }\n\n return page.makeGetRouteHandler()(request, context, h)\n })\n }\n}\n\nexport function makePostHandler(\n preparePageEventRequestOptions?: PreparePageEventRequestOptions\n) {\n return function postHandler(\n request: FormRequestPayload,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>\n ) {\n const { query } = request\n\n return redirectOrMakeHandler(request, h, async (page, context) => {\n const { pageDef } = page\n const { isForceAccess } = context\n const { model } = request.app\n const { events } = page\n\n // Redirect to GET for preview URL direct access\n if (isForceAccess && !hasFormComponents(pageDef)) {\n return proceed(request, h, redirectPath(page.href, query))\n }\n\n if (!model) {\n throw Boom.notFound(`No model found for /${request.params.path}`)\n }\n\n const response = await page.makePostRouteHandler()(request, context, h)\n\n if (\n events?.onSave &&\n events.onSave.type === 'http' &&\n isSuccessful(response)\n ) {\n await handleHttpEvent(\n request,\n page,\n context,\n events.onSave,\n model,\n preparePageEventRequestOptions\n )\n }\n\n return response\n })\n }\n}\n\nfunction isSuccessful(response: ResponseObject): boolean {\n const { statusCode } = response\n\n return !Boom.isBoom(response) && statusCode >= 200 && statusCode < 400\n}\n\nexport function getRoutes(\n getRouteOptions: RouteOptions<FormRequestRefs>,\n postRouteOptions: RouteOptions<FormRequestPayloadRefs>,\n preparePageEventRequestOptions?: PreparePageEventRequestOptions\n): (ServerRoute<FormRequestRefs> | ServerRoute<FormRequestPayloadRefs>)[] {\n return [\n {\n method: 'get',\n path: '/{slug}',\n handler: makeGetHandler(preparePageEventRequestOptions),\n options: {\n ...getRouteOptions,\n validate: {\n params: Joi.object().keys({\n slug: slugSchema\n })\n }\n }\n },\n {\n method: 'get',\n path: '/preview/{state}/{slug}',\n handler: dispatchHandler,\n options: {\n ...getRouteOptions,\n validate: {\n params: Joi.object().keys({\n state: stateSchema,\n slug: slugSchema\n })\n }\n }\n },\n {\n method: 'get',\n path: '/{slug}/{path}/{itemId?}',\n handler: makeGetHandler(preparePageEventRequestOptions),\n options: {\n ...getRouteOptions,\n validate: {\n params: Joi.object().keys({\n slug: slugSchema,\n path: pathSchema,\n itemId: itemIdSchema.optional()\n })\n }\n }\n },\n {\n method: 'get',\n path: '/preview/{state}/{slug}/{path}/{itemId?}',\n handler: makeGetHandler(preparePageEventRequestOptions),\n options: {\n ...getRouteOptions,\n validate: {\n params: Joi.object().keys({\n state: stateSchema,\n slug: slugSchema,\n path: pathSchema,\n itemId: itemIdSchema.optional()\n })\n }\n }\n },\n {\n method: 'post',\n path: '/{slug}/{path}/{itemId?}',\n handler: makePostHandler(preparePageEventRequestOptions),\n options: {\n ...postRouteOptions,\n validate: {\n params: Joi.object().keys({\n slug: slugSchema,\n path: pathSchema,\n itemId: itemIdSchema.optional()\n }),\n payload: Joi.object()\n .keys({\n crumb: crumbSchema,\n action: actionSchema\n })\n .unknown(true)\n .required()\n }\n }\n },\n {\n method: 'post',\n path: '/preview/{state}/{slug}/{path}/{itemId?}',\n handler: makePostHandler(preparePageEventRequestOptions),\n options: {\n ...postRouteOptions,\n validate: {\n params: Joi.object().keys({\n state: stateSchema,\n slug: slugSchema,\n path: pathSchema,\n itemId: itemIdSchema.optional()\n }),\n payload: Joi.object()\n .keys({\n crumb: crumbSchema,\n action: actionSchema\n })\n .unknown(true)\n .required()\n }\n }\n }\n ]\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -32,20 +32,18 @@ export const formsService = async () => {
|
|
|
32
32
|
// Instantiate the file loader form service
|
|
33
33
|
const loader = new FileFormService();
|
|
34
34
|
|
|
35
|
-
// Add a
|
|
36
|
-
await loader.addForm('src/server/forms/register-as-a-unicorn-breeder.
|
|
35
|
+
// Add a Yaml form
|
|
36
|
+
await loader.addForm('src/server/forms/register-as-a-unicorn-breeder.yaml', {
|
|
37
37
|
...metadata,
|
|
38
|
-
id: '
|
|
38
|
+
id: '641aeafd-13dd-40fa-9186-001703800efb',
|
|
39
39
|
title: 'Register as a unicorn breeder',
|
|
40
40
|
slug: 'register-as-a-unicorn-breeder'
|
|
41
41
|
});
|
|
42
|
-
|
|
43
|
-
// Add a Yaml form
|
|
44
|
-
await loader.addForm('src/server/forms/register-as-a-unicorn-breeder.yaml', {
|
|
42
|
+
await loader.addForm('src/server/forms/page-events.yaml', {
|
|
45
43
|
...metadata,
|
|
46
|
-
id: '
|
|
47
|
-
title: '
|
|
48
|
-
slug: '
|
|
44
|
+
id: '511db05e-ebbd-42e8-8270-5fe93f5c9762',
|
|
45
|
+
title: 'Page events demo',
|
|
46
|
+
slug: 'page-events-demo'
|
|
49
47
|
});
|
|
50
48
|
await loader.addForm('src/server/forms/components.json', {
|
|
51
49
|
...metadata,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localFormsService.js","names":["config","FileFormService","now","Date","user","id","displayName","author","createdAt","createdBy","updatedAt","updatedBy","metadata","organisation","teamName","teamEmail","submissionGuidance","notificationEmail","get","live","formsService","loader","addForm","title","slug","toFormsService"],"sources":["../../../../../src/server/plugins/engine/services/localFormsService.js"],"sourcesContent":["import { config } from '~/src/config/index.js'\nimport { FileFormService } from '~/src/server/utils/file-form-service.js'\n\n// Create shared form metadata\nconst now = new Date()\nconst user = { id: 'user', displayName: 'Username' }\nconst author = {\n createdAt: now,\n createdBy: user,\n updatedAt: now,\n updatedBy: user\n}\nconst metadata = {\n organisation: 'Defra',\n teamName: 'Team name',\n teamEmail: 'team@defra.gov.uk',\n submissionGuidance: \"Thanks for your submission, we'll be in touch\",\n notificationEmail: config.get('submissionEmailAddress'),\n ...author,\n live: author\n}\n\n/**\n * Return an function rather than the service directly. This is to prevent consumer applications\n * blowing up as they won't have these files on disk. We can defer the execution until when it's\n * needed, i.e. the createServer function of the devtool.\n */\nexport const formsService = async () => {\n // Instantiate the file loader form service\n const loader = new FileFormService()\n\n // Add a
|
|
1
|
+
{"version":3,"file":"localFormsService.js","names":["config","FileFormService","now","Date","user","id","displayName","author","createdAt","createdBy","updatedAt","updatedBy","metadata","organisation","teamName","teamEmail","submissionGuidance","notificationEmail","get","live","formsService","loader","addForm","title","slug","toFormsService"],"sources":["../../../../../src/server/plugins/engine/services/localFormsService.js"],"sourcesContent":["import { config } from '~/src/config/index.js'\nimport { FileFormService } from '~/src/server/utils/file-form-service.js'\n\n// Create shared form metadata\nconst now = new Date()\nconst user = { id: 'user', displayName: 'Username' }\nconst author = {\n createdAt: now,\n createdBy: user,\n updatedAt: now,\n updatedBy: user\n}\nconst metadata = {\n organisation: 'Defra',\n teamName: 'Team name',\n teamEmail: 'team@defra.gov.uk',\n submissionGuidance: \"Thanks for your submission, we'll be in touch\",\n notificationEmail: config.get('submissionEmailAddress'),\n ...author,\n live: author\n}\n\n/**\n * Return an function rather than the service directly. This is to prevent consumer applications\n * blowing up as they won't have these files on disk. We can defer the execution until when it's\n * needed, i.e. the createServer function of the devtool.\n */\nexport const formsService = async () => {\n // Instantiate the file loader form service\n const loader = new FileFormService()\n\n // Add a Yaml form\n await loader.addForm('src/server/forms/register-as-a-unicorn-breeder.yaml', {\n ...metadata,\n id: '641aeafd-13dd-40fa-9186-001703800efb',\n title: 'Register as a unicorn breeder',\n slug: 'register-as-a-unicorn-breeder'\n })\n\n await loader.addForm('src/server/forms/page-events.yaml', {\n ...metadata,\n id: '511db05e-ebbd-42e8-8270-5fe93f5c9762',\n title: 'Page events demo',\n slug: 'page-events-demo'\n })\n\n await loader.addForm('src/server/forms/components.json', {\n ...metadata,\n id: '6a872d3b-13f9e-804ce3e-4830-5c45fb32',\n title: 'Components',\n slug: 'components'\n })\n\n return loader.toFormsService()\n}\n"],"mappings":"AAAA,SAASA,MAAM;AACf,SAASC,eAAe;;AAExB;AACA,MAAMC,GAAG,GAAG,IAAIC,IAAI,CAAC,CAAC;AACtB,MAAMC,IAAI,GAAG;EAAEC,EAAE,EAAE,MAAM;EAAEC,WAAW,EAAE;AAAW,CAAC;AACpD,MAAMC,MAAM,GAAG;EACbC,SAAS,EAAEN,GAAG;EACdO,SAAS,EAAEL,IAAI;EACfM,SAAS,EAAER,GAAG;EACdS,SAAS,EAAEP;AACb,CAAC;AACD,MAAMQ,QAAQ,GAAG;EACfC,YAAY,EAAE,OAAO;EACrBC,QAAQ,EAAE,WAAW;EACrBC,SAAS,EAAE,mBAAmB;EAC9BC,kBAAkB,EAAE,+CAA+C;EACnEC,iBAAiB,EAAEjB,MAAM,CAACkB,GAAG,CAAC,wBAAwB,CAAC;EACvD,GAAGX,MAAM;EACTY,IAAI,EAAEZ;AACR,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMa,YAAY,GAAG,MAAAA,CAAA,KAAY;EACtC;EACA,MAAMC,MAAM,GAAG,IAAIpB,eAAe,CAAC,CAAC;;EAEpC;EACA,MAAMoB,MAAM,CAACC,OAAO,CAAC,qDAAqD,EAAE;IAC1E,GAAGV,QAAQ;IACXP,EAAE,EAAE,sCAAsC;IAC1CkB,KAAK,EAAE,+BAA+B;IACtCC,IAAI,EAAE;EACR,CAAC,CAAC;EAEF,MAAMH,MAAM,CAACC,OAAO,CAAC,mCAAmC,EAAE;IACxD,GAAGV,QAAQ;IACXP,EAAE,EAAE,sCAAsC;IAC1CkB,KAAK,EAAE,kBAAkB;IACzBC,IAAI,EAAE;EACR,CAAC,CAAC;EAEF,MAAMH,MAAM,CAACC,OAAO,CAAC,kCAAkC,EAAE;IACvD,GAAGV,QAAQ;IACXP,EAAE,EAAE,sCAAsC;IAC1CkB,KAAK,EAAE,YAAY;IACnBC,IAAI,EAAE;EACR,CAAC,CAAC;EAEF,OAAOH,MAAM,CAACI,cAAc,CAAC,CAAC;AAChC,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type Request, type ResponseToolkit } from '@hapi/hapi';
|
|
2
|
+
declare const _default: ({
|
|
3
|
+
method: string;
|
|
4
|
+
path: string;
|
|
5
|
+
handler(request: Request<{
|
|
6
|
+
Payload: {
|
|
7
|
+
meta: {
|
|
8
|
+
referenceNumber: string;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
}>, _h: ResponseToolkit): {
|
|
12
|
+
submissionEvent: string;
|
|
13
|
+
submissionReferenceNumber: string;
|
|
14
|
+
};
|
|
15
|
+
} | {
|
|
16
|
+
method: string;
|
|
17
|
+
path: string;
|
|
18
|
+
handler(request: Request<{
|
|
19
|
+
Payload: {
|
|
20
|
+
data: {
|
|
21
|
+
main: {
|
|
22
|
+
applicantFirstName: string;
|
|
23
|
+
applicantLastName: string;
|
|
24
|
+
dateOfBirth: string;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
meta: {
|
|
28
|
+
event: string;
|
|
29
|
+
referenceNumber: string;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
}>, _h: ResponseToolkit): {
|
|
33
|
+
calculatedAge: number;
|
|
34
|
+
submissionEvent: string;
|
|
35
|
+
submissionReferenceNumber: string;
|
|
36
|
+
};
|
|
37
|
+
})[];
|
|
38
|
+
export default _default;
|