@questpie/admin 0.0.1 → 1.0.0

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 (250) hide show
  1. package/README.md +439 -424
  2. package/dist/auth-layout-M8K8_q5R.mjs +181 -0
  3. package/dist/auth-layout-M8K8_q5R.mjs.map +1 -0
  4. package/dist/bulk-upload-dialog-h7zXD78Y.mjs +274 -0
  5. package/dist/bulk-upload-dialog-h7zXD78Y.mjs.map +1 -0
  6. package/dist/{components/ui/card.mjs → card-BKHjBQfw.mjs} +8 -8
  7. package/dist/card-BKHjBQfw.mjs.map +1 -0
  8. package/dist/client/styles/index.css +434 -0
  9. package/dist/client-BCGpkAz6.mjs +22635 -0
  10. package/dist/client-BCGpkAz6.mjs.map +1 -0
  11. package/dist/client-CcWZbkBP.d.mts +13585 -0
  12. package/dist/client-CcWZbkBP.d.mts.map +1 -0
  13. package/dist/client.d.mts +3 -0
  14. package/dist/client.mjs +14 -0
  15. package/dist/content-locales-provider-BXvuIgfg.mjs +1650 -0
  16. package/dist/content-locales-provider-BXvuIgfg.mjs.map +1 -0
  17. package/dist/dashboard-page-B4PGEdc2.mjs +2500 -0
  18. package/dist/dashboard-page-B4PGEdc2.mjs.map +1 -0
  19. package/dist/dashboard-page-CVlyR40m.mjs +6 -0
  20. package/dist/dropzone-Do3awXKd.mjs +634 -0
  21. package/dist/dropzone-Do3awXKd.mjs.map +1 -0
  22. package/dist/{views/auth/forgot-password-form.mjs → forgot-password-page-Bcp-An4Y.mjs} +87 -14
  23. package/dist/forgot-password-page-Bcp-An4Y.mjs.map +1 -0
  24. package/dist/forgot-password-page-CIILVhfo.mjs +7 -0
  25. package/dist/index-B9Xwk4hi.d.mts +2753 -0
  26. package/dist/index-B9Xwk4hi.d.mts.map +1 -0
  27. package/dist/index.d.mts +3 -0
  28. package/dist/index.mjs +14 -0
  29. package/dist/login-page-8K7fo0qK.mjs +7 -0
  30. package/dist/login-page-CP4gA-dl.mjs +298 -0
  31. package/dist/login-page-CP4gA-dl.mjs.map +1 -0
  32. package/dist/preview-utils-BKQ9-TMa.mjs +65 -0
  33. package/dist/preview-utils-BKQ9-TMa.mjs.map +1 -0
  34. package/dist/{views/auth/reset-password-form.mjs → reset-password-page-BqfDmLxA.mjs} +111 -14
  35. package/dist/reset-password-page-BqfDmLxA.mjs.map +1 -0
  36. package/dist/reset-password-page-DLATv0xQ.mjs +7 -0
  37. package/dist/runtime-6VZM878K.mjs +69 -0
  38. package/dist/runtime-6VZM878K.mjs.map +1 -0
  39. package/dist/saved-views.types-BMsz5mCy.d.mts +42 -0
  40. package/dist/saved-views.types-BMsz5mCy.d.mts.map +1 -0
  41. package/dist/server.d.mts +250 -0
  42. package/dist/server.d.mts.map +1 -0
  43. package/dist/server.mjs +832 -0
  44. package/dist/server.mjs.map +1 -0
  45. package/dist/setup-page-CMZ5P_OE.mjs +6 -0
  46. package/dist/setup-page-YAP_fzqh.mjs +264 -0
  47. package/dist/setup-page-YAP_fzqh.mjs.map +1 -0
  48. package/dist/shared.d.mts +57 -0
  49. package/dist/shared.d.mts.map +1 -0
  50. package/dist/shared.mjs +3 -0
  51. package/dist/{hooks/use-auth.mjs → use-auth-BoLmWtmU.mjs} +42 -30
  52. package/dist/use-auth-BoLmWtmU.mjs.map +1 -0
  53. package/package.json +48 -197
  54. package/.turbo/turbo-build.log +0 -108
  55. package/CHANGELOG.md +0 -10
  56. package/STATUS.md +0 -917
  57. package/VALIDATION.md +0 -602
  58. package/components.json +0 -24
  59. package/dist/__tests__/setup.mjs +0 -38
  60. package/dist/__tests__/test-utils.mjs +0 -45
  61. package/dist/__tests__/vitest.d.mjs +0 -3
  62. package/dist/components/admin-app.mjs +0 -69
  63. package/dist/components/fields/array-field.mjs +0 -190
  64. package/dist/components/fields/checkbox-field.mjs +0 -34
  65. package/dist/components/fields/custom-field.mjs +0 -32
  66. package/dist/components/fields/date-field.mjs +0 -41
  67. package/dist/components/fields/datetime-field.mjs +0 -42
  68. package/dist/components/fields/email-field.mjs +0 -37
  69. package/dist/components/fields/embedded-collection.mjs +0 -253
  70. package/dist/components/fields/field-types.mjs +0 -1
  71. package/dist/components/fields/field-utils.mjs +0 -10
  72. package/dist/components/fields/field-wrapper.mjs +0 -34
  73. package/dist/components/fields/index.mjs +0 -23
  74. package/dist/components/fields/json-field.mjs +0 -243
  75. package/dist/components/fields/locale-badge.mjs +0 -16
  76. package/dist/components/fields/number-field.mjs +0 -39
  77. package/dist/components/fields/password-field.mjs +0 -37
  78. package/dist/components/fields/relation-field.mjs +0 -104
  79. package/dist/components/fields/relation-picker.mjs +0 -229
  80. package/dist/components/fields/relation-select.mjs +0 -188
  81. package/dist/components/fields/rich-text-editor/index.mjs +0 -897
  82. package/dist/components/fields/select-field.mjs +0 -41
  83. package/dist/components/fields/switch-field.mjs +0 -34
  84. package/dist/components/fields/text-field.mjs +0 -38
  85. package/dist/components/fields/textarea-field.mjs +0 -38
  86. package/dist/components/index.mjs +0 -59
  87. package/dist/components/primitives/checkbox-input.mjs +0 -127
  88. package/dist/components/primitives/date-input.mjs +0 -303
  89. package/dist/components/primitives/index.mjs +0 -12
  90. package/dist/components/primitives/number-input.mjs +0 -104
  91. package/dist/components/primitives/select-input.mjs +0 -177
  92. package/dist/components/primitives/tag-input.mjs +0 -135
  93. package/dist/components/primitives/text-input.mjs +0 -39
  94. package/dist/components/primitives/textarea-input.mjs +0 -37
  95. package/dist/components/primitives/toggle-input.mjs +0 -31
  96. package/dist/components/primitives/types.mjs +0 -12
  97. package/dist/components/ui/accordion.mjs +0 -55
  98. package/dist/components/ui/avatar.mjs +0 -54
  99. package/dist/components/ui/badge.mjs +0 -34
  100. package/dist/components/ui/button.mjs +0 -48
  101. package/dist/components/ui/checkbox.mjs +0 -21
  102. package/dist/components/ui/combobox.mjs +0 -163
  103. package/dist/components/ui/dialog.mjs +0 -95
  104. package/dist/components/ui/dropdown-menu.mjs +0 -138
  105. package/dist/components/ui/field.mjs +0 -113
  106. package/dist/components/ui/input-group.mjs +0 -82
  107. package/dist/components/ui/input.mjs +0 -17
  108. package/dist/components/ui/label.mjs +0 -15
  109. package/dist/components/ui/popover.mjs +0 -56
  110. package/dist/components/ui/scroll-area.mjs +0 -38
  111. package/dist/components/ui/select.mjs +0 -100
  112. package/dist/components/ui/separator.mjs +0 -16
  113. package/dist/components/ui/sheet.mjs +0 -90
  114. package/dist/components/ui/sidebar.mjs +0 -387
  115. package/dist/components/ui/skeleton.mjs +0 -14
  116. package/dist/components/ui/spinner.mjs +0 -16
  117. package/dist/components/ui/switch.mjs +0 -22
  118. package/dist/components/ui/table.mjs +0 -68
  119. package/dist/components/ui/tabs.mjs +0 -48
  120. package/dist/components/ui/textarea.mjs +0 -15
  121. package/dist/components/ui/tooltip.mjs +0 -44
  122. package/dist/config/component-registry.mjs +0 -38
  123. package/dist/config/index.mjs +0 -129
  124. package/dist/hooks/admin-provider.mjs +0 -70
  125. package/dist/hooks/index.mjs +0 -7
  126. package/dist/hooks/store.mjs +0 -178
  127. package/dist/hooks/use-collection-db.mjs +0 -146
  128. package/dist/hooks/use-collection.mjs +0 -112
  129. package/dist/hooks/use-global.mjs +0 -46
  130. package/dist/hooks/use-mobile.mjs +0 -20
  131. package/dist/lib/utils.mjs +0 -10
  132. package/dist/styles/index.css +0 -336
  133. package/dist/styles/index.mjs +0 -1
  134. package/dist/utils/index.mjs +0 -9
  135. package/dist/views/auth/auth-layout.mjs +0 -52
  136. package/dist/views/auth/index.mjs +0 -6
  137. package/dist/views/auth/login-form.mjs +0 -156
  138. package/dist/views/collection/auto-form-fields.mjs +0 -525
  139. package/dist/views/collection/collection-form.mjs +0 -91
  140. package/dist/views/collection/collection-list.mjs +0 -76
  141. package/dist/views/collection/form-field.mjs +0 -42
  142. package/dist/views/collection/index.mjs +0 -6
  143. package/dist/views/common/index.mjs +0 -4
  144. package/dist/views/common/locale-switcher.mjs +0 -39
  145. package/dist/views/common/version-history.mjs +0 -272
  146. package/dist/views/index.mjs +0 -9
  147. package/dist/views/layout/admin-layout.mjs +0 -40
  148. package/dist/views/layout/admin-router.mjs +0 -95
  149. package/dist/views/layout/admin-sidebar.mjs +0 -63
  150. package/dist/views/layout/index.mjs +0 -5
  151. package/src/__tests__/setup.ts +0 -44
  152. package/src/__tests__/test-utils.tsx +0 -49
  153. package/src/__tests__/vitest.d.ts +0 -9
  154. package/src/components/admin-app.tsx +0 -221
  155. package/src/components/fields/array-field.tsx +0 -237
  156. package/src/components/fields/checkbox-field.tsx +0 -47
  157. package/src/components/fields/custom-field.tsx +0 -50
  158. package/src/components/fields/date-field.tsx +0 -65
  159. package/src/components/fields/datetime-field.tsx +0 -67
  160. package/src/components/fields/email-field.tsx +0 -51
  161. package/src/components/fields/embedded-collection.tsx +0 -315
  162. package/src/components/fields/field-types.ts +0 -162
  163. package/src/components/fields/field-utils.ts +0 -6
  164. package/src/components/fields/field-wrapper.tsx +0 -52
  165. package/src/components/fields/index.ts +0 -66
  166. package/src/components/fields/json-field.tsx +0 -440
  167. package/src/components/fields/locale-badge.tsx +0 -15
  168. package/src/components/fields/number-field.tsx +0 -57
  169. package/src/components/fields/password-field.tsx +0 -51
  170. package/src/components/fields/relation-field.tsx +0 -243
  171. package/src/components/fields/relation-picker.tsx +0 -402
  172. package/src/components/fields/relation-select.tsx +0 -327
  173. package/src/components/fields/rich-text-editor/index.tsx +0 -1337
  174. package/src/components/fields/select-field.tsx +0 -61
  175. package/src/components/fields/switch-field.tsx +0 -47
  176. package/src/components/fields/text-field.tsx +0 -55
  177. package/src/components/fields/textarea-field.tsx +0 -55
  178. package/src/components/index.ts +0 -40
  179. package/src/components/primitives/checkbox-input.tsx +0 -193
  180. package/src/components/primitives/date-input.tsx +0 -401
  181. package/src/components/primitives/index.ts +0 -24
  182. package/src/components/primitives/number-input.tsx +0 -132
  183. package/src/components/primitives/select-input.tsx +0 -296
  184. package/src/components/primitives/tag-input.tsx +0 -200
  185. package/src/components/primitives/text-input.tsx +0 -49
  186. package/src/components/primitives/textarea-input.tsx +0 -46
  187. package/src/components/primitives/toggle-input.tsx +0 -36
  188. package/src/components/primitives/types.ts +0 -235
  189. package/src/components/ui/accordion.tsx +0 -72
  190. package/src/components/ui/avatar.tsx +0 -106
  191. package/src/components/ui/badge.tsx +0 -48
  192. package/src/components/ui/button.tsx +0 -53
  193. package/src/components/ui/card.tsx +0 -94
  194. package/src/components/ui/checkbox.tsx +0 -27
  195. package/src/components/ui/combobox.tsx +0 -290
  196. package/src/components/ui/dialog.tsx +0 -151
  197. package/src/components/ui/dropdown-menu.tsx +0 -254
  198. package/src/components/ui/field.tsx +0 -227
  199. package/src/components/ui/input-group.tsx +0 -149
  200. package/src/components/ui/input.tsx +0 -20
  201. package/src/components/ui/label.tsx +0 -18
  202. package/src/components/ui/popover.tsx +0 -88
  203. package/src/components/ui/scroll-area.tsx +0 -53
  204. package/src/components/ui/select.tsx +0 -192
  205. package/src/components/ui/separator.tsx +0 -23
  206. package/src/components/ui/sheet.tsx +0 -127
  207. package/src/components/ui/sidebar.tsx +0 -723
  208. package/src/components/ui/skeleton.tsx +0 -13
  209. package/src/components/ui/spinner.tsx +0 -10
  210. package/src/components/ui/switch.tsx +0 -32
  211. package/src/components/ui/table.tsx +0 -99
  212. package/src/components/ui/tabs.tsx +0 -82
  213. package/src/components/ui/textarea.tsx +0 -18
  214. package/src/components/ui/tooltip.tsx +0 -70
  215. package/src/config/component-registry.ts +0 -190
  216. package/src/config/index.ts +0 -1099
  217. package/src/hooks/README.md +0 -269
  218. package/src/hooks/admin-provider.tsx +0 -110
  219. package/src/hooks/index.ts +0 -41
  220. package/src/hooks/store.ts +0 -248
  221. package/src/hooks/use-auth.ts +0 -168
  222. package/src/hooks/use-collection-db.ts +0 -209
  223. package/src/hooks/use-collection.ts +0 -156
  224. package/src/hooks/use-global.ts +0 -69
  225. package/src/hooks/use-mobile.ts +0 -21
  226. package/src/lib/utils.ts +0 -6
  227. package/src/styles/index.css +0 -340
  228. package/src/utils/index.ts +0 -6
  229. package/src/views/auth/auth-layout.tsx +0 -77
  230. package/src/views/auth/forgot-password-form.tsx +0 -192
  231. package/src/views/auth/index.ts +0 -21
  232. package/src/views/auth/login-form.tsx +0 -229
  233. package/src/views/auth/reset-password-form.tsx +0 -232
  234. package/src/views/collection/auto-form-fields.tsx +0 -982
  235. package/src/views/collection/collection-form.tsx +0 -186
  236. package/src/views/collection/collection-list.tsx +0 -223
  237. package/src/views/collection/form-field.tsx +0 -52
  238. package/src/views/collection/index.ts +0 -15
  239. package/src/views/common/index.ts +0 -8
  240. package/src/views/common/locale-switcher.tsx +0 -45
  241. package/src/views/common/version-history.tsx +0 -406
  242. package/src/views/index.ts +0 -25
  243. package/src/views/layout/admin-layout.tsx +0 -117
  244. package/src/views/layout/admin-router.tsx +0 -206
  245. package/src/views/layout/admin-sidebar.tsx +0 -185
  246. package/src/views/layout/index.ts +0 -12
  247. package/tsconfig.json +0 -13
  248. package/tsconfig.tsbuildinfo +0 -1
  249. package/tsdown.config.ts +0 -13
  250. package/vitest.config.ts +0 -29
@@ -1,229 +0,0 @@
1
- /**
2
- * Login Form - email/password authentication
3
- */
4
-
5
- import * as React from "react";
6
- import { useForm } from "react-hook-form";
7
- import { Envelope, Lock, SpinnerGap } from "@phosphor-icons/react";
8
- import { Button } from "../../components/ui/button";
9
- import { Input } from "../../components/ui/input";
10
- import {
11
- Field,
12
- FieldContent,
13
- FieldDescription,
14
- FieldError,
15
- FieldGroup,
16
- FieldLabel,
17
- } from "../../components/ui/field";
18
- import { cn } from "../../lib/utils";
19
-
20
- export type LoginFormValues = {
21
- email: string;
22
- password: string;
23
- rememberMe?: boolean;
24
- };
25
-
26
- export type LoginFormProps = {
27
- /** Called when form is submitted with valid data */
28
- onSubmit: (values: LoginFormValues) => Promise<void>;
29
- /** Called when sign up link is clicked */
30
- onSignUpClick?: () => void;
31
- /** Called when forgot password link is clicked */
32
- onForgotPasswordClick?: () => void;
33
- /** Show remember me checkbox */
34
- showRememberMe?: boolean;
35
- /** Show sign up link */
36
- showSignUp?: boolean;
37
- /** Show forgot password link */
38
- showForgotPassword?: boolean;
39
- /** Default values */
40
- defaultValues?: Partial<LoginFormValues>;
41
- /** Additional class name */
42
- className?: string;
43
- /** Error message from auth */
44
- error?: string | null;
45
- };
46
-
47
- /**
48
- * Login form with email and password fields
49
- *
50
- * @example
51
- * ```tsx
52
- * const authClient = createAdminAuthClient<typeof cms>({ baseURL: '...' })
53
- *
54
- * function LoginPage() {
55
- * const [error, setError] = useState<string | null>(null)
56
- *
57
- * const handleLogin = async (values: LoginFormValues) => {
58
- * const result = await authClient.signIn.email({
59
- * email: values.email,
60
- * password: values.password,
61
- * })
62
- * if (result.error) {
63
- * setError(result.error.message)
64
- * }
65
- * }
66
- *
67
- * return (
68
- * <AuthLayout title="Sign in">
69
- * <LoginForm onSubmit={handleLogin} error={error} />
70
- * </AuthLayout>
71
- * )
72
- * }
73
- * ```
74
- */
75
- export function LoginForm({
76
- onSubmit,
77
- onSignUpClick,
78
- onForgotPasswordClick,
79
- showRememberMe = false,
80
- showSignUp = true,
81
- showForgotPassword = true,
82
- defaultValues,
83
- className,
84
- error,
85
- }: LoginFormProps) {
86
- const {
87
- register,
88
- handleSubmit,
89
- formState: { errors, isSubmitting },
90
- } = useForm<LoginFormValues>({
91
- defaultValues: {
92
- email: "",
93
- password: "",
94
- rememberMe: false,
95
- ...defaultValues,
96
- },
97
- });
98
-
99
- const handleFormSubmit = handleSubmit(async (values) => {
100
- await onSubmit(values);
101
- });
102
-
103
- return (
104
- <form onSubmit={handleFormSubmit} className={cn("space-y-4", className)}>
105
- <FieldGroup>
106
- {/* Email Field */}
107
- <Field data-invalid={!!errors.email}>
108
- <FieldLabel htmlFor="email">Email</FieldLabel>
109
- <FieldContent>
110
- <div className="relative">
111
- <Envelope
112
- className="text-muted-foreground absolute left-2 top-1/2 size-4 -translate-y-1/2"
113
- weight="duotone"
114
- />
115
- <Input
116
- id="email"
117
- type="email"
118
- placeholder="you@example.com"
119
- className="pl-8"
120
- autoComplete="email"
121
- aria-invalid={!!errors.email}
122
- {...register("email", {
123
- required: "Email is required",
124
- pattern: {
125
- value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
126
- message: "Invalid email address",
127
- },
128
- })}
129
- />
130
- </div>
131
- <FieldError>{errors.email?.message}</FieldError>
132
- </FieldContent>
133
- </Field>
134
-
135
- {/* Password Field */}
136
- <Field data-invalid={!!errors.password}>
137
- <FieldLabel htmlFor="password">Password</FieldLabel>
138
- <FieldContent>
139
- <div className="relative">
140
- <Lock
141
- className="text-muted-foreground absolute left-2 top-1/2 size-4 -translate-y-1/2"
142
- weight="duotone"
143
- />
144
- <Input
145
- id="password"
146
- type="password"
147
- placeholder="Enter your password"
148
- className="pl-8"
149
- autoComplete="current-password"
150
- aria-invalid={!!errors.password}
151
- {...register("password", {
152
- required: "Password is required",
153
- minLength: {
154
- value: 6,
155
- message: "Password must be at least 6 characters",
156
- },
157
- })}
158
- />
159
- </div>
160
- <FieldError>{errors.password?.message}</FieldError>
161
- </FieldContent>
162
- </Field>
163
-
164
- {/* Remember Me & Forgot Password */}
165
- {(showRememberMe || showForgotPassword) && (
166
- <div className="flex items-center justify-between">
167
- {showRememberMe && (
168
- <label className="text-muted-foreground flex items-center gap-2 text-xs">
169
- <input
170
- type="checkbox"
171
- className="rounded border-gray-300"
172
- {...register("rememberMe")}
173
- />
174
- Remember me
175
- </label>
176
- )}
177
- {showForgotPassword && (
178
- <button
179
- type="button"
180
- onClick={onForgotPasswordClick}
181
- className="text-primary text-xs hover:underline"
182
- >
183
- Forgot password?
184
- </button>
185
- )}
186
- </div>
187
- )}
188
- </FieldGroup>
189
-
190
- {/* Error Message */}
191
- {error && (
192
- <div className="bg-destructive/10 text-destructive rounded-md p-3 text-xs">
193
- {error}
194
- </div>
195
- )}
196
-
197
- {/* Submit Button */}
198
- <Button
199
- type="submit"
200
- className="w-full"
201
- size="lg"
202
- disabled={isSubmitting}
203
- >
204
- {isSubmitting ? (
205
- <>
206
- <SpinnerGap className="animate-spin" weight="bold" />
207
- Signing in...
208
- </>
209
- ) : (
210
- "Sign in"
211
- )}
212
- </Button>
213
-
214
- {/* Sign Up Link */}
215
- {showSignUp && (
216
- <p className="text-muted-foreground text-center text-xs">
217
- Don't have an account?{" "}
218
- <button
219
- type="button"
220
- onClick={onSignUpClick}
221
- className="text-primary hover:underline"
222
- >
223
- Sign up
224
- </button>
225
- </p>
226
- )}
227
- </form>
228
- );
229
- }
@@ -1,232 +0,0 @@
1
- /**
2
- * Reset Password Form - set new password with token
3
- */
4
-
5
- import * as React from "react";
6
- import { useForm } from "react-hook-form";
7
- import { Lock, SpinnerGap, CheckCircle } from "@phosphor-icons/react";
8
- import { Button } from "../../components/ui/button";
9
- import { Input } from "../../components/ui/input";
10
- import {
11
- Field,
12
- FieldContent,
13
- FieldDescription,
14
- FieldError,
15
- FieldGroup,
16
- FieldLabel,
17
- } from "../../components/ui/field";
18
- import { cn } from "../../lib/utils";
19
-
20
- export type ResetPasswordFormValues = {
21
- password: string;
22
- confirmPassword: string;
23
- };
24
-
25
- export type ResetPasswordFormProps = {
26
- /** Reset token from URL */
27
- token: string;
28
- /** Called when form is submitted with valid data */
29
- onSubmit: (
30
- values: ResetPasswordFormValues & { token: string },
31
- ) => Promise<void>;
32
- /** Called when back to login link is clicked */
33
- onBackToLoginClick?: () => void;
34
- /** Minimum password length */
35
- minPasswordLength?: number;
36
- /** Additional class name */
37
- className?: string;
38
- /** Error message from auth */
39
- error?: string | null;
40
- };
41
-
42
- /**
43
- * Reset password form with password confirmation
44
- *
45
- * @example
46
- * ```tsx
47
- * const authClient = createAdminAuthClient<typeof cms>({ baseURL: '...' })
48
- *
49
- * function ResetPasswordPage() {
50
- * const token = useSearchParams().get('token')
51
- * const [error, setError] = useState<string | null>(null)
52
- *
53
- * const handleSubmit = async (values) => {
54
- * const result = await authClient.resetPassword({
55
- * token: values.token,
56
- * newPassword: values.password,
57
- * })
58
- * if (result.error) {
59
- * setError(result.error.message)
60
- * }
61
- * }
62
- *
63
- * return (
64
- * <AuthLayout title="Reset password">
65
- * <ResetPasswordForm token={token} onSubmit={handleSubmit} error={error} />
66
- * </AuthLayout>
67
- * )
68
- * }
69
- * ```
70
- */
71
- export function ResetPasswordForm({
72
- token,
73
- onSubmit,
74
- onBackToLoginClick,
75
- minPasswordLength = 8,
76
- className,
77
- error,
78
- }: ResetPasswordFormProps) {
79
- const [isSuccess, setIsSuccess] = React.useState(false);
80
-
81
- const {
82
- register,
83
- handleSubmit,
84
- watch,
85
- formState: { errors, isSubmitting },
86
- } = useForm<ResetPasswordFormValues>({
87
- defaultValues: {
88
- password: "",
89
- confirmPassword: "",
90
- },
91
- });
92
-
93
- const password = watch("password");
94
-
95
- const handleFormSubmit = handleSubmit(async (values) => {
96
- await onSubmit({ ...values, token });
97
- if (!error) {
98
- setIsSuccess(true);
99
- }
100
- });
101
-
102
- // Success state
103
- if (isSuccess) {
104
- return (
105
- <div className={cn("space-y-4 text-center", className)}>
106
- <div className="bg-primary/10 mx-auto flex size-12 items-center justify-center rounded-full">
107
- <CheckCircle className="text-primary size-6" weight="duotone" />
108
- </div>
109
- <div className="space-y-2">
110
- <h3 className="text-sm font-medium">Password reset successful</h3>
111
- <p className="text-muted-foreground text-xs">
112
- Your password has been reset successfully. You can now sign in with
113
- your new password.
114
- </p>
115
- </div>
116
- <Button
117
- type="button"
118
- className="w-full"
119
- size="lg"
120
- onClick={onBackToLoginClick}
121
- >
122
- Sign in
123
- </Button>
124
- </div>
125
- );
126
- }
127
-
128
- return (
129
- <form onSubmit={handleFormSubmit} className={cn("space-y-4", className)}>
130
- <p className="text-muted-foreground text-xs">
131
- Enter your new password below.
132
- </p>
133
-
134
- <FieldGroup>
135
- {/* Password Field */}
136
- <Field data-invalid={!!errors.password}>
137
- <FieldLabel htmlFor="password">New password</FieldLabel>
138
- <FieldContent>
139
- <div className="relative">
140
- <Lock
141
- className="text-muted-foreground absolute left-2 top-1/2 size-4 -translate-y-1/2"
142
- weight="duotone"
143
- />
144
- <Input
145
- id="password"
146
- type="password"
147
- placeholder="Enter new password"
148
- className="pl-8"
149
- autoComplete="new-password"
150
- aria-invalid={!!errors.password}
151
- {...register("password", {
152
- required: "Password is required",
153
- minLength: {
154
- value: minPasswordLength,
155
- message: `Password must be at least ${minPasswordLength} characters`,
156
- },
157
- })}
158
- />
159
- </div>
160
- <FieldDescription>
161
- Must be at least {minPasswordLength} characters
162
- </FieldDescription>
163
- <FieldError>{errors.password?.message}</FieldError>
164
- </FieldContent>
165
- </Field>
166
-
167
- {/* Confirm Password Field */}
168
- <Field data-invalid={!!errors.confirmPassword}>
169
- <FieldLabel htmlFor="confirmPassword">Confirm password</FieldLabel>
170
- <FieldContent>
171
- <div className="relative">
172
- <Lock
173
- className="text-muted-foreground absolute left-2 top-1/2 size-4 -translate-y-1/2"
174
- weight="duotone"
175
- />
176
- <Input
177
- id="confirmPassword"
178
- type="password"
179
- placeholder="Confirm new password"
180
- className="pl-8"
181
- autoComplete="new-password"
182
- aria-invalid={!!errors.confirmPassword}
183
- {...register("confirmPassword", {
184
- required: "Please confirm your password",
185
- validate: (value) =>
186
- value === password || "Passwords do not match",
187
- })}
188
- />
189
- </div>
190
- <FieldError>{errors.confirmPassword?.message}</FieldError>
191
- </FieldContent>
192
- </Field>
193
- </FieldGroup>
194
-
195
- {/* Error Message */}
196
- {error && (
197
- <div className="bg-destructive/10 text-destructive rounded-md p-3 text-xs">
198
- {error}
199
- </div>
200
- )}
201
-
202
- {/* Submit Button */}
203
- <Button
204
- type="submit"
205
- className="w-full"
206
- size="lg"
207
- disabled={isSubmitting}
208
- >
209
- {isSubmitting ? (
210
- <>
211
- <SpinnerGap className="animate-spin" weight="bold" />
212
- Resetting...
213
- </>
214
- ) : (
215
- "Reset password"
216
- )}
217
- </Button>
218
-
219
- {/* Back to Login Link */}
220
- <p className="text-muted-foreground text-center text-xs">
221
- Remember your password?{" "}
222
- <button
223
- type="button"
224
- onClick={onBackToLoginClick}
225
- className="text-primary hover:underline"
226
- >
227
- Back to login
228
- </button>
229
- </p>
230
- </form>
231
- );
232
- }