@main12/auth-login 0.1.0 → 0.1.2
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 +187 -151
- package/dist/components/pages/ForgotPasswordPage.d.ts +1 -1
- package/dist/components/pages/ForgotPasswordPage.js +9 -42
- package/dist/components/pages/ForgotPasswordPageHero.d.ts +5 -0
- package/dist/components/pages/ForgotPasswordPageHero.js +69 -0
- package/dist/components/pages/ForgotPasswordPageTailwind.d.ts +5 -0
- package/dist/components/pages/ForgotPasswordPageTailwind.js +45 -0
- package/dist/components/pages/LoginPage.js +8 -218
- package/dist/components/pages/LoginPageHero.d.ts +11 -0
- package/dist/components/pages/LoginPageHero.js +298 -0
- package/dist/components/pages/LoginPageTailwind.d.ts +11 -0
- package/dist/components/pages/LoginPageTailwind.js +222 -0
- package/dist/components/pages/SetPasswordPage.d.ts +1 -1
- package/dist/components/pages/SetPasswordPage.js +9 -71
- package/dist/components/pages/SetPasswordPageHero.d.ts +5 -0
- package/dist/components/pages/SetPasswordPageHero.js +93 -0
- package/dist/components/pages/SetPasswordPageTailwind.d.ts +5 -0
- package/dist/components/pages/SetPasswordPageTailwind.js +74 -0
- package/dist/components/pages/SignupPage.d.ts +1 -1
- package/dist/components/pages/SignupPage.js +9 -126
- package/dist/components/pages/SignupPageHero.d.ts +10 -0
- package/dist/components/pages/SignupPageHero.js +150 -0
- package/dist/components/pages/SignupPageTailwind.d.ts +10 -0
- package/dist/components/pages/SignupPageTailwind.js +129 -0
- package/dist/components/pages/VerifyOtpPage.js +8 -83
- package/dist/components/pages/VerifyOtpPageHero.d.ts +5 -0
- package/dist/components/pages/VerifyOtpPageHero.js +104 -0
- package/dist/components/pages/VerifyOtpPageTailwind.d.ts +5 -0
- package/dist/components/pages/VerifyOtpPageTailwind.js +87 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.js +6 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +5 -1
- package/package.json +5 -2
|
@@ -0,0 +1,150 @@
|
|
|
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, Divider } from '@heroui/react';
|
|
5
|
+
import { Icon } from '@iconify/react';
|
|
6
|
+
import { motion } from 'framer-motion';
|
|
7
|
+
import { AuthLayout } from '../AuthLayout.js';
|
|
8
|
+
export default function SignupPageHero({ onSignup, showGoogleOAuth = true, loginUrl = '/login', logo, poweredBy, cardClassName, backgroundClass }) {
|
|
9
|
+
const [name, setName] = React.useState('');
|
|
10
|
+
const [email, setEmail] = React.useState('');
|
|
11
|
+
const [isLoading, setIsLoading] = React.useState(false);
|
|
12
|
+
const [error, setError] = React.useState(null);
|
|
13
|
+
const handleSubmit = async (e)=>{
|
|
14
|
+
e.preventDefault();
|
|
15
|
+
setIsLoading(true);
|
|
16
|
+
setError(null);
|
|
17
|
+
try {
|
|
18
|
+
await onSignup({
|
|
19
|
+
name,
|
|
20
|
+
email
|
|
21
|
+
});
|
|
22
|
+
window.location.href = `/verify-otp?email=${encodeURIComponent(email)}&purpose=signup`;
|
|
23
|
+
} catch (err) {
|
|
24
|
+
setError(err.message || 'Signup failed');
|
|
25
|
+
} finally{
|
|
26
|
+
setIsLoading(false);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
return /*#__PURE__*/ _jsxs(AuthLayout, {
|
|
30
|
+
logo: logo,
|
|
31
|
+
title: "Create Account",
|
|
32
|
+
subtitle: "Enter your details to get started",
|
|
33
|
+
poweredBy: poweredBy,
|
|
34
|
+
cardClassName: cardClassName,
|
|
35
|
+
backgroundClass: backgroundClass,
|
|
36
|
+
footer: /*#__PURE__*/ _jsxs("p", {
|
|
37
|
+
className: "text-center text-gray-600 text-sm",
|
|
38
|
+
children: [
|
|
39
|
+
"Already have an account? ",
|
|
40
|
+
/*#__PURE__*/ _jsx("a", {
|
|
41
|
+
href: loginUrl,
|
|
42
|
+
className: "text-gray-900 font-medium hover:underline",
|
|
43
|
+
children: "Sign in"
|
|
44
|
+
})
|
|
45
|
+
]
|
|
46
|
+
}),
|
|
47
|
+
children: [
|
|
48
|
+
showGoogleOAuth && /*#__PURE__*/ _jsxs(_Fragment, {
|
|
49
|
+
children: [
|
|
50
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
51
|
+
fullWidth: true,
|
|
52
|
+
variant: "bordered",
|
|
53
|
+
size: "lg",
|
|
54
|
+
className: "mb-4 h-12 border-gray-300 rounded-full text-gray-700 hover:bg-gray-50",
|
|
55
|
+
startContent: /*#__PURE__*/ _jsx(Icon, {
|
|
56
|
+
icon: "flat-color-icons:google",
|
|
57
|
+
width: 20
|
|
58
|
+
}),
|
|
59
|
+
children: "Continue with Google"
|
|
60
|
+
}),
|
|
61
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
62
|
+
className: "flex items-center gap-4 my-4",
|
|
63
|
+
children: [
|
|
64
|
+
/*#__PURE__*/ _jsx(Divider, {
|
|
65
|
+
className: "flex-1"
|
|
66
|
+
}),
|
|
67
|
+
/*#__PURE__*/ _jsx("span", {
|
|
68
|
+
className: "text-gray-500 text-sm",
|
|
69
|
+
children: "or"
|
|
70
|
+
}),
|
|
71
|
+
/*#__PURE__*/ _jsx(Divider, {
|
|
72
|
+
className: "flex-1"
|
|
73
|
+
})
|
|
74
|
+
]
|
|
75
|
+
})
|
|
76
|
+
]
|
|
77
|
+
}),
|
|
78
|
+
/*#__PURE__*/ _jsxs("form", {
|
|
79
|
+
onSubmit: handleSubmit,
|
|
80
|
+
className: "space-y-4",
|
|
81
|
+
children: [
|
|
82
|
+
error && /*#__PURE__*/ _jsx(motion.div, {
|
|
83
|
+
className: "bg-red-50 text-red-600 border border-red-200 rounded-lg p-3 text-sm",
|
|
84
|
+
initial: {
|
|
85
|
+
opacity: 0
|
|
86
|
+
},
|
|
87
|
+
animate: {
|
|
88
|
+
opacity: 1
|
|
89
|
+
},
|
|
90
|
+
children: error
|
|
91
|
+
}),
|
|
92
|
+
/*#__PURE__*/ _jsx(Input, {
|
|
93
|
+
type: "text",
|
|
94
|
+
label: "Full Name",
|
|
95
|
+
value: name,
|
|
96
|
+
onValueChange: setName,
|
|
97
|
+
variant: "bordered",
|
|
98
|
+
size: "lg",
|
|
99
|
+
isRequired: true,
|
|
100
|
+
classNames: {
|
|
101
|
+
input: 'text-gray-900',
|
|
102
|
+
label: 'text-gray-600',
|
|
103
|
+
inputWrapper: 'border-gray-300 bg-white'
|
|
104
|
+
}
|
|
105
|
+
}),
|
|
106
|
+
/*#__PURE__*/ _jsx(Input, {
|
|
107
|
+
type: "email",
|
|
108
|
+
label: "Email",
|
|
109
|
+
value: email,
|
|
110
|
+
onValueChange: setEmail,
|
|
111
|
+
variant: "bordered",
|
|
112
|
+
size: "lg",
|
|
113
|
+
isRequired: true,
|
|
114
|
+
classNames: {
|
|
115
|
+
input: 'text-gray-900',
|
|
116
|
+
label: 'text-gray-600',
|
|
117
|
+
inputWrapper: 'border-gray-300 bg-white'
|
|
118
|
+
}
|
|
119
|
+
}),
|
|
120
|
+
/*#__PURE__*/ _jsxs("p", {
|
|
121
|
+
className: "text-xs text-gray-600 text-center",
|
|
122
|
+
children: [
|
|
123
|
+
"By signing up, you agree to our ",
|
|
124
|
+
/*#__PURE__*/ _jsx("a", {
|
|
125
|
+
href: "/terms",
|
|
126
|
+
className: "text-gray-900 hover:underline",
|
|
127
|
+
children: "Terms"
|
|
128
|
+
}),
|
|
129
|
+
" and ",
|
|
130
|
+
/*#__PURE__*/ _jsx("a", {
|
|
131
|
+
href: "/privacy",
|
|
132
|
+
className: "text-gray-900 hover:underline",
|
|
133
|
+
children: "Privacy"
|
|
134
|
+
})
|
|
135
|
+
]
|
|
136
|
+
}),
|
|
137
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
138
|
+
type: "submit",
|
|
139
|
+
fullWidth: true,
|
|
140
|
+
size: "lg",
|
|
141
|
+
color: "primary",
|
|
142
|
+
isLoading: isLoading,
|
|
143
|
+
className: "h-12 font-semibold",
|
|
144
|
+
children: "Create Account"
|
|
145
|
+
})
|
|
146
|
+
]
|
|
147
|
+
})
|
|
148
|
+
]
|
|
149
|
+
});
|
|
150
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AuthLayoutConfig } from '../AuthLayout.js';
|
|
2
|
+
export interface SignupPageProps extends AuthLayoutConfig {
|
|
3
|
+
onSignup: (data: {
|
|
4
|
+
name: string;
|
|
5
|
+
email: string;
|
|
6
|
+
}) => Promise<void>;
|
|
7
|
+
showGoogleOAuth?: boolean;
|
|
8
|
+
loginUrl?: string;
|
|
9
|
+
}
|
|
10
|
+
export default function SignupPage({ onSignup, showGoogleOAuth, loginUrl, logo, poweredBy, cardClassName, backgroundClass, }: SignupPageProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,129 @@
|
|
|
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, Divider } from '../ui/index.js';
|
|
5
|
+
import { AuthLayout } from '../AuthLayout.js';
|
|
6
|
+
export default function SignupPage({ onSignup, showGoogleOAuth = true, loginUrl = '/login', logo, poweredBy, cardClassName, backgroundClass }) {
|
|
7
|
+
const [name, setName] = React.useState('');
|
|
8
|
+
const [email, setEmail] = React.useState('');
|
|
9
|
+
const [isLoading, setIsLoading] = React.useState(false);
|
|
10
|
+
const [error, setError] = React.useState(null);
|
|
11
|
+
const handleSubmit = async (e)=>{
|
|
12
|
+
e.preventDefault();
|
|
13
|
+
setIsLoading(true);
|
|
14
|
+
setError(null);
|
|
15
|
+
try {
|
|
16
|
+
await onSignup({
|
|
17
|
+
name,
|
|
18
|
+
email
|
|
19
|
+
});
|
|
20
|
+
window.location.href = `/verify-otp?email=${encodeURIComponent(email)}&purpose=signup`;
|
|
21
|
+
} catch (err) {
|
|
22
|
+
setError(err.message || 'Signup failed');
|
|
23
|
+
} finally{
|
|
24
|
+
setIsLoading(false);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
return /*#__PURE__*/ _jsxs(AuthLayout, {
|
|
28
|
+
logo: logo,
|
|
29
|
+
title: "Create Account",
|
|
30
|
+
subtitle: "Enter your details to get started",
|
|
31
|
+
poweredBy: poweredBy,
|
|
32
|
+
cardClassName: cardClassName,
|
|
33
|
+
backgroundClass: backgroundClass,
|
|
34
|
+
footer: /*#__PURE__*/ _jsxs("p", {
|
|
35
|
+
className: "text-center text-gray-600 text-sm",
|
|
36
|
+
children: [
|
|
37
|
+
"Already have an account?",
|
|
38
|
+
' ',
|
|
39
|
+
/*#__PURE__*/ _jsx("a", {
|
|
40
|
+
href: loginUrl,
|
|
41
|
+
className: "text-gray-900 font-medium hover:underline",
|
|
42
|
+
children: "Sign in"
|
|
43
|
+
})
|
|
44
|
+
]
|
|
45
|
+
}),
|
|
46
|
+
children: [
|
|
47
|
+
showGoogleOAuth && /*#__PURE__*/ _jsxs(_Fragment, {
|
|
48
|
+
children: [
|
|
49
|
+
/*#__PURE__*/ _jsxs(Button, {
|
|
50
|
+
fullWidth: true,
|
|
51
|
+
variant: "bordered",
|
|
52
|
+
size: "lg",
|
|
53
|
+
className: "mb-4",
|
|
54
|
+
children: [
|
|
55
|
+
/*#__PURE__*/ _jsx("span", {
|
|
56
|
+
className: "text-lg",
|
|
57
|
+
children: "G"
|
|
58
|
+
}),
|
|
59
|
+
" Continue with Google"
|
|
60
|
+
]
|
|
61
|
+
}),
|
|
62
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
63
|
+
className: "flex items-center gap-4 my-4",
|
|
64
|
+
children: [
|
|
65
|
+
/*#__PURE__*/ _jsx(Divider, {
|
|
66
|
+
className: "flex-1"
|
|
67
|
+
}),
|
|
68
|
+
/*#__PURE__*/ _jsx("span", {
|
|
69
|
+
className: "text-gray-500 text-sm",
|
|
70
|
+
children: "or"
|
|
71
|
+
}),
|
|
72
|
+
/*#__PURE__*/ _jsx(Divider, {
|
|
73
|
+
className: "flex-1"
|
|
74
|
+
})
|
|
75
|
+
]
|
|
76
|
+
})
|
|
77
|
+
]
|
|
78
|
+
}),
|
|
79
|
+
/*#__PURE__*/ _jsxs("form", {
|
|
80
|
+
onSubmit: handleSubmit,
|
|
81
|
+
className: "space-y-4",
|
|
82
|
+
children: [
|
|
83
|
+
error && /*#__PURE__*/ _jsx("div", {
|
|
84
|
+
className: "bg-red-50 text-red-600 border border-red-200 rounded-lg p-3 text-sm animate-[fadeIn_0.2s_ease-out]",
|
|
85
|
+
children: error
|
|
86
|
+
}),
|
|
87
|
+
/*#__PURE__*/ _jsx(Input, {
|
|
88
|
+
label: "Full Name",
|
|
89
|
+
value: name,
|
|
90
|
+
onValueChange: setName,
|
|
91
|
+
isRequired: true
|
|
92
|
+
}),
|
|
93
|
+
/*#__PURE__*/ _jsx(Input, {
|
|
94
|
+
type: "email",
|
|
95
|
+
label: "Email",
|
|
96
|
+
value: email,
|
|
97
|
+
onValueChange: setEmail,
|
|
98
|
+
isRequired: true
|
|
99
|
+
}),
|
|
100
|
+
/*#__PURE__*/ _jsxs("p", {
|
|
101
|
+
className: "text-xs text-gray-600 text-center",
|
|
102
|
+
children: [
|
|
103
|
+
"By signing up, you agree to our",
|
|
104
|
+
' ',
|
|
105
|
+
/*#__PURE__*/ _jsx("a", {
|
|
106
|
+
href: "/terms",
|
|
107
|
+
className: "text-gray-900 hover:underline",
|
|
108
|
+
children: "Terms of Service"
|
|
109
|
+
}),
|
|
110
|
+
" and",
|
|
111
|
+
' ',
|
|
112
|
+
/*#__PURE__*/ _jsx("a", {
|
|
113
|
+
href: "/privacy",
|
|
114
|
+
className: "text-gray-900 hover:underline",
|
|
115
|
+
children: "Privacy Policy"
|
|
116
|
+
})
|
|
117
|
+
]
|
|
118
|
+
}),
|
|
119
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
120
|
+
type: "submit",
|
|
121
|
+
variant: "primary",
|
|
122
|
+
isLoading: isLoading,
|
|
123
|
+
children: "Create Account"
|
|
124
|
+
})
|
|
125
|
+
]
|
|
126
|
+
})
|
|
127
|
+
]
|
|
128
|
+
});
|
|
129
|
+
}
|
|
@@ -1,87 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsx as _jsx
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import { useVerifyOtpFlow } from '../../auth/application/hooks/useVerifyOtpFlow.js';
|
|
7
|
-
import { AuthLayout } from '../AuthLayout.js';
|
|
8
|
-
function VerifyOtpContent({ loginUrl = '/login', logo, poweredBy, cardClassName, backgroundClass }) {
|
|
9
|
-
const searchParams = useSearchParams();
|
|
10
|
-
const email = searchParams.get('email') || '';
|
|
11
|
-
const purpose = searchParams.get('purpose') || 'login';
|
|
12
|
-
const redirectTo = searchParams.get('redirect') || '/';
|
|
13
|
-
const { otp, error, isLoading, isResending, resendCooldown, setOtp, handleSubmit, handleResendCode } = useVerifyOtpFlow({
|
|
14
|
-
email,
|
|
15
|
-
purpose,
|
|
16
|
-
redirectTo
|
|
17
|
-
});
|
|
18
|
-
if (!email) return null;
|
|
19
|
-
const isPasswordReset = purpose === 'password-reset';
|
|
20
|
-
return /*#__PURE__*/ _jsx(AuthLayout, {
|
|
21
|
-
logo: logo,
|
|
22
|
-
title: isPasswordReset ? 'Reset Password' : 'Check Your Email',
|
|
23
|
-
subtitle: isPasswordReset ? 'Enter the code to reset your password' : 'We sent a 6-digit code to',
|
|
24
|
-
poweredBy: poweredBy,
|
|
25
|
-
cardClassName: cardClassName,
|
|
26
|
-
backgroundClass: backgroundClass,
|
|
27
|
-
footer: /*#__PURE__*/ _jsx("a", {
|
|
28
|
-
href: loginUrl,
|
|
29
|
-
className: "text-sm text-gray-600 hover:text-gray-900 flex items-center gap-1",
|
|
30
|
-
children: "← Back to Login"
|
|
31
|
-
}),
|
|
32
|
-
children: /*#__PURE__*/ _jsxs("div", {
|
|
33
|
-
className: "flex flex-col items-center gap-4",
|
|
34
|
-
children: [
|
|
35
|
-
/*#__PURE__*/ _jsx("p", {
|
|
36
|
-
className: "text-gray-700 text-sm font-medium",
|
|
37
|
-
children: email
|
|
38
|
-
}),
|
|
39
|
-
/*#__PURE__*/ _jsx(OtpInput, {
|
|
40
|
-
value: otp,
|
|
41
|
-
onValueChange: setOtp,
|
|
42
|
-
isDisabled: isLoading,
|
|
43
|
-
autoFocus: true
|
|
44
|
-
}),
|
|
45
|
-
error && /*#__PURE__*/ _jsx("div", {
|
|
46
|
-
className: "w-full bg-red-50 text-red-600 border border-red-200 rounded-lg p-3 text-sm animate-[fadeIn_0.2s_ease-out]",
|
|
47
|
-
children: error
|
|
48
|
-
}),
|
|
49
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
50
|
-
variant: "primary",
|
|
51
|
-
isLoading: isLoading,
|
|
52
|
-
isDisabled: otp.length !== 6,
|
|
53
|
-
onPress: handleSubmit,
|
|
54
|
-
children: "Verify"
|
|
55
|
-
}),
|
|
56
|
-
/*#__PURE__*/ _jsxs("div", {
|
|
57
|
-
className: "text-center",
|
|
58
|
-
children: [
|
|
59
|
-
/*#__PURE__*/ _jsx("p", {
|
|
60
|
-
className: "text-gray-600 text-sm mb-2",
|
|
61
|
-
children: "Didn't receive a code?"
|
|
62
|
-
}),
|
|
63
|
-
/*#__PURE__*/ _jsx("button", {
|
|
64
|
-
onClick: handleResendCode,
|
|
65
|
-
disabled: isResending || resendCooldown > 0,
|
|
66
|
-
className: "text-[#0071e3] font-medium text-sm hover:underline disabled:opacity-50 disabled:cursor-not-allowed",
|
|
67
|
-
children: isResending ? 'Sending...' : resendCooldown > 0 ? `Resend in ${resendCooldown}s` : 'Resend Code'
|
|
68
|
-
})
|
|
69
|
-
]
|
|
70
|
-
})
|
|
71
|
-
]
|
|
72
|
-
})
|
|
73
|
-
});
|
|
74
|
-
}
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { pluginConfig } from '../../config.js';
|
|
4
|
+
import VerifyOtpPageTailwind from './VerifyOtpPageTailwind.js';
|
|
5
|
+
import VerifyOtpPageHero from './VerifyOtpPageHero.js';
|
|
75
6
|
export default function VerifyOtpPage(props) {
|
|
76
|
-
return /*#__PURE__*/ _jsx(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
size: "lg"
|
|
81
|
-
})
|
|
82
|
-
}),
|
|
83
|
-
children: /*#__PURE__*/ _jsx(VerifyOtpContent, {
|
|
84
|
-
...props
|
|
85
|
-
})
|
|
7
|
+
return pluginConfig.style === 'hero-ui' ? /*#__PURE__*/ _jsx(VerifyOtpPageHero, {
|
|
8
|
+
...props
|
|
9
|
+
}) : /*#__PURE__*/ _jsx(VerifyOtpPageTailwind, {
|
|
10
|
+
...props
|
|
86
11
|
});
|
|
87
12
|
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import React, { Suspense } from 'react';
|
|
4
|
+
import { useSearchParams } from 'next/navigation';
|
|
5
|
+
import { Button, InputOtp, Spinner as HSpinner } from '@heroui/react';
|
|
6
|
+
import { Icon } from '@iconify/react';
|
|
7
|
+
import { motion } from 'framer-motion';
|
|
8
|
+
import { useVerifyOtpFlow } from '../../auth/application/hooks/useVerifyOtpFlow.js';
|
|
9
|
+
import { AuthLayout } from '../AuthLayout.js';
|
|
10
|
+
function VerifyOtpHeroContent({ loginUrl = '/login', logo, poweredBy, cardClassName, backgroundClass }) {
|
|
11
|
+
const searchParams = useSearchParams();
|
|
12
|
+
const email = searchParams.get('email') || '';
|
|
13
|
+
const purpose = searchParams.get('purpose') || 'login';
|
|
14
|
+
const redirectTo = searchParams.get('redirect') || '/';
|
|
15
|
+
const { otp, error, isLoading, isResending, resendCooldown, setOtp, handleSubmit, handleResendCode } = useVerifyOtpFlow({
|
|
16
|
+
email,
|
|
17
|
+
purpose,
|
|
18
|
+
redirectTo
|
|
19
|
+
});
|
|
20
|
+
if (!email) return null;
|
|
21
|
+
return /*#__PURE__*/ _jsx(AuthLayout, {
|
|
22
|
+
logo: logo,
|
|
23
|
+
title: purpose === 'password-reset' ? 'Reset Password' : 'Check Your Email',
|
|
24
|
+
subtitle: purpose === 'password-reset' ? 'Enter the code to reset your password' : 'We sent a 6-digit code to',
|
|
25
|
+
poweredBy: poweredBy,
|
|
26
|
+
cardClassName: cardClassName,
|
|
27
|
+
backgroundClass: backgroundClass,
|
|
28
|
+
footer: /*#__PURE__*/ _jsxs("a", {
|
|
29
|
+
href: loginUrl,
|
|
30
|
+
className: "text-sm text-gray-600 hover:text-gray-900 flex items-center gap-1",
|
|
31
|
+
children: [
|
|
32
|
+
/*#__PURE__*/ _jsx(Icon, {
|
|
33
|
+
icon: "lucide:arrow-left",
|
|
34
|
+
width: 16
|
|
35
|
+
}),
|
|
36
|
+
"Back to Login"
|
|
37
|
+
]
|
|
38
|
+
}),
|
|
39
|
+
children: /*#__PURE__*/ _jsxs("div", {
|
|
40
|
+
className: "flex flex-col items-center gap-4",
|
|
41
|
+
children: [
|
|
42
|
+
/*#__PURE__*/ _jsx("p", {
|
|
43
|
+
className: "text-gray-700 text-sm font-medium",
|
|
44
|
+
children: email
|
|
45
|
+
}),
|
|
46
|
+
/*#__PURE__*/ _jsx(InputOtp, {
|
|
47
|
+
length: 6,
|
|
48
|
+
value: otp,
|
|
49
|
+
onValueChange: setOtp,
|
|
50
|
+
isDisabled: isLoading,
|
|
51
|
+
autoFocus: true
|
|
52
|
+
}),
|
|
53
|
+
error && /*#__PURE__*/ _jsx(motion.div, {
|
|
54
|
+
className: "w-full bg-red-50 text-red-600 border border-red-200 rounded-lg p-3 text-sm",
|
|
55
|
+
initial: {
|
|
56
|
+
opacity: 0
|
|
57
|
+
},
|
|
58
|
+
animate: {
|
|
59
|
+
opacity: 1
|
|
60
|
+
},
|
|
61
|
+
children: error
|
|
62
|
+
}),
|
|
63
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
64
|
+
fullWidth: true,
|
|
65
|
+
size: "lg",
|
|
66
|
+
color: "primary",
|
|
67
|
+
isLoading: isLoading,
|
|
68
|
+
isDisabled: otp.length !== 6,
|
|
69
|
+
onPress: handleSubmit,
|
|
70
|
+
className: "h-12 font-semibold",
|
|
71
|
+
children: "Verify"
|
|
72
|
+
}),
|
|
73
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
74
|
+
className: "text-center",
|
|
75
|
+
children: [
|
|
76
|
+
/*#__PURE__*/ _jsx("p", {
|
|
77
|
+
className: "text-gray-600 text-sm mb-2",
|
|
78
|
+
children: "Didn't receive a code?"
|
|
79
|
+
}),
|
|
80
|
+
/*#__PURE__*/ _jsx("button", {
|
|
81
|
+
onClick: handleResendCode,
|
|
82
|
+
disabled: isResending || resendCooldown > 0,
|
|
83
|
+
className: "text-primary font-medium text-sm hover:underline disabled:opacity-50",
|
|
84
|
+
children: isResending ? 'Sending...' : resendCooldown > 0 ? `Resend in ${resendCooldown}s` : 'Resend Code'
|
|
85
|
+
})
|
|
86
|
+
]
|
|
87
|
+
})
|
|
88
|
+
]
|
|
89
|
+
})
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
export default function VerifyOtpPageHero(props) {
|
|
93
|
+
return /*#__PURE__*/ _jsx(Suspense, {
|
|
94
|
+
fallback: /*#__PURE__*/ _jsx("div", {
|
|
95
|
+
className: "min-h-screen flex items-center justify-center",
|
|
96
|
+
children: /*#__PURE__*/ _jsx(HSpinner, {
|
|
97
|
+
size: "lg"
|
|
98
|
+
})
|
|
99
|
+
}),
|
|
100
|
+
children: /*#__PURE__*/ _jsx(VerifyOtpHeroContent, {
|
|
101
|
+
...props
|
|
102
|
+
})
|
|
103
|
+
});
|
|
104
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import React, { Suspense } from 'react';
|
|
4
|
+
import { useSearchParams } from 'next/navigation';
|
|
5
|
+
import { Button, OtpInput, Spinner } from '../ui/index.js';
|
|
6
|
+
import { useVerifyOtpFlow } from '../../auth/application/hooks/useVerifyOtpFlow.js';
|
|
7
|
+
import { AuthLayout } from '../AuthLayout.js';
|
|
8
|
+
function VerifyOtpContent({ loginUrl = '/login', logo, poweredBy, cardClassName, backgroundClass }) {
|
|
9
|
+
const searchParams = useSearchParams();
|
|
10
|
+
const email = searchParams.get('email') || '';
|
|
11
|
+
const purpose = searchParams.get('purpose') || 'login';
|
|
12
|
+
const redirectTo = searchParams.get('redirect') || '/';
|
|
13
|
+
const { otp, error, isLoading, isResending, resendCooldown, setOtp, handleSubmit, handleResendCode } = useVerifyOtpFlow({
|
|
14
|
+
email,
|
|
15
|
+
purpose,
|
|
16
|
+
redirectTo
|
|
17
|
+
});
|
|
18
|
+
if (!email) return null;
|
|
19
|
+
const isPasswordReset = purpose === 'password-reset';
|
|
20
|
+
return /*#__PURE__*/ _jsx(AuthLayout, {
|
|
21
|
+
logo: logo,
|
|
22
|
+
title: isPasswordReset ? 'Reset Password' : 'Check Your Email',
|
|
23
|
+
subtitle: isPasswordReset ? 'Enter the code to reset your password' : 'We sent a 6-digit code to',
|
|
24
|
+
poweredBy: poweredBy,
|
|
25
|
+
cardClassName: cardClassName,
|
|
26
|
+
backgroundClass: backgroundClass,
|
|
27
|
+
footer: /*#__PURE__*/ _jsx("a", {
|
|
28
|
+
href: loginUrl,
|
|
29
|
+
className: "text-sm text-gray-600 hover:text-gray-900 flex items-center gap-1",
|
|
30
|
+
children: "← Back to Login"
|
|
31
|
+
}),
|
|
32
|
+
children: /*#__PURE__*/ _jsxs("div", {
|
|
33
|
+
className: "flex flex-col items-center gap-4",
|
|
34
|
+
children: [
|
|
35
|
+
/*#__PURE__*/ _jsx("p", {
|
|
36
|
+
className: "text-gray-700 text-sm font-medium",
|
|
37
|
+
children: email
|
|
38
|
+
}),
|
|
39
|
+
/*#__PURE__*/ _jsx(OtpInput, {
|
|
40
|
+
value: otp,
|
|
41
|
+
onValueChange: setOtp,
|
|
42
|
+
isDisabled: isLoading,
|
|
43
|
+
autoFocus: true
|
|
44
|
+
}),
|
|
45
|
+
error && /*#__PURE__*/ _jsx("div", {
|
|
46
|
+
className: "w-full bg-red-50 text-red-600 border border-red-200 rounded-lg p-3 text-sm animate-[fadeIn_0.2s_ease-out]",
|
|
47
|
+
children: error
|
|
48
|
+
}),
|
|
49
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
50
|
+
variant: "primary",
|
|
51
|
+
isLoading: isLoading,
|
|
52
|
+
isDisabled: otp.length !== 6,
|
|
53
|
+
onPress: handleSubmit,
|
|
54
|
+
children: "Verify"
|
|
55
|
+
}),
|
|
56
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
57
|
+
className: "text-center",
|
|
58
|
+
children: [
|
|
59
|
+
/*#__PURE__*/ _jsx("p", {
|
|
60
|
+
className: "text-gray-600 text-sm mb-2",
|
|
61
|
+
children: "Didn't receive a code?"
|
|
62
|
+
}),
|
|
63
|
+
/*#__PURE__*/ _jsx("button", {
|
|
64
|
+
onClick: handleResendCode,
|
|
65
|
+
disabled: isResending || resendCooldown > 0,
|
|
66
|
+
className: "text-[#0071e3] font-medium text-sm hover:underline disabled:opacity-50 disabled:cursor-not-allowed",
|
|
67
|
+
children: isResending ? 'Sending...' : resendCooldown > 0 ? `Resend in ${resendCooldown}s` : 'Resend Code'
|
|
68
|
+
})
|
|
69
|
+
]
|
|
70
|
+
})
|
|
71
|
+
]
|
|
72
|
+
})
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
export default function VerifyOtpPage(props) {
|
|
76
|
+
return /*#__PURE__*/ _jsx(Suspense, {
|
|
77
|
+
fallback: /*#__PURE__*/ _jsx("div", {
|
|
78
|
+
className: "min-h-screen flex items-center justify-center",
|
|
79
|
+
children: /*#__PURE__*/ _jsx(Spinner, {
|
|
80
|
+
size: "lg"
|
|
81
|
+
})
|
|
82
|
+
}),
|
|
83
|
+
children: /*#__PURE__*/ _jsx(VerifyOtpContent, {
|
|
84
|
+
...props
|
|
85
|
+
})
|
|
86
|
+
});
|
|
87
|
+
}
|
package/dist/config.d.ts
ADDED
package/dist/config.js
ADDED
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { Config } from 'payload';
|
|
2
|
+
import { pluginConfig, type AuthStyle } from './config.js';
|
|
2
3
|
export interface AuthLoginPluginOptions {
|
|
3
|
-
/** Enable/disable the plugin */
|
|
4
4
|
enabled?: boolean;
|
|
5
|
-
/** Project name used in emails */
|
|
6
5
|
projectName?: string;
|
|
7
|
-
/** Contact email used in email footers */
|
|
8
6
|
contactEmail?: string;
|
|
9
|
-
/** Domain for links in emails */
|
|
10
7
|
domain?: string;
|
|
8
|
+
/** UI style for auth pages: 'tailwind' (default) or 'hero-ui' */
|
|
9
|
+
style?: AuthStyle;
|
|
11
10
|
}
|
|
12
11
|
export declare const authLoginPlugin: (options?: AuthLoginPluginOptions) => (config: Config) => Config;
|
|
12
|
+
export { pluginConfig };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { authEndpoints } from './endpoints/authEndpoints.js';
|
|
2
|
+
import { pluginConfig } from './config.js';
|
|
2
3
|
export const authLoginPlugin = (options = {})=>(config)=>{
|
|
3
4
|
if (options.enabled === false) return config;
|
|
5
|
+
// Set global style config — all page components read this at render time
|
|
6
|
+
pluginConfig.style = options.style || 'tailwind';
|
|
4
7
|
// Register auth API endpoints
|
|
5
8
|
config.endpoints = [
|
|
6
9
|
...config.endpoints || [],
|
|
@@ -10,7 +13,8 @@ export const authLoginPlugin = (options = {})=>(config)=>{
|
|
|
10
13
|
const incomingOnInit = config.onInit;
|
|
11
14
|
config.onInit = async (payload)=>{
|
|
12
15
|
if (incomingOnInit) await incomingOnInit(payload);
|
|
13
|
-
payload.logger.info(`[auth-login]
|
|
16
|
+
payload.logger.info(`[auth-login] Initialized (style: ${pluginConfig.style}) for ${options.projectName || 'project'}`);
|
|
14
17
|
};
|
|
15
18
|
return config;
|
|
16
19
|
};
|
|
20
|
+
export { pluginConfig };
|