payload-better-auth 1.0.7 → 1.0.8
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/BetterAuthLoginServer.js +15 -1
- package/dist/components/BetterAuthLoginServer.js.map +1 -1
- package/dist/components/EmailPasswordFormClient.d.ts +2 -1
- package/dist/components/EmailPasswordFormClient.js +2 -2
- package/dist/components/EmailPasswordFormClient.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { headers } from 'next/headers.js';
|
|
2
3
|
import { EmailPasswordFormClient } from './EmailPasswordFormClient.js';
|
|
4
|
+
async function getPayloadBaseUrl() {
|
|
5
|
+
const h = await headers();
|
|
6
|
+
// Prefer proxy-aware headers (Vercel, reverse proxies)
|
|
7
|
+
const proto = h.get('x-forwarded-proto') ?? 'http';
|
|
8
|
+
const host = h.get('x-forwarded-host') ?? h.get('host') // fallback for local dev
|
|
9
|
+
;
|
|
10
|
+
if (!host) {
|
|
11
|
+
return '';
|
|
12
|
+
} // or throw, depending on your needs
|
|
13
|
+
return `${proto}://${host}`;
|
|
14
|
+
}
|
|
3
15
|
export async function fetchAuthMethods({ additionalHeaders, betterAuthBaseUrl }) {
|
|
4
16
|
const headers = new Headers(additionalHeaders);
|
|
5
17
|
headers.append('Content-Type', 'application/json');
|
|
@@ -29,6 +41,7 @@ export async function BetterAuthLoginServer({ authClientOptions }) {
|
|
|
29
41
|
additionalHeaders: authClientOptions.fetchOptions?.headers,
|
|
30
42
|
betterAuthBaseUrl: authClientOptions.baseURL
|
|
31
43
|
});
|
|
44
|
+
const payloadBaseUrl = await getPayloadBaseUrl();
|
|
32
45
|
return /*#__PURE__*/ _jsx("div", {
|
|
33
46
|
style: {
|
|
34
47
|
alignItems: 'center',
|
|
@@ -57,7 +70,8 @@ export async function BetterAuthLoginServer({ authClientOptions }) {
|
|
|
57
70
|
}),
|
|
58
71
|
authMethods.data?.some((m)=>m.method === 'emailAndPassword' || m.method === 'magicLink') && /*#__PURE__*/ _jsx(EmailPasswordFormClient, {
|
|
59
72
|
authClientOptions: authClientOptions,
|
|
60
|
-
authMethods: authMethods.data
|
|
73
|
+
authMethods: authMethods.data,
|
|
74
|
+
payloadBaseUrl: payloadBaseUrl
|
|
61
75
|
}),
|
|
62
76
|
authMethods.data?.length === 0 && /*#__PURE__*/ _jsxs("div", {
|
|
63
77
|
style: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/BetterAuthLoginServer.tsx"],"sourcesContent":["import type { ClientOptions } from 'better-auth'\nimport type React from 'react'\nimport type { AuthMethod } from 'src/better-auth/helpers.js'\n\nimport { EmailPasswordFormClient } from './EmailPasswordFormClient.js'\n\nexport async function fetchAuthMethods({\n additionalHeaders,\n betterAuthBaseUrl,\n}: {\n additionalHeaders?: HeadersInit\n betterAuthBaseUrl: string\n}): Promise<{ data: AuthMethod[]; error: null } | { data: null; error: Error }> {\n const headers = new Headers(additionalHeaders)\n headers.append('Content-Type', 'application/json')\n try {\n const response = await fetch(`${betterAuthBaseUrl}/api/auth/auth/methods`, {\n headers,\n method: 'GET',\n })\n\n if (!response.ok) {\n throw new Error(`Failed to fetch auth methods: ${response.status}`)\n }\n\n const data = await response.json()\n return { data, error: null } as { data: AuthMethod[]; error: null }\n } catch (error) {\n console.error('Error fetching auth methods:', error)\n return { data: null, error: error as Error }\n }\n}\n\nexport type BetterAuthLoginServerProps = {\n authClientOptions: { baseURL: string } & Omit<ClientOptions, 'baseURL'>\n}\n\nexport async function BetterAuthLoginServer({ authClientOptions }: BetterAuthLoginServerProps) {\n const authMethods = await fetchAuthMethods({\n additionalHeaders: authClientOptions.fetchOptions?.headers,\n betterAuthBaseUrl: authClientOptions.baseURL,\n })\n\n return (\n <div\n style={{\n alignItems: 'center',\n display: 'flex',\n justifyContent: 'center',\n }}\n >\n <div\n style={{\n background: 'white',\n borderRadius: '8px',\n boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)',\n maxWidth: '400px',\n padding: '2rem',\n width: '100%',\n }}\n >\n <h2\n style={{\n color: '#333',\n fontSize: '1.5rem',\n fontWeight: '600',\n marginBottom: '2rem',\n textAlign: 'center',\n }}\n >\n Sign In to Admin\n </h2>\n\n {authMethods.data?.some(\n (m) => m.method === 'emailAndPassword' || m.method === 'magicLink',\n ) && (\n <EmailPasswordFormClient\n authClientOptions={authClientOptions}\n authMethods={authMethods.data}\n />\n )}\n {authMethods.data?.length === 0 && (\n <div\n style={{\n color: '#666',\n padding: '2rem',\n textAlign: 'center',\n }}\n >\n <p>No authentication methods are currently available.</p>\n <p style={{ fontSize: '0.875rem', marginTop: '1rem' }}>\n Please contact your administrator.\n </p>\n </div>\n )}\n {authMethods.error && (\n <div\n style={{\n color: '#666',\n padding: '2rem',\n textAlign: 'center',\n }}\n >\n <p>Couldn't fetch authentication methods from better-auth</p>\n <p style={{ fontSize: '0.875rem', marginTop: '1rem' }}>\n Please contact your administrator.\n </p>\n </div>\n )}\n </div>\n </div>\n )\n}\n"],"names":["EmailPasswordFormClient","fetchAuthMethods","additionalHeaders","betterAuthBaseUrl","
|
|
1
|
+
{"version":3,"sources":["../../src/components/BetterAuthLoginServer.tsx"],"sourcesContent":["import type { ClientOptions } from 'better-auth'\nimport type React from 'react'\nimport type { AuthMethod } from 'src/better-auth/helpers.js'\n\nimport { headers } from 'next/headers.js'\n\nimport { EmailPasswordFormClient } from './EmailPasswordFormClient.js'\n\nasync function getPayloadBaseUrl() {\n const h = await headers()\n // Prefer proxy-aware headers (Vercel, reverse proxies)\n const proto = h.get('x-forwarded-proto') ?? 'http'\n const host = h.get('x-forwarded-host') ?? h.get('host') // fallback for local dev\n if (!host) {\n return ''\n } // or throw, depending on your needs\n return `${proto}://${host}`\n}\n\nexport async function fetchAuthMethods({\n additionalHeaders,\n betterAuthBaseUrl,\n}: {\n additionalHeaders?: HeadersInit\n betterAuthBaseUrl: string\n}): Promise<{ data: AuthMethod[]; error: null } | { data: null; error: Error }> {\n const headers = new Headers(additionalHeaders)\n headers.append('Content-Type', 'application/json')\n try {\n const response = await fetch(`${betterAuthBaseUrl}/api/auth/auth/methods`, {\n headers,\n method: 'GET',\n })\n\n if (!response.ok) {\n throw new Error(`Failed to fetch auth methods: ${response.status}`)\n }\n\n const data = await response.json()\n return { data, error: null } as { data: AuthMethod[]; error: null }\n } catch (error) {\n console.error('Error fetching auth methods:', error)\n return { data: null, error: error as Error }\n }\n}\n\nexport type BetterAuthLoginServerProps = {\n authClientOptions: { baseURL: string } & Omit<ClientOptions, 'baseURL'>\n}\n\nexport async function BetterAuthLoginServer({ authClientOptions }: BetterAuthLoginServerProps) {\n const authMethods = await fetchAuthMethods({\n additionalHeaders: authClientOptions.fetchOptions?.headers,\n betterAuthBaseUrl: authClientOptions.baseURL,\n })\n const payloadBaseUrl = await getPayloadBaseUrl()\n\n return (\n <div\n style={{\n alignItems: 'center',\n display: 'flex',\n justifyContent: 'center',\n }}\n >\n <div\n style={{\n background: 'white',\n borderRadius: '8px',\n boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)',\n maxWidth: '400px',\n padding: '2rem',\n width: '100%',\n }}\n >\n <h2\n style={{\n color: '#333',\n fontSize: '1.5rem',\n fontWeight: '600',\n marginBottom: '2rem',\n textAlign: 'center',\n }}\n >\n Sign In to Admin\n </h2>\n\n {authMethods.data?.some(\n (m) => m.method === 'emailAndPassword' || m.method === 'magicLink',\n ) && (\n <EmailPasswordFormClient\n authClientOptions={authClientOptions}\n authMethods={authMethods.data}\n payloadBaseUrl={payloadBaseUrl}\n />\n )}\n {authMethods.data?.length === 0 && (\n <div\n style={{\n color: '#666',\n padding: '2rem',\n textAlign: 'center',\n }}\n >\n <p>No authentication methods are currently available.</p>\n <p style={{ fontSize: '0.875rem', marginTop: '1rem' }}>\n Please contact your administrator.\n </p>\n </div>\n )}\n {authMethods.error && (\n <div\n style={{\n color: '#666',\n padding: '2rem',\n textAlign: 'center',\n }}\n >\n <p>Couldn't fetch authentication methods from better-auth</p>\n <p style={{ fontSize: '0.875rem', marginTop: '1rem' }}>\n Please contact your administrator.\n </p>\n </div>\n )}\n </div>\n </div>\n )\n}\n"],"names":["headers","EmailPasswordFormClient","getPayloadBaseUrl","h","proto","get","host","fetchAuthMethods","additionalHeaders","betterAuthBaseUrl","Headers","append","response","fetch","method","ok","Error","status","data","json","error","console","BetterAuthLoginServer","authClientOptions","authMethods","fetchOptions","baseURL","payloadBaseUrl","div","style","alignItems","display","justifyContent","background","borderRadius","boxShadow","maxWidth","padding","width","h2","color","fontSize","fontWeight","marginBottom","textAlign","some","m","length","p","marginTop"],"mappings":";AAIA,SAASA,OAAO,QAAQ,kBAAiB;AAEzC,SAASC,uBAAuB,QAAQ,+BAA8B;AAEtE,eAAeC;IACb,MAAMC,IAAI,MAAMH;IAChB,uDAAuD;IACvD,MAAMI,QAAQD,EAAEE,GAAG,CAAC,wBAAwB;IAC5C,MAAMC,OAAOH,EAAEE,GAAG,CAAC,uBAAuBF,EAAEE,GAAG,CAAC,QAAQ,yBAAyB;;IACjF,IAAI,CAACC,MAAM;QACT,OAAO;IACT,EAAE,oCAAoC;IACtC,OAAO,GAAGF,MAAM,GAAG,EAAEE,MAAM;AAC7B;AAEA,OAAO,eAAeC,iBAAiB,EACrCC,iBAAiB,EACjBC,iBAAiB,EAIlB;IACC,MAAMT,UAAU,IAAIU,QAAQF;IAC5BR,QAAQW,MAAM,CAAC,gBAAgB;IAC/B,IAAI;QACF,MAAMC,WAAW,MAAMC,MAAM,GAAGJ,kBAAkB,sBAAsB,CAAC,EAAE;YACzET;YACAc,QAAQ;QACV;QAEA,IAAI,CAACF,SAASG,EAAE,EAAE;YAChB,MAAM,IAAIC,MAAM,CAAC,8BAA8B,EAAEJ,SAASK,MAAM,EAAE;QACpE;QAEA,MAAMC,OAAO,MAAMN,SAASO,IAAI;QAChC,OAAO;YAAED;YAAME,OAAO;QAAK;IAC7B,EAAE,OAAOA,OAAO;QACdC,QAAQD,KAAK,CAAC,gCAAgCA;QAC9C,OAAO;YAAEF,MAAM;YAAME,OAAOA;QAAe;IAC7C;AACF;AAMA,OAAO,eAAeE,sBAAsB,EAAEC,iBAAiB,EAA8B;IAC3F,MAAMC,cAAc,MAAMjB,iBAAiB;QACzCC,mBAAmBe,kBAAkBE,YAAY,EAAEzB;QACnDS,mBAAmBc,kBAAkBG,OAAO;IAC9C;IACA,MAAMC,iBAAiB,MAAMzB;IAE7B,qBACE,KAAC0B;QACCC,OAAO;YACLC,YAAY;YACZC,SAAS;YACTC,gBAAgB;QAClB;kBAEA,cAAA,MAACJ;YACCC,OAAO;gBACLI,YAAY;gBACZC,cAAc;gBACdC,WAAW;gBACXC,UAAU;gBACVC,SAAS;gBACTC,OAAO;YACT;;8BAEA,KAACC;oBACCV,OAAO;wBACLW,OAAO;wBACPC,UAAU;wBACVC,YAAY;wBACZC,cAAc;wBACdC,WAAW;oBACb;8BACD;;gBAIApB,YAAYN,IAAI,EAAE2B,KACjB,CAACC,IAAMA,EAAEhC,MAAM,KAAK,sBAAsBgC,EAAEhC,MAAM,KAAK,8BAEvD,KAACb;oBACCsB,mBAAmBA;oBACnBC,aAAaA,YAAYN,IAAI;oBAC7BS,gBAAgBA;;gBAGnBH,YAAYN,IAAI,EAAE6B,WAAW,mBAC5B,MAACnB;oBACCC,OAAO;wBACLW,OAAO;wBACPH,SAAS;wBACTO,WAAW;oBACb;;sCAEA,KAACI;sCAAE;;sCACH,KAACA;4BAAEnB,OAAO;gCAAEY,UAAU;gCAAYQ,WAAW;4BAAO;sCAAG;;;;gBAK1DzB,YAAYJ,KAAK,kBAChB,MAACQ;oBACCC,OAAO;wBACLW,OAAO;wBACPH,SAAS;wBACTO,WAAW;oBACb;;sCAEA,KAACI;sCAAE;;sCACH,KAACA;4BAAEnB,OAAO;gCAAEY,UAAU;gCAAYQ,WAAW;4BAAO;sCAAG;;;;;;;AAQnE"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { default as React } from 'react';
|
|
2
2
|
import type { AuthMethod } from 'src/better-auth/helpers.js';
|
|
3
3
|
import { createAuthClient } from 'better-auth/react';
|
|
4
|
-
export declare function EmailPasswordFormClient({ authClientOptions, authMethods, }: {
|
|
4
|
+
export declare function EmailPasswordFormClient({ authClientOptions, authMethods, payloadBaseUrl, }: {
|
|
5
5
|
authClientOptions: Parameters<typeof createAuthClient>['0'];
|
|
6
6
|
authMethods: AuthMethod[];
|
|
7
|
+
payloadBaseUrl: string;
|
|
7
8
|
}): React.JSX.Element;
|
|
@@ -5,7 +5,7 @@ import { magicLinkClient } from 'better-auth/client/plugins';
|
|
|
5
5
|
import { createAuthClient } from 'better-auth/react';
|
|
6
6
|
import { useRouter } from 'next/navigation.js';
|
|
7
7
|
import { useState } from 'react';
|
|
8
|
-
export function EmailPasswordFormClient({ authClientOptions, authMethods }) {
|
|
8
|
+
export function EmailPasswordFormClient({ authClientOptions, authMethods, payloadBaseUrl }) {
|
|
9
9
|
const authClient = createAuthClient({
|
|
10
10
|
...authClientOptions,
|
|
11
11
|
plugins: [
|
|
@@ -88,7 +88,7 @@ export function EmailPasswordFormClient({ authClientOptions, authMethods }) {
|
|
|
88
88
|
}
|
|
89
89
|
} else if (withMagicLink && passwordValue === '') {
|
|
90
90
|
const result = await authClient.signIn.magicLink({
|
|
91
|
-
callbackURL:
|
|
91
|
+
callbackURL: `${payloadBaseUrl}/admin`,
|
|
92
92
|
email: String(emailValue || '')
|
|
93
93
|
});
|
|
94
94
|
if (result.error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/EmailPasswordFormClient.tsx"],"sourcesContent":["'use client'\n\nimport type { ChangeEvent, default as React } from 'react'\nimport type { AuthMethod } from 'src/better-auth/helpers.js'\n\nimport { Button, FieldLabel, TextInput } from '@payloadcms/ui'\nimport { magicLinkClient } from 'better-auth/client/plugins'\nimport { createAuthClient } from 'better-auth/react'\nimport { useRouter } from 'next/navigation.js'\nimport { useState } from 'react'\n\ninterface FormErrors {\n email?: string\n general?: string\n password?: string\n}\n\nexport function EmailPasswordFormClient({\n authClientOptions,\n authMethods,\n}: {\n authClientOptions: Parameters<typeof createAuthClient>['0']\n authMethods: AuthMethod[]\n}) {\n const authClient = createAuthClient({\n ...authClientOptions,\n plugins: [\n ...(authClientOptions?.plugins?.filter((p) => p.id !== 'magic-link') ?? []),\n magicLinkClient(),\n ],\n })\n const router = useRouter()\n const [errors, setErrors] = useState<FormErrors>({})\n const [isLoading, setIsLoading] = useState(false)\n\n // Use useField hooks for each input to get proper setValue functions\n const [emailValue, setEmailValue] = useState('')\n const [passwordValue, setPasswordValue] = useState('')\n\n const withEmailAndPassword = authMethods.find((m) => m.method === 'emailAndPassword')\n const withMagicLink = authMethods.find((m) => m.method === 'magicLink')\n\n if (!withEmailAndPassword && !withMagicLink) {\n throw new Error(\"This Form can't render with neither email nor magicLink activated.\")\n }\n\n const handleEmailChange = (event: ChangeEvent<HTMLInputElement>) => {\n setEmailValue(event.target.value)\n // Clear field-specific error when user starts typing\n if (errors.email) {\n setErrors((prev) => ({ ...prev, email: undefined }))\n }\n }\n\n const handlePasswordChange = (event: ChangeEvent<HTMLInputElement>) => {\n setPasswordValue(event.target.value)\n // Clear field-specific error when user starts typing\n if (errors.password) {\n setErrors((prev) => ({ ...prev, password: undefined }))\n }\n }\n\n const validateForm = (): boolean => {\n const newErrors: FormErrors = {}\n const email = String(emailValue || '').trim()\n const password = String(passwordValue || '').trim()\n\n if (!email) {\n newErrors.email = 'Email is required'\n } else if (!/^[^\\s@]+@[^\\s@][^\\s.@]*\\.[^\\s@]+$/.test(email)) {\n newErrors.email = 'Please enter a valid email address'\n }\n\n if (withEmailAndPassword && !withMagicLink) {\n if (!password) {\n newErrors.password = 'Password is required'\n // TODO: verify if minPasswordLength is also set if not actively specified\n } else if (password.length < withEmailAndPassword.options.minPasswordLength) {\n newErrors.password = `Password must be at least ${withEmailAndPassword.options.minPasswordLength} characters`\n }\n }\n\n setErrors(newErrors)\n return Object.keys(newErrors).length === 0\n }\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n\n if (!validateForm()) {\n return\n }\n\n setIsLoading(true)\n setErrors({})\n\n try {\n if (withEmailAndPassword && passwordValue !== '') {\n const result = await authClient.signIn.email({\n email: String(emailValue || ''),\n password: String(passwordValue || ''),\n })\n\n if (result.error) {\n setErrors({\n general: result.error.message || 'Sign in failed. Please check your credentials.',\n })\n } else {\n // Successful sign in - redirect to admin\n router.push('/admin')\n router.refresh()\n }\n } else if (withMagicLink && passwordValue === '') {\n const result = await authClient.signIn.magicLink({\n callbackURL: `/admin`,\n email: String(emailValue || ''),\n })\n\n if (result.error) {\n setErrors({\n general: result.error.message || 'Sign in failed. Please check your credentials.',\n })\n } else {\n // Successful sign in - redirect to admin\n router.push('/admin/auth/verify-email')\n router.refresh()\n }\n }\n } catch (error) {\n setErrors({\n general: (error as Error).message,\n })\n } finally {\n setIsLoading(false)\n }\n }\n\n const errorStyle = {\n color: '#dc2626',\n fontSize: '0.875rem',\n marginTop: '0.25rem',\n }\n\n return (\n <form className=\"email-password-form\" onSubmit={handleSubmit}>\n <div className=\"form-field\" style={{ marginBottom: '1.5rem' }}>\n <FieldLabel htmlFor=\"email\" label=\"Email\" required />\n <TextInput\n onChange={handleEmailChange}\n path=\"email\"\n readOnly={isLoading}\n required\n value={emailValue || ''}\n />\n {errors.email && (\n <div className=\"field-error\" style={errorStyle}>\n {errors.email}\n </div>\n )}\n </div>\n\n <div className=\"form-field\" style={{ marginBottom: '1.5rem' }}>\n <FieldLabel\n htmlFor=\"password\"\n label={`Password ${withMagicLink && '(Optional)'}`}\n required={!withMagicLink}\n />\n <TextInput\n onChange={handlePasswordChange}\n path=\"password\"\n readOnly={isLoading}\n required={!withMagicLink}\n value={passwordValue || ''}\n />\n {errors.password && (\n <div className=\"field-error\" style={errorStyle}>\n {errors.password}\n </div>\n )}\n </div>\n\n {errors.general && (\n <div\n className=\"general-error\"\n style={{\n ...errorStyle,\n backgroundColor: '#fef2f2',\n border: '1px solid #fecaca',\n borderRadius: '0.375rem',\n marginBottom: '1rem',\n padding: '0.75rem',\n }}\n >\n {errors.general}\n </div>\n )}\n\n <Button buttonStyle=\"primary\" disabled={isLoading} size=\"large\" type=\"submit\">\n {isLoading ? 'Signing In...' : 'Sign In'}\n </Button>\n </form>\n )\n}\n"],"names":["Button","FieldLabel","TextInput","magicLinkClient","createAuthClient","useRouter","useState","EmailPasswordFormClient","authClientOptions","authMethods","authClient","plugins","filter","p","id","router","errors","setErrors","isLoading","setIsLoading","emailValue","setEmailValue","passwordValue","setPasswordValue","withEmailAndPassword","find","m","method","withMagicLink","Error","handleEmailChange","event","target","value","email","prev","undefined","handlePasswordChange","password","validateForm","newErrors","String","trim","test","length","options","minPasswordLength","Object","keys","handleSubmit","e","preventDefault","result","signIn","error","general","message","push","refresh","magicLink","callbackURL","errorStyle","color","fontSize","marginTop","form","className","onSubmit","div","style","marginBottom","htmlFor","label","required","onChange","path","readOnly","backgroundColor","border","borderRadius","padding","buttonStyle","disabled","size","type"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/components/EmailPasswordFormClient.tsx"],"sourcesContent":["'use client'\n\nimport type { ChangeEvent, default as React } from 'react'\nimport type { AuthMethod } from 'src/better-auth/helpers.js'\n\nimport { Button, FieldLabel, TextInput } from '@payloadcms/ui'\nimport { magicLinkClient } from 'better-auth/client/plugins'\nimport { createAuthClient } from 'better-auth/react'\nimport { useRouter } from 'next/navigation.js'\nimport { useState } from 'react'\n\ninterface FormErrors {\n email?: string\n general?: string\n password?: string\n}\n\nexport function EmailPasswordFormClient({\n authClientOptions,\n authMethods,\n payloadBaseUrl,\n}: {\n authClientOptions: Parameters<typeof createAuthClient>['0']\n authMethods: AuthMethod[]\n payloadBaseUrl: string\n}) {\n const authClient = createAuthClient({\n ...authClientOptions,\n plugins: [\n ...(authClientOptions?.plugins?.filter((p) => p.id !== 'magic-link') ?? []),\n magicLinkClient(),\n ],\n })\n const router = useRouter()\n const [errors, setErrors] = useState<FormErrors>({})\n const [isLoading, setIsLoading] = useState(false)\n\n // Use useField hooks for each input to get proper setValue functions\n const [emailValue, setEmailValue] = useState('')\n const [passwordValue, setPasswordValue] = useState('')\n\n const withEmailAndPassword = authMethods.find((m) => m.method === 'emailAndPassword')\n const withMagicLink = authMethods.find((m) => m.method === 'magicLink')\n\n if (!withEmailAndPassword && !withMagicLink) {\n throw new Error(\"This Form can't render with neither email nor magicLink activated.\")\n }\n\n const handleEmailChange = (event: ChangeEvent<HTMLInputElement>) => {\n setEmailValue(event.target.value)\n // Clear field-specific error when user starts typing\n if (errors.email) {\n setErrors((prev) => ({ ...prev, email: undefined }))\n }\n }\n\n const handlePasswordChange = (event: ChangeEvent<HTMLInputElement>) => {\n setPasswordValue(event.target.value)\n // Clear field-specific error when user starts typing\n if (errors.password) {\n setErrors((prev) => ({ ...prev, password: undefined }))\n }\n }\n\n const validateForm = (): boolean => {\n const newErrors: FormErrors = {}\n const email = String(emailValue || '').trim()\n const password = String(passwordValue || '').trim()\n\n if (!email) {\n newErrors.email = 'Email is required'\n } else if (!/^[^\\s@]+@[^\\s@][^\\s.@]*\\.[^\\s@]+$/.test(email)) {\n newErrors.email = 'Please enter a valid email address'\n }\n\n if (withEmailAndPassword && !withMagicLink) {\n if (!password) {\n newErrors.password = 'Password is required'\n // TODO: verify if minPasswordLength is also set if not actively specified\n } else if (password.length < withEmailAndPassword.options.minPasswordLength) {\n newErrors.password = `Password must be at least ${withEmailAndPassword.options.minPasswordLength} characters`\n }\n }\n\n setErrors(newErrors)\n return Object.keys(newErrors).length === 0\n }\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n\n if (!validateForm()) {\n return\n }\n\n setIsLoading(true)\n setErrors({})\n\n try {\n if (withEmailAndPassword && passwordValue !== '') {\n const result = await authClient.signIn.email({\n email: String(emailValue || ''),\n password: String(passwordValue || ''),\n })\n\n if (result.error) {\n setErrors({\n general: result.error.message || 'Sign in failed. Please check your credentials.',\n })\n } else {\n // Successful sign in - redirect to admin\n router.push('/admin')\n router.refresh()\n }\n } else if (withMagicLink && passwordValue === '') {\n const result = await authClient.signIn.magicLink({\n callbackURL: `${payloadBaseUrl}/admin`,\n email: String(emailValue || ''),\n })\n\n if (result.error) {\n setErrors({\n general: result.error.message || 'Sign in failed. Please check your credentials.',\n })\n } else {\n // Successful sign in - redirect to admin\n router.push('/admin/auth/verify-email')\n router.refresh()\n }\n }\n } catch (error) {\n setErrors({\n general: (error as Error).message,\n })\n } finally {\n setIsLoading(false)\n }\n }\n\n const errorStyle = {\n color: '#dc2626',\n fontSize: '0.875rem',\n marginTop: '0.25rem',\n }\n\n return (\n <form className=\"email-password-form\" onSubmit={handleSubmit}>\n <div className=\"form-field\" style={{ marginBottom: '1.5rem' }}>\n <FieldLabel htmlFor=\"email\" label=\"Email\" required />\n <TextInput\n onChange={handleEmailChange}\n path=\"email\"\n readOnly={isLoading}\n required\n value={emailValue || ''}\n />\n {errors.email && (\n <div className=\"field-error\" style={errorStyle}>\n {errors.email}\n </div>\n )}\n </div>\n\n <div className=\"form-field\" style={{ marginBottom: '1.5rem' }}>\n <FieldLabel\n htmlFor=\"password\"\n label={`Password ${withMagicLink && '(Optional)'}`}\n required={!withMagicLink}\n />\n <TextInput\n onChange={handlePasswordChange}\n path=\"password\"\n readOnly={isLoading}\n required={!withMagicLink}\n value={passwordValue || ''}\n />\n {errors.password && (\n <div className=\"field-error\" style={errorStyle}>\n {errors.password}\n </div>\n )}\n </div>\n\n {errors.general && (\n <div\n className=\"general-error\"\n style={{\n ...errorStyle,\n backgroundColor: '#fef2f2',\n border: '1px solid #fecaca',\n borderRadius: '0.375rem',\n marginBottom: '1rem',\n padding: '0.75rem',\n }}\n >\n {errors.general}\n </div>\n )}\n\n <Button buttonStyle=\"primary\" disabled={isLoading} size=\"large\" type=\"submit\">\n {isLoading ? 'Signing In...' : 'Sign In'}\n </Button>\n </form>\n )\n}\n"],"names":["Button","FieldLabel","TextInput","magicLinkClient","createAuthClient","useRouter","useState","EmailPasswordFormClient","authClientOptions","authMethods","payloadBaseUrl","authClient","plugins","filter","p","id","router","errors","setErrors","isLoading","setIsLoading","emailValue","setEmailValue","passwordValue","setPasswordValue","withEmailAndPassword","find","m","method","withMagicLink","Error","handleEmailChange","event","target","value","email","prev","undefined","handlePasswordChange","password","validateForm","newErrors","String","trim","test","length","options","minPasswordLength","Object","keys","handleSubmit","e","preventDefault","result","signIn","error","general","message","push","refresh","magicLink","callbackURL","errorStyle","color","fontSize","marginTop","form","className","onSubmit","div","style","marginBottom","htmlFor","label","required","onChange","path","readOnly","backgroundColor","border","borderRadius","padding","buttonStyle","disabled","size","type"],"mappings":"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"}
|