@fluid-app/portal-sdk 0.1.164 → 0.1.165

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.
@@ -9,7 +9,7 @@ import { n as accountKeys, r as payKeys, t as useAccount } from "./use-account-B
9
9
  import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
10
10
  import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
11
11
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
12
- import { Pencil } from "lucide-react";
12
+ import { Info, Pencil } from "lucide-react";
13
13
  import { Controller, useController, useWatch } from "react-hook-form";
14
14
  import { z } from "zod";
15
15
  //#region ../../profile/core/src/context.ts
@@ -522,7 +522,7 @@ function FormTextField$1({ control, name, label, containerClassName, ...props })
522
522
  children: [
523
523
  label && /* @__PURE__ */ jsx(Label, {
524
524
  htmlFor: name,
525
- className: "mb-1.5 block text-sm font-medium text-gray-700",
525
+ className: "mb-1.5 block text-sm font-medium",
526
526
  children: label
527
527
  }),
528
528
  /* @__PURE__ */ jsx(Input, {
@@ -549,7 +549,7 @@ function FormSelectField$1({ control, name, label, options, placeholder, contain
549
549
  children: [
550
550
  label && /* @__PURE__ */ jsx(Label, {
551
551
  htmlFor: name,
552
- className: "block text-sm font-medium text-gray-700",
552
+ className: "block text-sm font-medium",
553
553
  children: label
554
554
  }),
555
555
  /* @__PURE__ */ jsxs(Select, {
@@ -575,11 +575,46 @@ function FormSelectField$1({ control, name, label, options, placeholder, contain
575
575
  }
576
576
  //#endregion
577
577
  //#region ../../profile/ui/src/components/user-info-dialog.tsx
578
- function UserInfoDialog({ control, isOpen, onSubmit, handleClose, languageOptions, errorMsg, isSubmitting }) {
578
+ function UserInfoDialog({ control, isOpen, onSubmit, handleClose, languageOptions, errorMsg, isSubmitting, email, onChangeEmail, isChangingEmail, pendingEmail }) {
579
579
  const { t } = useProfileUI();
580
+ const [isEditingEmail, setIsEditingEmail] = useState(false);
581
+ const [newEmail, setNewEmail] = useState("");
582
+ const [emailError, setEmailError] = useState(void 0);
583
+ const handleEmailSubmit = async () => {
584
+ setEmailError(void 0);
585
+ const trimmed = newEmail.trim();
586
+ if (!trimmed) {
587
+ setEmailError("Please enter a new email address");
588
+ return;
589
+ }
590
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(trimmed)) {
591
+ setEmailError("Please enter a valid email address");
592
+ return;
593
+ }
594
+ if (email && trimmed.toLowerCase() === email.toLowerCase()) {
595
+ setEmailError("New email must be different from your current email");
596
+ return;
597
+ }
598
+ try {
599
+ await onChangeEmail?.(trimmed);
600
+ setIsEditingEmail(false);
601
+ setNewEmail("");
602
+ } catch (err) {
603
+ setEmailError(err instanceof Error ? err.message : "Failed to initiate email change");
604
+ }
605
+ };
606
+ const handleCancelEmailEdit = () => {
607
+ setIsEditingEmail(false);
608
+ setNewEmail("");
609
+ setEmailError(void 0);
610
+ };
611
+ const handleDialogClose = () => {
612
+ handleCancelEmailEdit();
613
+ handleClose();
614
+ };
580
615
  return /* @__PURE__ */ jsx(Dialog, {
581
616
  open: isOpen,
582
- onOpenChange: (open) => !open && handleClose(),
617
+ onOpenChange: (open) => !open && handleDialogClose(),
583
618
  children: /* @__PURE__ */ jsxs(DialogContent, {
584
619
  className: "max-w-sm rounded md:max-w-lg",
585
620
  children: [
@@ -588,7 +623,7 @@ function UserInfoDialog({ control, isOpen, onSubmit, handleClose, languageOption
588
623
  children: t("edit_profile")
589
624
  }) }),
590
625
  /* @__PURE__ */ jsxs("div", {
591
- className: "space-y-0",
626
+ className: "space-y-4",
592
627
  children: [
593
628
  /* @__PURE__ */ jsx(FormTextField$1, {
594
629
  control,
@@ -615,6 +650,97 @@ function UserInfoDialog({ control, isOpen, onSubmit, handleClose, languageOption
615
650
  })
616
651
  ]
617
652
  }),
653
+ email && /* @__PURE__ */ jsxs("div", {
654
+ className: "space-y-2",
655
+ children: [/* @__PURE__ */ jsx("label", {
656
+ className: "text-foreground text-sm font-medium",
657
+ children: t("email") || "Email"
658
+ }), isEditingEmail ? /* @__PURE__ */ jsxs("div", {
659
+ className: "space-y-2",
660
+ children: [
661
+ /* @__PURE__ */ jsx(Input, {
662
+ type: "email",
663
+ placeholder: "Enter your new email...",
664
+ value: newEmail,
665
+ onChange: (e) => {
666
+ setNewEmail(e.target.value);
667
+ setEmailError(void 0);
668
+ },
669
+ onKeyDown: (e) => {
670
+ if (e.key === "Enter") {
671
+ e.preventDefault();
672
+ handleEmailSubmit();
673
+ }
674
+ if (e.key === "Escape") handleCancelEmailEdit();
675
+ },
676
+ "aria-invalid": !!emailError || void 0,
677
+ autoFocus: true
678
+ }),
679
+ emailError && /* @__PURE__ */ jsx("p", {
680
+ className: "text-xs text-red-500",
681
+ children: emailError
682
+ }),
683
+ /* @__PURE__ */ jsxs("div", {
684
+ className: "bg-muted flex items-start gap-2.5 rounded-md px-3 py-2.5",
685
+ children: [/* @__PURE__ */ jsx(Info, { className: "text-primary mt-0.5 h-4 w-4 shrink-0" }), /* @__PURE__ */ jsx("p", {
686
+ className: "text-muted-foreground text-xs",
687
+ children: "We'll send a verification link to your new email. Click it to complete the change."
688
+ })]
689
+ }),
690
+ /* @__PURE__ */ jsxs("div", {
691
+ className: "flex gap-2",
692
+ children: [/* @__PURE__ */ jsx(Button, {
693
+ type: "button",
694
+ variant: "outline",
695
+ size: "sm",
696
+ onClick: handleCancelEmailEdit,
697
+ className: "cursor-pointer",
698
+ children: "Cancel"
699
+ }), /* @__PURE__ */ jsxs(Button, {
700
+ type: "button",
701
+ size: "sm",
702
+ onClick: handleEmailSubmit,
703
+ disabled: !newEmail.trim() || isChangingEmail,
704
+ className: "cursor-pointer",
705
+ children: [isChangingEmail && /* @__PURE__ */ jsx("div", { className: "mr-2 h-3.5 w-3.5 animate-spin rounded-full border-2 border-current/30 border-t-current" }), isChangingEmail ? "Sending..." : "Send verification"]
706
+ })]
707
+ })
708
+ ]
709
+ }) : pendingEmail ? /* @__PURE__ */ jsxs("div", {
710
+ className: "space-y-2",
711
+ children: [/* @__PURE__ */ jsx("div", {
712
+ className: "bg-muted text-muted-foreground min-w-0 rounded-md px-3 py-2 text-sm",
713
+ children: email
714
+ }), /* @__PURE__ */ jsxs("div", {
715
+ className: "bg-muted flex items-start gap-2.5 rounded-md px-3 py-2.5",
716
+ children: [/* @__PURE__ */ jsx(Info, { className: "text-primary mt-0.5 h-4 w-4 shrink-0" }), /* @__PURE__ */ jsxs("p", {
717
+ className: "text-muted-foreground text-xs",
718
+ children: [
719
+ "Changing to",
720
+ " ",
721
+ /* @__PURE__ */ jsx("span", {
722
+ className: "text-foreground font-medium",
723
+ children: pendingEmail
724
+ }),
725
+ ". Check your new email inbox and click the verification link to complete the change."
726
+ ]
727
+ })]
728
+ })]
729
+ }) : /* @__PURE__ */ jsxs("div", {
730
+ className: "flex items-center gap-2",
731
+ children: [/* @__PURE__ */ jsx("div", {
732
+ className: "bg-muted text-muted-foreground min-w-0 flex-1 rounded-md px-3 py-2 text-sm",
733
+ children: email
734
+ }), onChangeEmail && /* @__PURE__ */ jsx(Button, {
735
+ type: "button",
736
+ variant: "outline",
737
+ size: "sm",
738
+ onClick: () => setIsEditingEmail(true),
739
+ className: "shrink-0 cursor-pointer",
740
+ children: "Change"
741
+ })]
742
+ })]
743
+ }),
618
744
  errorMsg && /* @__PURE__ */ jsx("p", {
619
745
  className: "text-sm text-red-500",
620
746
  children: errorMsg
@@ -623,13 +749,11 @@ function UserInfoDialog({ control, isOpen, onSubmit, handleClose, languageOption
623
749
  className: "flex flex-row items-center justify-end",
624
750
  children: /* @__PURE__ */ jsx("div", {
625
751
  className: "flex-1 text-right",
626
- children: /* @__PURE__ */ jsx(DialogClose, {
627
- asChild: true,
628
- children: /* @__PURE__ */ jsxs(Button, {
629
- type: "button",
630
- onClick: onSubmit,
631
- children: [isSubmitting && /* @__PURE__ */ jsx("div", { className: "mr-3 h-5 w-5 animate-spin rounded-full border-4 border-t-4 border-white border-t-transparent" }), isSubmitting ? t("saving") : t("save_changes")]
632
- })
752
+ children: /* @__PURE__ */ jsxs(Button, {
753
+ type: "button",
754
+ onClick: onSubmit,
755
+ className: "cursor-pointer",
756
+ children: [isSubmitting && /* @__PURE__ */ jsx("div", { className: "mr-2 h-4 w-4 animate-spin rounded-full border-2 border-current/30 border-t-current" }), isSubmitting ? t("saving") : t("save_changes")]
633
757
  })
634
758
  })
635
759
  })
@@ -647,13 +771,13 @@ function createUserInfoSchema(messages) {
647
771
  language: z.string().min(1, { message: messages.languageRequired })
648
772
  });
649
773
  }
650
- function CustomerInfo({ customerAccount, languages, onUpdateCustomer, isUpdating = false }) {
774
+ function CustomerInfo({ customerAccount, languages, onUpdateCustomer, isUpdating = false, onChangeEmail, isChangingEmail = false, pendingEmailChange, onCancelEmailChange, pendingEmail }) {
651
775
  const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
652
776
  const [updateError, setUpdateError] = useState(void 0);
653
777
  const { t } = useProfileUI();
654
778
  const { first_name, full_name } = customerAccount.customer;
655
779
  const derivedLastName = full_name.startsWith(first_name) ? full_name.slice(first_name.length).trim() : "";
656
- const userInitial = first_name ? first_name.charAt(0).toUpperCase() : "";
780
+ const userInitial = first_name ? first_name.charAt(0).toUpperCase() : customerAccount.customer.email?.charAt(0).toUpperCase() ?? "";
657
781
  const customerLanguage = languages?.find((language) => language.iso === customerAccount.fluid_pay_account.language_iso)?.name;
658
782
  const languageOptions = languages?.map((language) => ({
659
783
  name: language.name,
@@ -691,34 +815,83 @@ function CustomerInfo({ customerAccount, languages, onUpdateCustomer, isUpdating
691
815
  setUpdateError("Error updating profile. Please verify your information and try again.");
692
816
  }
693
817
  });
694
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("div", {
695
- className: "mb-6 flex flex-row items-center justify-between space-x-2 border-b border-gray-300 pb-4",
696
- children: [/* @__PURE__ */ jsxs("div", {
697
- className: "flex flex-row items-center space-x-2",
698
- children: [/* @__PURE__ */ jsx(Avatar, { children: /* @__PURE__ */ jsx(AvatarFallback, { children: userInitial }) }), /* @__PURE__ */ jsxs("div", {
699
- className: "flex flex-col",
700
- children: [/* @__PURE__ */ jsx("p", {
701
- className: "text-sm font-medium",
702
- children: customerAccount.customer.full_name
703
- }), /* @__PURE__ */ jsx("p", {
704
- className: "text-sm text-gray-500",
705
- children: customerAccount.customer.email
818
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
819
+ /* @__PURE__ */ jsxs("div", {
820
+ className: "mb-6 flex flex-row items-center justify-between space-x-2 border-b border-gray-300 pb-4",
821
+ children: [/* @__PURE__ */ jsxs("div", {
822
+ className: "flex flex-row items-center space-x-2",
823
+ children: [/* @__PURE__ */ jsx(Avatar, { children: /* @__PURE__ */ jsx(AvatarFallback, { children: userInitial }) }), /* @__PURE__ */ jsx("div", {
824
+ className: "flex flex-col",
825
+ children: first_name ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("p", {
826
+ className: "text-sm font-medium",
827
+ children: customerAccount.customer.full_name
828
+ }), /* @__PURE__ */ jsx("p", {
829
+ className: "text-sm text-gray-500",
830
+ children: customerAccount.customer.email
831
+ })] }) : /* @__PURE__ */ jsx("p", {
832
+ className: "text-sm font-medium",
833
+ children: customerAccount.customer.email
834
+ })
706
835
  })]
836
+ }), /* @__PURE__ */ jsx("button", {
837
+ className: "cursor-pointer rounded-md border border-gray-300 p-1 hover:bg-gray-50 disabled:opacity-50",
838
+ onClick: handleOpenEditDialog,
839
+ children: /* @__PURE__ */ jsx(Pencil, { className: "h-2.5 w-2.5 text-gray-400" })
707
840
  })]
708
- }), /* @__PURE__ */ jsx("button", {
709
- className: "cursor-pointer rounded-md border border-gray-300 p-1 hover:bg-gray-50 disabled:opacity-50",
710
- onClick: handleOpenEditDialog,
711
- children: /* @__PURE__ */ jsx(Pencil, { className: "h-2.5 w-2.5 text-gray-400" })
712
- })]
713
- }), /* @__PURE__ */ jsx(UserInfoDialog, {
714
- control,
715
- isOpen: isEditDialogOpen,
716
- onSubmit: onSubmitUserInfo,
717
- handleClose: handleCloseEditDialog,
718
- languageOptions,
719
- errorMsg: updateError,
720
- isSubmitting: isUpdating
721
- })] });
841
+ }),
842
+ pendingEmailChange && /* @__PURE__ */ jsxs("div", {
843
+ className: "bg-muted mb-6 flex items-start gap-2.5 rounded-md px-3 py-3",
844
+ children: [/* @__PURE__ */ jsx(Info, { className: "text-primary mt-0.5 h-4 w-4 shrink-0" }), /* @__PURE__ */ jsxs("div", {
845
+ className: "flex-1 space-y-2",
846
+ children: [
847
+ /* @__PURE__ */ jsx("p", {
848
+ className: "text-foreground text-sm font-medium",
849
+ children: "Email change pending"
850
+ }),
851
+ /* @__PURE__ */ jsxs("p", {
852
+ className: "text-muted-foreground text-xs",
853
+ children: [
854
+ "Your email is being changed to",
855
+ " ",
856
+ /* @__PURE__ */ jsx("span", {
857
+ className: "text-foreground font-medium",
858
+ children: pendingEmailChange.newEmail
859
+ }),
860
+ ".",
861
+ " ",
862
+ pendingEmailChange.newEmailConfirmed ? "Your new email has been verified." : "Check your new inbox and click the verification link to complete the change.",
863
+ " ",
864
+ (() => {
865
+ const diff = new Date(pendingEmailChange.expiresAt).getTime() - Date.now();
866
+ if (diff <= 0) return "This request has expired.";
867
+ const days = Math.ceil(diff / (1e3 * 60 * 60 * 24));
868
+ return `This request expires in ${days === 1 ? "1 day" : `${days} days`}.`;
869
+ })()
870
+ ]
871
+ }),
872
+ onCancelEmailChange && /* @__PURE__ */ jsx("button", {
873
+ type: "button",
874
+ onClick: onCancelEmailChange,
875
+ className: "bg-primary text-primary-foreground hover:bg-primary/90 cursor-pointer rounded-md px-3 py-1.5 text-xs font-medium",
876
+ children: "Cancel change"
877
+ })
878
+ ]
879
+ })]
880
+ }),
881
+ /* @__PURE__ */ jsx(UserInfoDialog, {
882
+ control,
883
+ isOpen: isEditDialogOpen,
884
+ onSubmit: onSubmitUserInfo,
885
+ handleClose: handleCloseEditDialog,
886
+ languageOptions,
887
+ errorMsg: updateError,
888
+ isSubmitting: isUpdating,
889
+ email: customerAccount.customer.email,
890
+ onChangeEmail,
891
+ isChangingEmail,
892
+ pendingEmail
893
+ })
894
+ ] });
722
895
  }
723
896
  //#endregion
724
897
  //#region ../../profile/ui/src/components/address-dropdown.tsx
@@ -1491,35 +1664,46 @@ function PaymentMethods({ paymentMethods, isLoading = false, onDeletePaymentMeth
1491
1664
  }
1492
1665
  //#endregion
1493
1666
  //#region ../../profile/ui/src/components/profile.tsx
1494
- function Profile({ customerAccount, languages, onUpdateCustomer, isUpdatingCustomer, rewardsPointsEnabled = false, pointsLedger, isLoadingPointsLedger, addresses, isLoadingAddresses, onDeleteAddress, isDeletingAddress, renderAddressDialog, paymentMethods, isLoadingPaymentMethods, onDeletePaymentMethod, isDeletingPaymentMethod, onUpdatePaymentMethod, isUpdatingPaymentMethod, getBillingAddress, countries, renderCreditCardDialog }) {
1667
+ function Profile({ customerAccount, languages, onUpdateCustomer, isUpdatingCustomer, onChangeEmail, isChangingEmail, pendingEmailChange, onCancelEmailChange, pendingEmail, rewardsPointsEnabled = false, pointsLedger, isLoadingPointsLedger, addresses, isLoadingAddresses, onDeleteAddress, isDeletingAddress, renderAddressDialog, paymentMethods, isLoadingPaymentMethods, onDeletePaymentMethod, isDeletingPaymentMethod, onUpdatePaymentMethod, isUpdatingPaymentMethod, getBillingAddress, countries, renderCreditCardDialog }) {
1495
1668
  return /* @__PURE__ */ jsxs(Fragment$1, { children: [
1496
1669
  /* @__PURE__ */ jsx(CustomerInfo, {
1497
1670
  customerAccount,
1498
1671
  languages,
1499
1672
  onUpdateCustomer,
1500
- isUpdating: isUpdatingCustomer
1673
+ isUpdating: isUpdatingCustomer,
1674
+ onChangeEmail,
1675
+ isChangingEmail,
1676
+ pendingEmailChange,
1677
+ onCancelEmailChange,
1678
+ pendingEmail
1501
1679
  }),
1502
1680
  rewardsPointsEnabled && /* @__PURE__ */ jsx(CustomerPointsLedger, {
1503
1681
  pointsLedger: pointsLedger ?? [],
1504
1682
  isLoading: isLoadingPointsLedger
1505
1683
  }),
1506
- /* @__PURE__ */ jsx(Addresses, {
1507
- addresses,
1508
- isLoading: isLoadingAddresses,
1509
- onDeleteAddress,
1510
- isDeletingAddress,
1511
- renderAddressDialog
1684
+ /* @__PURE__ */ jsx("div", {
1685
+ id: "profile-addresses",
1686
+ children: /* @__PURE__ */ jsx(Addresses, {
1687
+ addresses,
1688
+ isLoading: isLoadingAddresses,
1689
+ onDeleteAddress,
1690
+ isDeletingAddress,
1691
+ renderAddressDialog
1692
+ })
1512
1693
  }),
1513
- /* @__PURE__ */ jsx(PaymentMethods, {
1514
- paymentMethods,
1515
- isLoading: isLoadingPaymentMethods,
1516
- onDeletePaymentMethod,
1517
- isDeletingPaymentMethod,
1518
- onUpdatePaymentMethod,
1519
- isUpdatingPaymentMethod,
1520
- getBillingAddress,
1521
- countries,
1522
- renderCreditCardDialog
1694
+ /* @__PURE__ */ jsx("div", {
1695
+ id: "profile-payment-methods",
1696
+ children: /* @__PURE__ */ jsx(PaymentMethods, {
1697
+ paymentMethods,
1698
+ isLoading: isLoadingPaymentMethods,
1699
+ onDeletePaymentMethod,
1700
+ isDeletingPaymentMethod,
1701
+ onUpdatePaymentMethod,
1702
+ isUpdatingPaymentMethod,
1703
+ getBillingAddress,
1704
+ countries,
1705
+ renderCreditCardDialog
1706
+ })
1523
1707
  })
1524
1708
  ] });
1525
1709
  }
@@ -2802,4 +2986,4 @@ const profileScreenPropertySchema = {
2802
2986
  //#endregion
2803
2987
  export { ProfileScreen_exports as n, profileScreenPropertySchema as r, ProfileScreen as t };
2804
2988
 
2805
- //# sourceMappingURL=ProfileScreen-CiQy6_NM.mjs.map
2989
+ //# sourceMappingURL=ProfileScreen-BuIxKbXC.mjs.map