@insforge/react 1.0.4 → 1.0.5-dev.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.
@@ -163,13 +163,29 @@ declare function VerifyEmail({ token, onSuccess, onError, ...uiProps }: VerifyEm
163
163
  interface UserButtonProps {
164
164
  afterSignOutUrl?: string;
165
165
  mode?: 'detailed' | 'simple';
166
+ /** Whether to show the Profile menu item (default: true) */
167
+ showProfile?: boolean;
168
+ /** Callback when profile update fails */
169
+ onProfileError?: (error: string) => void;
166
170
  }
167
171
  /**
168
172
  * User profile button with dropdown menu and sign-out functionality.
169
173
  *
170
174
  * Styles are powered by Emotion CSS-in-JS to prevent FOUC in SSR environments.
171
175
  */
172
- declare function UserButton({ afterSignOutUrl, mode }: UserButtonProps): react_jsx_runtime.JSX.Element | null;
176
+ declare function UserButton({ afterSignOutUrl, mode, showProfile, onProfileError, }: UserButtonProps): react_jsx_runtime.JSX.Element | null;
177
+
178
+ interface UserProfileModalProps {
179
+ /** Called when the modal is closed */
180
+ onClose: () => void;
181
+ /** Called when an error occurs */
182
+ onError?: (error: string) => void;
183
+ }
184
+ /**
185
+ * User profile modal component.
186
+ * Displays user profile information with edit capability for allowed fields.
187
+ */
188
+ declare function UserProfileModal({ onClose, onError }: UserProfileModalProps): react_jsx_runtime.JSX.Element | null;
173
189
 
174
190
  interface ProtectProps {
175
191
  children: ReactNode;
@@ -341,4 +357,4 @@ interface SignOutButtonProps {
341
357
  */
342
358
  declare function SignOutButton({ children, className, afterSignOutUrl }: SignOutButtonProps): react_jsx_runtime.JSX.Element;
343
359
 
344
- export { type ConditionalProps$1 as ConditionalProps, ForgotPassword, type ForgotPasswordProps, Protect, type ProtectProps, ResetPassword, type ResetPasswordProps, SignIn, SignInButton, type SignInButtonProps, type SignInProps, SignOutButton, type SignOutButtonProps, SignUp, SignUpButton, type SignUpButtonProps, type SignUpProps, SignedIn, SignedOut, UserButton, type UserButtonProps, VerifyEmail, type VerifyEmailProps };
360
+ export { type ConditionalProps$1 as ConditionalProps, ForgotPassword, type ForgotPasswordProps, Protect, type ProtectProps, ResetPassword, type ResetPasswordProps, SignIn, SignInButton, type SignInButtonProps, type SignInProps, SignOutButton, type SignOutButtonProps, SignUp, SignUpButton, type SignUpButtonProps, type SignUpProps, SignedIn, SignedOut, UserButton, type UserButtonProps, UserProfileModal, type UserProfileModalProps, VerifyEmail, type VerifyEmailProps };
@@ -163,13 +163,29 @@ declare function VerifyEmail({ token, onSuccess, onError, ...uiProps }: VerifyEm
163
163
  interface UserButtonProps {
164
164
  afterSignOutUrl?: string;
165
165
  mode?: 'detailed' | 'simple';
166
+ /** Whether to show the Profile menu item (default: true) */
167
+ showProfile?: boolean;
168
+ /** Callback when profile update fails */
169
+ onProfileError?: (error: string) => void;
166
170
  }
167
171
  /**
168
172
  * User profile button with dropdown menu and sign-out functionality.
169
173
  *
170
174
  * Styles are powered by Emotion CSS-in-JS to prevent FOUC in SSR environments.
171
175
  */
172
- declare function UserButton({ afterSignOutUrl, mode }: UserButtonProps): react_jsx_runtime.JSX.Element | null;
176
+ declare function UserButton({ afterSignOutUrl, mode, showProfile, onProfileError, }: UserButtonProps): react_jsx_runtime.JSX.Element | null;
177
+
178
+ interface UserProfileModalProps {
179
+ /** Called when the modal is closed */
180
+ onClose: () => void;
181
+ /** Called when an error occurs */
182
+ onError?: (error: string) => void;
183
+ }
184
+ /**
185
+ * User profile modal component.
186
+ * Displays user profile information with edit capability for allowed fields.
187
+ */
188
+ declare function UserProfileModal({ onClose, onError }: UserProfileModalProps): react_jsx_runtime.JSX.Element | null;
173
189
 
174
190
  interface ProtectProps {
175
191
  children: ReactNode;
@@ -341,4 +357,4 @@ interface SignOutButtonProps {
341
357
  */
342
358
  declare function SignOutButton({ children, className, afterSignOutUrl }: SignOutButtonProps): react_jsx_runtime.JSX.Element;
343
359
 
344
- export { type ConditionalProps$1 as ConditionalProps, ForgotPassword, type ForgotPasswordProps, Protect, type ProtectProps, ResetPassword, type ResetPasswordProps, SignIn, SignInButton, type SignInButtonProps, type SignInProps, SignOutButton, type SignOutButtonProps, SignUp, SignUpButton, type SignUpButtonProps, type SignUpProps, SignedIn, SignedOut, UserButton, type UserButtonProps, VerifyEmail, type VerifyEmailProps };
360
+ export { type ConditionalProps$1 as ConditionalProps, ForgotPassword, type ForgotPasswordProps, Protect, type ProtectProps, ResetPassword, type ResetPasswordProps, SignIn, SignInButton, type SignInButtonProps, type SignInProps, SignOutButton, type SignOutButtonProps, SignUp, SignUpButton, type SignUpButtonProps, type SignUpProps, SignedIn, SignedOut, UserButton, type UserButtonProps, UserProfileModal, type UserProfileModalProps, VerifyEmail, type VerifyEmailProps };
@@ -1,9 +1,8 @@
1
1
  import * as React2 from 'react';
2
2
  import { createContext, forwardRef, useContext, useState, useMemo, useRef, useEffect, useCallback, isValidElement, cloneElement } from 'react';
3
3
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
- import '@insforge/sdk';
5
4
  import { InsforgeContext } from '@insforge/shared/react';
6
- import { AlertTriangle, Check, EyeOff, Eye, Loader2, CircleCheck, LogOut } from 'lucide-react';
5
+ import { AlertTriangle, Check, EyeOff, Eye, Loader2, CircleCheck, X, User, LogOut } from 'lucide-react';
7
6
  import { z } from 'zod';
8
7
 
9
8
  var __create = Object.create;
@@ -211,7 +210,7 @@ var require_react_is_development = __commonJS({
211
210
  var ContextProvider = REACT_PROVIDER_TYPE;
212
211
  var Element = REACT_ELEMENT_TYPE;
213
212
  var ForwardRef = REACT_FORWARD_REF_TYPE;
214
- var Fragment9 = REACT_FRAGMENT_TYPE;
213
+ var Fragment10 = REACT_FRAGMENT_TYPE;
215
214
  var Lazy = REACT_LAZY_TYPE;
216
215
  var Memo = REACT_MEMO_TYPE;
217
216
  var Portal = REACT_PORTAL_TYPE;
@@ -270,7 +269,7 @@ var require_react_is_development = __commonJS({
270
269
  exports$1.ContextProvider = ContextProvider;
271
270
  exports$1.Element = Element;
272
271
  exports$1.ForwardRef = ForwardRef;
273
- exports$1.Fragment = Fragment9;
272
+ exports$1.Fragment = Fragment10;
274
273
  exports$1.Lazy = Lazy;
275
274
  exports$1.Memo = Memo;
276
275
  exports$1.Portal = Portal;
@@ -2127,6 +2126,8 @@ var theme = {
2127
2126
  sm: "0.875rem",
2128
2127
  // 14px
2129
2128
  base: "1rem",
2129
+ // 16px
2130
+ lg: "1.125rem",
2130
2131
  // 20px
2131
2132
  "2xl": "1.5rem"
2132
2133
  // 24px
@@ -2158,6 +2159,10 @@ var theme = {
2158
2159
  base: "200ms cubic-bezier(0.4, 0, 0.2, 1)"
2159
2160
  },
2160
2161
  sizes: {
2162
+ input: {
2163
+ height: "2.5rem"
2164
+ // 40px
2165
+ },
2161
2166
  button: {
2162
2167
  height: "2.5rem",
2163
2168
  // 40px for submit
@@ -4673,9 +4678,384 @@ var UserButtonMenuItemIcon = styled.div`
4673
4678
  height: 100%;
4674
4679
  }
4675
4680
  `;
4676
- function UserButton({ afterSignOutUrl = "/", mode = "simple" }) {
4681
+ var ProfileModalOverlay = styled.div`
4682
+ position: fixed;
4683
+ inset: 0;
4684
+ background-color: rgba(0, 0, 0, 0.5);
4685
+ display: flex;
4686
+ align-items: center;
4687
+ justify-content: center;
4688
+ z-index: 100;
4689
+ padding: ${theme.spacing[4]};
4690
+ `;
4691
+ var ProfileModalContainer = styled.div`
4692
+ background-color: ${theme.colors.bgWhite};
4693
+ border-radius: ${theme.radius.xl};
4694
+ box-shadow: ${theme.shadow.lg};
4695
+ width: 100%;
4696
+ max-width: 400px;
4697
+ max-height: 90vh;
4698
+ overflow: hidden;
4699
+ display: flex;
4700
+ flex-direction: column;
4701
+ font-family: ${theme.fontFamily.base};
4702
+ `;
4703
+ var ProfileModalHeader = styled.div`
4704
+ display: flex;
4705
+ align-items: center;
4706
+ justify-content: space-between;
4707
+ padding: ${theme.spacing[4]} ${theme.spacing[6]};
4708
+ border-bottom: 1px solid ${theme.colors.border};
4709
+ `;
4710
+ var ProfileModalTitle = styled.h2`
4711
+ font-size: ${theme.fontSize.lg};
4712
+ font-weight: ${theme.fontWeight.semibold};
4713
+ color: ${theme.colors.text};
4714
+ margin: 0;
4715
+ `;
4716
+ var ProfileModalCloseButton = styled.button`
4717
+ display: flex;
4718
+ align-items: center;
4719
+ justify-content: center;
4720
+ width: 2rem;
4721
+ height: 2rem;
4722
+ border-radius: ${theme.radius.md};
4723
+ background: none;
4724
+ border: none;
4725
+ cursor: pointer;
4726
+ color: ${theme.colors.textSecondary};
4727
+ transition: all ${theme.transition.fast};
4728
+
4729
+ &:hover {
4730
+ background-color: ${theme.colors.bgLight};
4731
+ color: ${theme.colors.text};
4732
+ }
4733
+
4734
+ svg {
4735
+ width: 1.25rem;
4736
+ height: 1.25rem;
4737
+ }
4738
+ `;
4739
+ var ProfileModalBody = styled.div`
4740
+ padding: ${theme.spacing[6]};
4741
+ overflow-y: auto;
4742
+ flex: 1;
4743
+ `;
4744
+ var ProfileAvatarSection = styled.div`
4745
+ display: flex;
4746
+ flex-direction: column;
4747
+ align-items: center;
4748
+ margin-bottom: ${theme.spacing[6]};
4749
+ `;
4750
+ var ProfileAvatar = styled.div`
4751
+ width: 5rem;
4752
+ height: 5rem;
4753
+ border-radius: ${theme.radius.full};
4754
+ background-color: ${theme.colors.primary};
4755
+ color: ${theme.colors.bgWhite};
4756
+ display: flex;
4757
+ align-items: center;
4758
+ justify-content: center;
4759
+ font-weight: ${theme.fontWeight.semibold};
4760
+ font-size: ${theme.fontSize["2xl"]};
4761
+ overflow: hidden;
4762
+ `;
4763
+ var ProfileAvatarImage = styled.img`
4764
+ width: 100%;
4765
+ height: 100%;
4766
+ object-fit: cover;
4767
+ `;
4768
+ var ProfileFieldsContainer = styled.div`
4769
+ display: flex;
4770
+ flex-direction: column;
4771
+ gap: ${theme.spacing[4]};
4772
+ `;
4773
+ var ProfileField = styled.div`
4774
+ display: flex;
4775
+ flex-direction: column;
4776
+ gap: ${theme.spacing[1]};
4777
+ `;
4778
+ var ProfileFieldLabel = styled.label`
4779
+ font-size: ${theme.fontSize.sm};
4780
+ font-weight: ${theme.fontWeight.medium};
4781
+ color: ${theme.colors.textSecondary};
4782
+ text-transform: capitalize;
4783
+ `;
4784
+ var ProfileFieldValue = styled.div`
4785
+ font-size: ${theme.fontSize.base};
4786
+ color: ${theme.colors.text};
4787
+ padding: ${theme.spacing[2]} 0;
4788
+ word-break: break-word;
4789
+ `;
4790
+ var ProfileFieldInput = styled.input`
4791
+ width: 100%;
4792
+ height: ${theme.sizes.input.height};
4793
+ padding: 0 ${theme.spacing[3]};
4794
+ border: 1px solid ${theme.colors.border};
4795
+ border-radius: ${theme.radius.md};
4796
+ font-size: ${theme.fontSize.base};
4797
+ font-family: ${theme.fontFamily.base};
4798
+ color: ${theme.colors.text};
4799
+ background-color: ${theme.colors.bgWhite};
4800
+ transition: border-color ${theme.transition.fast};
4801
+
4802
+ &:focus {
4803
+ outline: none;
4804
+ border-color: ${theme.colors.borderFocus};
4805
+ }
4806
+
4807
+ &:disabled {
4808
+ background-color: ${theme.colors.bgLight};
4809
+ color: ${theme.colors.textSecondary};
4810
+ cursor: not-allowed;
4811
+ }
4812
+ `;
4813
+ var ProfileModalFooter = styled.div`
4814
+ display: flex;
4815
+ align-items: center;
4816
+ justify-content: flex-end;
4817
+ gap: ${theme.spacing[3]};
4818
+ padding: ${theme.spacing[4]} ${theme.spacing[6]};
4819
+ border-top: 1px solid ${theme.colors.border};
4820
+ `;
4821
+ var ProfileButton = styled.button`
4822
+ display: flex;
4823
+ align-items: center;
4824
+ justify-content: center;
4825
+ gap: ${theme.spacing[2]};
4826
+ height: ${theme.sizes.button.height};
4827
+ padding: 0 ${theme.spacing[4]};
4828
+ border-radius: ${theme.radius.md};
4829
+ font-size: ${theme.fontSize.sm};
4830
+ font-weight: ${theme.fontWeight.medium};
4831
+ font-family: ${theme.fontFamily.base};
4832
+ cursor: pointer;
4833
+ transition: all ${theme.transition.fast};
4834
+
4835
+ ${(props) => props.$primary ? `
4836
+ background-color: ${theme.colors.primary};
4837
+ color: ${theme.colors.bgWhite};
4838
+ border: none;
4839
+
4840
+ &:hover:not(:disabled) {
4841
+ background-color: ${theme.colors.primaryHover};
4842
+ }
4843
+
4844
+ &:disabled {
4845
+ opacity: 0.5;
4846
+ cursor: not-allowed;
4847
+ }
4848
+ ` : `
4849
+ background-color: ${theme.colors.bgWhite};
4850
+ color: ${theme.colors.text};
4851
+ border: 1px solid ${theme.colors.border};
4852
+
4853
+ &:hover:not(:disabled) {
4854
+ background-color: ${theme.colors.bgLight};
4855
+ }
4856
+
4857
+ &:disabled {
4858
+ opacity: 0.5;
4859
+ cursor: not-allowed;
4860
+ }
4861
+ `}
4862
+ `;
4863
+ var ProfileSpinner = styled.div`
4864
+ width: 1rem;
4865
+ height: 1rem;
4866
+ border: 2px solid transparent;
4867
+ border-top-color: currentColor;
4868
+ border-radius: ${theme.radius.full};
4869
+ animation: spin 0.6s linear infinite;
4870
+
4871
+ @keyframes spin {
4872
+ to {
4873
+ transform: rotate(360deg);
4874
+ }
4875
+ }
4876
+ `;
4877
+ var READ_ONLY_FIELDS = ["id", "email", "avatar_url", "created_at", "updated_at"];
4878
+ var HIDDEN_FIELDS = ["id"];
4879
+ function formatFieldLabel(key) {
4880
+ return key.replace(/_/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase();
4881
+ }
4882
+ function UserProfileModal({ onClose, onError }) {
4883
+ const { user, updateUser, isLoaded } = useInsforge();
4884
+ const [isEditing, setIsEditing] = useState(false);
4885
+ const [isSaving, setIsSaving] = useState(false);
4886
+ const [imageError, setImageError] = useState(false);
4887
+ const [formData, setFormData] = useState({});
4888
+ useEffect(() => {
4889
+ if (user) {
4890
+ const initialData = {
4891
+ name: user.profile?.name || ""
4892
+ };
4893
+ if (user.profile) {
4894
+ Object.entries(user.profile).forEach(([key, value]) => {
4895
+ if (!HIDDEN_FIELDS.includes(key) && typeof value === "string") {
4896
+ initialData[key] = value;
4897
+ }
4898
+ });
4899
+ }
4900
+ setFormData(initialData);
4901
+ }
4902
+ }, [user]);
4903
+ useEffect(() => {
4904
+ setImageError(false);
4905
+ const avatarUrl = user?.profile?.avatar_url;
4906
+ if (!avatarUrl) {
4907
+ return;
4908
+ }
4909
+ const checkImageUrl = async () => {
4910
+ try {
4911
+ const response = await fetch(avatarUrl, {
4912
+ method: "HEAD",
4913
+ cache: "no-cache"
4914
+ });
4915
+ if (!response.ok) {
4916
+ setImageError(true);
4917
+ }
4918
+ } catch {
4919
+ setImageError(true);
4920
+ }
4921
+ };
4922
+ void checkImageUrl();
4923
+ }, [user?.profile?.avatar_url]);
4924
+ const handleFieldChange = useCallback((key, value) => {
4925
+ setFormData((prev2) => ({
4926
+ ...prev2,
4927
+ [key]: value
4928
+ }));
4929
+ }, []);
4930
+ const handleSave = useCallback(async () => {
4931
+ if (!user) return;
4932
+ setIsSaving(true);
4933
+ try {
4934
+ const { name, ...dynamicFields } = formData;
4935
+ const updateData = {
4936
+ profile: {
4937
+ name
4938
+ }
4939
+ };
4940
+ if (Object.keys(dynamicFields).length > 0) {
4941
+ updateData.profile = dynamicFields;
4942
+ }
4943
+ const result = await updateUser(updateData);
4944
+ if (result?.error) {
4945
+ onError?.(result.error);
4946
+ } else {
4947
+ setIsEditing(false);
4948
+ }
4949
+ } catch (error) {
4950
+ onError?.(error instanceof Error ? error.message : "Failed to update profile");
4951
+ } finally {
4952
+ setIsSaving(false);
4953
+ }
4954
+ }, [user, formData, updateUser, onError]);
4955
+ const handleCancel = useCallback(() => {
4956
+ if (user) {
4957
+ const resetData = {
4958
+ name: user.profile?.name || ""
4959
+ };
4960
+ if (user.profile) {
4961
+ Object.entries(user.profile).forEach(([key, value]) => {
4962
+ if (!HIDDEN_FIELDS.includes(key) && typeof value === "string") {
4963
+ resetData[key] = value;
4964
+ }
4965
+ });
4966
+ }
4967
+ setFormData(resetData);
4968
+ }
4969
+ setIsEditing(false);
4970
+ }, [user]);
4971
+ const handleOverlayClick = useCallback(
4972
+ (e) => {
4973
+ if (e.target === e.currentTarget) {
4974
+ onClose();
4975
+ }
4976
+ },
4977
+ [onClose]
4978
+ );
4979
+ useEffect(() => {
4980
+ const handleEscape = (e) => {
4981
+ if (e.key === "Escape") {
4982
+ if (isEditing) {
4983
+ handleCancel();
4984
+ } else {
4985
+ onClose();
4986
+ }
4987
+ }
4988
+ };
4989
+ document.addEventListener("keydown", handleEscape);
4990
+ return () => document.removeEventListener("keydown", handleEscape);
4991
+ }, [isEditing, handleCancel, onClose]);
4992
+ if (!isLoaded || !user) {
4993
+ return null;
4994
+ }
4995
+ const initials = user.profile?.name ? user.profile.name.charAt(0).toUpperCase() : user.email.split("@")[0].slice(0, 2).toUpperCase();
4996
+ const fields = [];
4997
+ fields.push({ key: "email", value: user.email, readOnly: true });
4998
+ fields.push({
4999
+ key: "name",
5000
+ value: isEditing ? formData.name || "" : user.profile?.name || "",
5001
+ readOnly: false
5002
+ });
5003
+ if (user.profile) {
5004
+ Object.entries(user.profile).forEach(([key, value]) => {
5005
+ if (!HIDDEN_FIELDS.includes(key) && typeof value === "string") {
5006
+ fields.push({
5007
+ key,
5008
+ value: isEditing ? formData[key] ?? value : value,
5009
+ readOnly: READ_ONLY_FIELDS.includes(key)
5010
+ });
5011
+ }
5012
+ });
5013
+ }
5014
+ return /* @__PURE__ */ jsx(ProfileModalOverlay, { onClick: handleOverlayClick, children: /* @__PURE__ */ jsxs(ProfileModalContainer, { onClick: (e) => e.stopPropagation(), children: [
5015
+ /* @__PURE__ */ jsxs(ProfileModalHeader, { children: [
5016
+ /* @__PURE__ */ jsx(ProfileModalTitle, { children: "Profile" }),
5017
+ /* @__PURE__ */ jsx(ProfileModalCloseButton, { onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx(X, {}) })
5018
+ ] }),
5019
+ /* @__PURE__ */ jsxs(ProfileModalBody, { children: [
5020
+ /* @__PURE__ */ jsx(ProfileAvatarSection, { children: /* @__PURE__ */ jsx(ProfileAvatar, { children: user.profile?.avatar_url && !imageError ? /* @__PURE__ */ jsx(
5021
+ ProfileAvatarImage,
5022
+ {
5023
+ src: user.profile.avatar_url,
5024
+ alt: user.profile?.name || user.email,
5025
+ onError: () => setImageError(true)
5026
+ }
5027
+ ) : initials }) }),
5028
+ /* @__PURE__ */ jsx(ProfileFieldsContainer, { children: fields.map(({ key, value, readOnly }) => /* @__PURE__ */ jsxs(ProfileField, { children: [
5029
+ /* @__PURE__ */ jsx(ProfileFieldLabel, { children: formatFieldLabel(key) }),
5030
+ isEditing && !readOnly ? /* @__PURE__ */ jsx(
5031
+ ProfileFieldInput,
5032
+ {
5033
+ type: "text",
5034
+ value: formData[key] ?? value,
5035
+ onChange: (e) => handleFieldChange(key, e.target.value),
5036
+ disabled: isSaving
5037
+ }
5038
+ ) : /* @__PURE__ */ jsx(ProfileFieldValue, { children: value || "-" })
5039
+ ] }, key)) })
5040
+ ] }),
5041
+ /* @__PURE__ */ jsx(ProfileModalFooter, { children: isEditing ? /* @__PURE__ */ jsxs(Fragment, { children: [
5042
+ /* @__PURE__ */ jsx(ProfileButton, { onClick: handleCancel, disabled: isSaving, children: "Cancel" }),
5043
+ /* @__PURE__ */ jsxs(ProfileButton, { $primary: true, onClick: () => void handleSave(), disabled: isSaving, children: [
5044
+ isSaving && /* @__PURE__ */ jsx(ProfileSpinner, {}),
5045
+ isSaving ? "Saving..." : "Save"
5046
+ ] })
5047
+ ] }) : /* @__PURE__ */ jsx(ProfileButton, { $primary: true, onClick: () => setIsEditing(true), children: "Edit Profile" }) })
5048
+ ] }) });
5049
+ }
5050
+ function UserButton({
5051
+ afterSignOutUrl = "/",
5052
+ mode = "simple",
5053
+ showProfile = true,
5054
+ onProfileError
5055
+ }) {
4677
5056
  const { user } = useInsforge();
4678
5057
  const [isOpen, setIsOpen] = useState(false);
5058
+ const [showProfileModal, setShowProfileModal] = useState(false);
4679
5059
  const [imageError, setImageError] = useState(false);
4680
5060
  const [openUpward, setOpenUpward] = useState(false);
4681
5061
  const [horizontalOffset, setHorizontalOffset] = useState(0);
@@ -4683,7 +5063,7 @@ function UserButton({ afterSignOutUrl = "/", mode = "simple" }) {
4683
5063
  const menuRef = useRef(null);
4684
5064
  useEffect(() => {
4685
5065
  setImageError(false);
4686
- const avatarUrl = user?.avatarUrl;
5066
+ const avatarUrl = user?.profile?.avatar_url;
4687
5067
  if (!avatarUrl) {
4688
5068
  return;
4689
5069
  }
@@ -4704,7 +5084,7 @@ function UserButton({ afterSignOutUrl = "/", mode = "simple" }) {
4704
5084
  }
4705
5085
  };
4706
5086
  void checkImageUrl();
4707
- }, [user?.avatarUrl]);
5087
+ }, [user?.profile?.avatar_url]);
4708
5088
  useEffect(() => {
4709
5089
  if (isOpen && dropdownRef.current) {
4710
5090
  const buttonRect = dropdownRef.current.getBoundingClientRect();
@@ -4748,7 +5128,7 @@ function UserButton({ afterSignOutUrl = "/", mode = "simple" }) {
4748
5128
  if (!user) {
4749
5129
  return null;
4750
5130
  }
4751
- const initials = user.name ? user.name.charAt(0).toUpperCase() : user.email.split("@")[0].slice(0, 2).toUpperCase();
5131
+ const initials = user.profile?.name ? user.profile.name.charAt(0).toUpperCase() : user.email.split("@")[0].slice(0, 2).toUpperCase();
4752
5132
  return /* @__PURE__ */ jsxs(UserButtonContainer, { ref: dropdownRef, children: [
4753
5133
  /* @__PURE__ */ jsxs(
4754
5134
  UserButtonButton,
@@ -4758,25 +5138,41 @@ function UserButton({ afterSignOutUrl = "/", mode = "simple" }) {
4758
5138
  "aria-expanded": isOpen,
4759
5139
  "aria-haspopup": "true",
4760
5140
  children: [
4761
- /* @__PURE__ */ jsx(UserButtonAvatar, { children: user.avatarUrl && !imageError ? /* @__PURE__ */ jsx(
5141
+ /* @__PURE__ */ jsx(UserButtonAvatar, { children: user.profile?.avatar_url && !imageError ? /* @__PURE__ */ jsx(
4762
5142
  UserButtonAvatarImage,
4763
5143
  {
4764
- src: user.avatarUrl,
5144
+ src: user.profile.avatar_url,
4765
5145
  alt: user.email,
4766
5146
  onError: () => setImageError(true)
4767
5147
  }
4768
5148
  ) : /* @__PURE__ */ jsx(UserButtonAvatarInitials, { children: initials }) }),
4769
5149
  mode === "detailed" && /* @__PURE__ */ jsxs(UserButtonInfo, { children: [
4770
- user.name && /* @__PURE__ */ jsx(UserButtonName, { children: user.name }),
5150
+ user.profile?.name && /* @__PURE__ */ jsx(UserButtonName, { children: user.profile.name }),
4771
5151
  /* @__PURE__ */ jsx(UserButtonEmail, { children: user.email })
4772
5152
  ] })
4773
5153
  ]
4774
5154
  }
4775
5155
  ),
4776
- isOpen && /* @__PURE__ */ jsx(UserButtonMenu, { ref: menuRef, $openUpward: openUpward, $horizontalOffset: horizontalOffset, children: /* @__PURE__ */ jsx(SignOutButton, { afterSignOutUrl, children: /* @__PURE__ */ jsxs(UserButtonMenuItem, { $signout: true, onClick: () => setIsOpen(false), children: [
4777
- /* @__PURE__ */ jsx(UserButtonMenuItemIcon, { children: /* @__PURE__ */ jsx(LogOut, {}) }),
4778
- "Sign out"
4779
- ] }) }) })
5156
+ isOpen && /* @__PURE__ */ jsxs(UserButtonMenu, { ref: menuRef, $openUpward: openUpward, $horizontalOffset: horizontalOffset, children: [
5157
+ showProfile && /* @__PURE__ */ jsxs(
5158
+ UserButtonMenuItem,
5159
+ {
5160
+ onClick: () => {
5161
+ setShowProfileModal(true);
5162
+ setIsOpen(false);
5163
+ },
5164
+ children: [
5165
+ /* @__PURE__ */ jsx(UserButtonMenuItemIcon, { children: /* @__PURE__ */ jsx(User, {}) }),
5166
+ "Profile"
5167
+ ]
5168
+ }
5169
+ ),
5170
+ /* @__PURE__ */ jsx(SignOutButton, { afterSignOutUrl, children: /* @__PURE__ */ jsxs(UserButtonMenuItem, { $signout: true, onClick: () => setIsOpen(false), children: [
5171
+ /* @__PURE__ */ jsx(UserButtonMenuItemIcon, { children: /* @__PURE__ */ jsx(LogOut, {}) }),
5172
+ "Sign out"
5173
+ ] }) })
5174
+ ] }),
5175
+ showProfileModal && /* @__PURE__ */ jsx(UserProfileModal, { onClose: () => setShowProfileModal(false), onError: onProfileError })
4780
5176
  ] });
4781
5177
  }
4782
5178
  function Protect({
@@ -4895,6 +5291,6 @@ react-is/cjs/react-is.development.js:
4895
5291
  *)
4896
5292
  */
4897
5293
 
4898
- export { AuthBranding, AuthContainer, AuthDivider, AuthEmailVerificationStep, AuthErrorBanner, AuthFormField, AuthHeader, AuthLink, AuthOAuthButton, AuthOAuthProviders, AuthPasswordField, AuthPasswordStrengthIndicator, AuthResetPasswordVerificationStep, AuthSubmitButton, AuthVerificationCodeInput, ForgotPassword, ForgotPasswordForm, Protect, ResetPassword, ResetPasswordForm, SignIn, SignInButton, SignInForm, SignOutButton, SignUp, SignUpButton, SignUpForm, SignedIn, SignedOut, UserButton, VerifyEmail, VerifyEmailStatus };
5294
+ export { AuthBranding, AuthContainer, AuthDivider, AuthEmailVerificationStep, AuthErrorBanner, AuthFormField, AuthHeader, AuthLink, AuthOAuthButton, AuthOAuthProviders, AuthPasswordField, AuthPasswordStrengthIndicator, AuthResetPasswordVerificationStep, AuthSubmitButton, AuthVerificationCodeInput, ForgotPassword, ForgotPasswordForm, Protect, ResetPassword, ResetPasswordForm, SignIn, SignInButton, SignInForm, SignOutButton, SignUp, SignUpButton, SignUpForm, SignedIn, SignedOut, UserButton, UserProfileModal, VerifyEmail, VerifyEmailStatus };
4899
5295
  //# sourceMappingURL=components.js.map
4900
5296
  //# sourceMappingURL=components.js.map