@lalternative/auth 0.4.3 → 0.4.5
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/index.d.ts +58 -1
- package/dist/index.js +344 -187
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import * as better_auth_react from 'better-auth/react';
|
|
|
4
4
|
import * as better_auth from 'better-auth';
|
|
5
5
|
import { PlatformAuthClient } from './client.js';
|
|
6
6
|
import * as react from 'react';
|
|
7
|
+
import { InputHTMLAttributes, ReactNode } from 'react';
|
|
7
8
|
export { C as ClaimOutcome, i as isInvitationFailure } from './invitation-Bucmin-z.js';
|
|
8
9
|
|
|
9
10
|
/**
|
|
@@ -45,6 +46,50 @@ declare function useSession(authClient: PlatformAuthClient): {
|
|
|
45
46
|
*/
|
|
46
47
|
declare function useLogout(authClient: PlatformAuthClient): () => Promise<void>;
|
|
47
48
|
|
|
49
|
+
type NativeProps = Omit<InputHTMLAttributes<HTMLInputElement>, "id" | "className">;
|
|
50
|
+
interface AuthFieldProps extends NativeProps {
|
|
51
|
+
label: string;
|
|
52
|
+
/** Rendered on the right of the label row — typically a "forgot password" link */
|
|
53
|
+
hint?: ReactNode;
|
|
54
|
+
/** Persistent helper text under the field, tied to it for screen readers */
|
|
55
|
+
description?: string;
|
|
56
|
+
invalid?: boolean;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* A single credential field.
|
|
60
|
+
*
|
|
61
|
+
* The label is a real <label>, always visible, never a placeholder standing in
|
|
62
|
+
* for one: a placeholder disappears the moment someone types, which is exactly
|
|
63
|
+
* when a person double-checking a long password needs to know what the box is.
|
|
64
|
+
*
|
|
65
|
+
* Touch targets are 52px tall on mobile and 44px from sm up. Below ~48px,
|
|
66
|
+
* thumbs miss; on a pointer device the same height reads as oversized, so the
|
|
67
|
+
* two are not one compromise value.
|
|
68
|
+
*
|
|
69
|
+
* The focus ring is a ring rather than an outline so it follows the rounded
|
|
70
|
+
* corners exactly, and the border darkens at the same time — the border is what
|
|
71
|
+
* survives forced-colors mode, where the ring is dropped.
|
|
72
|
+
*/
|
|
73
|
+
declare function AuthField({ label, hint, description, invalid, ...props }: AuthFieldProps): react.JSX.Element;
|
|
74
|
+
|
|
75
|
+
interface AuthSubmitProps {
|
|
76
|
+
pending?: boolean;
|
|
77
|
+
disabled?: boolean;
|
|
78
|
+
pendingLabel: string;
|
|
79
|
+
children: ReactNode;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The primary action of an auth screen.
|
|
83
|
+
*
|
|
84
|
+
* The label swaps to its pending form in place, with the spinner absolutely
|
|
85
|
+
* positioned: a spinner inserted into the flow would widen the row and shift
|
|
86
|
+
* the text sideways at the exact moment the person is watching it.
|
|
87
|
+
*
|
|
88
|
+
* The press feedback is a 1px translate rather than a scale — scaling a
|
|
89
|
+
* full-width button visibly blurs its text mid-transform.
|
|
90
|
+
*/
|
|
91
|
+
declare function AuthSubmit({ pending, disabled, pendingLabel, children, }: AuthSubmitProps): react.JSX.Element;
|
|
92
|
+
|
|
48
93
|
declare function LoginForm({ onSuccess, registerUrl, forgotPasswordUrl, socialCallbackUrl, socialProviders, coreTokenUrl, labels, authClient, }: LoginFormProps): react.JSX.Element;
|
|
49
94
|
|
|
50
95
|
declare function RegisterForm({ onSuccess, loginUrl, legal, socialCallbackUrl, socialProviders, labels, authClient, }: RegisterFormProps): react.JSX.Element;
|
|
@@ -66,6 +111,18 @@ declare function ForgotPasswordForm({ onSuccess, loginUrl, authClient, }: Forgot
|
|
|
66
111
|
|
|
67
112
|
declare function ResetPasswordForm({ email, onSuccess, loginUrl, authClient, }: ResetPasswordFormProps): react.JSX.Element;
|
|
68
113
|
|
|
114
|
+
/**
|
|
115
|
+
* The frame every auth screen sits in.
|
|
116
|
+
*
|
|
117
|
+
* Mobile and desktop are two layouts, not one scaled down. On a phone the form
|
|
118
|
+
* IS the page: no card, no border, edge-to-edge padding, top-aligned so the
|
|
119
|
+
* fields stay above the keyboard instead of being pushed under it by vertical
|
|
120
|
+
* centering. From sm up it becomes a bounded card, centered, on a tinted
|
|
121
|
+
* ground — a full-width form on a 1440px display is unreadable.
|
|
122
|
+
*
|
|
123
|
+
* min-h-dvh rather than min-h-screen: on mobile browsers 100vh includes the
|
|
124
|
+
* retracting URL bar, so a screen-height container overflows by its height.
|
|
125
|
+
*/
|
|
69
126
|
declare function AuthLayout({ logo, title, subtitle, children, footer, }: AuthLayoutProps): react.JSX.Element;
|
|
70
127
|
|
|
71
128
|
/**
|
|
@@ -82,4 +139,4 @@ declare function AuthLayout({ logo, title, subtitle, children, footer, }: AuthLa
|
|
|
82
139
|
*/
|
|
83
140
|
declare function InvitationNotice({ reason, supportEmail, title, action, }: InvitationNoticeProps): react.JSX.Element;
|
|
84
141
|
|
|
85
|
-
export { AuthLayout, AuthLayoutProps, ForgotPasswordForm, ForgotPasswordFormProps, InvitationNotice, InvitationNoticeProps, LoginForm, LoginFormProps, RegisterForm, RegisterFormProps, ResetPasswordForm, ResetPasswordFormProps, SocialButtons, VerifyEmailForm, VerifyEmailFormProps, useLogout, useSession };
|
|
142
|
+
export { AuthField, type AuthFieldProps, AuthLayout, AuthLayoutProps, AuthSubmit, ForgotPasswordForm, ForgotPasswordFormProps, InvitationNotice, InvitationNoticeProps, LoginForm, LoginFormProps, RegisterForm, RegisterFormProps, ResetPasswordForm, ResetPasswordFormProps, SocialButtons, VerifyEmailForm, VerifyEmailFormProps, useLogout, useSession };
|
package/dist/index.js
CHANGED
|
@@ -13,11 +13,133 @@ function useLogout(authClient) {
|
|
|
13
13
|
return signOut;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
// src/components/auth-field.tsx
|
|
17
|
+
import { useId, useState } from "react";
|
|
18
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
19
|
+
function AuthField({
|
|
20
|
+
label,
|
|
21
|
+
hint,
|
|
22
|
+
description,
|
|
23
|
+
invalid = false,
|
|
24
|
+
...props
|
|
25
|
+
}) {
|
|
26
|
+
const id = useId();
|
|
27
|
+
const descriptionId = description ? `${id}-description` : void 0;
|
|
28
|
+
const [revealed, setRevealed] = useState(false);
|
|
29
|
+
const isPassword = props.type === "password";
|
|
30
|
+
const type = isPassword && revealed ? "text" : props.type;
|
|
31
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
32
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between gap-3", children: [
|
|
33
|
+
/* @__PURE__ */ jsx(
|
|
34
|
+
"label",
|
|
35
|
+
{
|
|
36
|
+
htmlFor: id,
|
|
37
|
+
className: "text-sm font-medium leading-none text-foreground",
|
|
38
|
+
children: label
|
|
39
|
+
}
|
|
40
|
+
),
|
|
41
|
+
hint
|
|
42
|
+
] }),
|
|
43
|
+
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
44
|
+
/* @__PURE__ */ jsx(
|
|
45
|
+
"input",
|
|
46
|
+
{
|
|
47
|
+
...props,
|
|
48
|
+
id,
|
|
49
|
+
type,
|
|
50
|
+
"aria-invalid": invalid || void 0,
|
|
51
|
+
"aria-describedby": descriptionId,
|
|
52
|
+
className: [
|
|
53
|
+
"h-[52px] w-full rounded-xl border bg-background px-4 text-base",
|
|
54
|
+
"sm:h-11 sm:text-sm",
|
|
55
|
+
isPassword ? "pr-12" : "",
|
|
56
|
+
"text-foreground placeholder:text-muted-foreground/70",
|
|
57
|
+
"transition-[border-color,box-shadow] duration-150 ease-out",
|
|
58
|
+
"focus-visible:outline-none focus-visible:ring-[3px]",
|
|
59
|
+
invalid ? "border-destructive focus-visible:border-destructive focus-visible:ring-destructive/20" : "border-input focus-visible:border-ring focus-visible:ring-ring/15",
|
|
60
|
+
"disabled:cursor-not-allowed disabled:opacity-60"
|
|
61
|
+
].filter(Boolean).join(" ")
|
|
62
|
+
}
|
|
63
|
+
),
|
|
64
|
+
isPassword && /* @__PURE__ */ jsx(
|
|
65
|
+
"button",
|
|
66
|
+
{
|
|
67
|
+
type: "button",
|
|
68
|
+
onClick: () => setRevealed((v) => !v),
|
|
69
|
+
disabled: props.disabled,
|
|
70
|
+
"aria-pressed": revealed,
|
|
71
|
+
"aria-label": revealed ? "Masquer le mot de passe" : "Afficher le mot de passe",
|
|
72
|
+
className: "absolute inset-y-0 right-0 flex w-12 items-center justify-center rounded-r-xl text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-60",
|
|
73
|
+
children: /* @__PURE__ */ jsx(EyeIcon, { open: revealed })
|
|
74
|
+
}
|
|
75
|
+
)
|
|
76
|
+
] }),
|
|
77
|
+
description && /* @__PURE__ */ jsx("p", { id: descriptionId, className: "text-xs text-muted-foreground", children: description })
|
|
78
|
+
] });
|
|
79
|
+
}
|
|
80
|
+
function EyeIcon({ open }) {
|
|
81
|
+
return /* @__PURE__ */ jsxs(
|
|
82
|
+
"svg",
|
|
83
|
+
{
|
|
84
|
+
width: "18",
|
|
85
|
+
height: "18",
|
|
86
|
+
viewBox: "0 0 24 24",
|
|
87
|
+
fill: "none",
|
|
88
|
+
stroke: "currentColor",
|
|
89
|
+
strokeWidth: "1.75",
|
|
90
|
+
strokeLinecap: "round",
|
|
91
|
+
strokeLinejoin: "round",
|
|
92
|
+
"aria-hidden": "true",
|
|
93
|
+
children: [
|
|
94
|
+
/* @__PURE__ */ jsx("path", { d: "M2.06 12.35a1 1 0 0 1 0-.7 10.75 10.75 0 0 1 19.88 0 1 1 0 0 1 0 .7 10.75 10.75 0 0 1-19.88 0Z" }),
|
|
95
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "3" }),
|
|
96
|
+
!open && /* @__PURE__ */ jsx("path", { d: "m3 3 18 18" })
|
|
97
|
+
]
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// src/components/auth-submit.tsx
|
|
103
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
104
|
+
function AuthSubmit({
|
|
105
|
+
pending = false,
|
|
106
|
+
disabled = false,
|
|
107
|
+
pendingLabel,
|
|
108
|
+
children
|
|
109
|
+
}) {
|
|
110
|
+
return /* @__PURE__ */ jsxs2(
|
|
111
|
+
"button",
|
|
112
|
+
{
|
|
113
|
+
type: "submit",
|
|
114
|
+
disabled: disabled || pending,
|
|
115
|
+
"aria-busy": pending || void 0,
|
|
116
|
+
className: [
|
|
117
|
+
"relative flex h-[52px] w-full items-center justify-center rounded-xl sm:h-11",
|
|
118
|
+
"bg-primary text-base font-medium text-primary-foreground sm:text-sm",
|
|
119
|
+
"shadow-sm transition-[background-color,transform,box-shadow] duration-150 ease-out",
|
|
120
|
+
"hover:bg-primary/90 active:translate-y-px",
|
|
121
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
122
|
+
"disabled:pointer-events-none disabled:opacity-55"
|
|
123
|
+
].join(" "),
|
|
124
|
+
children: [
|
|
125
|
+
pending && /* @__PURE__ */ jsx2(
|
|
126
|
+
"span",
|
|
127
|
+
{
|
|
128
|
+
"aria-hidden": "true",
|
|
129
|
+
className: "absolute left-4 size-4 animate-spin rounded-full border-2 border-current border-t-transparent opacity-70 motion-reduce:animate-none"
|
|
130
|
+
}
|
|
131
|
+
),
|
|
132
|
+
pending ? pendingLabel : children
|
|
133
|
+
]
|
|
134
|
+
}
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
16
138
|
// src/components/login-form.tsx
|
|
17
|
-
import { useState } from "react";
|
|
139
|
+
import { useState as useState2 } from "react";
|
|
18
140
|
|
|
19
141
|
// src/components/social-buttons.tsx
|
|
20
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
142
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
21
143
|
var LABELS = {
|
|
22
144
|
google: "Continuer avec Google",
|
|
23
145
|
github: "Continuer avec GitHub"
|
|
@@ -31,27 +153,73 @@ function SocialButtons({
|
|
|
31
153
|
}) {
|
|
32
154
|
if (providers.length === 0) return null;
|
|
33
155
|
const copy = { ...LABELS, ...labels };
|
|
34
|
-
return /* @__PURE__ */
|
|
35
|
-
/* @__PURE__ */
|
|
36
|
-
/* @__PURE__ */
|
|
37
|
-
/* @__PURE__ */
|
|
156
|
+
return /* @__PURE__ */ jsxs3("div", { className: "space-y-4", children: [
|
|
157
|
+
/* @__PURE__ */ jsxs3("div", { "aria-hidden": "true", className: "flex items-center gap-3", children: [
|
|
158
|
+
/* @__PURE__ */ jsx3("span", { className: "h-px flex-1 bg-border" }),
|
|
159
|
+
/* @__PURE__ */ jsx3("span", { className: "text-[11px] uppercase tracking-[0.14em] text-muted-foreground", children: separator }),
|
|
160
|
+
/* @__PURE__ */ jsx3("span", { className: "h-px flex-1 bg-border" })
|
|
38
161
|
] }),
|
|
39
|
-
/* @__PURE__ */
|
|
162
|
+
/* @__PURE__ */ jsx3("div", { className: "space-y-2.5", children: providers.map((provider) => /* @__PURE__ */ jsxs3(
|
|
40
163
|
"button",
|
|
41
164
|
{
|
|
42
165
|
type: "button",
|
|
43
166
|
onClick: () => onSelect(provider),
|
|
44
167
|
disabled,
|
|
45
|
-
className:
|
|
46
|
-
|
|
168
|
+
className: [
|
|
169
|
+
"flex h-[52px] w-full items-center justify-center gap-2.5 rounded-xl sm:h-11",
|
|
170
|
+
"border border-input bg-background text-base font-medium text-foreground sm:text-sm",
|
|
171
|
+
"transition-[background-color,border-color,transform] duration-150 ease-out",
|
|
172
|
+
"hover:border-foreground/20 hover:bg-accent active:translate-y-px",
|
|
173
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
174
|
+
"disabled:pointer-events-none disabled:opacity-55"
|
|
175
|
+
].join(" "),
|
|
176
|
+
children: [
|
|
177
|
+
/* @__PURE__ */ jsx3(ProviderMark, { provider }),
|
|
178
|
+
copy[provider] ?? provider
|
|
179
|
+
]
|
|
47
180
|
},
|
|
48
181
|
provider
|
|
49
182
|
)) })
|
|
50
183
|
] });
|
|
51
184
|
}
|
|
185
|
+
function ProviderMark({ provider }) {
|
|
186
|
+
if (provider === "google") {
|
|
187
|
+
return /* @__PURE__ */ jsxs3("svg", { width: "17", height: "17", viewBox: "0 0 18 18", "aria-hidden": "true", children: [
|
|
188
|
+
/* @__PURE__ */ jsx3(
|
|
189
|
+
"path",
|
|
190
|
+
{
|
|
191
|
+
fill: "#4285F4",
|
|
192
|
+
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
|
+
}
|
|
194
|
+
),
|
|
195
|
+
/* @__PURE__ */ jsx3(
|
|
196
|
+
"path",
|
|
197
|
+
{
|
|
198
|
+
fill: "#34A853",
|
|
199
|
+
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
|
+
}
|
|
201
|
+
),
|
|
202
|
+
/* @__PURE__ */ jsx3(
|
|
203
|
+
"path",
|
|
204
|
+
{
|
|
205
|
+
fill: "#FBBC05",
|
|
206
|
+
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
|
+
}
|
|
208
|
+
),
|
|
209
|
+
/* @__PURE__ */ jsx3(
|
|
210
|
+
"path",
|
|
211
|
+
{
|
|
212
|
+
fill: "#EA4335",
|
|
213
|
+
d: "M9 3.58c1.32 0 2.5.45 3.44 1.35l2.58-2.58C13.46.9 11.43 0 9 0A9 9 0 0 0 .96 4.95l3.02 2.33C4.68 5.16 6.66 3.58 9 3.58Z"
|
|
214
|
+
}
|
|
215
|
+
)
|
|
216
|
+
] });
|
|
217
|
+
}
|
|
218
|
+
return /* @__PURE__ */ jsx3("svg", { width: "17", height: "17", viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx3("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
|
+
}
|
|
52
220
|
|
|
53
221
|
// src/components/login-form.tsx
|
|
54
|
-
import { jsx as
|
|
222
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
55
223
|
var DEFAULTS = {
|
|
56
224
|
title: "Connexion",
|
|
57
225
|
subtitle: "Content de te revoir. Entre tes identifiants pour continuer.",
|
|
@@ -83,10 +251,10 @@ function LoginForm({
|
|
|
83
251
|
authClient
|
|
84
252
|
}) {
|
|
85
253
|
const t = { ...DEFAULTS, ...labels };
|
|
86
|
-
const [email, setEmail] =
|
|
87
|
-
const [password, setPassword] =
|
|
88
|
-
const [error, setError] =
|
|
89
|
-
const [isPending, setIsPending] =
|
|
254
|
+
const [email, setEmail] = useState2("");
|
|
255
|
+
const [password, setPassword] = useState2("");
|
|
256
|
+
const [error, setError] = useState2();
|
|
257
|
+
const [isPending, setIsPending] = useState2(false);
|
|
90
258
|
const handleSubmit = async (e) => {
|
|
91
259
|
e.preventDefault();
|
|
92
260
|
if (!email.trim()) {
|
|
@@ -132,69 +300,68 @@ function LoginForm({
|
|
|
132
300
|
);
|
|
133
301
|
}
|
|
134
302
|
};
|
|
135
|
-
return /* @__PURE__ */
|
|
136
|
-
/* @__PURE__ */
|
|
137
|
-
/* @__PURE__ */
|
|
138
|
-
/* @__PURE__ */
|
|
303
|
+
return /* @__PURE__ */ jsxs4("div", { className: "space-y-7", children: [
|
|
304
|
+
/* @__PURE__ */ jsxs4("header", { className: "space-y-1.5", children: [
|
|
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-sm leading-relaxed text-muted-foreground", children: t.subtitle })
|
|
139
307
|
] }),
|
|
140
|
-
error && /* @__PURE__ */
|
|
308
|
+
error && /* @__PURE__ */ jsx4(
|
|
141
309
|
"div",
|
|
142
310
|
{
|
|
143
311
|
role: "alert",
|
|
144
|
-
className: "rounded-
|
|
312
|
+
className: "rounded-xl border border-destructive/25 bg-destructive/10 px-3.5 py-3 text-sm leading-snug text-destructive",
|
|
145
313
|
children: error
|
|
146
314
|
}
|
|
147
315
|
),
|
|
148
|
-
/* @__PURE__ */
|
|
149
|
-
/* @__PURE__ */
|
|
150
|
-
|
|
316
|
+
/* @__PURE__ */ jsxs4("form", { onSubmit: handleSubmit, className: "space-y-5", noValidate: true, children: [
|
|
317
|
+
/* @__PURE__ */ jsx4(
|
|
318
|
+
AuthField,
|
|
151
319
|
{
|
|
320
|
+
label: t.emailPlaceholder,
|
|
152
321
|
type: "email",
|
|
322
|
+
inputMode: "email",
|
|
153
323
|
value: email,
|
|
154
324
|
onChange: (e) => setEmail(e.target.value),
|
|
155
|
-
placeholder: t.emailPlaceholder,
|
|
156
|
-
"aria-label": t.emailPlaceholder,
|
|
157
325
|
required: true,
|
|
158
326
|
disabled: isPending,
|
|
159
327
|
autoComplete: "email",
|
|
160
|
-
|
|
328
|
+
autoCapitalize: "none",
|
|
329
|
+
spellCheck: false,
|
|
330
|
+
invalid: !!error
|
|
161
331
|
}
|
|
162
332
|
),
|
|
163
|
-
/* @__PURE__ */
|
|
164
|
-
|
|
165
|
-
"input",
|
|
166
|
-
{
|
|
167
|
-
type: "password",
|
|
168
|
-
value: password,
|
|
169
|
-
onChange: (e) => setPassword(e.target.value),
|
|
170
|
-
placeholder: t.passwordPlaceholder,
|
|
171
|
-
"aria-label": t.passwordPlaceholder,
|
|
172
|
-
required: true,
|
|
173
|
-
disabled: isPending,
|
|
174
|
-
autoComplete: "current-password",
|
|
175
|
-
className: "flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm 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"
|
|
176
|
-
}
|
|
177
|
-
),
|
|
178
|
-
/* @__PURE__ */ jsx2("div", { className: "text-right", children: /* @__PURE__ */ jsx2(
|
|
179
|
-
"a",
|
|
180
|
-
{
|
|
181
|
-
href: forgotPasswordUrl,
|
|
182
|
-
className: "text-xs text-muted-foreground underline underline-offset-4 hover:text-foreground",
|
|
183
|
-
children: t.forgotPassword
|
|
184
|
-
}
|
|
185
|
-
) })
|
|
186
|
-
] }),
|
|
187
|
-
/* @__PURE__ */ jsx2(
|
|
188
|
-
"button",
|
|
333
|
+
/* @__PURE__ */ jsx4(
|
|
334
|
+
AuthField,
|
|
189
335
|
{
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
336
|
+
label: t.passwordPlaceholder,
|
|
337
|
+
type: "password",
|
|
338
|
+
value: password,
|
|
339
|
+
onChange: (e) => setPassword(e.target.value),
|
|
340
|
+
required: true,
|
|
341
|
+
disabled: isPending,
|
|
342
|
+
autoComplete: "current-password",
|
|
343
|
+
invalid: !!error,
|
|
344
|
+
hint: /* @__PURE__ */ jsx4(
|
|
345
|
+
"a",
|
|
346
|
+
{
|
|
347
|
+
href: forgotPasswordUrl,
|
|
348
|
+
className: "rounded text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-foreground hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
349
|
+
children: t.forgotPassword
|
|
350
|
+
}
|
|
351
|
+
)
|
|
352
|
+
}
|
|
353
|
+
),
|
|
354
|
+
/* @__PURE__ */ jsx4(
|
|
355
|
+
AuthSubmit,
|
|
356
|
+
{
|
|
357
|
+
pending: isPending,
|
|
358
|
+
disabled: !email.trim() || !password,
|
|
359
|
+
pendingLabel: t.submitPending,
|
|
360
|
+
children: t.submit
|
|
194
361
|
}
|
|
195
362
|
)
|
|
196
363
|
] }),
|
|
197
|
-
/* @__PURE__ */
|
|
364
|
+
/* @__PURE__ */ jsx4(
|
|
198
365
|
SocialButtons,
|
|
199
366
|
{
|
|
200
367
|
providers: socialProviders,
|
|
@@ -202,14 +369,14 @@ function LoginForm({
|
|
|
202
369
|
disabled: isPending
|
|
203
370
|
}
|
|
204
371
|
),
|
|
205
|
-
/* @__PURE__ */
|
|
372
|
+
/* @__PURE__ */ jsxs4("p", { className: "text-center text-sm text-muted-foreground", children: [
|
|
206
373
|
t.noAccount,
|
|
207
374
|
" ",
|
|
208
|
-
/* @__PURE__ */
|
|
375
|
+
/* @__PURE__ */ jsx4(
|
|
209
376
|
"a",
|
|
210
377
|
{
|
|
211
378
|
href: registerUrl,
|
|
212
|
-
className: "font-medium text-foreground underline underline-offset-4 hover:
|
|
379
|
+
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",
|
|
213
380
|
children: t.register
|
|
214
381
|
}
|
|
215
382
|
)
|
|
@@ -218,8 +385,8 @@ function LoginForm({
|
|
|
218
385
|
}
|
|
219
386
|
|
|
220
387
|
// src/components/register-form.tsx
|
|
221
|
-
import { useState as
|
|
222
|
-
import { jsx as
|
|
388
|
+
import { useState as useState3 } from "react";
|
|
389
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
223
390
|
var MIN_PASSWORD_LENGTH = 8;
|
|
224
391
|
var DEFAULTS2 = {
|
|
225
392
|
title: "Cr\xE9er un compte",
|
|
@@ -247,11 +414,12 @@ function RegisterForm({
|
|
|
247
414
|
authClient
|
|
248
415
|
}) {
|
|
249
416
|
const t = { ...DEFAULTS2, ...labels };
|
|
250
|
-
const [name, setName] =
|
|
251
|
-
const [email, setEmail] =
|
|
252
|
-
const [password, setPassword] =
|
|
253
|
-
const [error, setError] =
|
|
254
|
-
const [isPending, setIsPending] =
|
|
417
|
+
const [name, setName] = useState3("");
|
|
418
|
+
const [email, setEmail] = useState3("");
|
|
419
|
+
const [password, setPassword] = useState3("");
|
|
420
|
+
const [error, setError] = useState3();
|
|
421
|
+
const [isPending, setIsPending] = useState3(false);
|
|
422
|
+
const tooShort = password.length > 0 && password.length < MIN_PASSWORD_LENGTH;
|
|
255
423
|
const handleSubmit = async (e) => {
|
|
256
424
|
e.preventDefault();
|
|
257
425
|
if (!name.trim()) {
|
|
@@ -296,78 +464,65 @@ function RegisterForm({
|
|
|
296
464
|
setError(err instanceof Error ? err.message : t.signUpFailed);
|
|
297
465
|
}
|
|
298
466
|
};
|
|
299
|
-
return /* @__PURE__ */
|
|
300
|
-
/* @__PURE__ */
|
|
301
|
-
/* @__PURE__ */
|
|
302
|
-
/* @__PURE__ */
|
|
467
|
+
return /* @__PURE__ */ jsxs5("div", { className: "space-y-7", children: [
|
|
468
|
+
/* @__PURE__ */ jsxs5("header", { className: "space-y-1.5", children: [
|
|
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-sm leading-relaxed text-muted-foreground", children: t.subtitle })
|
|
303
471
|
] }),
|
|
304
|
-
error && /* @__PURE__ */
|
|
472
|
+
error && /* @__PURE__ */ jsx5(
|
|
305
473
|
"div",
|
|
306
474
|
{
|
|
307
475
|
role: "alert",
|
|
308
|
-
className: "rounded-
|
|
476
|
+
className: "rounded-xl border border-destructive/25 bg-destructive/10 px-3.5 py-3 text-sm leading-snug text-destructive",
|
|
309
477
|
children: error
|
|
310
478
|
}
|
|
311
479
|
),
|
|
312
|
-
/* @__PURE__ */
|
|
313
|
-
/* @__PURE__ */
|
|
314
|
-
|
|
480
|
+
/* @__PURE__ */ jsxs5("form", { onSubmit: handleSubmit, className: "space-y-5", noValidate: true, children: [
|
|
481
|
+
/* @__PURE__ */ jsx5(
|
|
482
|
+
AuthField,
|
|
315
483
|
{
|
|
484
|
+
label: t.namePlaceholder,
|
|
316
485
|
type: "text",
|
|
317
486
|
value: name,
|
|
318
487
|
onChange: (e) => setName(e.target.value),
|
|
319
|
-
placeholder: t.namePlaceholder,
|
|
320
|
-
"aria-label": t.namePlaceholder,
|
|
321
488
|
required: true,
|
|
322
489
|
disabled: isPending,
|
|
323
|
-
autoComplete: "name"
|
|
324
|
-
className: "flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm 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"
|
|
490
|
+
autoComplete: "name"
|
|
325
491
|
}
|
|
326
492
|
),
|
|
327
|
-
/* @__PURE__ */
|
|
328
|
-
|
|
493
|
+
/* @__PURE__ */ jsx5(
|
|
494
|
+
AuthField,
|
|
329
495
|
{
|
|
496
|
+
label: t.emailPlaceholder,
|
|
330
497
|
type: "email",
|
|
498
|
+
inputMode: "email",
|
|
331
499
|
value: email,
|
|
332
500
|
onChange: (e) => setEmail(e.target.value),
|
|
333
|
-
placeholder: t.emailPlaceholder,
|
|
334
|
-
"aria-label": t.emailPlaceholder,
|
|
335
501
|
required: true,
|
|
336
502
|
disabled: isPending,
|
|
337
503
|
autoComplete: "email",
|
|
338
|
-
|
|
504
|
+
autoCapitalize: "none",
|
|
505
|
+
spellCheck: false
|
|
339
506
|
}
|
|
340
507
|
),
|
|
341
|
-
/* @__PURE__ */
|
|
342
|
-
|
|
343
|
-
"input",
|
|
344
|
-
{
|
|
345
|
-
type: "password",
|
|
346
|
-
value: password,
|
|
347
|
-
onChange: (e) => setPassword(e.target.value),
|
|
348
|
-
placeholder: t.passwordPlaceholder,
|
|
349
|
-
"aria-label": t.passwordPlaceholder,
|
|
350
|
-
required: true,
|
|
351
|
-
disabled: isPending,
|
|
352
|
-
autoComplete: "new-password",
|
|
353
|
-
"aria-describedby": "register-password-hint",
|
|
354
|
-
className: "flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm 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"
|
|
355
|
-
}
|
|
356
|
-
),
|
|
357
|
-
/* @__PURE__ */ jsx3("p", { id: "register-password-hint", className: "text-xs text-muted-foreground", children: t.passwordHint })
|
|
358
|
-
] }),
|
|
359
|
-
/* @__PURE__ */ jsx3(
|
|
360
|
-
"button",
|
|
508
|
+
/* @__PURE__ */ jsx5(
|
|
509
|
+
AuthField,
|
|
361
510
|
{
|
|
362
|
-
|
|
511
|
+
label: t.passwordPlaceholder,
|
|
512
|
+
type: "password",
|
|
513
|
+
value: password,
|
|
514
|
+
onChange: (e) => setPassword(e.target.value),
|
|
515
|
+
required: true,
|
|
363
516
|
disabled: isPending,
|
|
364
|
-
|
|
365
|
-
|
|
517
|
+
autoComplete: "new-password",
|
|
518
|
+
description: t.passwordHint,
|
|
519
|
+
invalid: tooShort
|
|
366
520
|
}
|
|
367
521
|
),
|
|
368
|
-
|
|
522
|
+
/* @__PURE__ */ jsx5(AuthSubmit, { pending: isPending, pendingLabel: t.submitPending, children: t.submit }),
|
|
523
|
+
legal && /* @__PURE__ */ jsx5("p", { className: "text-center text-xs leading-relaxed text-muted-foreground", children: legal })
|
|
369
524
|
] }),
|
|
370
|
-
/* @__PURE__ */
|
|
525
|
+
/* @__PURE__ */ jsx5(
|
|
371
526
|
SocialButtons,
|
|
372
527
|
{
|
|
373
528
|
providers: socialProviders,
|
|
@@ -375,14 +530,14 @@ function RegisterForm({
|
|
|
375
530
|
disabled: isPending
|
|
376
531
|
}
|
|
377
532
|
),
|
|
378
|
-
/* @__PURE__ */
|
|
533
|
+
/* @__PURE__ */ jsxs5("p", { className: "text-center text-sm text-muted-foreground", children: [
|
|
379
534
|
t.haveAccount,
|
|
380
535
|
" ",
|
|
381
|
-
/* @__PURE__ */
|
|
536
|
+
/* @__PURE__ */ jsx5(
|
|
382
537
|
"a",
|
|
383
538
|
{
|
|
384
539
|
href: loginUrl,
|
|
385
|
-
className: "font-medium text-foreground underline underline-offset-4 hover:
|
|
540
|
+
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",
|
|
386
541
|
children: t.login
|
|
387
542
|
}
|
|
388
543
|
)
|
|
@@ -391,18 +546,18 @@ function RegisterForm({
|
|
|
391
546
|
}
|
|
392
547
|
|
|
393
548
|
// src/components/verify-email-form.tsx
|
|
394
|
-
import { useState as
|
|
395
|
-
import { Fragment, jsx as
|
|
549
|
+
import { useState as useState4 } from "react";
|
|
550
|
+
import { Fragment, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
396
551
|
function VerifyEmailForm({
|
|
397
552
|
email,
|
|
398
553
|
onSuccess,
|
|
399
554
|
authClient
|
|
400
555
|
}) {
|
|
401
|
-
const [otp, setOtp] =
|
|
402
|
-
const [isVerifying, setIsVerifying] =
|
|
403
|
-
const [isResending, setIsResending] =
|
|
404
|
-
const [resendMessage, setResendMessage] =
|
|
405
|
-
const [error, setError] =
|
|
556
|
+
const [otp, setOtp] = useState4("");
|
|
557
|
+
const [isVerifying, setIsVerifying] = useState4(false);
|
|
558
|
+
const [isResending, setIsResending] = useState4(false);
|
|
559
|
+
const [resendMessage, setResendMessage] = useState4();
|
|
560
|
+
const [error, setError] = useState4();
|
|
406
561
|
const handleVerify = async (e) => {
|
|
407
562
|
e.preventDefault();
|
|
408
563
|
if (!otp.trim() || otp.length < 6) {
|
|
@@ -445,19 +600,19 @@ function VerifyEmailForm({
|
|
|
445
600
|
setIsResending(false);
|
|
446
601
|
}
|
|
447
602
|
};
|
|
448
|
-
return /* @__PURE__ */
|
|
449
|
-
/* @__PURE__ */
|
|
450
|
-
/* @__PURE__ */
|
|
451
|
-
/* @__PURE__ */
|
|
603
|
+
return /* @__PURE__ */ jsxs6("div", { className: "space-y-8", children: [
|
|
604
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
605
|
+
/* @__PURE__ */ jsx6("h1", { className: "text-2xl font-bold tracking-tight", children: "Verify your email" }),
|
|
606
|
+
/* @__PURE__ */ jsx6("p", { className: "mt-1 text-sm text-muted-foreground", children: email ? /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
452
607
|
"Enter the 6-digit code sent to",
|
|
453
608
|
" ",
|
|
454
|
-
/* @__PURE__ */
|
|
609
|
+
/* @__PURE__ */ jsx6("span", { className: "font-medium text-foreground", children: email })
|
|
455
610
|
] }) : "Enter the 6-digit code sent to your email" })
|
|
456
611
|
] }),
|
|
457
|
-
error && /* @__PURE__ */
|
|
458
|
-
resendMessage && /* @__PURE__ */
|
|
459
|
-
/* @__PURE__ */
|
|
460
|
-
/* @__PURE__ */
|
|
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(
|
|
461
616
|
"input",
|
|
462
617
|
{
|
|
463
618
|
type: "text",
|
|
@@ -473,7 +628,7 @@ function VerifyEmailForm({
|
|
|
473
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"
|
|
474
629
|
}
|
|
475
630
|
),
|
|
476
|
-
/* @__PURE__ */
|
|
631
|
+
/* @__PURE__ */ jsx6(
|
|
477
632
|
"button",
|
|
478
633
|
{
|
|
479
634
|
type: "submit",
|
|
@@ -482,7 +637,7 @@ function VerifyEmailForm({
|
|
|
482
637
|
children: isVerifying ? "Verifying..." : "Verify email"
|
|
483
638
|
}
|
|
484
639
|
),
|
|
485
|
-
/* @__PURE__ */
|
|
640
|
+
/* @__PURE__ */ jsx6(
|
|
486
641
|
"button",
|
|
487
642
|
{
|
|
488
643
|
type: "button",
|
|
@@ -493,10 +648,10 @@ function VerifyEmailForm({
|
|
|
493
648
|
}
|
|
494
649
|
)
|
|
495
650
|
] }),
|
|
496
|
-
/* @__PURE__ */
|
|
651
|
+
/* @__PURE__ */ jsxs6("p", { className: "text-center text-sm text-muted-foreground", children: [
|
|
497
652
|
"Already verified?",
|
|
498
653
|
" ",
|
|
499
|
-
/* @__PURE__ */
|
|
654
|
+
/* @__PURE__ */ jsx6(
|
|
500
655
|
"a",
|
|
501
656
|
{
|
|
502
657
|
href: "/login",
|
|
@@ -509,16 +664,16 @@ function VerifyEmailForm({
|
|
|
509
664
|
}
|
|
510
665
|
|
|
511
666
|
// src/components/forgot-password-form.tsx
|
|
512
|
-
import { useState as
|
|
513
|
-
import { jsx as
|
|
667
|
+
import { useState as useState5 } from "react";
|
|
668
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
514
669
|
function ForgotPasswordForm({
|
|
515
670
|
onSuccess,
|
|
516
671
|
loginUrl = "/login",
|
|
517
672
|
authClient
|
|
518
673
|
}) {
|
|
519
|
-
const [email, setEmail] =
|
|
520
|
-
const [error, setError] =
|
|
521
|
-
const [isPending, setIsPending] =
|
|
674
|
+
const [email, setEmail] = useState5("");
|
|
675
|
+
const [error, setError] = useState5();
|
|
676
|
+
const [isPending, setIsPending] = useState5(false);
|
|
522
677
|
const handleSubmit = async (e) => {
|
|
523
678
|
e.preventDefault();
|
|
524
679
|
if (!email.trim()) {
|
|
@@ -543,14 +698,14 @@ function ForgotPasswordForm({
|
|
|
543
698
|
setIsPending(false);
|
|
544
699
|
}
|
|
545
700
|
};
|
|
546
|
-
return /* @__PURE__ */
|
|
547
|
-
/* @__PURE__ */
|
|
548
|
-
/* @__PURE__ */
|
|
549
|
-
/* @__PURE__ */
|
|
701
|
+
return /* @__PURE__ */ jsxs7("div", { className: "space-y-8", children: [
|
|
702
|
+
/* @__PURE__ */ jsxs7("div", { children: [
|
|
703
|
+
/* @__PURE__ */ jsx7("h1", { className: "text-2xl font-bold tracking-tight", children: "Forgot your password?" }),
|
|
704
|
+
/* @__PURE__ */ jsx7("p", { className: "mt-1 text-sm text-muted-foreground", children: "Enter your email address and we'll send you a code to reset your password." })
|
|
550
705
|
] }),
|
|
551
|
-
error && /* @__PURE__ */
|
|
552
|
-
/* @__PURE__ */
|
|
553
|
-
/* @__PURE__ */
|
|
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(
|
|
554
709
|
"input",
|
|
555
710
|
{
|
|
556
711
|
type: "email",
|
|
@@ -563,7 +718,7 @@ function ForgotPasswordForm({
|
|
|
563
718
|
className: "flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm 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"
|
|
564
719
|
}
|
|
565
720
|
),
|
|
566
|
-
/* @__PURE__ */
|
|
721
|
+
/* @__PURE__ */ jsx7(
|
|
567
722
|
"button",
|
|
568
723
|
{
|
|
569
724
|
type: "submit",
|
|
@@ -573,10 +728,10 @@ function ForgotPasswordForm({
|
|
|
573
728
|
}
|
|
574
729
|
)
|
|
575
730
|
] }),
|
|
576
|
-
/* @__PURE__ */
|
|
731
|
+
/* @__PURE__ */ jsxs7("p", { className: "text-center text-sm text-muted-foreground", children: [
|
|
577
732
|
"Remember your password?",
|
|
578
733
|
" ",
|
|
579
|
-
/* @__PURE__ */
|
|
734
|
+
/* @__PURE__ */ jsx7(
|
|
580
735
|
"a",
|
|
581
736
|
{
|
|
582
737
|
href: loginUrl,
|
|
@@ -589,21 +744,21 @@ function ForgotPasswordForm({
|
|
|
589
744
|
}
|
|
590
745
|
|
|
591
746
|
// src/components/reset-password-form.tsx
|
|
592
|
-
import { useState as
|
|
593
|
-
import { jsx as
|
|
747
|
+
import { useState as useState6 } from "react";
|
|
748
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
594
749
|
function ResetPasswordForm({
|
|
595
750
|
email,
|
|
596
751
|
onSuccess,
|
|
597
752
|
loginUrl = "/login",
|
|
598
753
|
authClient
|
|
599
754
|
}) {
|
|
600
|
-
const [otp, setOtp] =
|
|
601
|
-
const [password, setPassword] =
|
|
602
|
-
const [confirmPassword, setConfirmPassword] =
|
|
603
|
-
const [error, setError] =
|
|
604
|
-
const [isResetting, setIsResetting] =
|
|
605
|
-
const [isResending, setIsResending] =
|
|
606
|
-
const [resendMessage, setResendMessage] =
|
|
755
|
+
const [otp, setOtp] = useState6("");
|
|
756
|
+
const [password, setPassword] = useState6("");
|
|
757
|
+
const [confirmPassword, setConfirmPassword] = useState6("");
|
|
758
|
+
const [error, setError] = useState6();
|
|
759
|
+
const [isResetting, setIsResetting] = useState6(false);
|
|
760
|
+
const [isResending, setIsResending] = useState6(false);
|
|
761
|
+
const [resendMessage, setResendMessage] = useState6();
|
|
607
762
|
const handleSubmit = async (e) => {
|
|
608
763
|
e.preventDefault();
|
|
609
764
|
if (!otp.trim() || otp.length < 6) {
|
|
@@ -656,20 +811,20 @@ function ResetPasswordForm({
|
|
|
656
811
|
setIsResending(false);
|
|
657
812
|
}
|
|
658
813
|
};
|
|
659
|
-
return /* @__PURE__ */
|
|
660
|
-
/* @__PURE__ */
|
|
661
|
-
/* @__PURE__ */
|
|
662
|
-
/* @__PURE__ */
|
|
814
|
+
return /* @__PURE__ */ jsxs8("div", { className: "space-y-8", children: [
|
|
815
|
+
/* @__PURE__ */ jsxs8("div", { children: [
|
|
816
|
+
/* @__PURE__ */ jsx8("h1", { className: "text-2xl font-bold tracking-tight", children: "Reset your password" }),
|
|
817
|
+
/* @__PURE__ */ jsxs8("p", { className: "mt-1 text-sm text-muted-foreground", children: [
|
|
663
818
|
"Enter the 6-digit code sent to",
|
|
664
819
|
" ",
|
|
665
|
-
/* @__PURE__ */
|
|
820
|
+
/* @__PURE__ */ jsx8("span", { className: "font-medium text-foreground", children: email }),
|
|
666
821
|
" and your new password."
|
|
667
822
|
] })
|
|
668
823
|
] }),
|
|
669
|
-
error && /* @__PURE__ */
|
|
670
|
-
resendMessage && /* @__PURE__ */
|
|
671
|
-
/* @__PURE__ */
|
|
672
|
-
/* @__PURE__ */
|
|
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(
|
|
673
828
|
"input",
|
|
674
829
|
{
|
|
675
830
|
type: "text",
|
|
@@ -685,7 +840,7 @@ function ResetPasswordForm({
|
|
|
685
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"
|
|
686
841
|
}
|
|
687
842
|
),
|
|
688
|
-
/* @__PURE__ */
|
|
843
|
+
/* @__PURE__ */ jsx8(
|
|
689
844
|
"input",
|
|
690
845
|
{
|
|
691
846
|
type: "password",
|
|
@@ -698,7 +853,7 @@ function ResetPasswordForm({
|
|
|
698
853
|
className: "flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm 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"
|
|
699
854
|
}
|
|
700
855
|
),
|
|
701
|
-
/* @__PURE__ */
|
|
856
|
+
/* @__PURE__ */ jsx8(
|
|
702
857
|
"input",
|
|
703
858
|
{
|
|
704
859
|
type: "password",
|
|
@@ -711,7 +866,7 @@ function ResetPasswordForm({
|
|
|
711
866
|
className: "flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm 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"
|
|
712
867
|
}
|
|
713
868
|
),
|
|
714
|
-
/* @__PURE__ */
|
|
869
|
+
/* @__PURE__ */ jsx8(
|
|
715
870
|
"button",
|
|
716
871
|
{
|
|
717
872
|
type: "submit",
|
|
@@ -720,7 +875,7 @@ function ResetPasswordForm({
|
|
|
720
875
|
children: isResetting ? "Resetting..." : "Reset password"
|
|
721
876
|
}
|
|
722
877
|
),
|
|
723
|
-
/* @__PURE__ */
|
|
878
|
+
/* @__PURE__ */ jsx8(
|
|
724
879
|
"button",
|
|
725
880
|
{
|
|
726
881
|
type: "button",
|
|
@@ -731,10 +886,10 @@ function ResetPasswordForm({
|
|
|
731
886
|
}
|
|
732
887
|
)
|
|
733
888
|
] }),
|
|
734
|
-
/* @__PURE__ */
|
|
889
|
+
/* @__PURE__ */ jsxs8("p", { className: "text-center text-sm text-muted-foreground", children: [
|
|
735
890
|
"Remember your password?",
|
|
736
891
|
" ",
|
|
737
|
-
/* @__PURE__ */
|
|
892
|
+
/* @__PURE__ */ jsx8(
|
|
738
893
|
"a",
|
|
739
894
|
{
|
|
740
895
|
href: loginUrl,
|
|
@@ -747,7 +902,7 @@ function ResetPasswordForm({
|
|
|
747
902
|
}
|
|
748
903
|
|
|
749
904
|
// src/components/auth-layout.tsx
|
|
750
|
-
import { jsx as
|
|
905
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
751
906
|
function AuthLayout({
|
|
752
907
|
logo,
|
|
753
908
|
title,
|
|
@@ -755,19 +910,19 @@ function AuthLayout({
|
|
|
755
910
|
children,
|
|
756
911
|
footer
|
|
757
912
|
}) {
|
|
758
|
-
return /* @__PURE__ */
|
|
759
|
-
/* @__PURE__ */
|
|
760
|
-
logo && /* @__PURE__ */
|
|
761
|
-
/* @__PURE__ */
|
|
762
|
-
subtitle && /* @__PURE__ */
|
|
913
|
+
return /* @__PURE__ */ jsx9("div", { className: "flex min-h-dvh flex-col bg-background px-5 pb-10 pt-12 sm:items-center sm:justify-center sm:bg-muted/40 sm:px-6 sm:py-12", children: /* @__PURE__ */ jsxs9("div", { className: "mx-auto w-full max-w-[420px]", children: [
|
|
914
|
+
/* @__PURE__ */ jsxs9("div", { className: "mb-8 text-center sm:mb-7", children: [
|
|
915
|
+
logo && /* @__PURE__ */ jsx9("div", { className: "mb-5 flex justify-center", children: logo }),
|
|
916
|
+
/* @__PURE__ */ jsx9("p", { className: "text-sm font-medium tracking-[0.02em] text-foreground", children: title }),
|
|
917
|
+
subtitle && /* @__PURE__ */ jsx9("p", { className: "mt-1 text-sm text-muted-foreground", children: subtitle })
|
|
763
918
|
] }),
|
|
764
|
-
/* @__PURE__ */
|
|
765
|
-
footer && /* @__PURE__ */
|
|
919
|
+
/* @__PURE__ */ jsx9("div", { className: "sm:rounded-2xl sm:border sm:border-border/70 sm:bg-card sm:p-8 sm:shadow-lg sm:shadow-black/5", children }),
|
|
920
|
+
footer && /* @__PURE__ */ jsx9("div", { className: "mt-6 text-center text-xs leading-relaxed text-muted-foreground", children: footer })
|
|
766
921
|
] }) });
|
|
767
922
|
}
|
|
768
923
|
|
|
769
924
|
// src/components/invitation-notice.tsx
|
|
770
|
-
import { jsx as
|
|
925
|
+
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
771
926
|
function defaultSupportEmail() {
|
|
772
927
|
if (typeof window === "undefined") return void 0;
|
|
773
928
|
const host = window.location.hostname;
|
|
@@ -787,15 +942,15 @@ function InvitationNotice({
|
|
|
787
942
|
action
|
|
788
943
|
}) {
|
|
789
944
|
const contact = supportEmail ?? defaultSupportEmail();
|
|
790
|
-
return /* @__PURE__ */
|
|
791
|
-
/* @__PURE__ */
|
|
792
|
-
/* @__PURE__ */
|
|
793
|
-
/* @__PURE__ */
|
|
945
|
+
return /* @__PURE__ */ jsxs10("div", { className: "space-y-8", children: [
|
|
946
|
+
/* @__PURE__ */ jsxs10("div", { children: [
|
|
947
|
+
/* @__PURE__ */ jsx10("h1", { className: "text-2xl font-bold tracking-tight", children: title }),
|
|
948
|
+
/* @__PURE__ */ jsx10("p", { className: "mt-1 text-sm text-muted-foreground", children: REASON_MESSAGE[reason] ?? REASON_MESSAGE.unknown })
|
|
794
949
|
] }),
|
|
795
|
-
contact ? /* @__PURE__ */
|
|
950
|
+
contact ? /* @__PURE__ */ jsxs10("p", { className: "text-sm text-muted-foreground", children: [
|
|
796
951
|
"\xC9crivez-nous \xE0",
|
|
797
952
|
" ",
|
|
798
|
-
/* @__PURE__ */
|
|
953
|
+
/* @__PURE__ */ jsx10(
|
|
799
954
|
"a",
|
|
800
955
|
{
|
|
801
956
|
href: `mailto:${contact}`,
|
|
@@ -810,7 +965,9 @@ function InvitationNotice({
|
|
|
810
965
|
] });
|
|
811
966
|
}
|
|
812
967
|
export {
|
|
968
|
+
AuthField,
|
|
813
969
|
AuthLayout,
|
|
970
|
+
AuthSubmit,
|
|
814
971
|
ForgotPasswordForm,
|
|
815
972
|
InvitationNotice,
|
|
816
973
|
LoginForm,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/use-session.ts","../src/components/login-form.tsx","../src/components/social-buttons.tsx","../src/components/register-form.tsx","../src/components/verify-email-form.tsx","../src/components/forgot-password-form.tsx","../src/components/reset-password-form.tsx","../src/components/auth-layout.tsx","../src/components/invitation-notice.tsx"],"sourcesContent":["import type { PlatformAuthClient } from \"../client\"\n\n/**\n * Returns a useSession hook bound to the given auth client.\n * Usage: const { data: session, isPending } = useSession(authClient)\n */\nexport function useSession(authClient: PlatformAuthClient) {\n return authClient.useSession()\n}\n\n/**\n * Returns a logout function bound to the given auth client.\n * Usage: const logout = useLogout(authClient)\n */\nexport function useLogout(authClient: PlatformAuthClient) {\n const signOut = async () => {\n await authClient.signOut()\n }\n return signOut\n}\n","import { useState, type FormEvent } from \"react\"\nimport type { LoginFormLabels, LoginFormProps } from \"../types\"\nimport { SocialButtons } from \"./social-buttons\"\n\nconst DEFAULTS: Required<LoginFormLabels> = {\n title: \"Connexion\",\n subtitle: \"Content de te revoir. Entre tes identifiants pour continuer.\",\n emailPlaceholder: \"Adresse e-mail\",\n passwordPlaceholder: \"Mot de passe\",\n forgotPassword: \"Mot de passe oublié ?\",\n submit: \"Se connecter\",\n submitPending: \"Connexion…\",\n noAccount: \"Pas encore de compte ?\",\n register: \"Créer un compte\",\n emailRequired: \"Renseigne ton adresse e-mail\",\n passwordRequired: \"Renseigne ton mot de passe\",\n invalidCredentials: \"Adresse e-mail ou mot de passe incorrect\",\n // accountLinking is disabled in createPlatformAuth, so a social sign-in on an\n // address already registered with a password is refused with this code.\n // Without a message the button reads as broken rather than as a rejection.\n accountNotLinked:\n \"Cette adresse est déjà associée à un mot de passe. Connecte-toi avec ton mot de passe.\",\n socialCancelled: \"Connexion annulée.\",\n socialFailed: \"La connexion a échoué. Réessaie.\",\n}\n\nexport function LoginForm({\n onSuccess,\n registerUrl = \"/register\",\n forgotPasswordUrl = \"/forgot-password\",\n socialCallbackUrl = \"/\",\n socialProviders = [],\n coreTokenUrl = \"/api/auth/core-token\",\n labels,\n authClient,\n}: LoginFormProps) {\n const t = { ...DEFAULTS, ...labels }\n const [email, setEmail] = useState(\"\")\n const [password, setPassword] = useState(\"\")\n const [error, setError] = useState<string | undefined>()\n const [isPending, setIsPending] = useState(false)\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault()\n if (!email.trim()) {\n setError(t.emailRequired)\n return\n }\n if (!password) {\n setError(t.passwordRequired)\n return\n }\n setError(undefined)\n setIsPending(true)\n try {\n const res = await authClient.signIn.email({\n email: email.trim(),\n password,\n })\n if (res?.error) {\n setError(res.error.message ?? t.invalidCredentials)\n return\n }\n // The better-auth session cookie alone does not authenticate a Go core:\n // it verifies the EdDSA JWT minted here against the issuer's JWKS.\n // Skipped when the app sets the token itself, or has no core at all.\n if (coreTokenUrl) {\n await fetch(coreTokenUrl, { credentials: \"include\" })\n }\n onSuccess?.()\n } catch (err) {\n setError(err instanceof Error ? err.message : t.invalidCredentials)\n } finally {\n setIsPending(false)\n }\n }\n\n const handleSocial = async (provider: \"google\" | \"github\") => {\n setError(undefined)\n try {\n await authClient.signIn.social({\n provider,\n callbackURL: socialCallbackUrl,\n })\n } catch (err) {\n const code = err instanceof Error ? err.message : \"\"\n setError(\n code === \"account_not_linked\"\n ? t.accountNotLinked\n : code === \"access_denied\"\n ? t.socialCancelled\n : t.socialFailed,\n )\n }\n }\n\n return (\n <div className=\"space-y-8\">\n <div>\n <h1 className=\"text-2xl font-bold tracking-tight\">{t.title}</h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">{t.subtitle}</p>\n </div>\n\n {error && (\n <div\n role=\"alert\"\n className=\"rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive\"\n >\n {error}\n </div>\n )}\n\n <form onSubmit={handleSubmit} className=\"space-y-4\" noValidate>\n <input\n type=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder={t.emailPlaceholder}\n aria-label={t.emailPlaceholder}\n required\n disabled={isPending}\n autoComplete=\"email\"\n className=\"flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm 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\"\n />\n\n <div className=\"space-y-1\">\n <input\n type=\"password\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n placeholder={t.passwordPlaceholder}\n aria-label={t.passwordPlaceholder}\n required\n disabled={isPending}\n autoComplete=\"current-password\"\n className=\"flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm 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\"\n />\n <div className=\"text-right\">\n <a\n href={forgotPasswordUrl}\n className=\"text-xs text-muted-foreground underline underline-offset-4 hover:text-foreground\"\n >\n {t.forgotPassword}\n </a>\n </div>\n </div>\n\n <button\n type=\"submit\"\n disabled={isPending || !email.trim() || !password}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50\"\n >\n {isPending ? t.submitPending : t.submit}\n </button>\n </form>\n\n <SocialButtons\n providers={socialProviders}\n onSelect={handleSocial}\n disabled={isPending}\n />\n\n <p className=\"text-center text-sm text-muted-foreground\">\n {t.noAccount}{\" \"}\n <a\n href={registerUrl}\n className=\"font-medium text-foreground underline underline-offset-4 hover:text-foreground/80\"\n >\n {t.register}\n </a>\n </p>\n </div>\n )\n}\n","const LABELS: Record<string, string> = {\n google: \"Continuer avec Google\",\n github: \"Continuer avec GitHub\",\n}\n\ninterface SocialButtonsProps {\n providers: Array<\"google\" | \"github\">\n onSelect: (provider: \"google\" | \"github\") => void | Promise<void>\n disabled?: boolean\n /** Divider text between the password form and the providers */\n separator?: string\n /** Per-provider button copy, merged over the French defaults */\n labels?: Partial<Record<\"google\" | \"github\", string>>\n}\n\nexport function SocialButtons({\n providers,\n onSelect,\n disabled = false,\n separator = \"ou\",\n labels,\n}: SocialButtonsProps) {\n if (providers.length === 0) return null\n\n const copy = { ...LABELS, ...labels }\n\n return (\n <div className=\"space-y-4\">\n <div className=\"relative\">\n <div className=\"absolute inset-0 flex items-center\">\n <div className=\"w-full border-t border-input\" />\n </div>\n <div className=\"relative flex justify-center\">\n <span className=\"bg-background px-2 text-xs uppercase tracking-wider text-muted-foreground\">\n {separator}\n </span>\n </div>\n </div>\n\n <div className=\"space-y-2\">\n {providers.map((provider) => (\n <button\n key={provider}\n type=\"button\"\n onClick={() => onSelect(provider)}\n disabled={disabled}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md border border-input bg-background px-4 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50\"\n >\n {copy[provider] ?? provider}\n </button>\n ))}\n </div>\n </div>\n )\n}\n","import { useState, type FormEvent } from \"react\"\nimport type { RegisterFormLabels, RegisterFormProps } from \"../types\"\nimport { SocialButtons } from \"./social-buttons\"\n\nconst MIN_PASSWORD_LENGTH = 8\n\nconst DEFAULTS: Required<RegisterFormLabels> = {\n title: \"Créer un compte\",\n subtitle: \"Nous t'enverrons un code pour confirmer ton adresse e-mail.\",\n namePlaceholder: \"Nom complet\",\n emailPlaceholder: \"Adresse e-mail\",\n passwordPlaceholder: \"Mot de passe\",\n passwordHint: `Au moins ${MIN_PASSWORD_LENGTH} caractères.`,\n submit: \"Créer mon compte\",\n submitPending: \"Création…\",\n haveAccount: \"Tu as déjà un compte ?\",\n login: \"Se connecter\",\n nameRequired: \"Renseigne ton nom\",\n emailRequired: \"Renseigne ton adresse e-mail\",\n passwordTooShort: `Le mot de passe doit faire au moins ${MIN_PASSWORD_LENGTH} caractères`,\n signUpFailed: \"La création du compte a échoué\",\n}\n\nexport function RegisterForm({\n onSuccess,\n loginUrl = \"/login\",\n legal,\n socialCallbackUrl = \"/\",\n socialProviders = [],\n labels,\n authClient,\n}: RegisterFormProps) {\n const t = { ...DEFAULTS, ...labels }\n const [name, setName] = useState(\"\")\n const [email, setEmail] = useState(\"\")\n const [password, setPassword] = useState(\"\")\n const [error, setError] = useState<string | undefined>()\n const [isPending, setIsPending] = useState(false)\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault()\n if (!name.trim()) {\n setError(t.nameRequired)\n return\n }\n if (!email.trim()) {\n setError(t.emailRequired)\n return\n }\n if (password.length < MIN_PASSWORD_LENGTH) {\n setError(t.passwordTooShort)\n return\n }\n setError(undefined)\n setIsPending(true)\n try {\n const res = await authClient.signUp.email({\n name: name.trim(),\n email: email.trim(),\n password,\n })\n if (res?.error) {\n setError(res.error.message ?? t.signUpFailed)\n return\n }\n // createPlatformAuth sets requireEmailVerification, so sign-up leaves the\n // account unverified and without a session: the caller routes to the OTP\n // step rather than into the app.\n onSuccess?.(email.trim())\n } catch (err) {\n setError(err instanceof Error ? err.message : t.signUpFailed)\n } finally {\n setIsPending(false)\n }\n }\n\n const handleSocial = async (provider: \"google\" | \"github\") => {\n setError(undefined)\n try {\n await authClient.signIn.social({\n provider,\n callbackURL: socialCallbackUrl,\n })\n } catch (err) {\n setError(err instanceof Error ? err.message : t.signUpFailed)\n }\n }\n\n return (\n <div className=\"space-y-8\">\n <div>\n <h1 className=\"text-2xl font-bold tracking-tight\">{t.title}</h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">{t.subtitle}</p>\n </div>\n\n {error && (\n <div\n role=\"alert\"\n className=\"rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive\"\n >\n {error}\n </div>\n )}\n\n <form onSubmit={handleSubmit} className=\"space-y-4\" noValidate>\n <input\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={t.namePlaceholder}\n aria-label={t.namePlaceholder}\n required\n disabled={isPending}\n autoComplete=\"name\"\n className=\"flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm 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\"\n />\n\n <input\n type=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder={t.emailPlaceholder}\n aria-label={t.emailPlaceholder}\n required\n disabled={isPending}\n autoComplete=\"email\"\n className=\"flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm 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\"\n />\n\n <div className=\"space-y-1\">\n <input\n type=\"password\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n placeholder={t.passwordPlaceholder}\n aria-label={t.passwordPlaceholder}\n required\n disabled={isPending}\n autoComplete=\"new-password\"\n aria-describedby=\"register-password-hint\"\n className=\"flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm 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\"\n />\n <p id=\"register-password-hint\" className=\"text-xs text-muted-foreground\">\n {t.passwordHint}\n </p>\n </div>\n\n <button\n type=\"submit\"\n disabled={isPending}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50\"\n >\n {isPending ? t.submitPending : t.submit}\n </button>\n\n {legal && (\n <div className=\"text-center text-xs text-muted-foreground\">{legal}</div>\n )}\n </form>\n\n <SocialButtons\n providers={socialProviders}\n onSelect={handleSocial}\n disabled={isPending}\n />\n\n <p className=\"text-center text-sm text-muted-foreground\">\n {t.haveAccount}{\" \"}\n <a\n href={loginUrl}\n className=\"font-medium text-foreground underline underline-offset-4 hover:text-foreground/80\"\n >\n {t.login}\n </a>\n </p>\n </div>\n )\n}\n","import { useState, type FormEvent } from \"react\"\nimport type { VerifyEmailFormProps } from \"../types\"\n\nexport function VerifyEmailForm({\n email,\n onSuccess,\n authClient,\n}: VerifyEmailFormProps) {\n const [otp, setOtp] = useState(\"\")\n const [isVerifying, setIsVerifying] = useState(false)\n const [isResending, setIsResending] = useState(false)\n const [resendMessage, setResendMessage] = useState<string | undefined>()\n const [error, setError] = useState<string | undefined>()\n\n const handleVerify = async (e: FormEvent) => {\n e.preventDefault()\n if (!otp.trim() || otp.length < 6) {\n setError(\"Please enter the 6-digit code\")\n return\n }\n setError(undefined)\n setIsVerifying(true)\n try {\n const res = await authClient.emailOtp.verifyEmail({ email, otp })\n console.log(\"[verify-email] response:\", JSON.stringify(res?.data), \"error:\", JSON.stringify(res?.error))\n if (res?.error) {\n setError(res.error.message ?? \"Invalid code. Please try again.\")\n return\n }\n onSuccess?.()\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Invalid code. Please try again.\")\n } finally {\n setIsVerifying(false)\n }\n }\n\n const handleResend = async () => {\n if (!email) {\n setError(\"Email address is not available. Please register again.\")\n return\n }\n setError(undefined)\n setResendMessage(undefined)\n setIsResending(true)\n try {\n await authClient.emailOtp.sendVerificationOtp({\n email,\n type: \"email-verification\",\n })\n setResendMessage(\"A new code has been sent to your inbox.\")\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Failed to resend code.\")\n } finally {\n setIsResending(false)\n }\n }\n\n return (\n <div className=\"space-y-8\">\n <div>\n <h1 className=\"text-2xl font-bold tracking-tight\">\n Verify your email\n </h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n {email ? (\n <>\n Enter the 6-digit code sent to{\" \"}\n <span className=\"font-medium text-foreground\">{email}</span>\n </>\n ) : (\n \"Enter the 6-digit code sent to your email\"\n )}\n </p>\n </div>\n\n {error && (\n <div className=\"rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive\">\n {error}\n </div>\n )}\n\n {resendMessage && (\n <div className=\"rounded-lg border border-green-200 bg-green-50 px-3 py-2 text-xs text-green-700\">\n {resendMessage}\n </div>\n )}\n\n <form onSubmit={handleVerify} className=\"space-y-4\" noValidate>\n <input\n type=\"text\"\n inputMode=\"numeric\"\n pattern=\"[0-9]*\"\n maxLength={6}\n value={otp}\n onChange={(e) => setOtp(e.target.value.replace(/\\D/g, \"\"))}\n placeholder=\"000000\"\n required\n disabled={isVerifying}\n autoComplete=\"one-time-code\"\n 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\"\n />\n\n <button\n type=\"submit\"\n disabled={isVerifying || otp.length < 6}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50\"\n >\n {isVerifying ? \"Verifying...\" : \"Verify email\"}\n </button>\n\n <button\n type=\"button\"\n onClick={handleResend}\n disabled={isResending}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md border border-input bg-background px-4 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50\"\n >\n {isResending ? \"Sending...\" : \"Resend code\"}\n </button>\n </form>\n\n <p className=\"text-center text-sm text-muted-foreground\">\n Already verified?{\" \"}\n <a\n href=\"/login\"\n className=\"font-medium text-foreground underline underline-offset-4 hover:text-foreground/80\"\n >\n Sign in\n </a>\n </p>\n </div>\n )\n}\n","import { useState, type FormEvent } from \"react\"\nimport type { ForgotPasswordFormProps } from \"../types\"\n\nexport function ForgotPasswordForm({\n onSuccess,\n loginUrl = \"/login\",\n authClient,\n}: ForgotPasswordFormProps) {\n const [email, setEmail] = useState(\"\")\n const [error, setError] = useState<string | undefined>()\n const [isPending, setIsPending] = useState(false)\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault()\n if (!email.trim()) {\n setError(\"Please enter your email address\")\n return\n }\n setError(undefined)\n setIsPending(true)\n try {\n const res = await authClient.emailOtp.sendVerificationOtp({\n email,\n type: \"forget-password\",\n })\n if (res?.error) {\n setError(res.error.message ?? \"Failed to send reset code\")\n return\n }\n onSuccess?.(email)\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Failed to send reset code\")\n } finally {\n setIsPending(false)\n }\n }\n\n return (\n <div className=\"space-y-8\">\n <div>\n <h1 className=\"text-2xl font-bold tracking-tight\">\n Forgot your password?\n </h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n Enter your email address and we'll send you a code to reset your\n password.\n </p>\n </div>\n\n {error && (\n <div className=\"rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive\">\n {error}\n </div>\n )}\n\n <form onSubmit={handleSubmit} className=\"space-y-4\" noValidate>\n <input\n type=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder=\"Email address\"\n required\n disabled={isPending}\n autoComplete=\"email\"\n className=\"flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm 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\"\n />\n\n <button\n type=\"submit\"\n disabled={isPending || !email.trim()}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50\"\n >\n {isPending ? \"Sending...\" : \"Send reset code\"}\n </button>\n </form>\n\n <p className=\"text-center text-sm text-muted-foreground\">\n Remember your password?{\" \"}\n <a\n href={loginUrl}\n className=\"font-medium text-foreground underline underline-offset-4 hover:text-foreground/80\"\n >\n Sign in\n </a>\n </p>\n </div>\n )\n}\n","import { useState, type FormEvent } from \"react\"\nimport type { ResetPasswordFormProps } from \"../types\"\n\nexport function ResetPasswordForm({\n email,\n onSuccess,\n loginUrl = \"/login\",\n authClient,\n}: ResetPasswordFormProps) {\n const [otp, setOtp] = useState(\"\")\n const [password, setPassword] = useState(\"\")\n const [confirmPassword, setConfirmPassword] = useState(\"\")\n const [error, setError] = useState<string | undefined>()\n const [isResetting, setIsResetting] = useState(false)\n const [isResending, setIsResending] = useState(false)\n const [resendMessage, setResendMessage] = useState<string | undefined>()\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault()\n if (!otp.trim() || otp.length < 6) {\n setError(\"Please enter the 6-digit code\")\n return\n }\n if (password.length < 8) {\n setError(\"Password must be at least 8 characters\")\n return\n }\n if (password !== confirmPassword) {\n setError(\"Passwords do not match\")\n return\n }\n setError(undefined)\n setIsResetting(true)\n try {\n const res = await fetch(\"/api/auth/email-otp/reset-password\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ email, otp, password }),\n })\n if (!res.ok) {\n const body = await res.json().catch(() => null)\n setError(body?.message ?? \"Failed to reset password\")\n return\n }\n onSuccess?.()\n } catch (err) {\n setError(\n err instanceof Error ? err.message : \"Failed to reset password\",\n )\n } finally {\n setIsResetting(false)\n }\n }\n\n const handleResend = async () => {\n setError(undefined)\n setResendMessage(undefined)\n setIsResending(true)\n try {\n await authClient.emailOtp.sendVerificationOtp({\n email,\n type: \"forget-password\",\n })\n setResendMessage(\"A new code has been sent to your inbox.\")\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Failed to resend code.\")\n } finally {\n setIsResending(false)\n }\n }\n\n return (\n <div className=\"space-y-8\">\n <div>\n <h1 className=\"text-2xl font-bold tracking-tight\">\n Reset your password\n </h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n Enter the 6-digit code sent to{\" \"}\n <span className=\"font-medium text-foreground\">{email}</span> and your\n new password.\n </p>\n </div>\n\n {error && (\n <div className=\"rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive\">\n {error}\n </div>\n )}\n\n {resendMessage && (\n <div className=\"rounded-lg border border-green-200 bg-green-50 px-3 py-2 text-xs text-green-700\">\n {resendMessage}\n </div>\n )}\n\n <form onSubmit={handleSubmit} className=\"space-y-4\" noValidate>\n <input\n type=\"text\"\n inputMode=\"numeric\"\n pattern=\"[0-9]*\"\n maxLength={6}\n value={otp}\n onChange={(e) => setOtp(e.target.value.replace(/\\D/g, \"\"))}\n placeholder=\"000000\"\n required\n disabled={isResetting}\n autoComplete=\"one-time-code\"\n 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\"\n />\n\n <input\n type=\"password\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n placeholder=\"New password\"\n required\n disabled={isResetting}\n autoComplete=\"new-password\"\n className=\"flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm 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\"\n />\n\n <input\n type=\"password\"\n value={confirmPassword}\n onChange={(e) => setConfirmPassword(e.target.value)}\n placeholder=\"Confirm new password\"\n required\n disabled={isResetting}\n autoComplete=\"new-password\"\n className=\"flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm 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\"\n />\n\n <button\n type=\"submit\"\n disabled={isResetting || otp.length < 6 || !password}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50\"\n >\n {isResetting ? \"Resetting...\" : \"Reset password\"}\n </button>\n\n <button\n type=\"button\"\n onClick={handleResend}\n disabled={isResending}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md border border-input bg-background px-4 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50\"\n >\n {isResending ? \"Sending...\" : \"Resend code\"}\n </button>\n </form>\n\n <p className=\"text-center text-sm text-muted-foreground\">\n Remember your password?{\" \"}\n <a\n href={loginUrl}\n className=\"font-medium text-foreground underline underline-offset-4 hover:text-foreground/80\"\n >\n Sign in\n </a>\n </p>\n </div>\n )\n}\n","import type { AuthLayoutProps } from \"../types\"\n\nexport function AuthLayout({\n logo,\n title,\n subtitle,\n children,\n footer,\n}: AuthLayoutProps) {\n return (\n <div className=\"flex min-h-screen items-center justify-center bg-background\">\n <div className=\"w-full max-w-md\">\n <div className=\"mb-10 text-center\">\n {logo && <div className=\"mb-6 flex justify-center\">{logo}</div>}\n <h1 className=\"text-[32px] font-light tracking-tight\">{title}</h1>\n {subtitle && (\n <p className=\"mt-2 text-sm text-muted-foreground\">{subtitle}</p>\n )}\n </div>\n\n <div className=\"rounded-xl border bg-card p-8 shadow-sm\">\n {children}\n </div>\n\n {footer && (\n <div className=\"mt-6 text-center text-xs text-muted-foreground\">\n {footer}\n </div>\n )}\n </div>\n </div>\n )\n}\n","import type { InvitationNoticeProps } from \"../types\"\n\n/**\n * Every app is reachable at contact@ its own apex domain, so the address is\n * derived rather than configured. Sub-domains are stripped because the app is\n * routinely served from app./admin. while the mailbox lives on the apex;\n * multi-part public suffixes (.co.uk) would need a real suffix list and no app\n * using this is on one.\n */\nfunction defaultSupportEmail(): string | undefined {\n if (typeof window === \"undefined\") return undefined\n const host = window.location.hostname\n if (!host || host === \"localhost\" || /^[\\d.]+$/.test(host)) return undefined\n const apex = host.split(\".\").slice(-2).join(\".\")\n return `contact@${apex}`\n}\n\nconst REASON_MESSAGE: Record<string, string> = {\n expired: \"Cette invitation a expiré.\",\n claimed: \"Cette invitation a déjà été utilisée.\",\n unknown: \"Ce lien d'invitation n'est pas valide.\",\n}\n\n/**\n * What an invitee sees when their link does not work.\n *\n * It names the reason instead of merging the cases into one message: \"expired\"\n * tells someone their link was real and that asking for another one is worth\n * it, which \"invalid\" does not. Short TTLs make that distinction routine.\n *\n * The only way forward offered is a mailto, deliberately. A self-service\n * \"request a new invitation\" form would mean a public endpoint accepting dead\n * tokens, a queue to moderate, and a way to probe which tokens once existed —\n * for a flow where the operator already knows the person by name.\n */\nexport function InvitationNotice({\n reason = \"unknown\",\n supportEmail,\n title = \"Invitation indisponible\",\n action,\n}: InvitationNoticeProps) {\n const contact = supportEmail ?? defaultSupportEmail()\n\n return (\n <div className=\"space-y-8\">\n <div>\n <h1 className=\"text-2xl font-bold tracking-tight\">{title}</h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n {REASON_MESSAGE[reason] ?? REASON_MESSAGE.unknown}\n </p>\n </div>\n\n {contact ? (\n <p className=\"text-sm text-muted-foreground\">\n Écrivez-nous à{\" \"}\n <a\n href={`mailto:${contact}`}\n className=\"font-medium text-foreground underline underline-offset-4 hover:text-foreground/80\"\n >\n {contact}\n </a>{\" \"}\n pour en recevoir une nouvelle.\n </p>\n ) : null}\n\n {action}\n </div>\n )\n}\n"],"mappings":"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","names":["jsx","jsxs","useState","jsx","jsxs","DEFAULTS","useState","useState","jsx","jsxs","useState","jsx","jsxs","useState","jsx","jsxs","jsx","jsxs","jsx","jsxs"]}
|
|
1
|
+
{"version":3,"sources":["../src/hooks/use-session.ts","../src/components/auth-field.tsx","../src/components/auth-submit.tsx","../src/components/login-form.tsx","../src/components/social-buttons.tsx","../src/components/register-form.tsx","../src/components/verify-email-form.tsx","../src/components/forgot-password-form.tsx","../src/components/reset-password-form.tsx","../src/components/auth-layout.tsx","../src/components/invitation-notice.tsx"],"sourcesContent":["import type { PlatformAuthClient } from \"../client\"\n\n/**\n * Returns a useSession hook bound to the given auth client.\n * Usage: const { data: session, isPending } = useSession(authClient)\n */\nexport function useSession(authClient: PlatformAuthClient) {\n return authClient.useSession()\n}\n\n/**\n * Returns a logout function bound to the given auth client.\n * Usage: const logout = useLogout(authClient)\n */\nexport function useLogout(authClient: PlatformAuthClient) {\n const signOut = async () => {\n await authClient.signOut()\n }\n return signOut\n}\n","import { useId, useState, type InputHTMLAttributes, type ReactNode } from \"react\"\n\ntype NativeProps = Omit<InputHTMLAttributes<HTMLInputElement>, \"id\" | \"className\">\n\nexport interface AuthFieldProps extends NativeProps {\n label: string\n /** Rendered on the right of the label row — typically a \"forgot password\" link */\n hint?: ReactNode\n /** Persistent helper text under the field, tied to it for screen readers */\n description?: string\n invalid?: boolean\n}\n\n/**\n * A single credential field.\n *\n * The label is a real <label>, always visible, never a placeholder standing in\n * for one: a placeholder disappears the moment someone types, which is exactly\n * when a person double-checking a long password needs to know what the box is.\n *\n * Touch targets are 52px tall on mobile and 44px from sm up. Below ~48px,\n * thumbs miss; on a pointer device the same height reads as oversized, so the\n * two are not one compromise value.\n *\n * The focus ring is a ring rather than an outline so it follows the rounded\n * corners exactly, and the border darkens at the same time — the border is what\n * survives forced-colors mode, where the ring is dropped.\n */\nexport function AuthField({\n label,\n hint,\n description,\n invalid = false,\n ...props\n}: AuthFieldProps) {\n const id = useId()\n const descriptionId = description ? `${id}-description` : undefined\n const [revealed, setRevealed] = useState(false)\n\n const isPassword = props.type === \"password\"\n const type = isPassword && revealed ? \"text\" : props.type\n\n return (\n <div className=\"space-y-2\">\n <div className=\"flex items-baseline justify-between gap-3\">\n <label\n htmlFor={id}\n className=\"text-sm font-medium leading-none text-foreground\"\n >\n {label}\n </label>\n {hint}\n </div>\n\n <div className=\"relative\">\n <input\n {...props}\n id={id}\n type={type}\n aria-invalid={invalid || undefined}\n aria-describedby={descriptionId}\n className={[\n \"h-[52px] w-full rounded-xl border bg-background px-4 text-base\",\n \"sm:h-11 sm:text-sm\",\n isPassword ? \"pr-12\" : \"\",\n \"text-foreground placeholder:text-muted-foreground/70\",\n \"transition-[border-color,box-shadow] duration-150 ease-out\",\n \"focus-visible:outline-none focus-visible:ring-[3px]\",\n invalid\n ? \"border-destructive focus-visible:border-destructive focus-visible:ring-destructive/20\"\n : \"border-input focus-visible:border-ring focus-visible:ring-ring/15\",\n \"disabled:cursor-not-allowed disabled:opacity-60\",\n ]\n .filter(Boolean)\n .join(\" \")}\n />\n\n {isPassword && (\n <button\n type=\"button\"\n onClick={() => setRevealed((v) => !v)}\n disabled={props.disabled}\n aria-pressed={revealed}\n aria-label={\n revealed ? \"Masquer le mot de passe\" : \"Afficher le mot de passe\"\n }\n className=\"absolute inset-y-0 right-0 flex w-12 items-center justify-center rounded-r-xl text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-60\"\n >\n <EyeIcon open={revealed} />\n </button>\n )}\n </div>\n\n {description && (\n <p id={descriptionId} className=\"text-xs text-muted-foreground\">\n {description}\n </p>\n )}\n </div>\n )\n}\n\n// Inline rather than from lucide-react: the package would gain a dependency\n// consumers already have at a different version, for two paths.\nfunction EyeIcon({ open }: { open: boolean }) {\n return (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M2.06 12.35a1 1 0 0 1 0-.7 10.75 10.75 0 0 1 19.88 0 1 1 0 0 1 0 .7 10.75 10.75 0 0 1-19.88 0Z\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n {!open && <path d=\"m3 3 18 18\" />}\n </svg>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface AuthSubmitProps {\n pending?: boolean\n disabled?: boolean\n pendingLabel: string\n children: ReactNode\n}\n\n/**\n * The primary action of an auth screen.\n *\n * The label swaps to its pending form in place, with the spinner absolutely\n * positioned: a spinner inserted into the flow would widen the row and shift\n * the text sideways at the exact moment the person is watching it.\n *\n * The press feedback is a 1px translate rather than a scale — scaling a\n * full-width button visibly blurs its text mid-transform.\n */\nexport function AuthSubmit({\n pending = false,\n disabled = false,\n pendingLabel,\n children,\n}: AuthSubmitProps) {\n return (\n <button\n type=\"submit\"\n disabled={disabled || pending}\n aria-busy={pending || undefined}\n className={[\n \"relative flex h-[52px] w-full items-center justify-center rounded-xl sm:h-11\",\n \"bg-primary text-base font-medium text-primary-foreground sm:text-sm\",\n \"shadow-sm transition-[background-color,transform,box-shadow] duration-150 ease-out\",\n \"hover:bg-primary/90 active:translate-y-px\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n \"disabled:pointer-events-none disabled:opacity-55\",\n ].join(\" \")}\n >\n {pending && (\n <span\n aria-hidden=\"true\"\n className=\"absolute left-4 size-4 animate-spin rounded-full border-2 border-current border-t-transparent opacity-70 motion-reduce:animate-none\"\n />\n )}\n {pending ? pendingLabel : children}\n </button>\n )\n}\n","import { useState, type FormEvent } from \"react\"\nimport type { LoginFormLabels, LoginFormProps } from \"../types\"\nimport { AuthField } from \"./auth-field\"\nimport { AuthSubmit } from \"./auth-submit\"\nimport { SocialButtons } from \"./social-buttons\"\n\nconst DEFAULTS: Required<LoginFormLabels> = {\n title: \"Connexion\",\n subtitle: \"Content de te revoir. Entre tes identifiants pour continuer.\",\n emailPlaceholder: \"Adresse e-mail\",\n passwordPlaceholder: \"Mot de passe\",\n forgotPassword: \"Mot de passe oublié ?\",\n submit: \"Se connecter\",\n submitPending: \"Connexion…\",\n noAccount: \"Pas encore de compte ?\",\n register: \"Créer un compte\",\n emailRequired: \"Renseigne ton adresse e-mail\",\n passwordRequired: \"Renseigne ton mot de passe\",\n invalidCredentials: \"Adresse e-mail ou mot de passe incorrect\",\n // accountLinking is disabled in createPlatformAuth, so a social sign-in on an\n // address already registered with a password is refused with this code.\n // Without a message the button reads as broken rather than as a rejection.\n accountNotLinked:\n \"Cette adresse est déjà associée à un mot de passe. Connecte-toi avec ton mot de passe.\",\n socialCancelled: \"Connexion annulée.\",\n socialFailed: \"La connexion a échoué. Réessaie.\",\n}\n\nexport function LoginForm({\n onSuccess,\n registerUrl = \"/register\",\n forgotPasswordUrl = \"/forgot-password\",\n socialCallbackUrl = \"/\",\n socialProviders = [],\n coreTokenUrl = \"/api/auth/core-token\",\n labels,\n authClient,\n}: LoginFormProps) {\n const t = { ...DEFAULTS, ...labels }\n const [email, setEmail] = useState(\"\")\n const [password, setPassword] = useState(\"\")\n const [error, setError] = useState<string | undefined>()\n const [isPending, setIsPending] = useState(false)\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault()\n if (!email.trim()) {\n setError(t.emailRequired)\n return\n }\n if (!password) {\n setError(t.passwordRequired)\n return\n }\n setError(undefined)\n setIsPending(true)\n try {\n const res = await authClient.signIn.email({\n email: email.trim(),\n password,\n })\n if (res?.error) {\n setError(res.error.message ?? t.invalidCredentials)\n return\n }\n // The better-auth session cookie alone does not authenticate a Go core:\n // it verifies the EdDSA JWT minted here against the issuer's JWKS.\n // Skipped when the app sets the token itself, or has no core at all.\n if (coreTokenUrl) {\n await fetch(coreTokenUrl, { credentials: \"include\" })\n }\n onSuccess?.()\n } catch (err) {\n setError(err instanceof Error ? err.message : t.invalidCredentials)\n } finally {\n setIsPending(false)\n }\n }\n\n const handleSocial = async (provider: \"google\" | \"github\") => {\n setError(undefined)\n try {\n await authClient.signIn.social({\n provider,\n callbackURL: socialCallbackUrl,\n })\n } catch (err) {\n const code = err instanceof Error ? err.message : \"\"\n setError(\n code === \"account_not_linked\"\n ? t.accountNotLinked\n : code === \"access_denied\"\n ? t.socialCancelled\n : t.socialFailed,\n )\n }\n }\n\n return (\n <div className=\"space-y-7\">\n <header className=\"space-y-1.5\">\n <h1 className=\"text-[26px] font-semibold leading-tight tracking-[-0.02em] text-foreground sm:text-2xl\">\n {t.title}\n </h1>\n <p className=\"text-sm leading-relaxed text-muted-foreground\">\n {t.subtitle}\n </p>\n </header>\n\n {error && (\n <div\n role=\"alert\"\n className=\"rounded-xl border border-destructive/25 bg-destructive/10 px-3.5 py-3 text-sm leading-snug text-destructive\"\n >\n {error}\n </div>\n )}\n\n <form onSubmit={handleSubmit} className=\"space-y-5\" noValidate>\n <AuthField\n label={t.emailPlaceholder}\n type=\"email\"\n inputMode=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n required\n disabled={isPending}\n autoComplete=\"email\"\n autoCapitalize=\"none\"\n spellCheck={false}\n invalid={!!error}\n />\n\n <AuthField\n label={t.passwordPlaceholder}\n type=\"password\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n required\n disabled={isPending}\n autoComplete=\"current-password\"\n invalid={!!error}\n hint={\n <a\n href={forgotPasswordUrl}\n className=\"rounded text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-foreground hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n {t.forgotPassword}\n </a>\n }\n />\n\n <AuthSubmit\n pending={isPending}\n disabled={!email.trim() || !password}\n pendingLabel={t.submitPending}\n >\n {t.submit}\n </AuthSubmit>\n </form>\n\n <SocialButtons\n providers={socialProviders}\n onSelect={handleSocial}\n disabled={isPending}\n />\n\n <p className=\"text-center text-sm text-muted-foreground\">\n {t.noAccount}{\" \"}\n <a\n href={registerUrl}\n 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\"\n >\n {t.register}\n </a>\n </p>\n </div>\n )\n}\n","const LABELS: Record<string, string> = {\n google: \"Continuer avec Google\",\n github: \"Continuer avec GitHub\",\n}\n\ninterface SocialButtonsProps {\n providers: Array<\"google\" | \"github\">\n onSelect: (provider: \"google\" | \"github\") => void | Promise<void>\n disabled?: boolean\n /** Divider text between the password form and the providers */\n separator?: string\n /** Per-provider button copy, merged over the French defaults */\n labels?: Partial<Record<\"google\" | \"github\", string>>\n}\n\nexport function SocialButtons({\n providers,\n onSelect,\n disabled = false,\n separator = \"ou\",\n labels,\n}: SocialButtonsProps) {\n if (providers.length === 0) return null\n\n const copy = { ...LABELS, ...labels }\n\n return (\n <div className=\"space-y-4\">\n {/* The rule is two flex segments rather than a line behind an opaque\n label: an opaque background only hides the rule when it matches the\n surface behind it, which breaks the moment this sits on a card. */}\n <div aria-hidden=\"true\" className=\"flex items-center gap-3\">\n <span className=\"h-px flex-1 bg-border\" />\n <span className=\"text-[11px] uppercase tracking-[0.14em] text-muted-foreground\">\n {separator}\n </span>\n <span className=\"h-px flex-1 bg-border\" />\n </div>\n\n <div className=\"space-y-2.5\">\n {providers.map((provider) => (\n <button\n key={provider}\n type=\"button\"\n onClick={() => onSelect(provider)}\n disabled={disabled}\n className={[\n \"flex h-[52px] w-full items-center justify-center gap-2.5 rounded-xl sm:h-11\",\n \"border border-input bg-background text-base font-medium text-foreground sm:text-sm\",\n \"transition-[background-color,border-color,transform] duration-150 ease-out\",\n \"hover:border-foreground/20 hover:bg-accent active:translate-y-px\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n \"disabled:pointer-events-none disabled:opacity-55\",\n ].join(\" \")}\n >\n <ProviderMark provider={provider} />\n {copy[provider] ?? provider}\n </button>\n ))}\n </div>\n </div>\n )\n}\n\n// Brand marks are inlined: they must keep their own colors (Google's mark is\n// unusable in monochrome) and adding an icon dependency to this package would\n// duplicate one every consumer already ships.\nfunction ProviderMark({ provider }: { provider: \"google\" | \"github\" }) {\n if (provider === \"google\") {\n return (\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 18 18\" aria-hidden=\"true\">\n <path\n fill=\"#4285F4\"\n 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\"\n />\n <path\n fill=\"#34A853\"\n 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\"\n />\n <path\n fill=\"#FBBC05\"\n 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\"\n />\n <path\n fill=\"#EA4335\"\n d=\"M9 3.58c1.32 0 2.5.45 3.44 1.35l2.58-2.58C13.46.9 11.43 0 9 0A9 9 0 0 0 .96 4.95l3.02 2.33C4.68 5.16 6.66 3.58 9 3.58Z\"\n />\n </svg>\n )\n }\n return (\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\">\n <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\" />\n </svg>\n )\n}\n","import { useState, type FormEvent } from \"react\"\nimport type { RegisterFormLabels, RegisterFormProps } from \"../types\"\nimport { AuthField } from \"./auth-field\"\nimport { AuthSubmit } from \"./auth-submit\"\nimport { SocialButtons } from \"./social-buttons\"\n\nconst MIN_PASSWORD_LENGTH = 8\n\nconst DEFAULTS: Required<RegisterFormLabels> = {\n title: \"Créer un compte\",\n subtitle: \"Nous t'enverrons un code pour confirmer ton adresse e-mail.\",\n namePlaceholder: \"Nom complet\",\n emailPlaceholder: \"Adresse e-mail\",\n passwordPlaceholder: \"Mot de passe\",\n passwordHint: `Au moins ${MIN_PASSWORD_LENGTH} caractères.`,\n submit: \"Créer mon compte\",\n submitPending: \"Création…\",\n haveAccount: \"Tu as déjà un compte ?\",\n login: \"Se connecter\",\n nameRequired: \"Renseigne ton nom\",\n emailRequired: \"Renseigne ton adresse e-mail\",\n passwordTooShort: `Le mot de passe doit faire au moins ${MIN_PASSWORD_LENGTH} caractères`,\n signUpFailed: \"La création du compte a échoué\",\n}\n\nexport function RegisterForm({\n onSuccess,\n loginUrl = \"/login\",\n legal,\n socialCallbackUrl = \"/\",\n socialProviders = [],\n labels,\n authClient,\n}: RegisterFormProps) {\n const t = { ...DEFAULTS, ...labels }\n const [name, setName] = useState(\"\")\n const [email, setEmail] = useState(\"\")\n const [password, setPassword] = useState(\"\")\n const [error, setError] = useState<string | undefined>()\n const [isPending, setIsPending] = useState(false)\n\n const tooShort = password.length > 0 && password.length < MIN_PASSWORD_LENGTH\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault()\n if (!name.trim()) {\n setError(t.nameRequired)\n return\n }\n if (!email.trim()) {\n setError(t.emailRequired)\n return\n }\n if (password.length < MIN_PASSWORD_LENGTH) {\n setError(t.passwordTooShort)\n return\n }\n setError(undefined)\n setIsPending(true)\n try {\n const res = await authClient.signUp.email({\n name: name.trim(),\n email: email.trim(),\n password,\n })\n if (res?.error) {\n setError(res.error.message ?? t.signUpFailed)\n return\n }\n // createPlatformAuth sets requireEmailVerification, so sign-up leaves the\n // account unverified and without a session: the caller routes to the OTP\n // step rather than into the app.\n onSuccess?.(email.trim())\n } catch (err) {\n setError(err instanceof Error ? err.message : t.signUpFailed)\n } finally {\n setIsPending(false)\n }\n }\n\n const handleSocial = async (provider: \"google\" | \"github\") => {\n setError(undefined)\n try {\n await authClient.signIn.social({\n provider,\n callbackURL: socialCallbackUrl,\n })\n } catch (err) {\n setError(err instanceof Error ? err.message : t.signUpFailed)\n }\n }\n\n return (\n <div className=\"space-y-7\">\n <header className=\"space-y-1.5\">\n <h1 className=\"text-[26px] font-semibold leading-tight tracking-[-0.02em] text-foreground sm:text-2xl\">\n {t.title}\n </h1>\n <p className=\"text-sm leading-relaxed text-muted-foreground\">\n {t.subtitle}\n </p>\n </header>\n\n {error && (\n <div\n role=\"alert\"\n className=\"rounded-xl border border-destructive/25 bg-destructive/10 px-3.5 py-3 text-sm leading-snug text-destructive\"\n >\n {error}\n </div>\n )}\n\n <form onSubmit={handleSubmit} className=\"space-y-5\" noValidate>\n <AuthField\n label={t.namePlaceholder}\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n required\n disabled={isPending}\n autoComplete=\"name\"\n />\n\n <AuthField\n label={t.emailPlaceholder}\n type=\"email\"\n inputMode=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n required\n disabled={isPending}\n autoComplete=\"email\"\n autoCapitalize=\"none\"\n spellCheck={false}\n />\n\n <AuthField\n label={t.passwordPlaceholder}\n type=\"password\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n required\n disabled={isPending}\n autoComplete=\"new-password\"\n description={t.passwordHint}\n // Only once they have typed something: flagging an untouched field\n // red would scold someone for not having started yet.\n invalid={tooShort}\n />\n\n <AuthSubmit pending={isPending} pendingLabel={t.submitPending}>\n {t.submit}\n </AuthSubmit>\n\n {legal && (\n <p className=\"text-center text-xs leading-relaxed text-muted-foreground\">\n {legal}\n </p>\n )}\n </form>\n\n <SocialButtons\n providers={socialProviders}\n onSelect={handleSocial}\n disabled={isPending}\n />\n\n <p className=\"text-center text-sm text-muted-foreground\">\n {t.haveAccount}{\" \"}\n <a\n href={loginUrl}\n 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\"\n >\n {t.login}\n </a>\n </p>\n </div>\n )\n}\n","import { useState, type FormEvent } from \"react\"\nimport type { VerifyEmailFormProps } from \"../types\"\n\nexport function VerifyEmailForm({\n email,\n onSuccess,\n authClient,\n}: VerifyEmailFormProps) {\n const [otp, setOtp] = useState(\"\")\n const [isVerifying, setIsVerifying] = useState(false)\n const [isResending, setIsResending] = useState(false)\n const [resendMessage, setResendMessage] = useState<string | undefined>()\n const [error, setError] = useState<string | undefined>()\n\n const handleVerify = async (e: FormEvent) => {\n e.preventDefault()\n if (!otp.trim() || otp.length < 6) {\n setError(\"Please enter the 6-digit code\")\n return\n }\n setError(undefined)\n setIsVerifying(true)\n try {\n const res = await authClient.emailOtp.verifyEmail({ email, otp })\n console.log(\"[verify-email] response:\", JSON.stringify(res?.data), \"error:\", JSON.stringify(res?.error))\n if (res?.error) {\n setError(res.error.message ?? \"Invalid code. Please try again.\")\n return\n }\n onSuccess?.()\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Invalid code. Please try again.\")\n } finally {\n setIsVerifying(false)\n }\n }\n\n const handleResend = async () => {\n if (!email) {\n setError(\"Email address is not available. Please register again.\")\n return\n }\n setError(undefined)\n setResendMessage(undefined)\n setIsResending(true)\n try {\n await authClient.emailOtp.sendVerificationOtp({\n email,\n type: \"email-verification\",\n })\n setResendMessage(\"A new code has been sent to your inbox.\")\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Failed to resend code.\")\n } finally {\n setIsResending(false)\n }\n }\n\n return (\n <div className=\"space-y-8\">\n <div>\n <h1 className=\"text-2xl font-bold tracking-tight\">\n Verify your email\n </h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n {email ? (\n <>\n Enter the 6-digit code sent to{\" \"}\n <span className=\"font-medium text-foreground\">{email}</span>\n </>\n ) : (\n \"Enter the 6-digit code sent to your email\"\n )}\n </p>\n </div>\n\n {error && (\n <div className=\"rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive\">\n {error}\n </div>\n )}\n\n {resendMessage && (\n <div className=\"rounded-lg border border-green-200 bg-green-50 px-3 py-2 text-xs text-green-700\">\n {resendMessage}\n </div>\n )}\n\n <form onSubmit={handleVerify} className=\"space-y-4\" noValidate>\n <input\n type=\"text\"\n inputMode=\"numeric\"\n pattern=\"[0-9]*\"\n maxLength={6}\n value={otp}\n onChange={(e) => setOtp(e.target.value.replace(/\\D/g, \"\"))}\n placeholder=\"000000\"\n required\n disabled={isVerifying}\n autoComplete=\"one-time-code\"\n 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\"\n />\n\n <button\n type=\"submit\"\n disabled={isVerifying || otp.length < 6}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50\"\n >\n {isVerifying ? \"Verifying...\" : \"Verify email\"}\n </button>\n\n <button\n type=\"button\"\n onClick={handleResend}\n disabled={isResending}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md border border-input bg-background px-4 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50\"\n >\n {isResending ? \"Sending...\" : \"Resend code\"}\n </button>\n </form>\n\n <p className=\"text-center text-sm text-muted-foreground\">\n Already verified?{\" \"}\n <a\n href=\"/login\"\n className=\"font-medium text-foreground underline underline-offset-4 hover:text-foreground/80\"\n >\n Sign in\n </a>\n </p>\n </div>\n )\n}\n","import { useState, type FormEvent } from \"react\"\nimport type { ForgotPasswordFormProps } from \"../types\"\n\nexport function ForgotPasswordForm({\n onSuccess,\n loginUrl = \"/login\",\n authClient,\n}: ForgotPasswordFormProps) {\n const [email, setEmail] = useState(\"\")\n const [error, setError] = useState<string | undefined>()\n const [isPending, setIsPending] = useState(false)\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault()\n if (!email.trim()) {\n setError(\"Please enter your email address\")\n return\n }\n setError(undefined)\n setIsPending(true)\n try {\n const res = await authClient.emailOtp.sendVerificationOtp({\n email,\n type: \"forget-password\",\n })\n if (res?.error) {\n setError(res.error.message ?? \"Failed to send reset code\")\n return\n }\n onSuccess?.(email)\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Failed to send reset code\")\n } finally {\n setIsPending(false)\n }\n }\n\n return (\n <div className=\"space-y-8\">\n <div>\n <h1 className=\"text-2xl font-bold tracking-tight\">\n Forgot your password?\n </h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n Enter your email address and we'll send you a code to reset your\n password.\n </p>\n </div>\n\n {error && (\n <div className=\"rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive\">\n {error}\n </div>\n )}\n\n <form onSubmit={handleSubmit} className=\"space-y-4\" noValidate>\n <input\n type=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder=\"Email address\"\n required\n disabled={isPending}\n autoComplete=\"email\"\n className=\"flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm 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\"\n />\n\n <button\n type=\"submit\"\n disabled={isPending || !email.trim()}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50\"\n >\n {isPending ? \"Sending...\" : \"Send reset code\"}\n </button>\n </form>\n\n <p className=\"text-center text-sm text-muted-foreground\">\n Remember your password?{\" \"}\n <a\n href={loginUrl}\n className=\"font-medium text-foreground underline underline-offset-4 hover:text-foreground/80\"\n >\n Sign in\n </a>\n </p>\n </div>\n )\n}\n","import { useState, type FormEvent } from \"react\"\nimport type { ResetPasswordFormProps } from \"../types\"\n\nexport function ResetPasswordForm({\n email,\n onSuccess,\n loginUrl = \"/login\",\n authClient,\n}: ResetPasswordFormProps) {\n const [otp, setOtp] = useState(\"\")\n const [password, setPassword] = useState(\"\")\n const [confirmPassword, setConfirmPassword] = useState(\"\")\n const [error, setError] = useState<string | undefined>()\n const [isResetting, setIsResetting] = useState(false)\n const [isResending, setIsResending] = useState(false)\n const [resendMessage, setResendMessage] = useState<string | undefined>()\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault()\n if (!otp.trim() || otp.length < 6) {\n setError(\"Please enter the 6-digit code\")\n return\n }\n if (password.length < 8) {\n setError(\"Password must be at least 8 characters\")\n return\n }\n if (password !== confirmPassword) {\n setError(\"Passwords do not match\")\n return\n }\n setError(undefined)\n setIsResetting(true)\n try {\n const res = await fetch(\"/api/auth/email-otp/reset-password\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ email, otp, password }),\n })\n if (!res.ok) {\n const body = await res.json().catch(() => null)\n setError(body?.message ?? \"Failed to reset password\")\n return\n }\n onSuccess?.()\n } catch (err) {\n setError(\n err instanceof Error ? err.message : \"Failed to reset password\",\n )\n } finally {\n setIsResetting(false)\n }\n }\n\n const handleResend = async () => {\n setError(undefined)\n setResendMessage(undefined)\n setIsResending(true)\n try {\n await authClient.emailOtp.sendVerificationOtp({\n email,\n type: \"forget-password\",\n })\n setResendMessage(\"A new code has been sent to your inbox.\")\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Failed to resend code.\")\n } finally {\n setIsResending(false)\n }\n }\n\n return (\n <div className=\"space-y-8\">\n <div>\n <h1 className=\"text-2xl font-bold tracking-tight\">\n Reset your password\n </h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n Enter the 6-digit code sent to{\" \"}\n <span className=\"font-medium text-foreground\">{email}</span> and your\n new password.\n </p>\n </div>\n\n {error && (\n <div className=\"rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive\">\n {error}\n </div>\n )}\n\n {resendMessage && (\n <div className=\"rounded-lg border border-green-200 bg-green-50 px-3 py-2 text-xs text-green-700\">\n {resendMessage}\n </div>\n )}\n\n <form onSubmit={handleSubmit} className=\"space-y-4\" noValidate>\n <input\n type=\"text\"\n inputMode=\"numeric\"\n pattern=\"[0-9]*\"\n maxLength={6}\n value={otp}\n onChange={(e) => setOtp(e.target.value.replace(/\\D/g, \"\"))}\n placeholder=\"000000\"\n required\n disabled={isResetting}\n autoComplete=\"one-time-code\"\n 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\"\n />\n\n <input\n type=\"password\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n placeholder=\"New password\"\n required\n disabled={isResetting}\n autoComplete=\"new-password\"\n className=\"flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm 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\"\n />\n\n <input\n type=\"password\"\n value={confirmPassword}\n onChange={(e) => setConfirmPassword(e.target.value)}\n placeholder=\"Confirm new password\"\n required\n disabled={isResetting}\n autoComplete=\"new-password\"\n className=\"flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm 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\"\n />\n\n <button\n type=\"submit\"\n disabled={isResetting || otp.length < 6 || !password}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50\"\n >\n {isResetting ? \"Resetting...\" : \"Reset password\"}\n </button>\n\n <button\n type=\"button\"\n onClick={handleResend}\n disabled={isResending}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md border border-input bg-background px-4 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50\"\n >\n {isResending ? \"Sending...\" : \"Resend code\"}\n </button>\n </form>\n\n <p className=\"text-center text-sm text-muted-foreground\">\n Remember your password?{\" \"}\n <a\n href={loginUrl}\n className=\"font-medium text-foreground underline underline-offset-4 hover:text-foreground/80\"\n >\n Sign in\n </a>\n </p>\n </div>\n )\n}\n","import type { AuthLayoutProps } from \"../types\"\n\n/**\n * The frame every auth screen sits in.\n *\n * Mobile and desktop are two layouts, not one scaled down. On a phone the form\n * IS the page: no card, no border, edge-to-edge padding, top-aligned so the\n * fields stay above the keyboard instead of being pushed under it by vertical\n * centering. From sm up it becomes a bounded card, centered, on a tinted\n * ground — a full-width form on a 1440px display is unreadable.\n *\n * min-h-dvh rather than min-h-screen: on mobile browsers 100vh includes the\n * retracting URL bar, so a screen-height container overflows by its height.\n */\nexport function AuthLayout({\n logo,\n title,\n subtitle,\n children,\n footer,\n}: AuthLayoutProps) {\n return (\n <div className=\"flex min-h-dvh flex-col bg-background px-5 pb-10 pt-12 sm:items-center sm:justify-center sm:bg-muted/40 sm:px-6 sm:py-12\">\n <div className=\"mx-auto w-full max-w-[420px]\">\n <div className=\"mb-8 text-center sm:mb-7\">\n {logo && <div className=\"mb-5 flex justify-center\">{logo}</div>}\n <p className=\"text-sm font-medium tracking-[0.02em] text-foreground\">\n {title}\n </p>\n {subtitle && (\n <p className=\"mt-1 text-sm text-muted-foreground\">{subtitle}</p>\n )}\n </div>\n\n <div className=\"sm:rounded-2xl sm:border sm:border-border/70 sm:bg-card sm:p-8 sm:shadow-lg sm:shadow-black/5\">\n {children}\n </div>\n\n {footer && (\n <div className=\"mt-6 text-center text-xs leading-relaxed text-muted-foreground\">\n {footer}\n </div>\n )}\n </div>\n </div>\n )\n}\n","import type { InvitationNoticeProps } from \"../types\"\n\n/**\n * Every app is reachable at contact@ its own apex domain, so the address is\n * derived rather than configured. Sub-domains are stripped because the app is\n * routinely served from app./admin. while the mailbox lives on the apex;\n * multi-part public suffixes (.co.uk) would need a real suffix list and no app\n * using this is on one.\n */\nfunction defaultSupportEmail(): string | undefined {\n if (typeof window === \"undefined\") return undefined\n const host = window.location.hostname\n if (!host || host === \"localhost\" || /^[\\d.]+$/.test(host)) return undefined\n const apex = host.split(\".\").slice(-2).join(\".\")\n return `contact@${apex}`\n}\n\nconst REASON_MESSAGE: Record<string, string> = {\n expired: \"Cette invitation a expiré.\",\n claimed: \"Cette invitation a déjà été utilisée.\",\n unknown: \"Ce lien d'invitation n'est pas valide.\",\n}\n\n/**\n * What an invitee sees when their link does not work.\n *\n * It names the reason instead of merging the cases into one message: \"expired\"\n * tells someone their link was real and that asking for another one is worth\n * it, which \"invalid\" does not. Short TTLs make that distinction routine.\n *\n * The only way forward offered is a mailto, deliberately. A self-service\n * \"request a new invitation\" form would mean a public endpoint accepting dead\n * tokens, a queue to moderate, and a way to probe which tokens once existed —\n * for a flow where the operator already knows the person by name.\n */\nexport function InvitationNotice({\n reason = \"unknown\",\n supportEmail,\n title = \"Invitation indisponible\",\n action,\n}: InvitationNoticeProps) {\n const contact = supportEmail ?? defaultSupportEmail()\n\n return (\n <div className=\"space-y-8\">\n <div>\n <h1 className=\"text-2xl font-bold tracking-tight\">{title}</h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n {REASON_MESSAGE[reason] ?? REASON_MESSAGE.unknown}\n </p>\n </div>\n\n {contact ? (\n <p className=\"text-sm text-muted-foreground\">\n Écrivez-nous à{\" \"}\n <a\n href={`mailto:${contact}`}\n className=\"font-medium text-foreground underline underline-offset-4 hover:text-foreground/80\"\n >\n {contact}\n </a>{\" \"}\n pour en recevoir une nouvelle.\n </p>\n ) : null}\n\n {action}\n </div>\n )\n}\n"],"mappings":"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","names":["jsx","jsxs","useState","jsx","jsxs","jsx","jsxs","useState","useState","jsx","jsxs","DEFAULTS","useState","useState","jsx","jsxs","useState","jsx","jsxs","useState","jsx","jsxs","jsx","jsxs","jsx","jsxs"]}
|