@bookinglab/booking-ui-react 1.6.1 → 1.7.1

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/dist/index.mjs CHANGED
@@ -426,10 +426,12 @@ var DEFAULT_FIELDS = [
426
426
  validate: compose(required, email)
427
427
  },
428
428
  {
429
- name: "password",
430
- label: "Password",
431
- type: "password",
432
- required: false
429
+ name: "verifyEmail",
430
+ label: "Verify email address",
431
+ type: "email",
432
+ required: true,
433
+ // Cross-field validation is handled in the component
434
+ validate: required
433
435
  },
434
436
  {
435
437
  name: "phone",
@@ -438,6 +440,20 @@ var DEFAULT_FIELDS = [
438
440
  required: false,
439
441
  validate: phone
440
442
  },
443
+ {
444
+ name: "password",
445
+ label: "Password",
446
+ type: "password",
447
+ required: true,
448
+ validate: required
449
+ },
450
+ {
451
+ name: "confirmPassword",
452
+ label: "Confirm password",
453
+ type: "password",
454
+ required: true,
455
+ validate: required
456
+ },
441
457
  {
442
458
  name: "address1",
443
459
  label: "Address 1",
@@ -466,6 +482,7 @@ var DEFAULT_FIELDS = [
466
482
  validate: compose(required, ukPostcode)
467
483
  }
468
484
  ];
485
+ var HIDEABLE_FIELDS = ["address1", "address2", "city", "postcode"];
469
486
  var RegistrationForm = forwardRef(
470
487
  ({
471
488
  fields = DEFAULT_FIELDS,
@@ -475,31 +492,58 @@ var RegistrationForm = forwardRef(
475
492
  validateOnBlur = true,
476
493
  submitLabel = "Submit",
477
494
  className = "",
478
- classNames = {}
495
+ classNames = {},
496
+ fieldSettings = {}
479
497
  }, ref) => {
480
498
  const formId = useId();
481
499
  const [values, setValues] = useState({});
482
500
  const [errors, setErrors] = useState({});
483
501
  const [touched, setTouched] = useState({});
484
- const allFields = additionalFields ? [...fields, ...additionalFields] : fields;
502
+ const visibleFields = fields.filter((field) => {
503
+ if (HIDEABLE_FIELDS.includes(field.name)) {
504
+ const setting = fieldSettings[field.name];
505
+ if (setting?.hidden) return false;
506
+ }
507
+ return true;
508
+ });
509
+ const allFields = additionalFields ? [...visibleFields, ...additionalFields] : visibleFields;
510
+ const validateMatching = useCallback(
511
+ (fieldName, value, currentValues) => {
512
+ if (fieldName === "verifyEmail") {
513
+ if (value && currentValues.email && value !== currentValues.email) {
514
+ return "Email addresses do not match";
515
+ }
516
+ }
517
+ if (fieldName === "confirmPassword") {
518
+ if (value && currentValues.password && value !== currentValues.password) {
519
+ return "Passwords do not match";
520
+ }
521
+ }
522
+ return null;
523
+ },
524
+ []
525
+ );
485
526
  const validateField = useCallback(
486
- (field, value) => {
527
+ (field, value, currentValues) => {
487
528
  if (field.required && (!value || value.trim() === "")) {
488
529
  return "This field is required";
489
530
  }
490
531
  if (field.validate && value) {
491
- return field.validate(value);
532
+ const error = field.validate(value);
533
+ if (error) return error;
492
534
  }
535
+ const matchError = validateMatching(field.name, value, currentValues);
536
+ if (matchError) return matchError;
493
537
  return null;
494
538
  },
495
- []
539
+ [validateMatching]
496
540
  );
497
541
  const validateAll = useCallback(() => {
498
542
  const newErrors = {};
499
543
  let isValid = true;
500
544
  for (const field of allFields) {
501
545
  const value = values[field.name] || "";
502
- const error = validateField(field, value);
546
+ const error = validateField(field, value, values);
503
547
  if (error) {
504
548
  newErrors[field.name] = error;
505
549
  isValid = false;
@@ -512,7 +556,7 @@ var RegistrationForm = forwardRef(
512
556
  (currentValues) => {
513
557
  for (const field of allFields) {
514
558
  const value = currentValues[field.name] || "";
515
- const error = validateField(field, value);
559
+ const error = validateField(field, value, currentValues);
516
560
  if (error) return false;
517
561
  }
518
562
  return true;
@@ -526,7 +570,7 @@ var RegistrationForm = forwardRef(
526
570
  if (touched[fieldName]) {
527
571
  const field = allFields.find((f) => f.name === fieldName);
528
572
  if (field) {
529
- const error = validateField(field, value);
573
+ const error = validateField(field, value, newValues);
530
574
  if (!error) {
531
575
  setErrors((prev) => {
532
576
  const next = { ...prev };
@@ -536,6 +580,36 @@ var RegistrationForm = forwardRef(
536
580
  }
537
581
  }
538
582
  }
583
+ if (fieldName === "email" && touched.verifyEmail) {
584
+ const verifyField = allFields.find((f) => f.name === "verifyEmail");
585
+ if (verifyField) {
586
+ const verifyError = validateField(verifyField, newValues.verifyEmail || "", newValues);
587
+ setErrors((prev) => {
588
+ const next = { ...prev };
589
+ if (verifyError) {
590
+ next.verifyEmail = verifyError;
591
+ } else {
592
+ delete next.verifyEmail;
593
+ }
594
+ return next;
595
+ });
596
+ }
597
+ }
598
+ if (fieldName === "password" && touched.confirmPassword) {
599
+ const confirmField = allFields.find((f) => f.name === "confirmPassword");
600
+ if (confirmField) {
601
+ const confirmError = validateField(confirmField, newValues.confirmPassword || "", newValues);
602
+ setErrors((prev) => {
603
+ const next = { ...prev };
604
+ if (confirmError) {
605
+ next.confirmPassword = confirmError;
606
+ } else {
607
+ delete next.confirmPassword;
608
+ }
609
+ return next;
610
+ });
611
+ }
612
+ }
539
613
  if (onChange) {
540
614
  const isValid = checkIsValid(newValues);
541
615
  onChange(newValues, isValid);
@@ -543,6 +617,13 @@ var RegistrationForm = forwardRef(
543
617
  },
544
618
  [values, touched, allFields, validateField, onChange, checkIsValid]
545
619
  );
620
+ const handleCheckboxChange = useCallback(
621
+ (fieldName, checked) => {
622
+ const value = checked ? "true" : "";
623
+ handleChange(fieldName, value);
624
+ },
625
+ [handleChange]
626
+ );
546
627
  const handleBlur = useCallback(
547
628
  (fieldName) => {
548
629
  setTouched((prev) => ({ ...prev, [fieldName]: true }));
@@ -550,7 +631,7 @@ var RegistrationForm = forwardRef(
550
631
  const field = allFields.find((f) => f.name === fieldName);
551
632
  if (field) {
552
633
  const value = values[fieldName] || "";
553
- const error = validateField(field, value);
634
+ const error = validateField(field, value, values);
554
635
  if (error) {
555
636
  setErrors((prev) => ({ ...prev, [fieldName]: error }));
556
637
  } else {
@@ -606,6 +687,8 @@ var RegistrationForm = forwardRef(
606
687
  label: classNames.label || "block text-sm font-medium mb-1",
607
688
  input: classNames.input || "w-full px-3 py-2 border rounded-md",
608
689
  inputError: classNames.inputError || "border-red-500",
690
+ checkbox: classNames.checkbox || "",
691
+ checkboxWrapper: classNames.checkboxWrapper || "flex items-center gap-2",
609
692
  errorText: classNames.errorText || "mt-1 text-xs text-red-600",
610
693
  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"
611
694
  };
@@ -617,6 +700,32 @@ var RegistrationForm = forwardRef(
617
700
  const error = errors[field.name];
618
701
  const isTouched = touched[field.name];
619
702
  const showError = isTouched && error;
703
+ if (field.type === "check") {
704
+ return /* @__PURE__ */ jsxs("div", { className: styles.fieldWrapper, children: [
705
+ /* @__PURE__ */ jsxs("div", { className: styles.checkboxWrapper, children: [
706
+ /* @__PURE__ */ jsx(
707
+ "input",
708
+ {
709
+ id: fieldId,
710
+ name: field.name,
711
+ type: "checkbox",
712
+ checked: value === "true",
713
+ onChange: (e) => handleCheckboxChange(field.name, e.target.checked),
714
+ onBlur: () => handleBlur(field.name),
715
+ className: `${styles.checkbox} ${showError ? styles.inputError : ""}`,
716
+ "aria-invalid": showError ? "true" : "false",
717
+ "aria-describedby": showError ? errorId : void 0,
718
+ "aria-required": field.required ? "true" : "false"
719
+ }
720
+ ),
721
+ /* @__PURE__ */ jsxs("label", { htmlFor: fieldId, className: styles.label, children: [
722
+ field.label,
723
+ field.required && /* @__PURE__ */ jsx("span", { className: "text-red-500 ml-1", "aria-hidden": "true", children: "*" })
724
+ ] })
725
+ ] }),
726
+ showError && /* @__PURE__ */ jsx("p", { id: errorId, className: styles.errorText, role: "alert", children: error })
727
+ ] }, field.name);
728
+ }
620
729
  return /* @__PURE__ */ jsxs("div", { className: styles.fieldWrapper, children: [
621
730
  /* @__PURE__ */ jsxs("label", { htmlFor: fieldId, className: styles.label, children: [
622
731
  field.label,