@bookinglab/booking-ui-react 1.4.0 → 1.6.0
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/README.md +118 -1
- package/dist/index.d.cts +88 -1
- package/dist/index.d.ts +88 -1
- package/dist/index.js +197 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +197 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -353,6 +353,7 @@ A form component for collecting contact details (first name, last name, email) a
|
|
|
353
353
|
| Prop | Type | Default | Description |
|
|
354
354
|
|------|------|---------|-------------|
|
|
355
355
|
| `questions` | `Question[]` | `[]` | Additional questions to render after the contact fields |
|
|
356
|
+
| `initialValues` | `ContactDetailsInitialValues` | `undefined` | Initial values for pre-populating the form |
|
|
356
357
|
| `onSubmit` | `(values: ContactDetailsValues) => void` | required | Callback fired on valid submission |
|
|
357
358
|
| `onChange` | `(values: Partial<ContactDetailsValues>, isValid: boolean) => void` | `undefined` | Callback fired on every field change |
|
|
358
359
|
| `submitLabel` | `string` | `"Submit"` | Text for the submit button |
|
|
@@ -399,7 +400,39 @@ interface ContactDetailsFieldSettings {
|
|
|
399
400
|
}
|
|
400
401
|
```
|
|
401
402
|
|
|
402
|
-
###
|
|
403
|
+
### Initial Values
|
|
404
|
+
|
|
405
|
+
Pre-populate the form with existing data using `initialValues`:
|
|
406
|
+
|
|
407
|
+
```tsx
|
|
408
|
+
<ContactDetailsForm
|
|
409
|
+
onSubmit={handleSubmit}
|
|
410
|
+
initialValues={{
|
|
411
|
+
firstName: 'Sarah',
|
|
412
|
+
lastName: 'Grey',
|
|
413
|
+
email: 'sarah@example.com',
|
|
414
|
+
questions: {
|
|
415
|
+
2: '5', // select option ID as string
|
|
416
|
+
7: 25, // number value
|
|
417
|
+
10: 'Wheelchair access needed',
|
|
418
|
+
12: true, // checkbox
|
|
419
|
+
},
|
|
420
|
+
}}
|
|
421
|
+
/>
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
```typescript
|
|
425
|
+
interface ContactDetailsInitialValues {
|
|
426
|
+
firstName?: string;
|
|
427
|
+
lastName?: string;
|
|
428
|
+
email?: string;
|
|
429
|
+
questions?: Record<number, string | number | boolean>;
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
When `reset()` is called via ref, the form restores to these initial values rather than empty fields.
|
|
434
|
+
|
|
435
|
+
|
|
403
436
|
|
|
404
437
|
Pass additional questions to render after the contact fields:
|
|
405
438
|
|
|
@@ -448,6 +481,85 @@ const formRef = useRef<ContactDetailsFormRef>(null);
|
|
|
448
481
|
|
|
449
482
|
---
|
|
450
483
|
|
|
484
|
+
## ResetPasswordForm
|
|
485
|
+
|
|
486
|
+
A reusable password reset form with current password, new password, and confirm new password fields. Includes built-in validation, customizable submit button text, and programmatic control via ref.
|
|
487
|
+
|
|
488
|
+
### Props
|
|
489
|
+
|
|
490
|
+
| Prop | Type | Default | Description |
|
|
491
|
+
|------|------|---------|-------------|
|
|
492
|
+
| `onSubmit` | `(values: ResetPasswordFormValues) => void` | required | Called with all 3 values on valid submit |
|
|
493
|
+
| `onChange` | `(values: Partial<ResetPasswordFormValues>, isValid: boolean) => void` | `undefined` | Called on every field change |
|
|
494
|
+
| `submitLabel` | `string` | `"Update Password"` | Text for the submit button |
|
|
495
|
+
| `validateOnBlur` | `boolean` | `true` | Whether to validate fields on blur |
|
|
496
|
+
| `className` | `string` | `""` | Class name for the form element |
|
|
497
|
+
| `classNames` | `ResetPasswordFormClassNames` | `undefined` | Custom class names for styling |
|
|
498
|
+
|
|
499
|
+
### Fields
|
|
500
|
+
|
|
501
|
+
| Field | Label | Required | Validation |
|
|
502
|
+
|-------|-------|----------|------------|
|
|
503
|
+
| `currentPassword` | Current Password | Yes | required |
|
|
504
|
+
| `newPassword` | New Password | Yes | required |
|
|
505
|
+
| `confirmNewPassword` | Confirm New Password | Yes | required, must match New Password |
|
|
506
|
+
|
|
507
|
+
### Usage
|
|
508
|
+
|
|
509
|
+
```tsx
|
|
510
|
+
import { useRef } from 'react';
|
|
511
|
+
import {
|
|
512
|
+
ResetPasswordForm,
|
|
513
|
+
ResetPasswordFormRef,
|
|
514
|
+
ResetPasswordFormValues,
|
|
515
|
+
} from '@bookinglab/booking-ui-react';
|
|
516
|
+
|
|
517
|
+
function MyComponent() {
|
|
518
|
+
const formRef = useRef<ResetPasswordFormRef>(null);
|
|
519
|
+
|
|
520
|
+
const handleSubmit = (values: ResetPasswordFormValues) => {
|
|
521
|
+
console.log('Password reset:', values);
|
|
522
|
+
// { currentPassword: '...', newPassword: '...', confirmNewPassword: '...' }
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
return (
|
|
526
|
+
<>
|
|
527
|
+
<ResetPasswordForm
|
|
528
|
+
ref={formRef}
|
|
529
|
+
onSubmit={handleSubmit}
|
|
530
|
+
submitLabel="Change Password"
|
|
531
|
+
/>
|
|
532
|
+
<button onClick={() => formRef.current?.reset()}>Reset</button>
|
|
533
|
+
</>
|
|
534
|
+
);
|
|
535
|
+
}
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
### Ref Methods
|
|
539
|
+
|
|
540
|
+
| Method | Description |
|
|
541
|
+
|--------|-------------|
|
|
542
|
+
| `reset()` | Clear all values, errors, and touched state |
|
|
543
|
+
| `setValues(values)` | Programmatically set field values |
|
|
544
|
+
|
|
545
|
+
### Styling
|
|
546
|
+
|
|
547
|
+
```tsx
|
|
548
|
+
<ResetPasswordForm
|
|
549
|
+
onSubmit={handleSubmit}
|
|
550
|
+
classNames={{
|
|
551
|
+
fieldWrapper: 'mb-6',
|
|
552
|
+
label: 'text-white font-bold',
|
|
553
|
+
input: 'border-2 border-gray-400 rounded-lg p-3',
|
|
554
|
+
inputError: 'border-red-500',
|
|
555
|
+
errorText: 'text-red-400 text-sm',
|
|
556
|
+
button: 'bg-primary text-white py-3 px-6 rounded-lg',
|
|
557
|
+
}}
|
|
558
|
+
/>
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
---
|
|
562
|
+
|
|
451
563
|
## Requirements
|
|
452
564
|
|
|
453
565
|
- React 17.0.0 or higher
|
|
@@ -480,7 +592,12 @@ import type {
|
|
|
480
592
|
ContactDetailsQuestionEntry,
|
|
481
593
|
ContactDetailsAnswerEntry,
|
|
482
594
|
ContactDetailsFieldSettings,
|
|
595
|
+
ContactDetailsInitialValues,
|
|
483
596
|
ContactFieldSettings,
|
|
597
|
+
ResetPasswordFormProps,
|
|
598
|
+
ResetPasswordFormRef,
|
|
599
|
+
ResetPasswordFormValues,
|
|
600
|
+
ResetPasswordFormClassNames,
|
|
484
601
|
} from '@bookinglab/booking-ui-react';
|
|
485
602
|
```
|
|
486
603
|
|
package/dist/index.d.cts
CHANGED
|
@@ -168,12 +168,27 @@ interface ContactDetailsFieldSettings {
|
|
|
168
168
|
lastName?: ContactFieldSettings;
|
|
169
169
|
email?: ContactFieldSettings;
|
|
170
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Initial values for pre-populating the form
|
|
173
|
+
*/
|
|
174
|
+
interface ContactDetailsInitialValues {
|
|
175
|
+
/** Initial first name value */
|
|
176
|
+
firstName?: string;
|
|
177
|
+
/** Initial last name value */
|
|
178
|
+
lastName?: string;
|
|
179
|
+
/** Initial email value */
|
|
180
|
+
email?: string;
|
|
181
|
+
/** Initial question values keyed by question ID */
|
|
182
|
+
questions?: Record<number, string | number | boolean>;
|
|
183
|
+
}
|
|
171
184
|
/**
|
|
172
185
|
* Props for the ContactDetailsForm component
|
|
173
186
|
*/
|
|
174
187
|
interface ContactDetailsFormProps {
|
|
175
188
|
/** Additional questions to render after the contact fields */
|
|
176
189
|
questions?: Question[];
|
|
190
|
+
/** Initial values for pre-populating the form fields */
|
|
191
|
+
initialValues?: ContactDetailsInitialValues;
|
|
177
192
|
/** Callback fired when form is submitted with valid values */
|
|
178
193
|
onSubmit: (values: ContactDetailsValues) => void;
|
|
179
194
|
/** Callback fired on every field change */
|
|
@@ -203,6 +218,58 @@ interface ContactDetailsFormRef {
|
|
|
203
218
|
}>) => void;
|
|
204
219
|
}
|
|
205
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Values emitted by the ResetPasswordForm on submit
|
|
223
|
+
*/
|
|
224
|
+
interface ResetPasswordFormValues {
|
|
225
|
+
currentPassword: string;
|
|
226
|
+
newPassword: string;
|
|
227
|
+
confirmNewPassword: string;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Custom class names for styling ResetPasswordForm elements
|
|
231
|
+
*/
|
|
232
|
+
interface ResetPasswordFormClassNames {
|
|
233
|
+
/** Wrapper for each form field */
|
|
234
|
+
fieldWrapper?: string;
|
|
235
|
+
/** All labels */
|
|
236
|
+
label?: string;
|
|
237
|
+
/** All input elements */
|
|
238
|
+
input?: string;
|
|
239
|
+
/** Input elements in error state */
|
|
240
|
+
inputError?: string;
|
|
241
|
+
/** Error message text */
|
|
242
|
+
errorText?: string;
|
|
243
|
+
/** Submit button */
|
|
244
|
+
button?: string;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Props for the ResetPasswordForm component
|
|
248
|
+
*/
|
|
249
|
+
interface ResetPasswordFormProps {
|
|
250
|
+
/** Called with all 3 password values on valid submit */
|
|
251
|
+
onSubmit: (values: ResetPasswordFormValues) => void;
|
|
252
|
+
/** Called on every field change with current values and validity */
|
|
253
|
+
onChange?: (values: Partial<ResetPasswordFormValues>, isValid: boolean) => void;
|
|
254
|
+
/** Whether to validate on blur (default: true) */
|
|
255
|
+
validateOnBlur?: boolean;
|
|
256
|
+
/** Text for the submit button (default: "Update Password") */
|
|
257
|
+
submitLabel?: string;
|
|
258
|
+
/** Class name for the form element */
|
|
259
|
+
className?: string;
|
|
260
|
+
/** Custom class names for styling individual elements */
|
|
261
|
+
classNames?: ResetPasswordFormClassNames;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Imperative handle methods exposed via ref
|
|
265
|
+
*/
|
|
266
|
+
interface ResetPasswordFormRef {
|
|
267
|
+
/** Reset all form values and errors */
|
|
268
|
+
reset: () => void;
|
|
269
|
+
/** Programmatically set form values */
|
|
270
|
+
setValues: (values: Partial<ResetPasswordFormValues>) => void;
|
|
271
|
+
}
|
|
272
|
+
|
|
206
273
|
interface QuestionOption {
|
|
207
274
|
id: number;
|
|
208
275
|
name: string;
|
|
@@ -340,6 +407,26 @@ declare const RegistrationForm: React.ForwardRefExoticComponent<RegistrationForm
|
|
|
340
407
|
*/
|
|
341
408
|
declare const ContactDetailsForm: React.ForwardRefExoticComponent<ContactDetailsFormProps & React.RefAttributes<ContactDetailsFormRef>>;
|
|
342
409
|
|
|
410
|
+
/**
|
|
411
|
+
* A reusable, accessible reset-password form component.
|
|
412
|
+
*
|
|
413
|
+
* Features:
|
|
414
|
+
* - Three password fields: Current, New, Confirm New
|
|
415
|
+
* - Validation: all required; confirm must match new password
|
|
416
|
+
* - forwardRef for programmatic reset()/setValues()
|
|
417
|
+
* - onChange callback with live validity
|
|
418
|
+
* - Granular styling via classNames prop
|
|
419
|
+
*
|
|
420
|
+
* @example
|
|
421
|
+
* ```tsx
|
|
422
|
+
* <ResetPasswordForm
|
|
423
|
+
* onSubmit={(values) => console.log(values)}
|
|
424
|
+
* submitLabel="Change Password"
|
|
425
|
+
* />
|
|
426
|
+
* ```
|
|
427
|
+
*/
|
|
428
|
+
declare const ResetPasswordForm: React.ForwardRefExoticComponent<ResetPasswordFormProps & React.RefAttributes<ResetPasswordFormRef>>;
|
|
429
|
+
|
|
343
430
|
/**
|
|
344
431
|
* Validation helper functions for form fields
|
|
345
432
|
* Each validator returns an error message string if invalid, or null if valid
|
|
@@ -373,4 +460,4 @@ declare function minLen(min: number): (value: string) => string | null;
|
|
|
373
460
|
*/
|
|
374
461
|
declare function compose(...validators: Array<(value: string) => string | null>): (value: string) => string | null;
|
|
375
462
|
|
|
376
|
-
export { BookingForm, type BookingFormClassNames, type BookingFormProps, type BookingUIConfig, type ContactDetailsAnswerEntry, type ContactDetailsFieldSettings, ContactDetailsForm, type ContactDetailsFormClassNames, type ContactDetailsFormProps, type ContactDetailsFormRef, type ContactDetailsQuestionEntry, type ContactDetailsValues, type ContactFieldSettings, type FieldConfig, type FieldOption, type FormErrors, type FormValues, type Question, type QuestionOption, type QuestionSettings, RegistrationForm, type RegistrationFormClassNames, type RegistrationFormErrors, type RegistrationFormProps, type RegistrationFormRef, type RegistrationFormValues, compose, email, minLen, phone, required, ukPostcode };
|
|
463
|
+
export { BookingForm, type BookingFormClassNames, type BookingFormProps, type BookingUIConfig, type ContactDetailsAnswerEntry, type ContactDetailsFieldSettings, ContactDetailsForm, type ContactDetailsFormClassNames, type ContactDetailsFormProps, type ContactDetailsFormRef, type ContactDetailsInitialValues, type ContactDetailsQuestionEntry, type ContactDetailsValues, type ContactFieldSettings, type FieldConfig, type FieldOption, type FormErrors, type FormValues, type Question, type QuestionOption, type QuestionSettings, RegistrationForm, type RegistrationFormClassNames, type RegistrationFormErrors, type RegistrationFormProps, type RegistrationFormRef, type RegistrationFormValues, ResetPasswordForm, type ResetPasswordFormClassNames, type ResetPasswordFormProps, type ResetPasswordFormRef, type ResetPasswordFormValues, compose, email, minLen, phone, required, ukPostcode };
|
package/dist/index.d.ts
CHANGED
|
@@ -168,12 +168,27 @@ interface ContactDetailsFieldSettings {
|
|
|
168
168
|
lastName?: ContactFieldSettings;
|
|
169
169
|
email?: ContactFieldSettings;
|
|
170
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Initial values for pre-populating the form
|
|
173
|
+
*/
|
|
174
|
+
interface ContactDetailsInitialValues {
|
|
175
|
+
/** Initial first name value */
|
|
176
|
+
firstName?: string;
|
|
177
|
+
/** Initial last name value */
|
|
178
|
+
lastName?: string;
|
|
179
|
+
/** Initial email value */
|
|
180
|
+
email?: string;
|
|
181
|
+
/** Initial question values keyed by question ID */
|
|
182
|
+
questions?: Record<number, string | number | boolean>;
|
|
183
|
+
}
|
|
171
184
|
/**
|
|
172
185
|
* Props for the ContactDetailsForm component
|
|
173
186
|
*/
|
|
174
187
|
interface ContactDetailsFormProps {
|
|
175
188
|
/** Additional questions to render after the contact fields */
|
|
176
189
|
questions?: Question[];
|
|
190
|
+
/** Initial values for pre-populating the form fields */
|
|
191
|
+
initialValues?: ContactDetailsInitialValues;
|
|
177
192
|
/** Callback fired when form is submitted with valid values */
|
|
178
193
|
onSubmit: (values: ContactDetailsValues) => void;
|
|
179
194
|
/** Callback fired on every field change */
|
|
@@ -203,6 +218,58 @@ interface ContactDetailsFormRef {
|
|
|
203
218
|
}>) => void;
|
|
204
219
|
}
|
|
205
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Values emitted by the ResetPasswordForm on submit
|
|
223
|
+
*/
|
|
224
|
+
interface ResetPasswordFormValues {
|
|
225
|
+
currentPassword: string;
|
|
226
|
+
newPassword: string;
|
|
227
|
+
confirmNewPassword: string;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Custom class names for styling ResetPasswordForm elements
|
|
231
|
+
*/
|
|
232
|
+
interface ResetPasswordFormClassNames {
|
|
233
|
+
/** Wrapper for each form field */
|
|
234
|
+
fieldWrapper?: string;
|
|
235
|
+
/** All labels */
|
|
236
|
+
label?: string;
|
|
237
|
+
/** All input elements */
|
|
238
|
+
input?: string;
|
|
239
|
+
/** Input elements in error state */
|
|
240
|
+
inputError?: string;
|
|
241
|
+
/** Error message text */
|
|
242
|
+
errorText?: string;
|
|
243
|
+
/** Submit button */
|
|
244
|
+
button?: string;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Props for the ResetPasswordForm component
|
|
248
|
+
*/
|
|
249
|
+
interface ResetPasswordFormProps {
|
|
250
|
+
/** Called with all 3 password values on valid submit */
|
|
251
|
+
onSubmit: (values: ResetPasswordFormValues) => void;
|
|
252
|
+
/** Called on every field change with current values and validity */
|
|
253
|
+
onChange?: (values: Partial<ResetPasswordFormValues>, isValid: boolean) => void;
|
|
254
|
+
/** Whether to validate on blur (default: true) */
|
|
255
|
+
validateOnBlur?: boolean;
|
|
256
|
+
/** Text for the submit button (default: "Update Password") */
|
|
257
|
+
submitLabel?: string;
|
|
258
|
+
/** Class name for the form element */
|
|
259
|
+
className?: string;
|
|
260
|
+
/** Custom class names for styling individual elements */
|
|
261
|
+
classNames?: ResetPasswordFormClassNames;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Imperative handle methods exposed via ref
|
|
265
|
+
*/
|
|
266
|
+
interface ResetPasswordFormRef {
|
|
267
|
+
/** Reset all form values and errors */
|
|
268
|
+
reset: () => void;
|
|
269
|
+
/** Programmatically set form values */
|
|
270
|
+
setValues: (values: Partial<ResetPasswordFormValues>) => void;
|
|
271
|
+
}
|
|
272
|
+
|
|
206
273
|
interface QuestionOption {
|
|
207
274
|
id: number;
|
|
208
275
|
name: string;
|
|
@@ -340,6 +407,26 @@ declare const RegistrationForm: React.ForwardRefExoticComponent<RegistrationForm
|
|
|
340
407
|
*/
|
|
341
408
|
declare const ContactDetailsForm: React.ForwardRefExoticComponent<ContactDetailsFormProps & React.RefAttributes<ContactDetailsFormRef>>;
|
|
342
409
|
|
|
410
|
+
/**
|
|
411
|
+
* A reusable, accessible reset-password form component.
|
|
412
|
+
*
|
|
413
|
+
* Features:
|
|
414
|
+
* - Three password fields: Current, New, Confirm New
|
|
415
|
+
* - Validation: all required; confirm must match new password
|
|
416
|
+
* - forwardRef for programmatic reset()/setValues()
|
|
417
|
+
* - onChange callback with live validity
|
|
418
|
+
* - Granular styling via classNames prop
|
|
419
|
+
*
|
|
420
|
+
* @example
|
|
421
|
+
* ```tsx
|
|
422
|
+
* <ResetPasswordForm
|
|
423
|
+
* onSubmit={(values) => console.log(values)}
|
|
424
|
+
* submitLabel="Change Password"
|
|
425
|
+
* />
|
|
426
|
+
* ```
|
|
427
|
+
*/
|
|
428
|
+
declare const ResetPasswordForm: React.ForwardRefExoticComponent<ResetPasswordFormProps & React.RefAttributes<ResetPasswordFormRef>>;
|
|
429
|
+
|
|
343
430
|
/**
|
|
344
431
|
* Validation helper functions for form fields
|
|
345
432
|
* Each validator returns an error message string if invalid, or null if valid
|
|
@@ -373,4 +460,4 @@ declare function minLen(min: number): (value: string) => string | null;
|
|
|
373
460
|
*/
|
|
374
461
|
declare function compose(...validators: Array<(value: string) => string | null>): (value: string) => string | null;
|
|
375
462
|
|
|
376
|
-
export { BookingForm, type BookingFormClassNames, type BookingFormProps, type BookingUIConfig, type ContactDetailsAnswerEntry, type ContactDetailsFieldSettings, ContactDetailsForm, type ContactDetailsFormClassNames, type ContactDetailsFormProps, type ContactDetailsFormRef, type ContactDetailsQuestionEntry, type ContactDetailsValues, type ContactFieldSettings, type FieldConfig, type FieldOption, type FormErrors, type FormValues, type Question, type QuestionOption, type QuestionSettings, RegistrationForm, type RegistrationFormClassNames, type RegistrationFormErrors, type RegistrationFormProps, type RegistrationFormRef, type RegistrationFormValues, compose, email, minLen, phone, required, ukPostcode };
|
|
463
|
+
export { BookingForm, type BookingFormClassNames, type BookingFormProps, type BookingUIConfig, type ContactDetailsAnswerEntry, type ContactDetailsFieldSettings, ContactDetailsForm, type ContactDetailsFormClassNames, type ContactDetailsFormProps, type ContactDetailsFormRef, type ContactDetailsInitialValues, type ContactDetailsQuestionEntry, type ContactDetailsValues, type ContactFieldSettings, type FieldConfig, type FieldOption, type FormErrors, type FormValues, type Question, type QuestionOption, type QuestionSettings, RegistrationForm, type RegistrationFormClassNames, type RegistrationFormErrors, type RegistrationFormProps, type RegistrationFormRef, type RegistrationFormValues, ResetPasswordForm, type ResetPasswordFormClassNames, type ResetPasswordFormProps, type ResetPasswordFormRef, type ResetPasswordFormValues, compose, email, minLen, phone, required, ukPostcode };
|
package/dist/index.js
CHANGED
|
@@ -674,6 +674,7 @@ var ContactDetailsForm = react.forwardRef(
|
|
|
674
674
|
questions = [],
|
|
675
675
|
onSubmit,
|
|
676
676
|
onChange: _onChange,
|
|
677
|
+
initialValues,
|
|
677
678
|
validateOnBlur = true,
|
|
678
679
|
submitLabel = "Submit",
|
|
679
680
|
className = "",
|
|
@@ -681,12 +682,19 @@ var ContactDetailsForm = react.forwardRef(
|
|
|
681
682
|
fieldSettings = {}
|
|
682
683
|
}, ref) => {
|
|
683
684
|
const formId = react.useId();
|
|
684
|
-
const [firstName, setFirstName] = react.useState("");
|
|
685
|
-
const [lastName, setLastName] = react.useState("");
|
|
686
|
-
const [emailValue, setEmailValue] = react.useState("");
|
|
685
|
+
const [firstName, setFirstName] = react.useState(initialValues?.firstName || "");
|
|
686
|
+
const [lastName, setLastName] = react.useState(initialValues?.lastName || "");
|
|
687
|
+
const [emailValue, setEmailValue] = react.useState(initialValues?.email || "");
|
|
687
688
|
const [contactErrors, setContactErrors] = react.useState({});
|
|
688
689
|
const [contactTouched, setContactTouched] = react.useState({});
|
|
689
|
-
const [questionValues, setQuestionValues] = react.useState({
|
|
690
|
+
const [questionValues, setQuestionValues] = react.useState(() => {
|
|
691
|
+
if (!initialValues?.questions) return {};
|
|
692
|
+
const init = {};
|
|
693
|
+
for (const [key, val] of Object.entries(initialValues.questions)) {
|
|
694
|
+
init[Number(key)] = val;
|
|
695
|
+
}
|
|
696
|
+
return init;
|
|
697
|
+
});
|
|
690
698
|
const [questionErrors, setQuestionErrors] = react.useState({});
|
|
691
699
|
const [questionTouched, setQuestionTouched] = react.useState({});
|
|
692
700
|
const getFieldRequired = (name) => {
|
|
@@ -850,12 +858,20 @@ var ContactDetailsForm = react.forwardRef(
|
|
|
850
858
|
}, [contactFields, questions, validateAllContacts, validateAllQuestions, onSubmit, buildOutput]);
|
|
851
859
|
react.useImperativeHandle(ref, () => ({
|
|
852
860
|
reset: () => {
|
|
853
|
-
setFirstName("");
|
|
854
|
-
setLastName("");
|
|
855
|
-
setEmailValue("");
|
|
861
|
+
setFirstName(initialValues?.firstName || "");
|
|
862
|
+
setLastName(initialValues?.lastName || "");
|
|
863
|
+
setEmailValue(initialValues?.email || "");
|
|
856
864
|
setContactErrors({});
|
|
857
865
|
setContactTouched({});
|
|
858
|
-
|
|
866
|
+
if (initialValues?.questions) {
|
|
867
|
+
const init = {};
|
|
868
|
+
for (const [key, val] of Object.entries(initialValues.questions)) {
|
|
869
|
+
init[Number(key)] = val;
|
|
870
|
+
}
|
|
871
|
+
setQuestionValues(init);
|
|
872
|
+
} else {
|
|
873
|
+
setQuestionValues({});
|
|
874
|
+
}
|
|
859
875
|
setQuestionErrors({});
|
|
860
876
|
setQuestionTouched({});
|
|
861
877
|
},
|
|
@@ -864,7 +880,7 @@ var ContactDetailsForm = react.forwardRef(
|
|
|
864
880
|
if (vals.lastName !== void 0) setLastName(vals.lastName);
|
|
865
881
|
if (vals.email !== void 0) setEmailValue(vals.email);
|
|
866
882
|
}
|
|
867
|
-
}), []);
|
|
883
|
+
}), [initialValues]);
|
|
868
884
|
const styles = {
|
|
869
885
|
fieldWrapper: classNames.fieldWrapper || "mb-4",
|
|
870
886
|
label: classNames.label || "block text-sm font-medium mb-1",
|
|
@@ -1072,10 +1088,182 @@ var ContactDetailsForm = react.forwardRef(
|
|
|
1072
1088
|
}
|
|
1073
1089
|
);
|
|
1074
1090
|
ContactDetailsForm.displayName = "ContactDetailsForm";
|
|
1091
|
+
var FIELDS = [
|
|
1092
|
+
{ name: "currentPassword", label: "Current Password" },
|
|
1093
|
+
{ name: "newPassword", label: "New Password" },
|
|
1094
|
+
{ name: "confirmNewPassword", label: "Confirm New Password" }
|
|
1095
|
+
];
|
|
1096
|
+
var ResetPasswordForm = react.forwardRef(
|
|
1097
|
+
({
|
|
1098
|
+
onSubmit,
|
|
1099
|
+
onChange,
|
|
1100
|
+
validateOnBlur = true,
|
|
1101
|
+
submitLabel = "Update Password",
|
|
1102
|
+
className = "",
|
|
1103
|
+
classNames = {}
|
|
1104
|
+
}, ref) => {
|
|
1105
|
+
const formId = react.useId();
|
|
1106
|
+
const [values, setValues] = react.useState({
|
|
1107
|
+
currentPassword: "",
|
|
1108
|
+
newPassword: "",
|
|
1109
|
+
confirmNewPassword: ""
|
|
1110
|
+
});
|
|
1111
|
+
const [errors, setErrors] = react.useState({});
|
|
1112
|
+
const [touched, setTouched] = react.useState({});
|
|
1113
|
+
const validateField = react.useCallback(
|
|
1114
|
+
(name, val, allValues) => {
|
|
1115
|
+
if (!val || val.trim() === "") return "This field is required";
|
|
1116
|
+
if (name === "confirmNewPassword" && val !== allValues.newPassword) {
|
|
1117
|
+
return "Passwords do not match";
|
|
1118
|
+
}
|
|
1119
|
+
return null;
|
|
1120
|
+
},
|
|
1121
|
+
[]
|
|
1122
|
+
);
|
|
1123
|
+
const checkIsValid = react.useCallback(
|
|
1124
|
+
(v) => {
|
|
1125
|
+
for (const field of FIELDS) {
|
|
1126
|
+
if (validateField(field.name, v[field.name], v)) return false;
|
|
1127
|
+
}
|
|
1128
|
+
return true;
|
|
1129
|
+
},
|
|
1130
|
+
[validateField]
|
|
1131
|
+
);
|
|
1132
|
+
const handleChange = react.useCallback(
|
|
1133
|
+
(name, val) => {
|
|
1134
|
+
const newValues = { ...values, [name]: val };
|
|
1135
|
+
setValues(newValues);
|
|
1136
|
+
if (touched[name]) {
|
|
1137
|
+
const error = validateField(name, val, newValues);
|
|
1138
|
+
if (!error) {
|
|
1139
|
+
setErrors((prev) => {
|
|
1140
|
+
const next = { ...prev };
|
|
1141
|
+
delete next[name];
|
|
1142
|
+
return next;
|
|
1143
|
+
});
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
if (name === "newPassword" && touched.confirmNewPassword) {
|
|
1147
|
+
const confirmError = validateField("confirmNewPassword", newValues.confirmNewPassword, newValues);
|
|
1148
|
+
if (confirmError) {
|
|
1149
|
+
setErrors((prev) => ({ ...prev, confirmNewPassword: confirmError }));
|
|
1150
|
+
} else {
|
|
1151
|
+
setErrors((prev) => {
|
|
1152
|
+
const next = { ...prev };
|
|
1153
|
+
delete next.confirmNewPassword;
|
|
1154
|
+
return next;
|
|
1155
|
+
});
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
onChange?.(newValues, checkIsValid(newValues));
|
|
1159
|
+
},
|
|
1160
|
+
[values, touched, validateField, onChange, checkIsValid]
|
|
1161
|
+
);
|
|
1162
|
+
const handleBlur = react.useCallback(
|
|
1163
|
+
(name) => {
|
|
1164
|
+
setTouched((prev) => ({ ...prev, [name]: true }));
|
|
1165
|
+
if (validateOnBlur) {
|
|
1166
|
+
const error = validateField(name, values[name], values);
|
|
1167
|
+
if (error) {
|
|
1168
|
+
setErrors((prev) => ({ ...prev, [name]: error }));
|
|
1169
|
+
} else {
|
|
1170
|
+
setErrors((prev) => {
|
|
1171
|
+
const next = { ...prev };
|
|
1172
|
+
delete next[name];
|
|
1173
|
+
return next;
|
|
1174
|
+
});
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
},
|
|
1178
|
+
[validateOnBlur, values, validateField]
|
|
1179
|
+
);
|
|
1180
|
+
const handleSubmit = react.useCallback(
|
|
1181
|
+
(e) => {
|
|
1182
|
+
e.preventDefault();
|
|
1183
|
+
const allTouched = {};
|
|
1184
|
+
const newErrors = {};
|
|
1185
|
+
let isValid = true;
|
|
1186
|
+
for (const field of FIELDS) {
|
|
1187
|
+
allTouched[field.name] = true;
|
|
1188
|
+
const error = validateField(field.name, values[field.name], values);
|
|
1189
|
+
if (error) {
|
|
1190
|
+
newErrors[field.name] = error;
|
|
1191
|
+
isValid = false;
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
setTouched(allTouched);
|
|
1195
|
+
setErrors(newErrors);
|
|
1196
|
+
if (isValid) onSubmit(values);
|
|
1197
|
+
},
|
|
1198
|
+
[values, validateField, onSubmit]
|
|
1199
|
+
);
|
|
1200
|
+
react.useImperativeHandle(ref, () => ({
|
|
1201
|
+
reset: () => {
|
|
1202
|
+
setValues({ currentPassword: "", newPassword: "", confirmNewPassword: "" });
|
|
1203
|
+
setErrors({});
|
|
1204
|
+
setTouched({});
|
|
1205
|
+
},
|
|
1206
|
+
setValues: (newVals) => {
|
|
1207
|
+
setValues((prev) => {
|
|
1208
|
+
const merged = { ...prev };
|
|
1209
|
+
for (const [key, value] of Object.entries(newVals)) {
|
|
1210
|
+
if (value !== void 0) {
|
|
1211
|
+
merged[key] = value;
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
return merged;
|
|
1215
|
+
});
|
|
1216
|
+
}
|
|
1217
|
+
}), []);
|
|
1218
|
+
const styles = {
|
|
1219
|
+
fieldWrapper: classNames.fieldWrapper || "mb-4",
|
|
1220
|
+
label: classNames.label || "block text-sm font-medium mb-1",
|
|
1221
|
+
input: classNames.input || "w-full px-3 py-2 border rounded-md",
|
|
1222
|
+
inputError: classNames.inputError || "border-red-500",
|
|
1223
|
+
errorText: classNames.errorText || "mt-1 text-xs text-red-600",
|
|
1224
|
+
button: classNames.button || "w-full mt-4 px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50"
|
|
1225
|
+
};
|
|
1226
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className, noValidate: true, children: [
|
|
1227
|
+
FIELDS.map((field) => {
|
|
1228
|
+
const fieldId = `${formId}-${field.name}`;
|
|
1229
|
+
const errorId = `${fieldId}-error`;
|
|
1230
|
+
const value = values[field.name];
|
|
1231
|
+
const error = errors[field.name];
|
|
1232
|
+
const isTouched = touched[field.name];
|
|
1233
|
+
const showError = isTouched && error;
|
|
1234
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.fieldWrapper, children: [
|
|
1235
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: fieldId, className: styles.label, children: [
|
|
1236
|
+
field.label,
|
|
1237
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500 ml-1", "aria-hidden": "true", children: "*" })
|
|
1238
|
+
] }),
|
|
1239
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1240
|
+
"input",
|
|
1241
|
+
{
|
|
1242
|
+
id: fieldId,
|
|
1243
|
+
name: field.name,
|
|
1244
|
+
type: "password",
|
|
1245
|
+
value,
|
|
1246
|
+
onChange: (e) => handleChange(field.name, e.target.value),
|
|
1247
|
+
onBlur: () => handleBlur(field.name),
|
|
1248
|
+
className: `${styles.input} ${showError ? styles.inputError : ""}`,
|
|
1249
|
+
"aria-invalid": showError ? "true" : "false",
|
|
1250
|
+
"aria-describedby": showError ? errorId : void 0,
|
|
1251
|
+
"aria-required": "true"
|
|
1252
|
+
}
|
|
1253
|
+
),
|
|
1254
|
+
showError && /* @__PURE__ */ jsxRuntime.jsx("p", { id: errorId, className: styles.errorText, role: "alert", children: error })
|
|
1255
|
+
] }, field.name);
|
|
1256
|
+
}),
|
|
1257
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", className: styles.button, children: submitLabel })
|
|
1258
|
+
] });
|
|
1259
|
+
}
|
|
1260
|
+
);
|
|
1261
|
+
ResetPasswordForm.displayName = "ResetPasswordForm";
|
|
1075
1262
|
|
|
1076
1263
|
exports.BookingForm = BookingForm;
|
|
1077
1264
|
exports.ContactDetailsForm = ContactDetailsForm;
|
|
1078
1265
|
exports.RegistrationForm = RegistrationForm;
|
|
1266
|
+
exports.ResetPasswordForm = ResetPasswordForm;
|
|
1079
1267
|
exports.compose = compose;
|
|
1080
1268
|
exports.email = email;
|
|
1081
1269
|
exports.minLen = minLen;
|