funuicss 3.8.10 → 3.8.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/ui/form/Form.js +1006 -111
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "3.8.
|
|
2
|
+
"version": "3.8.11",
|
|
3
3
|
"name": "funuicss",
|
|
4
4
|
"description": "React and Next.js component UI Library for creating Easy and good looking websites with fewer lines of code. Elevate your web development experience with our cutting-edge React/Next.js component UI Library. Craft stunning websites effortlessly, boasting both seamless functionality and aesthetic appeal—all achieved with minimal lines of code. Unleash the power of simplicity and style in your projects!",
|
|
5
5
|
"main": "index.js",
|
package/ui/form/Form.js
CHANGED
|
@@ -164,7 +164,7 @@ var FormCheckbox = function (_a) {
|
|
|
164
164
|
alignItems: 'center',
|
|
165
165
|
justifyContent: 'center',
|
|
166
166
|
flexShrink: 0,
|
|
167
|
-
} }, checked && (react_1.default.createElement("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.
|
|
167
|
+
} }, checked && (react_1.default.createElement("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", style: {
|
|
168
168
|
stroke: 'white',
|
|
169
169
|
strokeWidth: '2',
|
|
170
170
|
strokeLinecap: 'round',
|
|
@@ -282,7 +282,7 @@ var formatWhatsAppMessage = function (values, fields, header, footer) {
|
|
|
282
282
|
}
|
|
283
283
|
return encodeURIComponent(message);
|
|
284
284
|
};
|
|
285
|
-
// Main Form Component -
|
|
285
|
+
// Main Form Component - MODIFIED for submit-only validation
|
|
286
286
|
var Form = function (props) {
|
|
287
287
|
var fieldsProp = props.fields, onSubmitProp = props.onSubmit, _a = props.defaultValues, defaultValuesProp = _a === void 0 ? {} : _a, _b = props.submitText, submitTextProp = _b === void 0 ? 'Submit' : _b, _c = props.submitBg, submitBgProp = _c === void 0 ? 'primary' : _c, submitPrefixProp = props.submitPrefix, submitSuffixProp = props.submitSuffix, _d = props.resetText, resetTextProp = _d === void 0 ? 'Reset' : _d, _e = props.showReset, showResetProp = _e === void 0 ? true : _e, _f = props.isLoading, isLoadingProp = _f === void 0 ? false : _f, _g = props.className, classNameProp = _g === void 0 ? '' : _g, _h = props.layout, layoutProp = _h === void 0 ? 'vertical' : _h, _j = props.gap, gapProp = _j === void 0 ? '1.5rem' : _j, titleProp = props.title, titleSizeProp = props.titleSize, titleColorProp = props.titleColor, descriptionProp = props.description, descriptionSizeProp = props.descriptionSize, descriptionColorProp = props.descriptionColor, whatsappContactProp = props.whatsappContact, widthProp = props.width, centeredProp = props.centered, whatsappHeaderProp = props.whatsappHeader, whatsappFooterProp = props.whatsappFooter, _k = props.fullWidth, fullWidthProp = _k === void 0 ? true : _k, _l = props.variant, variant = _l === void 0 ? '' : _l;
|
|
288
288
|
// Use component configuration with variant
|
|
@@ -349,8 +349,7 @@ var Form = function (props) {
|
|
|
349
349
|
var parsedDefaultValues = (0, react_1.useMemo)(function () { return parseJsonInput(defaultValues, {}); }, [defaultValues]);
|
|
350
350
|
// State management
|
|
351
351
|
var _m = (0, react_1.useState)({}), errors = _m[0], setErrors = _m[1];
|
|
352
|
-
var _o = (0, react_1.useState)(
|
|
353
|
-
var _p = (0, react_1.useState)(function () {
|
|
352
|
+
var _o = (0, react_1.useState)(function () {
|
|
354
353
|
// Initialize form values from defaultValues and field values
|
|
355
354
|
var initialValues = {};
|
|
356
355
|
parsedFields.forEach(function (field) {
|
|
@@ -374,8 +373,9 @@ var Form = function (props) {
|
|
|
374
373
|
}
|
|
375
374
|
});
|
|
376
375
|
return initialValues;
|
|
377
|
-
}), formValues =
|
|
378
|
-
var
|
|
376
|
+
}), formValues = _o[0], setFormValues = _o[1];
|
|
377
|
+
var _p = (0, react_1.useState)(false), isSubmitting = _p[0], setIsSubmitting = _p[1];
|
|
378
|
+
var _q = (0, react_1.useState)(false), hasBeenSubmitted = _q[0], setHasBeenSubmitted = _q[1];
|
|
379
379
|
// Update form values when defaultValues prop changes
|
|
380
380
|
(0, react_1.useEffect)(function () {
|
|
381
381
|
if (Object.keys(parsedDefaultValues).length > 0) {
|
|
@@ -476,6 +476,7 @@ var Form = function (props) {
|
|
|
476
476
|
}
|
|
477
477
|
});
|
|
478
478
|
setErrors(newErrors);
|
|
479
|
+
setHasBeenSubmitted(true);
|
|
479
480
|
return !hasErrors;
|
|
480
481
|
}, [parsedFields, validateField, formValues]);
|
|
481
482
|
// Handle field change for checkboxes and radios
|
|
@@ -485,96 +486,36 @@ var Form = function (props) {
|
|
|
485
486
|
var _a;
|
|
486
487
|
return (__assign(__assign({}, prev), (_a = {}, _a[fieldName] = newValue, _a)));
|
|
487
488
|
});
|
|
488
|
-
//
|
|
489
|
-
setTouched(function (prev) {
|
|
490
|
-
var _a;
|
|
491
|
-
return (__assign(__assign({}, prev), (_a = {}, _a[fieldName] = true, _a)));
|
|
492
|
-
});
|
|
493
|
-
// Validate the changed field
|
|
494
|
-
var field = parsedFields.find(function (f) { return f.name === fieldName; });
|
|
495
|
-
if (!field)
|
|
496
|
-
return;
|
|
497
|
-
var error = validateField(field, newValue);
|
|
489
|
+
// Clear error for this field when user makes a change
|
|
498
490
|
setErrors(function (prev) {
|
|
499
|
-
var
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
}
|
|
503
|
-
else {
|
|
504
|
-
var newErrors = __assign({}, prev);
|
|
505
|
-
delete newErrors[fieldName];
|
|
506
|
-
return newErrors;
|
|
507
|
-
}
|
|
491
|
+
var newErrors = __assign({}, prev);
|
|
492
|
+
delete newErrors[fieldName];
|
|
493
|
+
return newErrors;
|
|
508
494
|
});
|
|
509
|
-
}, [
|
|
510
|
-
//
|
|
495
|
+
}, []);
|
|
496
|
+
// Handle input change - NO VALIDATION ON CHANGE
|
|
511
497
|
var handleInputEventChange = (0, react_1.useCallback)(function (e) {
|
|
512
498
|
var fieldName = e.target.name;
|
|
513
499
|
var value = e.target.value;
|
|
514
|
-
// Update form values
|
|
500
|
+
// Update form values
|
|
515
501
|
setFormValues(function (prev) {
|
|
516
502
|
var _a;
|
|
517
503
|
return (__assign(__assign({}, prev), (_a = {}, _a[fieldName] = value, _a)));
|
|
518
504
|
});
|
|
519
|
-
//
|
|
520
|
-
setTouched(function (prev) {
|
|
521
|
-
var _a;
|
|
522
|
-
return (__assign(__assign({}, prev), (_a = {}, _a[fieldName] = true, _a)));
|
|
523
|
-
});
|
|
524
|
-
// Validate the changed field
|
|
525
|
-
var field = parsedFields.find(function (f) { return f.name === fieldName; });
|
|
526
|
-
if (!field)
|
|
527
|
-
return;
|
|
528
|
-
var error = validateField(field, value);
|
|
529
|
-
setErrors(function (prev) {
|
|
530
|
-
var _a;
|
|
531
|
-
if (error) {
|
|
532
|
-
return __assign(__assign({}, prev), (_a = {}, _a[fieldName] = error, _a));
|
|
533
|
-
}
|
|
534
|
-
else {
|
|
535
|
-
var newErrors = __assign({}, prev);
|
|
536
|
-
delete newErrors[fieldName];
|
|
537
|
-
return newErrors;
|
|
538
|
-
}
|
|
539
|
-
});
|
|
540
|
-
}, [parsedFields, validateField]);
|
|
541
|
-
// FIXED: Handle blur event - pass event directly to Input component
|
|
542
|
-
var handleInputEventBlur = (0, react_1.useCallback)(function (e) {
|
|
543
|
-
var fieldName = e.target.name;
|
|
544
|
-
setTouched(function (prev) {
|
|
545
|
-
var _a;
|
|
546
|
-
return (__assign(__assign({}, prev), (_a = {}, _a[fieldName] = true, _a)));
|
|
547
|
-
});
|
|
548
|
-
// Validate the field
|
|
549
|
-
var field = parsedFields.find(function (f) { return f.name === fieldName; });
|
|
550
|
-
if (!field)
|
|
551
|
-
return;
|
|
552
|
-
var value = formValues[fieldName];
|
|
553
|
-
var error = validateField(field, value);
|
|
505
|
+
// Clear error for this field when user makes a change
|
|
554
506
|
setErrors(function (prev) {
|
|
555
|
-
var
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
}
|
|
559
|
-
else {
|
|
560
|
-
var newErrors = __assign({}, prev);
|
|
561
|
-
delete newErrors[fieldName];
|
|
562
|
-
return newErrors;
|
|
563
|
-
}
|
|
507
|
+
var newErrors = __assign({}, prev);
|
|
508
|
+
delete newErrors[fieldName];
|
|
509
|
+
return newErrors;
|
|
564
510
|
});
|
|
565
|
-
}, [
|
|
511
|
+
}, []);
|
|
566
512
|
// Handle form submission
|
|
567
513
|
var handleSubmit = (0, react_1.useCallback)(function (e) { return __awaiter(void 0, void 0, void 0, function () {
|
|
568
|
-
var
|
|
514
|
+
var isValid, firstErrorField, element, message, cleanPhone, whatsappUrl, error_1;
|
|
569
515
|
return __generator(this, function (_a) {
|
|
570
516
|
switch (_a.label) {
|
|
571
517
|
case 0:
|
|
572
518
|
e.preventDefault();
|
|
573
|
-
allTouched = {};
|
|
574
|
-
parsedFields.forEach(function (field) {
|
|
575
|
-
allTouched[field.name] = true;
|
|
576
|
-
});
|
|
577
|
-
setTouched(allTouched);
|
|
578
519
|
isValid = validateForm();
|
|
579
520
|
if (!isValid) {
|
|
580
521
|
firstErrorField = Object.keys(errors)[0];
|
|
@@ -618,7 +559,7 @@ var Form = function (props) {
|
|
|
618
559
|
case 9: return [2 /*return*/];
|
|
619
560
|
}
|
|
620
561
|
});
|
|
621
|
-
}); }, [
|
|
562
|
+
}); }, [validateForm, formValues, whatsappContact, whatsappHeader, whatsappFooter, onSubmit, errors, parsedFields]);
|
|
622
563
|
// Handle form reset
|
|
623
564
|
var handleReset = (0, react_1.useCallback)(function () {
|
|
624
565
|
// Reset to initial values
|
|
@@ -644,49 +585,36 @@ var Form = function (props) {
|
|
|
644
585
|
});
|
|
645
586
|
setFormValues(initialValues);
|
|
646
587
|
setErrors({});
|
|
647
|
-
|
|
588
|
+
setHasBeenSubmitted(false);
|
|
648
589
|
}, [parsedFields, parsedDefaultValues]);
|
|
649
590
|
// Get field status for Input component
|
|
650
591
|
var getFieldStatus = (0, react_1.useCallback)(function (fieldName) {
|
|
651
592
|
var error = errors[fieldName];
|
|
652
|
-
|
|
653
|
-
if (error)
|
|
593
|
+
// Only show validation status if form has been submitted and there's an error
|
|
594
|
+
if (hasBeenSubmitted && error) {
|
|
654
595
|
return 'danger';
|
|
655
|
-
if (isTouched && !error && formValues[fieldName] !== '') {
|
|
656
|
-
return 'success';
|
|
657
596
|
}
|
|
658
597
|
return undefined;
|
|
659
|
-
}, [errors,
|
|
598
|
+
}, [errors, hasBeenSubmitted]);
|
|
660
599
|
// Check if form is valid for submission
|
|
661
600
|
var isFormValid = (0, react_1.useMemo)(function () {
|
|
662
|
-
//
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
}
|
|
670
|
-
if (field.type === 'checkbox') {
|
|
671
|
-
return value === false;
|
|
672
|
-
}
|
|
673
|
-
return !value || value === '';
|
|
674
|
-
});
|
|
675
|
-
// Check if there are any validation errors
|
|
676
|
-
var hasValidationErrors = Object.keys(errors).length > 0;
|
|
677
|
-
return !hasEmptyRequiredFields && !hasValidationErrors;
|
|
678
|
-
}, [parsedFields, formValues, errors]);
|
|
601
|
+
// Only check validity when form has been submitted
|
|
602
|
+
if (hasBeenSubmitted) {
|
|
603
|
+
return Object.keys(errors).length === 0;
|
|
604
|
+
}
|
|
605
|
+
// If form hasn't been submitted yet, consider it valid
|
|
606
|
+
return true;
|
|
607
|
+
}, [hasBeenSubmitted, errors]);
|
|
679
608
|
// Submit button disabled state
|
|
680
|
-
var isSubmitDisabled = isSubmitting || isLoading
|
|
609
|
+
var isSubmitDisabled = isSubmitting || isLoading;
|
|
681
610
|
// Check if WhatsApp is configured
|
|
682
611
|
var hasWhatsApp = !!whatsappContact;
|
|
683
|
-
// Render field based on type
|
|
612
|
+
// Render field based on type
|
|
684
613
|
var renderField = (0, react_1.useCallback)(function (field) {
|
|
685
614
|
var _a, _b, _c, _d, _e;
|
|
686
615
|
var status = getFieldStatus(field.name);
|
|
687
616
|
var error = errors[field.name];
|
|
688
|
-
var
|
|
689
|
-
var showError = error && isTouched;
|
|
617
|
+
var showError = hasBeenSubmitted && error;
|
|
690
618
|
var value = formValues[field.name];
|
|
691
619
|
// Field wrapper classes
|
|
692
620
|
var wrapperClass = "col min-w-200 field ".concat(showError ? 'field-error' : '').trim();
|
|
@@ -739,16 +667,16 @@ var Form = function (props) {
|
|
|
739
667
|
react_1.default.createElement(Flex_1.default, { direction: "column", gap: "0.5rem" }, field.options.map(function (option, index) { return (react_1.default.createElement(FormRadio, { key: "".concat(field.name, "_").concat(index), id: "".concat(inputId, "_").concat(index), label: option.label, checked: value === option.value, onChange: function () { return handleFieldChange(field.name, option.value); }, disabled: field.disabled || option.disabled || isLoading, required: field.required && index === 0, value: option.value })); }))));
|
|
740
668
|
case 'textarea':
|
|
741
669
|
return (react_1.default.createElement("div", { key: field.name, className: wrapperClass },
|
|
742
|
-
react_1.default.createElement(Input_1.default, __assign({ multiline: true, rows: ((_d = field.inputProps) === null || _d === void 0 ? void 0 : _d.rows) || 4, value: value || '', onChange: handleInputEventChange
|
|
670
|
+
react_1.default.createElement(Input_1.default, __assign({ multiline: true, rows: ((_d = field.inputProps) === null || _d === void 0 ? void 0 : _d.rows) || 4, value: value || '', onChange: handleInputEventChange }, baseProps))));
|
|
743
671
|
case 'select':
|
|
744
672
|
return (react_1.default.createElement("div", { key: field.name, className: wrapperClass },
|
|
745
|
-
react_1.default.createElement(Input_1.default, __assign({ select: true, options: ((_e = field.options) === null || _e === void 0 ? void 0 : _e.map(function (opt) { return ({ text: opt.label, value: opt.value }); })) || [], value: value || '', onChange: handleInputEventChange
|
|
673
|
+
react_1.default.createElement(Input_1.default, __assign({ select: true, options: ((_e = field.options) === null || _e === void 0 ? void 0 : _e.map(function (opt) { return ({ text: opt.label, value: opt.value }); })) || [], value: value || '', onChange: handleInputEventChange }, baseProps))));
|
|
746
674
|
default:
|
|
747
675
|
// text, email, number, tel, date, file, password
|
|
748
676
|
return (react_1.default.createElement("div", { key: field.name, className: wrapperClass },
|
|
749
|
-
react_1.default.createElement(Input_1.default, __assign({ type: field.type, value: value || '', onChange: handleInputEventChange
|
|
677
|
+
react_1.default.createElement(Input_1.default, __assign({ type: field.type, value: value || '', onChange: handleInputEventChange }, baseProps))));
|
|
750
678
|
}
|
|
751
|
-
}, [errors,
|
|
679
|
+
}, [errors, hasBeenSubmitted, formValues, isLoading, getFieldStatus, handleFieldChange, handleInputEventChange, fullWidth]);
|
|
752
680
|
// Don't render if no fields are configured
|
|
753
681
|
if (parsedFields.length === 0) {
|
|
754
682
|
console.warn('Form: No fields configured. Please provide fields prop or configure via theme.');
|
|
@@ -765,3 +693,970 @@ var Form = function (props) {
|
|
|
765
693
|
react_1.default.createElement(Button_1.default, { type: "submit", text: hasWhatsApp ? "Send via WhatsApp" : submitText, bg: submitBg || "primary", raised: true, prefix: submitPrefix || hasWhatsApp ? react_1.default.createElement(pi_1.PiWhatsappLogo, null) : react_1.default.createElement(pi_1.PiPaperPlaneTilt, null), suffix: submitSuffix, disabled: isSubmitDisabled, isLoading: isSubmitting || isLoading, fullWidth: fullWidth })))));
|
|
766
694
|
};
|
|
767
695
|
exports.default = Form;
|
|
696
|
+
// 'use client';
|
|
697
|
+
// import React, { useState, useEffect, useCallback, useMemo } from 'react';
|
|
698
|
+
// import Button from '../button/Button';
|
|
699
|
+
// import Input from '../input/Input';
|
|
700
|
+
// import Flex from '../flex/Flex';
|
|
701
|
+
// import Text from '../text/Text';
|
|
702
|
+
// import { PiPaperPlaneTilt, PiWarningCircle, PiWhatsappLogo } from 'react-icons/pi';
|
|
703
|
+
// import { useComponentConfiguration } from '../../utils/componentUtils';
|
|
704
|
+
// import { useVariant } from '../theme/theme';
|
|
705
|
+
// // Field types supported
|
|
706
|
+
// export type InputType =
|
|
707
|
+
// | 'text'
|
|
708
|
+
// | 'email'
|
|
709
|
+
// | 'number'
|
|
710
|
+
// | 'tel'
|
|
711
|
+
// | 'textarea'
|
|
712
|
+
// | 'password'
|
|
713
|
+
// | 'date'
|
|
714
|
+
// | 'select'
|
|
715
|
+
// | 'checkbox'
|
|
716
|
+
// | 'radio'
|
|
717
|
+
// | 'file';
|
|
718
|
+
// // Field option
|
|
719
|
+
// export interface FieldOption {
|
|
720
|
+
// label: string;
|
|
721
|
+
// value: string;
|
|
722
|
+
// disabled?: boolean;
|
|
723
|
+
// }
|
|
724
|
+
// // Simplified field configuration
|
|
725
|
+
// export interface FormField {
|
|
726
|
+
// name: string;
|
|
727
|
+
// label?: string;
|
|
728
|
+
// type: InputType;
|
|
729
|
+
// required?: boolean;
|
|
730
|
+
// placeholder?: string;
|
|
731
|
+
// options?: FieldOption[];
|
|
732
|
+
// multiple?: boolean; // For checkboxes
|
|
733
|
+
// value?: any; // Initial value
|
|
734
|
+
// disabled?: boolean;
|
|
735
|
+
// helperText?: string;
|
|
736
|
+
// // Input component props (passed directly to Input)
|
|
737
|
+
// inputProps?: {
|
|
738
|
+
// startIcon?: React.ReactNode;
|
|
739
|
+
// endIcon?: React.ReactNode;
|
|
740
|
+
// prefix?: React.ReactNode;
|
|
741
|
+
// suffix?: React.ReactNode;
|
|
742
|
+
// stringPrefix?: string;
|
|
743
|
+
// stringSuffix?: string;
|
|
744
|
+
// iconicBg?: string;
|
|
745
|
+
// funcss?: string;
|
|
746
|
+
// bg?: string;
|
|
747
|
+
// flat?: boolean;
|
|
748
|
+
// bordered?: boolean;
|
|
749
|
+
// borderless?: boolean;
|
|
750
|
+
// rounded?: boolean;
|
|
751
|
+
// leftRounded?: boolean;
|
|
752
|
+
// rightRounded?: boolean;
|
|
753
|
+
// rows?: number;
|
|
754
|
+
// noBorder?: boolean;
|
|
755
|
+
// variant?: string;
|
|
756
|
+
// // Standard HTML attributes
|
|
757
|
+
// id?: string;
|
|
758
|
+
// autocomplete?: string;
|
|
759
|
+
// pattern?: string;
|
|
760
|
+
// min?: string | number;
|
|
761
|
+
// max?: string | number;
|
|
762
|
+
// minLength?: number;
|
|
763
|
+
// maxLength?: number;
|
|
764
|
+
// step?: string | number;
|
|
765
|
+
// };
|
|
766
|
+
// }
|
|
767
|
+
// // Form props
|
|
768
|
+
// export interface FormProps {
|
|
769
|
+
// fields?: FormField[] | string; // Allow string (JSON) or array
|
|
770
|
+
// onSubmit?: (values: Record<string, any>, viaWhatsApp?: boolean) => void;
|
|
771
|
+
// defaultValues?: Record<string, any> | string; // Allow string (JSON) or object
|
|
772
|
+
// submitText?: string;
|
|
773
|
+
// submitBg?: string;
|
|
774
|
+
// submitPrefix?: React.ReactNode | string;
|
|
775
|
+
// submitSuffix?: React.ReactNode | string;
|
|
776
|
+
// resetText?: string;
|
|
777
|
+
// showReset?: boolean;
|
|
778
|
+
// isLoading?: boolean;
|
|
779
|
+
// className?: string;
|
|
780
|
+
// layout?: 'vertical' | 'horizontal';
|
|
781
|
+
// gap?: number | string;
|
|
782
|
+
// title?: string;
|
|
783
|
+
// titleSize?: string;
|
|
784
|
+
// titleColor?: string;
|
|
785
|
+
// description?: string;
|
|
786
|
+
// descriptionSize?: string;
|
|
787
|
+
// descriptionColor?: string;
|
|
788
|
+
// // WhatsApp props (simple, not object)
|
|
789
|
+
// whatsappContact?: string;
|
|
790
|
+
// whatsappHeader?: string;
|
|
791
|
+
// whatsappFooter?: string;
|
|
792
|
+
// // New props for fullWidth
|
|
793
|
+
// fullWidth?: boolean;
|
|
794
|
+
// width?: string;
|
|
795
|
+
// centered?: boolean;
|
|
796
|
+
// // Variant support
|
|
797
|
+
// variant?: string;
|
|
798
|
+
// }
|
|
799
|
+
// // Helper function to parse JSON input
|
|
800
|
+
// const parseJsonInput = <T,>(input: T | string | undefined, defaultValue: T): T => {
|
|
801
|
+
// if (input === undefined || input === null) {
|
|
802
|
+
// return defaultValue;
|
|
803
|
+
// }
|
|
804
|
+
// // If it's already the correct type, return as is
|
|
805
|
+
// if (typeof input !== 'string') {
|
|
806
|
+
// return input;
|
|
807
|
+
// }
|
|
808
|
+
// try {
|
|
809
|
+
// // Try to parse as JSON
|
|
810
|
+
// const parsed = JSON.parse(input);
|
|
811
|
+
// return parsed;
|
|
812
|
+
// } catch (error) {
|
|
813
|
+
// console.warn('Failed to parse JSON input:', input, error);
|
|
814
|
+
// // If parsing fails, try to interpret as a string that might be valid
|
|
815
|
+
// try {
|
|
816
|
+
// // Try to handle common cases like arrays or objects without quotes
|
|
817
|
+
// const trimmed = input.trim();
|
|
818
|
+
// if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
|
|
819
|
+
// return JSON.parse(trimmed);
|
|
820
|
+
// } else if (trimmed.startsWith('{') && trimmed.endsWith('}')) {
|
|
821
|
+
// return JSON.parse(trimmed);
|
|
822
|
+
// }
|
|
823
|
+
// } catch (e) {
|
|
824
|
+
// // If still fails, return default
|
|
825
|
+
// }
|
|
826
|
+
// return defaultValue;
|
|
827
|
+
// }
|
|
828
|
+
// };
|
|
829
|
+
// // Custom Checkbox Component (unchanged)
|
|
830
|
+
// const FormCheckbox: React.FC<{
|
|
831
|
+
// label?: string;
|
|
832
|
+
// checked: boolean;
|
|
833
|
+
// onChange: (checked: boolean) => void;
|
|
834
|
+
// disabled?: boolean;
|
|
835
|
+
// required?: boolean;
|
|
836
|
+
// value?: string;
|
|
837
|
+
// id?: string;
|
|
838
|
+
// }> = ({ label, checked, onChange, disabled, required, value, id }) => {
|
|
839
|
+
// return (
|
|
840
|
+
// <label
|
|
841
|
+
// className="funui_form-checkbox"
|
|
842
|
+
// style={{
|
|
843
|
+
// display: 'flex',
|
|
844
|
+
// alignItems: 'center',
|
|
845
|
+
// gap: '0.5rem',
|
|
846
|
+
// cursor: disabled ? 'not-allowed' : 'pointer',
|
|
847
|
+
// userSelect: 'none',
|
|
848
|
+
// width: 'fit-content',
|
|
849
|
+
// padding: '0.25rem 0',
|
|
850
|
+
// }}
|
|
851
|
+
// >
|
|
852
|
+
// <input
|
|
853
|
+
// type="checkbox"
|
|
854
|
+
// id={id}
|
|
855
|
+
// checked={checked}
|
|
856
|
+
// onChange={(e) => !disabled && onChange(e.target.checked)}
|
|
857
|
+
// disabled={disabled}
|
|
858
|
+
// required={required}
|
|
859
|
+
// value={value}
|
|
860
|
+
// style={{
|
|
861
|
+
// position: 'absolute',
|
|
862
|
+
// opacity: 0,
|
|
863
|
+
// width: 0,
|
|
864
|
+
// height: 0,
|
|
865
|
+
// pointerEvents: 'none'
|
|
866
|
+
// }}
|
|
867
|
+
// />
|
|
868
|
+
// <div
|
|
869
|
+
// className="funui_form-checkbox-box"
|
|
870
|
+
// style={{
|
|
871
|
+
// width: '1.25rem',
|
|
872
|
+
// height: '1.25rem',
|
|
873
|
+
// border: checked ? '2px solid var(--primary)' : '2px solid var(--borderColor)',
|
|
874
|
+
// borderRadius: '0.25rem',
|
|
875
|
+
// backgroundColor: checked ? 'var(--primary)' : 'transparent',
|
|
876
|
+
// position: 'relative',
|
|
877
|
+
// transition: 'all 0.2s ease',
|
|
878
|
+
// display: 'flex',
|
|
879
|
+
// alignItems: 'center',
|
|
880
|
+
// justifyContent: 'center',
|
|
881
|
+
// flexShrink: 0,
|
|
882
|
+
// }}
|
|
883
|
+
// >
|
|
884
|
+
// {checked && (
|
|
885
|
+
// <svg
|
|
886
|
+
// width="14"
|
|
887
|
+
// height="14"
|
|
888
|
+
// viewBox="0 0 14 14"
|
|
889
|
+
// fill="none"
|
|
890
|
+
// xmlns="http://www.w3.org2000/svg"
|
|
891
|
+
// style={{
|
|
892
|
+
// stroke: 'white',
|
|
893
|
+
// strokeWidth: '2',
|
|
894
|
+
// strokeLinecap: 'round',
|
|
895
|
+
// strokeLinejoin: 'round',
|
|
896
|
+
// }}
|
|
897
|
+
// >
|
|
898
|
+
// <path d="M3 7L6 10L11 4" />
|
|
899
|
+
// </svg>
|
|
900
|
+
// )}
|
|
901
|
+
// </div>
|
|
902
|
+
// {label && (
|
|
903
|
+
// <span
|
|
904
|
+
// className="funui_form-checkbox-label"
|
|
905
|
+
// style={{
|
|
906
|
+
// fontSize: '0.875rem',
|
|
907
|
+
// color: disabled ? 'var(--text-muted)' : 'var(--text)',
|
|
908
|
+
// fontWeight: checked ? '500' : '400',
|
|
909
|
+
// }}
|
|
910
|
+
// >
|
|
911
|
+
// {label}{required && ' *'}
|
|
912
|
+
// </span>
|
|
913
|
+
// )}
|
|
914
|
+
// </label>
|
|
915
|
+
// );
|
|
916
|
+
// };
|
|
917
|
+
// // Custom Radio Component (unchanged)
|
|
918
|
+
// const FormRadio: React.FC<{
|
|
919
|
+
// label?: string;
|
|
920
|
+
// checked: boolean;
|
|
921
|
+
// onChange: (checked: boolean) => void;
|
|
922
|
+
// disabled?: boolean;
|
|
923
|
+
// required?: boolean;
|
|
924
|
+
// value?: string;
|
|
925
|
+
// id?: string;
|
|
926
|
+
// }> = ({ label, checked, onChange, disabled, required, value, id }) => {
|
|
927
|
+
// return (
|
|
928
|
+
// <label
|
|
929
|
+
// className="funui_form-radio"
|
|
930
|
+
// style={{
|
|
931
|
+
// display: 'flex',
|
|
932
|
+
// alignItems: 'center',
|
|
933
|
+
// gap: '0.5rem',
|
|
934
|
+
// cursor: disabled ? 'not-allowed' : 'pointer',
|
|
935
|
+
// userSelect: 'none',
|
|
936
|
+
// width: 'fit-content',
|
|
937
|
+
// padding: '0.25rem 0',
|
|
938
|
+
// }}
|
|
939
|
+
// >
|
|
940
|
+
// <input
|
|
941
|
+
// type="radio"
|
|
942
|
+
// id={id}
|
|
943
|
+
// checked={checked}
|
|
944
|
+
// onChange={(e) => !disabled && onChange(e.target.checked)}
|
|
945
|
+
// disabled={disabled}
|
|
946
|
+
// required={required}
|
|
947
|
+
// value={value}
|
|
948
|
+
// style={{
|
|
949
|
+
// position: 'absolute',
|
|
950
|
+
// opacity: 0,
|
|
951
|
+
// width: 0,
|
|
952
|
+
// height: 0,
|
|
953
|
+
// pointerEvents: 'none'
|
|
954
|
+
// }}
|
|
955
|
+
// />
|
|
956
|
+
// <div
|
|
957
|
+
// className="funui_form-radio-circle"
|
|
958
|
+
// style={{
|
|
959
|
+
// width: '1.25rem',
|
|
960
|
+
// height: '1.25rem',
|
|
961
|
+
// border: checked ? '2px solid var(--primary)' : '2px solid var(--borderColor)',
|
|
962
|
+
// borderRadius: '50%',
|
|
963
|
+
// backgroundColor: 'transparent',
|
|
964
|
+
// position: 'relative',
|
|
965
|
+
// transition: 'all 0.2s ease',
|
|
966
|
+
// display: 'flex',
|
|
967
|
+
// alignItems: 'center',
|
|
968
|
+
// justifyContent: 'center',
|
|
969
|
+
// flexShrink: 0,
|
|
970
|
+
// }}
|
|
971
|
+
// >
|
|
972
|
+
// {checked && (
|
|
973
|
+
// <div
|
|
974
|
+
// style={{
|
|
975
|
+
// width: '0.75rem',
|
|
976
|
+
// height: '0.75rem',
|
|
977
|
+
// backgroundColor: 'var(--primary)',
|
|
978
|
+
// borderRadius: '50%',
|
|
979
|
+
// }}
|
|
980
|
+
// />
|
|
981
|
+
// )}
|
|
982
|
+
// </div>
|
|
983
|
+
// {label && (
|
|
984
|
+
// <span
|
|
985
|
+
// className="funui_form-radio-label"
|
|
986
|
+
// style={{
|
|
987
|
+
// fontSize: '0.875rem',
|
|
988
|
+
// color: disabled ? 'var(--text-muted)' : 'var(--text)',
|
|
989
|
+
// fontWeight: checked ? '500' : '400',
|
|
990
|
+
// }}
|
|
991
|
+
// >
|
|
992
|
+
// {label}{required && ' *'}
|
|
993
|
+
// </span>
|
|
994
|
+
// )}
|
|
995
|
+
// </label>
|
|
996
|
+
// );
|
|
997
|
+
// };
|
|
998
|
+
// // Function to format WhatsApp message - UPDATED with proper formatting
|
|
999
|
+
// const formatWhatsAppMessage = (
|
|
1000
|
+
// values: Record<string, any>,
|
|
1001
|
+
// fields: FormField[],
|
|
1002
|
+
// header?: string,
|
|
1003
|
+
// footer?: string
|
|
1004
|
+
// ): string => {
|
|
1005
|
+
// // Build message lines
|
|
1006
|
+
// let message = '';
|
|
1007
|
+
// // Add header if provided
|
|
1008
|
+
// if (header) {
|
|
1009
|
+
// message += `${header}\n\n`;
|
|
1010
|
+
// }
|
|
1011
|
+
// // Filter out empty/null/undefined values
|
|
1012
|
+
// const nonEmptyFields = fields.filter(field => {
|
|
1013
|
+
// const value = values[field.name];
|
|
1014
|
+
// // Skip if value is undefined, null, or empty string
|
|
1015
|
+
// if (value === undefined || value === null || value === '') {
|
|
1016
|
+
// return false;
|
|
1017
|
+
// }
|
|
1018
|
+
// // Skip if array is empty
|
|
1019
|
+
// if (Array.isArray(value) && value.length === 0) {
|
|
1020
|
+
// return false;
|
|
1021
|
+
// }
|
|
1022
|
+
// // Skip if checkbox is false
|
|
1023
|
+
// if (field.type === 'checkbox' && !field.multiple && value === false) {
|
|
1024
|
+
// return false;
|
|
1025
|
+
// }
|
|
1026
|
+
// return true;
|
|
1027
|
+
// });
|
|
1028
|
+
// // Format each field
|
|
1029
|
+
// const fieldLines = nonEmptyFields.map(field => {
|
|
1030
|
+
// const value = values[field.name];
|
|
1031
|
+
// let displayValue = value;
|
|
1032
|
+
// // Format array values (for multiple checkboxes)
|
|
1033
|
+
// if (Array.isArray(value)) {
|
|
1034
|
+
// displayValue = value.join(', ');
|
|
1035
|
+
// }
|
|
1036
|
+
// // Format checkbox values
|
|
1037
|
+
// if (field.type === 'checkbox' && !field.multiple) {
|
|
1038
|
+
// displayValue = value ? 'Yes' : 'No';
|
|
1039
|
+
// }
|
|
1040
|
+
// // Format select/radio values
|
|
1041
|
+
// if ((field.type === 'select' || field.type === 'radio') && field.options) {
|
|
1042
|
+
// const option = field.options.find(opt => opt.value === value);
|
|
1043
|
+
// displayValue = option ? option.label : value;
|
|
1044
|
+
// }
|
|
1045
|
+
// // Ensure displayValue is a string and preserve spaces/newlines
|
|
1046
|
+
// displayValue = String(displayValue);
|
|
1047
|
+
// // WhatsApp formatting:
|
|
1048
|
+
// // - Field label on its own line
|
|
1049
|
+
// // - Value on next line wrapped in backticks
|
|
1050
|
+
// // - Double newline between fields for readability
|
|
1051
|
+
// return `${field.label || field.name}\n\`${displayValue}\``;
|
|
1052
|
+
// });
|
|
1053
|
+
// // Join with double newline for spacing
|
|
1054
|
+
// message += fieldLines.join('\n\n');
|
|
1055
|
+
// // Add footer if provided
|
|
1056
|
+
// if (footer) {
|
|
1057
|
+
// message += `\n\n${footer}`;
|
|
1058
|
+
// }
|
|
1059
|
+
// return encodeURIComponent(message);
|
|
1060
|
+
// };
|
|
1061
|
+
// // Main Form Component - FIXED
|
|
1062
|
+
// const Form: React.FC<FormProps> = (props) => {
|
|
1063
|
+
// const {
|
|
1064
|
+
// fields: fieldsProp,
|
|
1065
|
+
// onSubmit: onSubmitProp,
|
|
1066
|
+
// defaultValues: defaultValuesProp = {},
|
|
1067
|
+
// submitText: submitTextProp = 'Submit',
|
|
1068
|
+
// submitBg: submitBgProp = 'primary',
|
|
1069
|
+
// submitPrefix: submitPrefixProp,
|
|
1070
|
+
// submitSuffix: submitSuffixProp,
|
|
1071
|
+
// resetText: resetTextProp = 'Reset',
|
|
1072
|
+
// showReset: showResetProp = true,
|
|
1073
|
+
// isLoading: isLoadingProp = false,
|
|
1074
|
+
// className: classNameProp = '',
|
|
1075
|
+
// layout: layoutProp = 'vertical',
|
|
1076
|
+
// gap: gapProp = '1.5rem',
|
|
1077
|
+
// title: titleProp,
|
|
1078
|
+
// titleSize: titleSizeProp,
|
|
1079
|
+
// titleColor: titleColorProp,
|
|
1080
|
+
// description: descriptionProp,
|
|
1081
|
+
// descriptionSize: descriptionSizeProp,
|
|
1082
|
+
// descriptionColor: descriptionColorProp,
|
|
1083
|
+
// whatsappContact: whatsappContactProp,
|
|
1084
|
+
// width: widthProp,
|
|
1085
|
+
// centered: centeredProp,
|
|
1086
|
+
// whatsappHeader: whatsappHeaderProp,
|
|
1087
|
+
// whatsappFooter: whatsappFooterProp,
|
|
1088
|
+
// fullWidth: fullWidthProp = true,
|
|
1089
|
+
// variant = '',
|
|
1090
|
+
// } = props;
|
|
1091
|
+
// // Use component configuration with variant
|
|
1092
|
+
// const { mergeWithLocal } = useComponentConfiguration('Form', variant);
|
|
1093
|
+
// // Create local props object
|
|
1094
|
+
// const localProps = {
|
|
1095
|
+
// fields: fieldsProp,
|
|
1096
|
+
// onSubmit: onSubmitProp,
|
|
1097
|
+
// defaultValues: defaultValuesProp,
|
|
1098
|
+
// submitText: submitTextProp,
|
|
1099
|
+
// submitBg: submitBgProp,
|
|
1100
|
+
// submitPrefix: submitPrefixProp,
|
|
1101
|
+
// submitSuffix: submitSuffixProp,
|
|
1102
|
+
// resetText: resetTextProp,
|
|
1103
|
+
// showReset: showResetProp,
|
|
1104
|
+
// isLoading: isLoadingProp,
|
|
1105
|
+
// className: classNameProp,
|
|
1106
|
+
// layout: layoutProp,
|
|
1107
|
+
// gap: gapProp,
|
|
1108
|
+
// title: titleProp,
|
|
1109
|
+
// titleSize: titleSizeProp,
|
|
1110
|
+
// titleColor: titleColorProp,
|
|
1111
|
+
// description: descriptionProp,
|
|
1112
|
+
// descriptionSize: descriptionSizeProp,
|
|
1113
|
+
// descriptionColor: descriptionColorProp,
|
|
1114
|
+
// whatsappContact: whatsappContactProp,
|
|
1115
|
+
// width: widthProp,
|
|
1116
|
+
// centered: centeredProp,
|
|
1117
|
+
// whatsappHeader: whatsappHeaderProp,
|
|
1118
|
+
// whatsappFooter: whatsappFooterProp,
|
|
1119
|
+
// fullWidth: fullWidthProp,
|
|
1120
|
+
// variant,
|
|
1121
|
+
// };
|
|
1122
|
+
// // Merge with theme configuration
|
|
1123
|
+
// const { props: mergedProps } = mergeWithLocal(localProps);
|
|
1124
|
+
// // Destructure with proper priority: local props override config props
|
|
1125
|
+
// const fields = fieldsProp !== undefined ? fieldsProp : mergedProps.fields;
|
|
1126
|
+
// const onSubmit = onSubmitProp !== undefined ? onSubmitProp : mergedProps.onSubmit;
|
|
1127
|
+
// const defaultValues = defaultValuesProp !== undefined ? defaultValuesProp : mergedProps.defaultValues;
|
|
1128
|
+
// const submitText = submitTextProp !== undefined ? submitTextProp : mergedProps.submitText;
|
|
1129
|
+
// const submitBg = submitBgProp !== undefined ? submitBgProp : mergedProps.submitBg;
|
|
1130
|
+
// const submitPrefix = submitPrefixProp !== undefined ? submitPrefixProp : mergedProps.submitPrefix;
|
|
1131
|
+
// const submitSuffix = submitSuffixProp !== undefined ? submitSuffixProp : mergedProps.submitSuffix;
|
|
1132
|
+
// const resetText = resetTextProp !== undefined ? resetTextProp : mergedProps.resetText;
|
|
1133
|
+
// const showReset = showResetProp !== undefined ? showResetProp : mergedProps.showReset;
|
|
1134
|
+
// const isLoading = isLoadingProp !== undefined ? isLoadingProp : mergedProps.isLoading;
|
|
1135
|
+
// const className = classNameProp !== undefined ? classNameProp : mergedProps.className;
|
|
1136
|
+
// const layout = layoutProp !== undefined ? layoutProp : mergedProps.layout;
|
|
1137
|
+
// const gap = gapProp !== undefined ? gapProp : mergedProps.gap;
|
|
1138
|
+
// const title = titleProp !== undefined ? titleProp : mergedProps.title;
|
|
1139
|
+
// const titleSize = titleSizeProp !== undefined ? titleSizeProp : mergedProps.titleSize;
|
|
1140
|
+
// const titleColor = titleColorProp !== undefined ? titleColorProp : mergedProps.titleColor;
|
|
1141
|
+
// const description = descriptionProp !== undefined ? descriptionProp : mergedProps.description;
|
|
1142
|
+
// const descriptionSize = descriptionSizeProp !== undefined ? descriptionSizeProp : mergedProps.descriptionSize;
|
|
1143
|
+
// const descriptionColor = descriptionColorProp !== undefined ? descriptionColorProp : mergedProps.descriptionColor;
|
|
1144
|
+
// const whatsappContact = whatsappContactProp !== undefined ? whatsappContactProp : mergedProps.whatsappContact;
|
|
1145
|
+
// const width = widthProp !== undefined ? widthProp : mergedProps.width;
|
|
1146
|
+
// const centered = centeredProp !== undefined ? centeredProp : mergedProps.centered;
|
|
1147
|
+
// const whatsappHeader = whatsappHeaderProp !== undefined ? whatsappHeaderProp : mergedProps.whatsappHeader;
|
|
1148
|
+
// const whatsappFooter = whatsappFooterProp !== undefined ? whatsappFooterProp : mergedProps.whatsappFooter;
|
|
1149
|
+
// const fullWidth = fullWidthProp !== undefined ? fullWidthProp : mergedProps.fullWidth;
|
|
1150
|
+
// // Parse JSON inputs
|
|
1151
|
+
// const parsedFields = useMemo(() => parseJsonInput(fields, [] as FormField[]), [fields]);
|
|
1152
|
+
// const parsedDefaultValues = useMemo(() => parseJsonInput(defaultValues, {} as Record<string, any>), [defaultValues]);
|
|
1153
|
+
// // State management
|
|
1154
|
+
// const [errors, setErrors] = useState<Record<string, string>>({});
|
|
1155
|
+
// const [touched, setTouched] = useState<Record<string, boolean>>({});
|
|
1156
|
+
// const [formValues, setFormValues] = useState<Record<string, any>>(() => {
|
|
1157
|
+
// // Initialize form values from defaultValues and field values
|
|
1158
|
+
// const initialValues: Record<string, any> = {};
|
|
1159
|
+
// parsedFields.forEach((field: any) => {
|
|
1160
|
+
// if (field.value !== undefined) {
|
|
1161
|
+
// initialValues[field.name] = field.value;
|
|
1162
|
+
// } else if (parsedDefaultValues[field.name] !== undefined) {
|
|
1163
|
+
// initialValues[field.name] = parsedDefaultValues[field.name];
|
|
1164
|
+
// } else {
|
|
1165
|
+
// // Set default empty values
|
|
1166
|
+
// if (field.type === 'checkbox' && field.multiple) {
|
|
1167
|
+
// initialValues[field.name] = [];
|
|
1168
|
+
// } else if (field.type === 'checkbox') {
|
|
1169
|
+
// initialValues[field.name] = false;
|
|
1170
|
+
// } else {
|
|
1171
|
+
// initialValues[field.name] = '';
|
|
1172
|
+
// }
|
|
1173
|
+
// }
|
|
1174
|
+
// });
|
|
1175
|
+
// return initialValues;
|
|
1176
|
+
// });
|
|
1177
|
+
// const [isSubmitting, setIsSubmitting] = useState(false);
|
|
1178
|
+
// // Update form values when defaultValues prop changes
|
|
1179
|
+
// useEffect(() => {
|
|
1180
|
+
// if (Object.keys(parsedDefaultValues).length > 0) {
|
|
1181
|
+
// setFormValues(prev => ({
|
|
1182
|
+
// ...prev,
|
|
1183
|
+
// ...parsedDefaultValues
|
|
1184
|
+
// }));
|
|
1185
|
+
// }
|
|
1186
|
+
// }, [parsedDefaultValues]);
|
|
1187
|
+
// // Validate a single field
|
|
1188
|
+
// const validateField = useCallback((field: FormField, value: any): string | null => {
|
|
1189
|
+
// // Required validation
|
|
1190
|
+
// if (field.required) {
|
|
1191
|
+
// if (value === undefined || value === null || value === '') {
|
|
1192
|
+
// return `${field.label || field.name} is required`;
|
|
1193
|
+
// }
|
|
1194
|
+
// if (field.type === 'checkbox' && field.multiple && Array.isArray(value) && value.length === 0) {
|
|
1195
|
+
// return `${field.label || field.name} is required`;
|
|
1196
|
+
// }
|
|
1197
|
+
// if (field.type === 'checkbox' && !field.multiple && value === false) {
|
|
1198
|
+
// return `${field.label || field.name} is required`;
|
|
1199
|
+
// }
|
|
1200
|
+
// }
|
|
1201
|
+
// // Type-specific validations (only for non-empty values)
|
|
1202
|
+
// if (value && (typeof value !== 'string' || value !== '')) {
|
|
1203
|
+
// // Email validation
|
|
1204
|
+
// if (field.type === 'email' && typeof value === 'string') {
|
|
1205
|
+
// const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
1206
|
+
// if (!emailRegex.test(value)) {
|
|
1207
|
+
// return 'Please enter a valid email address';
|
|
1208
|
+
// }
|
|
1209
|
+
// }
|
|
1210
|
+
// // Number validation
|
|
1211
|
+
// if (field.type === 'number') {
|
|
1212
|
+
// let numValue: number;
|
|
1213
|
+
// if (typeof value === 'string') {
|
|
1214
|
+
// numValue = parseFloat(value);
|
|
1215
|
+
// } else if (typeof value === 'number') {
|
|
1216
|
+
// numValue = value;
|
|
1217
|
+
// } else {
|
|
1218
|
+
// return 'Please enter a valid number';
|
|
1219
|
+
// }
|
|
1220
|
+
// if (isNaN(numValue)) {
|
|
1221
|
+
// return 'Please enter a valid number';
|
|
1222
|
+
// }
|
|
1223
|
+
// const min = field.inputProps?.min;
|
|
1224
|
+
// const max = field.inputProps?.max;
|
|
1225
|
+
// if (min !== undefined && numValue < parseFloat(min.toString())) {
|
|
1226
|
+
// return `Minimum value is ${min}`;
|
|
1227
|
+
// }
|
|
1228
|
+
// if (max !== undefined && numValue > parseFloat(max.toString())) {
|
|
1229
|
+
// return `Maximum value is ${max}`;
|
|
1230
|
+
// }
|
|
1231
|
+
// }
|
|
1232
|
+
// // Phone validation (basic) - only for strings
|
|
1233
|
+
// if (field.type === 'tel' && typeof value === 'string') {
|
|
1234
|
+
// const phoneRegex = /^[\+]?[1-9][\d]{0,17}$/;
|
|
1235
|
+
// if (!phoneRegex.test(value.replace(/[\s+\-()]/g, ''))) {
|
|
1236
|
+
// return 'Please enter a valid phone number';
|
|
1237
|
+
// }
|
|
1238
|
+
// }
|
|
1239
|
+
// // Length validation for strings
|
|
1240
|
+
// if (typeof value === 'string') {
|
|
1241
|
+
// const minLength = field.inputProps?.minLength;
|
|
1242
|
+
// const maxLength = field.inputProps?.maxLength;
|
|
1243
|
+
// if (minLength && value.length < minLength) {
|
|
1244
|
+
// return `Minimum ${minLength} characters required`;
|
|
1245
|
+
// }
|
|
1246
|
+
// if (maxLength && value.length > maxLength) {
|
|
1247
|
+
// return `Maximum ${maxLength} characters allowed`;
|
|
1248
|
+
// }
|
|
1249
|
+
// }
|
|
1250
|
+
// // Pattern validation if provided - only for strings
|
|
1251
|
+
// if (field.inputProps?.pattern && typeof value === 'string') {
|
|
1252
|
+
// try {
|
|
1253
|
+
// const regex = new RegExp(field.inputProps.pattern);
|
|
1254
|
+
// if (!regex.test(value)) {
|
|
1255
|
+
// return 'Invalid format';
|
|
1256
|
+
// }
|
|
1257
|
+
// } catch (error) {
|
|
1258
|
+
// console.warn('Invalid regex pattern:', field.inputProps.pattern);
|
|
1259
|
+
// }
|
|
1260
|
+
// }
|
|
1261
|
+
// }
|
|
1262
|
+
// return null;
|
|
1263
|
+
// }, []);
|
|
1264
|
+
// // Validate form
|
|
1265
|
+
// const validateForm = useCallback((): boolean => {
|
|
1266
|
+
// const newErrors: Record<string, string> = {};
|
|
1267
|
+
// let hasErrors = false;
|
|
1268
|
+
// parsedFields.forEach((field: any) => {
|
|
1269
|
+
// const value = formValues[field.name];
|
|
1270
|
+
// const error = validateField(field, value);
|
|
1271
|
+
// if (error) {
|
|
1272
|
+
// newErrors[field.name] = error;
|
|
1273
|
+
// hasErrors = true;
|
|
1274
|
+
// }
|
|
1275
|
+
// });
|
|
1276
|
+
// setErrors(newErrors);
|
|
1277
|
+
// return !hasErrors;
|
|
1278
|
+
// }, [parsedFields, validateField, formValues]);
|
|
1279
|
+
// // Handle field change for checkboxes and radios
|
|
1280
|
+
// const handleFieldChange = useCallback((fieldName: string, newValue: any) => {
|
|
1281
|
+
// // Update form values
|
|
1282
|
+
// setFormValues(prev => ({
|
|
1283
|
+
// ...prev,
|
|
1284
|
+
// [fieldName]: newValue
|
|
1285
|
+
// }));
|
|
1286
|
+
// // Update touched state
|
|
1287
|
+
// setTouched(prev => ({ ...prev, [fieldName]: true }));
|
|
1288
|
+
// // Validate the changed field
|
|
1289
|
+
// const field = parsedFields.find((f: any) => f.name === fieldName);
|
|
1290
|
+
// if (!field) return;
|
|
1291
|
+
// const error = validateField(field, newValue);
|
|
1292
|
+
// setErrors(prev => {
|
|
1293
|
+
// if (error) {
|
|
1294
|
+
// return { ...prev, [fieldName]: error };
|
|
1295
|
+
// } else {
|
|
1296
|
+
// const newErrors = { ...prev };
|
|
1297
|
+
// delete newErrors[fieldName];
|
|
1298
|
+
// return newErrors;
|
|
1299
|
+
// }
|
|
1300
|
+
// });
|
|
1301
|
+
// }, [parsedFields, validateField]);
|
|
1302
|
+
// // FIXED: Handle input change - pass event directly to Input component
|
|
1303
|
+
// const handleInputEventChange = useCallback((e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => {
|
|
1304
|
+
// const fieldName = e.target.name;
|
|
1305
|
+
// const value = e.target.value;
|
|
1306
|
+
// // Update form values - PASS VALUE AS-IS (preserves spaces)
|
|
1307
|
+
// setFormValues(prev => ({
|
|
1308
|
+
// ...prev,
|
|
1309
|
+
// [fieldName]: value
|
|
1310
|
+
// }));
|
|
1311
|
+
// // Update touched state
|
|
1312
|
+
// setTouched(prev => ({ ...prev, [fieldName]: true }));
|
|
1313
|
+
// // Validate the changed field
|
|
1314
|
+
// const field = parsedFields.find((f: any) => f.name === fieldName);
|
|
1315
|
+
// if (!field) return;
|
|
1316
|
+
// const error = validateField(field, value);
|
|
1317
|
+
// setErrors(prev => {
|
|
1318
|
+
// if (error) {
|
|
1319
|
+
// return { ...prev, [fieldName]: error };
|
|
1320
|
+
// } else {
|
|
1321
|
+
// const newErrors = { ...prev };
|
|
1322
|
+
// delete newErrors[fieldName];
|
|
1323
|
+
// return newErrors;
|
|
1324
|
+
// }
|
|
1325
|
+
// });
|
|
1326
|
+
// }, [parsedFields, validateField]);
|
|
1327
|
+
// // FIXED: Handle blur event - pass event directly to Input component
|
|
1328
|
+
// const handleInputEventBlur = useCallback((e: React.FocusEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => {
|
|
1329
|
+
// const fieldName = e.target.name;
|
|
1330
|
+
// setTouched(prev => ({ ...prev, [fieldName]: true }));
|
|
1331
|
+
// // Validate the field
|
|
1332
|
+
// const field = parsedFields.find((f: any) => f.name === fieldName);
|
|
1333
|
+
// if (!field) return;
|
|
1334
|
+
// const value = formValues[fieldName];
|
|
1335
|
+
// const error = validateField(field, value);
|
|
1336
|
+
// setErrors(prev => {
|
|
1337
|
+
// if (error) {
|
|
1338
|
+
// return { ...prev, [fieldName]: error };
|
|
1339
|
+
// } else {
|
|
1340
|
+
// const newErrors = { ...prev };
|
|
1341
|
+
// delete newErrors[fieldName];
|
|
1342
|
+
// return newErrors;
|
|
1343
|
+
// }
|
|
1344
|
+
// });
|
|
1345
|
+
// }, [parsedFields, validateField, formValues]);
|
|
1346
|
+
// // Handle form submission
|
|
1347
|
+
// const handleSubmit = useCallback(async (e: React.FormEvent) => {
|
|
1348
|
+
// e.preventDefault();
|
|
1349
|
+
// // Mark all fields as touched
|
|
1350
|
+
// const allTouched: Record<string, boolean> = {};
|
|
1351
|
+
// parsedFields.forEach((field: any) => {
|
|
1352
|
+
// allTouched[field.name] = true;
|
|
1353
|
+
// });
|
|
1354
|
+
// setTouched(allTouched);
|
|
1355
|
+
// // Validate form
|
|
1356
|
+
// const isValid = validateForm();
|
|
1357
|
+
// if (!isValid) {
|
|
1358
|
+
// // Scroll to first error
|
|
1359
|
+
// const firstErrorField = Object.keys(errors)[0];
|
|
1360
|
+
// if (firstErrorField) {
|
|
1361
|
+
// const element = document.getElementById(`form-field-${firstErrorField}`);
|
|
1362
|
+
// element?.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
1363
|
+
// }
|
|
1364
|
+
// return;
|
|
1365
|
+
// }
|
|
1366
|
+
// // Get form data and submit
|
|
1367
|
+
// setIsSubmitting(true);
|
|
1368
|
+
// try {
|
|
1369
|
+
// if (whatsappContact) {
|
|
1370
|
+
// // Submit via WhatsApp
|
|
1371
|
+
// const message = formatWhatsAppMessage(formValues, parsedFields, whatsappHeader, whatsappFooter);
|
|
1372
|
+
// const cleanPhone = whatsappContact.replace(/[\s+\-()]/g, '');
|
|
1373
|
+
// const whatsappUrl = `https://wa.me/${cleanPhone}?text=${message}`;
|
|
1374
|
+
// window.open(whatsappUrl, '_blank');
|
|
1375
|
+
// // Still call onSubmit if provided
|
|
1376
|
+
// if (onSubmit) {
|
|
1377
|
+
// await onSubmit(formValues, true);
|
|
1378
|
+
// }
|
|
1379
|
+
// } else {
|
|
1380
|
+
// // Regular submission
|
|
1381
|
+
// if (onSubmit) {
|
|
1382
|
+
// await onSubmit(formValues, false);
|
|
1383
|
+
// }
|
|
1384
|
+
// }
|
|
1385
|
+
// } catch (error) {
|
|
1386
|
+
// console.error('Form submission error:', error);
|
|
1387
|
+
// setErrors(prev => ({
|
|
1388
|
+
// ...prev,
|
|
1389
|
+
// _form: 'There was an error submitting the form. Please try again.'
|
|
1390
|
+
// }));
|
|
1391
|
+
// } finally {
|
|
1392
|
+
// setIsSubmitting(false);
|
|
1393
|
+
// }
|
|
1394
|
+
// }, [parsedFields, validateForm, formValues, whatsappContact, whatsappHeader, whatsappFooter, onSubmit, errors]);
|
|
1395
|
+
// // Handle form reset
|
|
1396
|
+
// const handleReset = useCallback(() => {
|
|
1397
|
+
// // Reset to initial values
|
|
1398
|
+
// const initialValues: Record<string, any> = {};
|
|
1399
|
+
// parsedFields.forEach((field: any) => {
|
|
1400
|
+
// if (field.value !== undefined) {
|
|
1401
|
+
// initialValues[field.name] = field.value;
|
|
1402
|
+
// } else if (parsedDefaultValues[field.name] !== undefined) {
|
|
1403
|
+
// initialValues[field.name] = parsedDefaultValues[field.name];
|
|
1404
|
+
// } else {
|
|
1405
|
+
// if (field.type === 'checkbox' && field.multiple) {
|
|
1406
|
+
// initialValues[field.name] = [];
|
|
1407
|
+
// } else if (field.type === 'checkbox') {
|
|
1408
|
+
// initialValues[field.name] = false;
|
|
1409
|
+
// } else {
|
|
1410
|
+
// initialValues[field.name] = '';
|
|
1411
|
+
// }
|
|
1412
|
+
// }
|
|
1413
|
+
// });
|
|
1414
|
+
// setFormValues(initialValues);
|
|
1415
|
+
// setErrors({});
|
|
1416
|
+
// setTouched({});
|
|
1417
|
+
// }, [parsedFields, parsedDefaultValues]);
|
|
1418
|
+
// // Get field status for Input component
|
|
1419
|
+
// const getFieldStatus = useCallback((fieldName: string): 'success' | 'warning' | 'danger' | 'info' | undefined => {
|
|
1420
|
+
// const error = errors[fieldName];
|
|
1421
|
+
// const isTouched = touched[fieldName];
|
|
1422
|
+
// if (error) return 'danger';
|
|
1423
|
+
// if (isTouched && !error && formValues[fieldName] !== '') {
|
|
1424
|
+
// return 'success';
|
|
1425
|
+
// }
|
|
1426
|
+
// return undefined;
|
|
1427
|
+
// }, [errors, touched, formValues]);
|
|
1428
|
+
// // Check if form is valid for submission
|
|
1429
|
+
// const isFormValid = useMemo(() => {
|
|
1430
|
+
// // Check if any required fields are empty
|
|
1431
|
+
// const hasEmptyRequiredFields = parsedFields.some((field: any) => {
|
|
1432
|
+
// if (!field.required) return false;
|
|
1433
|
+
// const value = formValues[field.name];
|
|
1434
|
+
// if (field.type === 'checkbox' && field.multiple) {
|
|
1435
|
+
// return !Array.isArray(value) || value.length === 0;
|
|
1436
|
+
// }
|
|
1437
|
+
// if (field.type === 'checkbox') {
|
|
1438
|
+
// return value === false;
|
|
1439
|
+
// }
|
|
1440
|
+
// return !value || value === '';
|
|
1441
|
+
// });
|
|
1442
|
+
// // Check if there are any validation errors
|
|
1443
|
+
// const hasValidationErrors = Object.keys(errors).length > 0;
|
|
1444
|
+
// return !hasEmptyRequiredFields && !hasValidationErrors;
|
|
1445
|
+
// }, [parsedFields, formValues, errors]);
|
|
1446
|
+
// // Submit button disabled state
|
|
1447
|
+
// const isSubmitDisabled = isSubmitting || isLoading || !isFormValid;
|
|
1448
|
+
// // Check if WhatsApp is configured
|
|
1449
|
+
// const hasWhatsApp = !!whatsappContact;
|
|
1450
|
+
// // Render field based on type - FIXED
|
|
1451
|
+
// const renderField = useCallback((field: FormField) => {
|
|
1452
|
+
// const status = getFieldStatus(field.name);
|
|
1453
|
+
// const error = errors[field.name];
|
|
1454
|
+
// const isTouched = touched[field.name];
|
|
1455
|
+
// const showError = error && isTouched;
|
|
1456
|
+
// const value = formValues[field.name];
|
|
1457
|
+
// // Field wrapper classes
|
|
1458
|
+
// const wrapperClass = `col min-w-200 field ${showError ? 'field-error' : ''}`.trim();
|
|
1459
|
+
// // Helper text (error takes priority)
|
|
1460
|
+
// const helperText = showError ? error : field.helperText;
|
|
1461
|
+
// // Generate unique ID for the input
|
|
1462
|
+
// const inputId = field.inputProps?.id || `form-field-${field.name}`;
|
|
1463
|
+
// // Base props for Input component
|
|
1464
|
+
// const baseProps: any = {
|
|
1465
|
+
// id: inputId,
|
|
1466
|
+
// name: field.name, // IMPORTANT: Make sure name is passed
|
|
1467
|
+
// label: field.label,
|
|
1468
|
+
// placeholder: field.placeholder,
|
|
1469
|
+
// helperText: helperText,
|
|
1470
|
+
// disabled: field.disabled || isLoading,
|
|
1471
|
+
// fullWidth: fullWidth,
|
|
1472
|
+
// ...field.inputProps,
|
|
1473
|
+
// };
|
|
1474
|
+
// // Only add status if it's not undefined
|
|
1475
|
+
// if (status !== undefined) {
|
|
1476
|
+
// baseProps.status = status;
|
|
1477
|
+
// }
|
|
1478
|
+
// // Render based on field type
|
|
1479
|
+
// switch (field.type) {
|
|
1480
|
+
// case 'checkbox':
|
|
1481
|
+
// if (field.options?.length) {
|
|
1482
|
+
// // Multiple checkboxes (checkbox group)
|
|
1483
|
+
// const checkedValues = Array.isArray(value) ? value : [];
|
|
1484
|
+
// return (
|
|
1485
|
+
// <div key={field.name} className={wrapperClass}>
|
|
1486
|
+
// {field.label && (
|
|
1487
|
+
// <div className="form-label" style={{ marginBottom: '0.5rem' }}>
|
|
1488
|
+
// <Text text={field.label + (field.required ? ' *' : '')} size="sm" color="text" bold />
|
|
1489
|
+
// </div>
|
|
1490
|
+
// )}
|
|
1491
|
+
// <Flex direction="column" gap="0.5rem">
|
|
1492
|
+
// {field.options.map((option, index) => {
|
|
1493
|
+
// const isChecked = checkedValues.includes(option.value);
|
|
1494
|
+
// return (
|
|
1495
|
+
// <FormCheckbox
|
|
1496
|
+
// key={`${field.name}_${index}`}
|
|
1497
|
+
// id={`${inputId}_${index}`}
|
|
1498
|
+
// label={option.label}
|
|
1499
|
+
// checked={isChecked}
|
|
1500
|
+
// onChange={(checked) => {
|
|
1501
|
+
// if (checked) {
|
|
1502
|
+
// // Add value to array
|
|
1503
|
+
// const newValues = [...checkedValues, option.value];
|
|
1504
|
+
// handleFieldChange(field.name, newValues);
|
|
1505
|
+
// } else {
|
|
1506
|
+
// // Remove value from array
|
|
1507
|
+
// const newValues = checkedValues.filter(v => v !== option.value);
|
|
1508
|
+
// handleFieldChange(field.name, newValues);
|
|
1509
|
+
// }
|
|
1510
|
+
// }}
|
|
1511
|
+
// disabled={field.disabled || option.disabled || isLoading}
|
|
1512
|
+
// required={field.required && index === 0}
|
|
1513
|
+
// value={option.value}
|
|
1514
|
+
// />
|
|
1515
|
+
// );
|
|
1516
|
+
// })}
|
|
1517
|
+
// </Flex>
|
|
1518
|
+
// </div>
|
|
1519
|
+
// );
|
|
1520
|
+
// } else {
|
|
1521
|
+
// // Single checkbox (boolean)
|
|
1522
|
+
// return (
|
|
1523
|
+
// <div key={field.name} className={wrapperClass}>
|
|
1524
|
+
// <FormCheckbox
|
|
1525
|
+
// label={field.label}
|
|
1526
|
+
// checked={!!value}
|
|
1527
|
+
// onChange={(checked) => handleFieldChange(field.name, checked)}
|
|
1528
|
+
// disabled={field.disabled || isLoading}
|
|
1529
|
+
// required={field.required}
|
|
1530
|
+
// id={inputId}
|
|
1531
|
+
// />
|
|
1532
|
+
// </div>
|
|
1533
|
+
// );
|
|
1534
|
+
// }
|
|
1535
|
+
// case 'radio':
|
|
1536
|
+
// if (!field.options?.length) return null;
|
|
1537
|
+
// return (
|
|
1538
|
+
// <div key={field.name} className={wrapperClass}>
|
|
1539
|
+
// {field.label && (
|
|
1540
|
+
// <div className="form-label" style={{ marginBottom: '0.5rem' }}>
|
|
1541
|
+
// <Text text={field.label + (field.required ? ' *' : '')} size="sm" color="text" bold />
|
|
1542
|
+
// </div>
|
|
1543
|
+
// )}
|
|
1544
|
+
// <Flex direction="column" gap="0.5rem">
|
|
1545
|
+
// {field.options.map((option, index) => (
|
|
1546
|
+
// <FormRadio
|
|
1547
|
+
// key={`${field.name}_${index}`}
|
|
1548
|
+
// id={`${inputId}_${index}`}
|
|
1549
|
+
// label={option.label}
|
|
1550
|
+
// checked={value === option.value}
|
|
1551
|
+
// onChange={() => handleFieldChange(field.name, option.value)}
|
|
1552
|
+
// disabled={field.disabled || option.disabled || isLoading}
|
|
1553
|
+
// required={field.required && index === 0}
|
|
1554
|
+
// value={option.value}
|
|
1555
|
+
// />
|
|
1556
|
+
// ))}
|
|
1557
|
+
// </Flex>
|
|
1558
|
+
// </div>
|
|
1559
|
+
// );
|
|
1560
|
+
// case 'textarea':
|
|
1561
|
+
// return (
|
|
1562
|
+
// <div key={field.name} className={wrapperClass}>
|
|
1563
|
+
// <Input
|
|
1564
|
+
// multiline
|
|
1565
|
+
// rows={field.inputProps?.rows || 4}
|
|
1566
|
+
// value={value || ''}
|
|
1567
|
+
// onChange={handleInputEventChange} // FIXED: Pass event handler directly
|
|
1568
|
+
// onBlur={handleInputEventBlur} // FIXED: Pass event handler directly
|
|
1569
|
+
// {...baseProps}
|
|
1570
|
+
// />
|
|
1571
|
+
// </div>
|
|
1572
|
+
// );
|
|
1573
|
+
// case 'select':
|
|
1574
|
+
// return (
|
|
1575
|
+
// <div key={field.name} className={wrapperClass}>
|
|
1576
|
+
// <Input
|
|
1577
|
+
// select
|
|
1578
|
+
// options={field.options?.map(opt => ({ text: opt.label, value: opt.value })) || []}
|
|
1579
|
+
// value={value || ''}
|
|
1580
|
+
// onChange={handleInputEventChange} // FIXED: Pass event handler directly
|
|
1581
|
+
// onBlur={handleInputEventBlur} // FIXED: Pass event handler directly
|
|
1582
|
+
// {...baseProps}
|
|
1583
|
+
// />
|
|
1584
|
+
// </div>
|
|
1585
|
+
// );
|
|
1586
|
+
// default:
|
|
1587
|
+
// // text, email, number, tel, date, file, password
|
|
1588
|
+
// return (
|
|
1589
|
+
// <div key={field.name} className={wrapperClass}>
|
|
1590
|
+
// <Input
|
|
1591
|
+
// type={field.type}
|
|
1592
|
+
// value={value || ''}
|
|
1593
|
+
// onChange={handleInputEventChange} // FIXED: Pass event handler directly
|
|
1594
|
+
// onBlur={handleInputEventBlur} // FIXED: Pass event handler directly
|
|
1595
|
+
// {...baseProps}
|
|
1596
|
+
// />
|
|
1597
|
+
// </div>
|
|
1598
|
+
// );
|
|
1599
|
+
// }
|
|
1600
|
+
// }, [errors, touched, formValues, isLoading, getFieldStatus, handleFieldChange, handleInputEventChange, handleInputEventBlur, fullWidth]);
|
|
1601
|
+
// // Don't render if no fields are configured
|
|
1602
|
+
// if (parsedFields.length === 0) {
|
|
1603
|
+
// console.warn('Form: No fields configured. Please provide fields prop or configure via theme.');
|
|
1604
|
+
// return null;
|
|
1605
|
+
// }
|
|
1606
|
+
// return (
|
|
1607
|
+
// <div className={`form-wrapper ${centered ? 'center' : ''} ${className}`} style={{ width: "100%", maxWidth: width || "450px" }}>
|
|
1608
|
+
// {/* Title Section */}
|
|
1609
|
+
// {title && (
|
|
1610
|
+
// <div className="form-header" style={{ marginBottom: '2rem' }}>
|
|
1611
|
+
// <Text
|
|
1612
|
+
// text={title}
|
|
1613
|
+
// size={titleSize || "3xl"}
|
|
1614
|
+
// color={titleColor || ""}
|
|
1615
|
+
// block
|
|
1616
|
+
// />
|
|
1617
|
+
// {description && (
|
|
1618
|
+
// <Text article
|
|
1619
|
+
// size={descriptionSize || "sm"}
|
|
1620
|
+
// color={descriptionColor || ""}
|
|
1621
|
+
// >
|
|
1622
|
+
// <div
|
|
1623
|
+
// className="article text-sm"
|
|
1624
|
+
// dangerouslySetInnerHTML={{ __html: description }}
|
|
1625
|
+
// />
|
|
1626
|
+
// </Text>
|
|
1627
|
+
// )}
|
|
1628
|
+
// </div>
|
|
1629
|
+
// )}
|
|
1630
|
+
// <form
|
|
1631
|
+
// className="form"
|
|
1632
|
+
// onSubmit={handleSubmit}
|
|
1633
|
+
// style={{ width: '100%' }}
|
|
1634
|
+
// >
|
|
1635
|
+
// {/* Form fields wrapped in Flex */}
|
|
1636
|
+
// <Flex
|
|
1637
|
+
// direction={layout === 'horizontal' ? 'row' : 'column'}
|
|
1638
|
+
// gap={gap}
|
|
1639
|
+
// width='100%'
|
|
1640
|
+
// >
|
|
1641
|
+
// {parsedFields.map(renderField)}
|
|
1642
|
+
// </Flex>
|
|
1643
|
+
// {/* Form actions - SINGLE BUTTON */}
|
|
1644
|
+
// <Flex direction="column" gap="1rem" style={{ marginTop: '2rem', width: fullWidth ? '100%' : undefined }}>
|
|
1645
|
+
// {/* Single submit button */}
|
|
1646
|
+
// <Button
|
|
1647
|
+
// type="submit"
|
|
1648
|
+
// text={hasWhatsApp ? `Send via WhatsApp` : submitText}
|
|
1649
|
+
// bg={submitBg || "primary"}
|
|
1650
|
+
// raised
|
|
1651
|
+
// prefix={submitPrefix || hasWhatsApp ? <PiWhatsappLogo /> : <PiPaperPlaneTilt />}
|
|
1652
|
+
// suffix={submitSuffix}
|
|
1653
|
+
// disabled={isSubmitDisabled}
|
|
1654
|
+
// isLoading={isSubmitting || isLoading}
|
|
1655
|
+
// fullWidth={fullWidth}
|
|
1656
|
+
// />
|
|
1657
|
+
// </Flex>
|
|
1658
|
+
// </form>
|
|
1659
|
+
// </div>
|
|
1660
|
+
// );
|
|
1661
|
+
// };
|
|
1662
|
+
// export default Form;
|