datasync-dynamic-form 1.3.6 → 1.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "datasync-dynamic-form",
3
3
  "description": "Datasync Dynamic Form component",
4
- "version": "1.3.6",
4
+ "version": "1.3.7",
5
5
  "main": "dist/DsDynamicForm.js",
6
6
  "module": "dist/DsDynamicForm.js",
7
7
  "types": "dist/types/DsDynamicForm.d.ts",
@@ -1,619 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import React, { Component, useImperativeHandle, forwardRef } from "react";
3
- import Multiselect from 'multiselect-react-dropdown';
4
- import { CTimeStamp, Randomize, SaveDataTierToDatasync, WScrollTo } from "datasync-core";
5
- import { DsBlob } from "datasync-blob";
6
- import { DsPdf } from "datasync-pdf";
7
- // reactstrap components
8
- import { Button, Label, FormGroup, Input, InputGroupText, InputGroup, Row as ReactstrapRow, Col as ReactstrapCol, } from "reactstrap";
9
- import "./flex-grid.css";
10
- const FlexRow = ({ className, ...props }) => (_jsx(ReactstrapRow, { className: ["flex-row", className].filter(Boolean).join(" "), ...props }));
11
- const FlexCol = ({ className, ...props }) => (_jsx(ReactstrapCol, { className: ["flex-col", className].filter(Boolean).join(" "), ...props }));
12
- const globals = {
13
- parameters: {
14
- local: true,
15
- production: false,
16
- use_navigate: false,
17
- save_failed_alert: false,
18
- form_version: "1.0",
19
- form_modified_version: 2
20
- }
21
- };
22
- export class DsDynamicForm extends Component {
23
- constructor(props) {
24
- super(props);
25
- this.componentDidMount = () => {
26
- //Component initialization in edit mode
27
- if (this.props.form) {
28
- this.clearForm();
29
- }
30
- };
31
- /**
32
- * Prototype : updateElement
33
- */
34
- this.updatePageDomElement = (p_pageIndex, p_page_isVisible) => {
35
- let pageObject = document.getElementById(`dsdf_page_${p_pageIndex}`);
36
- if (this.debugging)
37
- console.log(`updatePageDomElement = (${p_pageIndex}, ${p_page_isVisible ? "show" : "hide"})`);
38
- if (!pageObject) {
39
- console.error(`Page element with id 'dsdf_page_${p_pageIndex}' not found`);
40
- return;
41
- }
42
- if (this.debugging)
43
- console.log("pageObject.classList(before)->", pageObject.classList);
44
- if (p_page_isVisible)
45
- pageObject.classList.add("page_visible");
46
- else
47
- pageObject.classList.remove("page_visible");
48
- if (this.debugging)
49
- console.log("pageObject.classList(after)->", pageObject.classList);
50
- };
51
- /**
52
- * Prototype : clearForm
53
- */
54
- this.clearForm = () => {
55
- this.setState({ fieldError: {}, form: { Pages: [] }, captcha1: Randomize(0, 5), captcha2: Randomize(0, 5) }, //Clear forced
56
- () => {
57
- this.setState({ form: this.props.form || { Pages: [] }, fieldError: {} }); //No need to override form property with clearObject2 anymore because data are written outside form.
58
- });
59
- //Real efficient fix
60
- let duplicate_data_tier = (this.props.data_blob && this.props.data_blob.data_tier) ? JSON.parse(JSON.stringify(this.props.data_blob.data_tier)) : {};
61
- //duplicate_data_tier = Object.assign(duplicate_data_tier, (this.props.data_blob && this.props.data_blob.data_tier)?this.props.data_blob.data_tier:{})
62
- this.local_data_blob = { data_tier: {} };
63
- //this.local_data_blob.data_tier = Object.assign({}, duplicate_data_tier);
64
- //Ensure props.foreign_keys is a json object - PMAB on 2025-04-10
65
- if (this.props.foreign_keys && typeof this.props.foreign_keys !== "object")
66
- throw new Error("foreign_keys must be a json object !");
67
- this.local_data_blob.data_tier = Object.assign(this.props.foreign_keys ? this.props.foreign_keys : {}, duplicate_data_tier);
68
- if (this.debugging)
69
- console.log("clearForm->this.local_data_blob.data_tier =>", this.local_data_blob.data_tier);
70
- };
71
- this.getFieldData = (fieldName) => {
72
- /** Return data value form field object */
73
- let nextFieldData = this.local_data_blob.data_tier[fieldName] ? this.local_data_blob.data_tier[fieldName] : "";
74
- return nextFieldData;
75
- };
76
- this.setFieldData = (fieldName, value) => {
77
- try {
78
- if (this.debugging)
79
- console.log("setFieldData:fieldName ->", fieldName, " value ->", value);
80
- let duplicate_data_tier = JSON.parse(JSON.stringify(this.local_data_blob.data_tier));
81
- duplicate_data_tier[fieldName] = value;
82
- this.local_data_blob.data_tier = duplicate_data_tier;
83
- //this.local_data_blob.data_tier[fieldName] = value
84
- }
85
- catch (error) {
86
- alert(error);
87
- }
88
- //onFormChange handler return current form value to caller - PMAB on 2025-02-03
89
- if (this.props.onFormChange)
90
- this.props.onFormChange(this.local_data_blob.data_tier);
91
- };
92
- this.setFieldError = (pFieldObject, value) => {
93
- try {
94
- let nextFieldError = this.state.fieldError || {};
95
- nextFieldError[pFieldObject.name] = value;
96
- this.setState({ fieldError: nextFieldError });
97
- }
98
- catch (e) {
99
- console.error(`Error caught on ${e}`);
100
- }
101
- };
102
- this.getFieldError = (pFieldObject) => {
103
- /** Return data value form field object */
104
- try {
105
- if (this.debugging)
106
- console.log(`getFieldError(${JSON.stringify(pFieldObject)}) -> ${this.state.fieldError}`);
107
- let dbg = (this.state.fieldError && this.state.fieldError[pFieldObject.name]) ? this.state.fieldError[pFieldObject.name] : "";
108
- return `${dbg}`;
109
- }
110
- catch (e) {
111
- console.error(`getFieldError raises -> ${e}`);
112
- return (``);
113
- }
114
- };
115
- this._error_label = (field) => {
116
- return (_jsx("label", { className: "dynamic-form-error", children: this.getFieldError(field) }));
117
- };
118
- this.getFieldLabelTitle = (pFieldObject) => {
119
- return (_jsxs("h6", { id: pFieldObject.name, children: [pFieldObject.title ? pFieldObject.title : pFieldObject.placeholder, (pFieldObject.required && !this.props.read_only) && _jsx("span", { className: "icon-danger", children: "*" })] }));
120
- };
121
- this.getCaptchaFieldLabelTitle = (pFieldObject) => {
122
- return (_jsxs("h6", { id: pFieldObject.name, children: [`${this.state.captcha1} + ${this.state.captcha2}`, pFieldObject.required && _jsx("span", { className: "icon-danger", children: "*" })] }));
123
- };
124
- this.getFieldPrompt = (pFieldObject) => {
125
- return (pFieldObject.placeholder ? pFieldObject.placeholder : pFieldObject.title || "");
126
- };
127
- this._numeric_field_with_add_on = (field, fa_symbol) => {
128
- return (_jsxs(_Fragment, { children: [this.getFieldLabelTitle(field), _jsxs(InputGroup, { className: "border-input", children: [_jsx(Input, { readOnly: this.props.read_only ? this.props.read_only : false, type: field.input_type, value: this.getFieldData(field.name), placeholder: field.placeholder, autoComplete: "on", id: field.name, name: field.name, onChange: (e) => {
129
- e.preventDefault();
130
- this.dynamicInputNumericChangeHandler({ event: e, fieldObject: field });
131
- } }), fa_symbol &&
132
- _jsx("div", { className: "input-group-append", children: _jsx(InputGroupText, { children: _jsx("i", { className: `fa ${fa_symbol}` }) }) })] }), this._error_label(field)] }));
133
- };
134
- this._captcha_field = (field, fa_symbol) => {
135
- return (_jsxs(_Fragment, { children: [this.getCaptchaFieldLabelTitle(field), _jsx(InputGroup, { className: "border-input", children: _jsx(Input, { readOnly: this.props.read_only ? this.props.read_only : false, type: field.input_type, value: this.getFieldData(field.name), placeholder: field.placeholder, autoComplete: "on", id: field.name, name: field.name, onChange: (e) => {
136
- e.preventDefault();
137
- this.dynamicInputNumericChangeHandler({ event: e, fieldObject: field });
138
- } }) }), this._error_label(field)] }));
139
- };
140
- this._text_field = (field) => {
141
- return (_jsxs("div", { children: [this.getFieldLabelTitle(field), _jsx(Input, { readOnly: this.props.read_only ? this.props.read_only : false, type: field.input_type, value: this.getFieldData(field.name), placeholder: field.placeholder, autoComplete: "off", onChange: (e) => {
142
- e.preventDefault();
143
- this.dynamicInputTextChangeHandler({ event: e, fieldObject: field });
144
- } }), this._error_label(field)] }));
145
- };
146
- this._email_field = (field) => {
147
- return (_jsxs("div", { children: [this.getFieldLabelTitle(field), _jsx(Input, { readOnly: this.props.read_only ? this.props.read_only : false, type: field.input_type, value: this.getFieldData(field.name), placeholder: field.placeholder, pattern: "[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,4}$", autoComplete: "on", id: field.name, name: field.name, onChange: (e) => {
148
- e.preventDefault();
149
- this.dynamicInputTextChangeHandler({ event: e, fieldObject: field });
150
- } }), this._error_label(field)] }));
151
- };
152
- this._memo_field = (field) => {
153
- return (_jsxs("div", { children: [this.getFieldLabelTitle(field), _jsx("textarea", { className: "form-control", readOnly: this.props.read_only ? this.props.read_only : false, value: this.getFieldData(field.name), placeholder: field.placeholder, rows: field.rows, onChange: (e) => {
154
- e.preventDefault();
155
- this.dynamicInputTextChangeHandler({ event: e, fieldObject: field });
156
- } }), this._error_label(field)] }));
157
- };
158
- this._combo_field = (field) => {
159
- return (_jsxs("div", { children: [this.getFieldLabelTitle(field), _jsx(Multiselect, { showArrow: true, options: field.combo_list || [], isObject: false, displayValue: "key", selectedValues: this.getFieldData(field.name) ? this.getFieldData(field.name).split(";") : [], placeholder: field.placeholder, emptyRecordMsg: "", onSelect: (selectedList, selectedItem) => { this.setFieldData(field.name, selectedList.join(";")); }, onRemove: (selectedList, selectedItem) => { this.setFieldData(field.name, selectedList.join(";")); }, disable: this.props.read_only, singleSelect: true }), this._error_label(field)] }));
160
- };
161
- this._multi_field = (field) => {
162
- return (_jsxs("div", { children: [this.getFieldLabelTitle(field), _jsx(Multiselect, { showArrow: true, options: field.combo_list || [], isObject: false, displayValue: "key", selectedValues: this.getFieldData(field.name) ? this.getFieldData(field.name).split(";") : [], placeholder: field.placeholder, emptyRecordMsg: "", onSelect: (selectedList, selectedItem) => { this.setFieldData(field.name, selectedList.join(";")); }, onRemove: (selectedList, selectedItem) => { this.setFieldData(field.name, selectedList.join(";")); }, disable: this.props.read_only, singleSelect: false }), this._error_label(field)] }));
163
- };
164
- this._date_field = (field) => {
165
- return (_jsxs("div", { className: "date-div", children: [this.getFieldLabelTitle(field), _jsxs("div", { className: "date-day-month-year-container-div", children: [_jsx("div", { className: "date-day-div", children: _jsx(Multiselect, { showArrow: true, options: ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31"], isObject: false, displayValue: "key", selectedValues: this.getFieldData(field.name_hour || "") ? this.getFieldData(field.name_hour || "").split(";") : [], placeholder: field.placeholder, emptyRecordMsg: "", onSelect: (selectedList, selectedItem) => { this.handle_date_picker({ fieldObject: field, sub_field_name: field.name_day || "", value: selectedList.join(";") }); }, onRemove: (selectedList, selectedItem) => { this.handle_date_picker({ fieldObject: field, sub_field_name: field.name_day || "", value: selectedList.join(";") }); }, disable: this.props.read_only, singleSelect: true }) }), _jsx("div", { className: "date-month-div", children: _jsx(Multiselect, { showArrow: false, options: ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"], isObject: false, displayValue: "key", selectedValues: this.getFieldData(field.name_min || "") ? this.getFieldData(field.name_min || "").split(";") : [], placeholder: field.placeholder, emptyRecordMsg: "", onSelect: (selectedList, selectedItem) => { this.handle_date_picker({ fieldObject: field, sub_field_name: field.name_month || "", value: selectedList.join(";") }); }, onRemove: (selectedList, selectedItem) => { this.handle_date_picker({ fieldObject: field, sub_field_name: field.name_month || "", value: selectedList.join(";") }); }, disable: this.props.read_only, singleSelect: true }) }), _jsx("div", { className: "date-year-div", children: _jsx(Multiselect, { showArrow: false, options: ["2025", "2026", "2027", "2028", "2030"], isObject: false, displayValue: "key", selectedValues: this.getFieldData(field.name_min || "") ? this.getFieldData(field.name_min || "").split(";") : [], placeholder: field.placeholder, emptyRecordMsg: "", onSelect: (selectedList, selectedItem) => { this.handle_date_picker({ fieldObject: field, sub_field_name: field.name_year || "", value: selectedList.join(";") }); }, onRemove: (selectedList, selectedItem) => { this.handle_date_picker({ fieldObject: field, sub_field_name: field.name_year || "", value: selectedList.join(";") }); }, disable: this.props.read_only, singleSelect: true }) })] }), this._error_label(field)] }));
166
- };
167
- this._time_field = (field) => {
168
- return (_jsxs("div", { className: "time-div", children: [this.getFieldLabelTitle(field), _jsxs("div", { className: "time-hour-and-min-container-div", children: [_jsx("div", { className: "time-hour-div", children: _jsx(Multiselect, { showArrow: true, options: ["07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22"], isObject: false, displayValue: "key", selectedValues: this.getFieldData(field.name_hour || "") ? this.getFieldData(field.name_hour || "").split(";") : [], placeholder: field.placeholder, emptyRecordMsg: "", onSelect: (selectedList, selectedItem) => { this.handle_time_picker({ fieldObject: field, sub_field_name: field.name_hour || "", value: selectedList.join(";") }); }, onRemove: (selectedList, selectedItem) => { this.handle_time_picker({ fieldObject: field, sub_field_name: field.name_hour || "", value: selectedList.join(";") }); }, disable: this.props.read_only, singleSelect: true }) }), _jsx("div", { className: "time-min-div", children: _jsx(Multiselect, { showArrow: false, options: ["00", "15", "20", "25", "30", "35", "40", "45", "50", "55"], isObject: false, displayValue: "key", selectedValues: this.getFieldData(field.name_min || "") ? this.getFieldData(field.name_min || "").split(";") : [], placeholder: field.placeholder, emptyRecordMsg: "", onSelect: (selectedList, selectedItem) => { this.handle_time_picker({ fieldObject: field, sub_field_name: field.name_min || "", value: selectedList.join(";") }); }, onRemove: (selectedList, selectedItem) => { this.handle_time_picker({ fieldObject: field, sub_field_name: field.name_min || "", value: selectedList.join(";") }); }, disable: this.props.read_only, singleSelect: true }) })] }), this._error_label(field)] }));
169
- };
170
- this.saveFormToDatasyncProcess = () => {
171
- //Everything sounds ok in Form, Go ahead
172
- let hasDataGuid = (this.props.datasync_object && this.props.datasync_object.data_guid) ? true : false;
173
- SaveDataTierToDatasync(this.props.datasync_url || "", hasDataGuid ? this.props.datasync_object.data_guid : null, //data_guid
174
- this.local_data_blob, //p_o_data_blob,
175
- this.props.company_guid || "", //p_s_company_guid,
176
- this.props.table_guid || "", //p_s_table_guid,
177
- hasDataGuid ? this.props.datasync_object.createstamp : CTimeStamp(), //p_dt_createstamp,
178
- hasDataGuid ? CTimeStamp() : undefined, //p_dt_updatestamp,
179
- undefined, //p_dt_deletestamp,
180
- this.onFormSavedLocalHandler, this.onFormUpdatedLocalHandler, this.onFormFailedLocalHandler, null);
181
- };
182
- /** Form Handlers */
183
- this.onClickSubmitFormHandler = async (event) => {
184
- try {
185
- //Trigger handler as user click submit button in order to animate checking + saving progress bar.
186
- if (this.props.onBeforeFormSubmit)
187
- this.props.onBeforeFormSubmit(this.local_data_blob);
188
- if (event)
189
- event.preventDefault();
190
- //Force all fields check
191
- let canSubmit = true;
192
- let firstErrFieldName = null;
193
- let iPage = 0;
194
- while (iPage < this.state.form.Pages.length) {
195
- let iRow = 0;
196
- while (iRow < this.state.form.Pages[iPage].Rows.length) {
197
- let iCol = 0;
198
- while (iCol < this.state.form.Pages[iPage].Rows[iRow].Cols.length) {
199
- let ii = 0;
200
- while (ii < this.state.form.Pages[iPage].Rows[iRow].Cols[iCol].Fields.length) {
201
- const field = this.state.form.Pages[iPage].Rows[iRow].Cols[iCol].Fields[ii];
202
- const isValid = this.checkValidation(field);
203
- if (!isValid && firstErrFieldName === null) {
204
- firstErrFieldName = field.name;
205
- }
206
- canSubmit = canSubmit && isValid;
207
- ii++;
208
- }
209
- iCol++;
210
- }
211
- iRow++;
212
- }
213
- iPage++;
214
- }
215
- if (!canSubmit) {
216
- // Scroll to the first field with error only on submit
217
- if (firstErrFieldName) {
218
- if (this.debugging)
219
- console.log("WScrollTo invoked :-)");
220
- WScrollTo(firstErrFieldName);
221
- }
222
- let err_message = "Le formulaire comporte des erreurs !";
223
- if (this.props.onFormFailed)
224
- this.props.onFormFailed(err_message);
225
- else
226
- alert(`${err_message}`);
227
- return false;
228
- }
229
- //Invoke onFormSubmit props
230
- if (this.props.onFormSubmit) {
231
- if (this.debugging)
232
- alert("onFormSubmit => filter log with AsyncDebug:: prefixe");
233
- //If props function return false then cancel form submit and do not save !
234
- this.props.onFormSubmit(this.local_data_blob);
235
- }
236
- else {
237
- //Call save anyway
238
- this.saveFormToDatasyncProcess();
239
- }
240
- return true;
241
- }
242
- catch (error) {
243
- console.error(`onClickSubmitFormHandler raises "${error}"`);
244
- return false;
245
- }
246
- };
247
- this.checkCurrentPage = async (event) => {
248
- try {
249
- /*Trigger typically called from external to check curetn page fields.
250
- returns true when all fields are correct. User is then allowed to pursue to next page*/
251
- if (event)
252
- event.preventDefault();
253
- //Force all fields check
254
- let canSubmit = true;
255
- let firstErrFieldName = null;
256
- let iPage = this.props.active_page || 0; //Process only current page
257
- let iRow = 0;
258
- while (iRow < this.state.form.Pages[iPage].Rows.length) {
259
- let iCol = 0;
260
- while (iCol < this.state.form.Pages[iPage].Rows[iRow].Cols.length) {
261
- let ii = 0;
262
- while (ii < this.state.form.Pages[iPage].Rows[iRow].Cols[iCol].Fields.length) {
263
- const field = this.state.form.Pages[iPage].Rows[iRow].Cols[iCol].Fields[ii];
264
- const isValid = this.checkValidation(field);
265
- if (!isValid && firstErrFieldName === null) {
266
- firstErrFieldName = field.name;
267
- }
268
- canSubmit = canSubmit && isValid;
269
- ii++;
270
- }
271
- iCol++;
272
- }
273
- iRow++;
274
- }
275
- if (!canSubmit) {
276
- let err_message = `La page ${iPage} de formulaire comporte des erreurs !`;
277
- if (this.props.onFormFailed)
278
- this.props.onFormFailed(err_message);
279
- else
280
- console.error(`checkCurrentPage ${iPage} raises "${err_message}"`);
281
- return false;
282
- }
283
- return canSubmit;
284
- }
285
- catch (error) {
286
- console.error(`checkCurrentPage raises "${error}"`);
287
- return false;
288
- }
289
- };
290
- this.onFormSavedLocalHandler = (blob) => {
291
- if (this.props.onFormSaved)
292
- this.props.onFormSaved(blob);
293
- else
294
- console.error("DsDynamicForm.onFormSaved props is not defined !");
295
- //clear form
296
- if (this.props.clearOnSave)
297
- this.clearForm();
298
- //Call onTerminated if set by user
299
- if (this.props.onTerminated)
300
- this.props.onTerminated();
301
- };
302
- this.onFormUpdatedLocalHandler = (blob) => {
303
- try {
304
- if (this.props.onFormUpdated)
305
- this.props.onFormUpdated(blob);
306
- else
307
- console.error("DsDynamicForm.onFormUpdated props is not defined !");
308
- //clear form
309
- if (this.props.clearOnUpdate)
310
- this.clearForm();
311
- //Call onTerminated if set by user
312
- if (this.props.onTerminated)
313
- this.props.onTerminated();
314
- }
315
- catch (error) {
316
- console.error(`onFormUpdatedLocalHandler raises "${error}"`);
317
- }
318
- };
319
- this.onFormFailedLocalHandler = (err) => {
320
- if (this.props.onFormFailed)
321
- this.props.onFormFailed(err);
322
- else {
323
- console.error("DsDynamicForm.onFormFailed props is not defined !");
324
- alert("Erreur de sauvegarde !!!");
325
- }
326
- };
327
- this.onBlobErrorLocalHandler = (errorObject) => {
328
- if (this.props.onBlobErrorHandler)
329
- this.props.onBlobErrorHandler(errorObject);
330
- else {
331
- console.error("DsDynamicForm.onBlobErrorHandler props is not defined !");
332
- alert(errorObject.message);
333
- }
334
- };
335
- this.checkValidation = (pFieldObject) => {
336
- /** Get field properties */
337
- let min = pFieldObject.min_length || 0;
338
- let max = pFieldObject.max_length || 0;
339
- let fieldValue = this.getFieldData(pFieldObject.name);
340
- let nextErrors = [];
341
- /** Check basic field validity except combo and radio */
342
- if ((pFieldObject.required) && (fieldValue.trim().length <= 0))
343
- nextErrors.push(`obligatoire`);
344
- if ((min > 0) && (pFieldObject.required) && (fieldValue.trim().length < min))
345
- nextErrors.push(`trop court.`);
346
- //Captcha check
347
- if (pFieldObject.input_type.toLowerCase() == "captcha") {
348
- if (parseInt(fieldValue) !== ((this.state.captcha1 || 0) + (this.state.captcha2 || 0)))
349
- nextErrors.push(`calcul faux !`);
350
- }
351
- //Email check
352
- if (pFieldObject.input_type.toLowerCase() == "email") {
353
- if (!fieldValue.match(/^([\w.%+-]+)@([\w-]+\.)+([\w]{2,})$/i))
354
- nextErrors.push(`Format de mail incorrect !`);
355
- }
356
- //Date check
357
- if (pFieldObject.input_type.toLowerCase() == "date") {
358
- if (!fieldValue.match(/^(\d{2}\/\d{2}\/\d{4})$/i))
359
- nextErrors.push(`Format de date incorrect !`);
360
- }
361
- if ((max > 0) && (fieldValue.trim().length > max))
362
- nextErrors.push(`trop long, ${fieldValue.trim().length - max} caractères en trop.`);
363
- if (this.debugging) {
364
- console.log(`pFieldObject.name->`, JSON.stringify(pFieldObject.name));
365
- console.log(`nextErrors->`, JSON.stringify(nextErrors));
366
- console.log(`-----------`);
367
- }
368
- //update error field
369
- this.setFieldError(pFieldObject, nextErrors.join("/"));
370
- //Return validation predicate
371
- return (nextErrors.length === 0); //returns true if no error occurs
372
- };
373
- this.dynamicInputTextChangeHandler = (eventObject) => {
374
- if (eventObject && eventObject.event)
375
- eventObject.event.preventDefault();
376
- this.setFieldData(eventObject.fieldObject.name, eventObject.event.target.value);
377
- //Validate field
378
- this.checkValidation(eventObject.fieldObject);
379
- };
380
- this.dynamicInputNumericChangeHandler = (eventObject) => {
381
- if (eventObject && eventObject.event)
382
- eventObject.event.preventDefault();
383
- if (eventObject.event.target.value.length == 0 ||
384
- !isNaN(Number(eventObject.event.target.value)) &&
385
- !isNaN(parseFloat(eventObject.event.target.value)))
386
- this.setFieldData(eventObject.fieldObject.name, eventObject.event.target.value);
387
- else {
388
- if (this.debugging)
389
- console.error(`Value rejected -> ${eventObject.event.target.value}`);
390
- }
391
- this.checkValidation(eventObject.fieldObject);
392
- };
393
- this.convertDate = (p_o_day_month_year) => {
394
- function pad(s) { return (s < 10) ? '0' + s : s.toString(); }
395
- return {
396
- asString: [pad(p_o_day_month_year.day), pad(p_o_day_month_year.month), p_o_day_month_year.year].join('/'),
397
- asDate: {
398
- day: p_o_day_month_year.day,
399
- month: p_o_day_month_year.month,
400
- year: p_o_day_month_year.year
401
- },
402
- };
403
- };
404
- this.OLD_handle_date_picker = (eventObject) => {
405
- let p_oDate = eventObject.selection;
406
- //Convert date picker string as day month year object
407
- let dateConvertedObject = this.convertDate({ day: p_oDate.getDate(), month: 1 + p_oDate.getMonth(), year: p_oDate.getFullYear() });
408
- this.setFieldData(eventObject.fieldObject.name, dateConvertedObject.asString);
409
- this.setFieldData(eventObject.fieldObject.name_day || "", dateConvertedObject.asDate.day.toString());
410
- this.setFieldData(eventObject.fieldObject.name_month || "", dateConvertedObject.asDate.month.toString());
411
- this.setFieldData(eventObject.fieldObject.name_year || "", dateConvertedObject.asDate.year.toString());
412
- //Validate field
413
- this.checkValidation(eventObject.fieldObject);
414
- };
415
- this.handle_date_picker = (eventObject) => {
416
- //Set date
417
- this.setFieldData(eventObject.sub_field_name, eventObject.value);
418
- //update full date field
419
- this.setFieldData(eventObject.fieldObject.name, this.getFieldData(eventObject.fieldObject.name_day || "")
420
- + "/" + this.getFieldData(eventObject.fieldObject.name_month || "")
421
- + "/" + this.getFieldData(eventObject.fieldObject.name_year || ""));
422
- //Validate field
423
- this.checkValidation(eventObject.fieldObject);
424
- };
425
- this.handle_time_picker = (eventObject) => {
426
- //Set hour or min
427
- this.setFieldData(eventObject.sub_field_name, eventObject.value);
428
- //update fulll time field
429
- this.setFieldData(eventObject.fieldObject.name, this.getFieldData(eventObject.fieldObject.name_hour || "") + ":" + this.getFieldData(eventObject.fieldObject.name_min || ""));
430
- //Validate field
431
- this.checkValidation(eventObject.fieldObject);
432
- };
433
- this._rowRendering = (row) => {
434
- try {
435
- return (_jsx(FlexRow, { children: row.Cols.map((col, ii) => {
436
- return (this._colRendering(col));
437
- }) }));
438
- }
439
- catch (err) {
440
- return (_jsxs(FlexCol, { children: ["Error ", err.message] }));
441
- }
442
- };
443
- this._colRendering = (col) => {
444
- try {
445
- return (_jsx(FlexCol, { id: `${col.Id ? col.Id : ''}`, children: col.Fields.map((field, ii) => {
446
- return this._fieldRendering(field, ii);
447
- }) }));
448
- }
449
- catch (err) {
450
- return (_jsxs(FlexCol, { children: ["Error ", err.message] }));
451
- }
452
- };
453
- this._fieldRendering = (field, ii) => {
454
- try {
455
- //Do not display field if empty in read only mode
456
- if (this.props.read_only &&
457
- ((this.getFieldData(field.name) == null) || (!this.getFieldData(field.name)) || (this.getFieldData(field.name).trim().length == 0)))
458
- return (_jsx(_Fragment, {}));
459
- //Do not display hidden field
460
- if (field.hidden && !this.props.show_hidden)
461
- return (_jsx(_Fragment, {}));
462
- switch (field.input_type.toLowerCase()) {
463
- /** Dynamic fields */
464
- case "checkbox-DISABLED":
465
- return (_jsx(FormGroup, { check: true, children: _jsxs(Label, { check: true, children: [_jsx(Input, { defaultValue: "", type: "checkbox", readOnly: this.props.read_only ? this.props.read_only : false }), field.placeholder, _jsx("span", { className: "form-check-sign" })] }) }));
466
- case "checkbox":
467
- /* Checkbox is override with combobox */
468
- return (_jsxs("div", { children: [this.getFieldLabelTitle(field), _jsx(Multiselect, { showArrow: true, options: ["Oui", "Non"], isObject: false, displayValue: "key", selectedValues: this.getFieldData(field.name) ? this.getFieldData(field.name).split(";") : [], placeholder: field.placeholder, emptyRecordMsg: "", onSelect: (selectedList, selectedItem) => { this.setFieldData(field.name, selectedList.join(";")); }, onRemove: (selectedList, selectedItem) => { this.setFieldData(field.name, selectedList.join(";")); }, disable: this.props.read_only, singleSelect: true }), this._error_label(field)] }));
469
- case "blob":
470
- return (_jsxs(_Fragment, { children: [this.getFieldLabelTitle(field), _jsxs("div", { className: "col-md-10", children: [_jsx(DsBlob, { item_id: field.name, readOnly: this.props.read_only ? this.props.read_only : false, Caption: `${this.getFieldPrompt(field)} ...`, data: this.getFieldData(field.name), uploadPicture: (UploadFile) => { this.setFieldData(field.name, UploadFile.data); this.checkValidation(field); }, pictureStyle: "pic", buttonStyle: "btn btn-secondary", width: field.width ? field.width : undefined, height: field.height ? field.height : undefined, maxWidth: field.max_width ? field.max_width : undefined, maxHeight: field.max_height ? field.max_height : undefined, maxKBytes: field.max_kbytes ? field.max_kbytes : undefined, reduceImage: field.reduceImage ? field.reduceImage : undefined, onErrorHandler: (errorObject) => { this.onBlobErrorLocalHandler(errorObject); }, debugging: this.debugging }), this._error_label(field)] })] }));
471
- case "pdf":
472
- return (_jsxs(_Fragment, { children: [this.getFieldLabelTitle(field), _jsxs("div", { className: "col-md-10", children: [_jsx(DsPdf, { item_id: field.name, readOnly: this.props.read_only ? this.props.read_only : false, Caption: `${this.getFieldPrompt(field)} ...`, data: this.getFieldData(field.name), uploadPdf: (UploadFile) => { this.setFieldData(field.name, UploadFile.data); this.checkValidation(field); }, pictureStyle: "pic", buttonStyle: "btn btn-secondary" }), this._error_label(field)] })] }));
473
- case "email":
474
- return this._email_field(field);
475
- case "text":
476
- return this._text_field(field);
477
- case "memo":
478
- return this._memo_field(field);
479
- case "combo":
480
- case "radio":
481
- return this._combo_field(field);
482
- case "multi":
483
- return this._multi_field(field);
484
- case "date":
485
- //set day month and year fields
486
- if (!field.name_day)
487
- field.name_day = "__day";
488
- if (!field.name_month)
489
- field.name_month = "__month";
490
- if (!field.name_year)
491
- field.name_year = "__year";
492
- return this._date_field(field);
493
- case "time":
494
- //set day month and year fields
495
- if (!field.name_hour)
496
- field.name_hour = "__hour";
497
- if (!field.name_min)
498
- field.name_min = "__min";
499
- return this._time_field(field);
500
- case "numeric":
501
- return this._numeric_field_with_add_on(field, "*");
502
- case "amount":
503
- return this._numeric_field_with_add_on(field, "fa-euro");
504
- case "percent":
505
- return this._numeric_field_with_add_on(field, "%");
506
- case "captcha":
507
- return this._captcha_field(field);
508
- default:
509
- console.error(`${field.input_type.toLowerCase()} type is incorrect !!!`);
510
- return (_jsx(_Fragment, {}));
511
- }
512
- }
513
- catch (error) {
514
- console.error(`_fieldRendering raises "${error}"`);
515
- return (_jsx(_Fragment, {}));
516
- }
517
- };
518
- this._cancelButton = () => {
519
- let buttonIsHidden = (this.props.read_only || (this.props.buttons_options && this.props.buttons_options.cancel_button_hidden)) ? true : false;
520
- let buttonCaption = (this.props.buttons_options && this.props.buttons_options.cancel_button_caption) ? this.props.buttons_options.cancel_button_caption : "Annuler";
521
- if (buttonIsHidden)
522
- return (_jsx(_Fragment, {}));
523
- else {
524
- return (_jsx(FlexCol, { children: _jsx(Button, { id: "dsdf_clear_button", block: true, className: "btn-round", color: "danger", outline: true, type: "reset", onClick: () => { this.clearForm(); }, children: buttonCaption }) }));
525
- }
526
- };
527
- this._submitButton = () => {
528
- let buttonIsHidden = (this.props.read_only || (this.props.buttons_options && this.props.buttons_options.submit_button_hidden)) ? true : false;
529
- let buttonCaption = (this.props.buttons_options && this.props.buttons_options.submit_button_caption) ? this.props.buttons_options.submit_button_caption : "Soumettre";
530
- if (buttonIsHidden)
531
- return (_jsx(_Fragment, {}));
532
- else {
533
- return (_jsx(FlexCol, { children: _jsx(Button, { id: "dsdf_submit_button", block: true, className: "btn-round", color: "danger", outline: true, type: "submit", onClick: () => { this.onClickSubmitFormHandler(); }, children: buttonCaption }) }));
534
- }
535
- };
536
- this.render = () => {
537
- return (_jsxs(_Fragment, { children: [_jsx(_Fragment, {}), !this.state.form &&
538
- _jsx("div", { children: _jsx("h1", { children: "Form loading..." }) }), !(this.state.form &&
539
- this.state.form.Pages) &&
540
- _jsx("div", { children: _jsx("h1", { children: "Form Missing Pages !!!" }) }), _jsx("form", { children: this.state.form &&
541
- this.state.form.Pages &&
542
- this.state.form.Pages.map((page, pageIndex) => {
543
- if (this.debugging)
544
- console.log(`Rendering page ${pageIndex}:`, page);
545
- return (_jsx("div", { id: `dsdf_page_${pageIndex}`, className: `form-page ${((pageIndex == this.state.active_page) || this.props.read_only) ? "page_visible" : ""}`, children: page.Rows.map((row, rowIndex) => {
546
- return (_jsx("div", { children: this._rowRendering(row) }, rowIndex));
547
- }) }, pageIndex));
548
- }) }), _jsxs(FlexRow, { id: "dsdf_buttons_container", className: "buttons-row", children: [this._cancelButton(), this._submitButton(), this.props.custom_button_caption &&
549
- _jsx(FlexCol, { children: _jsx(Button, { id: "dsdf_custom_button", block: true, className: "btn-round", color: "primary", type: "submit", onClick: (e) => { if (this.props.custom_button_handler)
550
- this.props.custom_button_handler(this.state.form);
551
- else
552
- console.error("custom_button_handler unset !"); }, children: this.props.custom_button_caption }) }), this.props.custom_button_caption2 &&
553
- _jsx(FlexCol, { children: _jsx(Button, { id: "dsdf_custom_button2", block: true, className: "btn-round", color: "primary", type: "submit", onClick: (e) => { if (this.props.custom_button_handler2)
554
- this.props.custom_button_handler2(this.state.form);
555
- else
556
- console.error("custom_button_handler2 unset !"); }, children: this.props.custom_button_caption2 }) })] })] }));
557
- };
558
- this.state = { form: { Pages: [] }, active_page: 0 };
559
- this.local_data_blob = { data_tier: {} };
560
- }
561
- // Helper method to get debugging value from props with default fallback
562
- get debugging() {
563
- return this.props.debugging ?? false;
564
- }
565
- componentDidUpdate(prevProps) {
566
- // Typical usage (don't forget to compare props):
567
- if (this.props.form !== prevProps.form) {
568
- //Lookup field props has changed
569
- this.clearForm();
570
- }
571
- if (this.props.data_blob !== prevProps.data_blob) {
572
- //Lookup field props has changed
573
- this.clearForm();
574
- }
575
- if (this.props.active_page != prevProps.active_page) {
576
- //Page is about to change, then triger onPageChanging Handler
577
- if (this.props.onPageChanging)
578
- this.props.onPageChanging({ "active_page": prevProps.active_page ?? 0, "next_page": this.props.active_page ?? 0, "last_page": this.state.form.Pages.length - 1 });
579
- if (this.debugging)
580
- console.log("active_page has changed !");
581
- try {
582
- if (prevProps.active_page !== undefined) {
583
- this.updatePageDomElement(prevProps.active_page, false);
584
- }
585
- }
586
- catch (error) {
587
- this.updatePageDomElement(0, false);
588
- }
589
- try {
590
- if (this.props.active_page !== undefined) {
591
- this.updatePageDomElement(this.props.active_page, true);
592
- }
593
- }
594
- catch (error) {
595
- this.updatePageDomElement(1, true);
596
- }
597
- }
598
- }
599
- }
600
- // ForwardRef wrapper that exposes only the desired methods
601
- export const DsDynamicFormForwardRef = forwardRef((props, ref) => {
602
- const innerRef = React.useRef(null);
603
- useImperativeHandle(ref, () => ({
604
- clearForm: () => {
605
- innerRef.current?.clearForm();
606
- },
607
- onClickSubmitFormHandler: (event) => {
608
- return innerRef.current
609
- ? innerRef.current.onClickSubmitFormHandler(event)
610
- : Promise.resolve(false);
611
- },
612
- checkCurrentPage: (event) => {
613
- return innerRef.current
614
- ? innerRef.current.checkCurrentPage(event)
615
- : Promise.resolve(false);
616
- },
617
- }));
618
- return (_jsx(DsDynamicForm, { ...props, ref: innerRef }));
619
- });
@@ -1,51 +0,0 @@
1
- .flex-row {
2
- display: flex;
3
- flex-wrap: wrap;
4
- gap: 10px;
5
- margin-bottom: 10px;
6
- /* Make all .flex-col in a flex-row equal height */
7
- align-items: stretch;
8
- /* For multi-line rows, ensure lines use full vertical space */
9
- align-content: stretch;
10
- }
11
-
12
- .flex-col {
13
- flex: 1 1 0;
14
- /* Fill available vertical space of its flex line */
15
- height: 100%;
16
- min-height: 100px;
17
- border: 3px solid;
18
- border-radius: 8px;
19
- display: flex;
20
- align-items: center;
21
- justify-content: center;
22
- }
23
-
24
- .box-next {
25
- flex: 1 1 0;
26
- display: flex;
27
- flex-wrap: wrap;
28
- align-content: center;
29
- }
30
-
31
- /* Media query pour 600px : diviser par 2 le nombre de div par ligne */
32
- @media (max-width: 600px) {
33
- .box {
34
- flex: 1 1 calc(50% - 5px);
35
- max-width: calc(50% - 5px);
36
- }
37
-
38
- /* Si une div est seule sur sa ligne, elle prend 100% */
39
- .box:only-child {
40
- flex: 1 1 100%;
41
- max-width: 100%;
42
- }
43
- }
44
-
45
- /* Media query pour 300px : toutes les divs à 100% de la largeur */
46
- @media (max-width: 300px) {
47
- .box {
48
- flex: 1 1 100%;
49
- max-width: 100%;
50
- }
51
- }
package/dist/index.js DELETED
@@ -1 +0,0 @@
1
- export { DsDynamicForm } from './components/DsDynamicForm';
@@ -1,191 +0,0 @@
1
- import React, { Component, ChangeEvent } from "react";
2
- import "./flex-grid.css";
3
- interface Field {
4
- name: string;
5
- input_type: string;
6
- placeholder?: string;
7
- title?: string;
8
- required?: boolean;
9
- min_length?: number;
10
- max_length?: number;
11
- combo_list?: string[];
12
- rows?: number;
13
- hidden?: boolean;
14
- width?: number;
15
- height?: number;
16
- max_width?: number;
17
- max_height?: number;
18
- max_kbytes?: number;
19
- reduceImage?: boolean;
20
- name_day?: string;
21
- name_month?: string;
22
- name_year?: string;
23
- name_hour?: string;
24
- name_min?: string;
25
- }
26
- interface Col {
27
- Id: string;
28
- Fields: Field[];
29
- }
30
- interface Row {
31
- Cols: Col[];
32
- }
33
- interface Page {
34
- Rows: Row[];
35
- }
36
- interface Form {
37
- Pages: Page[];
38
- }
39
- interface DataTier {
40
- [key: string]: any;
41
- }
42
- interface DataBlob {
43
- data_tier: DataTier;
44
- }
45
- interface DatasyncObject {
46
- data_guid: string;
47
- createstamp: string;
48
- }
49
- interface ButtonsOptions {
50
- cancel_button_hidden?: boolean;
51
- cancel_button_caption?: string;
52
- submit_button_hidden?: boolean;
53
- submit_button_caption?: string;
54
- }
55
- interface EventObject {
56
- event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>;
57
- fieldObject: Field;
58
- }
59
- interface DatePickerEventObject {
60
- fieldObject: Field;
61
- sub_field_name: string;
62
- value: string;
63
- }
64
- interface TimePickerEventObject {
65
- fieldObject: Field;
66
- sub_field_name: string;
67
- value: string;
68
- }
69
- interface DateObject {
70
- day: number;
71
- month: number;
72
- year: number;
73
- }
74
- interface ConvertedDate {
75
- asString: string;
76
- asDate: DateObject;
77
- }
78
- interface DsDynamicFormProps {
79
- data_blob?: DataBlob;
80
- form?: Form;
81
- read_only?: boolean;
82
- foreign_keys?: DataTier;
83
- onFormChange?: (data: DataTier) => void;
84
- onBeforeFormSubmit?: (data: DataBlob) => void;
85
- onFormSubmit?: (data: DataBlob) => void;
86
- onFormSaved?: (blob: DataBlob) => void;
87
- onFormUpdated?: (blob: DataBlob) => void;
88
- onFormFailed?: (error: string) => void;
89
- onPageChanging?: (pageInfo: {
90
- active_page: number;
91
- next_page: number;
92
- last_page: number;
93
- }) => void;
94
- onBlobErrorHandler?: (errorObject: ErrorObject) => void;
95
- clearOnSave?: boolean;
96
- clearOnUpdate?: boolean;
97
- onTerminated?: () => void;
98
- datasync_url?: string;
99
- datasync_object?: DatasyncObject;
100
- company_guid?: string;
101
- table_guid?: string;
102
- buttons_options?: ButtonsOptions;
103
- custom_button_caption?: string;
104
- custom_button_handler?: (form: Form) => void;
105
- custom_button_caption2?: string;
106
- custom_button_handler2?: (form: Form) => void;
107
- show_hidden?: boolean;
108
- active_page?: number;
109
- col_xs?: number | string;
110
- col_sm?: number | string;
111
- col_md?: number | string;
112
- col_lg?: number | string;
113
- debugging?: boolean;
114
- }
115
- interface DsDynamicFormState {
116
- form: Form;
117
- fieldError?: {
118
- [key: string]: string;
119
- };
120
- captcha1?: number;
121
- captcha2?: number;
122
- active_page?: number;
123
- }
124
- interface ErrorObject {
125
- error_code: string;
126
- error_definition: string;
127
- message: string;
128
- }
129
- export declare class DsDynamicForm extends Component<DsDynamicFormProps, DsDynamicFormState> {
130
- private local_data_blob;
131
- constructor(props: DsDynamicFormProps);
132
- private get debugging();
133
- componentDidMount: () => void;
134
- componentDidUpdate(prevProps: DsDynamicFormProps): void;
135
- /**
136
- * Prototype : updateElement
137
- */
138
- updatePageDomElement: (p_pageIndex: number, p_page_isVisible: boolean) => void;
139
- /**
140
- * Prototype : clearForm
141
- */
142
- clearForm: () => void;
143
- getFieldData: (fieldName: string) => string;
144
- setFieldData: (fieldName: string, value: string) => void;
145
- setFieldError: (pFieldObject: Field, value: string) => void;
146
- getFieldError: (pFieldObject: Field) => string;
147
- _error_label: (field: Field) => JSX.Element;
148
- getFieldLabelTitle: (pFieldObject: Field) => JSX.Element;
149
- getCaptchaFieldLabelTitle: (pFieldObject: Field) => JSX.Element;
150
- getFieldPrompt: (pFieldObject: Field) => string;
151
- _numeric_field_with_add_on: (field: Field, fa_symbol: string) => JSX.Element;
152
- _captcha_field: (field: Field, fa_symbol?: string) => JSX.Element;
153
- _text_field: (field: Field) => JSX.Element;
154
- _email_field: (field: Field) => JSX.Element;
155
- _memo_field: (field: Field) => JSX.Element;
156
- _combo_field: (field: Field) => JSX.Element;
157
- _multi_field: (field: Field) => JSX.Element;
158
- _date_field: (field: Field) => JSX.Element;
159
- _time_field: (field: Field) => JSX.Element;
160
- saveFormToDatasyncProcess: () => void;
161
- /** Form Handlers */
162
- onClickSubmitFormHandler: (event?: React.MouseEvent<HTMLButtonElement>) => Promise<boolean>;
163
- checkCurrentPage: (event?: React.MouseEvent<HTMLButtonElement>) => Promise<boolean>;
164
- onFormSavedLocalHandler: (blob: DataBlob) => void;
165
- onFormUpdatedLocalHandler: (blob: DataBlob) => void;
166
- onFormFailedLocalHandler: (err: string) => void;
167
- onBlobErrorLocalHandler: (errorObject: ErrorObject) => void;
168
- checkValidation: (pFieldObject: Field) => boolean;
169
- dynamicInputTextChangeHandler: (eventObject: EventObject) => void;
170
- dynamicInputNumericChangeHandler: (eventObject: EventObject) => void;
171
- convertDate: (p_o_day_month_year: DateObject) => ConvertedDate;
172
- OLD_handle_date_picker: (eventObject: {
173
- selection: Date;
174
- fieldObject: Field;
175
- }) => void;
176
- handle_date_picker: (eventObject: DatePickerEventObject) => void;
177
- handle_time_picker: (eventObject: TimePickerEventObject) => void;
178
- _rowRendering: (row: Row) => JSX.Element;
179
- _colRendering: (col: Col) => JSX.Element;
180
- _fieldRendering: (field: Field, ii: number) => JSX.Element;
181
- _cancelButton: () => JSX.Element;
182
- _submitButton: () => JSX.Element;
183
- render: () => JSX.Element;
184
- }
185
- export type DsDynamicFormRef = {
186
- clearForm: () => void;
187
- onClickSubmitFormHandler: (event?: React.MouseEvent<HTMLButtonElement>) => Promise<boolean>;
188
- checkCurrentPage: (event?: React.MouseEvent<HTMLButtonElement>) => Promise<boolean>;
189
- };
190
- export declare const DsDynamicFormForwardRef: React.ForwardRefExoticComponent<DsDynamicFormProps & React.RefAttributes<DsDynamicFormRef>>;
191
- export {};
@@ -1 +0,0 @@
1
- export { DsDynamicForm } from './components/DsDynamicForm';