@main12/auth-login 0.4.2 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -7
- package/dist/components/AuthCard.d.ts +41 -0
- package/dist/components/AuthCard.js +28 -0
- package/dist/components/AuthCardServer.d.ts +29 -0
- package/dist/components/AuthCardServer.js +57 -0
- package/dist/components/AuthLayout.d.ts +23 -13
- package/dist/components/AuthLayout.js +26 -87
- package/dist/components/AuthPages.d.ts +4 -29
- package/dist/components/AuthPages.js +23 -105
- package/dist/components/AuthPagesServer.d.ts +3 -4
- package/dist/components/AuthPagesServer.js +15 -8
- package/dist/components/auth-card/AuthCardShell.d.ts +21 -0
- package/dist/components/auth-card/AuthCardShell.js +104 -0
- package/dist/components/auth-card/FormRenderer.d.ts +32 -0
- package/dist/components/auth-card/FormRenderer.js +88 -0
- package/dist/components/auth-card/formConfigs.d.ts +25 -0
- package/dist/components/auth-card/formConfigs.js +56 -0
- package/dist/components/auth-card/index.d.ts +3 -0
- package/dist/components/auth-card/index.js +3 -0
- package/dist/components/forms/ForgotPasswordForm.d.ts +7 -0
- package/dist/components/forms/ForgotPasswordForm.js +56 -0
- package/dist/components/forms/LoginForm.d.ts +15 -0
- package/dist/components/forms/LoginForm.js +247 -0
- package/dist/components/forms/SetPasswordForm.d.ts +7 -0
- package/dist/components/forms/SetPasswordForm.js +75 -0
- package/dist/components/forms/SignupForm.d.ts +13 -0
- package/dist/components/forms/SignupForm.js +152 -0
- package/dist/components/forms/VerifyOtpForm.d.ts +9 -0
- package/dist/components/forms/VerifyOtpForm.js +107 -0
- package/dist/components/forms/index.d.ts +19 -0
- package/dist/components/forms/index.js +21 -0
- package/dist/components/pages/ForgotPasswordPage.d.ts +2 -1
- package/dist/components/pages/ForgotPasswordPageHero.d.ts +3 -2
- package/dist/components/pages/ForgotPasswordPageHero.js +70 -64
- package/dist/components/pages/ForgotPasswordPageTailwind.d.ts +3 -2
- package/dist/components/pages/ForgotPasswordPageTailwind.js +42 -36
- package/dist/components/pages/LoginPage.d.ts +2 -1
- package/dist/components/pages/LoginPageHero.d.ts +2 -1
- package/dist/components/pages/LoginPageHero.js +297 -291
- package/dist/components/pages/LoginPageTailwind.d.ts +2 -1
- package/dist/components/pages/LoginPageTailwind.js +197 -191
- package/dist/components/pages/SetPasswordPage.d.ts +2 -1
- package/dist/components/pages/SetPasswordPageHero.d.ts +3 -2
- package/dist/components/pages/SetPasswordPageHero.js +98 -92
- package/dist/components/pages/SetPasswordPageTailwind.d.ts +3 -2
- package/dist/components/pages/SetPasswordPageTailwind.js +63 -57
- package/dist/components/pages/SignupPage.d.ts +2 -1
- package/dist/components/pages/SignupPageHero.d.ts +3 -2
- package/dist/components/pages/SignupPageHero.js +139 -133
- package/dist/components/pages/SignupPageTailwind.d.ts +3 -2
- package/dist/components/pages/SignupPageTailwind.js +123 -117
- package/dist/components/pages/VerifyOtpPage.d.ts +2 -1
- package/dist/components/pages/VerifyOtpPageHero.d.ts +2 -1
- package/dist/components/pages/VerifyOtpPageHero.js +110 -104
- package/dist/components/pages/VerifyOtpPageTailwind.d.ts +2 -1
- package/dist/components/pages/VerifyOtpPageTailwind.js +60 -54
- package/dist/components/ui/translations.d.ts +9 -0
- package/dist/components/ui/translations.js +18 -0
- package/dist/config.d.ts +12 -0
- package/dist/config.js +11 -0
- package/dist/exports/client.d.ts +5 -0
- package/dist/exports/client.js +5 -0
- package/dist/exports/rsc.d.ts +7 -0
- package/dist/exports/rsc.js +8 -0
- package/dist/index.js +12 -2
- package/package.json +3 -2
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { headers } from 'next/headers';
|
|
3
|
+
import { redirect } from 'next/navigation';
|
|
3
4
|
import AuthPagesClient from './AuthPages.js';
|
|
4
|
-
import { pluginConfig } from '../config.js';
|
|
5
|
+
import { getServerAllowSignup, getServerGoogleOAuthEnabled, pluginConfig } from '../config.js';
|
|
5
6
|
import { detectServerLocale } from './ui/locale.js';
|
|
7
|
+
// Use pluginConfig singleton directly - standard Payload plugin pattern
|
|
6
8
|
/**
|
|
7
9
|
* Server component wrapper for AuthPages.
|
|
8
|
-
* Reads plugin config
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* `style`, `googleOAuthEnabled`, etc. options are the single source of truth.
|
|
10
|
+
* Reads plugin config from environment variables set during plugin initialization,
|
|
11
|
+
* ensuring the correct settings are used even in linked monorepo setups where
|
|
12
|
+
* module singletons may not be shared across entry points.
|
|
12
13
|
*
|
|
13
14
|
* Locale is resolved per-request: an explicit `locale` prop always wins,
|
|
14
15
|
* otherwise it's auto-detected from the `NEXT_LOCALE` cookie or
|
|
@@ -25,11 +26,17 @@ import { detectServerLocale } from './ui/locale.js';
|
|
|
25
26
|
* ```
|
|
26
27
|
*/ export default async function AuthPages(props) {
|
|
27
28
|
const resolvedLocale = props.locale ?? detectServerLocale(await headers());
|
|
29
|
+
const resolvedAllowSignup = props.allowSignup ?? getServerAllowSignup();
|
|
30
|
+
const basePath = props.basePath?.replace(/\/$/, '') ?? '/auth';
|
|
31
|
+
// Redirect /signup to /login when signup is disabled
|
|
32
|
+
const currentSlug = Array.isArray(props.slug) ? props.slug[0] : props.slug;
|
|
33
|
+
if (!resolvedAllowSignup && currentSlug === 'signup') {
|
|
34
|
+
redirect(`${basePath}/login`);
|
|
35
|
+
}
|
|
28
36
|
return /*#__PURE__*/ _jsx(AuthPagesClient, {
|
|
29
37
|
...props,
|
|
30
|
-
showGoogleOAuth: props.showGoogleOAuth ??
|
|
31
|
-
|
|
32
|
-
allowSignup: props.allowSignup ?? pluginConfig.allowSignup,
|
|
38
|
+
showGoogleOAuth: props.showGoogleOAuth ?? getServerGoogleOAuthEnabled(),
|
|
39
|
+
allowSignup: resolvedAllowSignup,
|
|
33
40
|
passwordLogin: pluginConfig.passwordLogin,
|
|
34
41
|
otpLogin: pluginConfig.otpLogin,
|
|
35
42
|
locale: resolvedLocale
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface PoweredByConfig {
|
|
3
|
+
enabled?: boolean;
|
|
4
|
+
logoUrl?: string;
|
|
5
|
+
linkUrl?: string;
|
|
6
|
+
width?: number;
|
|
7
|
+
height?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface AuthCardShellProps {
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
logo?: React.ReactNode;
|
|
12
|
+
title?: string;
|
|
13
|
+
subtitle?: string;
|
|
14
|
+
footer?: React.ReactNode;
|
|
15
|
+
poweredBy?: PoweredByConfig;
|
|
16
|
+
cardClassName?: string;
|
|
17
|
+
removeBorder?: boolean;
|
|
18
|
+
removeShadow?: boolean;
|
|
19
|
+
mobileVariant?: 'plain' | 'card';
|
|
20
|
+
}
|
|
21
|
+
export declare function AuthCardShell({ children, logo, title, subtitle, footer, poweredBy, cardClassName, removeBorder, removeShadow, mobileVariant, }: AuthCardShellProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { Card, CardContent, CardFooter } from '../ui/index.js';
|
|
5
|
+
import { PoweredBy } from '../PoweredBy.js';
|
|
6
|
+
import { pluginConfig } from '../../config.js';
|
|
7
|
+
function DefaultLogo() {
|
|
8
|
+
if (pluginConfig.Logo) {
|
|
9
|
+
const L = pluginConfig.Logo;
|
|
10
|
+
return /*#__PURE__*/ _jsx(L, {});
|
|
11
|
+
}
|
|
12
|
+
if (pluginConfig.logoUrl) {
|
|
13
|
+
return /*#__PURE__*/ _jsx("img", {
|
|
14
|
+
src: pluginConfig.logoUrl,
|
|
15
|
+
alt: "",
|
|
16
|
+
width: 180,
|
|
17
|
+
height: 42,
|
|
18
|
+
className: "object-contain"
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
export function AuthCardShell({ children, logo, title, subtitle, footer, poweredBy, cardClassName = '', removeBorder = false, removeShadow = false, mobileVariant = 'plain' }) {
|
|
24
|
+
const displayLogo = logo || /*#__PURE__*/ _jsx(DefaultLogo, {});
|
|
25
|
+
const header = (displayLogo || title) && /*#__PURE__*/ _jsxs("div", {
|
|
26
|
+
className: "flex flex-col items-center gap-2 pt-8 pb-4 px-8",
|
|
27
|
+
children: [
|
|
28
|
+
displayLogo && /*#__PURE__*/ _jsx("div", {
|
|
29
|
+
className: "flex justify-center mb-3",
|
|
30
|
+
children: displayLogo
|
|
31
|
+
}),
|
|
32
|
+
title && /*#__PURE__*/ _jsx("h1", {
|
|
33
|
+
className: "text-2xl font-bold text-gray-900 text-center tracking-tight",
|
|
34
|
+
children: title
|
|
35
|
+
}),
|
|
36
|
+
subtitle && /*#__PURE__*/ _jsx("p", {
|
|
37
|
+
className: "text-gray-600 text-sm text-center",
|
|
38
|
+
children: subtitle
|
|
39
|
+
})
|
|
40
|
+
]
|
|
41
|
+
});
|
|
42
|
+
const cardBorderShadowClass = [
|
|
43
|
+
removeBorder ? '!border-0' : '',
|
|
44
|
+
removeShadow ? '!shadow-none' : ''
|
|
45
|
+
].filter(Boolean).join(' ');
|
|
46
|
+
const cardBody = /*#__PURE__*/ _jsxs("div", {
|
|
47
|
+
className: "w-full max-w-md mx-auto animate-[fadeIn_0.5s_ease-out]",
|
|
48
|
+
style: {
|
|
49
|
+
maxWidth: '448px'
|
|
50
|
+
},
|
|
51
|
+
children: [
|
|
52
|
+
/*#__PURE__*/ _jsxs(Card, {
|
|
53
|
+
className: `${cardBorderShadowClass} ${cardClassName}`.trim(),
|
|
54
|
+
children: [
|
|
55
|
+
header,
|
|
56
|
+
/*#__PURE__*/ _jsx(CardContent, {
|
|
57
|
+
children: children
|
|
58
|
+
}),
|
|
59
|
+
footer && /*#__PURE__*/ _jsx(CardFooter, {
|
|
60
|
+
children: footer
|
|
61
|
+
})
|
|
62
|
+
]
|
|
63
|
+
}),
|
|
64
|
+
/*#__PURE__*/ _jsx(PoweredBy, {
|
|
65
|
+
...poweredBy
|
|
66
|
+
})
|
|
67
|
+
]
|
|
68
|
+
});
|
|
69
|
+
if (mobileVariant === 'card') {
|
|
70
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
71
|
+
className: "px-4 py-8 md:py-12",
|
|
72
|
+
children: cardBody
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
76
|
+
children: [
|
|
77
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
78
|
+
className: "md:hidden flex flex-col w-full max-w-md mx-auto light [color-scheme:light] px-4 py-8",
|
|
79
|
+
"data-theme": "light",
|
|
80
|
+
style: {
|
|
81
|
+
maxWidth: '448px'
|
|
82
|
+
},
|
|
83
|
+
children: [
|
|
84
|
+
header,
|
|
85
|
+
/*#__PURE__*/ _jsx("div", {
|
|
86
|
+
className: "px-8 pb-6",
|
|
87
|
+
children: children
|
|
88
|
+
}),
|
|
89
|
+
footer && /*#__PURE__*/ _jsx("div", {
|
|
90
|
+
className: "px-8 pb-8 flex justify-center",
|
|
91
|
+
children: footer
|
|
92
|
+
}),
|
|
93
|
+
/*#__PURE__*/ _jsx(PoweredBy, {
|
|
94
|
+
...poweredBy
|
|
95
|
+
})
|
|
96
|
+
]
|
|
97
|
+
}),
|
|
98
|
+
/*#__PURE__*/ _jsx("div", {
|
|
99
|
+
className: "hidden md:flex items-center justify-center px-4 py-12 w-full h-full",
|
|
100
|
+
children: cardBody
|
|
101
|
+
})
|
|
102
|
+
]
|
|
103
|
+
});
|
|
104
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { type DeepPartial, type UiTranslations } from '../ui/translations';
|
|
3
|
+
import { type PoweredByConfig } from './AuthCardShell';
|
|
4
|
+
export interface FormRendererProps {
|
|
5
|
+
slug: string | string[];
|
|
6
|
+
redirectTo?: string;
|
|
7
|
+
onPasswordLogin?: (credentials: {
|
|
8
|
+
email: string;
|
|
9
|
+
password: string;
|
|
10
|
+
}) => Promise<void>;
|
|
11
|
+
onSignup?: (data: {
|
|
12
|
+
name: string;
|
|
13
|
+
email: string;
|
|
14
|
+
}) => Promise<void>;
|
|
15
|
+
basePath?: string;
|
|
16
|
+
showGoogleOAuth?: boolean;
|
|
17
|
+
allowSignup?: boolean;
|
|
18
|
+
passwordLogin?: boolean;
|
|
19
|
+
otpLogin?: boolean;
|
|
20
|
+
locale?: string;
|
|
21
|
+
messages?: Record<string, DeepPartial<UiTranslations>>;
|
|
22
|
+
logo?: React.ReactNode;
|
|
23
|
+
title?: string;
|
|
24
|
+
subtitle?: string;
|
|
25
|
+
footer?: React.ReactNode;
|
|
26
|
+
poweredBy?: PoweredByConfig;
|
|
27
|
+
cardClassName?: string;
|
|
28
|
+
removeBorder?: boolean;
|
|
29
|
+
removeShadow?: boolean;
|
|
30
|
+
mobileVariant?: 'plain' | 'card';
|
|
31
|
+
}
|
|
32
|
+
export declare function FormRenderer({ slug, redirectTo, onPasswordLogin, onSignup, basePath, showGoogleOAuth, allowSignup, passwordLogin, otpLogin, locale, messages, logo, title: titleOverride, subtitle: subtitleOverride, footer, poweredBy, cardClassName, removeBorder, removeShadow, mobileVariant, }: FormRendererProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import React, { useState } from 'react';
|
|
4
|
+
import { pluginConfig, initClientConfig } from '../../config.js';
|
|
5
|
+
import { detectClientLocale } from '../ui/locale.js';
|
|
6
|
+
import { getUiTranslations } from '../ui/translations.js';
|
|
7
|
+
import { AUTH_FORMS } from '../forms/index.js';
|
|
8
|
+
import { FORM_CONFIGS } from './formConfigs.js';
|
|
9
|
+
import { AuthCardShell } from './AuthCardShell.js';
|
|
10
|
+
const defaultPasswordLogin = async ({ email, password })=>{
|
|
11
|
+
const res = await fetch('/api/users/login', {
|
|
12
|
+
method: 'POST',
|
|
13
|
+
headers: {
|
|
14
|
+
'Content-Type': 'application/json'
|
|
15
|
+
},
|
|
16
|
+
body: JSON.stringify({
|
|
17
|
+
email,
|
|
18
|
+
password
|
|
19
|
+
})
|
|
20
|
+
});
|
|
21
|
+
if (!res.ok) {
|
|
22
|
+
const err = await res.json();
|
|
23
|
+
throw new Error(err.errors?.[0]?.message || 'Login failed');
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const defaultSignup = async ({ name, email })=>{
|
|
27
|
+
const res = await fetch('/api/auth/signup', {
|
|
28
|
+
method: 'POST',
|
|
29
|
+
headers: {
|
|
30
|
+
'Content-Type': 'application/json'
|
|
31
|
+
},
|
|
32
|
+
body: JSON.stringify({
|
|
33
|
+
name,
|
|
34
|
+
email
|
|
35
|
+
})
|
|
36
|
+
});
|
|
37
|
+
if (!res.ok) {
|
|
38
|
+
const err = await res.json();
|
|
39
|
+
throw new Error(err.message || 'Signup failed');
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
export function FormRenderer({ slug, redirectTo = '/admin', onPasswordLogin = defaultPasswordLogin, onSignup = defaultSignup, basePath = '/auth', showGoogleOAuth, allowSignup = true, passwordLogin = true, otpLogin = true, locale, messages, logo, title: titleOverride, subtitle: subtitleOverride, footer, poweredBy, cardClassName, removeBorder, removeShadow, mobileVariant }) {
|
|
43
|
+
initClientConfig({
|
|
44
|
+
style: pluginConfig.style,
|
|
45
|
+
googleOAuthEnabled: showGoogleOAuth ?? pluginConfig.googleOAuthEnabled,
|
|
46
|
+
passwordLogin,
|
|
47
|
+
otpLogin
|
|
48
|
+
});
|
|
49
|
+
const resolvedLocale = locale ?? detectClientLocale();
|
|
50
|
+
const t = getUiTranslations(resolvedLocale, messages);
|
|
51
|
+
const normalizedSlug = Array.isArray(slug) ? slug[0] : slug;
|
|
52
|
+
const base = basePath.replace(/\/$/, '');
|
|
53
|
+
const [dynamicTitle, setDynamicTitle] = useState(undefined);
|
|
54
|
+
const [dynamicSubtitle, setDynamicSubtitle] = useState(undefined);
|
|
55
|
+
const effectiveSlug = !allowSignup && normalizedSlug === 'signup' ? 'login' : normalizedSlug in AUTH_FORMS ? normalizedSlug : 'login';
|
|
56
|
+
const config = FORM_CONFIGS[effectiveSlug];
|
|
57
|
+
const FormComponent = AUTH_FORMS[effectiveSlug];
|
|
58
|
+
const propsContext = {
|
|
59
|
+
redirectTo,
|
|
60
|
+
onPasswordLogin,
|
|
61
|
+
onSignup,
|
|
62
|
+
basePath: base,
|
|
63
|
+
showGoogleOAuth: showGoogleOAuth ?? pluginConfig.googleOAuthEnabled,
|
|
64
|
+
allowSignup,
|
|
65
|
+
locale: resolvedLocale,
|
|
66
|
+
messages,
|
|
67
|
+
setDynamicTitle,
|
|
68
|
+
setDynamicSubtitle
|
|
69
|
+
};
|
|
70
|
+
const translationSection = t[config.translationKey];
|
|
71
|
+
const title = titleOverride ?? dynamicTitle ?? translationSection.title;
|
|
72
|
+
const subtitle = subtitleOverride ?? dynamicSubtitle ?? translationSection.subtitle;
|
|
73
|
+
const formProps = config.getProps(propsContext);
|
|
74
|
+
return /*#__PURE__*/ _jsx(AuthCardShell, {
|
|
75
|
+
logo: logo,
|
|
76
|
+
title: title,
|
|
77
|
+
subtitle: subtitle,
|
|
78
|
+
footer: footer,
|
|
79
|
+
poweredBy: poweredBy,
|
|
80
|
+
cardClassName: cardClassName,
|
|
81
|
+
removeBorder: removeBorder,
|
|
82
|
+
removeShadow: removeShadow,
|
|
83
|
+
mobileVariant: mobileVariant,
|
|
84
|
+
children: /*#__PURE__*/ _jsx(FormComponent, {
|
|
85
|
+
...formProps
|
|
86
|
+
})
|
|
87
|
+
});
|
|
88
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { UiTranslations, DeepPartial } from '../ui/translations';
|
|
2
|
+
import type { AuthFormSlug } from '../forms/index';
|
|
3
|
+
export interface FormPropsContext {
|
|
4
|
+
redirectTo: string;
|
|
5
|
+
onPasswordLogin: (credentials: {
|
|
6
|
+
email: string;
|
|
7
|
+
password: string;
|
|
8
|
+
}) => Promise<void>;
|
|
9
|
+
onSignup: (data: {
|
|
10
|
+
name: string;
|
|
11
|
+
email: string;
|
|
12
|
+
}) => Promise<void>;
|
|
13
|
+
basePath: string;
|
|
14
|
+
showGoogleOAuth: boolean;
|
|
15
|
+
allowSignup: boolean;
|
|
16
|
+
locale: string;
|
|
17
|
+
messages?: Record<string, DeepPartial<UiTranslations>>;
|
|
18
|
+
setDynamicTitle: (title: string | undefined) => void;
|
|
19
|
+
setDynamicSubtitle: (subtitle: string | undefined) => void;
|
|
20
|
+
}
|
|
21
|
+
export interface FormConfig {
|
|
22
|
+
translationKey: keyof UiTranslations;
|
|
23
|
+
getProps: (ctx: FormPropsContext) => Record<string, any>;
|
|
24
|
+
}
|
|
25
|
+
export declare const FORM_CONFIGS: Record<AuthFormSlug, FormConfig>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export const FORM_CONFIGS = {
|
|
2
|
+
'login': {
|
|
3
|
+
translationKey: 'login',
|
|
4
|
+
getProps: (ctx)=>({
|
|
5
|
+
onPasswordLogin: ctx.onPasswordLogin,
|
|
6
|
+
redirectTo: ctx.redirectTo,
|
|
7
|
+
showGoogleOAuth: ctx.showGoogleOAuth,
|
|
8
|
+
signupUrl: ctx.allowSignup ? `${ctx.basePath}/signup` : undefined,
|
|
9
|
+
locale: ctx.locale,
|
|
10
|
+
messages: ctx.messages,
|
|
11
|
+
onStepChange: (_, title, subtitle)=>{
|
|
12
|
+
ctx.setDynamicTitle(title);
|
|
13
|
+
ctx.setDynamicSubtitle(subtitle);
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
},
|
|
17
|
+
'signup': {
|
|
18
|
+
translationKey: 'signup',
|
|
19
|
+
getProps: (ctx)=>({
|
|
20
|
+
onSignup: ctx.onSignup,
|
|
21
|
+
showGoogleOAuth: ctx.showGoogleOAuth,
|
|
22
|
+
loginUrl: `${ctx.basePath}/login`,
|
|
23
|
+
verifyOtpUrl: `${ctx.basePath}/verify-otp`,
|
|
24
|
+
locale: ctx.locale,
|
|
25
|
+
messages: ctx.messages
|
|
26
|
+
})
|
|
27
|
+
},
|
|
28
|
+
'forgot-password': {
|
|
29
|
+
translationKey: 'forgotPassword',
|
|
30
|
+
getProps: (ctx)=>({
|
|
31
|
+
loginUrl: `${ctx.basePath}/login`,
|
|
32
|
+
locale: ctx.locale,
|
|
33
|
+
messages: ctx.messages
|
|
34
|
+
})
|
|
35
|
+
},
|
|
36
|
+
'verify-otp': {
|
|
37
|
+
translationKey: 'verifyOtp',
|
|
38
|
+
getProps: (ctx)=>({
|
|
39
|
+
loginUrl: `${ctx.basePath}/login`,
|
|
40
|
+
locale: ctx.locale,
|
|
41
|
+
messages: ctx.messages,
|
|
42
|
+
onPurposeChange: (_, title, subtitle)=>{
|
|
43
|
+
ctx.setDynamicTitle(title);
|
|
44
|
+
ctx.setDynamicSubtitle(subtitle);
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
},
|
|
48
|
+
'set-password': {
|
|
49
|
+
translationKey: 'setPassword',
|
|
50
|
+
getProps: (ctx)=>({
|
|
51
|
+
redirectTo: ctx.redirectTo,
|
|
52
|
+
locale: ctx.locale,
|
|
53
|
+
messages: ctx.messages
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type DeepPartial, type UiTranslations } from '../ui/translations';
|
|
2
|
+
export interface ForgotPasswordFormProps {
|
|
3
|
+
loginUrl?: string;
|
|
4
|
+
locale?: string;
|
|
5
|
+
messages?: Record<string, DeepPartial<UiTranslations>>;
|
|
6
|
+
}
|
|
7
|
+
export declare function ForgotPasswordForm({ loginUrl, locale, messages, }: ForgotPasswordFormProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { Button, Input } from '../ui/index.js';
|
|
5
|
+
import { useForgotPasswordFlow } from '../../auth/application/hooks/useForgotPasswordFlow.js';
|
|
6
|
+
import { getUiTranslations } from '../ui/translations.js';
|
|
7
|
+
export function ForgotPasswordForm({ loginUrl = '/login', locale, messages }) {
|
|
8
|
+
const { email, error, isLoading, setEmail, handleSubmit } = useForgotPasswordFlow();
|
|
9
|
+
const translations = getUiTranslations(locale, messages);
|
|
10
|
+
const t = translations.forgotPassword;
|
|
11
|
+
const errors = translations.errors;
|
|
12
|
+
// Helper to translate error keys
|
|
13
|
+
const getErrorMessage = (err)=>{
|
|
14
|
+
if (!err) return null;
|
|
15
|
+
if (err in errors) return errors[err];
|
|
16
|
+
return err;
|
|
17
|
+
};
|
|
18
|
+
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
19
|
+
children: [
|
|
20
|
+
/*#__PURE__*/ _jsxs("form", {
|
|
21
|
+
onSubmit: handleSubmit,
|
|
22
|
+
className: "space-y-4",
|
|
23
|
+
children: [
|
|
24
|
+
error && /*#__PURE__*/ _jsx("div", {
|
|
25
|
+
className: "bg-red-50 text-red-600 border border-red-200 rounded-lg p-3 text-sm animate-[fadeIn_0.2s_ease-out]",
|
|
26
|
+
children: getErrorMessage(error)
|
|
27
|
+
}),
|
|
28
|
+
/*#__PURE__*/ _jsx(Input, {
|
|
29
|
+
type: "email",
|
|
30
|
+
label: t.emailLabel,
|
|
31
|
+
value: email,
|
|
32
|
+
onChange: (e)=>setEmail(e.target.value),
|
|
33
|
+
isRequired: true
|
|
34
|
+
}),
|
|
35
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
36
|
+
type: "submit",
|
|
37
|
+
variant: "primary",
|
|
38
|
+
isLoading: isLoading,
|
|
39
|
+
children: t.sendResetCode
|
|
40
|
+
})
|
|
41
|
+
]
|
|
42
|
+
}),
|
|
43
|
+
/*#__PURE__*/ _jsx("div", {
|
|
44
|
+
className: "text-center mt-6",
|
|
45
|
+
children: /*#__PURE__*/ _jsxs("a", {
|
|
46
|
+
href: loginUrl,
|
|
47
|
+
className: "text-sm text-gray-600 hover:text-gray-900 inline-flex items-center gap-1",
|
|
48
|
+
children: [
|
|
49
|
+
"← ",
|
|
50
|
+
t.backToLogin
|
|
51
|
+
]
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
]
|
|
55
|
+
});
|
|
56
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type DeepPartial, type UiTranslations } from '../ui/translations';
|
|
2
|
+
export interface LoginFormProps {
|
|
3
|
+
onPasswordLogin: (credentials: {
|
|
4
|
+
email: string;
|
|
5
|
+
password: string;
|
|
6
|
+
}) => Promise<void>;
|
|
7
|
+
redirectTo?: string;
|
|
8
|
+
showGoogleOAuth?: boolean;
|
|
9
|
+
signupUrl?: string;
|
|
10
|
+
locale?: string;
|
|
11
|
+
messages?: Record<string, DeepPartial<UiTranslations>>;
|
|
12
|
+
/** Callback to update the card title based on current step */
|
|
13
|
+
onStepChange?: (step: 'email' | 'password' | 'otp-prompt', title: string, subtitle: string) => void;
|
|
14
|
+
}
|
|
15
|
+
export declare function LoginForm(props: LoginFormProps): import("react/jsx-runtime").JSX.Element;
|