@delmaredigital/payload-better-auth 0.3.8 → 0.3.10

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.
Files changed (206) hide show
  1. package/dist/adapter/collections.d.ts +0 -1
  2. package/dist/adapter/collections.js +0 -2
  3. package/dist/adapter/index.d.ts +0 -1
  4. package/dist/adapter/index.js +0 -2
  5. package/dist/components/BeforeLogin.d.ts +0 -1
  6. package/dist/components/BeforeLogin.js +0 -2
  7. package/dist/components/LoginView.d.ts +0 -1
  8. package/dist/components/LoginView.js +0 -2
  9. package/dist/components/LoginViewWrapper.d.ts +0 -1
  10. package/dist/components/LoginViewWrapper.js +0 -2
  11. package/dist/components/LogoutButton.d.ts +0 -1
  12. package/dist/components/LogoutButton.js +0 -2
  13. package/dist/components/PasskeyRegisterButton.d.ts +0 -1
  14. package/dist/components/PasskeyRegisterButton.js +0 -2
  15. package/dist/components/PasskeySignInButton.d.ts +0 -1
  16. package/dist/components/PasskeySignInButton.js +0 -2
  17. package/dist/components/auth/ForgotPasswordView.d.ts +0 -1
  18. package/dist/components/auth/ForgotPasswordView.js +0 -2
  19. package/dist/components/auth/ResetPasswordView.d.ts +0 -1
  20. package/dist/components/auth/ResetPasswordView.js +0 -2
  21. package/dist/components/auth/index.d.ts +0 -1
  22. package/dist/components/auth/index.js +0 -2
  23. package/dist/components/management/ApiKeysManagementClient.d.ts +0 -1
  24. package/dist/components/management/ApiKeysManagementClient.js +0 -2
  25. package/dist/components/management/PasskeysManagementClient.d.ts +0 -1
  26. package/dist/components/management/PasskeysManagementClient.js +0 -2
  27. package/dist/components/management/SecurityNavLinks.d.ts +0 -1
  28. package/dist/components/management/SecurityNavLinks.js +0 -2
  29. package/dist/components/management/TwoFactorManagementClient.d.ts +0 -1
  30. package/dist/components/management/TwoFactorManagementClient.js +0 -2
  31. package/dist/components/management/index.d.ts +0 -1
  32. package/dist/components/management/index.js +0 -2
  33. package/dist/components/management/views/ApiKeysView.d.ts +0 -1
  34. package/dist/components/management/views/ApiKeysView.js +0 -2
  35. package/dist/components/management/views/PasskeysView.d.ts +0 -1
  36. package/dist/components/management/views/PasskeysView.js +0 -2
  37. package/dist/components/management/views/TwoFactorView.d.ts +0 -1
  38. package/dist/components/management/views/TwoFactorView.js +0 -2
  39. package/dist/components/management/views/index.d.ts +0 -1
  40. package/dist/components/management/views/index.js +0 -2
  41. package/dist/components/twoFactor/TwoFactorSetupView.d.ts +0 -1
  42. package/dist/components/twoFactor/TwoFactorSetupView.js +0 -2
  43. package/dist/components/twoFactor/TwoFactorVerifyView.d.ts +0 -1
  44. package/dist/components/twoFactor/TwoFactorVerifyView.js +0 -2
  45. package/dist/components/twoFactor/index.d.ts +0 -1
  46. package/dist/components/twoFactor/index.js +0 -2
  47. package/dist/exports/client.d.ts +0 -1
  48. package/dist/exports/client.js +0 -2
  49. package/dist/exports/components.d.ts +0 -1
  50. package/dist/exports/components.js +0 -2
  51. package/dist/exports/management.d.ts +0 -1
  52. package/dist/exports/management.js +0 -2
  53. package/dist/exports/rsc.d.ts +0 -1
  54. package/dist/exports/rsc.js +0 -2
  55. package/dist/generated-types.d.ts +0 -1
  56. package/dist/generated-types.js +0 -2
  57. package/dist/index.d.ts +0 -1
  58. package/dist/index.js +0 -2
  59. package/dist/plugin/index.d.ts +0 -1
  60. package/dist/plugin/index.js +0 -2
  61. package/dist/scripts/generate-types.d.ts +0 -1
  62. package/dist/scripts/generate-types.js +0 -2
  63. package/dist/types/apiKey.d.ts +0 -1
  64. package/dist/types/apiKey.js +0 -2
  65. package/dist/types/betterAuth.d.ts +0 -1
  66. package/dist/types/betterAuth.js +0 -2
  67. package/dist/utils/access.d.ts +0 -1
  68. package/dist/utils/access.js +0 -2
  69. package/dist/utils/apiKeyAccess.d.ts +0 -1
  70. package/dist/utils/apiKeyAccess.js +0 -2
  71. package/dist/utils/betterAuthDefaults.d.ts +0 -1
  72. package/dist/utils/betterAuthDefaults.js +0 -2
  73. package/dist/utils/detectAuthConfig.d.ts +0 -1
  74. package/dist/utils/detectAuthConfig.js +0 -2
  75. package/dist/utils/detectEnabledPlugins.d.ts +0 -1
  76. package/dist/utils/detectEnabledPlugins.js +0 -2
  77. package/dist/utils/firstUserAdmin.d.ts +0 -1
  78. package/dist/utils/firstUserAdmin.js +0 -2
  79. package/dist/utils/generateScopes.d.ts +0 -1
  80. package/dist/utils/generateScopes.js +0 -2
  81. package/dist/utils/session.d.ts +0 -1
  82. package/dist/utils/session.js +0 -2
  83. package/package.json +34 -91
  84. package/dist/adapter/collections.d.ts.map +0 -1
  85. package/dist/adapter/collections.js.map +0 -1
  86. package/dist/adapter/index.d.ts.map +0 -1
  87. package/dist/adapter/index.js.map +0 -1
  88. package/dist/components/BeforeLogin.d.ts.map +0 -1
  89. package/dist/components/BeforeLogin.js.map +0 -1
  90. package/dist/components/LoginView.d.ts.map +0 -1
  91. package/dist/components/LoginView.js.map +0 -1
  92. package/dist/components/LoginViewWrapper.d.ts.map +0 -1
  93. package/dist/components/LoginViewWrapper.js.map +0 -1
  94. package/dist/components/LogoutButton.d.ts.map +0 -1
  95. package/dist/components/LogoutButton.js.map +0 -1
  96. package/dist/components/PasskeyRegisterButton.d.ts.map +0 -1
  97. package/dist/components/PasskeyRegisterButton.js.map +0 -1
  98. package/dist/components/PasskeySignInButton.d.ts.map +0 -1
  99. package/dist/components/PasskeySignInButton.js.map +0 -1
  100. package/dist/components/auth/ForgotPasswordView.d.ts.map +0 -1
  101. package/dist/components/auth/ForgotPasswordView.js.map +0 -1
  102. package/dist/components/auth/ResetPasswordView.d.ts.map +0 -1
  103. package/dist/components/auth/ResetPasswordView.js.map +0 -1
  104. package/dist/components/auth/index.d.ts.map +0 -1
  105. package/dist/components/auth/index.js.map +0 -1
  106. package/dist/components/management/ApiKeysManagementClient.d.ts.map +0 -1
  107. package/dist/components/management/ApiKeysManagementClient.js.map +0 -1
  108. package/dist/components/management/PasskeysManagementClient.d.ts.map +0 -1
  109. package/dist/components/management/PasskeysManagementClient.js.map +0 -1
  110. package/dist/components/management/SecurityNavLinks.d.ts.map +0 -1
  111. package/dist/components/management/SecurityNavLinks.js.map +0 -1
  112. package/dist/components/management/TwoFactorManagementClient.d.ts.map +0 -1
  113. package/dist/components/management/TwoFactorManagementClient.js.map +0 -1
  114. package/dist/components/management/index.d.ts.map +0 -1
  115. package/dist/components/management/index.js.map +0 -1
  116. package/dist/components/management/views/ApiKeysView.d.ts.map +0 -1
  117. package/dist/components/management/views/ApiKeysView.js.map +0 -1
  118. package/dist/components/management/views/PasskeysView.d.ts.map +0 -1
  119. package/dist/components/management/views/PasskeysView.js.map +0 -1
  120. package/dist/components/management/views/TwoFactorView.d.ts.map +0 -1
  121. package/dist/components/management/views/TwoFactorView.js.map +0 -1
  122. package/dist/components/management/views/index.d.ts.map +0 -1
  123. package/dist/components/management/views/index.js.map +0 -1
  124. package/dist/components/twoFactor/TwoFactorSetupView.d.ts.map +0 -1
  125. package/dist/components/twoFactor/TwoFactorSetupView.js.map +0 -1
  126. package/dist/components/twoFactor/TwoFactorVerifyView.d.ts.map +0 -1
  127. package/dist/components/twoFactor/TwoFactorVerifyView.js.map +0 -1
  128. package/dist/components/twoFactor/index.d.ts.map +0 -1
  129. package/dist/components/twoFactor/index.js.map +0 -1
  130. package/dist/exports/client.d.ts.map +0 -1
  131. package/dist/exports/client.js.map +0 -1
  132. package/dist/exports/components.d.ts.map +0 -1
  133. package/dist/exports/components.js.map +0 -1
  134. package/dist/exports/management.d.ts.map +0 -1
  135. package/dist/exports/management.js.map +0 -1
  136. package/dist/exports/rsc.d.ts.map +0 -1
  137. package/dist/exports/rsc.js.map +0 -1
  138. package/dist/generated-types.d.ts.map +0 -1
  139. package/dist/generated-types.js.map +0 -1
  140. package/dist/index.d.ts.map +0 -1
  141. package/dist/index.js.map +0 -1
  142. package/dist/plugin/index.d.ts.map +0 -1
  143. package/dist/plugin/index.js.map +0 -1
  144. package/dist/scripts/generate-types.d.ts.map +0 -1
  145. package/dist/scripts/generate-types.js.map +0 -1
  146. package/dist/types/apiKey.d.ts.map +0 -1
  147. package/dist/types/apiKey.js.map +0 -1
  148. package/dist/types/betterAuth.d.ts.map +0 -1
  149. package/dist/types/betterAuth.js.map +0 -1
  150. package/dist/utils/access.d.ts.map +0 -1
  151. package/dist/utils/access.js.map +0 -1
  152. package/dist/utils/apiKeyAccess.d.ts.map +0 -1
  153. package/dist/utils/apiKeyAccess.js.map +0 -1
  154. package/dist/utils/betterAuthDefaults.d.ts.map +0 -1
  155. package/dist/utils/betterAuthDefaults.js.map +0 -1
  156. package/dist/utils/detectAuthConfig.d.ts.map +0 -1
  157. package/dist/utils/detectAuthConfig.js.map +0 -1
  158. package/dist/utils/detectEnabledPlugins.d.ts.map +0 -1
  159. package/dist/utils/detectEnabledPlugins.js.map +0 -1
  160. package/dist/utils/firstUserAdmin.d.ts.map +0 -1
  161. package/dist/utils/firstUserAdmin.js.map +0 -1
  162. package/dist/utils/generateScopes.d.ts.map +0 -1
  163. package/dist/utils/generateScopes.js.map +0 -1
  164. package/dist/utils/session.d.ts.map +0 -1
  165. package/dist/utils/session.js.map +0 -1
  166. package/src/adapter/collections.ts +0 -621
  167. package/src/adapter/index.ts +0 -712
  168. package/src/components/BeforeLogin.tsx +0 -39
  169. package/src/components/LoginView.tsx +0 -1516
  170. package/src/components/LoginViewWrapper.tsx +0 -35
  171. package/src/components/LogoutButton.tsx +0 -58
  172. package/src/components/PasskeyRegisterButton.tsx +0 -105
  173. package/src/components/PasskeySignInButton.tsx +0 -96
  174. package/src/components/auth/ForgotPasswordView.tsx +0 -274
  175. package/src/components/auth/ResetPasswordView.tsx +0 -331
  176. package/src/components/auth/index.ts +0 -8
  177. package/src/components/management/ApiKeysManagementClient.tsx +0 -988
  178. package/src/components/management/PasskeysManagementClient.tsx +0 -409
  179. package/src/components/management/SecurityNavLinks.tsx +0 -117
  180. package/src/components/management/TwoFactorManagementClient.tsx +0 -560
  181. package/src/components/management/index.ts +0 -20
  182. package/src/components/management/views/ApiKeysView.tsx +0 -57
  183. package/src/components/management/views/PasskeysView.tsx +0 -42
  184. package/src/components/management/views/TwoFactorView.tsx +0 -42
  185. package/src/components/management/views/index.ts +0 -10
  186. package/src/components/twoFactor/TwoFactorSetupView.tsx +0 -515
  187. package/src/components/twoFactor/TwoFactorVerifyView.tsx +0 -238
  188. package/src/components/twoFactor/index.ts +0 -8
  189. package/src/exports/client.ts +0 -77
  190. package/src/exports/components.ts +0 -30
  191. package/src/exports/management.ts +0 -25
  192. package/src/exports/rsc.ts +0 -11
  193. package/src/generated-types.ts +0 -269
  194. package/src/index.ts +0 -135
  195. package/src/plugin/index.ts +0 -834
  196. package/src/scripts/generate-types.ts +0 -269
  197. package/src/types/apiKey.ts +0 -63
  198. package/src/types/betterAuth.ts +0 -253
  199. package/src/utils/access.ts +0 -410
  200. package/src/utils/apiKeyAccess.ts +0 -443
  201. package/src/utils/betterAuthDefaults.ts +0 -102
  202. package/src/utils/detectAuthConfig.ts +0 -47
  203. package/src/utils/detectEnabledPlugins.ts +0 -69
  204. package/src/utils/firstUserAdmin.ts +0 -164
  205. package/src/utils/generateScopes.ts +0 -150
  206. package/src/utils/session.ts +0 -91
@@ -1,35 +0,0 @@
1
- import type { AdminViewProps } from 'payload'
2
- import { LoginView, type LoginViewProps } from './LoginView.js'
3
-
4
- type LoginConfig = Omit<LoginViewProps, 'authClient' | 'logo'>
5
-
6
- type LoginViewWrapperProps = AdminViewProps
7
-
8
- /**
9
- * Server component wrapper for LoginView.
10
- * Reads login configuration from payload.config.custom.betterAuth.login
11
- * and passes it as props to the client LoginView component.
12
- */
13
- export async function LoginViewWrapper({ initPageResult }: LoginViewWrapperProps) {
14
- const { req } = initPageResult
15
- const { payload } = req
16
-
17
- // Read login config from payload.config.custom.betterAuth.login
18
- const loginConfig = (payload.config.custom?.betterAuth?.login ?? {}) as LoginConfig
19
-
20
- return (
21
- <LoginView
22
- afterLoginPath={loginConfig.afterLoginPath}
23
- requiredRole={loginConfig.requiredRole}
24
- requireAllRoles={loginConfig.requireAllRoles}
25
- enablePasskey={loginConfig.enablePasskey}
26
- enableSignUp={loginConfig.enableSignUp}
27
- defaultSignUpRole={loginConfig.defaultSignUpRole}
28
- enableForgotPassword={loginConfig.enableForgotPassword}
29
- resetPasswordUrl={loginConfig.resetPasswordUrl}
30
- title={loginConfig.title}
31
- />
32
- )
33
- }
34
-
35
- export default LoginViewWrapper
@@ -1,58 +0,0 @@
1
- 'use client'
2
-
3
- import { useState } from 'react'
4
- import { useRouter } from 'next/navigation.js'
5
-
6
- /**
7
- * Logout button component styled to match Payload's admin nav.
8
- * Uses Payload's CSS classes and variables for native theme integration.
9
- */
10
- export function LogoutButton() {
11
- const router = useRouter()
12
- const [isLoading, setIsLoading] = useState(false)
13
-
14
- async function handleLogout() {
15
- if (isLoading) return
16
- setIsLoading(true)
17
-
18
- try {
19
- await fetch('/api/auth/sign-out', {
20
- method: 'POST',
21
- credentials: 'include',
22
- headers: {
23
- 'Content-Type': 'application/json',
24
- },
25
- body: JSON.stringify({}),
26
- })
27
-
28
- router.push('/admin/login')
29
- } catch (error) {
30
- console.error('[better-auth] Logout error:', error)
31
- setIsLoading(false)
32
- }
33
- }
34
-
35
- return (
36
- <button
37
- onClick={handleLogout}
38
- disabled={isLoading}
39
- type="button"
40
- className="nav__link"
41
- style={{
42
- background: 'none',
43
- border: 'none',
44
- cursor: isLoading ? 'not-allowed' : 'pointer',
45
- opacity: isLoading ? 0.7 : 1,
46
- width: '100%',
47
- textAlign: 'left',
48
- padding: 0,
49
- }}
50
- >
51
- <span className="nav__link-label">
52
- {isLoading ? 'Logging out...' : 'Log out'}
53
- </span>
54
- </button>
55
- )
56
- }
57
-
58
- export default LogoutButton
@@ -1,105 +0,0 @@
1
- 'use client'
2
-
3
- import { useState, type ButtonHTMLAttributes } from 'react'
4
- import {
5
- createPayloadAuthClient,
6
- type PayloadAuthClient,
7
- } from '../exports/client.js'
8
-
9
- export type PasskeyRegisterButtonProps = Omit<
10
- ButtonHTMLAttributes<HTMLButtonElement>,
11
- 'onClick'
12
- > & {
13
- /** Optional pre-configured auth client */
14
- authClient?: PayloadAuthClient
15
- /** Optional name for the passkey */
16
- passkeyName?: string
17
- /** Callback when registration succeeds */
18
- onSuccess?: (passkey: { id: string; name?: string }) => void
19
- /** Callback when registration fails */
20
- onError?: (error: string) => void
21
- /** Button text when idle. Default: 'Add Passkey' */
22
- label?: string
23
- /** Button text when loading. Default: 'Registering...' */
24
- loadingLabel?: string
25
- }
26
-
27
- /**
28
- * Standalone passkey registration button component.
29
- * Handles the WebAuthn registration flow with Better Auth.
30
- *
31
- * @example
32
- * ```tsx
33
- * import { PasskeyRegisterButton } from '@delmaredigital/payload-better-auth/components'
34
- *
35
- * function SecuritySettings() {
36
- * return (
37
- * <PasskeyRegisterButton
38
- * passkeyName="My MacBook"
39
- * onSuccess={(passkey) => {
40
- * console.log('Passkey registered:', passkey.id)
41
- * refetchPasskeys()
42
- * }}
43
- * onError={(error) => {
44
- * setError(error)
45
- * }}
46
- * />
47
- * )
48
- * }
49
- * ```
50
- */
51
- export function PasskeyRegisterButton({
52
- authClient: providedClient,
53
- passkeyName,
54
- onSuccess,
55
- onError,
56
- label = 'Add Passkey',
57
- loadingLabel = 'Registering...',
58
- disabled,
59
- children,
60
- ...buttonProps
61
- }: PasskeyRegisterButtonProps) {
62
- const [loading, setLoading] = useState(false)
63
-
64
- async function handleClick() {
65
- setLoading(true)
66
-
67
- try {
68
- const client = providedClient ?? createPayloadAuthClient()
69
- const result = await client.passkey.addPasskey({
70
- name: passkeyName,
71
- })
72
-
73
- if (result.error) {
74
- onError?.(result.error.message ?? 'Passkey registration failed')
75
- } else if (result.data) {
76
- onSuccess?.({ id: result.data.id, name: passkeyName })
77
- }
78
- } catch (err) {
79
- if (err instanceof Error && err.name === 'NotAllowedError') {
80
- onError?.('Passkey registration was cancelled or not allowed')
81
- } else if (err instanceof Error && err.name === 'InvalidStateError') {
82
- onError?.('This passkey is already registered')
83
- } else {
84
- onError?.(
85
- err instanceof Error ? err.message : 'Passkey registration failed'
86
- )
87
- }
88
- } finally {
89
- setLoading(false)
90
- }
91
- }
92
-
93
- return (
94
- <button
95
- type="button"
96
- onClick={handleClick}
97
- disabled={disabled || loading}
98
- {...buttonProps}
99
- >
100
- {children ?? (loading ? loadingLabel : label)}
101
- </button>
102
- )
103
- }
104
-
105
- export default PasskeyRegisterButton
@@ -1,96 +0,0 @@
1
- 'use client'
2
-
3
- import { useState, type ButtonHTMLAttributes } from 'react'
4
- import {
5
- createPayloadAuthClient,
6
- type PayloadAuthClient,
7
- } from '../exports/client.js'
8
-
9
- export type PasskeySignInButtonProps = Omit<
10
- ButtonHTMLAttributes<HTMLButtonElement>,
11
- 'onClick'
12
- > & {
13
- /** Optional pre-configured auth client */
14
- authClient?: PayloadAuthClient
15
- /** Callback when sign-in succeeds */
16
- onSuccess?: (user: { id: string; email: string; role?: string }) => void
17
- /** Callback when sign-in fails */
18
- onError?: (error: string) => void
19
- /** Button text when idle. Default: 'Sign in with Passkey' */
20
- label?: string
21
- /** Button text when loading. Default: 'Authenticating...' */
22
- loadingLabel?: string
23
- }
24
-
25
- /**
26
- * Standalone passkey sign-in button component.
27
- * Handles the WebAuthn authentication flow with Better Auth.
28
- *
29
- * @example
30
- * ```tsx
31
- * import { PasskeySignInButton } from '@delmaredigital/payload-better-auth/components'
32
- *
33
- * function LoginForm() {
34
- * return (
35
- * <PasskeySignInButton
36
- * onSuccess={(user) => {
37
- * router.push('/dashboard')
38
- * }}
39
- * onError={(error) => {
40
- * setError(error)
41
- * }}
42
- * />
43
- * )
44
- * }
45
- * ```
46
- */
47
- export function PasskeySignInButton({
48
- authClient: providedClient,
49
- onSuccess,
50
- onError,
51
- label = 'Sign in with Passkey',
52
- loadingLabel = 'Authenticating...',
53
- disabled,
54
- children,
55
- ...buttonProps
56
- }: PasskeySignInButtonProps) {
57
- const [loading, setLoading] = useState(false)
58
-
59
- async function handleClick() {
60
- setLoading(true)
61
-
62
- try {
63
- const client = providedClient ?? createPayloadAuthClient()
64
- const result = await client.signIn.passkey()
65
-
66
- if (result.error) {
67
- onError?.(result.error.message ?? 'Passkey authentication failed')
68
- } else if (result.data?.user) {
69
- onSuccess?.(result.data.user as { id: string; email: string; role?: string })
70
- }
71
- } catch (err) {
72
- if (err instanceof Error && err.name === 'NotAllowedError') {
73
- onError?.('Passkey authentication was cancelled or not allowed')
74
- } else {
75
- onError?.(
76
- err instanceof Error ? err.message : 'Passkey authentication failed'
77
- )
78
- }
79
- } finally {
80
- setLoading(false)
81
- }
82
- }
83
-
84
- return (
85
- <button
86
- type="button"
87
- onClick={handleClick}
88
- disabled={disabled || loading}
89
- {...buttonProps}
90
- >
91
- {children ?? (loading ? loadingLabel : label)}
92
- </button>
93
- )
94
- }
95
-
96
- export default PasskeySignInButton
@@ -1,274 +0,0 @@
1
- 'use client'
2
-
3
- import { useState, type FormEvent } from 'react'
4
-
5
- export type ForgotPasswordViewProps = {
6
- /** Custom logo element */
7
- logo?: React.ReactNode
8
- /** Page title. Default: 'Forgot Password' */
9
- title?: string
10
- /** Path to login page. Default: '/admin/login' */
11
- loginPath?: string
12
- /** Success message to show after email is sent */
13
- successMessage?: string
14
- }
15
-
16
- /**
17
- * Forgot password page component for requesting a password reset email.
18
- * Uses Better Auth's forgetPassword endpoint.
19
- */
20
- export function ForgotPasswordView({
21
- logo,
22
- title = 'Forgot Password',
23
- loginPath = '/admin/login',
24
- successMessage = 'If an account exists with this email, you will receive a password reset link.',
25
- }: ForgotPasswordViewProps) {
26
- const [email, setEmail] = useState('')
27
- const [error, setError] = useState<string | null>(null)
28
- const [success, setSuccess] = useState(false)
29
- const [loading, setLoading] = useState(false)
30
-
31
- async function handleSubmit(e: FormEvent) {
32
- e.preventDefault()
33
- setLoading(true)
34
- setError(null)
35
-
36
- try {
37
- const response = await fetch('/api/auth/forget-password', {
38
- method: 'POST',
39
- headers: { 'Content-Type': 'application/json' },
40
- credentials: 'include',
41
- body: JSON.stringify({
42
- email,
43
- redirectTo: `${window.location.origin}/admin/reset-password`,
44
- }),
45
- })
46
-
47
- if (response.ok) {
48
- setSuccess(true)
49
- } else {
50
- // Always show success message to prevent email enumeration
51
- setSuccess(true)
52
- }
53
- } catch {
54
- setError('An error occurred. Please try again.')
55
- } finally {
56
- setLoading(false)
57
- }
58
- }
59
-
60
- if (success) {
61
- return (
62
- <div
63
- style={{
64
- minHeight: '100vh',
65
- display: 'flex',
66
- alignItems: 'center',
67
- justifyContent: 'center',
68
- background: 'var(--theme-bg)',
69
- padding: 'var(--base)',
70
- }}
71
- >
72
- <div
73
- style={{
74
- background: 'var(--theme-elevation-50)',
75
- padding: 'calc(var(--base) * 2)',
76
- borderRadius: 'var(--style-radius-m)',
77
- boxShadow: '0 2px 20px rgba(0, 0, 0, 0.1)',
78
- width: '100%',
79
- maxWidth: '400px',
80
- textAlign: 'center',
81
- }}
82
- >
83
- {logo && (
84
- <div style={{ marginBottom: 'calc(var(--base) * 1.5)' }}>
85
- {logo}
86
- </div>
87
- )}
88
-
89
- <h1
90
- style={{
91
- color: 'var(--theme-text)',
92
- fontSize: 'var(--font-size-h3)',
93
- fontWeight: 600,
94
- margin: '0 0 var(--base) 0',
95
- }}
96
- >
97
- Check Your Email
98
- </h1>
99
-
100
- <p
101
- style={{
102
- color: 'var(--theme-text)',
103
- opacity: 0.8,
104
- marginBottom: 'calc(var(--base) * 1.5)',
105
- fontSize: 'var(--font-size-small)',
106
- }}
107
- >
108
- {successMessage}
109
- </p>
110
-
111
- <a
112
- href={loginPath}
113
- style={{
114
- color: 'var(--theme-elevation-800)',
115
- fontSize: 'var(--font-size-small)',
116
- textDecoration: 'underline',
117
- }}
118
- >
119
- Back to login
120
- </a>
121
- </div>
122
- </div>
123
- )
124
- }
125
-
126
- return (
127
- <div
128
- style={{
129
- minHeight: '100vh',
130
- display: 'flex',
131
- alignItems: 'center',
132
- justifyContent: 'center',
133
- background: 'var(--theme-bg)',
134
- padding: 'var(--base)',
135
- }}
136
- >
137
- <div
138
- style={{
139
- background: 'var(--theme-elevation-50)',
140
- padding: 'calc(var(--base) * 2)',
141
- borderRadius: 'var(--style-radius-m)',
142
- boxShadow: '0 2px 20px rgba(0, 0, 0, 0.1)',
143
- width: '100%',
144
- maxWidth: '400px',
145
- }}
146
- >
147
- {logo && (
148
- <div
149
- style={{
150
- textAlign: 'center',
151
- marginBottom: 'calc(var(--base) * 1.5)',
152
- }}
153
- >
154
- {logo}
155
- </div>
156
- )}
157
-
158
- <h1
159
- style={{
160
- color: 'var(--theme-text)',
161
- fontSize: 'var(--font-size-h3)',
162
- fontWeight: 600,
163
- marginBottom: 'calc(var(--base) * 0.5)',
164
- textAlign: 'center',
165
- margin: '0 0 calc(var(--base) * 0.5) 0',
166
- }}
167
- >
168
- {title}
169
- </h1>
170
-
171
- <p
172
- style={{
173
- color: 'var(--theme-text)',
174
- opacity: 0.7,
175
- fontSize: 'var(--font-size-small)',
176
- textAlign: 'center',
177
- marginBottom: 'calc(var(--base) * 1.5)',
178
- }}
179
- >
180
- Enter your email and we'll send you a reset link.
181
- </p>
182
-
183
- <form onSubmit={handleSubmit}>
184
- <div style={{ marginBottom: 'calc(var(--base) * 1.5)' }}>
185
- <label
186
- htmlFor="email"
187
- style={{
188
- display: 'block',
189
- color: 'var(--theme-text)',
190
- marginBottom: 'calc(var(--base) * 0.5)',
191
- fontSize: 'var(--font-size-small)',
192
- fontWeight: 500,
193
- }}
194
- >
195
- Email
196
- </label>
197
- <input
198
- id="email"
199
- type="email"
200
- value={email}
201
- onChange={(e) => setEmail(e.target.value)}
202
- required
203
- autoComplete="email"
204
- style={{
205
- width: '100%',
206
- padding: 'calc(var(--base) * 0.75)',
207
- background: 'var(--theme-input-bg)',
208
- border: '1px solid var(--theme-elevation-150)',
209
- borderRadius: 'var(--style-radius-s)',
210
- color: 'var(--theme-text)',
211
- fontSize: 'var(--font-size-base)',
212
- outline: 'none',
213
- boxSizing: 'border-box',
214
- }}
215
- />
216
- </div>
217
-
218
- {error && (
219
- <div
220
- style={{
221
- color: 'var(--theme-error-500)',
222
- marginBottom: 'var(--base)',
223
- fontSize: 'var(--font-size-small)',
224
- padding: 'calc(var(--base) * 0.5)',
225
- background: 'var(--theme-error-50)',
226
- borderRadius: 'var(--style-radius-s)',
227
- border: '1px solid var(--theme-error-200)',
228
- }}
229
- >
230
- {error}
231
- </div>
232
- )}
233
-
234
- <button
235
- type="submit"
236
- disabled={loading}
237
- style={{
238
- width: '100%',
239
- padding: 'calc(var(--base) * 0.75)',
240
- background: 'var(--theme-elevation-800)',
241
- border: 'none',
242
- borderRadius: 'var(--style-radius-s)',
243
- color: 'var(--theme-elevation-50)',
244
- fontSize: 'var(--font-size-base)',
245
- fontWeight: 500,
246
- cursor: loading ? 'not-allowed' : 'pointer',
247
- opacity: loading ? 0.7 : 1,
248
- transition: 'opacity 150ms ease',
249
- marginBottom: 'var(--base)',
250
- }}
251
- >
252
- {loading ? 'Sending...' : 'Send Reset Link'}
253
- </button>
254
-
255
- <div style={{ textAlign: 'center' }}>
256
- <a
257
- href={loginPath}
258
- style={{
259
- color: 'var(--theme-text)',
260
- opacity: 0.7,
261
- fontSize: 'var(--font-size-small)',
262
- textDecoration: 'underline',
263
- }}
264
- >
265
- Back to login
266
- </a>
267
- </div>
268
- </form>
269
- </div>
270
- </div>
271
- )
272
- }
273
-
274
- export default ForgotPasswordView