@riligar/auth-react 1.9.4 → 1.10.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/dist/index.esm.js CHANGED
@@ -3,9 +3,10 @@ import { useMemo, useEffect, createContext, useState, useRef } from 'react';
3
3
  import { useShallow } from 'zustand/react/shallow';
4
4
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
5
  import { Navigate, Outlet } from 'react-router-dom';
6
- import { Paper, Stack, Image, Title, Text, TextInput, PasswordInput, Anchor, Button, Divider, Group, Center, Loader } from '@mantine/core';
6
+ import { Paper, Stack, Image, Title, Text, TextInput, PasswordInput, Anchor, Button, Divider, Group, Center, Loader, Modal, Box, Avatar, Collapse, Card, Tooltip, ThemeIcon } from '@mantine/core';
7
7
  import { useForm } from '@mantine/form';
8
- import { IconMail, IconLock, IconArrowRight, IconBrandGoogle, IconBrandGithub, IconUser, IconSend, IconCheck, IconX, IconRefresh } from '@tabler/icons-react';
8
+ import { IconMail, IconLock, IconArrowRight, IconBrandGoogle, IconBrandGithub, IconUser, IconSend, IconCheck, IconX, IconRefresh, IconPhoto, IconTrash, IconPencil, IconShield, IconKey, IconUserCircle } from '@tabler/icons-react';
9
+ import { notifications } from '@mantine/notifications';
9
10
 
10
11
  // Config - pode ser sobrescrita pelo AuthProvider
11
12
  // Tenta detectar ambiente Vite, mas falha graciosamente se não existir
@@ -281,6 +282,34 @@ const getApplicationInfo = async () => {
281
282
  }
282
283
  };
283
284
 
285
+ /*--- Profile Management ---------------------------*/
286
+ const updateProfile = async data => {
287
+ return await api('/auth/update-user', {
288
+ method: 'POST',
289
+ body: JSON.stringify(data)
290
+ });
291
+ };
292
+ const changePassword = async (currentPassword, newPassword, revokeOtherSessions = false) => {
293
+ return await api('/auth/change-password', {
294
+ method: 'POST',
295
+ body: JSON.stringify({
296
+ currentPassword,
297
+ newPassword,
298
+ revokeOtherSessions
299
+ })
300
+ });
301
+ };
302
+ const changeEmail = async (newEmail, callbackURL) => {
303
+ const callback = callbackURL || (typeof window !== 'undefined' ? `${window.location.origin}/auth/verify-email` : '/auth/verify-email');
304
+ return await api('/auth/change-email', {
305
+ method: 'POST',
306
+ body: JSON.stringify({
307
+ newEmail,
308
+ callbackURL: callback
309
+ })
310
+ });
311
+ };
312
+
284
313
  /* Social login redirect (ex.: Google) -----------*/
285
314
  function socialRedirect(provider, redirectTo = typeof window !== 'undefined' ? window.location.href : '/') {
286
315
  if (typeof window === 'undefined') return;
@@ -301,7 +330,10 @@ const useAuthStore = create((set, get) => ({
301
330
  verifyMagicLink: false,
302
331
  resetPassword: false,
303
332
  verifyEmail: false,
304
- resendVerification: false
333
+ resendVerification: false,
334
+ updateProfile: false,
335
+ changePassword: false,
336
+ changeEmail: false
305
337
  },
306
338
  // Application info (logo, nome, etc)
307
339
  applicationInfo: null,
@@ -668,7 +700,75 @@ const useAuthStore = create((set, get) => ({
668
700
  /* Atualizar usuário manualmente */
669
701
  setUser: user => set({
670
702
  user
671
- })
703
+ }),
704
+ /* Profile Management */
705
+ updateProfile: async data => {
706
+ const {
707
+ setLoading
708
+ } = get();
709
+ setLoading('updateProfile', true);
710
+ set({
711
+ error: null
712
+ });
713
+ try {
714
+ const result = await updateProfile(data);
715
+ // Atualiza o user no store com os novos dados
716
+ set(state => ({
717
+ user: state.user ? {
718
+ ...state.user,
719
+ ...data
720
+ } : null
721
+ }));
722
+ setLoading('updateProfile', false);
723
+ return result;
724
+ } catch (err) {
725
+ set({
726
+ error: err
727
+ });
728
+ setLoading('updateProfile', false);
729
+ throw err;
730
+ }
731
+ },
732
+ changePassword: async (currentPassword, newPassword, revokeOtherSessions = false) => {
733
+ const {
734
+ setLoading
735
+ } = get();
736
+ setLoading('changePassword', true);
737
+ set({
738
+ error: null
739
+ });
740
+ try {
741
+ const result = await changePassword(currentPassword, newPassword, revokeOtherSessions);
742
+ setLoading('changePassword', false);
743
+ return result;
744
+ } catch (err) {
745
+ set({
746
+ error: err
747
+ });
748
+ setLoading('changePassword', false);
749
+ throw err;
750
+ }
751
+ },
752
+ changeEmail: async (newEmail, callbackURL) => {
753
+ const {
754
+ setLoading
755
+ } = get();
756
+ setLoading('changeEmail', true);
757
+ set({
758
+ error: null
759
+ });
760
+ try {
761
+ const result = await changeEmail(newEmail, callbackURL);
762
+ setLoading('changeEmail', false);
763
+ return result;
764
+ } catch (err) {
765
+ set({
766
+ error: err
767
+ });
768
+ setLoading('changeEmail', false);
769
+ throw err;
770
+ }
771
+ }
672
772
  }));
673
773
 
674
774
  const AuthContext = /*#__PURE__*/createContext(); // só para ter o Provider em JSX
@@ -792,6 +892,18 @@ const useSession = () => useAuthStore(useShallow(s => ({
792
892
  // Loading States Hook
793
893
  const useAuthLoading = () => useAuthStore(s => s.loadingStates);
794
894
 
895
+ // Profile Management Hook
896
+ const useProfile = () => useAuthStore(useShallow(s => ({
897
+ user: s.user,
898
+ updateProfile: s.updateProfile,
899
+ changePassword: s.changePassword,
900
+ changeEmail: s.changeEmail,
901
+ loadingUpdateProfile: s.loadingStates.updateProfile,
902
+ loadingChangePassword: s.loadingStates.changePassword,
903
+ loadingChangeEmail: s.loadingStates.changeEmail,
904
+ error: s.error
905
+ })));
906
+
795
907
  // Application Logo Hook
796
908
  const useApplicationLogo = () => {
797
909
  const applicationInfo = useAuthStore(s => s.applicationInfo);
@@ -1728,5 +1840,680 @@ function VerifyEmailCard({
1728
1840
  });
1729
1841
  }
1730
1842
 
1731
- export { AuthCard, AuthProvider, ForgotPasswordForm, MagicLinkForm, MagicLinkVerify, ProtectedRoute, ResetPasswordForm, SignInForm, SignUpForm, VerifyEmailCard, configure, decodeJWT, forgotPassword, getApplicationInfo, getCurrentUser, getSession, isAuthenticated, refreshToken, resendVerification, resetPassword, sendMagicLink, signIn, signOut, signUp, socialRedirect, useAuth, useAuthLoading, useAuthStore, useCheckToken, useEmailVerification, useMagicLink, usePasswordReset, useSession, useSignIn, useSignOut, useSignUp, verifyEmail, verifyMagicLink };
1843
+ function AccountModal({
1844
+ // Controle do modal
1845
+ opened,
1846
+ onClose,
1847
+ // Callbacks
1848
+ onProfileUpdate,
1849
+ onPasswordChange,
1850
+ onEmailChange,
1851
+ onError,
1852
+ // Features toggle
1853
+ showAvatar = true,
1854
+ showName = true,
1855
+ showEmail = true,
1856
+ showPassword = true,
1857
+ // Customização
1858
+ labels = {},
1859
+ title = 'Account',
1860
+ subtitle = 'Manage your account info.',
1861
+ // Avatar config
1862
+ maxAvatarSize = 500 * 1024,
1863
+ // 500KB
1864
+
1865
+ ...modalProps
1866
+ }) {
1867
+ // Local state - which section is expanded
1868
+ const [editingSection, setEditingSection] = useState(null); // 'password' | 'email' | 'name' | 'avatar' | null
1869
+
1870
+ // Hook para profile
1871
+ const {
1872
+ user,
1873
+ updateProfile,
1874
+ changePassword,
1875
+ changeEmail,
1876
+ loadingUpdateProfile,
1877
+ loadingChangePassword,
1878
+ loadingChangeEmail
1879
+ } = useProfile();
1880
+
1881
+ // Password form
1882
+ const passwordForm = useForm({
1883
+ initialValues: {
1884
+ currentPassword: '',
1885
+ newPassword: '',
1886
+ confirmPassword: ''
1887
+ },
1888
+ validate: {
1889
+ currentPassword: v => !v ? labels.currentPasswordRequired || 'Senha atual obrigatória' : null,
1890
+ newPassword: v => {
1891
+ if (!v) return labels.newPasswordRequired || 'Nova senha obrigatória';
1892
+ if (v.length < 8) return labels.passwordMinLength || 'Mínimo 8 caracteres';
1893
+ return null;
1894
+ },
1895
+ confirmPassword: (v, values) => v !== values.newPassword ? labels.passwordMismatch || 'Senhas não coincidem' : null
1896
+ }
1897
+ });
1898
+
1899
+ // Email form
1900
+ const emailForm = useForm({
1901
+ initialValues: {
1902
+ newEmail: ''
1903
+ },
1904
+ validate: {
1905
+ newEmail: v => {
1906
+ if (!v) return labels.emailRequired || 'Email obrigatório';
1907
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v)) return labels.emailInvalid || 'Email inválido';
1908
+ return null;
1909
+ }
1910
+ }
1911
+ });
1912
+
1913
+ // Name form
1914
+ const nameForm = useForm({
1915
+ initialValues: {
1916
+ name: ''
1917
+ },
1918
+ validate: {
1919
+ name: v => !v ? labels.nameRequired || 'Nome obrigatório' : null
1920
+ }
1921
+ });
1922
+
1923
+ // Avatar state (base64)
1924
+ const [avatarPreview, setAvatarPreview] = useState(null);
1925
+ const [avatarFile, setAvatarFile] = useState(null);
1926
+
1927
+ // Handle file selection and convert to base64
1928
+ const handleAvatarFileChange = file => {
1929
+ if (!file) {
1930
+ setAvatarPreview(null);
1931
+ setAvatarFile(null);
1932
+ return;
1933
+ }
1934
+
1935
+ // Validate file type
1936
+ if (!file.type.startsWith('image/')) {
1937
+ notifications.show({
1938
+ title: labels.errorTitle || 'Erro',
1939
+ message: labels.avatarInvalidType || 'Por favor, selecione uma imagem válida',
1940
+ color: 'red'
1941
+ });
1942
+ return;
1943
+ }
1944
+
1945
+ // Validate file size
1946
+ if (file.size > maxAvatarSize) {
1947
+ notifications.show({
1948
+ title: labels.errorTitle || 'Erro',
1949
+ message: labels.avatarTooLarge || `Imagem muito grande. Máximo ${Math.round(maxAvatarSize / 1024)}KB.`,
1950
+ color: 'red'
1951
+ });
1952
+ return;
1953
+ }
1954
+ setAvatarFile(file);
1955
+
1956
+ // Convert to base64
1957
+ const reader = new FileReader();
1958
+ reader.onloadend = () => {
1959
+ setAvatarPreview(reader.result);
1960
+ };
1961
+ reader.readAsDataURL(file);
1962
+ };
1963
+
1964
+ // Populate forms when user data is available or section opens
1965
+ useEffect(() => {
1966
+ if (editingSection === 'name' && user?.name) {
1967
+ nameForm.setValues({
1968
+ name: user.name
1969
+ });
1970
+ }
1971
+ if (editingSection === 'avatar' && user?.image) {
1972
+ setAvatarPreview(user.image);
1973
+ }
1974
+ }, [editingSection, user]);
1975
+ const handleToggleSection = section => {
1976
+ if (editingSection === section) {
1977
+ setEditingSection(null);
1978
+ passwordForm.reset();
1979
+ emailForm.reset();
1980
+ nameForm.reset();
1981
+ setAvatarPreview(null);
1982
+ setAvatarFile(null);
1983
+ } else {
1984
+ setEditingSection(section);
1985
+ }
1986
+ };
1987
+ const handleChangePassword = async values => {
1988
+ try {
1989
+ await changePassword(values.currentPassword, values.newPassword);
1990
+ notifications.show({
1991
+ title: labels.successTitle || 'Sucesso',
1992
+ message: labels.passwordChanged || 'Senha alterada com sucesso',
1993
+ color: 'green'
1994
+ });
1995
+ passwordForm.reset();
1996
+ setEditingSection(null);
1997
+ onPasswordChange?.();
1998
+ } catch (error) {
1999
+ notifications.show({
2000
+ title: labels.errorTitle || 'Erro',
2001
+ message: error.message || labels.passwordChangeFailed || 'Falha ao alterar senha',
2002
+ color: 'red'
2003
+ });
2004
+ onError?.(error);
2005
+ }
2006
+ };
2007
+ const handleChangeEmail = async values => {
2008
+ try {
2009
+ await changeEmail(values.newEmail);
2010
+ notifications.show({
2011
+ title: labels.successTitle || 'Sucesso',
2012
+ message: labels.emailVerificationSent || 'Verifique seu novo email para confirmar a alteração',
2013
+ color: 'green'
2014
+ });
2015
+ emailForm.reset();
2016
+ setEditingSection(null);
2017
+ onEmailChange?.(values.newEmail);
2018
+ } catch (error) {
2019
+ notifications.show({
2020
+ title: labels.errorTitle || 'Erro',
2021
+ message: error.message || labels.emailChangeFailed || 'Falha ao alterar email',
2022
+ color: 'red'
2023
+ });
2024
+ onError?.(error);
2025
+ }
2026
+ };
2027
+ const handleChangeName = async values => {
2028
+ try {
2029
+ await updateProfile({
2030
+ name: values.name
2031
+ });
2032
+ notifications.show({
2033
+ title: labels.successTitle || 'Sucesso',
2034
+ message: labels.nameUpdated || 'Nome atualizado com sucesso',
2035
+ color: 'green'
2036
+ });
2037
+ nameForm.reset();
2038
+ setEditingSection(null);
2039
+ onProfileUpdate?.({
2040
+ name: values.name
2041
+ });
2042
+ } catch (error) {
2043
+ notifications.show({
2044
+ title: labels.errorTitle || 'Erro',
2045
+ message: error.message || labels.nameUpdateFailed || 'Falha ao atualizar nome',
2046
+ color: 'red'
2047
+ });
2048
+ onError?.(error);
2049
+ }
2050
+ };
2051
+ const handleChangeAvatar = async () => {
2052
+ if (!avatarPreview) {
2053
+ notifications.show({
2054
+ title: labels.errorTitle || 'Erro',
2055
+ message: labels.avatarRequired || 'Selecione uma imagem',
2056
+ color: 'red'
2057
+ });
2058
+ return;
2059
+ }
2060
+ try {
2061
+ await updateProfile({
2062
+ image: avatarPreview
2063
+ });
2064
+ notifications.show({
2065
+ title: labels.successTitle || 'Sucesso',
2066
+ message: labels.avatarUpdated || 'Foto de perfil atualizada com sucesso',
2067
+ color: 'green'
2068
+ });
2069
+ setAvatarPreview(null);
2070
+ setAvatarFile(null);
2071
+ setEditingSection(null);
2072
+ onProfileUpdate?.({
2073
+ image: avatarPreview
2074
+ });
2075
+ } catch (error) {
2076
+ notifications.show({
2077
+ title: labels.errorTitle || 'Erro',
2078
+ message: error.message || labels.avatarUpdateFailed || 'Falha ao atualizar foto',
2079
+ color: 'red'
2080
+ });
2081
+ onError?.(error);
2082
+ }
2083
+ };
2084
+ const handleRemoveAvatar = async () => {
2085
+ try {
2086
+ await updateProfile({
2087
+ image: ''
2088
+ });
2089
+ notifications.show({
2090
+ title: labels.successTitle || 'Sucesso',
2091
+ message: labels.avatarRemoved || 'Foto de perfil removida',
2092
+ color: 'green'
2093
+ });
2094
+ setAvatarPreview(null);
2095
+ setAvatarFile(null);
2096
+ setEditingSection(null);
2097
+ onProfileUpdate?.({
2098
+ image: ''
2099
+ });
2100
+ } catch (error) {
2101
+ notifications.show({
2102
+ title: labels.errorTitle || 'Erro',
2103
+ message: error.message || labels.avatarRemoveFailed || 'Falha ao remover foto',
2104
+ color: 'red'
2105
+ });
2106
+ onError?.(error);
2107
+ }
2108
+ };
2109
+
2110
+ // Reusable Section Header
2111
+ const SectionHeader = ({
2112
+ icon: Icon,
2113
+ sectionTitle,
2114
+ description
2115
+ }) => /*#__PURE__*/jsxs(Group, {
2116
+ gap: "sm",
2117
+ mb: "lg",
2118
+ children: [/*#__PURE__*/jsx(ThemeIcon, {
2119
+ size: 36,
2120
+ variant: "light",
2121
+ children: /*#__PURE__*/jsx(Icon, {
2122
+ size: 18
2123
+ })
2124
+ }), /*#__PURE__*/jsxs(Box, {
2125
+ children: [/*#__PURE__*/jsx(Text, {
2126
+ fw: 600,
2127
+ size: "md",
2128
+ children: sectionTitle
2129
+ }), description && /*#__PURE__*/jsx(Text, {
2130
+ size: "xs",
2131
+ c: "dimmed",
2132
+ children: description
2133
+ })]
2134
+ })]
2135
+ });
2136
+
2137
+ // Reusable Row component
2138
+ const SettingRow = ({
2139
+ label,
2140
+ children,
2141
+ action,
2142
+ actionLabel,
2143
+ onClick,
2144
+ expanded
2145
+ }) => /*#__PURE__*/jsx(Card, {
2146
+ p: "xs",
2147
+ children: /*#__PURE__*/jsxs(Group, {
2148
+ justify: "space-between",
2149
+ wrap: "nowrap",
2150
+ children: [/*#__PURE__*/jsxs(Group, {
2151
+ gap: "xl",
2152
+ wrap: "nowrap",
2153
+ flex: 1,
2154
+ children: [/*#__PURE__*/jsx(Text, {
2155
+ size: "sm",
2156
+ c: "dimmed",
2157
+ w: 100,
2158
+ style: {
2159
+ flexShrink: 0
2160
+ },
2161
+ children: label
2162
+ }), /*#__PURE__*/jsx(Box, {
2163
+ flex: 1,
2164
+ children: children
2165
+ })]
2166
+ }), action && /*#__PURE__*/jsx(Tooltip, {
2167
+ label: actionLabel || action,
2168
+ position: "left",
2169
+ children: /*#__PURE__*/jsx(Anchor, {
2170
+ size: "sm",
2171
+ fw: 500,
2172
+ onClick: onClick,
2173
+ c: expanded ? 'red' : 'blue',
2174
+ children: expanded ? labels.cancel || 'Cancel' : action
2175
+ })
2176
+ })]
2177
+ })
2178
+ });
2179
+ return /*#__PURE__*/jsxs(Modal, {
2180
+ opened: opened,
2181
+ onClose: onClose,
2182
+ size: 550,
2183
+ withCloseButton: true,
2184
+ radius: "lg",
2185
+ overlayProps: {
2186
+ backgroundOpacity: 0.55,
2187
+ blur: 3
2188
+ },
2189
+ title: /*#__PURE__*/jsxs(Group, {
2190
+ gap: "md",
2191
+ children: [/*#__PURE__*/jsx(ThemeIcon, {
2192
+ size: 44,
2193
+ variant: "light",
2194
+ children: /*#__PURE__*/jsx(IconUserCircle, {
2195
+ size: 24
2196
+ })
2197
+ }), /*#__PURE__*/jsxs(Box, {
2198
+ children: [/*#__PURE__*/jsx(Title, {
2199
+ order: 4,
2200
+ children: title
2201
+ }), /*#__PURE__*/jsx(Text, {
2202
+ size: "sm",
2203
+ c: "dimmed",
2204
+ children: subtitle
2205
+ })]
2206
+ })]
2207
+ }),
2208
+ ...modalProps,
2209
+ children: [/*#__PURE__*/jsx(Divider, {
2210
+ mb: "md"
2211
+ }), (showAvatar || showName || showEmail) && /*#__PURE__*/jsxs(Box, {
2212
+ mb: "xl",
2213
+ children: [/*#__PURE__*/jsx(SectionHeader, {
2214
+ icon: IconUser,
2215
+ sectionTitle: labels.profileSection || 'Profile',
2216
+ description: labels.profileDescription || 'Your personal information'
2217
+ }), /*#__PURE__*/jsxs(Stack, {
2218
+ gap: "sm",
2219
+ children: [showAvatar && /*#__PURE__*/jsxs(Fragment, {
2220
+ children: [/*#__PURE__*/jsx(SettingRow, {
2221
+ label: labels.avatar || 'Avatar',
2222
+ action: labels.update || 'Update',
2223
+ actionLabel: labels.updateAvatar || 'Update your profile picture',
2224
+ onClick: () => handleToggleSection('avatar'),
2225
+ expanded: editingSection === 'avatar',
2226
+ children: /*#__PURE__*/jsx(Group, {
2227
+ gap: "md",
2228
+ children: /*#__PURE__*/jsx(Avatar, {
2229
+ src: user?.image,
2230
+ name: user?.name || user?.email,
2231
+ size: 48,
2232
+ radius: "xl",
2233
+ color: "initials"
2234
+ })
2235
+ })
2236
+ }), /*#__PURE__*/jsx(Collapse, {
2237
+ in: editingSection === 'avatar',
2238
+ children: /*#__PURE__*/jsx(Card, {
2239
+ p: "md",
2240
+ withBorder: true,
2241
+ children: /*#__PURE__*/jsxs(Stack, {
2242
+ gap: "md",
2243
+ align: "center",
2244
+ children: [/*#__PURE__*/jsx("input", {
2245
+ type: "file",
2246
+ id: "avatar-upload",
2247
+ accept: "image/*",
2248
+ style: {
2249
+ display: 'none'
2250
+ },
2251
+ onChange: e => handleAvatarFileChange(e.target.files?.[0])
2252
+ }), /*#__PURE__*/jsx(Tooltip, {
2253
+ label: labels.clickToChange || 'Clique para alterar',
2254
+ position: "bottom",
2255
+ children: /*#__PURE__*/jsxs(Box, {
2256
+ onClick: () => document.getElementById('avatar-upload')?.click(),
2257
+ style: {
2258
+ position: 'relative',
2259
+ cursor: 'pointer',
2260
+ borderRadius: '50%'
2261
+ },
2262
+ children: [/*#__PURE__*/jsx(Avatar, {
2263
+ src: avatarPreview || user?.image,
2264
+ name: user?.name || user?.email,
2265
+ size: 100,
2266
+ radius: 100,
2267
+ color: "initials"
2268
+ }), /*#__PURE__*/jsx(ThemeIcon, {
2269
+ size: 32,
2270
+ radius: "xl",
2271
+ color: "blue",
2272
+ style: {
2273
+ position: 'absolute',
2274
+ bottom: 0,
2275
+ right: 0,
2276
+ border: '2px solid var(--mantine-color-body)'
2277
+ },
2278
+ children: /*#__PURE__*/jsx(IconPhoto, {
2279
+ size: 16
2280
+ })
2281
+ })]
2282
+ })
2283
+ }), /*#__PURE__*/jsx(Text, {
2284
+ size: "xs",
2285
+ c: "dimmed",
2286
+ ta: "center",
2287
+ children: labels.avatarHint || `Máximo ${Math.round(maxAvatarSize / 1024)}KB • JPG, PNG, GIF, WebP`
2288
+ }), /*#__PURE__*/jsxs(Group, {
2289
+ justify: "center",
2290
+ gap: "sm",
2291
+ children: [user?.image && /*#__PURE__*/jsx(Tooltip, {
2292
+ label: labels.removePhoto || 'Remover foto',
2293
+ children: /*#__PURE__*/jsx(Button, {
2294
+ variant: "light",
2295
+ color: "red",
2296
+ size: "xs",
2297
+ onClick: handleRemoveAvatar,
2298
+ loading: loadingUpdateProfile,
2299
+ leftSection: /*#__PURE__*/jsx(IconTrash, {
2300
+ size: 14
2301
+ }),
2302
+ children: labels.remove || 'Remover'
2303
+ })
2304
+ }), /*#__PURE__*/jsx(Button, {
2305
+ variant: "default",
2306
+ size: "xs",
2307
+ onClick: () => handleToggleSection('avatar'),
2308
+ children: labels.cancel || 'Cancelar'
2309
+ }), /*#__PURE__*/jsx(Button, {
2310
+ size: "xs",
2311
+ loading: loadingUpdateProfile,
2312
+ leftSection: /*#__PURE__*/jsx(IconCheck, {
2313
+ size: 14
2314
+ }),
2315
+ onClick: handleChangeAvatar,
2316
+ disabled: !avatarPreview || avatarPreview === user?.image,
2317
+ children: labels.save || 'Salvar'
2318
+ })]
2319
+ })]
2320
+ })
2321
+ })
2322
+ })]
2323
+ }), showName && /*#__PURE__*/jsxs(Fragment, {
2324
+ children: [/*#__PURE__*/jsx(SettingRow, {
2325
+ label: labels.name || 'Nome',
2326
+ action: labels.change || 'Change',
2327
+ actionLabel: labels.changeName || 'Change your display name',
2328
+ onClick: () => handleToggleSection('name'),
2329
+ expanded: editingSection === 'name',
2330
+ children: /*#__PURE__*/jsxs(Group, {
2331
+ gap: "xs",
2332
+ children: [/*#__PURE__*/jsx(IconPencil, {
2333
+ size: 16,
2334
+ color: "var(--mantine-color-dimmed)"
2335
+ }), /*#__PURE__*/jsx(Text, {
2336
+ size: "sm",
2337
+ children: user?.name || labels.notDefined || 'Não definido'
2338
+ })]
2339
+ })
2340
+ }), /*#__PURE__*/jsx(Collapse, {
2341
+ in: editingSection === 'name',
2342
+ children: /*#__PURE__*/jsx(Card, {
2343
+ p: "md",
2344
+ withBorder: true,
2345
+ children: /*#__PURE__*/jsx("form", {
2346
+ onSubmit: nameForm.onSubmit(handleChangeName),
2347
+ children: /*#__PURE__*/jsxs(Stack, {
2348
+ gap: "sm",
2349
+ children: [/*#__PURE__*/jsx(TextInput, {
2350
+ label: labels.name || 'Nome',
2351
+ placeholder: labels.namePlaceholder || 'Digite seu nome',
2352
+ leftSection: /*#__PURE__*/jsx(IconUser, {
2353
+ size: 16
2354
+ }),
2355
+ ...nameForm.getInputProps('name')
2356
+ }), /*#__PURE__*/jsxs(Group, {
2357
+ justify: "flex-end",
2358
+ gap: "sm",
2359
+ children: [/*#__PURE__*/jsx(Button, {
2360
+ variant: "default",
2361
+ size: "xs",
2362
+ onClick: () => handleToggleSection('name'),
2363
+ leftSection: /*#__PURE__*/jsx(IconX, {
2364
+ size: 14
2365
+ }),
2366
+ children: labels.cancel || 'Cancelar'
2367
+ }), /*#__PURE__*/jsx(Button, {
2368
+ type: "submit",
2369
+ size: "xs",
2370
+ loading: loadingUpdateProfile,
2371
+ leftSection: /*#__PURE__*/jsx(IconCheck, {
2372
+ size: 14
2373
+ }),
2374
+ children: labels.save || 'Salvar'
2375
+ })]
2376
+ })]
2377
+ })
2378
+ })
2379
+ })
2380
+ })]
2381
+ }), showEmail && /*#__PURE__*/jsxs(Fragment, {
2382
+ children: [/*#__PURE__*/jsx(SettingRow, {
2383
+ label: labels.email || 'Email',
2384
+ action: labels.change || 'Change',
2385
+ actionLabel: labels.changeEmail || 'Change your email',
2386
+ onClick: () => handleToggleSection('email'),
2387
+ expanded: editingSection === 'email',
2388
+ children: /*#__PURE__*/jsxs(Group, {
2389
+ gap: "xs",
2390
+ children: [/*#__PURE__*/jsx(IconMail, {
2391
+ size: 16,
2392
+ color: "var(--mantine-color-dimmed)"
2393
+ }), /*#__PURE__*/jsx(Text, {
2394
+ size: "sm",
2395
+ children: user?.email || 'email@exemplo.com'
2396
+ })]
2397
+ })
2398
+ }), /*#__PURE__*/jsx(Collapse, {
2399
+ in: editingSection === 'email',
2400
+ children: /*#__PURE__*/jsx(Card, {
2401
+ p: "md",
2402
+ withBorder: true,
2403
+ children: /*#__PURE__*/jsx("form", {
2404
+ onSubmit: emailForm.onSubmit(handleChangeEmail),
2405
+ children: /*#__PURE__*/jsxs(Stack, {
2406
+ gap: "sm",
2407
+ children: [/*#__PURE__*/jsx(TextInput, {
2408
+ label: labels.newEmail || 'Novo Email',
2409
+ placeholder: labels.newEmailPlaceholder || 'Digite o novo email',
2410
+ leftSection: /*#__PURE__*/jsx(IconMail, {
2411
+ size: 16
2412
+ }),
2413
+ ...emailForm.getInputProps('newEmail')
2414
+ }), /*#__PURE__*/jsxs(Group, {
2415
+ justify: "flex-end",
2416
+ gap: "sm",
2417
+ children: [/*#__PURE__*/jsx(Button, {
2418
+ variant: "default",
2419
+ size: "xs",
2420
+ onClick: () => handleToggleSection('email'),
2421
+ leftSection: /*#__PURE__*/jsx(IconX, {
2422
+ size: 14
2423
+ }),
2424
+ children: labels.cancel || 'Cancelar'
2425
+ }), /*#__PURE__*/jsx(Button, {
2426
+ type: "submit",
2427
+ size: "xs",
2428
+ loading: loadingChangeEmail,
2429
+ leftSection: /*#__PURE__*/jsx(IconCheck, {
2430
+ size: 14
2431
+ }),
2432
+ children: labels.save || 'Salvar'
2433
+ })]
2434
+ })]
2435
+ })
2436
+ })
2437
+ })
2438
+ })]
2439
+ })]
2440
+ })]
2441
+ }), showPassword && /*#__PURE__*/jsxs(Box, {
2442
+ mb: "md",
2443
+ children: [/*#__PURE__*/jsx(SectionHeader, {
2444
+ icon: IconShield,
2445
+ sectionTitle: labels.securitySection || 'Security',
2446
+ description: labels.securityDescription || 'Protect your account'
2447
+ }), /*#__PURE__*/jsxs(Stack, {
2448
+ gap: "sm",
2449
+ children: [/*#__PURE__*/jsx(SettingRow, {
2450
+ label: labels.password || 'Password',
2451
+ action: labels.change || 'Change',
2452
+ actionLabel: labels.changePassword || 'Change your password',
2453
+ onClick: () => handleToggleSection('password'),
2454
+ expanded: editingSection === 'password',
2455
+ children: /*#__PURE__*/jsxs(Group, {
2456
+ gap: "xs",
2457
+ children: [/*#__PURE__*/jsx(IconKey, {
2458
+ size: 16,
2459
+ color: "var(--mantine-color-dimmed)"
2460
+ }), /*#__PURE__*/jsx(Text, {
2461
+ size: "sm",
2462
+ c: "dimmed",
2463
+ children: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022"
2464
+ })]
2465
+ })
2466
+ }), /*#__PURE__*/jsx(Collapse, {
2467
+ in: editingSection === 'password',
2468
+ children: /*#__PURE__*/jsx(Card, {
2469
+ p: "md",
2470
+ withBorder: true,
2471
+ children: /*#__PURE__*/jsx("form", {
2472
+ onSubmit: passwordForm.onSubmit(handleChangePassword),
2473
+ children: /*#__PURE__*/jsxs(Stack, {
2474
+ gap: "sm",
2475
+ children: [/*#__PURE__*/jsx(PasswordInput, {
2476
+ label: labels.currentPassword || 'Senha Atual',
2477
+ placeholder: labels.currentPasswordPlaceholder || 'Digite sua senha atual',
2478
+ ...passwordForm.getInputProps('currentPassword')
2479
+ }), /*#__PURE__*/jsx(PasswordInput, {
2480
+ label: labels.newPassword || 'Nova Senha',
2481
+ placeholder: labels.newPasswordPlaceholder || 'Digite a nova senha',
2482
+ description: labels.passwordDescription || 'Mínimo 8 caracteres',
2483
+ ...passwordForm.getInputProps('newPassword')
2484
+ }), /*#__PURE__*/jsx(PasswordInput, {
2485
+ label: labels.confirmPassword || 'Confirmar Nova Senha',
2486
+ placeholder: labels.confirmPasswordPlaceholder || 'Confirme a nova senha',
2487
+ ...passwordForm.getInputProps('confirmPassword')
2488
+ }), /*#__PURE__*/jsxs(Group, {
2489
+ justify: "flex-end",
2490
+ gap: "xs",
2491
+ children: [/*#__PURE__*/jsx(Button, {
2492
+ variant: "default",
2493
+ size: "xs",
2494
+ onClick: () => handleToggleSection('password'),
2495
+ leftSection: /*#__PURE__*/jsx(IconX, {
2496
+ size: 14
2497
+ }),
2498
+ children: labels.cancel || 'Cancelar'
2499
+ }), /*#__PURE__*/jsx(Button, {
2500
+ type: "submit",
2501
+ size: "xs",
2502
+ loading: loadingChangePassword,
2503
+ leftSection: /*#__PURE__*/jsx(IconCheck, {
2504
+ size: 14
2505
+ }),
2506
+ children: labels.save || 'Salvar'
2507
+ })]
2508
+ })]
2509
+ })
2510
+ })
2511
+ })
2512
+ })]
2513
+ })]
2514
+ })]
2515
+ });
2516
+ }
2517
+
2518
+ export { AccountModal, AuthCard, AuthProvider, ForgotPasswordForm, MagicLinkForm, MagicLinkVerify, ProtectedRoute, ResetPasswordForm, SignInForm, SignUpForm, VerifyEmailCard, changeEmail, changePassword, configure, decodeJWT, forgotPassword, getApplicationInfo, getCurrentUser, getSession, isAuthenticated, refreshToken, resendVerification, resetPassword, sendMagicLink, signIn, signOut, signUp, socialRedirect, updateProfile, useAuth, useAuthLoading, useAuthStore, useCheckToken, useEmailVerification, useMagicLink, usePasswordReset, useProfile, useSession, useSignIn, useSignOut, useSignUp, verifyEmail, verifyMagicLink };
1732
2519
  //# sourceMappingURL=index.esm.js.map