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