@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,42 +0,0 @@
1
- import type { AdminViewProps, Locale } from 'payload'
2
- import { DefaultTemplate } from '@payloadcms/next/templates'
3
- import { getVisibleEntities } from '@payloadcms/ui/shared'
4
- import { TwoFactorManagementClient } from '../TwoFactorManagementClient.js'
5
-
6
- type TwoFactorViewProps = AdminViewProps
7
-
8
- /**
9
- * Two-factor management view for Payload admin panel.
10
- * Server component that provides the admin layout.
11
- */
12
- export async function TwoFactorView({
13
- initPageResult,
14
- params,
15
- searchParams,
16
- }: TwoFactorViewProps) {
17
- const { req } = initPageResult
18
- const { payload } = req
19
-
20
- // Await params/searchParams for Next.js 15+ compatibility
21
- const resolvedParams = params ? await params : undefined
22
- const resolvedSearchParams = searchParams ? await searchParams : undefined
23
-
24
- const visibleEntities = getVisibleEntities({ req })
25
-
26
- return (
27
- <DefaultTemplate
28
- i18n={req.i18n}
29
- locale={req.locale as Locale | undefined}
30
- params={resolvedParams}
31
- payload={payload}
32
- permissions={initPageResult.permissions}
33
- searchParams={resolvedSearchParams}
34
- user={req.user ?? undefined}
35
- visibleEntities={visibleEntities}
36
- >
37
- <TwoFactorManagementClient />
38
- </DefaultTemplate>
39
- )
40
- }
41
-
42
- export default TwoFactorView
@@ -1,10 +0,0 @@
1
- /**
2
- * Server Component Views for Payload Admin Panel
3
- *
4
- * These are async server components that use DefaultTemplate
5
- * for proper integration with Payload's admin layout.
6
- */
7
-
8
- export { TwoFactorView } from './TwoFactorView.js'
9
- export { ApiKeysView } from './ApiKeysView.js'
10
- export { PasskeysView } from './PasskeysView.js'
@@ -1,515 +0,0 @@
1
- 'use client'
2
-
3
- import { useState, useEffect, type FormEvent } from 'react'
4
-
5
- export type TwoFactorSetupViewProps = {
6
- /** Custom logo element */
7
- logo?: React.ReactNode
8
- /** Page title. Default: 'Set Up Two-Factor Authentication' */
9
- title?: string
10
- /** Path to redirect after successful setup. Default: '/admin' */
11
- afterSetupPath?: string
12
- /** Callback after successful setup */
13
- onSetupComplete?: () => void
14
- }
15
-
16
- /**
17
- * Two-factor authentication setup component.
18
- * Displays QR code for TOTP apps and allows verification.
19
- * Uses Better Auth's twoFactor plugin endpoints.
20
- */
21
- export function TwoFactorSetupView({
22
- logo,
23
- title = 'Set Up Two-Factor Authentication',
24
- afterSetupPath = '/admin',
25
- onSetupComplete,
26
- }: TwoFactorSetupViewProps) {
27
- const [step, setStep] = useState<'loading' | 'qr' | 'verify' | 'backup' | 'complete'>('loading')
28
- const [totpUri, setTotpUri] = useState<string | null>(null)
29
- const [secret, setSecret] = useState<string | null>(null)
30
- const [backupCodes, setBackupCodes] = useState<string[]>([])
31
- const [verificationCode, setVerificationCode] = useState('')
32
- const [error, setError] = useState<string | null>(null)
33
- const [loading, setLoading] = useState(false)
34
-
35
- useEffect(() => {
36
- async function enableTwoFactor() {
37
- try {
38
- const response = await fetch('/api/auth/two-factor/enable', {
39
- method: 'POST',
40
- headers: { 'Content-Type': 'application/json' },
41
- credentials: 'include',
42
- body: JSON.stringify({}),
43
- })
44
-
45
- if (response.ok) {
46
- const data = await response.json()
47
- setTotpUri(data.totpURI)
48
- setSecret(data.secret)
49
- setBackupCodes(data.backupCodes || [])
50
- setStep('qr')
51
- } else {
52
- const data = await response.json().catch(() => ({}))
53
- setError(data.message || 'Failed to enable two-factor authentication.')
54
- setStep('qr')
55
- }
56
- } catch {
57
- setError('An error occurred. Please try again.')
58
- setStep('qr')
59
- }
60
- }
61
- enableTwoFactor()
62
- }, [])
63
-
64
- async function handleVerify(e: FormEvent) {
65
- e.preventDefault()
66
- setLoading(true)
67
- setError(null)
68
-
69
- try {
70
- const response = await fetch('/api/auth/two-factor/verify-totp', {
71
- method: 'POST',
72
- headers: { 'Content-Type': 'application/json' },
73
- credentials: 'include',
74
- body: JSON.stringify({ code: verificationCode }),
75
- })
76
-
77
- if (response.ok) {
78
- if (backupCodes.length > 0) {
79
- setStep('backup')
80
- } else {
81
- setStep('complete')
82
- onSetupComplete?.()
83
- }
84
- } else {
85
- const data = await response.json().catch(() => ({}))
86
- setError(data.message || 'Invalid verification code. Please try again.')
87
- }
88
- } catch {
89
- setError('An error occurred. Please try again.')
90
- } finally {
91
- setLoading(false)
92
- }
93
- }
94
-
95
- function handleBackupContinue() {
96
- setStep('complete')
97
- onSetupComplete?.()
98
- }
99
-
100
- // Loading state
101
- if (step === 'loading') {
102
- return (
103
- <div
104
- style={{
105
- minHeight: '100vh',
106
- display: 'flex',
107
- alignItems: 'center',
108
- justifyContent: 'center',
109
- background: 'var(--theme-bg)',
110
- }}
111
- >
112
- <div style={{ color: 'var(--theme-text)', opacity: 0.7 }}>
113
- Setting up two-factor authentication...
114
- </div>
115
- </div>
116
- )
117
- }
118
-
119
- // Complete state
120
- if (step === 'complete') {
121
- return (
122
- <div
123
- style={{
124
- minHeight: '100vh',
125
- display: 'flex',
126
- alignItems: 'center',
127
- justifyContent: 'center',
128
- background: 'var(--theme-bg)',
129
- padding: 'var(--base)',
130
- }}
131
- >
132
- <div
133
- style={{
134
- background: 'var(--theme-elevation-50)',
135
- padding: 'calc(var(--base) * 2)',
136
- borderRadius: 'var(--style-radius-m)',
137
- boxShadow: '0 2px 20px rgba(0, 0, 0, 0.1)',
138
- width: '100%',
139
- maxWidth: '400px',
140
- textAlign: 'center',
141
- }}
142
- >
143
- {logo && (
144
- <div style={{ marginBottom: 'calc(var(--base) * 1.5)' }}>
145
- {logo}
146
- </div>
147
- )}
148
-
149
- <h1
150
- style={{
151
- color: 'var(--theme-success-500)',
152
- fontSize: 'var(--font-size-h3)',
153
- fontWeight: 600,
154
- margin: '0 0 var(--base) 0',
155
- }}
156
- >
157
- Two-Factor Enabled!
158
- </h1>
159
-
160
- <p
161
- style={{
162
- color: 'var(--theme-text)',
163
- opacity: 0.8,
164
- marginBottom: 'calc(var(--base) * 1.5)',
165
- fontSize: 'var(--font-size-small)',
166
- }}
167
- >
168
- Your account is now protected with two-factor authentication.
169
- </p>
170
-
171
- <a
172
- href={afterSetupPath}
173
- style={{
174
- display: 'inline-block',
175
- padding: 'calc(var(--base) * 0.75) calc(var(--base) * 1.5)',
176
- background: 'var(--theme-elevation-800)',
177
- border: 'none',
178
- borderRadius: 'var(--style-radius-s)',
179
- color: 'var(--theme-elevation-50)',
180
- fontSize: 'var(--font-size-base)',
181
- fontWeight: 500,
182
- textDecoration: 'none',
183
- }}
184
- >
185
- Continue
186
- </a>
187
- </div>
188
- </div>
189
- )
190
- }
191
-
192
- // Backup codes state
193
- if (step === 'backup') {
194
- return (
195
- <div
196
- style={{
197
- minHeight: '100vh',
198
- display: 'flex',
199
- alignItems: 'center',
200
- justifyContent: 'center',
201
- background: 'var(--theme-bg)',
202
- padding: 'var(--base)',
203
- }}
204
- >
205
- <div
206
- style={{
207
- background: 'var(--theme-elevation-50)',
208
- padding: 'calc(var(--base) * 2)',
209
- borderRadius: 'var(--style-radius-m)',
210
- boxShadow: '0 2px 20px rgba(0, 0, 0, 0.1)',
211
- width: '100%',
212
- maxWidth: '450px',
213
- }}
214
- >
215
- {logo && (
216
- <div
217
- style={{
218
- textAlign: 'center',
219
- marginBottom: 'calc(var(--base) * 1.5)',
220
- }}
221
- >
222
- {logo}
223
- </div>
224
- )}
225
-
226
- <h1
227
- style={{
228
- color: 'var(--theme-text)',
229
- fontSize: 'var(--font-size-h3)',
230
- fontWeight: 600,
231
- margin: '0 0 calc(var(--base) * 0.5) 0',
232
- textAlign: 'center',
233
- }}
234
- >
235
- Save Your Backup Codes
236
- </h1>
237
-
238
- <p
239
- style={{
240
- color: 'var(--theme-text)',
241
- opacity: 0.7,
242
- fontSize: 'var(--font-size-small)',
243
- textAlign: 'center',
244
- marginBottom: 'calc(var(--base) * 1.5)',
245
- }}
246
- >
247
- Store these codes safely. You can use them to access your account if you lose your authenticator.
248
- </p>
249
-
250
- <div
251
- style={{
252
- background: 'var(--theme-elevation-100)',
253
- padding: 'var(--base)',
254
- borderRadius: 'var(--style-radius-s)',
255
- marginBottom: 'calc(var(--base) * 1.5)',
256
- fontFamily: 'monospace',
257
- fontSize: 'var(--font-size-small)',
258
- }}
259
- >
260
- <div
261
- style={{
262
- display: 'grid',
263
- gridTemplateColumns: 'repeat(2, 1fr)',
264
- gap: 'calc(var(--base) * 0.5)',
265
- }}
266
- >
267
- {backupCodes.map((code, index) => (
268
- <div
269
- key={index}
270
- style={{
271
- color: 'var(--theme-text)',
272
- padding: 'calc(var(--base) * 0.25)',
273
- }}
274
- >
275
- {code}
276
- </div>
277
- ))}
278
- </div>
279
- </div>
280
-
281
- <button
282
- onClick={() => {
283
- navigator.clipboard.writeText(backupCodes.join('\n'))
284
- }}
285
- style={{
286
- width: '100%',
287
- padding: 'calc(var(--base) * 0.5)',
288
- background: 'var(--theme-elevation-150)',
289
- border: 'none',
290
- borderRadius: 'var(--style-radius-s)',
291
- color: 'var(--theme-text)',
292
- fontSize: 'var(--font-size-small)',
293
- cursor: 'pointer',
294
- marginBottom: 'var(--base)',
295
- }}
296
- >
297
- Copy to Clipboard
298
- </button>
299
-
300
- <button
301
- onClick={handleBackupContinue}
302
- style={{
303
- width: '100%',
304
- padding: 'calc(var(--base) * 0.75)',
305
- background: 'var(--theme-elevation-800)',
306
- border: 'none',
307
- borderRadius: 'var(--style-radius-s)',
308
- color: 'var(--theme-elevation-50)',
309
- fontSize: 'var(--font-size-base)',
310
- fontWeight: 500,
311
- cursor: 'pointer',
312
- }}
313
- >
314
- I've Saved My Codes
315
- </button>
316
- </div>
317
- </div>
318
- )
319
- }
320
-
321
- // QR code and verify state
322
- return (
323
- <div
324
- style={{
325
- minHeight: '100vh',
326
- display: 'flex',
327
- alignItems: 'center',
328
- justifyContent: 'center',
329
- background: 'var(--theme-bg)',
330
- padding: 'var(--base)',
331
- }}
332
- >
333
- <div
334
- style={{
335
- background: 'var(--theme-elevation-50)',
336
- padding: 'calc(var(--base) * 2)',
337
- borderRadius: 'var(--style-radius-m)',
338
- boxShadow: '0 2px 20px rgba(0, 0, 0, 0.1)',
339
- width: '100%',
340
- maxWidth: '400px',
341
- }}
342
- >
343
- {logo && (
344
- <div
345
- style={{
346
- textAlign: 'center',
347
- marginBottom: 'calc(var(--base) * 1.5)',
348
- }}
349
- >
350
- {logo}
351
- </div>
352
- )}
353
-
354
- <h1
355
- style={{
356
- color: 'var(--theme-text)',
357
- fontSize: 'var(--font-size-h3)',
358
- fontWeight: 600,
359
- margin: '0 0 calc(var(--base) * 0.5) 0',
360
- textAlign: 'center',
361
- }}
362
- >
363
- {title}
364
- </h1>
365
-
366
- <p
367
- style={{
368
- color: 'var(--theme-text)',
369
- opacity: 0.7,
370
- fontSize: 'var(--font-size-small)',
371
- textAlign: 'center',
372
- marginBottom: 'calc(var(--base) * 1.5)',
373
- }}
374
- >
375
- Scan the QR code with your authenticator app, then enter the code below.
376
- </p>
377
-
378
- {totpUri && (
379
- <div
380
- style={{
381
- textAlign: 'center',
382
- marginBottom: 'calc(var(--base) * 1.5)',
383
- }}
384
- >
385
- {/* QR code using QRServer.com API */}
386
- <img
387
- src={`https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${encodeURIComponent(totpUri)}`}
388
- alt="QR Code for authenticator app"
389
- style={{
390
- width: '200px',
391
- height: '200px',
392
- border: '1px solid var(--theme-elevation-150)',
393
- borderRadius: 'var(--style-radius-s)',
394
- }}
395
- />
396
- </div>
397
- )}
398
-
399
- {secret && (
400
- <div
401
- style={{
402
- marginBottom: 'calc(var(--base) * 1.5)',
403
- textAlign: 'center',
404
- }}
405
- >
406
- <p
407
- style={{
408
- color: 'var(--theme-text)',
409
- opacity: 0.7,
410
- fontSize: 'var(--font-size-small)',
411
- marginBottom: 'calc(var(--base) * 0.5)',
412
- }}
413
- >
414
- Or enter this code manually:
415
- </p>
416
- <code
417
- style={{
418
- display: 'inline-block',
419
- padding: 'calc(var(--base) * 0.5)',
420
- background: 'var(--theme-elevation-100)',
421
- borderRadius: 'var(--style-radius-s)',
422
- fontFamily: 'monospace',
423
- fontSize: 'var(--font-size-small)',
424
- color: 'var(--theme-text)',
425
- wordBreak: 'break-all',
426
- }}
427
- >
428
- {secret}
429
- </code>
430
- </div>
431
- )}
432
-
433
- <form onSubmit={handleVerify}>
434
- <div style={{ marginBottom: 'calc(var(--base) * 1.5)' }}>
435
- <label
436
- htmlFor="code"
437
- style={{
438
- display: 'block',
439
- color: 'var(--theme-text)',
440
- marginBottom: 'calc(var(--base) * 0.5)',
441
- fontSize: 'var(--font-size-small)',
442
- fontWeight: 500,
443
- }}
444
- >
445
- Verification Code
446
- </label>
447
- <input
448
- id="code"
449
- type="text"
450
- inputMode="numeric"
451
- pattern="[0-9]*"
452
- autoComplete="one-time-code"
453
- value={verificationCode}
454
- onChange={(e) => setVerificationCode(e.target.value.replace(/\D/g, '').slice(0, 6))}
455
- required
456
- placeholder="000000"
457
- style={{
458
- width: '100%',
459
- padding: 'calc(var(--base) * 0.75)',
460
- background: 'var(--theme-input-bg)',
461
- border: '1px solid var(--theme-elevation-150)',
462
- borderRadius: 'var(--style-radius-s)',
463
- color: 'var(--theme-text)',
464
- fontSize: 'var(--font-size-h4)',
465
- fontFamily: 'monospace',
466
- textAlign: 'center',
467
- letterSpacing: '0.5em',
468
- outline: 'none',
469
- boxSizing: 'border-box',
470
- }}
471
- />
472
- </div>
473
-
474
- {error && (
475
- <div
476
- style={{
477
- color: 'var(--theme-error-500)',
478
- marginBottom: 'var(--base)',
479
- fontSize: 'var(--font-size-small)',
480
- padding: 'calc(var(--base) * 0.5)',
481
- background: 'var(--theme-error-50)',
482
- borderRadius: 'var(--style-radius-s)',
483
- border: '1px solid var(--theme-error-200)',
484
- }}
485
- >
486
- {error}
487
- </div>
488
- )}
489
-
490
- <button
491
- type="submit"
492
- disabled={loading || verificationCode.length !== 6}
493
- style={{
494
- width: '100%',
495
- padding: 'calc(var(--base) * 0.75)',
496
- background: 'var(--theme-elevation-800)',
497
- border: 'none',
498
- borderRadius: 'var(--style-radius-s)',
499
- color: 'var(--theme-elevation-50)',
500
- fontSize: 'var(--font-size-base)',
501
- fontWeight: 500,
502
- cursor: loading || verificationCode.length !== 6 ? 'not-allowed' : 'pointer',
503
- opacity: loading || verificationCode.length !== 6 ? 0.7 : 1,
504
- transition: 'opacity 150ms ease',
505
- }}
506
- >
507
- {loading ? 'Verifying...' : 'Verify and Enable'}
508
- </button>
509
- </form>
510
- </div>
511
- </div>
512
- )
513
- }
514
-
515
- export default TwoFactorSetupView