@better-auth-ui/heroui 1.6.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/components/account/account.d.ts +18 -0
- package/dist/components/account/account.js +24 -0
- package/dist/components/account/settings/account-settings.d.ts +5 -0
- package/dist/components/account/settings/account-settings.js +6 -0
- package/dist/components/account/settings/settings.d.ts +5 -0
- package/dist/components/account/settings/settings.js +5 -0
- package/dist/components/account/settings/user-profile.d.ts +5 -0
- package/dist/components/account/settings/user-profile.js +20 -0
- package/dist/components/auth/auth-provider.d.ts +9 -0
- package/dist/components/auth/auth-provider.js +12 -0
- package/dist/components/auth/auth.d.ts +23 -0
- package/dist/components/auth/auth.js +42 -0
- package/dist/components/auth/field-separator.d.ts +4 -0
- package/dist/components/auth/field-separator.js +5 -0
- package/dist/components/auth/forgot-password.d.ts +15 -0
- package/dist/components/auth/forgot-password.js +28 -0
- package/dist/components/auth/magic-link-button.d.ts +13 -0
- package/dist/components/auth/magic-link-button.js +19 -0
- package/dist/components/auth/magic-link.d.ts +17 -0
- package/dist/components/auth/magic-link.js +43 -0
- package/dist/components/auth/provider-buttons.d.ts +19 -0
- package/dist/components/auth/provider-buttons.js +34 -0
- package/dist/components/auth/reset-password.d.ts +11 -0
- package/dist/components/auth/reset-password.js +58 -0
- package/dist/components/auth/sign-in.d.ts +14 -0
- package/dist/components/auth/sign-in.js +64 -0
- package/dist/components/auth/sign-out.d.ts +9 -0
- package/dist/components/auth/sign-out.js +33 -0
- package/dist/components/auth/sign-up.d.ts +19 -0
- package/dist/components/auth/sign-up.js +71 -0
- package/dist/components/email/email-changed-email.d.ts +3 -0
- package/dist/components/email/email-changed-email.js +23 -0
- package/dist/components/email/email-verification-email.d.ts +3 -0
- package/dist/components/email/email-verification-email.js +23 -0
- package/dist/components/email/magic-link-email.d.ts +3 -0
- package/dist/components/email/magic-link-email.js +23 -0
- package/dist/components/email/new-device-email.d.ts +3 -0
- package/dist/components/email/new-device-email.js +23 -0
- package/dist/components/email/otp-email.d.ts +3 -0
- package/dist/components/email/otp-email.js +22 -0
- package/dist/components/email/password-changed-email.d.ts +3 -0
- package/dist/components/email/password-changed-email.js +23 -0
- package/dist/components/email/reset-password-email.d.ts +3 -0
- package/dist/components/email/reset-password-email.js +23 -0
- package/dist/components/settings/account/account-settings.d.ts +16 -0
- package/dist/components/settings/account/account-settings.js +20 -0
- package/dist/components/settings/account/accounts.d.ts +14 -0
- package/dist/components/settings/account/accounts.js +26 -0
- package/dist/components/settings/account/appearance.d.ts +16 -0
- package/dist/components/settings/account/appearance.js +28 -0
- package/dist/components/settings/account/change-avatar.d.ts +4 -0
- package/dist/components/settings/account/change-avatar.js +56 -0
- package/dist/components/settings/account/change-email.d.ts +15 -0
- package/dist/components/settings/account/change-email.js +29 -0
- package/dist/components/settings/account/manage-account.d.ts +19 -0
- package/dist/components/settings/account/manage-account.js +32 -0
- package/dist/components/settings/account/manage-accounts.d.ts +14 -0
- package/dist/components/settings/account/manage-accounts.js +37 -0
- package/dist/components/settings/account/theme-selector.d.ts +16 -0
- package/dist/components/settings/account/theme-selector.js +33 -0
- package/dist/components/settings/account/theme-settings.d.ts +16 -0
- package/dist/components/settings/account/theme-settings.js +31 -0
- package/dist/components/settings/account/user-profile.d.ts +11 -0
- package/dist/components/settings/account/user-profile.js +23 -0
- package/dist/components/settings/account-settings.d.ts +5 -0
- package/dist/components/settings/account-settings.js +6 -0
- package/dist/components/settings/account.d.ts +18 -0
- package/dist/components/settings/account.js +24 -0
- package/dist/components/settings/security/active-session.d.ts +14 -0
- package/dist/components/settings/security/active-session.js +53 -0
- package/dist/components/settings/security/active-sessions.d.ts +14 -0
- package/dist/components/settings/security/active-sessions.js +28 -0
- package/dist/components/settings/security/change-password.d.ts +15 -0
- package/dist/components/settings/security/change-password.js +79 -0
- package/dist/components/settings/security/connected-account.d.ts +16 -0
- package/dist/components/settings/security/connected-account.js +46 -0
- package/dist/components/settings/security/connected-accounts.d.ts +15 -0
- package/dist/components/settings/security/connected-accounts.js +31 -0
- package/dist/components/settings/security/danger-zone.d.ts +11 -0
- package/dist/components/settings/security/danger-zone.js +12 -0
- package/dist/components/settings/security/delete-user.d.ts +9 -0
- package/dist/components/settings/security/delete-user.js +47 -0
- package/dist/components/settings/security/linked-account.d.ts +16 -0
- package/dist/components/settings/security/linked-account.js +48 -0
- package/dist/components/settings/security/linked-accounts.d.ts +15 -0
- package/dist/components/settings/security/linked-accounts.js +42 -0
- package/dist/components/settings/security/security-settings.d.ts +17 -0
- package/dist/components/settings/security/security-settings.js +21 -0
- package/dist/components/settings/security/sessions.d.ts +14 -0
- package/dist/components/settings/security/sessions.js +40 -0
- package/dist/components/settings/settings/account-settings.d.ts +5 -0
- package/dist/components/settings/settings/account-settings.js +6 -0
- package/dist/components/settings/settings/user-profile.d.ts +5 -0
- package/dist/components/settings/settings/user-profile.js +20 -0
- package/dist/components/settings/settings.d.ts +24 -0
- package/dist/components/settings/settings.js +28 -0
- package/dist/components/settings/user-profile.d.ts +5 -0
- package/dist/components/settings/user-profile.js +20 -0
- package/dist/components/user/switch-account-item.d.ts +16 -0
- package/dist/components/user/switch-account-item.js +16 -0
- package/dist/components/user/switch-account-menu.d.ts +10 -0
- package/dist/components/user/switch-account-menu.js +29 -0
- package/dist/components/user/switch-account-popover.d.ts +10 -0
- package/dist/components/user/switch-account-popover.js +25 -0
- package/dist/components/user/switch-account-submenu.d.ts +10 -0
- package/dist/components/user/switch-account-submenu.js +25 -0
- package/dist/components/user/user-avatar.d.ts +25 -0
- package/dist/components/user/user-avatar.js +31 -0
- package/dist/components/user/user-button.d.ts +25 -0
- package/dist/components/user/user-button.js +24 -0
- package/dist/components/user/user-view.d.ts +22 -0
- package/dist/components/user/user-view.js +24 -0
- package/dist/core.d.ts +1 -0
- package/dist/core.js +1 -0
- package/dist/hooks/use-auth.d.ts +2 -0
- package/dist/hooks/use-auth.js +8 -0
- package/dist/hooks/use-redirect-to.d.ts +8 -0
- package/dist/hooks/use-redirect-to.js +19 -0
- package/dist/hooks/use-sign-in.d.ts +8 -0
- package/dist/hooks/use-sign-in.js +53 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +34 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.js +5 -0
- package/dist/react-exports.d.ts +1 -0
- package/dist/react-exports.js +1 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.js +1 -0
- package/dist/src/components/auth/auth-provider.d.ts +8 -0
- package/dist/src/components/auth/auth-provider.js +13 -0
- package/dist/src/components/auth/auth.d.ts +22 -0
- package/dist/src/components/auth/auth.js +42 -0
- package/dist/src/components/auth/field-separator.d.ts +4 -0
- package/dist/src/components/auth/field-separator.js +5 -0
- package/dist/src/components/auth/forgot-password.d.ts +15 -0
- package/dist/src/components/auth/forgot-password.js +29 -0
- package/dist/src/components/auth/magic-link-button.d.ts +13 -0
- package/dist/src/components/auth/magic-link-button.js +20 -0
- package/dist/src/components/auth/magic-link.d.ts +17 -0
- package/dist/src/components/auth/magic-link.js +37 -0
- package/dist/src/components/auth/provider-buttons.d.ts +19 -0
- package/dist/src/components/auth/provider-buttons.js +35 -0
- package/dist/src/components/auth/reset-password.d.ts +11 -0
- package/dist/src/components/auth/reset-password.js +59 -0
- package/dist/src/components/auth/sign-in.d.ts +14 -0
- package/dist/src/components/auth/sign-in.js +58 -0
- package/dist/src/components/auth/sign-out.d.ts +11 -0
- package/dist/src/components/auth/sign-out.js +34 -0
- package/dist/src/components/auth/sign-up.d.ts +19 -0
- package/dist/src/components/auth/sign-up.js +65 -0
- package/dist/src/components/email/email-changed-email.d.ts +3 -0
- package/dist/src/components/email/email-changed-email.js +23 -0
- package/dist/src/components/email/email-verification-email.d.ts +3 -0
- package/dist/src/components/email/email-verification-email.js +23 -0
- package/dist/src/components/email/magic-link-email.d.ts +3 -0
- package/dist/src/components/email/magic-link-email.js +23 -0
- package/dist/src/components/email/new-device-email.d.ts +3 -0
- package/dist/src/components/email/new-device-email.js +23 -0
- package/dist/src/components/email/otp-email.d.ts +3 -0
- package/dist/src/components/email/otp-email.js +22 -0
- package/dist/src/components/email/password-changed-email.d.ts +3 -0
- package/dist/src/components/email/password-changed-email.js +23 -0
- package/dist/src/components/email/reset-password-email.d.ts +3 -0
- package/dist/src/components/email/reset-password-email.js +23 -0
- package/dist/src/components/settings/account/account-settings.d.ts +13 -0
- package/dist/src/components/settings/account/account-settings.js +19 -0
- package/dist/src/components/settings/account/appearance.d.ts +16 -0
- package/dist/src/components/settings/account/appearance.js +28 -0
- package/dist/src/components/settings/account/change-email.d.ts +15 -0
- package/dist/src/components/settings/account/change-email.js +35 -0
- package/dist/src/components/settings/account/manage-account.d.ts +19 -0
- package/dist/src/components/settings/account/manage-account.js +27 -0
- package/dist/src/components/settings/account/manage-accounts.d.ts +14 -0
- package/dist/src/components/settings/account/manage-accounts.js +27 -0
- package/dist/src/components/settings/account/user-profile.d.ts +13 -0
- package/dist/src/components/settings/account/user-profile.js +29 -0
- package/dist/src/components/settings/security/active-session.d.ts +14 -0
- package/dist/src/components/settings/security/active-session.js +35 -0
- package/dist/src/components/settings/security/active-sessions.d.ts +14 -0
- package/dist/src/components/settings/security/active-sessions.js +29 -0
- package/dist/src/components/settings/security/change-password.d.ts +15 -0
- package/dist/src/components/settings/security/change-password.js +57 -0
- package/dist/src/components/settings/security/linked-account.d.ts +16 -0
- package/dist/src/components/settings/security/linked-account.js +46 -0
- package/dist/src/components/settings/security/linked-accounts.d.ts +15 -0
- package/dist/src/components/settings/security/linked-accounts.js +31 -0
- package/dist/src/components/settings/security/security-settings.d.ts +15 -0
- package/dist/src/components/settings/security/security-settings.js +18 -0
- package/dist/src/components/settings/settings.d.ts +29 -0
- package/dist/src/components/settings/settings.js +39 -0
- package/dist/src/components/user/switch-account-item.d.ts +16 -0
- package/dist/src/components/user/switch-account-item.js +14 -0
- package/dist/src/components/user/switch-account-menu.d.ts +10 -0
- package/dist/src/components/user/switch-account-menu.js +23 -0
- package/dist/src/components/user/user-avatar.d.ts +24 -0
- package/dist/src/components/user/user-avatar.js +31 -0
- package/dist/src/components/user/user-button.d.ts +21 -0
- package/dist/src/components/user/user-button.js +24 -0
- package/dist/src/components/user/user-view.d.ts +21 -0
- package/dist/src/components/user/user-view.js +24 -0
- package/dist/src/core.d.ts +1 -0
- package/dist/src/core.js +1 -0
- package/dist/src/index.d.ts +31 -0
- package/dist/src/index.js +32 -0
- package/dist/src/lib/utils.d.ts +2 -0
- package/dist/src/lib/utils.js +5 -0
- package/dist/src/react-exports.d.ts +1 -0
- package/dist/src/react-exports.js +1 -0
- package/dist/styles.css +1 -0
- package/package.json +63 -0
- package/src/components/auth/auth-provider.tsx +27 -0
- package/src/components/auth/auth.tsx +87 -0
- package/src/components/auth/field-separator.tsx +14 -0
- package/src/components/auth/forgot-password.tsx +107 -0
- package/src/components/auth/magic-link-button.tsx +43 -0
- package/src/components/auth/magic-link.tsx +181 -0
- package/src/components/auth/provider-buttons.tsx +85 -0
- package/src/components/auth/reset-password.tsx +210 -0
- package/src/components/auth/sign-in.tsx +260 -0
- package/src/components/auth/sign-out.tsx +44 -0
- package/src/components/auth/sign-up.tsx +314 -0
- package/src/components/email/email-changed-email.tsx +38 -0
- package/src/components/email/email-verification-email.tsx +38 -0
- package/src/components/email/magic-link-email.tsx +38 -0
- package/src/components/email/new-device-email.tsx +38 -0
- package/src/components/email/otp-email.tsx +33 -0
- package/src/components/email/password-changed-email.tsx +38 -0
- package/src/components/email/reset-password-email.tsx +38 -0
- package/src/components/settings/account/account-settings.tsx +48 -0
- package/src/components/settings/account/appearance.tsx +157 -0
- package/src/components/settings/account/change-avatar.tsx +142 -0
- package/src/components/settings/account/change-email.tsx +111 -0
- package/src/components/settings/account/manage-account.tsx +123 -0
- package/src/components/settings/account/manage-accounts.tsx +78 -0
- package/src/components/settings/account/user-profile.tsx +103 -0
- package/src/components/settings/security/active-session.tsx +123 -0
- package/src/components/settings/security/active-sessions.tsx +77 -0
- package/src/components/settings/security/change-password.tsx +335 -0
- package/src/components/settings/security/danger-zone.tsx +32 -0
- package/src/components/settings/security/delete-user.tsx +187 -0
- package/src/components/settings/security/linked-account.tsx +136 -0
- package/src/components/settings/security/linked-accounts.tsx +98 -0
- package/src/components/settings/security/security-settings.tsx +43 -0
- package/src/components/settings/settings.tsx +96 -0
- package/src/components/user/switch-account-item.tsx +39 -0
- package/src/components/user/switch-account-menu.tsx +64 -0
- package/src/components/user/user-avatar.tsx +88 -0
- package/src/components/user/user-button.tsx +221 -0
- package/src/components/user/user-view.tsx +74 -0
- package/src/core.ts +1 -0
- package/src/index.tsx +35 -0
- package/src/react-exports.ts +1 -0
- package/src/styles.css +1 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type CardProps } from "@heroui/react";
|
|
2
|
+
import { type SocialLayout } from "./provider-buttons";
|
|
3
|
+
export type SignUpProps = {
|
|
4
|
+
className?: string;
|
|
5
|
+
socialLayout?: SocialLayout;
|
|
6
|
+
socialPosition?: "top" | "bottom";
|
|
7
|
+
variant?: CardProps["variant"];
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Render a sign-up form with name, email, password (and optional confirm password) fields, optional social provider buttons, and password visibility controls.
|
|
11
|
+
*
|
|
12
|
+
* The component reflects request state by disabling inputs and showing a pending indicator during sign-up or social sign-in.
|
|
13
|
+
*
|
|
14
|
+
* @param className - Additional CSS classes applied to the outer card container
|
|
15
|
+
* @param socialLayout - Social layout to apply to the provider buttons component
|
|
16
|
+
* @param socialPosition - Position of social provider buttons relative to the form; `"top"` or `"bottom"` (default `"bottom"`)
|
|
17
|
+
* @returns The sign-up form React element
|
|
18
|
+
*/
|
|
19
|
+
export declare function SignUp({ className, socialLayout, socialPosition, variant, ...props }: SignUpProps & CardProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useAuth, useSignInSocial, useSignUpEmail } from "@better-auth-ui/react";
|
|
3
|
+
import { Eye, EyeSlash } from "@gravity-ui/icons";
|
|
4
|
+
import { Button, Card, cn, Description, FieldError, Form, Input, InputGroup, Label, Link, Spinner, TextField, toast } from "@heroui/react";
|
|
5
|
+
import { useState } from "react";
|
|
6
|
+
import { FieldSeparator } from "./field-separator";
|
|
7
|
+
import { MagicLinkButton } from "./magic-link-button";
|
|
8
|
+
import { ProviderButtons } from "./provider-buttons";
|
|
9
|
+
/**
|
|
10
|
+
* Render a sign-up form with name, email, password (and optional confirm password) fields, optional social provider buttons, and password visibility controls.
|
|
11
|
+
*
|
|
12
|
+
* The component reflects request state by disabling inputs and showing a pending indicator during sign-up or social sign-in.
|
|
13
|
+
*
|
|
14
|
+
* @param className - Additional CSS classes applied to the outer card container
|
|
15
|
+
* @param socialLayout - Social layout to apply to the provider buttons component
|
|
16
|
+
* @param socialPosition - Position of social provider buttons relative to the form; `"top"` or `"bottom"` (default `"bottom"`)
|
|
17
|
+
* @returns The sign-up form React element
|
|
18
|
+
*/
|
|
19
|
+
export function SignUp({ className, socialLayout, socialPosition = "bottom", variant, ...props }) {
|
|
20
|
+
const { basePaths, emailAndPassword, localization, magicLink, redirectTo, socialProviders, viewPaths, navigate } = useAuth();
|
|
21
|
+
const [password, setPassword] = useState("");
|
|
22
|
+
const [confirmPassword, setConfirmPassword] = useState("");
|
|
23
|
+
const { mutate: signUpEmail, isPending: signUpPending } = useSignUpEmail({
|
|
24
|
+
onError: (error) => {
|
|
25
|
+
setPassword("");
|
|
26
|
+
setConfirmPassword("");
|
|
27
|
+
toast.danger(error.error?.message || error.message);
|
|
28
|
+
},
|
|
29
|
+
onSuccess: () => {
|
|
30
|
+
if (emailAndPassword?.requireEmailVerification) {
|
|
31
|
+
toast.success(localization.auth.verifyYourEmail);
|
|
32
|
+
navigate({ to: `${basePaths.auth}/${viewPaths.auth.signIn}` });
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
navigate({ to: redirectTo });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
const [socialRedirecting, setSocialRedirecting] = useState(false);
|
|
40
|
+
const { mutate: signInSocial, isPending: socialPending } = useSignInSocial({
|
|
41
|
+
onError: (error) => toast.danger(error.error?.message || error.message),
|
|
42
|
+
onSuccess: () => {
|
|
43
|
+
setSocialRedirecting(true);
|
|
44
|
+
setTimeout(() => {
|
|
45
|
+
setSocialRedirecting(false);
|
|
46
|
+
}, 5000);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
const [isPasswordVisible, setIsPasswordVisible] = useState(false);
|
|
50
|
+
const [isConfirmPasswordVisible, setIsConfirmPasswordVisible] = useState(false);
|
|
51
|
+
const isPending = signUpPending || socialPending || socialRedirecting;
|
|
52
|
+
const handleSubmit = (e) => {
|
|
53
|
+
e.preventDefault();
|
|
54
|
+
const formData = new FormData(e.currentTarget);
|
|
55
|
+
const name = formData.get("name");
|
|
56
|
+
const email = formData.get("email");
|
|
57
|
+
if (emailAndPassword?.confirmPassword && password !== confirmPassword) {
|
|
58
|
+
toast.danger(localization.auth.passwordsDoNotMatch);
|
|
59
|
+
setPassword("");
|
|
60
|
+
setConfirmPassword("");
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
signUpEmail({ name, email, password });
|
|
64
|
+
};
|
|
65
|
+
const showSeparator = emailAndPassword?.enabled && !!socialProviders?.length;
|
|
66
|
+
return (_jsxs(Card, { className: cn("w-full max-w-sm p-4 md:p-6", className), variant: variant, ...props, children: [_jsx(Card.Header, { children: _jsx(Card.Title, { className: "text-xl font-semibold mb-1", children: localization.auth.signUp }) }), _jsxs(Card.Content, { className: "gap-4", children: [socialPosition === "top" && (_jsxs(_Fragment, { children: [!!socialProviders?.length && (_jsx(ProviderButtons, { isPending: isPending, socialLayout: socialLayout, signInSocial: signInSocial })), showSeparator && (_jsx(FieldSeparator, { children: localization.auth.or }))] })), emailAndPassword?.enabled && (_jsxs(Form, { onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [_jsxs(TextField, { name: "name", type: "text", autoComplete: "name", isDisabled: isPending, children: [_jsx(Label, { children: localization.auth.name }), _jsx(Input, { placeholder: localization.auth.namePlaceholder, required: true, variant: variant === "transparent" ? "primary" : "secondary" }), _jsx(FieldError, {})] }), _jsxs(TextField, { name: "email", type: "email", autoComplete: "email", isDisabled: isPending, children: [_jsx(Label, { children: localization.auth.email }), _jsx(Input, { placeholder: localization.auth.emailPlaceholder, required: true, variant: variant === "transparent" ? "primary" : "secondary" }), _jsx(FieldError, {})] }), _jsxs(TextField, { minLength: emailAndPassword?.minPasswordLength, maxLength: emailAndPassword?.maxPasswordLength, name: "password", autoComplete: "new-password", isDisabled: isPending, value: password, onChange: setPassword, children: [_jsx(Label, { children: localization.auth.password }), _jsxs(InputGroup, { variant: variant === "transparent" ? "primary" : "secondary", children: [_jsx(InputGroup.Input, { placeholder: localization.auth.passwordPlaceholder, type: isPasswordVisible ? "text" : "password", name: "password", required: true }), _jsx(InputGroup.Suffix, { className: "px-0", children: _jsx(Button, { isIconOnly: true, "aria-label": isPasswordVisible
|
|
67
|
+
? localization.auth.hidePassword
|
|
68
|
+
: localization.auth.showPassword, size: "sm", variant: "ghost", onPress: () => setIsPasswordVisible(!isPasswordVisible), isDisabled: isPending, children: isPasswordVisible ? _jsx(EyeSlash, {}) : _jsx(Eye, {}) }) })] }), _jsx(FieldError, {})] }), emailAndPassword?.confirmPassword && (_jsxs(TextField, { minLength: emailAndPassword?.minPasswordLength, maxLength: emailAndPassword?.maxPasswordLength, name: "confirmPassword", autoComplete: "new-password", isDisabled: isPending, value: confirmPassword, onChange: setConfirmPassword, children: [_jsx(Label, { children: localization.auth.confirmPassword }), _jsxs(InputGroup, { variant: variant === "transparent" ? "primary" : "secondary", children: [_jsx(InputGroup.Input, { name: "confirmPassword", placeholder: localization.auth.confirmPasswordPlaceholder, type: isConfirmPasswordVisible ? "text" : "password", required: true }), _jsx(InputGroup.Suffix, { className: "px-0", children: _jsx(Button, { isIconOnly: true, "aria-label": isConfirmPasswordVisible
|
|
69
|
+
? localization.auth.hidePassword
|
|
70
|
+
: localization.auth.showPassword, size: "sm", variant: "ghost", onPress: () => setIsConfirmPasswordVisible(!isConfirmPasswordVisible), isDisabled: isPending, children: isConfirmPasswordVisible ? _jsx(EyeSlash, {}) : _jsx(Eye, {}) }) })] }), _jsx(FieldError, {})] })), _jsxs("div", { className: "flex flex-col gap-3", children: [_jsxs(Button, { type: "submit", className: "w-full", isPending: isPending, children: [isPending && _jsx(Spinner, { color: "current", size: "sm" }), localization.auth.signUp] }), magicLink && (_jsx(MagicLinkButton, { view: "signUp", isPending: isPending }))] })] })), socialPosition === "bottom" && (_jsxs(_Fragment, { children: [showSeparator && (_jsx(FieldSeparator, { children: localization.auth.or })), !!socialProviders?.length && (_jsx(ProviderButtons, { socialLayout: socialLayout, signInSocial: signInSocial, isPending: isPending }))] }))] }), _jsx(Card.Footer, { className: "flex-col", children: _jsxs(Description, { className: "text-sm", children: [localization.auth.alreadyHaveAnAccount, " ", _jsx(Link, { href: `${basePaths.auth}/${viewPaths.auth.signIn}`, className: "text-accent decoration-accent no-underline hover:underline", children: localization.auth.signIn })] }) })] }));
|
|
71
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type EmailChangedEmailProps } from "@better-auth-ui/react";
|
|
2
|
+
export type { EmailChangedEmailProps } from "@better-auth-ui/react";
|
|
3
|
+
export declare function EmailChangedEmail({ colors, classNames, ...props }: EmailChangedEmailProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { EmailChangedEmail as EmailChangedEmailPrimitive } from "@better-auth-ui/react";
|
|
3
|
+
import { cn } from "@heroui/react";
|
|
4
|
+
export function EmailChangedEmail({ colors, classNames, ...props }) {
|
|
5
|
+
return (_jsx(EmailChangedEmailPrimitive, { colors: {
|
|
6
|
+
light: {
|
|
7
|
+
background: "#F5F5F5",
|
|
8
|
+
primary: "#0285F7",
|
|
9
|
+
primaryForeground: "#FCFCFC",
|
|
10
|
+
...colors?.light
|
|
11
|
+
},
|
|
12
|
+
dark: {
|
|
13
|
+
background: "#060607",
|
|
14
|
+
primary: "#0584F6",
|
|
15
|
+
primaryForeground: "#FCFCFC",
|
|
16
|
+
...colors?.dark
|
|
17
|
+
}
|
|
18
|
+
}, classNames: {
|
|
19
|
+
...classNames,
|
|
20
|
+
card: cn("border-none rounded-3xl", classNames?.card),
|
|
21
|
+
button: cn("rounded-full", classNames?.button)
|
|
22
|
+
}, ...props }));
|
|
23
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type EmailVerificationEmailProps } from "@better-auth-ui/react";
|
|
2
|
+
export type { EmailVerificationEmailProps } from "@better-auth-ui/react";
|
|
3
|
+
export declare function EmailVerificationEmail({ colors, classNames, ...props }: EmailVerificationEmailProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { EmailVerificationEmail as EmailVerificationEmailPrimitive } from "@better-auth-ui/react";
|
|
3
|
+
import { cn } from "@heroui/react";
|
|
4
|
+
export function EmailVerificationEmail({ colors, classNames, ...props }) {
|
|
5
|
+
return (_jsx(EmailVerificationEmailPrimitive, { colors: {
|
|
6
|
+
light: {
|
|
7
|
+
background: "#F5F5F5",
|
|
8
|
+
primary: "#0285F7",
|
|
9
|
+
primaryForeground: "#FCFCFC",
|
|
10
|
+
...colors?.light
|
|
11
|
+
},
|
|
12
|
+
dark: {
|
|
13
|
+
background: "#060607",
|
|
14
|
+
primary: "#0584F6",
|
|
15
|
+
primaryForeground: "#FCFCFC",
|
|
16
|
+
...colors?.dark
|
|
17
|
+
}
|
|
18
|
+
}, classNames: {
|
|
19
|
+
...classNames,
|
|
20
|
+
card: cn("border-none rounded-3xl", classNames?.card),
|
|
21
|
+
button: cn("rounded-full", classNames?.button)
|
|
22
|
+
}, ...props }));
|
|
23
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { MagicLinkEmail as MagicLinkEmailPrimitive } from "@better-auth-ui/react";
|
|
3
|
+
import { cn } from "@heroui/react";
|
|
4
|
+
export function MagicLinkEmail({ colors, classNames, ...props }) {
|
|
5
|
+
return (_jsx(MagicLinkEmailPrimitive, { colors: {
|
|
6
|
+
light: {
|
|
7
|
+
background: "#F5F5F5",
|
|
8
|
+
primary: "#0285F7",
|
|
9
|
+
primaryForeground: "#FCFCFC",
|
|
10
|
+
...colors?.light
|
|
11
|
+
},
|
|
12
|
+
dark: {
|
|
13
|
+
background: "#060607",
|
|
14
|
+
primary: "#0584F6",
|
|
15
|
+
primaryForeground: "#FCFCFC",
|
|
16
|
+
...colors?.dark
|
|
17
|
+
}
|
|
18
|
+
}, classNames: {
|
|
19
|
+
...classNames,
|
|
20
|
+
card: cn("border-none rounded-3xl", classNames?.card),
|
|
21
|
+
button: cn("rounded-full", classNames?.button)
|
|
22
|
+
}, ...props }));
|
|
23
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { NewDeviceEmail as NewDeviceEmailPrimitive } from "@better-auth-ui/react";
|
|
3
|
+
import { cn } from "@heroui/react";
|
|
4
|
+
export function NewDeviceEmail({ colors, classNames, ...props }) {
|
|
5
|
+
return (_jsx(NewDeviceEmailPrimitive, { colors: {
|
|
6
|
+
light: {
|
|
7
|
+
background: "#F5F5F5",
|
|
8
|
+
primary: "#0285F7",
|
|
9
|
+
primaryForeground: "#FCFCFC",
|
|
10
|
+
...colors?.light
|
|
11
|
+
},
|
|
12
|
+
dark: {
|
|
13
|
+
background: "#060607",
|
|
14
|
+
primary: "#0584F6",
|
|
15
|
+
primaryForeground: "#FCFCFC",
|
|
16
|
+
...colors?.dark
|
|
17
|
+
}
|
|
18
|
+
}, classNames: {
|
|
19
|
+
...classNames,
|
|
20
|
+
card: cn("border-none rounded-3xl", classNames?.card),
|
|
21
|
+
button: cn("rounded-full", classNames?.button)
|
|
22
|
+
}, ...props }));
|
|
23
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { OtpEmail as OtpEmailPrimitive } from "@better-auth-ui/react";
|
|
3
|
+
import { cn } from "@heroui/react";
|
|
4
|
+
export function OtpEmail({ colors, classNames, ...props }) {
|
|
5
|
+
return (_jsx(OtpEmailPrimitive, { colors: {
|
|
6
|
+
light: {
|
|
7
|
+
background: "#F5F5F5",
|
|
8
|
+
primary: "#0285F7",
|
|
9
|
+
primaryForeground: "#FCFCFC",
|
|
10
|
+
...colors?.light
|
|
11
|
+
},
|
|
12
|
+
dark: {
|
|
13
|
+
background: "#060607",
|
|
14
|
+
primary: "#0584F6",
|
|
15
|
+
primaryForeground: "#FCFCFC",
|
|
16
|
+
...colors?.dark
|
|
17
|
+
}
|
|
18
|
+
}, classNames: {
|
|
19
|
+
...classNames,
|
|
20
|
+
card: cn("border-none rounded-3xl", classNames?.card)
|
|
21
|
+
}, ...props }));
|
|
22
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type PasswordChangedEmailProps } from "@better-auth-ui/react";
|
|
2
|
+
export type { PasswordChangedEmailProps } from "@better-auth-ui/react";
|
|
3
|
+
export declare function PasswordChangedEmail({ colors, classNames, ...props }: PasswordChangedEmailProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { PasswordChangedEmail as PasswordChangedEmailPrimitive } from "@better-auth-ui/react";
|
|
3
|
+
import { cn } from "@heroui/react";
|
|
4
|
+
export function PasswordChangedEmail({ colors, classNames, ...props }) {
|
|
5
|
+
return (_jsx(PasswordChangedEmailPrimitive, { colors: {
|
|
6
|
+
light: {
|
|
7
|
+
background: "#F5F5F5",
|
|
8
|
+
primary: "#0285F7",
|
|
9
|
+
primaryForeground: "#FCFCFC",
|
|
10
|
+
...colors?.light
|
|
11
|
+
},
|
|
12
|
+
dark: {
|
|
13
|
+
background: "#060607",
|
|
14
|
+
primary: "#0584F6",
|
|
15
|
+
primaryForeground: "#FCFCFC",
|
|
16
|
+
...colors?.dark
|
|
17
|
+
}
|
|
18
|
+
}, classNames: {
|
|
19
|
+
...classNames,
|
|
20
|
+
card: cn("border-none rounded-3xl", classNames?.card),
|
|
21
|
+
button: cn("rounded-full", classNames?.button)
|
|
22
|
+
}, ...props }));
|
|
23
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type ResetPasswordEmailProps } from "@better-auth-ui/react";
|
|
2
|
+
export type { ResetPasswordEmailProps } from "@better-auth-ui/react";
|
|
3
|
+
export declare function ResetPasswordEmail({ colors, classNames, ...props }: ResetPasswordEmailProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { ResetPasswordEmail as ResetPasswordEmailPrimitive } from "@better-auth-ui/react";
|
|
3
|
+
import { cn } from "@heroui/react";
|
|
4
|
+
export function ResetPasswordEmail({ colors, classNames, ...props }) {
|
|
5
|
+
return (_jsx(ResetPasswordEmailPrimitive, { colors: {
|
|
6
|
+
light: {
|
|
7
|
+
background: "#F5F5F5",
|
|
8
|
+
primary: "#0285F7",
|
|
9
|
+
primaryForeground: "#FCFCFC",
|
|
10
|
+
...colors?.light
|
|
11
|
+
},
|
|
12
|
+
dark: {
|
|
13
|
+
background: "#060607",
|
|
14
|
+
primary: "#0584F6",
|
|
15
|
+
primaryForeground: "#FCFCFC",
|
|
16
|
+
...colors?.dark
|
|
17
|
+
}
|
|
18
|
+
}, classNames: {
|
|
19
|
+
...classNames,
|
|
20
|
+
card: cn("border-none rounded-3xl", classNames?.card),
|
|
21
|
+
button: cn("rounded-full", classNames?.button)
|
|
22
|
+
}, ...props }));
|
|
23
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type CardProps } from "@heroui/react";
|
|
2
|
+
import type { ComponentProps } from "react";
|
|
3
|
+
export type AccountSettingsProps = {
|
|
4
|
+
className?: string;
|
|
5
|
+
variant?: CardProps["variant"];
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Renders the account settings layout including user profile, change email, appearance, and accounts management.
|
|
9
|
+
*
|
|
10
|
+
* UserProfile, ChangeEmail, and Appearance are always rendered; Accounts is rendered when `multiSession` is enabled.
|
|
11
|
+
*
|
|
12
|
+
* @param className - Optional additional CSS class names for the outer container.
|
|
13
|
+
* @param variant - Card variant forwarded to each account settings card.
|
|
14
|
+
* @returns The account settings container as a JSX element.
|
|
15
|
+
*/
|
|
16
|
+
export declare function AccountSettings({ className, variant, ...props }: AccountSettingsProps & ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useAuth } from "@better-auth-ui/react";
|
|
3
|
+
import { cn } from "@heroui/react";
|
|
4
|
+
import { Appearance } from "./appearance";
|
|
5
|
+
import { ChangeEmail } from "./change-email";
|
|
6
|
+
import { ManageAccounts } from "./manage-accounts";
|
|
7
|
+
import { UserProfile } from "./user-profile";
|
|
8
|
+
/**
|
|
9
|
+
* Renders the account settings layout including user profile, change email, appearance, and accounts management.
|
|
10
|
+
*
|
|
11
|
+
* UserProfile, ChangeEmail, and Appearance are always rendered; Accounts is rendered when `multiSession` is enabled.
|
|
12
|
+
*
|
|
13
|
+
* @param className - Optional additional CSS class names for the outer container.
|
|
14
|
+
* @param variant - Card variant forwarded to each account settings card.
|
|
15
|
+
* @returns The account settings container as a JSX element.
|
|
16
|
+
*/
|
|
17
|
+
export function AccountSettings({ className, variant, ...props }) {
|
|
18
|
+
const { multiSession, emailAndPassword, magicLink, appearance: { setTheme } } = useAuth();
|
|
19
|
+
return (_jsxs("div", { className: cn("flex w-full flex-col gap-4 md:gap-6", className), ...props, children: [_jsx(UserProfile, { variant: variant }), (emailAndPassword?.enabled || magicLink) && (_jsx(ChangeEmail, { variant: variant })), setTheme && _jsx(Appearance, { variant: variant }), multiSession && _jsx(ManageAccounts, { variant: variant })] }));
|
|
20
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type CardProps } from "@heroui/react";
|
|
2
|
+
export type AccountsProps = {
|
|
3
|
+
className?: string;
|
|
4
|
+
variant?: CardProps["variant"];
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Render a card that lists and manages all device sessions for the current user.
|
|
8
|
+
*
|
|
9
|
+
* Shows each session with user information and actions to switch to or revoke a session.
|
|
10
|
+
* When device session data is loading, a pending placeholder row is displayed.
|
|
11
|
+
*
|
|
12
|
+
* @returns A JSX element containing the accounts management card
|
|
13
|
+
*/
|
|
14
|
+
export declare function Accounts({ className, ...props }: AccountsProps & CardProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useAuth, useListDeviceSessions, useRevokeMultiSession, useSession, useSetActiveSession } from "@better-auth-ui/react";
|
|
3
|
+
import { ArrowRightArrowLeft, ArrowRightFromSquare, CirclePlus } from "@gravity-ui/icons";
|
|
4
|
+
import { Button, buttonVariants, Card, cn, Spinner } from "@heroui/react";
|
|
5
|
+
import { UserView } from "../../user/user-view";
|
|
6
|
+
/**
|
|
7
|
+
* Render a card that lists and manages all device sessions for the current user.
|
|
8
|
+
*
|
|
9
|
+
* Shows each session with user information and actions to switch to or revoke a session.
|
|
10
|
+
* When device session data is loading, a pending placeholder row is displayed.
|
|
11
|
+
*
|
|
12
|
+
* @returns A JSX element containing the accounts management card
|
|
13
|
+
*/
|
|
14
|
+
export function Accounts({ className, ...props }) {
|
|
15
|
+
const { basePaths, localization, viewPaths, Link } = useAuth();
|
|
16
|
+
const { data: sessionData } = useSession();
|
|
17
|
+
const { data: deviceSessions, isPending } = useListDeviceSessions();
|
|
18
|
+
const { settingActiveSession, setActiveSession } = useSetActiveSession();
|
|
19
|
+
const { revokingSession, revokeSession } = useRevokeMultiSession();
|
|
20
|
+
return (_jsxs(Card, { className: cn("p-4 md:p-6 gap-4", className), ...props, children: [_jsx(Card.Header, { children: _jsx(Card.Title, { className: "text-xl", children: localization.settings.accounts }) }), _jsx(Card.Content, { className: "gap-3", children: !isPending ? (deviceSessions?.map((deviceSession) => {
|
|
21
|
+
const isActive = deviceSession.session.userId === sessionData?.session.userId;
|
|
22
|
+
const isSwitching = settingActiveSession === deviceSession.session.token;
|
|
23
|
+
const isRevoking = revokingSession === deviceSession.session.token;
|
|
24
|
+
return (_jsxs(Card, { className: "flex-row items-center border p-3 shadow-none", children: [_jsx(UserView, { user: deviceSession.user, size: "md" }), _jsxs("div", { className: "flex items-center gap-1 shrink-0 ml-auto", children: [!isActive && (_jsx(Button, { isIconOnly: true, variant: "ghost", size: "sm", onPress: () => setActiveSession(deviceSession.session.token), isPending: isSwitching || isRevoking, "aria-label": localization.auth.switchAccount, children: isSwitching ? (_jsx(Spinner, { color: "current", size: "sm" })) : (_jsx(ArrowRightArrowLeft, {})) })), _jsx(Button, { isIconOnly: true, variant: "ghost", size: "sm", onPress: () => revokeSession(deviceSession.session.token), isPending: isSwitching || isRevoking, "aria-label": localization.auth.signOut, children: isRevoking ? (_jsx(Spinner, { color: "current", size: "sm" })) : (_jsx(ArrowRightFromSquare, {})) })] })] }, deviceSession.session.id));
|
|
25
|
+
})) : (_jsx("div", { className: "flex items-center rounded-3xl border p-3", children: _jsx(UserView, { isPending: true, size: "md" }) })) }), _jsx(Card.Footer, { children: _jsxs(Link, { href: `${basePaths.auth}/${viewPaths.auth.signIn}`, className: cn(buttonVariants({ variant: "secondary" })), children: [_jsx(CirclePlus, {}), localization.auth.addAccount] }) })] }));
|
|
26
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type CardProps } from "@heroui/react";
|
|
2
|
+
export type AppearanceProps = {
|
|
3
|
+
className?: string;
|
|
4
|
+
variant?: CardProps["variant"];
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Renders a theme selector card with visual theme previews.
|
|
8
|
+
*
|
|
9
|
+
* Displays a card containing radio buttons for selecting between system, light,
|
|
10
|
+
* and dark themes. Each option shows a visual preview of the theme. Only renders
|
|
11
|
+
* if theme settings are configured (theme, setTheme, and themes are provided).
|
|
12
|
+
*
|
|
13
|
+
* @param className - Optional additional CSS class names for the card container.
|
|
14
|
+
* @returns A JSX element containing the theme selector card, or null if theme settings are not configured.
|
|
15
|
+
*/
|
|
16
|
+
export declare function Appearance({ className, variant, ...props }: AppearanceProps & CardProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ThemePreviewDark, ThemePreviewLight, ThemePreviewSystem, useAuth, useSession } from "@better-auth-ui/react";
|
|
3
|
+
import { Display, Moon, Sun } from "@gravity-ui/icons";
|
|
4
|
+
import { Card, cn, Label, Radio, RadioGroup } from "@heroui/react";
|
|
5
|
+
/**
|
|
6
|
+
* Renders a theme selector card with visual theme previews.
|
|
7
|
+
*
|
|
8
|
+
* Displays a card containing radio buttons for selecting between system, light,
|
|
9
|
+
* and dark themes. Each option shows a visual preview of the theme. Only renders
|
|
10
|
+
* if theme settings are configured (theme, setTheme, and themes are provided).
|
|
11
|
+
*
|
|
12
|
+
* @param className - Optional additional CSS class names for the card container.
|
|
13
|
+
* @returns A JSX element containing the theme selector card, or null if theme settings are not configured.
|
|
14
|
+
*/
|
|
15
|
+
export function Appearance({ className, variant, ...props }) {
|
|
16
|
+
const { localization, appearance: { theme, setTheme, themes } } = useAuth();
|
|
17
|
+
const { data: session } = useSession();
|
|
18
|
+
if (!setTheme || !themes?.length) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return (_jsxs("div", { children: [_jsx("h2", { className: cn("text-sm font-semibold mb-3"), children: localization.settings.appearance }), _jsx(Card, { className: cn("p-4 gap-4", className), variant: variant, ...props, children: _jsxs(Card.Content, { children: [_jsx(Label, { children: localization.settings.theme }), _jsx(RadioGroup, { variant: variant === "transparent" ? "secondary" : "primary", value: session ? theme : "", onChange: setTheme, isDisabled: !session || !theme, children: _jsxs("div", { className: "grid gap-3 grid-cols-2 sm:grid-cols-3", children: [themes.includes("system") && (_jsx(Radio, { value: "system", className: cn("mt-0 px-4 pb-4 pt-3 rounded-xl", "border border-transparent data-[selected=true]:border-accent data-[selected=true]:bg-accent/10", "data-[focus-visible=true]:border-accent data-[focus-visible=true]:bg-accent/10", variant === "transparent"
|
|
22
|
+
? "bg-surface"
|
|
23
|
+
: "bg-surface-secondary"), children: _jsxs(Radio.Content, { className: "gap-2", children: [_jsxs("div", { className: "flex gap-2 justify-between", children: [_jsxs(Label, { className: "flex gap-2 items-center", children: [_jsx(Display, { className: "text-muted" }), localization.settings.system] }), _jsx(Radio.Control, { children: _jsx(Radio.Indicator, {}) })] }), _jsx(ThemePreviewSystem, { className: "w-full" })] }) })), themes.includes("light") && (_jsx(Radio, { value: "light", className: cn("mt-0 px-4 pb-4 pt-3 rounded-xl", "border border-transparent data-[selected=true]:border-accent data-[selected=true]:bg-accent/10", "data-[focus-visible=true]:border-accent data-[focus-visible=true]:bg-accent/10", variant === "transparent"
|
|
24
|
+
? "bg-surface"
|
|
25
|
+
: "bg-surface-secondary"), children: _jsxs(Radio.Content, { className: "gap-2", children: [_jsxs("div", { className: "flex gap-2 justify-between", children: [_jsxs(Label, { className: "flex gap-2 items-center", children: [_jsx(Sun, { className: "text-muted" }), localization.settings.light] }), _jsx(Radio.Control, { children: _jsx(Radio.Indicator, {}) })] }), _jsx(ThemePreviewLight, { className: "w-full" })] }) })), themes.includes("dark") && (_jsx(Radio, { value: "dark", className: cn("mt-0 px-4 pb-4 pt-3 rounded-xl", "border border-transparent data-[selected=true]:border-accent data-[selected=true]:bg-accent/10", "data-[focus-visible=true]:border-accent data-[focus-visible=true]:bg-accent/10", variant === "transparent"
|
|
26
|
+
? "bg-surface"
|
|
27
|
+
: "bg-surface-secondary"), children: _jsxs(Radio.Content, { className: "gap-2", children: [_jsxs("div", { className: "flex gap-2 justify-between", children: [_jsxs(Label, { className: "flex gap-2 items-center", children: [_jsx(Moon, { className: "text-muted" }), localization.settings.dark] }), _jsx(Radio.Control, { children: _jsx(Radio.Indicator, {}) })] }), _jsx(ThemePreviewDark, { className: "w-full" })] }) }))] }) })] }) })] }));
|
|
28
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { fileToBase64 } from "@better-auth-ui/core";
|
|
3
|
+
import { useAuth, useSession, useUpdateUser } from "@better-auth-ui/react";
|
|
4
|
+
import { CloudArrowUpIn, TrashBin } from "@gravity-ui/icons";
|
|
5
|
+
import { Button, cn, Dropdown, Label, Spinner, toast } from "@heroui/react";
|
|
6
|
+
import { useRef, useState } from "react";
|
|
7
|
+
import { UserAvatar } from "../../user/user-avatar";
|
|
8
|
+
export function ChangeAvatar({ className }) {
|
|
9
|
+
const { localization, avatar } = useAuth();
|
|
10
|
+
const { data: session } = useSession();
|
|
11
|
+
const { mutate: updateUser, isPending: updatePending } = useUpdateUser({
|
|
12
|
+
onError: (error) => toast.danger(error.error?.message || error.message)
|
|
13
|
+
});
|
|
14
|
+
const fileInputRef = useRef(null);
|
|
15
|
+
const [isUploading, setIsUploading] = useState(false);
|
|
16
|
+
const [isDeleting, setIsDeleting] = useState(false);
|
|
17
|
+
const isPending = updatePending || isUploading || isDeleting;
|
|
18
|
+
async function handleFileChange(e) {
|
|
19
|
+
const file = e.target.files?.[0];
|
|
20
|
+
if (!file)
|
|
21
|
+
return;
|
|
22
|
+
e.target.value = "";
|
|
23
|
+
setIsUploading(true);
|
|
24
|
+
try {
|
|
25
|
+
const resized = (await avatar.resize?.(file, avatar.size, avatar.extension)) || file;
|
|
26
|
+
const image = (await avatar.upload?.(resized)) || (await fileToBase64(resized));
|
|
27
|
+
updateUser({ image }, {
|
|
28
|
+
onSuccess: () => toast.success(localization.settings.avatarChangedSuccess)
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
if (error instanceof Error) {
|
|
33
|
+
toast.danger(error.message);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
setIsUploading(false);
|
|
37
|
+
}
|
|
38
|
+
async function handleDelete() {
|
|
39
|
+
const currentImage = session?.user.image;
|
|
40
|
+
updateUser({ image: null }, {
|
|
41
|
+
onSuccess: async () => {
|
|
42
|
+
if (currentImage) {
|
|
43
|
+
setIsDeleting(true);
|
|
44
|
+
try {
|
|
45
|
+
await avatar.delete?.(currentImage);
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
setIsDeleting(false);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
toast.success(localization.settings.avatarDeletedSuccess);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return (_jsxs("div", { className: cn("flex flex-col gap-1", className), children: [_jsx(Label, { isDisabled: !session, children: localization.settings.avatar }), _jsx("input", { ref: fileInputRef, type: "file", accept: "image/*", className: "hidden", onChange: handleFileChange }), _jsxs("div", { className: "flex items-center gap-4", children: [_jsx(Button, { type: "button", isIconOnly: true, variant: "ghost", className: "p-0 h-auto w-auto rounded-full", isDisabled: !session || isPending, onPress: () => fileInputRef.current?.click(), children: _jsx(UserAvatar, { size: "lg", isPending: isPending }) }), _jsxs(Dropdown, { children: [_jsxs(Button, { isDisabled: !session || isPending, size: "sm", variant: "secondary", children: [isPending && _jsx(Spinner, { size: "sm" }), localization.settings.changeAvatar] }), _jsx(Dropdown.Popover, { className: "min-w-fit", children: _jsxs(Dropdown.Menu, { children: [_jsxs(Dropdown.Item, { textValue: localization.settings.uploadAvatar, onAction: () => fileInputRef.current?.click(), children: [_jsx(CloudArrowUpIn, { className: "text-muted" }), _jsx(Label, { children: localization.settings.uploadAvatar })] }), _jsxs(Dropdown.Item, { textValue: localization.settings.deleteAvatar, isDisabled: !session?.user.image, onAction: handleDelete, variant: "danger", children: [_jsx(TrashBin, { className: "text-danger" }), _jsx(Label, { children: localization.settings.deleteAvatar })] })] }) })] })] })] }));
|
|
56
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type CardProps } from "@heroui/react";
|
|
2
|
+
export type ChangeEmailProps = {
|
|
3
|
+
className?: string;
|
|
4
|
+
variant?: CardProps["variant"];
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Render a card containing a form to view and update the authenticated user's email.
|
|
8
|
+
*
|
|
9
|
+
* Shows a loading skeleton until session data is available, displays the current
|
|
10
|
+
* email as the form's default value, and sends a verification email to the
|
|
11
|
+
* new address upon successful submission.
|
|
12
|
+
*
|
|
13
|
+
* @returns A JSX element rendering the change-email card and form
|
|
14
|
+
*/
|
|
15
|
+
export declare function ChangeEmail({ className, variant, ...props }: ChangeEmailProps & CardProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useAuth, useChangeEmail, useSession } from "@better-auth-ui/react";
|
|
3
|
+
import { Button, Card, cn, FieldError, Fieldset, Form, Input, Label, Skeleton, Spinner, TextField, toast } from "@heroui/react";
|
|
4
|
+
/**
|
|
5
|
+
* Render a card containing a form to view and update the authenticated user's email.
|
|
6
|
+
*
|
|
7
|
+
* Shows a loading skeleton until session data is available, displays the current
|
|
8
|
+
* email as the form's default value, and sends a verification email to the
|
|
9
|
+
* new address upon successful submission.
|
|
10
|
+
*
|
|
11
|
+
* @returns A JSX element rendering the change-email card and form
|
|
12
|
+
*/
|
|
13
|
+
export function ChangeEmail({ className, variant, ...props }) {
|
|
14
|
+
const { localization, baseURL, viewPaths } = useAuth();
|
|
15
|
+
const { data: session } = useSession();
|
|
16
|
+
const { mutate: changeEmail, isPending } = useChangeEmail({
|
|
17
|
+
onSuccess: () => toast.success(localization.settings.changeEmailSuccess),
|
|
18
|
+
onError: (error) => toast.danger(error.error?.message || error.message)
|
|
19
|
+
});
|
|
20
|
+
function handleSubmit(e) {
|
|
21
|
+
e.preventDefault();
|
|
22
|
+
const formData = new FormData(e.currentTarget);
|
|
23
|
+
changeEmail({
|
|
24
|
+
newEmail: formData.get("email"),
|
|
25
|
+
callbackURL: `${baseURL}/${viewPaths.settings.account}`
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return (_jsxs("div", { children: [_jsx("h2", { className: cn("text-sm font-semibold mb-3"), children: localization.settings.changeEmail }), _jsx(Card, { className: cn("p-4 gap-4", className), variant: variant, ...props, children: _jsx(Card.Content, { children: _jsx(Form, { onSubmit: handleSubmit, children: _jsxs(Fieldset, { className: "w-full gap-4", children: [_jsx(Fieldset.Group, { children: _jsxs(TextField, { name: "email", type: "email", defaultValue: session?.user.email, isDisabled: isPending || !session, children: [_jsx(Label, { children: localization.auth.email }), session ? (_jsx(Input, { required: true, variant: variant === "transparent" ? "primary" : "secondary", autoComplete: "email", placeholder: localization.auth.emailPlaceholder })) : (_jsx(Skeleton, { className: "h-10 md:h-9 w-full rounded-xl" })), _jsx(FieldError, {})] }, session?.user.email) }), _jsx(Fieldset.Actions, { children: _jsxs(Button, { type: "submit", isPending: isPending, isDisabled: !session, size: "sm", children: [isPending && _jsx(Spinner, { color: "current", size: "sm" }), localization.settings.updateEmail] }) })] }) }) }) })] }));
|
|
29
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Session, User } from "better-auth";
|
|
2
|
+
export type DeviceSession = {
|
|
3
|
+
session: Session;
|
|
4
|
+
user: User;
|
|
5
|
+
};
|
|
6
|
+
export type ManageAccountProps = {
|
|
7
|
+
deviceSession?: DeviceSession | null;
|
|
8
|
+
isPending?: boolean;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Render a single account row with user info and a dropdown for switch/sign-out actions.
|
|
12
|
+
*
|
|
13
|
+
* Shows the user's avatar and info. A three-dot menu provides options to
|
|
14
|
+
* switch account (for non-active sessions) and sign out.
|
|
15
|
+
*
|
|
16
|
+
* @param deviceSession - The device session object containing session and user data
|
|
17
|
+
* @returns A JSX element containing the account row
|
|
18
|
+
*/
|
|
19
|
+
export declare function ManageAccount({ deviceSession, isPending }: ManageAccountProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useAuth, useRevokeMultiSession, useSetActiveSession, useUser } from "@better-auth-ui/react";
|
|
3
|
+
import { ArrowRightArrowLeft, ArrowRightFromSquare, Ellipsis } from "@gravity-ui/icons";
|
|
4
|
+
import { Button, Dropdown, Spinner, toast } from "@heroui/react";
|
|
5
|
+
import { UserView } from "../../user/user-view";
|
|
6
|
+
/**
|
|
7
|
+
* Render a single account row with user info and a dropdown for switch/sign-out actions.
|
|
8
|
+
*
|
|
9
|
+
* Shows the user's avatar and info. A three-dot menu provides options to
|
|
10
|
+
* switch account (for non-active sessions) and sign out.
|
|
11
|
+
*
|
|
12
|
+
* @param deviceSession - The device session object containing session and user data
|
|
13
|
+
* @returns A JSX element containing the account row
|
|
14
|
+
*/
|
|
15
|
+
export function ManageAccount({ deviceSession, isPending }) {
|
|
16
|
+
const { localization } = useAuth();
|
|
17
|
+
const { data: user } = useUser();
|
|
18
|
+
const { mutate: setActiveSession, isPending: isSwitching } = useSetActiveSession({
|
|
19
|
+
onError: (error) => toast.danger(error.error?.message || error.message)
|
|
20
|
+
});
|
|
21
|
+
const { mutate: revokeSession, isPending: isRevoking } = useRevokeMultiSession({
|
|
22
|
+
onError: (error) => toast.danger(error.error?.message || error.message),
|
|
23
|
+
onSuccess: () => toast.success(localization.settings.revokeSessionSuccess)
|
|
24
|
+
});
|
|
25
|
+
const isActive = deviceSession?.session.userId === user?.id;
|
|
26
|
+
const isBusy = isSwitching || isRevoking;
|
|
27
|
+
return (_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx(UserView, { user: deviceSession?.user, isPending: isPending, size: "md" }), deviceSession && isActive && (_jsxs(Button, { className: "shrink-0", variant: "outline", size: "sm", onPress: () => revokeSession({ sessionToken: deviceSession.session.token }), isDisabled: isBusy, children: [isRevoking ? (_jsx(Spinner, { color: "current", size: "sm" })) : (_jsx(ArrowRightFromSquare, {})), localization.auth.signOut] })), deviceSession && !isActive && (_jsxs(Dropdown, { children: [_jsx(Button, { isIconOnly: true, variant: "ghost", className: "shrink-0", size: "sm", isDisabled: isBusy, children: _jsx(Ellipsis, {}) }), _jsx(Dropdown.Popover, { children: _jsxs(Dropdown.Menu, { children: [_jsxs(Dropdown.Item, { textValue: localization.auth.switchAccount, onAction: () => setActiveSession({
|
|
28
|
+
sessionToken: deviceSession.session.token
|
|
29
|
+
}), children: [_jsx(ArrowRightArrowLeft, { className: "text-muted" }), localization.auth.switchAccount] }), _jsxs(Dropdown.Item, { textValue: localization.auth.signOut, onAction: () => revokeSession({
|
|
30
|
+
sessionToken: deviceSession.session.token
|
|
31
|
+
}), children: [_jsx(ArrowRightFromSquare, { className: "text-muted" }), localization.auth.signOut] })] }) })] }))] }));
|
|
32
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type CardProps } from "@heroui/react";
|
|
2
|
+
export type ManageAccountsProps = {
|
|
3
|
+
className?: string;
|
|
4
|
+
variant?: CardProps["variant"];
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Render a card that lists and manages all device sessions for the current user.
|
|
8
|
+
*
|
|
9
|
+
* Shows each session with user information and actions to switch to or revoke a session.
|
|
10
|
+
* When device session data is loading, a pending placeholder row is displayed.
|
|
11
|
+
*
|
|
12
|
+
* @returns A JSX element containing the accounts management card
|
|
13
|
+
*/
|
|
14
|
+
export declare function ManageAccounts({ className, variant, ...props }: ManageAccountsProps & CardProps): import("react/jsx-runtime").JSX.Element;
|