@fovestta2/web-react 1.2.1 → 1.2.3

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.
@@ -1,4 +1,6 @@
1
1
  "use strict";
2
+ // import React, { useState, useEffect } from 'react';
3
+ // import { ValidationSchema } from '@fovestta2/validation-engine';
2
4
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
5
  if (k2 === undefined) k2 = k;
4
6
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -24,6 +26,308 @@ var __importStar = (this && this.__importStar) || function (mod) {
24
26
  };
25
27
  Object.defineProperty(exports, "__esModule", { value: true });
26
28
  exports.AddUpdateForm = void 0;
29
+ // // Import all Fv controls
30
+ // import { FvEntryField } from './FvEntryField';
31
+ // import { FvDropdown } from './FvDropdown';
32
+ // import { FvNumberField } from './FvNumberField';
33
+ // import { FvDateField } from './FvDateField';
34
+ // import { FvMonthYearField } from './FvMonthYearField';
35
+ // import { FvFileSelector } from './FvFileSelector';
36
+ // import { FvImageSelector } from './FvImageSelector';
37
+ // import { FvRichTextEditor } from './FvRichTextEditor';
38
+ // import { FvNameCode } from './FvNameCode';
39
+ // import { FvPhoneField } from './FvPhoneField';
40
+ // import { FvUanField } from './FvUanField';
41
+ // import { FvPfField } from './FvPfField';
42
+ // import { FvEsiField } from './FvEsiField';
43
+ // import { FvIfscField } from './FvIfscField';
44
+ // import { FvMicrField } from './FvMicrField';
45
+ // import { FvIbanField } from './FvIbanField';
46
+ // import { FvEmailField } from './FvEmailField';
47
+ // import { FvPasswordField } from './FvPasswordField';
48
+ // import { FvToggle } from './FvToggle';
49
+ // import { FvCheckbox } from './FvCheckbox';
50
+ // import { FvRadioGroup } from './FvRadioGroup';
51
+ // import { FvServicePeriod } from './FvServicePeriod';
52
+ // import { FvDocumentField } from './FvDocumentField';
53
+ // import { FvTimeField } from './FvTimeField';
54
+ // export type FieldType = 'text' | 'email' | 'number' | 'select' | 'name-code' | 'checkbox' | 'textarea' | 'date' | 'password' | 'radio' | 'file' | 'month-year' | 'phone' | 'uan' | 'pf' | 'esi' | 'ifsc' | 'micr' | 'iban' | 'service-period' | 'scan' | 'document' | 'time' | 'toggle';
55
+ // export type ValidationType = 'required' | 'email' | 'minLength' | 'maxLength' | 'pattern' | 'min' | 'max' | 'custom' | 'duplicate' | 'passwordComplexity';
56
+ // export interface FieldValidation {
57
+ // type: ValidationType;
58
+ // value?: any;
59
+ // message?: string;
60
+ // errorKey?: string;
61
+ // params?: any;
62
+ // }
63
+ // export interface FormColumn {
64
+ // name: string;
65
+ // label: string;
66
+ // type: FieldType;
67
+ // placeholder?: string;
68
+ // required?: boolean;
69
+ // options?: { label: string; value: any }[];
70
+ // validations?: FieldValidation[];
71
+ // value?: any;
72
+ // disabled?: boolean | ((formData: any) => boolean);
73
+ // className?: string;
74
+ // hidden?: boolean;
75
+ // hint?: string;
76
+ // colSpan?: number;
77
+ // onChange?: (value: any, formData: any) => void;
78
+ // accept?: string;
79
+ // filePreview?: boolean;
80
+ // showTimePicker?: boolean;
81
+ // allowAlphabetsOnly?: boolean;
82
+ // maxLength?: number;
83
+ // layout?: 'vertical' | 'horizontal';
84
+ // servicePeriodConfig?: { startField: string; endField: string };
85
+ // }
86
+ // export interface FormSection {
87
+ // title?: string;
88
+ // fields: FormColumn[];
89
+ // isRepeatable?: boolean;
90
+ // sectionKey?: string;
91
+ // }
92
+ // export interface FormConfig {
93
+ // sections: FormSection[];
94
+ // submitLabel?: string;
95
+ // resetLabel?: string;
96
+ // onSubmit: (data: any) => void;
97
+ // onReset?: () => void;
98
+ // onCancel: () => void;
99
+ // cancelLabel?: string;
100
+ // formTitle?: string;
101
+ // maxColsPerRow?: number;
102
+ // disableSubmit?: boolean;
103
+ // disableCancel?: boolean;
104
+ // hideSubmit?: boolean;
105
+ // hideCancel?: boolean;
106
+ // }
107
+ // export interface AddUpdateFormProps {
108
+ // config: FormConfig;
109
+ // }
110
+ // export const AddUpdateForm: React.FC<AddUpdateFormProps> = ({ config }) => {
111
+ // const [formData, setFormData] = useState<Record<string, any>>({});
112
+ // useEffect(() => {
113
+ // // Initialize form structure
114
+ // const initialData: Record<string, any> = {};
115
+ // config.sections.forEach((section) => {
116
+ // if (section.isRepeatable && section.sectionKey) {
117
+ // // Init as array with one empty object
118
+ // const groupObj: Record<string, any> = {};
119
+ // section.fields.forEach((col) => {
120
+ // groupObj[col.name] = col.value || '';
121
+ // });
122
+ // initialData[section.sectionKey] = [groupObj];
123
+ // } else {
124
+ // section.fields.forEach((col) => {
125
+ // initialData[col.name] = col.value || '';
126
+ // });
127
+ // }
128
+ // });
129
+ // setFormData(initialData);
130
+ // }, [config]);
131
+ // const handleFieldChange = (name: string, value: any, sectionKey?: string, index?: number) => {
132
+ // setFormData((prev) => {
133
+ // const copy = { ...prev };
134
+ // if (sectionKey && index !== undefined) {
135
+ // copy[sectionKey] = [...(copy[sectionKey] || [])];
136
+ // copy[sectionKey][index] = { ...copy[sectionKey][index], [name]: value };
137
+ // } else {
138
+ // copy[name] = value;
139
+ // }
140
+ // return copy;
141
+ // });
142
+ // // We do a delayed trigger to on change to simulate reactive form passing state
143
+ // setTimeout(() => {
144
+ // const col = findColumn(name, sectionKey);
145
+ // if (col && col.onChange) {
146
+ // // Needs recent state
147
+ // setFormData((latestState) => {
148
+ // col.onChange!(value, latestState);
149
+ // return latestState;
150
+ // });
151
+ // }
152
+ // }, 0);
153
+ // };
154
+ // const findColumn = (name: string, sectionKey?: string): FormColumn | undefined => {
155
+ // for (const section of config.sections) {
156
+ // if (sectionKey && section.sectionKey !== sectionKey) continue;
157
+ // const col = section.fields.find(c => c.name === name);
158
+ // if (col) return col;
159
+ // }
160
+ // return undefined;
161
+ // };
162
+ // const addSectionItem = (sectionKey: string, fields: FormColumn[]) => {
163
+ // setFormData((prev) => {
164
+ // const copy = { ...prev };
165
+ // const groupObj: Record<string, any> = {};
166
+ // fields.forEach((col) => { groupObj[col.name] = col.value || ''; });
167
+ // copy[sectionKey] = [...(copy[sectionKey] || []), groupObj];
168
+ // return copy;
169
+ // });
170
+ // };
171
+ // const removeSectionItem = (sectionKey: string, index: number) => {
172
+ // setFormData((prev) => {
173
+ // const copy = { ...prev };
174
+ // if (copy[sectionKey] && copy[sectionKey].length > 1) {
175
+ // const arr = [...copy[sectionKey]];
176
+ // arr.splice(index, 1);
177
+ // copy[sectionKey] = arr;
178
+ // }
179
+ // return copy;
180
+ // });
181
+ // };
182
+ // const handleSubmit = (e: React.FormEvent) => {
183
+ // e.preventDefault();
184
+ // config.onSubmit(formData);
185
+ // };
186
+ // const getSchema = (column: FormColumn): ValidationSchema => {
187
+ // const rules: any[] = [];
188
+ // const errorPriority: string[] = [];
189
+ // if (column.validations) {
190
+ // column.validations.forEach((v) => {
191
+ // if (v.type === 'required') { rules.push({ name: 'required', params: { enabled: true }, errorKey: 'ERR_REQUIRED', message: v.message }); errorPriority.push('required'); }
192
+ // if (v.type === 'email') { rules.push({ name: 'regex', params: { pattern: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$' }, errorKey: 'ERR_REGEX_MISMATCH', message: v.message }); errorPriority.push('regex'); }
193
+ // if (v.type === 'minLength') { rules.push({ name: 'minLength', params: { value: v.value }, errorKey: 'ERR_MIN_LENGTH', message: v.message }); errorPriority.push('minLength'); }
194
+ // if (v.type === 'maxLength') { rules.push({ name: 'maxLength', params: { value: v.value }, errorKey: 'ERR_MAX_LENGTH', message: v.message }); errorPriority.push('maxLength'); }
195
+ // if (v.type === 'pattern') { rules.push({ name: 'regex', params: { pattern: v.value }, errorKey: 'ERR_REGEX_MISMATCH', message: v.message }); errorPriority.push('regex'); }
196
+ // });
197
+ // }
198
+ // return { controlType: 'EntryField' as any, rules, errorPriority };
199
+ // };
200
+ // const isFieldDisabled = (column: FormColumn): boolean => {
201
+ // if (typeof column.disabled === 'function') {
202
+ // return column.disabled(formData);
203
+ // }
204
+ // return column.disabled || false;
205
+ // };
206
+ // const renderField = (column: FormColumn, value: any, sectionKey?: string, index?: number) => {
207
+ // const disabled = isFieldDisabled(column);
208
+ // const schema = getSchema(column);
209
+ // const onChange = (val: any) => handleFieldChange(column.name, val, sectionKey, index);
210
+ // if (column.hidden) return null;
211
+ // switch (column.type) {
212
+ // case 'text':
213
+ // return <FvEntryField label={column.label} placeholder={column.placeholder} value={value || ''} schema={schema} disabled={disabled} onChange={onChange} />;
214
+ // case 'email':
215
+ // return <FvEmailField label={column.label} placeholder={column.placeholder} value={value || ''} schema={schema} disabled={disabled} onChange={onChange} />;
216
+ // case 'password':
217
+ // return <FvPasswordField label={column.label} placeholder={column.placeholder} value={value || ''} schema={schema} disabled={disabled} onChange={onChange} />;
218
+ // case 'number':
219
+ // return <FvNumberField label={column.label} placeholder={column.placeholder} value={value || null} schema={schema} disabled={disabled} onChange={onChange} />;
220
+ // case 'select':
221
+ // return <FvDropdown label={column.label} placeholder={column.placeholder} options={column.options || []} value={value || ''} schema={schema} disabled={disabled} onChange={onChange} />;
222
+ // case 'checkbox':
223
+ // return <FvCheckbox label={column.label} value={value || false} disabled={disabled} onChange={onChange} />;
224
+ // case 'toggle':
225
+ // return <FvToggle label={column.label} value={value || false} disabled={disabled} onChange={onChange} />;
226
+ // case 'radio':
227
+ // return <FvRadioGroup label={column.label} options={column.options || []} value={value || ''} disabled={disabled} layout={column.layout} onChange={onChange} />;
228
+ // case 'date':
229
+ // return <FvDateField label={column.label} value={value || ''} schema={schema} disabled={disabled} onChange={onChange} />;
230
+ // case 'month-year':
231
+ // return <FvMonthYearField label={column.label} value={value || ''} schema={schema} disabled={disabled} onChange={onChange} />;
232
+ // case 'textarea':
233
+ // return <FvRichTextEditor label={column.label} placeholder={column.placeholder} value={value || ''} schema={schema} disabled={disabled} onChange={onChange} />;
234
+ // case 'file':
235
+ // if (column.accept?.startsWith('image') || column.filePreview) {
236
+ // return <FvImageSelector label={column.label} placeholder={column.placeholder} value={value || null} schema={schema} disabled={disabled} onChange={onChange} />;
237
+ // }
238
+ // return <FvFileSelector label={column.label} placeholder={column.placeholder} accept={column.accept} value={value || null} schema={schema} disabled={disabled} onChange={onChange} />;
239
+ // case 'name-code':
240
+ // return <FvNameCode label={column.label} placeholder={column.placeholder} options={column.options?.map(o => ({ code: o.value, name: o.label, value: o.value })) || []} value={value || ''} schema={schema} disabled={disabled} onChange={onChange} />;
241
+ // case 'phone':
242
+ // return <FvPhoneField label={column.label} value={value || ''} schema={schema} disabled={disabled} onChange={onChange} />;
243
+ // case 'uan':
244
+ // return <FvUanField label={column.label} value={value || ''} schema={schema} disabled={disabled} onChange={onChange} />;
245
+ // case 'pf':
246
+ // return <FvPfField label={column.label} value={value || ''} schema={schema} disabled={disabled} onChange={onChange} />;
247
+ // case 'esi':
248
+ // return <FvEsiField label={column.label} value={value || ''} schema={schema} disabled={disabled} onChange={onChange} />;
249
+ // case 'ifsc':
250
+ // return <FvIfscField label={column.label} value={value || ''} schema={schema} disabled={disabled} onChange={onChange} />;
251
+ // case 'micr':
252
+ // return <FvMicrField label={column.label} value={value || ''} schema={schema} disabled={disabled} onChange={onChange} />;
253
+ // case 'iban':
254
+ // return <FvIbanField label={column.label} value={value || ''} schema={schema} disabled={disabled} onChange={onChange} />;
255
+ // case 'document':
256
+ // return <FvDocumentField label={column.label} placeholder={column.placeholder} accept={column.accept} value={value || null} schema={schema} disabled={disabled} onChange={onChange} />;
257
+ // case 'time':
258
+ // return <FvTimeField label={column.label} placeholder={column.placeholder} value={value || ''} schema={schema} disabled={disabled} onChange={onChange} />;
259
+ // case 'service-period':
260
+ // // Not perfectly mapped due to pure group dependency, simple implementation shown for continuity
261
+ // return <FvEntryField label={column.label} value={value || ''} disabled={true} onChange={onChange} />;
262
+ // default:
263
+ // return null; // unsupported
264
+ // }
265
+ // };
266
+ // return (
267
+ // <div style={{ background: '#f5f5f5', padding: '15px 20px', borderRadius: '8px', maxWidth: '100%', boxSizing: 'border-box' }}>
268
+ // {config.formTitle && (
269
+ // <div style={{ marginBottom: '15px' }}>
270
+ // <h2 style={{ margin: 0, fontSize: '20px', fontWeight: 700, color: '#303030' }}>{config.formTitle}</h2>
271
+ // </div>
272
+ // )}
273
+ // <form onSubmit={handleSubmit} style={{ background: '#fff', padding: '15px', borderRadius: '6px', boxShadow: '0 1px 3px rgba(0,0,0,0.1)' }}>
274
+ // {config.sections.map((section, sIdx) => (
275
+ // <div key={sIdx} style={{ marginBottom: '20px' }}>
276
+ // {section.title && <h3 style={{ fontSize: '16px', fontWeight: 700, color: '#303030', marginBottom: '16px', textTransform: 'uppercase' }}>{section.title}</h3>}
277
+ // {section.isRepeatable && section.sectionKey ? (
278
+ // (formData[section.sectionKey] || []).map((group: any, idx: number) => (
279
+ // <div key={idx} style={{ position: 'relative', border: '1px solid #eee', borderRadius: '8px', padding: '20px 80px 20px 20px', marginBottom: '15px', background: '#fafafa' }}>
280
+ // <div style={{ position: 'absolute', top: '15px', right: '15px', display: 'flex', gap: '8px' }}>
281
+ // <button type="button" onClick={() => addSectionItem(section.sectionKey!, section.fields)} style={{ background: 'none', border: 'none', cursor: 'pointer', fontSize: '20px', color: '#2ecc71' }}>⊕</button>
282
+ // {(formData[section.sectionKey!] || []).length > 1 && (
283
+ // <button type="button" onClick={() => removeSectionItem(section.sectionKey!, idx)} style={{ background: 'none', border: 'none', cursor: 'pointer', fontSize: '20px', color: '#e74c3c' }}>⊗</button>
284
+ // )}
285
+ // </div>
286
+ // <div style={{ display: 'grid', gridTemplateColumns: `repeat(auto-fit, minmax(200px, 1fr))`, gap: '16px' }}>
287
+ // {section.fields.map((col, cIdx) => (
288
+ // <div key={cIdx} style={{ gridColumn: `span ${col.colSpan || 1}` }}>
289
+ // {renderField(col, group[col.name], section.sectionKey, idx)}
290
+ // </div>
291
+ // ))}
292
+ // </div>
293
+ // </div>
294
+ // ))
295
+ // ) : (
296
+ // <div style={{ display: 'grid', gridTemplateColumns: `repeat(auto-fit, minmax(200px, 1fr))`, gap: '16px' }}>
297
+ // {section.fields.map((col, cIdx) => (
298
+ // <div key={cIdx} style={{ gridColumn: `span ${col.colSpan || 1}` }}>
299
+ // {renderField(col, formData[col.name])}
300
+ // </div>
301
+ // ))}
302
+ // </div>
303
+ // )}
304
+ // </div>
305
+ // ))}
306
+ // <div style={{ display: 'flex', justifyContent: 'space-between', gap: '12px', marginTop: '20px' }}>
307
+ // {!config.hideSubmit && (
308
+ // <button
309
+ // type="submit"
310
+ // disabled={config.disableSubmit}
311
+ // style={{ padding: '8px 24px', background: config.disableSubmit ? '#bdc3c7' : '#006aff', color: '#fff', border: 'none', borderRadius: '7px', fontWeight: 600, cursor: config.disableSubmit ? 'not-allowed' : 'pointer' }}
312
+ // >
313
+ // {config.submitLabel || 'Save'}
314
+ // </button>
315
+ // )}
316
+ // {!config.hideCancel && (
317
+ // <button
318
+ // type="button"
319
+ // disabled={config.disableCancel}
320
+ // onClick={config.onCancel}
321
+ // style={{ padding: '8px 24px', background: '#303030', color: '#fff', border: 'none', borderRadius: '7px', fontWeight: 600, cursor: config.disableCancel ? 'not-allowed' : 'pointer' }}
322
+ // >
323
+ // {config.cancelLabel || 'Cancel'}
324
+ // </button>
325
+ // )}
326
+ // </div>
327
+ // </form>
328
+ // </div>
329
+ // );
330
+ // };
27
331
  const react_1 = __importStar(require("react"));
28
332
  // Import all Fv controls
29
333
  const FvEntryField_1 = require("./FvEntryField");
@@ -49,24 +353,90 @@ const FvCheckbox_1 = require("./FvCheckbox");
49
353
  const FvRadioGroup_1 = require("./FvRadioGroup");
50
354
  const FvDocumentField_1 = require("./FvDocumentField");
51
355
  const FvTimeField_1 = require("./FvTimeField");
52
- const AddUpdateForm = ({ config }) => {
356
+ // ─── Modal overlay styles ────────────────────────────────────────────────────
357
+ const overlayStyle = {
358
+ position: 'fixed',
359
+ inset: 0,
360
+ background: 'rgba(0, 0, 0, 0.4)',
361
+ display: 'flex',
362
+ alignItems: 'center',
363
+ justifyContent: 'center',
364
+ zIndex: 1000,
365
+ };
366
+ const modalBoxStyle = {
367
+ background: '#ffffff',
368
+ borderRadius: '12px',
369
+ boxShadow: '0 4px 20px rgba(0,0,0,0.15)',
370
+ width: '100%',
371
+ maxWidth: '540px',
372
+ backgroundColor: '#fff',
373
+ position: 'relative',
374
+ padding: '30px 24px',
375
+ };
376
+ const closeBtnStyle = {
377
+ position: 'absolute',
378
+ top: '16px',
379
+ right: '16px',
380
+ background: 'none',
381
+ border: 'none',
382
+ cursor: 'pointer',
383
+ fontSize: '20px',
384
+ color: '#666',
385
+ padding: '4px',
386
+ };
387
+ const modalTitleStyle = {
388
+ margin: '0 0 24px 0',
389
+ fontSize: '22px',
390
+ fontWeight: 700,
391
+ color: '#1a1a1a',
392
+ };
393
+ const getSubmitButtonStyle = (disabled) => ({
394
+ width: '100%',
395
+ padding: '12px',
396
+ background: disabled ? '#8cc1f7' : '#005bb5',
397
+ color: '#ffffff',
398
+ border: 'none',
399
+ borderRadius: '8px',
400
+ fontWeight: 600,
401
+ fontSize: '16px',
402
+ cursor: disabled ? 'not-allowed' : 'pointer',
403
+ marginTop: '24px',
404
+ });
405
+ // ── Standalone (non-modal) wrapper styles ───────────────────────────────────
406
+ const standaloneWrapStyle = {
407
+ background: '#ffffff',
408
+ borderRadius: '8px',
409
+ boxShadow: '0 1px 4px rgba(0,0,0,0.08)',
410
+ padding: '24px',
411
+ };
412
+ // ── Section title ────────────────────────────────────────────────────────────
413
+ const sectionTitleStyle = {
414
+ fontSize: '14px',
415
+ fontWeight: 600,
416
+ color: '#555',
417
+ marginBottom: '16px',
418
+ };
419
+ // ── Helpers ──────────────────────────────────────────────────────────────────
420
+ const buildGridStyle = (maxCols) => ({
421
+ display: 'grid',
422
+ gridTemplateColumns: `repeat(${maxCols}, minmax(0, 1fr))`,
423
+ gap: '16px',
424
+ });
425
+ // ── Component ────────────────────────────────────────────────────────────────
426
+ const AddUpdateForm = ({ config, asModal = false, }) => {
427
+ var _a;
53
428
  const [formData, setFormData] = (0, react_1.useState)({});
429
+ const maxCols = (_a = config.maxColsPerRow) !== null && _a !== void 0 ? _a : 3;
54
430
  (0, react_1.useEffect)(() => {
55
- // Initialize form structure
56
431
  const initialData = {};
57
432
  config.sections.forEach((section) => {
58
433
  if (section.isRepeatable && section.sectionKey) {
59
- // Init as array with one empty object
60
434
  const groupObj = {};
61
- section.fields.forEach((col) => {
62
- groupObj[col.name] = col.value || '';
63
- });
435
+ section.fields.forEach((col) => { var _a; groupObj[col.name] = (_a = col.value) !== null && _a !== void 0 ? _a : ''; });
64
436
  initialData[section.sectionKey] = [groupObj];
65
437
  }
66
438
  else {
67
- section.fields.forEach((col) => {
68
- initialData[col.name] = col.value || '';
69
- });
439
+ section.fields.forEach((col) => { var _a; initialData[col.name] = (_a = col.value) !== null && _a !== void 0 ? _a : ''; });
70
440
  }
71
441
  });
72
442
  setFormData(initialData);
@@ -83,11 +453,9 @@ const AddUpdateForm = ({ config }) => {
83
453
  }
84
454
  return copy;
85
455
  });
86
- // We do a delayed trigger to on change to simulate reactive form passing state
87
456
  setTimeout(() => {
88
457
  const col = findColumn(name, sectionKey);
89
- if (col && col.onChange) {
90
- // Needs recent state
458
+ if (col === null || col === void 0 ? void 0 : col.onChange) {
91
459
  setFormData((latestState) => {
92
460
  col.onChange(value, latestState);
93
461
  return latestState;
@@ -99,7 +467,7 @@ const AddUpdateForm = ({ config }) => {
99
467
  for (const section of config.sections) {
100
468
  if (sectionKey && section.sectionKey !== sectionKey)
101
469
  continue;
102
- const col = section.fields.find(c => c.name === name);
470
+ const col = section.fields.find((c) => c.name === name);
103
471
  if (col)
104
472
  return col;
105
473
  }
@@ -109,15 +477,16 @@ const AddUpdateForm = ({ config }) => {
109
477
  setFormData((prev) => {
110
478
  const copy = { ...prev };
111
479
  const groupObj = {};
112
- fields.forEach((col) => { groupObj[col.name] = col.value || ''; });
480
+ fields.forEach((col) => { var _a; groupObj[col.name] = (_a = col.value) !== null && _a !== void 0 ? _a : ''; });
113
481
  copy[sectionKey] = [...(copy[sectionKey] || []), groupObj];
114
482
  return copy;
115
483
  });
116
484
  };
117
485
  const removeSectionItem = (sectionKey, index) => {
118
486
  setFormData((prev) => {
487
+ var _a;
119
488
  const copy = { ...prev };
120
- if (copy[sectionKey] && copy[sectionKey].length > 1) {
489
+ if (((_a = copy[sectionKey]) === null || _a === void 0 ? void 0 : _a.length) > 1) {
121
490
  const arr = [...copy[sectionKey]];
122
491
  arr.splice(index, 1);
123
492
  copy[sectionKey] = arr;
@@ -143,102 +512,102 @@ const AddUpdateForm = ({ config }) => {
143
512
  errorPriority.push('regex');
144
513
  }
145
514
  if (v.type === 'minLength') {
146
- rules.push({ name: 'minLength', params: { value: v.value }, errorKey: 'ERR_MIN_LENGTH', message: v.message });
515
+ rules.push({ name: 'minLength', params: { value: v.value }, errorKey: v.errorKey || 'ERR_MIN_LENGTH', message: v.message });
147
516
  errorPriority.push('minLength');
148
517
  }
149
518
  if (v.type === 'maxLength') {
150
- rules.push({ name: 'maxLength', params: { value: v.value }, errorKey: 'ERR_MAX_LENGTH', message: v.message });
519
+ rules.push({ name: 'maxLength', params: { value: v.value }, errorKey: v.errorKey || 'ERR_MAX_LENGTH', message: v.message });
151
520
  errorPriority.push('maxLength');
152
521
  }
153
522
  if (v.type === 'pattern') {
154
- rules.push({ name: 'regex', params: { pattern: v.value }, errorKey: 'ERR_REGEX_MISMATCH', message: v.message });
523
+ rules.push({ name: 'regex', params: { pattern: v.value }, errorKey: v.errorKey || 'ERR_REGEX_MISMATCH', message: v.message });
155
524
  errorPriority.push('regex');
156
525
  }
526
+ if (v.type === 'min') {
527
+ rules.push({ name: 'min', params: { value: v.value }, errorKey: v.errorKey || 'ERR_MIN_VALUE', message: v.message });
528
+ errorPriority.push('min');
529
+ }
530
+ if (v.type === 'max') {
531
+ rules.push({ name: 'max', params: { value: v.value }, errorKey: v.errorKey || 'ERR_MAX_VALUE', message: v.message });
532
+ errorPriority.push('max');
533
+ }
534
+ if (v.type === 'custom') {
535
+ rules.push({ name: 'custom', params: { validator: v.value }, errorKey: v.errorKey || 'ERR_CUSTOM_INVALID', message: v.message });
536
+ errorPriority.push('custom');
537
+ }
538
+ if (v.type === 'duplicate') {
539
+ rules.push({ name: 'duplicate', params: v.params, errorKey: v.errorKey || 'ERR_DUPLICATE', message: v.message });
540
+ errorPriority.push('duplicate');
541
+ }
542
+ if (v.type === 'passwordComplexity') {
543
+ rules.push({ name: 'passwordComplexity', params: v.params, errorKey: v.errorKey || 'ERR_PASSWORD_COMPLEXITY', message: v.message });
544
+ errorPriority.push('passwordComplexity');
545
+ }
157
546
  });
158
547
  }
159
548
  return { controlType: 'EntryField', rules, errorPriority };
160
549
  };
161
- const isFieldDisabled = (column) => {
162
- if (typeof column.disabled === 'function') {
163
- return column.disabled(formData);
164
- }
165
- return column.disabled || false;
166
- };
550
+ const isFieldDisabled = (column) => typeof column.disabled === 'function' ? column.disabled(formData) : column.disabled || false;
167
551
  const renderField = (column, value, sectionKey, index) => {
168
552
  var _a, _b;
553
+ if (column.hidden)
554
+ return null;
169
555
  const disabled = isFieldDisabled(column);
170
556
  const schema = getSchema(column);
171
557
  const onChange = (val) => handleFieldChange(column.name, val, sectionKey, index);
172
- if (column.hidden)
173
- return null;
174
558
  switch (column.type) {
175
- case 'text':
176
- return react_1.default.createElement(FvEntryField_1.FvEntryField, { label: column.label, placeholder: column.placeholder, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
177
- case 'email':
178
- return react_1.default.createElement(FvEmailField_1.FvEmailField, { label: column.label, placeholder: column.placeholder, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
179
- case 'password':
180
- return react_1.default.createElement(FvPasswordField_1.FvPasswordField, { label: column.label, placeholder: column.placeholder, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
181
- case 'number':
182
- return react_1.default.createElement(FvNumberField_1.FvNumberField, { label: column.label, placeholder: column.placeholder, value: value || null, schema: schema, disabled: disabled, onChange: onChange });
183
- case 'select':
184
- return react_1.default.createElement(FvDropdown_1.FvDropdown, { label: column.label, placeholder: column.placeholder, options: column.options || [], value: value || '', schema: schema, disabled: disabled, onChange: onChange });
185
- case 'checkbox':
186
- return react_1.default.createElement(FvCheckbox_1.FvCheckbox, { label: column.label, value: value || false, disabled: disabled, onChange: onChange });
187
- case 'toggle':
188
- return react_1.default.createElement(FvToggle_1.FvToggle, { label: column.label, value: value || false, disabled: disabled, onChange: onChange });
189
- case 'radio':
190
- return react_1.default.createElement(FvRadioGroup_1.FvRadioGroup, { label: column.label, options: column.options || [], value: value || '', disabled: disabled, layout: column.layout, onChange: onChange });
191
- case 'date':
192
- return react_1.default.createElement(FvDateField_1.FvDateField, { label: column.label, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
193
- case 'month-year':
194
- return react_1.default.createElement(FvMonthYearField_1.FvMonthYearField, { label: column.label, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
195
- case 'textarea':
196
- return react_1.default.createElement(FvRichTextEditor_1.FvRichTextEditor, { label: column.label, placeholder: column.placeholder, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
559
+ case 'text': return react_1.default.createElement(FvEntryField_1.FvEntryField, { label: column.label, placeholder: column.placeholder, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
560
+ case 'email': return react_1.default.createElement(FvEmailField_1.FvEmailField, { label: column.label, placeholder: column.placeholder, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
561
+ case 'password': return react_1.default.createElement(FvPasswordField_1.FvPasswordField, { label: column.label, placeholder: column.placeholder, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
562
+ case 'number': return react_1.default.createElement(FvNumberField_1.FvNumberField, { label: column.label, placeholder: column.placeholder, value: value !== null && value !== void 0 ? value : null, schema: schema, disabled: disabled, onChange: onChange });
563
+ case 'select': return react_1.default.createElement(FvDropdown_1.FvDropdown, { label: column.label, placeholder: column.placeholder, options: column.options || [], value: value || '', schema: schema, disabled: disabled, onChange: onChange });
564
+ case 'checkbox': return react_1.default.createElement(FvCheckbox_1.FvCheckbox, { label: column.label, value: value || false, disabled: disabled, onChange: onChange });
565
+ case 'toggle': return react_1.default.createElement(FvToggle_1.FvToggle, { label: column.label, value: value || false, disabled: disabled, onChange: onChange });
566
+ case 'radio': return react_1.default.createElement(FvRadioGroup_1.FvRadioGroup, { label: column.label, options: column.options || [], value: value || '', disabled: disabled, layout: column.layout, onChange: onChange });
567
+ case 'date': return react_1.default.createElement(FvDateField_1.FvDateField, { label: column.label, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
568
+ case 'month-year': return react_1.default.createElement(FvMonthYearField_1.FvMonthYearField, { label: column.label, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
569
+ case 'textarea': return react_1.default.createElement(FvRichTextEditor_1.FvRichTextEditor, { label: column.label, placeholder: column.placeholder, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
197
570
  case 'file':
198
571
  if (((_a = column.accept) === null || _a === void 0 ? void 0 : _a.startsWith('image')) || column.filePreview) {
199
- return react_1.default.createElement(FvImageSelector_1.FvImageSelector, { label: column.label, placeholder: column.placeholder, value: value || null, schema: schema, disabled: disabled, onChange: onChange });
572
+ return react_1.default.createElement(FvImageSelector_1.FvImageSelector, { label: column.label, placeholder: column.placeholder, value: value !== null && value !== void 0 ? value : null, schema: schema, disabled: disabled, onChange: onChange });
200
573
  }
201
- return react_1.default.createElement(FvFileSelector_1.FvFileSelector, { label: column.label, placeholder: column.placeholder, accept: column.accept, value: value || null, schema: schema, disabled: disabled, onChange: onChange });
202
- case 'name-code':
203
- return react_1.default.createElement(FvNameCode_1.FvNameCode, { label: column.label, placeholder: column.placeholder, options: ((_b = column.options) === null || _b === void 0 ? void 0 : _b.map(o => ({ code: o.value, name: o.label, value: o.value }))) || [], value: value || '', schema: schema, disabled: disabled, onChange: onChange });
204
- case 'phone':
205
- return react_1.default.createElement(FvPhoneField_1.FvPhoneField, { label: column.label, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
206
- case 'uan':
207
- return react_1.default.createElement(FvUanField_1.FvUanField, { label: column.label, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
208
- case 'pf':
209
- return react_1.default.createElement(FvPfField_1.FvPfField, { label: column.label, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
210
- case 'esi':
211
- return react_1.default.createElement(FvEsiField_1.FvEsiField, { label: column.label, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
212
- case 'ifsc':
213
- return react_1.default.createElement(FvIfscField_1.FvIfscField, { label: column.label, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
214
- case 'micr':
215
- return react_1.default.createElement(FvMicrField_1.FvMicrField, { label: column.label, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
216
- case 'iban':
217
- return react_1.default.createElement(FvIbanField_1.FvIbanField, { label: column.label, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
218
- case 'document':
219
- return react_1.default.createElement(FvDocumentField_1.FvDocumentField, { label: column.label, placeholder: column.placeholder, accept: column.accept, value: value || null, schema: schema, disabled: disabled, onChange: onChange });
220
- case 'time':
221
- return react_1.default.createElement(FvTimeField_1.FvTimeField, { label: column.label, placeholder: column.placeholder, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
222
- case 'service-period':
223
- // Not perfectly mapped due to pure group dependency, simple implementation shown for continuity
224
- return react_1.default.createElement(FvEntryField_1.FvEntryField, { label: column.label, value: value || '', disabled: true, onChange: onChange });
225
- default:
226
- return null; // unsupported
574
+ return react_1.default.createElement(FvFileSelector_1.FvFileSelector, { label: column.label, placeholder: column.placeholder, accept: column.accept, value: value !== null && value !== void 0 ? value : null, schema: schema, disabled: disabled, onChange: onChange });
575
+ case 'name-code': return react_1.default.createElement(FvNameCode_1.FvNameCode, { label: column.label, placeholder: column.placeholder, options: ((_b = column.options) === null || _b === void 0 ? void 0 : _b.map((o) => ({ code: o.value, name: o.label, value: o.value }))) || [], value: value || '', schema: schema, disabled: disabled, onChange: onChange });
576
+ case 'phone': return react_1.default.createElement(FvPhoneField_1.FvPhoneField, { label: column.label, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
577
+ case 'uan': return react_1.default.createElement(FvUanField_1.FvUanField, { label: column.label, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
578
+ case 'pf': return react_1.default.createElement(FvPfField_1.FvPfField, { label: column.label, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
579
+ case 'esi': return react_1.default.createElement(FvEsiField_1.FvEsiField, { label: column.label, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
580
+ case 'ifsc': return react_1.default.createElement(FvIfscField_1.FvIfscField, { label: column.label, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
581
+ case 'micr': return react_1.default.createElement(FvMicrField_1.FvMicrField, { label: column.label, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
582
+ case 'iban': return react_1.default.createElement(FvIbanField_1.FvIbanField, { label: column.label, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
583
+ case 'document': return react_1.default.createElement(FvDocumentField_1.FvDocumentField, { label: column.label, placeholder: column.placeholder, accept: column.accept, value: value !== null && value !== void 0 ? value : null, schema: schema, disabled: disabled, onChange: onChange });
584
+ case 'time': return react_1.default.createElement(FvTimeField_1.FvTimeField, { label: column.label, placeholder: column.placeholder, value: value || '', schema: schema, disabled: disabled, onChange: onChange });
585
+ case 'service-period': return react_1.default.createElement(FvEntryField_1.FvEntryField, { label: column.label, value: value || '', disabled: true, onChange: onChange });
586
+ default: return null;
227
587
  }
228
588
  };
229
- return (react_1.default.createElement("div", { style: { background: '#f5f5f5', padding: '15px 20px', borderRadius: '8px', maxWidth: '100%', boxSizing: 'border-box' } },
230
- config.formTitle && (react_1.default.createElement("div", { style: { marginBottom: '15px' } },
231
- react_1.default.createElement("h2", { style: { margin: 0, fontSize: '20px', fontWeight: 700, color: '#303030' } }, config.formTitle))),
232
- react_1.default.createElement("form", { onSubmit: handleSubmit, style: { background: '#fff', padding: '15px', borderRadius: '6px', boxShadow: '0 1px 3px rgba(0,0,0,0.1)' } },
233
- config.sections.map((section, sIdx) => (react_1.default.createElement("div", { key: sIdx, style: { marginBottom: '20px' } },
234
- section.title && react_1.default.createElement("h3", { style: { fontSize: '16px', fontWeight: 700, color: '#303030', marginBottom: '16px', textTransform: 'uppercase' } }, section.title),
235
- section.isRepeatable && section.sectionKey ? ((formData[section.sectionKey] || []).map((group, idx) => (react_1.default.createElement("div", { key: idx, style: { position: 'relative', border: '1px solid #eee', borderRadius: '8px', padding: '20px 80px 20px 20px', marginBottom: '15px', background: '#fafafa' } },
236
- react_1.default.createElement("div", { style: { position: 'absolute', top: '15px', right: '15px', display: 'flex', gap: '8px' } },
237
- react_1.default.createElement("button", { type: "button", onClick: () => addSectionItem(section.sectionKey, section.fields), style: { background: 'none', border: 'none', cursor: 'pointer', fontSize: '20px', color: '#2ecc71' } }, "\u2295"),
238
- (formData[section.sectionKey] || []).length > 1 && (react_1.default.createElement("button", { type: "button", onClick: () => removeSectionItem(section.sectionKey, idx), style: { background: 'none', border: 'none', cursor: 'pointer', fontSize: '20px', color: '#e74c3c' } }, "\u2297"))),
239
- react_1.default.createElement("div", { style: { display: 'grid', gridTemplateColumns: `repeat(auto-fit, minmax(200px, 1fr))`, gap: '16px' } }, section.fields.map((col, cIdx) => (react_1.default.createElement("div", { key: cIdx, style: { gridColumn: `span ${col.colSpan || 1}` } }, renderField(col, group[col.name], section.sectionKey, idx))))))))) : (react_1.default.createElement("div", { style: { display: 'grid', gridTemplateColumns: `repeat(auto-fit, minmax(200px, 1fr))`, gap: '16px' } }, section.fields.map((col, cIdx) => (react_1.default.createElement("div", { key: cIdx, style: { gridColumn: `span ${col.colSpan || 1}` } }, renderField(col, formData[col.name]))))))))),
240
- react_1.default.createElement("div", { style: { display: 'flex', justifyContent: 'space-between', gap: '12px', marginTop: '20px' } },
241
- !config.hideSubmit && (react_1.default.createElement("button", { type: "submit", disabled: config.disableSubmit, style: { padding: '8px 24px', background: config.disableSubmit ? '#bdc3c7' : '#006aff', color: '#fff', border: 'none', borderRadius: '7px', fontWeight: 600, cursor: config.disableSubmit ? 'not-allowed' : 'pointer' } }, config.submitLabel || 'Save')),
242
- !config.hideCancel && (react_1.default.createElement("button", { type: "button", disabled: config.disableCancel, onClick: config.onCancel, style: { padding: '8px 24px', background: '#303030', color: '#fff', border: 'none', borderRadius: '7px', fontWeight: 600, cursor: config.disableCancel ? 'not-allowed' : 'pointer' } }, config.cancelLabel || 'Cancel'))))));
589
+ const formBody = (react_1.default.createElement("form", { onSubmit: handleSubmit, className: `fv-add-update-form ${config.className || ''}`.trim() },
590
+ config.sections.map((section, sIdx) => {
591
+ var _a;
592
+ const sectionMaxCols = (_a = section.maxColsPerRow) !== null && _a !== void 0 ? _a : maxCols;
593
+ return (react_1.default.createElement("div", { key: sIdx, style: { marginBottom: '16px' }, className: `fv-form-section ${section.className || ''}`.trim() },
594
+ section.title && react_1.default.createElement("div", { style: sectionTitleStyle, className: "fv-form-section-title" }, section.title),
595
+ section.isRepeatable && section.sectionKey ? ((formData[section.sectionKey] || []).map((group, idx) => (react_1.default.createElement("div", { key: idx, style: { position: 'relative', border: '1px solid #eee', borderRadius: '8px', padding: '12px', marginBottom: '12px', background: '#fafafa' }, className: "fv-form-repeatable-item" },
596
+ react_1.default.createElement("div", { style: { position: 'absolute', top: '8px', right: '8px', display: 'flex', gap: '4px' }, className: "fv-form-repeatable-actions" },
597
+ react_1.default.createElement("button", { type: "button", onClick: () => addSectionItem(section.sectionKey, section.fields), style: { background: 'none', border: 'none', cursor: 'pointer', fontSize: '18px', color: '#2ecc71' }, className: "fv-form-add-btn" }, "\u2295"),
598
+ (formData[section.sectionKey] || []).length > 1 && (react_1.default.createElement("button", { type: "button", onClick: () => removeSectionItem(section.sectionKey, idx), style: { background: 'none', border: 'none', cursor: 'pointer', fontSize: '18px', color: '#e74c3c' }, className: "fv-form-remove-btn" }, "\u2297"))),
599
+ react_1.default.createElement("div", { style: buildGridStyle(sectionMaxCols), className: "fv-form-grid" }, section.fields.map((col, cIdx) => (react_1.default.createElement("div", { key: cIdx, style: { gridColumn: `span ${col.colSpan || 1}`, minWidth: 0 }, className: `fv-form-field-wrapper ${col.className || ''}`.trim() }, renderField(col, group[col.name], section.sectionKey, idx))))))))) : (react_1.default.createElement("div", { style: buildGridStyle(sectionMaxCols), className: "fv-form-grid" }, section.fields.map((col, cIdx) => (react_1.default.createElement("div", { key: cIdx, style: { gridColumn: `span ${col.colSpan || 1}`, minWidth: 0 }, className: `fv-form-field-wrapper ${col.className || ''}`.trim() }, renderField(col, formData[col.name]))))))));
600
+ }),
601
+ react_1.default.createElement("div", { style: { display: 'flex', gap: '12px', marginTop: '8px' }, className: "fv-form-footer" }, !config.hideSubmit && (react_1.default.createElement("button", { type: "submit", disabled: config.disableSubmit, style: getSubmitButtonStyle(!!config.disableSubmit), className: "fv-form-submit-btn" }, config.submitLabel || 'Save')))));
602
+ if (asModal) {
603
+ return (react_1.default.createElement("div", { style: overlayStyle, className: "fv-form-overlay" },
604
+ react_1.default.createElement("div", { style: modalBoxStyle, className: "fv-modal-container" },
605
+ react_1.default.createElement("button", { type: "button", style: closeBtnStyle, onClick: config.onCancel, className: "fv-modal-close-btn" }, "\u2715"),
606
+ config.formTitle && react_1.default.createElement("h2", { style: modalTitleStyle, className: "fv-modal-title" }, config.formTitle),
607
+ react_1.default.createElement("div", { className: "fv-modal-body" }, formBody))));
608
+ }
609
+ return (react_1.default.createElement("div", { style: { background: '#f5f5f5', padding: '16px', borderRadius: '8px' }, className: "fv-standalone-form-container" },
610
+ config.formTitle && react_1.default.createElement("h2", { style: { margin: '0 0 16px', fontSize: '20px', fontWeight: 700 }, className: "fv-form-title" }, config.formTitle),
611
+ react_1.default.createElement("div", { style: standaloneWrapStyle, className: "fv-form-body-wrapper" }, formBody)));
243
612
  };
244
613
  exports.AddUpdateForm = AddUpdateForm;