@gov-cy/govcy-express-services 1.0.0-alpha.6 β 1.0.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/index.mjs +8 -8
- package/src/middleware/govcyFormsPostHandler.mjs +1 -1
- package/src/middleware/govcyPageHandler.mjs +4 -1
- package/src/public/js/govcyFiles.js +117 -11
- package/src/resources/govcyResources.mjs +24 -3
- package/src/utils/govcyApiDetection.mjs +1 -1
- package/src/utils/govcyConstants.mjs +1 -1
- package/src/utils/govcyDataLayer.mjs +8 -0
- package/src/utils/govcyFormHandling.mjs +64 -3
- package/src/utils/govcyHandleFiles.mjs +5 -0
- package/src/utils/govcyValidator.mjs +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gov-cy/govcy-express-services",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.7",
|
|
4
4
|
"description": "An Express-based system that dynamically renders services using @gov-cy/govcy-frontend-renderer and posts data to a submission API.",
|
|
5
5
|
"author": "DMRID - DSF Team",
|
|
6
6
|
"license": "MIT",
|
package/src/index.mjs
CHANGED
|
@@ -129,6 +129,14 @@ export default function initializeGovCyExpressService(){
|
|
|
129
129
|
|
|
130
130
|
// π -- ROUTE: Serve manifest.json dynamically for each site
|
|
131
131
|
app.get('/:siteId/manifest.json', serviceConfigDataMiddleware, govcyManifestHandler());
|
|
132
|
+
|
|
133
|
+
// ποΈ -- ROUTE: Handle POST requests for file uploads for a page.
|
|
134
|
+
app.post('/apis/:siteId/:pageUrl/upload',
|
|
135
|
+
serviceConfigDataMiddleware,
|
|
136
|
+
requireAuth, // UNCOMMENT
|
|
137
|
+
naturalPersonPolicy, // UNCOMMENT
|
|
138
|
+
govcyServiceEligibilityHandler(true), // UNCOMMENT
|
|
139
|
+
govcyUploadMiddleware);
|
|
132
140
|
|
|
133
141
|
// π -- ROUTE: Handle route with only siteId (/:siteId or /:siteId/)
|
|
134
142
|
app.get('/:siteId', serviceConfigDataMiddleware, requireAuth, naturalPersonPolicy, govcyServiceEligibilityHandler(true),govcyLoadSubmissionData(),govcyPageHandler(), renderGovcyPage());
|
|
@@ -148,14 +156,6 @@ export default function initializeGovCyExpressService(){
|
|
|
148
156
|
// π₯ -- ROUTE: Handle POST requests for review page. The `submit` action
|
|
149
157
|
app.post('/:siteId/review', serviceConfigDataMiddleware, requireAuth, naturalPersonPolicy, govcyServiceEligibilityHandler(), govcyReviewPostHandler());
|
|
150
158
|
|
|
151
|
-
// ποΈ -- ROUTE: Handle POST requests for file uploads for a page.
|
|
152
|
-
app.post('/:siteId/:pageUrl/upload',
|
|
153
|
-
serviceConfigDataMiddleware,
|
|
154
|
-
requireAuth, // UNCOMMENT
|
|
155
|
-
naturalPersonPolicy, // UNCOMMENT
|
|
156
|
-
govcyServiceEligibilityHandler(true), // UNCOMMENT
|
|
157
|
-
govcyUploadMiddleware);
|
|
158
|
-
|
|
159
159
|
// ππ₯ -- ROUTE: Handle POST requests (Form Submissions) based on siteId and pageUrl, using govcyFormsPostHandler middleware
|
|
160
160
|
app.post('/:siteId/:pageUrl', serviceConfigDataMiddleware, requireAuth, naturalPersonPolicy, govcyServiceEligibilityHandler(true), govcyFormsPostHandler());
|
|
161
161
|
|
|
@@ -43,7 +43,7 @@ export function govcyFormsPostHandler() {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
// const formData = req.body; // Submitted data
|
|
46
|
-
const formData = getFormData(formElement.params.elements, req.body); // Submitted data
|
|
46
|
+
const formData = getFormData(formElement.params.elements, req.body, req.session, siteId, pageUrl); // Submitted data
|
|
47
47
|
|
|
48
48
|
// βοΈ Start validation from top-level form elements
|
|
49
49
|
const validationErrors = validateFormElements(formElement.params.elements, formData);
|
|
@@ -53,6 +53,9 @@ export function govcyPageHandler() {
|
|
|
53
53
|
element.params.method = "POST";
|
|
54
54
|
// β Add CSRF token
|
|
55
55
|
element.params.elements.push(govcyResources.csrfTokenInput(req.csrfToken()));
|
|
56
|
+
// // β Add siteId and pageUrl to form data
|
|
57
|
+
// element.params.elements.push(govcyResources.siteAndPageInput(siteId, pageUrl, req.globalLang));
|
|
58
|
+
// β Add govcyFormsJs script to the form
|
|
56
59
|
element.params.elements.push(govcyResources.staticResources.elements["govcyFormsJs"]);
|
|
57
60
|
|
|
58
61
|
// π Find the first button with `prototypeNavigate`
|
|
@@ -88,7 +91,7 @@ export function govcyPageHandler() {
|
|
|
88
91
|
}
|
|
89
92
|
//--------- End of Handle Validation Errors ---------
|
|
90
93
|
|
|
91
|
-
populateFormData(element.params.elements, theData,validationErrors);
|
|
94
|
+
populateFormData(element.params.elements, theData,validationErrors, req.session, siteId, pageUrl, req.globalLang);
|
|
92
95
|
// if there are validation errors, add an error summary
|
|
93
96
|
if (validationErrors?.errorSummary?.length > 0) {
|
|
94
97
|
element.params.elements.unshift(govcyResources.errorSummary(validationErrors.errorSummary));
|
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
// π Select all file inputs that have the .govcy-file-upload class
|
|
2
2
|
const fileInputs = document.querySelectorAll('input[type="file"].govcy-file-upload');
|
|
3
3
|
|
|
4
|
-
// π Get the CSRF token from a hidden input field (generated by your backend)
|
|
5
|
-
const csrfToken = document.querySelector('input[type="hidden"][name="_csrf"]')?.value;
|
|
6
|
-
|
|
7
|
-
// π§ Define siteId and pageUrl (you can dynamically extract these later)
|
|
8
|
-
const siteId = 'test';
|
|
9
|
-
const pageUrl = 'data-entry-all';
|
|
10
|
-
|
|
11
4
|
// π Loop over each file input and attach a change event listener
|
|
12
5
|
fileInputs.forEach(input => {
|
|
13
6
|
input.addEventListener('change', async (event) => {
|
|
7
|
+
const messages = {
|
|
8
|
+
"uploadSuccesful": {
|
|
9
|
+
"el": "΀ο Ξ±ΟΟΡιΜΞΏ ανΡβαΟΟΞ·ΞΊΞ΅",
|
|
10
|
+
"en": "File uploaded successfully",
|
|
11
|
+
"tr": "File uploaded successfully"
|
|
12
|
+
},
|
|
13
|
+
"uploadFailed": {
|
|
14
|
+
"el": "ΞΟΞΏΟΟ
ΟΞΉΞ± ανΡβαΟΞ·Ο",
|
|
15
|
+
"en": "File upload failed",
|
|
16
|
+
"tr": "File upload failed"
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
// π Get the CSRF token from a hidden input field (generated by your backend)
|
|
20
|
+
const csrfToken = document.querySelector('input[type="hidden"][name="_csrf"]')?.value;
|
|
21
|
+
// π§ Define siteId and pageUrl (you can dynamically extract these later)
|
|
22
|
+
const siteId = window._govcySiteId || "";
|
|
23
|
+
const pageUrl = window._govcyPageUrl || "";
|
|
24
|
+
const lang = window._govcyLang || "el";
|
|
14
25
|
// π¦ Grab the selected file
|
|
15
26
|
const file = event.target.files[0];
|
|
16
27
|
const elementName = input.name; // Form field's `name` attribute
|
|
@@ -24,7 +35,7 @@ fileInputs.forEach(input => {
|
|
|
24
35
|
|
|
25
36
|
try {
|
|
26
37
|
// π Send file to the backend upload API
|
|
27
|
-
const response = await axios.post(
|
|
38
|
+
const response = await axios.post(`/apis/${siteId}/${pageUrl}/upload`, formData, {
|
|
28
39
|
headers: {
|
|
29
40
|
'X-CSRF-Token': csrfToken // π Pass CSRF token in custom header
|
|
30
41
|
}
|
|
@@ -36,11 +47,106 @@ fileInputs.forEach(input => {
|
|
|
36
47
|
document.querySelector(`[name="${elementName}Attachment[fileId]"`).value = fileId;
|
|
37
48
|
document.querySelector(`[name="${elementName}Attachment[sha256]"`).value = sha256;
|
|
38
49
|
|
|
39
|
-
|
|
50
|
+
// β
Success
|
|
51
|
+
// Create an instance of GovcyFrontendRendererBrowser
|
|
52
|
+
const renderer = new GovcyFrontendRendererBrowser();
|
|
53
|
+
// Define the input data
|
|
54
|
+
const inputData =
|
|
55
|
+
{
|
|
56
|
+
"site": {
|
|
57
|
+
"lang": lang
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const fileInputMap = window._govcyFileInputs || {};
|
|
62
|
+
let fileElement = fileInputMap[elementName];
|
|
63
|
+
fileElement.element = "fileView";
|
|
64
|
+
fileElement.params.fileId = fileId;
|
|
65
|
+
fileElement.params.sha256 = sha256;
|
|
66
|
+
fileElement.params.visuallyHiddenText = fileElement.params.label;
|
|
67
|
+
fileElement.params.error = null;
|
|
68
|
+
// TODO: Also need to set the `view` and `download` URLs
|
|
69
|
+
fileElement.params.viewHref = "#viewHref";
|
|
70
|
+
fileElement.params.deleteHref = "#deleteHref";
|
|
71
|
+
// Construct the JSONTemplate
|
|
72
|
+
const JSONTemplate = {
|
|
73
|
+
"elements": [fileElement]
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
//render HTML into string
|
|
77
|
+
let renderedHtml = renderer.renderFromJSON(JSONTemplate,inputData);
|
|
78
|
+
// look for element with id `${elementName}-outer-control`
|
|
79
|
+
// if not found look for element with id `${elementName}-input-control`
|
|
80
|
+
// if not found look for element with id `${elementName}-view-control`
|
|
81
|
+
var outerElement = document.getElementById(`${elementName}-outer-control`)
|
|
82
|
+
|| document.getElementById(`${elementName}-input-control`)
|
|
83
|
+
|| document.getElementById(`${elementName}-view-control`);
|
|
84
|
+
|
|
85
|
+
if (outerElement) {
|
|
86
|
+
//remove all classes from outerElement
|
|
87
|
+
outerElement.className = "";
|
|
88
|
+
//set the id of the outerElement to `${elementName}-outer-control`
|
|
89
|
+
outerElement.id = `${elementName}-outer-control`;
|
|
90
|
+
//update DOM and initialize the JS components
|
|
91
|
+
renderer.updateDOMAndInitialize(`${elementName}-outer-control`, renderedHtml);
|
|
92
|
+
}
|
|
93
|
+
// β
Update ARIA live region with success message
|
|
94
|
+
const statusRegion = document.getElementById('_govcy-upload-status');
|
|
95
|
+
if (statusRegion) {
|
|
96
|
+
statusRegion.textContent = messages.uploadSuccesful[lang];
|
|
97
|
+
setTimeout(() => {
|
|
98
|
+
statusRegion.textContent = '';
|
|
99
|
+
}, 10000);
|
|
100
|
+
}
|
|
101
|
+
// alert('β
File uploaded successfully');
|
|
40
102
|
|
|
41
103
|
} catch (err) {
|
|
42
|
-
//
|
|
43
|
-
|
|
104
|
+
// Create an instance of GovcyFrontendRendererBrowser
|
|
105
|
+
const renderer = new GovcyFrontendRendererBrowser();
|
|
106
|
+
const lang = window._govcyLang || "el";
|
|
107
|
+
// Define the input data
|
|
108
|
+
const inputData =
|
|
109
|
+
{
|
|
110
|
+
"site": {
|
|
111
|
+
"lang": lang
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
const fileInputMap = window._govcyFileInputs || {};
|
|
115
|
+
let fileElement = fileInputMap[elementName];
|
|
116
|
+
fileElement.element = "fileInput";
|
|
117
|
+
fileElement.params.fileId = "";
|
|
118
|
+
fileElement.params.sha256 = ""
|
|
119
|
+
fileElement.params.error = messages.uploadFailed;
|
|
120
|
+
|
|
121
|
+
// Construct the JSONTemplate
|
|
122
|
+
const JSONTemplate = {
|
|
123
|
+
"elements": [fileElement]
|
|
124
|
+
};
|
|
125
|
+
//render HTML into string
|
|
126
|
+
let renderedHtml = renderer.renderFromJSON(JSONTemplate,inputData);
|
|
127
|
+
var outerElement = document.getElementById(`${elementName}-outer-control`)
|
|
128
|
+
|| document.getElementById(`${elementName}-input-control`)
|
|
129
|
+
|| document.getElementById(`${elementName}-view-control`);
|
|
130
|
+
|
|
131
|
+
if (outerElement) {
|
|
132
|
+
//remove all classes from outerElement
|
|
133
|
+
outerElement.className = "";
|
|
134
|
+
//set the id of the outerElement to `${elementName}-outer-control`
|
|
135
|
+
outerElement.id = `${elementName}-outer-control`;
|
|
136
|
+
//update DOM and initialize the JS components
|
|
137
|
+
renderer.updateDOMAndInitialize(`${elementName}-outer-control`, renderedHtml);
|
|
138
|
+
//TODO: Kamran need to figure a way to re register the DOM event on change
|
|
139
|
+
}
|
|
140
|
+
// β
Update ARIA live region with success message
|
|
141
|
+
const statusRegion = document.getElementById('_govcy-upload-error');
|
|
142
|
+
if (statusRegion) {
|
|
143
|
+
statusRegion.textContent = messages.uploadFailed[lang];
|
|
144
|
+
setTimeout(() => {
|
|
145
|
+
statusRegion.textContent = '';
|
|
146
|
+
}, 10000);
|
|
147
|
+
}
|
|
148
|
+
// // β οΈ Show an error message if upload fails
|
|
149
|
+
// alert('β Upload failed: ' + (err.response?.data?.error || err.message));
|
|
44
150
|
}
|
|
45
151
|
});
|
|
46
152
|
});
|
|
@@ -113,9 +113,9 @@ export const staticResources = {
|
|
|
113
113
|
element: "htmlElement",
|
|
114
114
|
params: {
|
|
115
115
|
text: {
|
|
116
|
-
en: `<script src="https://cdn.jsdelivr.net/npm/axios@1.6.2/dist/axios.min.js"></script><script src="/js/govcyForms.js"></script><script src="/js/govcyFiles.js"></script>`,
|
|
117
|
-
el: `<script src="https://cdn.jsdelivr.net/npm/axios@1.6.2/dist/axios.min.js"></script><script src="/js/govcyForms.js"></script><script src="/js/govcyFiles.js"></script>`,
|
|
118
|
-
tr: `<script src="https://cdn.jsdelivr.net/npm/axios@1.6.2/dist/axios.min.js"></script><script src="/js/govcyForms.js"></script><script src="/js/govcyFiles.js"></script>`
|
|
116
|
+
en: `<script src="https://cdn.jsdelivr.net/npm/axios@1.6.2/dist/axios.min.js"></script><script src="https://cdn.jsdelivr.net/gh/gov-cy/govcy-frontend-renderer@v1/dist/govcyCompiledTemplates.browser.js"></script><script src="https://cdn.jsdelivr.net/gh/gov-cy/govcy-frontend-renderer@v1/dist/govcyFrontendRenderer.browser.js"></script><script src="/js/govcyForms.js"></script><script src="/js/govcyFiles.js"></script>`,
|
|
117
|
+
el: `<script src="https://cdn.jsdelivr.net/npm/axios@1.6.2/dist/axios.min.js"></script><script src="https://cdn.jsdelivr.net/gh/gov-cy/govcy-frontend-renderer@v1/dist/govcyCompiledTemplates.browser.js"></script><script src="https://cdn.jsdelivr.net/gh/gov-cy/govcy-frontend-renderer@v1/dist/govcyFrontendRenderer.browser.js"></script><script src="/js/govcyForms.js"></script><script src="/js/govcyFiles.js"></script>`,
|
|
118
|
+
tr: `<script src="https://cdn.jsdelivr.net/npm/axios@1.6.2/dist/axios.min.js"></script><script src="https://cdn.jsdelivr.net/gh/gov-cy/govcy-frontend-renderer@v1/dist/govcyCompiledTemplates.browser.js"></script><script src="https://cdn.jsdelivr.net/gh/gov-cy/govcy-frontend-renderer@v1/dist/govcyFrontendRenderer.browser.js"></script><script src="/js/govcyForms.js"></script><script src="/js/govcyFiles.js"></script>`
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
},
|
|
@@ -192,6 +192,27 @@ export function csrfTokenInput(csrfToken) {
|
|
|
192
192
|
};
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
+
/**
|
|
196
|
+
* Get the site and page input elements
|
|
197
|
+
* @param {string} siteId The site id
|
|
198
|
+
* @param {string} pageUrl The page url
|
|
199
|
+
* @param {string} lang The page language
|
|
200
|
+
* @returns {object} htmlElement with the site and page inputs
|
|
201
|
+
*/
|
|
202
|
+
export function siteAndPageInput(siteId, pageUrl, lang = "el") {
|
|
203
|
+
const siteAndPageInputs = `<input type="hidden" name="_siteId" value="${siteId}"><input type="hidden" name="_pageUrl" value="${pageUrl}"><input type="hidden" name="_lang" value="${lang}">`;
|
|
204
|
+
return {
|
|
205
|
+
element: "htmlElement",
|
|
206
|
+
params: {
|
|
207
|
+
text: {
|
|
208
|
+
en: siteAndPageInputs,
|
|
209
|
+
el: siteAndPageInputs,
|
|
210
|
+
tr: siteAndPageInputs
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
195
216
|
/**
|
|
196
217
|
* Error page template
|
|
197
218
|
* @param {object} title the title text element
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
export function isApiRequest(req) {
|
|
11
11
|
const acceptJson = (req.headers?.accept || "").toLowerCase().includes("application/json");
|
|
12
12
|
|
|
13
|
-
const apiUrlPattern =
|
|
13
|
+
const apiUrlPattern = /^\/apis\/[^/]+\/[^/]+\/(upload|download)$/;
|
|
14
14
|
const isStructuredApiUrl = apiUrlPattern.test(req.originalUrl || req.url);
|
|
15
15
|
|
|
16
16
|
return acceptJson || isStructuredApiUrl;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared constants for allowed form elements.
|
|
3
3
|
*/
|
|
4
|
-
export const ALLOWED_FORM_ELEMENTS = ["textInput", "textArea", "select", "radios", "checkboxes", "datePicker", "dateInput"];
|
|
4
|
+
export const ALLOWED_FORM_ELEMENTS = ["textInput", "textArea", "select", "radios", "checkboxes", "datePicker", "dateInput","fileInput","fileView"];
|
|
5
5
|
export const ALLOWED_FILE_MIME_TYPES = ['application/pdf', 'image/jpeg', 'image/png'];
|
|
6
6
|
export const ALLOWED_FILE_EXTENSIONS = ['pdf', 'jpg', 'jpeg', 'png'];
|
|
7
7
|
export const ALLOWED_FILE_SIZE_MB = 5; // Maximum file size in MB
|
|
@@ -98,6 +98,14 @@ export function storePageData(store, siteId, pageUrl, formData) {
|
|
|
98
98
|
|
|
99
99
|
store.siteData[siteId].inputData[pageUrl]["formData"] = formData;
|
|
100
100
|
}
|
|
101
|
+
|
|
102
|
+
export function storePageDataElement(store, siteId, pageUrl, elementName, value) {
|
|
103
|
+
// Ensure session structure is initialized
|
|
104
|
+
initializeSiteData(store, siteId, pageUrl);
|
|
105
|
+
|
|
106
|
+
// Store the element value
|
|
107
|
+
store.siteData[siteId].inputData[pageUrl].formData[elementName] = value;
|
|
108
|
+
}
|
|
101
109
|
/**
|
|
102
110
|
* Stores the page's input data in the data layer
|
|
103
111
|
* *
|
|
@@ -5,16 +5,22 @@
|
|
|
5
5
|
* and show error summary when there are validation errors.
|
|
6
6
|
*/
|
|
7
7
|
import { ALLOWED_FORM_ELEMENTS } from "./govcyConstants.mjs";
|
|
8
|
+
import * as dataLayer from "./govcyDataLayer.mjs";
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Helper function to populate form data with session data
|
|
12
13
|
* @param {Array} formElements The form elements
|
|
13
14
|
* @param {*} theData The data either from session or request
|
|
15
|
+
* @param {Object} validationErrors The validation errors
|
|
16
|
+
* @param {Object} store The session store
|
|
17
|
+
* @param {string} siteId The site ID
|
|
18
|
+
* @param {string} pageUrl The page URL
|
|
19
|
+
* @param {string} lang The language
|
|
14
20
|
*/
|
|
15
|
-
export function populateFormData(formElements, theData, validationErrors) {
|
|
21
|
+
export function populateFormData(formElements, theData, validationErrors, store = {}, siteId = "", pageUrl = "", lang = "el") {
|
|
16
22
|
const inputElements = ALLOWED_FORM_ELEMENTS;
|
|
17
|
-
|
|
23
|
+
let fileInputElements = {};
|
|
18
24
|
// Recursively populate form data with session data
|
|
19
25
|
formElements.forEach(element => {
|
|
20
26
|
if (inputElements.includes(element.element)) {
|
|
@@ -53,6 +59,24 @@ export function populateFormData(formElements, theData, validationErrors) {
|
|
|
53
59
|
// Invalid format (not matching D/M/YYYY or DD/MM/YYYY)
|
|
54
60
|
element.params.value = "";
|
|
55
61
|
}
|
|
62
|
+
} else if (element.element === "fileInput") {
|
|
63
|
+
// For fileInput, we change the element.element to "fileView" and set the
|
|
64
|
+
// fileId and sha256 from the session store
|
|
65
|
+
const fileData = dataLayer.getFormDataValue(store, siteId, pageUrl, fieldName + "Attachment");
|
|
66
|
+
// TODO: Ask Andreas how to handle empty file inputs
|
|
67
|
+
if (fileData) {
|
|
68
|
+
element.element = "fileView";
|
|
69
|
+
element.params.fileId = fileData.fileId;
|
|
70
|
+
element.params.sha256 = fileData.sha256;
|
|
71
|
+
element.params.visuallyHiddenText = element.params.label;
|
|
72
|
+
// TODO: Also need to set the `view` and `download` URLs
|
|
73
|
+
element.params.viewHref = "#viewHref";
|
|
74
|
+
element.params.deleteHref = "#deleteHref";
|
|
75
|
+
} else {
|
|
76
|
+
// TODO: Ask Andreas how to handle empty file inputs
|
|
77
|
+
element.params.value = "";
|
|
78
|
+
}
|
|
79
|
+
fileInputElements[fieldName] = element;
|
|
56
80
|
// Handle all other input elements (textInput, checkboxes, radios, etc.)
|
|
57
81
|
} else {
|
|
58
82
|
element.params.value = theData[fieldName] || "";
|
|
@@ -88,6 +112,29 @@ export function populateFormData(formElements, theData, validationErrors) {
|
|
|
88
112
|
});
|
|
89
113
|
}
|
|
90
114
|
});
|
|
115
|
+
// add file input elements's definition in js object
|
|
116
|
+
if (fileInputElements != {}) {
|
|
117
|
+
const scriptTag = `
|
|
118
|
+
<script type="text/javascript">
|
|
119
|
+
window._govcyFileInputs = ${JSON.stringify(fileInputElements)};
|
|
120
|
+
window._govcySiteId = "${siteId}";
|
|
121
|
+
window._govcyPageUrl = "${pageUrl}";
|
|
122
|
+
window._govcyLang = "${lang}";
|
|
123
|
+
</script>
|
|
124
|
+
<div id="_govcy-upload-status" class="govcy-visually-hidden" role="status" aria-live="polite"></div>
|
|
125
|
+
<div id="_govcy-upload-error" class="govcy-visually-hidden" role="alert" aria-live="assertive"></div>
|
|
126
|
+
`.trim();
|
|
127
|
+
formElements.push({
|
|
128
|
+
element: 'htmlElement',
|
|
129
|
+
params: {
|
|
130
|
+
text: {
|
|
131
|
+
en: scriptTag,
|
|
132
|
+
el: scriptTag,
|
|
133
|
+
tr: scriptTag
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
91
138
|
}
|
|
92
139
|
|
|
93
140
|
|
|
@@ -96,9 +143,12 @@ export function populateFormData(formElements, theData, validationErrors) {
|
|
|
96
143
|
*
|
|
97
144
|
* @param {Array} elements - The form elements (including conditional ones).
|
|
98
145
|
* @param {Object} formData - The submitted form data.
|
|
146
|
+
* @param {Object} store - The session store .
|
|
147
|
+
* @param {string} siteId - The site ID .
|
|
148
|
+
* @param {string} pageUrl - The page URL .
|
|
99
149
|
* @returns {Object} filteredData - The filtered form data.
|
|
100
150
|
*/
|
|
101
|
-
export function getFormData(elements, formData) {
|
|
151
|
+
export function getFormData(elements, formData, store = {}, siteId = "", pageUrl = "") {
|
|
102
152
|
const filteredData = {};
|
|
103
153
|
elements.forEach(element => {
|
|
104
154
|
const { name } = element.params || {};
|
|
@@ -130,6 +180,17 @@ export function getFormData(elements, formData) {
|
|
|
130
180
|
filteredData[`${name}_day`] = day !== undefined && day !== null ? day : "";
|
|
131
181
|
filteredData[`${name}_month`] = month !== undefined && month !== null ? month : "";
|
|
132
182
|
filteredData[`${name}_year`] = year !== undefined && year !== null ? year : "";
|
|
183
|
+
// handle fileInput
|
|
184
|
+
} else if (element.element === "fileInput") {
|
|
185
|
+
// fileInput elements are already stored in the store when it was uploaded
|
|
186
|
+
// so we just need to check if the file exists in the dataLayer in the store and add it the filteredData
|
|
187
|
+
const fileData = dataLayer.getFormDataValue(store, siteId, pageUrl, name + "Attachment");
|
|
188
|
+
if (fileData) {
|
|
189
|
+
filteredData[name + "Attachment"] = fileData;
|
|
190
|
+
} else {
|
|
191
|
+
//TODO: Ask Andreas how to handle empty file inputs
|
|
192
|
+
filteredData[name + "Attachment"] = ""; // or handle as needed
|
|
193
|
+
}
|
|
133
194
|
// Handle other elements (e.g., textInput, textArea, datePicker)
|
|
134
195
|
} else {
|
|
135
196
|
filteredData[name] = formData[name] !== undefined && formData[name] !== null ? formData[name] : "";
|
|
@@ -174,6 +174,11 @@ export async function handleFileUpload({ service, store, siteId, pageUrl, elemen
|
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
// β
Success
|
|
177
|
+
// Store the file metadata in the session store
|
|
178
|
+
dataLayer.storePageDataElement(store, siteId, pageUrl, elementName+"Attachment", {
|
|
179
|
+
sha256: response.Data.sha256,
|
|
180
|
+
fileId: response.Data.fileId,
|
|
181
|
+
});
|
|
177
182
|
logger.debug("File upload successful", response.Data);
|
|
178
183
|
logger.info(`File uploaded successfully for element ${elementName} on page ${pageUrl} for site ${siteId}`);
|
|
179
184
|
return {
|
|
@@ -263,6 +263,8 @@ export function validateFormElements(elements, formData, pageUrl) {
|
|
|
263
263
|
formData[`${field.params.name}_day`]]
|
|
264
264
|
.filter(Boolean) // Remove empty values
|
|
265
265
|
.join("-") // Join remaining parts
|
|
266
|
+
: (field.element === "fileInput") // Handle fileInput
|
|
267
|
+
? formData[`${field.params.name}Attachment`] || ""
|
|
266
268
|
: formData[field.params.name] || ""; // Get submitted value
|
|
267
269
|
|
|
268
270
|
//Autocheck: check for "checkboxes", "radios", "select" if `fieldValue` is one of the `field.params.items
|
|
@@ -310,6 +312,8 @@ export function validateFormElements(elements, formData, pageUrl) {
|
|
|
310
312
|
formData[`${conditionalElement.params.name}_day`]]
|
|
311
313
|
.filter(Boolean) // Remove empty values
|
|
312
314
|
.join("-") // Join remaining parts
|
|
315
|
+
: (conditionalElement.element === "fileInput") // Handle fileInput
|
|
316
|
+
? formData[`${conditionalElement.params.name}Attachment`] || ""
|
|
313
317
|
: formData[conditionalElement.params.name] || ""; // Get submitted value
|
|
314
318
|
|
|
315
319
|
//Autocheck: check for "checkboxes", "radios", "select" if `fieldValue` is one of the `field.params.items`
|