diff --git a/src/components/registration/DynamicFormField.js b/src/components/registration/DynamicFormField.js index 1f416d7..5e097f2 100644 --- a/src/components/registration/DynamicFormField.js +++ b/src/components/registration/DynamicFormField.js @@ -47,6 +47,15 @@ const DynamicFormField = ({ const hasError = errors.length > 0; const errorMessage = errors[0]; + const formatPhoneNumber = (rawValue) => { + const digits = String(rawValue || '').replace(/\D/g, '').slice(0, 10); + if (digits.length <= 3) return digits; + if (digits.length <= 6) { + return `(${digits.slice(0, 3)}) ${digits.slice(3)}`; + } + return `(${digits.slice(0, 3)}) ${digits.slice(3, 6)}-${digits.slice(6)}`; + }; + // Common input className const inputClassName = `h-14 rounded-xl border-2 ${ hasError @@ -59,6 +68,11 @@ const DynamicFormField = ({ const { value: newValue, type: inputType, checked } = e.target; if (inputType === 'checkbox') { onChange(id, checked); + return; + } + if (type === 'phone') { + onChange(id, formatPhoneNumber(newValue)); + return; } else { onChange(id, newValue); } @@ -111,6 +125,8 @@ const DynamicFormField = ({ value={value || ''} onChange={handleInputChange} placeholder={placeholder} + inputMode={type === 'phone' ? 'numeric' : undefined} + maxLength={type === 'phone' ? 14 : undefined} className={inputClassName} data-testid={`field-${id}`} /> diff --git a/src/pages/admin/AdminRegistrationBuilder.js b/src/pages/admin/AdminRegistrationBuilder.js index 18ee294..104c60d 100644 --- a/src/pages/admin/AdminRegistrationBuilder.js +++ b/src/pages/admin/AdminRegistrationBuilder.js @@ -51,6 +51,7 @@ import { Zap, Copy, X, + Grip } from 'lucide-react'; // Field type icons @@ -319,11 +320,11 @@ const AdminRegistrationBuilder = () => { steps: prev.steps.map((s) => s.id === selectedStep ? { - ...s, - sections: s.sections - .filter((sec) => sec.id !== sectionId) - .map((sec, idx) => ({ ...sec, order: idx + 1 })), - } + ...s, + sections: s.sections + .filter((sec) => sec.id !== sectionId) + .map((sec, idx) => ({ ...sec, order: idx + 1 })), + } : s ), })); @@ -361,13 +362,13 @@ const AdminRegistrationBuilder = () => { steps: prev.steps.map((s) => s.id === selectedStep ? { - ...s, - sections: s.sections.map((sec) => - sec.id === selectedSection - ? { ...sec, fields: [...(sec.fields || []), newField] } - : sec - ), - } + ...s, + sections: s.sections.map((sec) => + sec.id === selectedSection + ? { ...sec, fields: [...(sec.fields || []), newField] } + : sec + ), + } : s ), })); @@ -395,18 +396,18 @@ const AdminRegistrationBuilder = () => { steps: prev.steps.map((s) => s.id === selectedStep ? { - ...s, - sections: s.sections.map((sec) => - sec.id === selectedSection - ? { - ...sec, - fields: sec.fields - .filter((f) => f.id !== fieldId) - .map((f, idx) => ({ ...f, order: idx + 1 })), - } - : sec - ), - } + ...s, + sections: s.sections.map((sec) => + sec.id === selectedSection + ? { + ...sec, + fields: sec.fields + .filter((f) => f.id !== fieldId) + .map((f, idx) => ({ ...f, order: idx + 1 })), + } + : sec + ), + } : s ), })); @@ -423,18 +424,18 @@ const AdminRegistrationBuilder = () => { steps: prev.steps.map((s) => s.id === selectedStep ? { - ...s, - sections: s.sections.map((sec) => - sec.id === selectedSection - ? { - ...sec, - fields: sec.fields.map((f) => - f.id === fieldId ? { ...f, ...updates } : f - ), - } - : sec - ), - } + ...s, + sections: s.sections.map((sec) => + sec.id === selectedSection + ? { + ...sec, + fields: sec.fields.map((f) => + f.id === fieldId ? { ...f, ...updates } : f + ), + } + : sec + ), + } : s ), })); @@ -492,132 +493,137 @@ const AdminRegistrationBuilder = () => { )} {/* Main Builder Layout */} -
- {/* Left Sidebar - Steps & Sections */} -
- -
-

Steps

- -
+ {/* Left Sidebar - Steps & Sections */} +
+ +
+

Steps

+ +
-
- {sortedSteps.map((step, index) => ( -
+ {sortedSteps.map((step, index) => ( +
{ + setSelectedStep(step.id); + setSelectedSection(null); + setSelectedField(null); + }} + > +
+
+
Step:
+ {step.title} +
+ {/* Mod Buttons */} +
+ {/* + */} + +
+
+
+ ))} +
+ + {/* Sections for selected step */} + {currentStep && ( + <> +
+

Sections

+ +
+ +
+ {sortedSections.map((section) => ( +
{ - setSelectedStep(step.id); - setSelectedSection(null); - setSelectedField(null); - }} - > -
-
- - {step.title} -
-
- - + }`} + onClick={() => { + setSelectedSection(section.id); + setSelectedField(null); + }} + > +
+ {section.title}
-
- ))} -
- - {/* Sections for selected step */} - {currentStep && ( - <> -
-

Sections

- -
- -
- {sortedSections.map((section) => ( -
{ - setSelectedSection(section.id); - setSelectedField(null); - }} - > -
- {section.title} - -
-
- ))} -
- - )} - -
+ ))} +
+ + )} +
+
+
{/* Center - Form Canvas */} -
+
+ +
-

- {currentStep?.title || 'Select a step'} -

+
+ + +

+ {currentStep?.title || 'Select a step'} +

+
{selectedSection && ( -
-
- {schema?.conditional_rules?.length || 0} conditional rule(s) configured -
-
{/* Right Sidebar - Field Properties */} @@ -912,6 +900,23 @@ const AdminRegistrationBuilder = () => {
)} + {/* Conditional Rules */} + +
+
+ +

Conditional Rules

+
+ +
+ +
+ {schema?.conditional_rules?.length || 0} conditional rule(s) configured +
+
@@ -1120,13 +1125,12 @@ const AdminRegistrationBuilder = () => { .map((field) => (
- + { dataTestId="stat-rejected" /> - +