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