@lalternative/auth 0.6.0 → 0.8.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.
- package/dist/client.d.ts +1 -1
- package/dist/index.d.ts +59 -15
- package/dist/index.js +454 -247
- package/dist/index.js.map +1 -1
- package/dist/{invitation-aZz_6M7B.d.ts → invitation-CfZAFUdJ.d.ts} +1 -1
- package/dist/server.d.ts +3 -3
- package/dist/{types-BEldQPou.d.ts → types-Dmjo9lEL.d.ts} +112 -11
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -21,6 +21,7 @@ function AuthField({
|
|
|
21
21
|
hint,
|
|
22
22
|
description,
|
|
23
23
|
invalid = false,
|
|
24
|
+
fieldClassName = "border-foreground/25 bg-background",
|
|
24
25
|
...props
|
|
25
26
|
}) {
|
|
26
27
|
const id = useId();
|
|
@@ -50,13 +51,13 @@ function AuthField({
|
|
|
50
51
|
"aria-invalid": invalid || void 0,
|
|
51
52
|
"aria-describedby": descriptionId,
|
|
52
53
|
className: [
|
|
53
|
-
"h-[52px] w-full rounded-
|
|
54
|
+
"h-[52px] w-full rounded-lg border px-4 text-base",
|
|
54
55
|
"sm:h-11 sm:text-sm",
|
|
55
56
|
isPassword ? "pr-12" : "",
|
|
56
57
|
"text-foreground placeholder:text-muted-foreground/70",
|
|
57
58
|
"transition-[border-color,box-shadow] duration-150 ease-out",
|
|
58
59
|
"focus-visible:outline-none focus-visible:ring-[3px]",
|
|
59
|
-
invalid ? "border-destructive focus-visible:border-destructive focus-visible:ring-destructive/20" :
|
|
60
|
+
invalid ? "border-destructive bg-background focus-visible:border-destructive focus-visible:ring-destructive/20" : `${fieldClassName} focus-visible:border-ring focus-visible:ring-ring/15`,
|
|
60
61
|
"disabled:cursor-not-allowed disabled:opacity-60"
|
|
61
62
|
].filter(Boolean).join(" ")
|
|
62
63
|
}
|
|
@@ -105,7 +106,8 @@ function AuthSubmit({
|
|
|
105
106
|
pending = false,
|
|
106
107
|
disabled = false,
|
|
107
108
|
pendingLabel,
|
|
108
|
-
children
|
|
109
|
+
children,
|
|
110
|
+
className = "bg-primary text-primary-foreground hover:bg-primary/90"
|
|
109
111
|
}) {
|
|
110
112
|
return /* @__PURE__ */ jsxs2(
|
|
111
113
|
"button",
|
|
@@ -114,10 +116,11 @@ function AuthSubmit({
|
|
|
114
116
|
disabled: disabled || pending,
|
|
115
117
|
"aria-busy": pending || void 0,
|
|
116
118
|
className: [
|
|
117
|
-
"relative flex h-[52px] w-full items-center justify-center rounded-
|
|
118
|
-
"
|
|
119
|
+
"relative flex h-[52px] w-full items-center justify-center rounded-lg sm:h-11",
|
|
120
|
+
"text-base font-medium sm:text-sm",
|
|
121
|
+
className,
|
|
119
122
|
"shadow-sm transition-[background-color,transform,box-shadow] duration-150 ease-out",
|
|
120
|
-
"
|
|
123
|
+
"active:translate-y-px",
|
|
121
124
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
122
125
|
"disabled:pointer-events-none disabled:opacity-55"
|
|
123
126
|
].join(" "),
|
|
@@ -138,8 +141,25 @@ function AuthSubmit({
|
|
|
138
141
|
// src/components/login-form.tsx
|
|
139
142
|
import { useState as useState2 } from "react";
|
|
140
143
|
|
|
144
|
+
// src/components/auth-alert.tsx
|
|
145
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
146
|
+
function AuthAlert({ children, tone = "error" }) {
|
|
147
|
+
return /* @__PURE__ */ jsx3(
|
|
148
|
+
"div",
|
|
149
|
+
{
|
|
150
|
+
role: tone === "error" ? "alert" : "status",
|
|
151
|
+
"aria-live": tone === "error" ? "assertive" : "polite",
|
|
152
|
+
className: children ? [
|
|
153
|
+
"rounded-lg border px-3.5 py-3 text-sm leading-snug",
|
|
154
|
+
tone === "error" ? "border-destructive/25 bg-destructive/10 text-destructive" : "border-emerald-500/25 bg-emerald-500/10 text-emerald-700 dark:text-emerald-400"
|
|
155
|
+
].join(" ") : void 0,
|
|
156
|
+
children
|
|
157
|
+
}
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
141
161
|
// src/components/social-buttons.tsx
|
|
142
|
-
import { jsx as
|
|
162
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
143
163
|
var LABELS = {
|
|
144
164
|
google: "Continuer avec Google",
|
|
145
165
|
github: "Continuer avec GitHub"
|
|
@@ -155,58 +175,65 @@ function SocialButtons({
|
|
|
155
175
|
const copy = { ...LABELS, ...labels };
|
|
156
176
|
return /* @__PURE__ */ jsxs3("div", { className: "space-y-4", children: [
|
|
157
177
|
/* @__PURE__ */ jsxs3("div", { "aria-hidden": "true", className: "flex items-center gap-3", children: [
|
|
158
|
-
/* @__PURE__ */
|
|
159
|
-
/* @__PURE__ */
|
|
160
|
-
/* @__PURE__ */
|
|
178
|
+
/* @__PURE__ */ jsx4("span", { className: "h-px flex-1 bg-border" }),
|
|
179
|
+
/* @__PURE__ */ jsx4("span", { className: "text-[11px] uppercase tracking-[0.14em] text-muted-foreground", children: separator }),
|
|
180
|
+
/* @__PURE__ */ jsx4("span", { className: "h-px flex-1 bg-border" })
|
|
161
181
|
] }),
|
|
162
|
-
/* @__PURE__ */
|
|
163
|
-
"
|
|
182
|
+
/* @__PURE__ */ jsx4(
|
|
183
|
+
"div",
|
|
164
184
|
{
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
185
|
+
className: providers.length > 1 ? "grid gap-2.5 sm:grid-cols-2" : "grid gap-2.5",
|
|
186
|
+
children: providers.map((provider) => /* @__PURE__ */ jsxs3(
|
|
187
|
+
"button",
|
|
188
|
+
{
|
|
189
|
+
type: "button",
|
|
190
|
+
onClick: () => onSelect(provider),
|
|
191
|
+
disabled,
|
|
192
|
+
"aria-label": copy[provider] ?? provider,
|
|
193
|
+
className: [
|
|
194
|
+
"flex h-[52px] w-full items-center justify-center gap-2.5 rounded-lg sm:h-11",
|
|
195
|
+
"border border-foreground/25 bg-background text-base font-medium text-foreground sm:text-sm",
|
|
196
|
+
"transition-[background-color,border-color,transform] duration-150 ease-out",
|
|
197
|
+
"hover:border-foreground/20 hover:bg-accent active:translate-y-px",
|
|
198
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
199
|
+
"disabled:pointer-events-none disabled:opacity-55"
|
|
200
|
+
].join(" "),
|
|
201
|
+
children: [
|
|
202
|
+
/* @__PURE__ */ jsx4(ProviderMark, { provider }),
|
|
203
|
+
/* @__PURE__ */ jsx4("span", { className: providers.length > 1 ? "sm:hidden" : "", children: copy[provider] ?? provider })
|
|
204
|
+
]
|
|
205
|
+
},
|
|
206
|
+
provider
|
|
207
|
+
))
|
|
208
|
+
}
|
|
209
|
+
)
|
|
183
210
|
] });
|
|
184
211
|
}
|
|
185
212
|
function ProviderMark({ provider }) {
|
|
186
213
|
if (provider === "google") {
|
|
187
214
|
return /* @__PURE__ */ jsxs3("svg", { width: "17", height: "17", viewBox: "0 0 18 18", "aria-hidden": "true", children: [
|
|
188
|
-
/* @__PURE__ */
|
|
215
|
+
/* @__PURE__ */ jsx4(
|
|
189
216
|
"path",
|
|
190
217
|
{
|
|
191
218
|
fill: "#4285F4",
|
|
192
219
|
d: "M17.64 9.2c0-.64-.06-1.25-.16-1.84H9v3.48h4.84a4.14 4.14 0 0 1-1.8 2.72v2.26h2.92c1.7-1.57 2.68-3.88 2.68-6.62Z"
|
|
193
220
|
}
|
|
194
221
|
),
|
|
195
|
-
/* @__PURE__ */
|
|
222
|
+
/* @__PURE__ */ jsx4(
|
|
196
223
|
"path",
|
|
197
224
|
{
|
|
198
225
|
fill: "#34A853",
|
|
199
226
|
d: "M9 18c2.43 0 4.47-.8 5.96-2.18l-2.92-2.26c-.8.54-1.84.86-3.04.86-2.34 0-4.32-1.58-5.02-3.7H.96v2.33A9 9 0 0 0 9 18Z"
|
|
200
227
|
}
|
|
201
228
|
),
|
|
202
|
-
/* @__PURE__ */
|
|
229
|
+
/* @__PURE__ */ jsx4(
|
|
203
230
|
"path",
|
|
204
231
|
{
|
|
205
232
|
fill: "#FBBC05",
|
|
206
233
|
d: "M3.98 10.72a5.4 5.4 0 0 1 0-3.44V4.95H.96a9 9 0 0 0 0 8.1l3.02-2.33Z"
|
|
207
234
|
}
|
|
208
235
|
),
|
|
209
|
-
/* @__PURE__ */
|
|
236
|
+
/* @__PURE__ */ jsx4(
|
|
210
237
|
"path",
|
|
211
238
|
{
|
|
212
239
|
fill: "#EA4335",
|
|
@@ -215,11 +242,11 @@ function ProviderMark({ provider }) {
|
|
|
215
242
|
)
|
|
216
243
|
] });
|
|
217
244
|
}
|
|
218
|
-
return /* @__PURE__ */
|
|
245
|
+
return /* @__PURE__ */ jsx4("svg", { width: "17", height: "17", viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx4("path", { d: "M8 0a8 8 0 0 0-2.53 15.59c.4.07.55-.17.55-.38l-.01-1.49c-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82a7.4 7.4 0 0 1 4 0c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48l-.01 2.2c0 .21.15.46.55.38A8 8 0 0 0 8 0Z" }) });
|
|
219
246
|
}
|
|
220
247
|
|
|
221
248
|
// src/components/login-form.tsx
|
|
222
|
-
import { jsx as
|
|
249
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
223
250
|
var DEFAULTS = {
|
|
224
251
|
title: "Connexion",
|
|
225
252
|
subtitle: "Content de te revoir. Entre tes identifiants pour continuer.",
|
|
@@ -248,13 +275,18 @@ function LoginForm({
|
|
|
248
275
|
socialProviders = [],
|
|
249
276
|
coreTokenUrl = "/api/auth/core-token",
|
|
250
277
|
labels,
|
|
278
|
+
submitClassName,
|
|
279
|
+
fieldClassName,
|
|
280
|
+
error: externalError,
|
|
251
281
|
authClient
|
|
252
282
|
}) {
|
|
253
283
|
const t = { ...DEFAULTS, ...labels };
|
|
254
284
|
const [email, setEmail] = useState2("");
|
|
255
285
|
const [password, setPassword] = useState2("");
|
|
256
|
-
const [
|
|
286
|
+
const [ownError, setOwnError] = useState2();
|
|
257
287
|
const [isPending, setIsPending] = useState2(false);
|
|
288
|
+
const error = ownError ?? externalError;
|
|
289
|
+
const setError = setOwnError;
|
|
258
290
|
const handleSubmit = async (e) => {
|
|
259
291
|
e.preventDefault();
|
|
260
292
|
if (!email.trim()) {
|
|
@@ -300,21 +332,10 @@ function LoginForm({
|
|
|
300
332
|
);
|
|
301
333
|
}
|
|
302
334
|
};
|
|
303
|
-
return /* @__PURE__ */ jsxs4("div", { className: "space-y-
|
|
304
|
-
/* @__PURE__ */
|
|
305
|
-
/* @__PURE__ */ jsx4("h1", { className: "text-[26px] font-semibold leading-tight tracking-[-0.02em] text-foreground sm:text-2xl", children: t.title }),
|
|
306
|
-
/* @__PURE__ */ jsx4("p", { className: "text-balance text-sm leading-relaxed text-muted-foreground", children: t.subtitle })
|
|
307
|
-
] }),
|
|
308
|
-
error && /* @__PURE__ */ jsx4(
|
|
309
|
-
"div",
|
|
310
|
-
{
|
|
311
|
-
role: "alert",
|
|
312
|
-
className: "rounded-xl border border-destructive/25 bg-destructive/10 px-3.5 py-3 text-sm leading-snug text-destructive",
|
|
313
|
-
children: error
|
|
314
|
-
}
|
|
315
|
-
),
|
|
335
|
+
return /* @__PURE__ */ jsxs4("div", { className: "space-y-6", children: [
|
|
336
|
+
/* @__PURE__ */ jsx5(AuthAlert, { children: error }),
|
|
316
337
|
/* @__PURE__ */ jsxs4("form", { onSubmit: handleSubmit, className: "space-y-5", noValidate: true, children: [
|
|
317
|
-
/* @__PURE__ */
|
|
338
|
+
/* @__PURE__ */ jsx5(
|
|
318
339
|
AuthField,
|
|
319
340
|
{
|
|
320
341
|
label: t.emailPlaceholder,
|
|
@@ -327,10 +348,11 @@ function LoginForm({
|
|
|
327
348
|
autoComplete: "email",
|
|
328
349
|
autoCapitalize: "none",
|
|
329
350
|
spellCheck: false,
|
|
330
|
-
invalid: !!error
|
|
351
|
+
invalid: !!error,
|
|
352
|
+
fieldClassName
|
|
331
353
|
}
|
|
332
354
|
),
|
|
333
|
-
/* @__PURE__ */
|
|
355
|
+
/* @__PURE__ */ jsx5(
|
|
334
356
|
AuthField,
|
|
335
357
|
{
|
|
336
358
|
label: t.passwordPlaceholder,
|
|
@@ -341,7 +363,8 @@ function LoginForm({
|
|
|
341
363
|
disabled: isPending,
|
|
342
364
|
autoComplete: "current-password",
|
|
343
365
|
invalid: !!error,
|
|
344
|
-
|
|
366
|
+
fieldClassName,
|
|
367
|
+
hint: /* @__PURE__ */ jsx5(
|
|
345
368
|
"a",
|
|
346
369
|
{
|
|
347
370
|
href: forgotPasswordUrl,
|
|
@@ -351,17 +374,18 @@ function LoginForm({
|
|
|
351
374
|
)
|
|
352
375
|
}
|
|
353
376
|
),
|
|
354
|
-
/* @__PURE__ */
|
|
377
|
+
/* @__PURE__ */ jsx5(
|
|
355
378
|
AuthSubmit,
|
|
356
379
|
{
|
|
357
380
|
pending: isPending,
|
|
358
381
|
disabled: !email.trim() || !password,
|
|
359
382
|
pendingLabel: t.submitPending,
|
|
383
|
+
className: submitClassName,
|
|
360
384
|
children: t.submit
|
|
361
385
|
}
|
|
362
386
|
)
|
|
363
387
|
] }),
|
|
364
|
-
/* @__PURE__ */
|
|
388
|
+
/* @__PURE__ */ jsx5(
|
|
365
389
|
SocialButtons,
|
|
366
390
|
{
|
|
367
391
|
providers: socialProviders,
|
|
@@ -372,7 +396,7 @@ function LoginForm({
|
|
|
372
396
|
/* @__PURE__ */ jsxs4("p", { className: "text-center text-sm text-muted-foreground", children: [
|
|
373
397
|
t.noAccount,
|
|
374
398
|
" ",
|
|
375
|
-
/* @__PURE__ */
|
|
399
|
+
/* @__PURE__ */ jsx5(
|
|
376
400
|
"a",
|
|
377
401
|
{
|
|
378
402
|
href: registerUrl,
|
|
@@ -383,10 +407,14 @@ function LoginForm({
|
|
|
383
407
|
] })
|
|
384
408
|
] });
|
|
385
409
|
}
|
|
410
|
+
LoginForm.defaults = {
|
|
411
|
+
title: DEFAULTS.title,
|
|
412
|
+
subtitle: DEFAULTS.subtitle
|
|
413
|
+
};
|
|
386
414
|
|
|
387
415
|
// src/components/register-form.tsx
|
|
388
416
|
import { useState as useState3 } from "react";
|
|
389
|
-
import { jsx as
|
|
417
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
390
418
|
var MIN_PASSWORD_LENGTH = 8;
|
|
391
419
|
var DEFAULTS2 = {
|
|
392
420
|
title: "Cr\xE9er un compte",
|
|
@@ -395,6 +423,8 @@ var DEFAULTS2 = {
|
|
|
395
423
|
emailPlaceholder: "Adresse e-mail",
|
|
396
424
|
passwordPlaceholder: "Mot de passe",
|
|
397
425
|
passwordHint: `Au moins ${MIN_PASSWORD_LENGTH} caract\xE8res.`,
|
|
426
|
+
confirmPlaceholder: "Confirme le mot de passe",
|
|
427
|
+
passwordMismatch: "Les deux mots de passe ne correspondent pas",
|
|
398
428
|
submit: "Cr\xE9er mon compte",
|
|
399
429
|
submitPending: "Cr\xE9ation\u2026",
|
|
400
430
|
haveAccount: "Tu as d\xE9j\xE0 un compte ?",
|
|
@@ -411,15 +441,22 @@ function RegisterForm({
|
|
|
411
441
|
socialCallbackUrl = "/",
|
|
412
442
|
socialProviders = [],
|
|
413
443
|
labels,
|
|
444
|
+
submitClassName,
|
|
445
|
+
fieldClassName,
|
|
446
|
+
error: externalError,
|
|
414
447
|
authClient
|
|
415
448
|
}) {
|
|
416
449
|
const t = { ...DEFAULTS2, ...labels };
|
|
417
450
|
const [name, setName] = useState3("");
|
|
418
451
|
const [email, setEmail] = useState3("");
|
|
419
452
|
const [password, setPassword] = useState3("");
|
|
420
|
-
const [
|
|
453
|
+
const [confirmPassword, setConfirmPassword] = useState3("");
|
|
454
|
+
const [ownError, setOwnError] = useState3();
|
|
421
455
|
const [isPending, setIsPending] = useState3(false);
|
|
456
|
+
const error = ownError ?? externalError;
|
|
457
|
+
const setError = setOwnError;
|
|
422
458
|
const tooShort = password.length > 0 && password.length < MIN_PASSWORD_LENGTH;
|
|
459
|
+
const mismatch = confirmPassword.length > 0 && confirmPassword !== password;
|
|
423
460
|
const handleSubmit = async (e) => {
|
|
424
461
|
e.preventDefault();
|
|
425
462
|
if (!name.trim()) {
|
|
@@ -434,6 +471,10 @@ function RegisterForm({
|
|
|
434
471
|
setError(t.passwordTooShort);
|
|
435
472
|
return;
|
|
436
473
|
}
|
|
474
|
+
if (password !== confirmPassword) {
|
|
475
|
+
setError(t.passwordMismatch);
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
437
478
|
setError(void 0);
|
|
438
479
|
setIsPending(true);
|
|
439
480
|
try {
|
|
@@ -464,21 +505,10 @@ function RegisterForm({
|
|
|
464
505
|
setError(err instanceof Error ? err.message : t.signUpFailed);
|
|
465
506
|
}
|
|
466
507
|
};
|
|
467
|
-
return /* @__PURE__ */ jsxs5("div", { className: "space-y-
|
|
468
|
-
/* @__PURE__ */
|
|
469
|
-
/* @__PURE__ */ jsx5("h1", { className: "text-[26px] font-semibold leading-tight tracking-[-0.02em] text-foreground sm:text-2xl", children: t.title }),
|
|
470
|
-
/* @__PURE__ */ jsx5("p", { className: "text-balance text-sm leading-relaxed text-muted-foreground", children: t.subtitle })
|
|
471
|
-
] }),
|
|
472
|
-
error && /* @__PURE__ */ jsx5(
|
|
473
|
-
"div",
|
|
474
|
-
{
|
|
475
|
-
role: "alert",
|
|
476
|
-
className: "rounded-xl border border-destructive/25 bg-destructive/10 px-3.5 py-3 text-sm leading-snug text-destructive",
|
|
477
|
-
children: error
|
|
478
|
-
}
|
|
479
|
-
),
|
|
508
|
+
return /* @__PURE__ */ jsxs5("div", { className: "space-y-6", children: [
|
|
509
|
+
/* @__PURE__ */ jsx6(AuthAlert, { children: error }),
|
|
480
510
|
/* @__PURE__ */ jsxs5("form", { onSubmit: handleSubmit, className: "space-y-5", noValidate: true, children: [
|
|
481
|
-
/* @__PURE__ */
|
|
511
|
+
/* @__PURE__ */ jsx6(
|
|
482
512
|
AuthField,
|
|
483
513
|
{
|
|
484
514
|
label: t.namePlaceholder,
|
|
@@ -487,10 +517,11 @@ function RegisterForm({
|
|
|
487
517
|
onChange: (e) => setName(e.target.value),
|
|
488
518
|
required: true,
|
|
489
519
|
disabled: isPending,
|
|
490
|
-
autoComplete: "name"
|
|
520
|
+
autoComplete: "name",
|
|
521
|
+
fieldClassName
|
|
491
522
|
}
|
|
492
523
|
),
|
|
493
|
-
/* @__PURE__ */
|
|
524
|
+
/* @__PURE__ */ jsx6(
|
|
494
525
|
AuthField,
|
|
495
526
|
{
|
|
496
527
|
label: t.emailPlaceholder,
|
|
@@ -502,10 +533,11 @@ function RegisterForm({
|
|
|
502
533
|
disabled: isPending,
|
|
503
534
|
autoComplete: "email",
|
|
504
535
|
autoCapitalize: "none",
|
|
505
|
-
spellCheck: false
|
|
536
|
+
spellCheck: false,
|
|
537
|
+
fieldClassName
|
|
506
538
|
}
|
|
507
539
|
),
|
|
508
|
-
/* @__PURE__ */
|
|
540
|
+
/* @__PURE__ */ jsx6(
|
|
509
541
|
AuthField,
|
|
510
542
|
{
|
|
511
543
|
label: t.passwordPlaceholder,
|
|
@@ -516,13 +548,36 @@ function RegisterForm({
|
|
|
516
548
|
disabled: isPending,
|
|
517
549
|
autoComplete: "new-password",
|
|
518
550
|
description: t.passwordHint,
|
|
519
|
-
invalid: tooShort
|
|
551
|
+
invalid: tooShort,
|
|
552
|
+
fieldClassName
|
|
520
553
|
}
|
|
521
554
|
),
|
|
522
|
-
/* @__PURE__ */
|
|
523
|
-
|
|
555
|
+
/* @__PURE__ */ jsx6(
|
|
556
|
+
AuthField,
|
|
557
|
+
{
|
|
558
|
+
label: t.confirmPlaceholder,
|
|
559
|
+
type: "password",
|
|
560
|
+
value: confirmPassword,
|
|
561
|
+
onChange: (e) => setConfirmPassword(e.target.value),
|
|
562
|
+
required: true,
|
|
563
|
+
disabled: isPending,
|
|
564
|
+
autoComplete: "new-password",
|
|
565
|
+
invalid: mismatch,
|
|
566
|
+
fieldClassName
|
|
567
|
+
}
|
|
568
|
+
),
|
|
569
|
+
/* @__PURE__ */ jsx6(
|
|
570
|
+
AuthSubmit,
|
|
571
|
+
{
|
|
572
|
+
pending: isPending,
|
|
573
|
+
pendingLabel: t.submitPending,
|
|
574
|
+
className: submitClassName,
|
|
575
|
+
children: t.submit
|
|
576
|
+
}
|
|
577
|
+
),
|
|
578
|
+
legal && /* @__PURE__ */ jsx6("p", { className: "text-center text-xs leading-relaxed text-muted-foreground", children: legal })
|
|
524
579
|
] }),
|
|
525
|
-
/* @__PURE__ */
|
|
580
|
+
/* @__PURE__ */ jsx6(
|
|
526
581
|
SocialButtons,
|
|
527
582
|
{
|
|
528
583
|
providers: socialProviders,
|
|
@@ -533,7 +588,7 @@ function RegisterForm({
|
|
|
533
588
|
/* @__PURE__ */ jsxs5("p", { className: "text-center text-sm text-muted-foreground", children: [
|
|
534
589
|
t.haveAccount,
|
|
535
590
|
" ",
|
|
536
|
-
/* @__PURE__ */
|
|
591
|
+
/* @__PURE__ */ jsx6(
|
|
537
592
|
"a",
|
|
538
593
|
{
|
|
539
594
|
href: loginUrl,
|
|
@@ -544,15 +599,92 @@ function RegisterForm({
|
|
|
544
599
|
] })
|
|
545
600
|
] });
|
|
546
601
|
}
|
|
602
|
+
RegisterForm.defaults = {
|
|
603
|
+
title: DEFAULTS2.title,
|
|
604
|
+
subtitle: DEFAULTS2.subtitle
|
|
605
|
+
};
|
|
547
606
|
|
|
548
607
|
// src/components/verify-email-form.tsx
|
|
549
608
|
import { useState as useState4 } from "react";
|
|
550
|
-
|
|
609
|
+
|
|
610
|
+
// src/components/auth-otp-field.tsx
|
|
611
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
612
|
+
var OTP_LENGTH = 6;
|
|
613
|
+
function AuthOtpField({
|
|
614
|
+
label,
|
|
615
|
+
value,
|
|
616
|
+
onChange,
|
|
617
|
+
disabled = false,
|
|
618
|
+
invalid = false,
|
|
619
|
+
id,
|
|
620
|
+
fieldClassName = "border-foreground/25 bg-background"
|
|
621
|
+
}) {
|
|
622
|
+
return /* @__PURE__ */ jsxs6("div", { className: "space-y-2", children: [
|
|
623
|
+
/* @__PURE__ */ jsx7(
|
|
624
|
+
"label",
|
|
625
|
+
{
|
|
626
|
+
htmlFor: id,
|
|
627
|
+
className: "block text-sm font-medium leading-none text-foreground",
|
|
628
|
+
children: label
|
|
629
|
+
}
|
|
630
|
+
),
|
|
631
|
+
/* @__PURE__ */ jsx7(
|
|
632
|
+
"input",
|
|
633
|
+
{
|
|
634
|
+
id,
|
|
635
|
+
type: "text",
|
|
636
|
+
inputMode: "numeric",
|
|
637
|
+
pattern: "[0-9]*",
|
|
638
|
+
maxLength: OTP_LENGTH,
|
|
639
|
+
value,
|
|
640
|
+
onChange: (e) => onChange(e.target.value.replace(/\D/g, "")),
|
|
641
|
+
required: true,
|
|
642
|
+
disabled,
|
|
643
|
+
autoComplete: "one-time-code",
|
|
644
|
+
"aria-invalid": invalid || void 0,
|
|
645
|
+
className: [
|
|
646
|
+
"h-[52px] w-full rounded-lg border px-4 sm:h-11",
|
|
647
|
+
"text-center font-mono text-lg tracking-[0.4em]",
|
|
648
|
+
"text-foreground",
|
|
649
|
+
"transition-[border-color,box-shadow] duration-150 ease-out",
|
|
650
|
+
"focus-visible:outline-none focus-visible:ring-[3px]",
|
|
651
|
+
invalid ? "border-destructive bg-background focus-visible:border-destructive focus-visible:ring-destructive/20" : `${fieldClassName} focus-visible:border-ring focus-visible:ring-ring/15`,
|
|
652
|
+
"disabled:cursor-not-allowed disabled:opacity-60"
|
|
653
|
+
].join(" ")
|
|
654
|
+
}
|
|
655
|
+
)
|
|
656
|
+
] });
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// src/components/verify-email-form.tsx
|
|
660
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
661
|
+
var DEFAULTS3 = {
|
|
662
|
+
title: "V\xE9rifie ton adresse",
|
|
663
|
+
subtitle: "Entre le code \xE0 6 chiffres envoy\xE9 \xE0",
|
|
664
|
+
subtitleNoEmail: "Entre le code \xE0 6 chiffres re\xE7u par e-mail.",
|
|
665
|
+
codePlaceholder: "Code de v\xE9rification",
|
|
666
|
+
submit: "V\xE9rifier",
|
|
667
|
+
submitPending: "V\xE9rification\u2026",
|
|
668
|
+
resend: "Renvoyer le code",
|
|
669
|
+
resendPending: "Envoi\u2026",
|
|
670
|
+
resent: "Un nouveau code vient de t'\xEAtre envoy\xE9.",
|
|
671
|
+
alreadyVerified: "Adresse d\xE9j\xE0 v\xE9rifi\xE9e ?",
|
|
672
|
+
login: "Se connecter",
|
|
673
|
+
codeRequired: "Entre le code \xE0 6 chiffres",
|
|
674
|
+
invalidCode: "Code invalide. R\xE9essaie.",
|
|
675
|
+
resendFailed: "L'envoi du code a \xE9chou\xE9",
|
|
676
|
+
missingEmail: "Adresse e-mail introuvable. Recommence l'inscription."
|
|
677
|
+
};
|
|
551
678
|
function VerifyEmailForm({
|
|
552
679
|
email,
|
|
553
680
|
onSuccess,
|
|
681
|
+
loginUrl = "/login",
|
|
682
|
+
labels,
|
|
683
|
+
submitClassName,
|
|
684
|
+
fieldClassName,
|
|
554
685
|
authClient
|
|
555
686
|
}) {
|
|
687
|
+
const t = { ...DEFAULTS3, ...labels };
|
|
556
688
|
const [otp, setOtp] = useState4("");
|
|
557
689
|
const [isVerifying, setIsVerifying] = useState4(false);
|
|
558
690
|
const [isResending, setIsResending] = useState4(false);
|
|
@@ -560,29 +692,29 @@ function VerifyEmailForm({
|
|
|
560
692
|
const [error, setError] = useState4();
|
|
561
693
|
const handleVerify = async (e) => {
|
|
562
694
|
e.preventDefault();
|
|
563
|
-
if (
|
|
564
|
-
setError(
|
|
695
|
+
if (otp.length < OTP_LENGTH) {
|
|
696
|
+
setError(t.codeRequired);
|
|
565
697
|
return;
|
|
566
698
|
}
|
|
567
699
|
setError(void 0);
|
|
700
|
+
setResendMessage(void 0);
|
|
568
701
|
setIsVerifying(true);
|
|
569
702
|
try {
|
|
570
703
|
const res = await authClient.emailOtp.verifyEmail({ email, otp });
|
|
571
|
-
console.log("[verify-email] response:", JSON.stringify(res?.data), "error:", JSON.stringify(res?.error));
|
|
572
704
|
if (res?.error) {
|
|
573
|
-
setError(res.error.message ??
|
|
705
|
+
setError(res.error.message ?? t.invalidCode);
|
|
574
706
|
return;
|
|
575
707
|
}
|
|
576
708
|
onSuccess?.();
|
|
577
709
|
} catch (err) {
|
|
578
|
-
setError(err instanceof Error ? err.message :
|
|
710
|
+
setError(err instanceof Error ? err.message : t.invalidCode);
|
|
579
711
|
} finally {
|
|
580
712
|
setIsVerifying(false);
|
|
581
713
|
}
|
|
582
714
|
};
|
|
583
715
|
const handleResend = async () => {
|
|
584
716
|
if (!email) {
|
|
585
|
-
setError(
|
|
717
|
+
setError(t.missingEmail);
|
|
586
718
|
return;
|
|
587
719
|
}
|
|
588
720
|
setError(void 0);
|
|
@@ -593,165 +725,203 @@ function VerifyEmailForm({
|
|
|
593
725
|
email,
|
|
594
726
|
type: "email-verification"
|
|
595
727
|
});
|
|
596
|
-
setResendMessage(
|
|
728
|
+
setResendMessage(t.resent);
|
|
597
729
|
} catch (err) {
|
|
598
|
-
setError(err instanceof Error ? err.message :
|
|
730
|
+
setError(err instanceof Error ? err.message : t.resendFailed);
|
|
599
731
|
} finally {
|
|
600
732
|
setIsResending(false);
|
|
601
733
|
}
|
|
602
734
|
};
|
|
603
|
-
return /* @__PURE__ */
|
|
604
|
-
/* @__PURE__ */
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
/* @__PURE__ */ jsx6("span", { className: "font-medium text-foreground", children: email })
|
|
610
|
-
] }) : "Enter the 6-digit code sent to your email" })
|
|
611
|
-
] }),
|
|
612
|
-
error && /* @__PURE__ */ jsx6("div", { className: "rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: error }),
|
|
613
|
-
resendMessage && /* @__PURE__ */ jsx6("div", { className: "rounded-lg border border-green-200 bg-green-50 px-3 py-2 text-xs text-green-700", children: resendMessage }),
|
|
614
|
-
/* @__PURE__ */ jsxs6("form", { onSubmit: handleVerify, className: "space-y-4", noValidate: true, children: [
|
|
615
|
-
/* @__PURE__ */ jsx6(
|
|
616
|
-
"input",
|
|
735
|
+
return /* @__PURE__ */ jsxs7("div", { className: "space-y-6", children: [
|
|
736
|
+
/* @__PURE__ */ jsx8(AuthAlert, { children: error }),
|
|
737
|
+
/* @__PURE__ */ jsx8(AuthAlert, { tone: "success", children: resendMessage }),
|
|
738
|
+
/* @__PURE__ */ jsxs7("form", { onSubmit: handleVerify, className: "space-y-5", noValidate: true, children: [
|
|
739
|
+
/* @__PURE__ */ jsx8(
|
|
740
|
+
AuthOtpField,
|
|
617
741
|
{
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
pattern: "[0-9]*",
|
|
621
|
-
maxLength: 6,
|
|
742
|
+
id: "verify-email-otp",
|
|
743
|
+
label: t.codePlaceholder,
|
|
622
744
|
value: otp,
|
|
623
|
-
onChange:
|
|
624
|
-
placeholder: "000000",
|
|
625
|
-
required: true,
|
|
745
|
+
onChange: setOtp,
|
|
626
746
|
disabled: isVerifying,
|
|
627
|
-
|
|
628
|
-
className: "flex h-12 w-full rounded-md border border-input bg-background px-3 py-2 text-center text-lg tracking-[0.4em] font-mono ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed"
|
|
747
|
+
fieldClassName
|
|
629
748
|
}
|
|
630
749
|
),
|
|
631
|
-
/* @__PURE__ */
|
|
632
|
-
|
|
750
|
+
/* @__PURE__ */ jsx8(
|
|
751
|
+
AuthSubmit,
|
|
633
752
|
{
|
|
634
|
-
|
|
635
|
-
disabled:
|
|
636
|
-
|
|
637
|
-
|
|
753
|
+
pending: isVerifying,
|
|
754
|
+
disabled: otp.length < OTP_LENGTH,
|
|
755
|
+
pendingLabel: t.submitPending,
|
|
756
|
+
className: submitClassName,
|
|
757
|
+
children: t.submit
|
|
638
758
|
}
|
|
639
|
-
)
|
|
640
|
-
|
|
759
|
+
)
|
|
760
|
+
] }),
|
|
761
|
+
/* @__PURE__ */ jsxs7("div", { className: "space-y-4 text-center text-sm text-muted-foreground", children: [
|
|
762
|
+
/* @__PURE__ */ jsx8(
|
|
641
763
|
"button",
|
|
642
764
|
{
|
|
643
765
|
type: "button",
|
|
644
766
|
onClick: handleResend,
|
|
645
767
|
disabled: isResending,
|
|
646
|
-
className: "
|
|
647
|
-
children: isResending ?
|
|
768
|
+
className: "rounded font-medium text-foreground underline underline-offset-4 decoration-foreground/25 transition-colors hover:decoration-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-55",
|
|
769
|
+
children: isResending ? t.resendPending : t.resend
|
|
648
770
|
}
|
|
649
|
-
)
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
)
|
|
771
|
+
),
|
|
772
|
+
/* @__PURE__ */ jsxs7("p", { children: [
|
|
773
|
+
t.alreadyVerified,
|
|
774
|
+
" ",
|
|
775
|
+
/* @__PURE__ */ jsx8(
|
|
776
|
+
"a",
|
|
777
|
+
{
|
|
778
|
+
href: loginUrl,
|
|
779
|
+
className: "rounded font-medium text-foreground underline underline-offset-4 decoration-foreground/25 transition-colors hover:decoration-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
780
|
+
children: t.login
|
|
781
|
+
}
|
|
782
|
+
)
|
|
783
|
+
] })
|
|
662
784
|
] })
|
|
663
785
|
] });
|
|
664
786
|
}
|
|
787
|
+
VerifyEmailForm.defaults = {
|
|
788
|
+
title: DEFAULTS3.title,
|
|
789
|
+
subtitle: DEFAULTS3.subtitle
|
|
790
|
+
};
|
|
665
791
|
|
|
666
792
|
// src/components/forgot-password-form.tsx
|
|
667
793
|
import { useState as useState5 } from "react";
|
|
668
|
-
import { jsx as
|
|
794
|
+
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
795
|
+
var DEFAULTS4 = {
|
|
796
|
+
title: "Mot de passe oubli\xE9 ?",
|
|
797
|
+
subtitle: "Entre ton adresse e-mail et nous t'enverrons un code pour le r\xE9initialiser.",
|
|
798
|
+
emailPlaceholder: "Adresse e-mail",
|
|
799
|
+
submit: "Envoyer le code",
|
|
800
|
+
submitPending: "Envoi\u2026",
|
|
801
|
+
rememberPassword: "Tu t'en souviens finalement ?",
|
|
802
|
+
login: "Se connecter",
|
|
803
|
+
emailRequired: "Renseigne ton adresse e-mail",
|
|
804
|
+
sendFailed: "L'envoi du code a \xE9chou\xE9"
|
|
805
|
+
};
|
|
669
806
|
function ForgotPasswordForm({
|
|
670
807
|
onSuccess,
|
|
671
808
|
loginUrl = "/login",
|
|
809
|
+
labels,
|
|
810
|
+
submitClassName,
|
|
811
|
+
fieldClassName,
|
|
672
812
|
authClient
|
|
673
813
|
}) {
|
|
814
|
+
const t = { ...DEFAULTS4, ...labels };
|
|
674
815
|
const [email, setEmail] = useState5("");
|
|
675
816
|
const [error, setError] = useState5();
|
|
676
817
|
const [isPending, setIsPending] = useState5(false);
|
|
677
818
|
const handleSubmit = async (e) => {
|
|
678
819
|
e.preventDefault();
|
|
679
820
|
if (!email.trim()) {
|
|
680
|
-
setError(
|
|
821
|
+
setError(t.emailRequired);
|
|
681
822
|
return;
|
|
682
823
|
}
|
|
683
824
|
setError(void 0);
|
|
684
825
|
setIsPending(true);
|
|
685
826
|
try {
|
|
686
827
|
const res = await authClient.emailOtp.sendVerificationOtp({
|
|
687
|
-
email,
|
|
828
|
+
email: email.trim(),
|
|
688
829
|
type: "forget-password"
|
|
689
830
|
});
|
|
690
831
|
if (res?.error) {
|
|
691
|
-
setError(res.error.message ??
|
|
832
|
+
setError(res.error.message ?? t.sendFailed);
|
|
692
833
|
return;
|
|
693
834
|
}
|
|
694
|
-
onSuccess?.(email);
|
|
835
|
+
onSuccess?.(email.trim());
|
|
695
836
|
} catch (err) {
|
|
696
|
-
setError(err instanceof Error ? err.message :
|
|
837
|
+
setError(err instanceof Error ? err.message : t.sendFailed);
|
|
697
838
|
} finally {
|
|
698
839
|
setIsPending(false);
|
|
699
840
|
}
|
|
700
841
|
};
|
|
701
|
-
return /* @__PURE__ */
|
|
702
|
-
/* @__PURE__ */
|
|
703
|
-
|
|
704
|
-
/* @__PURE__ */
|
|
705
|
-
|
|
706
|
-
error && /* @__PURE__ */ jsx7("div", { className: "rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: error }),
|
|
707
|
-
/* @__PURE__ */ jsxs7("form", { onSubmit: handleSubmit, className: "space-y-4", noValidate: true, children: [
|
|
708
|
-
/* @__PURE__ */ jsx7(
|
|
709
|
-
"input",
|
|
842
|
+
return /* @__PURE__ */ jsxs8("div", { className: "space-y-6", children: [
|
|
843
|
+
/* @__PURE__ */ jsx9(AuthAlert, { children: error }),
|
|
844
|
+
/* @__PURE__ */ jsxs8("form", { onSubmit: handleSubmit, className: "space-y-5", noValidate: true, children: [
|
|
845
|
+
/* @__PURE__ */ jsx9(
|
|
846
|
+
AuthField,
|
|
710
847
|
{
|
|
848
|
+
label: t.emailPlaceholder,
|
|
711
849
|
type: "email",
|
|
850
|
+
inputMode: "email",
|
|
712
851
|
value: email,
|
|
713
852
|
onChange: (e) => setEmail(e.target.value),
|
|
714
|
-
placeholder: "Email address",
|
|
715
853
|
required: true,
|
|
716
854
|
disabled: isPending,
|
|
717
855
|
autoComplete: "email",
|
|
718
|
-
|
|
856
|
+
autoCapitalize: "none",
|
|
857
|
+
spellCheck: false,
|
|
858
|
+
invalid: !!error
|
|
719
859
|
}
|
|
720
860
|
),
|
|
721
|
-
/* @__PURE__ */
|
|
722
|
-
|
|
861
|
+
/* @__PURE__ */ jsx9(
|
|
862
|
+
AuthSubmit,
|
|
723
863
|
{
|
|
724
|
-
|
|
725
|
-
disabled:
|
|
726
|
-
|
|
727
|
-
|
|
864
|
+
pending: isPending,
|
|
865
|
+
disabled: !email.trim(),
|
|
866
|
+
pendingLabel: t.submitPending,
|
|
867
|
+
className: submitClassName,
|
|
868
|
+
children: t.submit
|
|
728
869
|
}
|
|
729
870
|
)
|
|
730
871
|
] }),
|
|
731
|
-
/* @__PURE__ */
|
|
732
|
-
|
|
872
|
+
/* @__PURE__ */ jsxs8("p", { className: "text-center text-sm text-muted-foreground", children: [
|
|
873
|
+
t.rememberPassword,
|
|
733
874
|
" ",
|
|
734
|
-
/* @__PURE__ */
|
|
875
|
+
/* @__PURE__ */ jsx9(
|
|
735
876
|
"a",
|
|
736
877
|
{
|
|
737
878
|
href: loginUrl,
|
|
738
|
-
className: "font-medium text-foreground underline underline-offset-4 hover:
|
|
739
|
-
children:
|
|
879
|
+
className: "rounded font-medium text-foreground underline underline-offset-4 decoration-foreground/25 transition-colors hover:decoration-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
880
|
+
children: t.login
|
|
740
881
|
}
|
|
741
882
|
)
|
|
742
883
|
] })
|
|
743
884
|
] });
|
|
744
885
|
}
|
|
886
|
+
ForgotPasswordForm.defaults = {
|
|
887
|
+
title: DEFAULTS4.title,
|
|
888
|
+
subtitle: DEFAULTS4.subtitle
|
|
889
|
+
};
|
|
745
890
|
|
|
746
891
|
// src/components/reset-password-form.tsx
|
|
747
892
|
import { useState as useState6 } from "react";
|
|
748
|
-
import { jsx as
|
|
893
|
+
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
894
|
+
var MIN_PASSWORD_LENGTH2 = 8;
|
|
895
|
+
var DEFAULTS5 = {
|
|
896
|
+
title: "Nouveau mot de passe",
|
|
897
|
+
subtitle: "Entre le code \xE0 6 chiffres re\xE7u par e-mail et ton nouveau mot de passe.",
|
|
898
|
+
codePlaceholder: "Code de v\xE9rification",
|
|
899
|
+
passwordPlaceholder: "Nouveau mot de passe",
|
|
900
|
+
passwordHint: `Au moins ${MIN_PASSWORD_LENGTH2} caract\xE8res.`,
|
|
901
|
+
confirmPlaceholder: "Confirme le mot de passe",
|
|
902
|
+
submit: "R\xE9initialiser",
|
|
903
|
+
submitPending: "R\xE9initialisation\u2026",
|
|
904
|
+
resend: "Renvoyer le code",
|
|
905
|
+
resendPending: "Envoi\u2026",
|
|
906
|
+
resent: "Un nouveau code vient de t'\xEAtre envoy\xE9.",
|
|
907
|
+
rememberPassword: "Tu t'en souviens finalement ?",
|
|
908
|
+
login: "Se connecter",
|
|
909
|
+
codeRequired: "Entre le code \xE0 6 chiffres",
|
|
910
|
+
passwordTooShort: `Le mot de passe doit faire au moins ${MIN_PASSWORD_LENGTH2} caract\xE8res`,
|
|
911
|
+
passwordMismatch: "Les deux mots de passe ne correspondent pas",
|
|
912
|
+
resetFailed: "La r\xE9initialisation a \xE9chou\xE9",
|
|
913
|
+
resendFailed: "L'envoi du code a \xE9chou\xE9"
|
|
914
|
+
};
|
|
749
915
|
function ResetPasswordForm({
|
|
750
916
|
email,
|
|
751
917
|
onSuccess,
|
|
752
918
|
loginUrl = "/login",
|
|
919
|
+
labels,
|
|
920
|
+
submitClassName,
|
|
921
|
+
fieldClassName,
|
|
753
922
|
authClient
|
|
754
923
|
}) {
|
|
924
|
+
const t = { ...DEFAULTS5, ...labels };
|
|
755
925
|
const [otp, setOtp] = useState6("");
|
|
756
926
|
const [password, setPassword] = useState6("");
|
|
757
927
|
const [confirmPassword, setConfirmPassword] = useState6("");
|
|
@@ -759,21 +929,24 @@ function ResetPasswordForm({
|
|
|
759
929
|
const [isResetting, setIsResetting] = useState6(false);
|
|
760
930
|
const [isResending, setIsResending] = useState6(false);
|
|
761
931
|
const [resendMessage, setResendMessage] = useState6();
|
|
932
|
+
const tooShort = password.length > 0 && password.length < MIN_PASSWORD_LENGTH2;
|
|
933
|
+
const mismatch = confirmPassword.length > 0 && confirmPassword !== password;
|
|
762
934
|
const handleSubmit = async (e) => {
|
|
763
935
|
e.preventDefault();
|
|
764
|
-
if (
|
|
765
|
-
setError(
|
|
936
|
+
if (otp.length < OTP_LENGTH) {
|
|
937
|
+
setError(t.codeRequired);
|
|
766
938
|
return;
|
|
767
939
|
}
|
|
768
|
-
if (password.length <
|
|
769
|
-
setError(
|
|
940
|
+
if (password.length < MIN_PASSWORD_LENGTH2) {
|
|
941
|
+
setError(t.passwordTooShort);
|
|
770
942
|
return;
|
|
771
943
|
}
|
|
772
944
|
if (password !== confirmPassword) {
|
|
773
|
-
setError(
|
|
945
|
+
setError(t.passwordMismatch);
|
|
774
946
|
return;
|
|
775
947
|
}
|
|
776
948
|
setError(void 0);
|
|
949
|
+
setResendMessage(void 0);
|
|
777
950
|
setIsResetting(true);
|
|
778
951
|
try {
|
|
779
952
|
const res = await fetch("/api/auth/email-otp/reset-password", {
|
|
@@ -783,14 +956,12 @@ function ResetPasswordForm({
|
|
|
783
956
|
});
|
|
784
957
|
if (!res.ok) {
|
|
785
958
|
const body = await res.json().catch(() => null);
|
|
786
|
-
setError(body?.message ??
|
|
959
|
+
setError(body?.message ?? t.resetFailed);
|
|
787
960
|
return;
|
|
788
961
|
}
|
|
789
962
|
onSuccess?.();
|
|
790
963
|
} catch (err) {
|
|
791
|
-
setError(
|
|
792
|
-
err instanceof Error ? err.message : "Failed to reset password"
|
|
793
|
-
);
|
|
964
|
+
setError(err instanceof Error ? err.message : t.resetFailed);
|
|
794
965
|
} finally {
|
|
795
966
|
setIsResetting(false);
|
|
796
967
|
}
|
|
@@ -804,125 +975,161 @@ function ResetPasswordForm({
|
|
|
804
975
|
email,
|
|
805
976
|
type: "forget-password"
|
|
806
977
|
});
|
|
807
|
-
setResendMessage(
|
|
978
|
+
setResendMessage(t.resent);
|
|
808
979
|
} catch (err) {
|
|
809
|
-
setError(err instanceof Error ? err.message :
|
|
980
|
+
setError(err instanceof Error ? err.message : t.resendFailed);
|
|
810
981
|
} finally {
|
|
811
982
|
setIsResending(false);
|
|
812
983
|
}
|
|
813
984
|
};
|
|
814
|
-
return /* @__PURE__ */
|
|
815
|
-
/* @__PURE__ */
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
/* @__PURE__ */ jsx8("span", { className: "font-medium text-foreground", children: email }),
|
|
821
|
-
" and your new password."
|
|
822
|
-
] })
|
|
823
|
-
] }),
|
|
824
|
-
error && /* @__PURE__ */ jsx8("div", { className: "rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: error }),
|
|
825
|
-
resendMessage && /* @__PURE__ */ jsx8("div", { className: "rounded-lg border border-green-200 bg-green-50 px-3 py-2 text-xs text-green-700", children: resendMessage }),
|
|
826
|
-
/* @__PURE__ */ jsxs8("form", { onSubmit: handleSubmit, className: "space-y-4", noValidate: true, children: [
|
|
827
|
-
/* @__PURE__ */ jsx8(
|
|
828
|
-
"input",
|
|
985
|
+
return /* @__PURE__ */ jsxs9("div", { className: "space-y-6", children: [
|
|
986
|
+
/* @__PURE__ */ jsx10(AuthAlert, { children: error }),
|
|
987
|
+
/* @__PURE__ */ jsx10(AuthAlert, { tone: "success", children: resendMessage }),
|
|
988
|
+
/* @__PURE__ */ jsxs9("form", { onSubmit: handleSubmit, className: "space-y-5", noValidate: true, children: [
|
|
989
|
+
/* @__PURE__ */ jsx10(
|
|
990
|
+
AuthOtpField,
|
|
829
991
|
{
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
pattern: "[0-9]*",
|
|
833
|
-
maxLength: 6,
|
|
992
|
+
id: "reset-password-otp",
|
|
993
|
+
label: t.codePlaceholder,
|
|
834
994
|
value: otp,
|
|
835
|
-
onChange:
|
|
836
|
-
placeholder: "000000",
|
|
837
|
-
required: true,
|
|
995
|
+
onChange: setOtp,
|
|
838
996
|
disabled: isResetting,
|
|
839
|
-
|
|
840
|
-
className: "flex h-12 w-full rounded-md border border-input bg-background px-3 py-2 text-center text-lg tracking-[0.4em] font-mono ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed"
|
|
997
|
+
fieldClassName
|
|
841
998
|
}
|
|
842
999
|
),
|
|
843
|
-
/* @__PURE__ */
|
|
844
|
-
|
|
1000
|
+
/* @__PURE__ */ jsx10(
|
|
1001
|
+
AuthField,
|
|
845
1002
|
{
|
|
1003
|
+
label: t.passwordPlaceholder,
|
|
846
1004
|
type: "password",
|
|
847
1005
|
value: password,
|
|
848
1006
|
onChange: (e) => setPassword(e.target.value),
|
|
849
|
-
placeholder: "New password",
|
|
850
1007
|
required: true,
|
|
851
1008
|
disabled: isResetting,
|
|
852
1009
|
autoComplete: "new-password",
|
|
853
|
-
|
|
1010
|
+
description: t.passwordHint,
|
|
1011
|
+
invalid: tooShort
|
|
854
1012
|
}
|
|
855
1013
|
),
|
|
856
|
-
/* @__PURE__ */
|
|
857
|
-
|
|
1014
|
+
/* @__PURE__ */ jsx10(
|
|
1015
|
+
AuthField,
|
|
858
1016
|
{
|
|
1017
|
+
label: t.confirmPlaceholder,
|
|
859
1018
|
type: "password",
|
|
860
1019
|
value: confirmPassword,
|
|
861
1020
|
onChange: (e) => setConfirmPassword(e.target.value),
|
|
862
|
-
placeholder: "Confirm new password",
|
|
863
1021
|
required: true,
|
|
864
1022
|
disabled: isResetting,
|
|
865
1023
|
autoComplete: "new-password",
|
|
866
|
-
|
|
1024
|
+
invalid: mismatch
|
|
867
1025
|
}
|
|
868
1026
|
),
|
|
869
|
-
/* @__PURE__ */
|
|
870
|
-
|
|
1027
|
+
/* @__PURE__ */ jsx10(
|
|
1028
|
+
AuthSubmit,
|
|
871
1029
|
{
|
|
872
|
-
|
|
873
|
-
disabled:
|
|
874
|
-
|
|
875
|
-
|
|
1030
|
+
pending: isResetting,
|
|
1031
|
+
disabled: otp.length < OTP_LENGTH || !password || !confirmPassword,
|
|
1032
|
+
pendingLabel: t.submitPending,
|
|
1033
|
+
className: submitClassName,
|
|
1034
|
+
children: t.submit
|
|
876
1035
|
}
|
|
877
|
-
)
|
|
878
|
-
|
|
1036
|
+
)
|
|
1037
|
+
] }),
|
|
1038
|
+
/* @__PURE__ */ jsxs9("div", { className: "space-y-4 text-center text-sm text-muted-foreground", children: [
|
|
1039
|
+
/* @__PURE__ */ jsx10(
|
|
879
1040
|
"button",
|
|
880
1041
|
{
|
|
881
1042
|
type: "button",
|
|
882
1043
|
onClick: handleResend,
|
|
883
1044
|
disabled: isResending,
|
|
884
|
-
className: "
|
|
885
|
-
children: isResending ?
|
|
1045
|
+
className: "rounded font-medium text-foreground underline underline-offset-4 decoration-foreground/25 transition-colors hover:decoration-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-55",
|
|
1046
|
+
children: isResending ? t.resendPending : t.resend
|
|
886
1047
|
}
|
|
887
|
-
)
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
)
|
|
1048
|
+
),
|
|
1049
|
+
/* @__PURE__ */ jsxs9("p", { children: [
|
|
1050
|
+
t.rememberPassword,
|
|
1051
|
+
" ",
|
|
1052
|
+
/* @__PURE__ */ jsx10(
|
|
1053
|
+
"a",
|
|
1054
|
+
{
|
|
1055
|
+
href: loginUrl,
|
|
1056
|
+
className: "rounded font-medium text-foreground underline underline-offset-4 decoration-foreground/25 transition-colors hover:decoration-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
1057
|
+
children: t.login
|
|
1058
|
+
}
|
|
1059
|
+
)
|
|
1060
|
+
] })
|
|
900
1061
|
] })
|
|
901
1062
|
] });
|
|
902
1063
|
}
|
|
1064
|
+
ResetPasswordForm.defaults = {
|
|
1065
|
+
title: DEFAULTS5.title,
|
|
1066
|
+
subtitle: DEFAULTS5.subtitle
|
|
1067
|
+
};
|
|
1068
|
+
|
|
1069
|
+
// src/components/auth-heading.tsx
|
|
1070
|
+
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1071
|
+
function AuthHeading({
|
|
1072
|
+
title,
|
|
1073
|
+
subtitle,
|
|
1074
|
+
titleClassName = "text-2xl font-semibold tracking-tight"
|
|
1075
|
+
}) {
|
|
1076
|
+
return /* @__PURE__ */ jsxs10("header", { className: "space-y-1.5 text-center", children: [
|
|
1077
|
+
/* @__PURE__ */ jsx11("h1", { className: `leading-tight text-foreground ${titleClassName}`, children: title }),
|
|
1078
|
+
subtitle && /* @__PURE__ */ jsx11("p", { className: "text-balance text-sm leading-relaxed text-muted-foreground", children: subtitle })
|
|
1079
|
+
] });
|
|
1080
|
+
}
|
|
903
1081
|
|
|
904
1082
|
// src/components/auth-layout.tsx
|
|
905
|
-
import { jsx as
|
|
1083
|
+
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
906
1084
|
function AuthLayout({
|
|
907
1085
|
logo,
|
|
1086
|
+
panel,
|
|
908
1087
|
title,
|
|
909
1088
|
subtitle,
|
|
1089
|
+
titleClassName,
|
|
910
1090
|
children,
|
|
911
1091
|
footer
|
|
912
1092
|
}) {
|
|
913
|
-
return /* @__PURE__ */
|
|
914
|
-
/* @__PURE__ */
|
|
915
|
-
logo && /* @__PURE__ */
|
|
916
|
-
/* @__PURE__ */
|
|
917
|
-
|
|
1093
|
+
return /* @__PURE__ */ jsx12("div", { className: "flex min-h-dvh flex-col bg-background px-5 pb-10 pt-12 sm:items-center sm:bg-muted/40 sm:px-6 sm:py-16", children: /* @__PURE__ */ jsxs11("div", { className: `mx-auto w-full ${panel ? "max-w-4xl" : "max-w-[420px]"}`, children: [
|
|
1094
|
+
(logo || title) && /* @__PURE__ */ jsxs11("div", { className: "mb-7 space-y-5", children: [
|
|
1095
|
+
logo && /* @__PURE__ */ jsx12("div", { className: "flex justify-center", children: logo }),
|
|
1096
|
+
title && /* @__PURE__ */ jsx12(
|
|
1097
|
+
AuthHeading,
|
|
1098
|
+
{
|
|
1099
|
+
title,
|
|
1100
|
+
subtitle,
|
|
1101
|
+
titleClassName
|
|
1102
|
+
}
|
|
1103
|
+
)
|
|
918
1104
|
] }),
|
|
919
|
-
/* @__PURE__ */
|
|
920
|
-
|
|
1105
|
+
/* @__PURE__ */ jsxs11(
|
|
1106
|
+
"div",
|
|
1107
|
+
{
|
|
1108
|
+
className: [
|
|
1109
|
+
"sm:rounded-lg sm:border sm:border-border/70 sm:bg-card sm:shadow-sm",
|
|
1110
|
+
panel ? "sm:overflow-hidden md:grid md:grid-cols-2" : ""
|
|
1111
|
+
].filter(Boolean).join(" "),
|
|
1112
|
+
children: [
|
|
1113
|
+
panel && // Decorative: it must never carry information the form does not,
|
|
1114
|
+
// so it is hidden from assistive tech rather than described.
|
|
1115
|
+
/* @__PURE__ */ jsx12(
|
|
1116
|
+
"div",
|
|
1117
|
+
{
|
|
1118
|
+
"aria-hidden": "true",
|
|
1119
|
+
className: "relative hidden overflow-hidden bg-muted md:block [&>*]:absolute [&>*]:inset-0 [&>*]:h-full [&>*]:w-full [&>img]:object-cover",
|
|
1120
|
+
children: panel
|
|
1121
|
+
}
|
|
1122
|
+
),
|
|
1123
|
+
/* @__PURE__ */ jsx12("div", { className: "flex flex-col justify-center sm:p-8", children })
|
|
1124
|
+
]
|
|
1125
|
+
}
|
|
1126
|
+
),
|
|
1127
|
+
footer && /* @__PURE__ */ jsx12("div", { className: "mt-6 text-center text-xs leading-relaxed text-muted-foreground", children: footer })
|
|
921
1128
|
] }) });
|
|
922
1129
|
}
|
|
923
1130
|
|
|
924
1131
|
// src/components/invitation-notice.tsx
|
|
925
|
-
import { jsx as
|
|
1132
|
+
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
926
1133
|
function defaultSupportEmail() {
|
|
927
1134
|
if (typeof window === "undefined") return void 0;
|
|
928
1135
|
const host = window.location.hostname;
|
|
@@ -942,15 +1149,15 @@ function InvitationNotice({
|
|
|
942
1149
|
action
|
|
943
1150
|
}) {
|
|
944
1151
|
const contact = supportEmail ?? defaultSupportEmail();
|
|
945
|
-
return /* @__PURE__ */
|
|
946
|
-
/* @__PURE__ */
|
|
947
|
-
/* @__PURE__ */
|
|
948
|
-
/* @__PURE__ */
|
|
1152
|
+
return /* @__PURE__ */ jsxs12("div", { className: "space-y-8", children: [
|
|
1153
|
+
/* @__PURE__ */ jsxs12("div", { children: [
|
|
1154
|
+
/* @__PURE__ */ jsx13("h1", { className: "text-2xl font-bold tracking-tight", children: title }),
|
|
1155
|
+
/* @__PURE__ */ jsx13("p", { className: "mt-1 text-sm text-muted-foreground", children: REASON_MESSAGE[reason] ?? REASON_MESSAGE.unknown })
|
|
949
1156
|
] }),
|
|
950
|
-
contact ? /* @__PURE__ */
|
|
1157
|
+
contact ? /* @__PURE__ */ jsxs12("p", { className: "text-sm text-muted-foreground", children: [
|
|
951
1158
|
"\xC9crivez-nous \xE0",
|
|
952
1159
|
" ",
|
|
953
|
-
/* @__PURE__ */
|
|
1160
|
+
/* @__PURE__ */ jsx13(
|
|
954
1161
|
"a",
|
|
955
1162
|
{
|
|
956
1163
|
href: `mailto:${contact}`,
|