@fayz-ai/auth 0.44.0 → 0.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/chunk-2MO4QTQA.js +78 -0
- package/dist/chunk-2MO4QTQA.js.map +1 -0
- package/dist/chunk-2S7KVJQO.js +18 -0
- package/dist/chunk-2S7KVJQO.js.map +1 -0
- package/dist/chunk-4HVM2UJS.js +30 -0
- package/dist/chunk-4HVM2UJS.js.map +1 -0
- package/dist/chunk-55RFOMW5.js +15 -0
- package/dist/chunk-55RFOMW5.js.map +1 -0
- package/dist/chunk-7JYNJQJJ.js +138 -0
- package/dist/chunk-7JYNJQJJ.js.map +1 -0
- package/dist/chunk-BGCCXJJA.js +174 -0
- package/dist/chunk-BGCCXJJA.js.map +1 -0
- package/dist/chunk-CV4LQYNX.js +109 -0
- package/dist/chunk-CV4LQYNX.js.map +1 -0
- package/dist/chunk-ERIPMYL2.js +137 -0
- package/dist/chunk-ERIPMYL2.js.map +1 -0
- package/dist/chunk-HKILBDG2.js +158 -0
- package/dist/chunk-HKILBDG2.js.map +1 -0
- package/dist/chunk-KLQDHFVS.js +11 -0
- package/dist/chunk-KLQDHFVS.js.map +1 -0
- package/dist/chunk-OI74ER2Z.js +31 -0
- package/dist/chunk-OI74ER2Z.js.map +1 -0
- package/dist/chunk-Q6DFI35B.js +187 -0
- package/dist/chunk-Q6DFI35B.js.map +1 -0
- package/dist/chunk-QJRTW7Q3.js +90 -0
- package/dist/chunk-QJRTW7Q3.js.map +1 -0
- package/dist/chunk-REU4D5UF.js +44 -0
- package/dist/chunk-REU4D5UF.js.map +1 -0
- package/dist/chunk-SMFXGZN7.js +18 -0
- package/dist/chunk-SMFXGZN7.js.map +1 -0
- package/dist/chunk-W35GQEGU.js +80 -0
- package/dist/chunk-W35GQEGU.js.map +1 -0
- package/dist/chunk-W7565FXD.js +64 -0
- package/dist/chunk-W7565FXD.js.map +1 -0
- package/dist/chunk-WZVZMNLB.js +48 -0
- package/dist/chunk-WZVZMNLB.js.map +1 -0
- package/dist/components/AmbassadorBubbles.d.ts +9 -0
- package/dist/components/AmbassadorBubbles.d.ts.map +1 -0
- package/dist/components/AmbassadorBubbles.js +3 -0
- package/dist/components/AmbassadorBubbles.js.map +1 -0
- package/dist/components/TrialPromise.d.ts +12 -0
- package/dist/components/TrialPromise.d.ts.map +1 -0
- package/dist/components/TrialPromise.js +3 -0
- package/dist/components/TrialPromise.js.map +1 -0
- package/dist/components/form-classes.d.ts +3 -0
- package/dist/components/form-classes.d.ts.map +1 -0
- package/dist/components/form-classes.js +3 -0
- package/dist/components/form-classes.js.map +1 -0
- package/dist/context.js +5 -0
- package/dist/context.js.map +1 -0
- package/dist/data/mock.d.ts.map +1 -0
- package/dist/data/mock.js +3 -0
- package/dist/data/mock.js.map +1 -0
- package/dist/data/supabase.d.ts.map +1 -0
- package/dist/data/supabase.js +4 -0
- package/dist/data/supabase.js.map +1 -0
- package/dist/domain/auth-config.d.ts +71 -0
- package/dist/domain/auth-config.d.ts.map +1 -0
- package/dist/domain/auth-config.js +3 -0
- package/dist/domain/auth-config.js.map +1 -0
- package/dist/domain/auth-link.d.ts +26 -0
- package/dist/domain/auth-link.d.ts.map +1 -0
- package/dist/domain/auth-link.js +3 -0
- package/dist/domain/auth-link.js.map +1 -0
- package/dist/domain/password.d.ts +5 -0
- package/dist/domain/password.d.ts.map +1 -0
- package/dist/domain/password.js +3 -0
- package/dist/domain/password.js.map +1 -0
- package/dist/index.d.ts +8 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -573
- package/dist/index.js.map +1 -1
- package/dist/lib/runtime.d.ts +6 -0
- package/dist/lib/runtime.d.ts.map +1 -0
- package/dist/lib/runtime.js +51 -0
- package/dist/lib/runtime.js.map +1 -0
- package/dist/lib/url-intent.d.ts +1 -25
- package/dist/lib/url-intent.d.ts.map +1 -1
- package/dist/lib/url-intent.js +3 -0
- package/dist/lib/url-intent.js.map +1 -0
- package/dist/store.js +3 -0
- package/dist/store.js.map +1 -0
- package/dist/views/AuthCallbackPage.d.ts +7 -0
- package/dist/views/AuthCallbackPage.d.ts.map +1 -0
- package/dist/views/AuthCallbackPage.js +33 -0
- package/dist/views/AuthCallbackPage.js.map +1 -0
- package/dist/views/AuthGate.d.ts +9 -0
- package/dist/views/AuthGate.d.ts.map +1 -0
- package/dist/views/AuthGate.js +28 -0
- package/dist/views/AuthGate.js.map +1 -0
- package/dist/views/ForgotPasswordForm.d.ts +18 -0
- package/dist/views/ForgotPasswordForm.d.ts.map +1 -0
- package/dist/views/ForgotPasswordForm.js +7 -0
- package/dist/views/ForgotPasswordForm.js.map +1 -0
- package/dist/views/LoginForm.d.ts +16 -0
- package/dist/views/LoginForm.d.ts.map +1 -0
- package/dist/views/LoginForm.js +8 -0
- package/dist/views/LoginForm.js.map +1 -0
- package/dist/views/LoginPage.d.ts +34 -0
- package/dist/views/LoginPage.d.ts.map +1 -0
- package/dist/views/LoginPage.js +16 -0
- package/dist/views/LoginPage.js.map +1 -0
- package/dist/views/OAuthButtons.d.ts +18 -0
- package/dist/views/OAuthButtons.d.ts.map +1 -0
- package/dist/views/OAuthButtons.js +7 -0
- package/dist/views/OAuthButtons.js.map +1 -0
- package/dist/views/ResetPasswordForm.d.ts +6 -0
- package/dist/views/ResetPasswordForm.d.ts.map +1 -0
- package/dist/views/ResetPasswordForm.js +53 -0
- package/dist/views/ResetPasswordForm.js.map +1 -0
- package/dist/views/ResetPasswordPage.d.ts +7 -0
- package/dist/views/ResetPasswordPage.d.ts.map +1 -0
- package/dist/views/ResetPasswordPage.js +16 -0
- package/dist/views/ResetPasswordPage.js.map +1 -0
- package/dist/views/SetPasswordPage.d.ts +15 -0
- package/dist/views/SetPasswordPage.d.ts.map +1 -0
- package/dist/views/SetPasswordPage.js +9 -0
- package/dist/views/SetPasswordPage.js.map +1 -0
- package/dist/views/SignupForm.d.ts +24 -0
- package/dist/views/SignupForm.d.ts.map +1 -0
- package/dist/views/SignupForm.js +9 -0
- package/dist/views/SignupForm.js.map +1 -0
- package/dist/views/VerifyEmailNotice.d.ts +15 -0
- package/dist/views/VerifyEmailNotice.d.ts.map +1 -0
- package/dist/views/VerifyEmailNotice.js +6 -0
- package/dist/views/VerifyEmailNotice.js.map +1 -0
- package/dist/views/usePasswordSetupGate.d.ts +20 -0
- package/dist/views/usePasswordSetupGate.d.ts.map +1 -0
- package/dist/views/usePasswordSetupGate.js +27 -0
- package/dist/views/usePasswordSetupGate.js.map +1 -0
- package/package.json +14 -3
- package/dist/adapters/mock.d.ts.map +0 -1
- package/dist/adapters/supabase.d.ts.map +0 -1
- /package/dist/{adapters → data}/mock.d.ts +0 -0
- /package/dist/{adapters → data}/supabase.d.ts +0 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// src/data/mock.ts
|
|
2
|
+
var DEFAULT_MOCK_USER = {
|
|
3
|
+
id: "mock-user-id",
|
|
4
|
+
email: "demo@fayz.dev",
|
|
5
|
+
fullName: "Demo User",
|
|
6
|
+
role: "admin"
|
|
7
|
+
};
|
|
8
|
+
var STORAGE_KEY = "fayz:mock-auth";
|
|
9
|
+
function toAuthUser(mockUser) {
|
|
10
|
+
return {
|
|
11
|
+
id: mockUser.id,
|
|
12
|
+
email: mockUser.email,
|
|
13
|
+
fullName: mockUser.fullName
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function createMockSession(user) {
|
|
17
|
+
return {
|
|
18
|
+
accessToken: `mock-token-${user.id}`,
|
|
19
|
+
refreshToken: `mock-refresh-${user.id}`,
|
|
20
|
+
expiresAt: Math.floor(Date.now() / 1e3) + 3600,
|
|
21
|
+
user
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function getStored() {
|
|
25
|
+
try {
|
|
26
|
+
if (typeof localStorage === "undefined") return null;
|
|
27
|
+
const raw = localStorage.getItem(STORAGE_KEY);
|
|
28
|
+
if (!raw) return null;
|
|
29
|
+
return JSON.parse(raw);
|
|
30
|
+
} catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function setStored(data) {
|
|
35
|
+
try {
|
|
36
|
+
if (typeof localStorage === "undefined") return;
|
|
37
|
+
if (data) {
|
|
38
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
|
|
39
|
+
} else {
|
|
40
|
+
localStorage.removeItem(STORAGE_KEY);
|
|
41
|
+
}
|
|
42
|
+
} catch {
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function createMockAuthAdapter(mockUser = DEFAULT_MOCK_USER) {
|
|
46
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
47
|
+
function notifyListeners(user) {
|
|
48
|
+
for (const cb of listeners) cb(user);
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
async getSession() {
|
|
52
|
+
return getStored();
|
|
53
|
+
},
|
|
54
|
+
onAuthStateChange(cb) {
|
|
55
|
+
listeners.add(cb);
|
|
56
|
+
return () => {
|
|
57
|
+
listeners.delete(cb);
|
|
58
|
+
};
|
|
59
|
+
},
|
|
60
|
+
async signIn(email, _password) {
|
|
61
|
+
const stored = getStored();
|
|
62
|
+
const user = stored && stored.user.email === email ? stored.user : {
|
|
63
|
+
id: email === mockUser.email ? mockUser.id : `mock-${email}`,
|
|
64
|
+
email,
|
|
65
|
+
fullName: email === mockUser.email ? mockUser.fullName : email.split("@")[0] ?? "Cliente"
|
|
66
|
+
};
|
|
67
|
+
const session = createMockSession(user);
|
|
68
|
+
setStored({ user, session });
|
|
69
|
+
notifyListeners(user);
|
|
70
|
+
return session;
|
|
71
|
+
},
|
|
72
|
+
async signUp(email, _password, fullName) {
|
|
73
|
+
const user = {
|
|
74
|
+
id: `mock-${email}`,
|
|
75
|
+
email,
|
|
76
|
+
fullName: fullName || (email.split("@")[0] ?? "Cliente")
|
|
77
|
+
};
|
|
78
|
+
const session = createMockSession(user);
|
|
79
|
+
setStored({ user, session });
|
|
80
|
+
notifyListeners(user);
|
|
81
|
+
return session;
|
|
82
|
+
},
|
|
83
|
+
async signOut() {
|
|
84
|
+
setStored(null);
|
|
85
|
+
notifyListeners(null);
|
|
86
|
+
},
|
|
87
|
+
async signInWithOAuth(_provider) {
|
|
88
|
+
const user = toAuthUser(mockUser);
|
|
89
|
+
const session = createMockSession(user);
|
|
90
|
+
setStored({ user, session });
|
|
91
|
+
notifyListeners(user);
|
|
92
|
+
},
|
|
93
|
+
async resetPassword(_email) {
|
|
94
|
+
},
|
|
95
|
+
async updatePassword(_password) {
|
|
96
|
+
const stored = getStored();
|
|
97
|
+
return stored?.session;
|
|
98
|
+
},
|
|
99
|
+
async handleCallback() {
|
|
100
|
+
return getStored()?.session ?? null;
|
|
101
|
+
},
|
|
102
|
+
async inviteUser(_email, _options) {
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export { createMockAuthAdapter };
|
|
108
|
+
//# sourceMappingURL=chunk-CV4LQYNX.js.map
|
|
109
|
+
//# sourceMappingURL=chunk-CV4LQYNX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/data/mock.ts"],"names":[],"mappings":"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","file":"chunk-CV4LQYNX.js","sourcesContent":["import type { AuthAdapter, AuthUser, AuthSession } from '@fayz-ai/core'\n\nexport interface MockUser {\n id: string\n email: string\n fullName: string\n role?: string\n}\n\nconst DEFAULT_MOCK_USER: MockUser = {\n id: 'mock-user-id',\n email: 'demo@fayz.dev',\n fullName: 'Demo User',\n role: 'admin',\n}\n\nconst STORAGE_KEY = 'fayz:mock-auth'\n\nfunction toAuthUser(mockUser: MockUser): AuthUser {\n return {\n id: mockUser.id,\n email: mockUser.email,\n fullName: mockUser.fullName,\n }\n}\n\nfunction createMockSession(user: AuthUser): AuthSession {\n return {\n accessToken: `mock-token-${user.id}`,\n refreshToken: `mock-refresh-${user.id}`,\n expiresAt: Math.floor(Date.now() / 1000) + 3600,\n user,\n }\n}\n\nfunction getStored(): { user: AuthUser; session: AuthSession } | null {\n try {\n if (typeof localStorage === 'undefined') return null\n const raw = localStorage.getItem(STORAGE_KEY)\n if (!raw) return null\n return JSON.parse(raw) as { user: AuthUser; session: AuthSession }\n } catch {\n return null\n }\n}\n\nfunction setStored(data: { user: AuthUser; session: AuthSession } | null): void {\n try {\n if (typeof localStorage === 'undefined') return\n if (data) {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(data))\n } else {\n localStorage.removeItem(STORAGE_KEY)\n }\n } catch {\n // SSR or storage unavailable — silently skip\n }\n}\n\nexport function createMockAuthAdapter(mockUser: MockUser = DEFAULT_MOCK_USER): AuthAdapter {\n const listeners = new Set<(user: AuthUser | null) => void>()\n\n function notifyListeners(user: AuthUser | null): void {\n for (const cb of listeners) cb(user)\n }\n\n return {\n async getSession() {\n return getStored()\n },\n\n onAuthStateChange(cb) {\n listeners.add(cb)\n return () => {\n listeners.delete(cb)\n }\n },\n\n async signIn(email, _password) {\n // Mock accepts any credentials, but the identity FOLLOWS the email —\n // storefront customers and saas users keep their own purchase/session\n // history instead of all becoming the configured demo user.\n const stored = getStored()\n const user: AuthUser =\n stored && stored.user.email === email\n ? stored.user\n : {\n id: email === mockUser.email ? mockUser.id : `mock-${email}`,\n email,\n fullName: email === mockUser.email ? mockUser.fullName : (email.split('@')[0] ?? 'Cliente'),\n }\n const session = createMockSession(user)\n setStored({ user, session })\n notifyListeners(user)\n return session\n },\n\n async signUp(email, _password, fullName) {\n // Mock signup creates a user from the provided details\n const user: AuthUser = {\n id: `mock-${email}`,\n email,\n fullName: fullName || (email.split('@')[0] ?? 'Cliente'),\n }\n const session = createMockSession(user)\n setStored({ user, session })\n notifyListeners(user)\n return session\n },\n\n async signOut() {\n setStored(null)\n notifyListeners(null)\n },\n\n async signInWithOAuth(_provider) {\n // Mock OAuth signs in as the configured user\n const user = toAuthUser(mockUser)\n const session = createMockSession(user)\n setStored({ user, session })\n notifyListeners(user)\n },\n\n async resetPassword(_email) {\n // No-op in mock\n },\n\n async updatePassword(_password) {\n const stored = getStored()\n return stored?.session\n },\n\n async handleCallback() {\n return getStored()?.session ?? null\n },\n\n async inviteUser(_email, _options) {\n // No admin path in mock — the org mock adapter still records the pending\n // invite so the Team UI shows it. Delivery is a no-op locally.\n },\n }\n}\n"]}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { newPasswordProblem, MIN_PASSWORD_LENGTH } from './chunk-KLQDHFVS.js';
|
|
2
|
+
import { ForgotPasswordForm } from './chunk-W7565FXD.js';
|
|
3
|
+
import { useAuth } from './chunk-Q6DFI35B.js';
|
|
4
|
+
import { fieldClass, buttonClass } from './chunk-55RFOMW5.js';
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
import { useTranslation } from '@fayz-ai/core';
|
|
7
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
8
|
+
|
|
9
|
+
function useTr() {
|
|
10
|
+
const t = useTranslation();
|
|
11
|
+
return React.useCallback(
|
|
12
|
+
(key, fallback, params) => {
|
|
13
|
+
const value = t(key, params);
|
|
14
|
+
return !value || value === key ? fallback : value;
|
|
15
|
+
},
|
|
16
|
+
[t]
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
function SetPasswordPage({
|
|
20
|
+
reason,
|
|
21
|
+
appName = "App",
|
|
22
|
+
logo,
|
|
23
|
+
expired,
|
|
24
|
+
checking,
|
|
25
|
+
onSuccess
|
|
26
|
+
}) {
|
|
27
|
+
const tr = useTr();
|
|
28
|
+
const { user, updatePassword, signOut, error, isLoading } = useAuth();
|
|
29
|
+
const [password, setPassword] = React.useState("");
|
|
30
|
+
const [confirmPassword, setConfirmPassword] = React.useState("");
|
|
31
|
+
const [localError, setLocalError] = React.useState(null);
|
|
32
|
+
const [busy, setBusy] = React.useState(false);
|
|
33
|
+
const disabled = busy || isLoading;
|
|
34
|
+
const invite = reason === "invite";
|
|
35
|
+
const title = invite ? tr("auth.setPassword.welcomeTitle", `Welcome to ${appName}`, { appName }) : tr("auth.setPassword.recoveryTitle", "Choose a new password");
|
|
36
|
+
const subtitle = invite ? tr("auth.setPassword.welcomeSubtitle", "Choose a password to finish setting up your access.") : tr("auth.setPassword.recoverySubtitle", "Set a new password to get back into your account.");
|
|
37
|
+
async function submit(event) {
|
|
38
|
+
event.preventDefault();
|
|
39
|
+
setLocalError(null);
|
|
40
|
+
const problem = newPasswordProblem(password, confirmPassword);
|
|
41
|
+
if (problem === "too-short") {
|
|
42
|
+
setLocalError(tr("auth.setPassword.tooShort", `Password must be at least ${MIN_PASSWORD_LENGTH} characters.`));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (problem === "mismatch") {
|
|
46
|
+
setLocalError(tr("auth.setPassword.mismatch", "Passwords do not match."));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
setBusy(true);
|
|
50
|
+
try {
|
|
51
|
+
await updatePassword(password);
|
|
52
|
+
onSuccess?.();
|
|
53
|
+
} catch {
|
|
54
|
+
} finally {
|
|
55
|
+
setBusy(false);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return /* @__PURE__ */ jsx("div", { className: "flex min-h-screen items-center justify-center bg-sidebar p-4", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-md rounded-2xl border border-border/50 bg-card p-8 shadow-2xl sm:p-10", children: [
|
|
59
|
+
logo && /* @__PURE__ */ jsx("div", { className: "mb-6 flex justify-center", children: logo }),
|
|
60
|
+
checking ? /* @__PURE__ */ jsx("p", { className: "py-6 text-center text-sm text-muted-foreground", children: tr("auth.setPassword.checking", "Checking your link...") }) : expired ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
61
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-6", children: [
|
|
62
|
+
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold text-foreground", children: tr("auth.setPassword.expiredTitle", "This link has expired") }),
|
|
63
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: tr(
|
|
64
|
+
"auth.setPassword.expiredSubtitle",
|
|
65
|
+
"Reset links can only be used once. Enter your e-mail and we will send a new one."
|
|
66
|
+
) })
|
|
67
|
+
] }),
|
|
68
|
+
/* @__PURE__ */ jsx(
|
|
69
|
+
ForgotPasswordForm,
|
|
70
|
+
{
|
|
71
|
+
initialEmail: user?.email,
|
|
72
|
+
submitLabel: tr("auth.setPassword.sendNewLink", "Send new link"),
|
|
73
|
+
sendingLabel: tr("auth.setPassword.sending", "Sending..."),
|
|
74
|
+
sentLabel: tr("auth.setPassword.sent", "Check your inbox \u2014 a new link is on the way."),
|
|
75
|
+
emailLabel: tr("auth.setPassword.email", "E-mail"),
|
|
76
|
+
backLabel: tr("auth.setPassword.backToLogin", "Back to sign in"),
|
|
77
|
+
onBackToLogin: onSuccess
|
|
78
|
+
}
|
|
79
|
+
)
|
|
80
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
81
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-6", children: [
|
|
82
|
+
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold text-foreground", children: title }),
|
|
83
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: subtitle })
|
|
84
|
+
] }),
|
|
85
|
+
/* @__PURE__ */ jsxs("form", { onSubmit: submit, className: "space-y-4", children: [
|
|
86
|
+
/* @__PURE__ */ jsxs("label", { className: "block space-y-1.5 text-sm font-medium", children: [
|
|
87
|
+
/* @__PURE__ */ jsx("span", { children: tr("auth.setPassword.newPassword", "New password") }),
|
|
88
|
+
/* @__PURE__ */ jsx(
|
|
89
|
+
"input",
|
|
90
|
+
{
|
|
91
|
+
className: fieldClass(),
|
|
92
|
+
type: "password",
|
|
93
|
+
autoComplete: "new-password",
|
|
94
|
+
autoFocus: true,
|
|
95
|
+
required: true,
|
|
96
|
+
value: password,
|
|
97
|
+
onChange: (e) => setPassword(e.target.value),
|
|
98
|
+
disabled
|
|
99
|
+
}
|
|
100
|
+
)
|
|
101
|
+
] }),
|
|
102
|
+
/* @__PURE__ */ jsxs("label", { className: "block space-y-1.5 text-sm font-medium", children: [
|
|
103
|
+
/* @__PURE__ */ jsx("span", { children: tr("auth.setPassword.confirmPassword", "Confirm password") }),
|
|
104
|
+
/* @__PURE__ */ jsx(
|
|
105
|
+
"input",
|
|
106
|
+
{
|
|
107
|
+
className: fieldClass(),
|
|
108
|
+
type: "password",
|
|
109
|
+
autoComplete: "new-password",
|
|
110
|
+
required: true,
|
|
111
|
+
value: confirmPassword,
|
|
112
|
+
onChange: (e) => setConfirmPassword(e.target.value),
|
|
113
|
+
disabled
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
] }),
|
|
117
|
+
(localError || error) && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: localError ?? error?.message }),
|
|
118
|
+
/* @__PURE__ */ jsx("button", { className: buttonClass(), type: "submit", disabled, children: disabled ? tr("auth.setPassword.saving", "Saving...") : tr("auth.setPassword.submit", "Save password") })
|
|
119
|
+
] }),
|
|
120
|
+
/* @__PURE__ */ jsx(
|
|
121
|
+
"button",
|
|
122
|
+
{
|
|
123
|
+
type: "button",
|
|
124
|
+
className: "mt-4 w-full text-center text-sm text-muted-foreground hover:text-foreground",
|
|
125
|
+
onClick: () => {
|
|
126
|
+
void signOut().finally(() => onSuccess?.());
|
|
127
|
+
},
|
|
128
|
+
children: tr("auth.setPassword.backToLogin", "Back to sign in")
|
|
129
|
+
}
|
|
130
|
+
)
|
|
131
|
+
] })
|
|
132
|
+
] }) });
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export { SetPasswordPage };
|
|
136
|
+
//# sourceMappingURL=chunk-ERIPMYL2.js.map
|
|
137
|
+
//# sourceMappingURL=chunk-ERIPMYL2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/views/SetPasswordPage.tsx"],"names":[],"mappings":"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","file":"chunk-ERIPMYL2.js","sourcesContent":["import * as React from 'react'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useAuth } from '../context'\nimport type { PasswordSetupReason } from '../domain/auth-link'\nimport { newPasswordProblem, MIN_PASSWORD_LENGTH } from '../domain/password'\nimport { buttonClass, fieldClass } from '../components/form-classes'\nimport { ForgotPasswordForm } from './ForgotPasswordForm'\n\nexport type SetPasswordReason = PasswordSetupReason\n\nfunction useTr() {\n const t = useTranslation()\n return React.useCallback(\n (key: string, fallback: string, params?: Record<string, string | number>) => {\n const value = t(key, params)\n return !value || value === key ? fallback : value\n },\n [t],\n )\n}\n\nexport interface SetPasswordPageProps {\n reason: SetPasswordReason\n appName?: string\n logo?: React.ReactNode\n /** Show the \"ask for a new link\" form instead of the password fields. */\n expired?: boolean\n /** Waiting on the link's session — renders a quiet placeholder. */\n checking?: boolean\n onSuccess?: () => void\n}\n\nexport function SetPasswordPage({\n reason,\n appName = 'App',\n logo,\n expired,\n checking,\n onSuccess,\n}: SetPasswordPageProps) {\n const tr = useTr()\n const { user, updatePassword, signOut, error, isLoading } = useAuth()\n const [password, setPassword] = React.useState('')\n const [confirmPassword, setConfirmPassword] = React.useState('')\n const [localError, setLocalError] = React.useState<string | null>(null)\n const [busy, setBusy] = React.useState(false)\n const disabled = busy || isLoading\n\n const invite = reason === 'invite'\n const title = invite\n ? tr('auth.setPassword.welcomeTitle', `Welcome to ${appName}`, { appName })\n : tr('auth.setPassword.recoveryTitle', 'Choose a new password')\n const subtitle = invite\n ? tr('auth.setPassword.welcomeSubtitle', 'Choose a password to finish setting up your access.')\n : tr('auth.setPassword.recoverySubtitle', 'Set a new password to get back into your account.')\n\n async function submit(event: React.FormEvent) {\n event.preventDefault()\n setLocalError(null)\n const problem = newPasswordProblem(password, confirmPassword)\n if (problem === 'too-short') {\n setLocalError(tr('auth.setPassword.tooShort', `Password must be at least ${MIN_PASSWORD_LENGTH} characters.`))\n return\n }\n if (problem === 'mismatch') {\n setLocalError(tr('auth.setPassword.mismatch', 'Passwords do not match.'))\n return\n }\n setBusy(true)\n try {\n await updatePassword(password)\n onSuccess?.()\n } catch {\n // useAuth already surfaced it; keep the user on the form.\n } finally {\n setBusy(false)\n }\n }\n\n return (\n <div className=\"flex min-h-screen items-center justify-center bg-sidebar p-4\">\n <div className=\"w-full max-w-md rounded-2xl border border-border/50 bg-card p-8 shadow-2xl sm:p-10\">\n {logo && <div className=\"mb-6 flex justify-center\">{logo}</div>}\n {checking ? (\n <p className=\"py-6 text-center text-sm text-muted-foreground\">\n {tr('auth.setPassword.checking', 'Checking your link...')}\n </p>\n ) : expired ? (\n <>\n <div className=\"mb-6\">\n <h1 className=\"text-2xl font-bold text-foreground\">\n {tr('auth.setPassword.expiredTitle', 'This link has expired')}\n </h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n {tr(\n 'auth.setPassword.expiredSubtitle',\n 'Reset links can only be used once. Enter your e-mail and we will send a new one.',\n )}\n </p>\n </div>\n <ForgotPasswordForm\n initialEmail={user?.email}\n submitLabel={tr('auth.setPassword.sendNewLink', 'Send new link')}\n sendingLabel={tr('auth.setPassword.sending', 'Sending...')}\n sentLabel={tr('auth.setPassword.sent', 'Check your inbox — a new link is on the way.')}\n emailLabel={tr('auth.setPassword.email', 'E-mail')}\n backLabel={tr('auth.setPassword.backToLogin', 'Back to sign in')}\n onBackToLogin={onSuccess}\n />\n </>\n ) : (\n <>\n <div className=\"mb-6\">\n <h1 className=\"text-2xl font-bold text-foreground\">{title}</h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">{subtitle}</p>\n </div>\n <form onSubmit={submit} className=\"space-y-4\">\n <label className=\"block space-y-1.5 text-sm font-medium\">\n <span>{tr('auth.setPassword.newPassword', 'New password')}</span>\n <input\n className={fieldClass()}\n type=\"password\"\n autoComplete=\"new-password\"\n autoFocus\n required\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n disabled={disabled}\n />\n </label>\n <label className=\"block space-y-1.5 text-sm font-medium\">\n <span>{tr('auth.setPassword.confirmPassword', 'Confirm password')}</span>\n <input\n className={fieldClass()}\n type=\"password\"\n autoComplete=\"new-password\"\n required\n value={confirmPassword}\n onChange={(e) => setConfirmPassword(e.target.value)}\n disabled={disabled}\n />\n </label>\n {(localError || error) && (\n <p className=\"text-sm text-destructive\">{localError ?? error?.message}</p>\n )}\n <button className={buttonClass()} type=\"submit\" disabled={disabled}>\n {disabled\n ? tr('auth.setPassword.saving', 'Saving...')\n : tr('auth.setPassword.submit', 'Save password')}\n </button>\n </form>\n {/* An invitee who does not want to continue needs a way out that does\n not leave them stuck on this screen with a live session. */}\n <button\n type=\"button\"\n className=\"mt-4 w-full text-center text-sm text-muted-foreground hover:text-foreground\"\n onClick={() => {\n void signOut().finally(() => onSuccess?.())\n }}\n >\n {tr('auth.setPassword.backToLogin', 'Back to sign in')}\n </button>\n </>\n )}\n </div>\n </div>\n )\n}\n"]}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { OAuthButtons } from './chunk-WZVZMNLB.js';
|
|
2
|
+
import { newPasswordProblem, MIN_PASSWORD_LENGTH } from './chunk-KLQDHFVS.js';
|
|
3
|
+
import { useAuth } from './chunk-Q6DFI35B.js';
|
|
4
|
+
import { fieldClass, buttonClass } from './chunk-55RFOMW5.js';
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
import { tl } from '@fayz-ai/core';
|
|
7
|
+
import { EyeOff, Eye } from 'lucide-react';
|
|
8
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
9
|
+
|
|
10
|
+
function SignupForm({
|
|
11
|
+
onSuccess,
|
|
12
|
+
showOAuth,
|
|
13
|
+
oauthProviders,
|
|
14
|
+
oauthComingSoon,
|
|
15
|
+
requireConfirmation = false,
|
|
16
|
+
termsUrl,
|
|
17
|
+
privacyUrl
|
|
18
|
+
}) {
|
|
19
|
+
const { signUp, error, isLoading } = useAuth();
|
|
20
|
+
const [fullName, setFullName] = React.useState("");
|
|
21
|
+
const [email, setEmail] = React.useState("");
|
|
22
|
+
const [password, setPassword] = React.useState("");
|
|
23
|
+
const [confirmPassword, setConfirmPassword] = React.useState("");
|
|
24
|
+
const [reveal, setReveal] = React.useState(false);
|
|
25
|
+
const [localError, setLocalError] = React.useState(null);
|
|
26
|
+
const [busy, setBusy] = React.useState(false);
|
|
27
|
+
const disabled = busy || isLoading;
|
|
28
|
+
const passwordRef = React.useRef(null);
|
|
29
|
+
async function submit(event) {
|
|
30
|
+
event.preventDefault();
|
|
31
|
+
setLocalError(null);
|
|
32
|
+
const problem = newPasswordProblem(password, requireConfirmation ? confirmPassword : void 0);
|
|
33
|
+
if (problem === "too-short") {
|
|
34
|
+
setLocalError(tl(
|
|
35
|
+
`Use at least ${MIN_PASSWORD_LENGTH} characters.`,
|
|
36
|
+
`Use pelo menos ${MIN_PASSWORD_LENGTH} caracteres.`
|
|
37
|
+
));
|
|
38
|
+
passwordRef.current?.focus();
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (problem === "mismatch") {
|
|
42
|
+
setLocalError(tl("The passwords do not match.", "As senhas n\xE3o conferem."));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
setBusy(true);
|
|
46
|
+
try {
|
|
47
|
+
await signUp(email, password, fullName);
|
|
48
|
+
onSuccess?.();
|
|
49
|
+
} finally {
|
|
50
|
+
setBusy(false);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const tooShort = password.length > 0 && newPasswordProblem(password) === "too-short";
|
|
54
|
+
return /* @__PURE__ */ jsxs("form", { onSubmit: submit, className: "space-y-4", children: [
|
|
55
|
+
/* @__PURE__ */ jsxs("label", { className: "block space-y-1.5 text-sm font-medium", children: [
|
|
56
|
+
/* @__PURE__ */ jsx("span", { children: tl("Full name", "Nome completo") }),
|
|
57
|
+
/* @__PURE__ */ jsx(
|
|
58
|
+
"input",
|
|
59
|
+
{
|
|
60
|
+
className: fieldClass(),
|
|
61
|
+
autoComplete: "name",
|
|
62
|
+
required: true,
|
|
63
|
+
value: fullName,
|
|
64
|
+
onChange: (e) => setFullName(e.target.value),
|
|
65
|
+
disabled
|
|
66
|
+
}
|
|
67
|
+
)
|
|
68
|
+
] }),
|
|
69
|
+
/* @__PURE__ */ jsxs("label", { className: "block space-y-1.5 text-sm font-medium", children: [
|
|
70
|
+
/* @__PURE__ */ jsx("span", { children: tl("Email", "E-mail") }),
|
|
71
|
+
/* @__PURE__ */ jsx(
|
|
72
|
+
"input",
|
|
73
|
+
{
|
|
74
|
+
className: fieldClass(),
|
|
75
|
+
type: "email",
|
|
76
|
+
inputMode: "email",
|
|
77
|
+
autoComplete: "username",
|
|
78
|
+
required: true,
|
|
79
|
+
value: email,
|
|
80
|
+
onChange: (e) => setEmail(e.target.value),
|
|
81
|
+
disabled
|
|
82
|
+
}
|
|
83
|
+
)
|
|
84
|
+
] }),
|
|
85
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1.5 text-sm font-medium", children: [
|
|
86
|
+
/* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", htmlFor: "signup-password", children: [
|
|
87
|
+
/* @__PURE__ */ jsx("span", { children: tl("Password", "Senha") }),
|
|
88
|
+
/* @__PURE__ */ jsxs("span", { className: "relative block", children: [
|
|
89
|
+
/* @__PURE__ */ jsx(
|
|
90
|
+
"input",
|
|
91
|
+
{
|
|
92
|
+
id: "signup-password",
|
|
93
|
+
ref: passwordRef,
|
|
94
|
+
className: `${fieldClass()} pr-10`,
|
|
95
|
+
type: reveal ? "text" : "password",
|
|
96
|
+
autoComplete: "new-password",
|
|
97
|
+
minLength: MIN_PASSWORD_LENGTH,
|
|
98
|
+
required: true,
|
|
99
|
+
value: password,
|
|
100
|
+
onChange: (e) => setPassword(e.target.value),
|
|
101
|
+
disabled,
|
|
102
|
+
"aria-describedby": "signup-password-hint"
|
|
103
|
+
}
|
|
104
|
+
),
|
|
105
|
+
/* @__PURE__ */ jsx(
|
|
106
|
+
"button",
|
|
107
|
+
{
|
|
108
|
+
type: "button",
|
|
109
|
+
onClick: () => setReveal((v) => !v),
|
|
110
|
+
"aria-label": reveal ? tl("Hide password", "Ocultar senha") : tl("Show password", "Mostrar senha"),
|
|
111
|
+
"aria-pressed": reveal,
|
|
112
|
+
className: "absolute inset-y-0 right-0 flex w-10 items-center justify-center rounded-r-md text-muted-foreground transition-colors hover:text-foreground",
|
|
113
|
+
children: reveal ? /* @__PURE__ */ jsx(EyeOff, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(Eye, { className: "h-4 w-4" })
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
] })
|
|
117
|
+
] }),
|
|
118
|
+
/* @__PURE__ */ jsx(
|
|
119
|
+
"p",
|
|
120
|
+
{
|
|
121
|
+
id: "signup-password-hint",
|
|
122
|
+
className: `text-xs font-normal ${tooShort ? "text-warning" : "text-muted-foreground"}`,
|
|
123
|
+
children: tl(`At least ${MIN_PASSWORD_LENGTH} characters.`, `Pelo menos ${MIN_PASSWORD_LENGTH} caracteres.`)
|
|
124
|
+
}
|
|
125
|
+
)
|
|
126
|
+
] }),
|
|
127
|
+
requireConfirmation && /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5 text-sm font-medium", children: [
|
|
128
|
+
/* @__PURE__ */ jsx("span", { children: tl("Confirm password", "Confirme a senha") }),
|
|
129
|
+
/* @__PURE__ */ jsx(
|
|
130
|
+
"input",
|
|
131
|
+
{
|
|
132
|
+
className: fieldClass(),
|
|
133
|
+
type: reveal ? "text" : "password",
|
|
134
|
+
autoComplete: "new-password",
|
|
135
|
+
required: true,
|
|
136
|
+
value: confirmPassword,
|
|
137
|
+
onChange: (e) => setConfirmPassword(e.target.value),
|
|
138
|
+
disabled
|
|
139
|
+
}
|
|
140
|
+
)
|
|
141
|
+
] }),
|
|
142
|
+
(localError || error) && /* @__PURE__ */ jsx("p", { role: "alert", className: "text-sm text-destructive", children: localError ?? error?.message }),
|
|
143
|
+
/* @__PURE__ */ jsx("button", { className: buttonClass(), type: "submit", disabled, children: disabled ? tl("Creating account...", "Criando conta...") : tl("Create account", "Criar conta") }),
|
|
144
|
+
(termsUrl || privacyUrl) && /* @__PURE__ */ jsxs("p", { className: "text-center text-xs leading-relaxed text-muted-foreground", children: [
|
|
145
|
+
tl("By continuing you agree to our", "Ao continuar, voc\xEA concorda com os"),
|
|
146
|
+
" ",
|
|
147
|
+
termsUrl && /* @__PURE__ */ jsx("a", { href: termsUrl, target: "_blank", rel: "noopener noreferrer", className: "underline hover:text-foreground", children: tl("terms of service", "termos de uso") }),
|
|
148
|
+
termsUrl && privacyUrl && tl(" and ", " e a "),
|
|
149
|
+
privacyUrl && /* @__PURE__ */ jsx("a", { href: privacyUrl, target: "_blank", rel: "noopener noreferrer", className: "underline hover:text-foreground", children: tl("privacy policy", "pol\xEDtica de privacidade") }),
|
|
150
|
+
"."
|
|
151
|
+
] }),
|
|
152
|
+
showOAuth && /* @__PURE__ */ jsx(OAuthButtons, { providers: oauthProviders, disabled, comingSoon: oauthComingSoon })
|
|
153
|
+
] });
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export { SignupForm };
|
|
157
|
+
//# sourceMappingURL=chunk-HKILBDG2.js.map
|
|
158
|
+
//# sourceMappingURL=chunk-HKILBDG2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/views/SignupForm.tsx"],"names":[],"mappings":"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","file":"chunk-HKILBDG2.js","sourcesContent":["import * as React from 'react'\nimport { tl } from '@fayz-ai/core'\nimport { Eye, EyeOff } from 'lucide-react'\nimport { useAuth } from '../context'\nimport type { OAuthProviderKey } from '../domain/auth-config'\nimport { MIN_PASSWORD_LENGTH, newPasswordProblem } from '../domain/password'\nimport { buttonClass, fieldClass } from '../components/form-classes'\nimport { OAuthButtons } from './OAuthButtons'\n\nexport interface SignupFormProps {\n onSuccess?: () => void\n /** Same social buttons the sign-in form offers. Parity is the point: an\n * account created with Google must be creatable from this side too. */\n showOAuth?: boolean\n oauthProviders?: OAuthProviderKey[]\n oauthComingSoon?: OAuthProviderKey[]\n /**\n * Ask for the password twice.\n *\n * Off by default, and that is a deliberate reversal: the field exists to\n * catch a typo you cannot see, and a reveal toggle catches the same typo\n * while REMOVING a field from the shortest form in the product. Apps that\n * must keep it (an internal policy, an audit) turn it back on.\n */\n requireConfirmation?: boolean\n /** Terms and privacy, shown under the button when the app has them. */\n termsUrl?: string\n privacyUrl?: string\n}\n\nexport function SignupForm({\n onSuccess,\n showOAuth,\n oauthProviders,\n oauthComingSoon,\n requireConfirmation = false,\n termsUrl,\n privacyUrl,\n}: SignupFormProps) {\n const { signUp, error, isLoading } = useAuth()\n const [fullName, setFullName] = React.useState('')\n const [email, setEmail] = React.useState('')\n const [password, setPassword] = React.useState('')\n const [confirmPassword, setConfirmPassword] = React.useState('')\n const [reveal, setReveal] = React.useState(false)\n const [localError, setLocalError] = React.useState<string | null>(null)\n const [busy, setBusy] = React.useState(false)\n const disabled = busy || isLoading\n const passwordRef = React.useRef<HTMLInputElement>(null)\n\n async function submit(event: React.FormEvent) {\n event.preventDefault()\n setLocalError(null)\n const problem = newPasswordProblem(password, requireConfirmation ? confirmPassword : undefined)\n if (problem === 'too-short') {\n setLocalError(tl(\n `Use at least ${MIN_PASSWORD_LENGTH} characters.`,\n `Use pelo menos ${MIN_PASSWORD_LENGTH} caracteres.`,\n ))\n // The error is under the field it is about, and the cursor goes there too.\n passwordRef.current?.focus()\n return\n }\n if (problem === 'mismatch') {\n setLocalError(tl('The passwords do not match.', 'As senhas não conferem.'))\n return\n }\n setBusy(true)\n try {\n await signUp(email, password, fullName)\n onSuccess?.()\n } finally {\n setBusy(false)\n }\n }\n\n const tooShort = password.length > 0 && newPasswordProblem(password) === 'too-short'\n\n return (\n <form onSubmit={submit} className=\"space-y-4\">\n <label className=\"block space-y-1.5 text-sm font-medium\">\n <span>{tl('Full name', 'Nome completo')}</span>\n <input\n className={fieldClass()}\n autoComplete=\"name\"\n required\n value={fullName}\n onChange={(e) => setFullName(e.target.value)}\n disabled={disabled}\n />\n </label>\n <label className=\"block space-y-1.5 text-sm font-medium\">\n <span>{tl('Email', 'E-mail')}</span>\n <input\n className={fieldClass()}\n type=\"email\"\n inputMode=\"email\"\n autoComplete=\"username\"\n required\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n disabled={disabled}\n />\n </label>\n\n <div className=\"space-y-1.5 text-sm font-medium\">\n <label className=\"block space-y-1.5\" htmlFor=\"signup-password\">\n <span>{tl('Password', 'Senha')}</span>\n <span className=\"relative block\">\n <input\n id=\"signup-password\"\n ref={passwordRef}\n className={`${fieldClass()} pr-10`}\n type={reveal ? 'text' : 'password'}\n autoComplete=\"new-password\"\n minLength={MIN_PASSWORD_LENGTH}\n required\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n disabled={disabled}\n aria-describedby=\"signup-password-hint\"\n />\n {/* The toggle is what replaces the confirmation field: you check a\n password by reading it, not by typing it twice. */}\n <button\n type=\"button\"\n onClick={() => setReveal((v) => !v)}\n aria-label={reveal ? tl('Hide password', 'Ocultar senha') : tl('Show password', 'Mostrar senha')}\n aria-pressed={reveal}\n className=\"absolute inset-y-0 right-0 flex w-10 items-center justify-center rounded-r-md text-muted-foreground transition-colors hover:text-foreground\"\n >\n {reveal ? <EyeOff className=\"h-4 w-4\" /> : <Eye className=\"h-4 w-4\" />}\n </button>\n </span>\n </label>\n <p\n id=\"signup-password-hint\"\n className={`text-xs font-normal ${tooShort ? 'text-warning' : 'text-muted-foreground'}`}\n >\n {tl(`At least ${MIN_PASSWORD_LENGTH} characters.`, `Pelo menos ${MIN_PASSWORD_LENGTH} caracteres.`)}\n </p>\n </div>\n\n {requireConfirmation && (\n <label className=\"block space-y-1.5 text-sm font-medium\">\n <span>{tl('Confirm password', 'Confirme a senha')}</span>\n <input\n className={fieldClass()}\n type={reveal ? 'text' : 'password'}\n autoComplete=\"new-password\"\n required\n value={confirmPassword}\n onChange={(e) => setConfirmPassword(e.target.value)}\n disabled={disabled}\n />\n </label>\n )}\n\n {(localError || error) && (\n <p role=\"alert\" className=\"text-sm text-destructive\">{localError ?? error?.message}</p>\n )}\n\n <button className={buttonClass()} type=\"submit\" disabled={disabled}>\n {disabled ? tl('Creating account...', 'Criando conta...') : tl('Create account', 'Criar conta')}\n </button>\n\n {(termsUrl || privacyUrl) && (\n <p className=\"text-center text-xs leading-relaxed text-muted-foreground\">\n {tl('By continuing you agree to our', 'Ao continuar, você concorda com os')}{' '}\n {termsUrl && (\n <a href={termsUrl} target=\"_blank\" rel=\"noopener noreferrer\" className=\"underline hover:text-foreground\">\n {tl('terms of service', 'termos de uso')}\n </a>\n )}\n {termsUrl && privacyUrl && tl(' and ', ' e a ')}\n {privacyUrl && (\n <a href={privacyUrl} target=\"_blank\" rel=\"noopener noreferrer\" className=\"underline hover:text-foreground\">\n {tl('privacy policy', 'política de privacidade')}\n </a>\n )}\n .\n </p>\n )}\n\n {showOAuth && (\n <OAuthButtons providers={oauthProviders} disabled={disabled} comingSoon={oauthComingSoon} />\n )}\n </form>\n )\n}\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// src/domain/password.ts
|
|
2
|
+
var MIN_PASSWORD_LENGTH = 8;
|
|
3
|
+
function newPasswordProblem(password, confirmation) {
|
|
4
|
+
if (password.length < MIN_PASSWORD_LENGTH) return "too-short";
|
|
5
|
+
if (confirmation !== void 0 && password !== confirmation) return "mismatch";
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export { MIN_PASSWORD_LENGTH, newPasswordProblem };
|
|
10
|
+
//# sourceMappingURL=chunk-KLQDHFVS.js.map
|
|
11
|
+
//# sourceMappingURL=chunk-KLQDHFVS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/domain/password.ts"],"names":[],"mappings":";AAAO,IAAM,mBAAA,GAAsB;AAK5B,SAAS,kBAAA,CAAmB,UAAkB,YAAA,EAAkD;AACrG,EAAA,IAAI,QAAA,CAAS,MAAA,GAAS,mBAAA,EAAqB,OAAO,WAAA;AAClD,EAAA,IAAI,YAAA,KAAiB,MAAA,IAAa,QAAA,KAAa,YAAA,EAAc,OAAO,UAAA;AACpE,EAAA,OAAO,IAAA;AACT","file":"chunk-KLQDHFVS.js","sourcesContent":["export const MIN_PASSWORD_LENGTH = 8\n\nexport type NewPasswordProblem = 'too-short' | 'mismatch'\n\n/** Why a chosen password cannot be saved, or null when it can. No confirmation means none was asked. */\nexport function newPasswordProblem(password: string, confirmation?: string): NewPasswordProblem | null {\n if (password.length < MIN_PASSWORD_LENGTH) return 'too-short'\n if (confirmation !== undefined && password !== confirmation) return 'mismatch'\n return null\n}\n"]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { create } from 'zustand';
|
|
2
|
+
|
|
3
|
+
// src/store.ts
|
|
4
|
+
var initialState = {
|
|
5
|
+
user: null,
|
|
6
|
+
session: null,
|
|
7
|
+
isLoading: true,
|
|
8
|
+
isAuthenticated: false,
|
|
9
|
+
error: null,
|
|
10
|
+
pendingVerification: null
|
|
11
|
+
};
|
|
12
|
+
var useAuthStore = create((set) => ({
|
|
13
|
+
...initialState,
|
|
14
|
+
setUser: (user) => set({ user, isAuthenticated: user !== null }),
|
|
15
|
+
setSession: (session) => set({
|
|
16
|
+
session,
|
|
17
|
+
user: session?.user ?? null,
|
|
18
|
+
isAuthenticated: session !== null,
|
|
19
|
+
// A real session arriving is the confirmation landing — the notice it
|
|
20
|
+
// would otherwise keep showing is now about an address already verified.
|
|
21
|
+
...session ? { pendingVerification: null } : {}
|
|
22
|
+
}),
|
|
23
|
+
setLoading: (isLoading) => set({ isLoading }),
|
|
24
|
+
setError: (error) => set({ error }),
|
|
25
|
+
setPendingVerification: (pendingVerification) => set({ pendingVerification }),
|
|
26
|
+
reset: () => set(initialState)
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
export { useAuthStore };
|
|
30
|
+
//# sourceMappingURL=chunk-OI74ER2Z.js.map
|
|
31
|
+
//# sourceMappingURL=chunk-OI74ER2Z.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/store.ts"],"names":[],"mappings":";;;AA2BA,IAAM,YAAA,GAA0B;AAAA,EAC9B,IAAA,EAAM,IAAA;AAAA,EACN,OAAA,EAAS,IAAA;AAAA,EACT,SAAA,EAAW,IAAA;AAAA,EACX,eAAA,EAAiB,KAAA;AAAA,EACjB,KAAA,EAAO,IAAA;AAAA,EACP,mBAAA,EAAqB;AACvB,CAAA;AAEO,IAAM,YAAA,GAAe,MAAA,CAAkB,CAAC,GAAA,MAAS;AAAA,EACtD,GAAG,YAAA;AAAA,EAEH,OAAA,EAAS,CAAC,IAAA,KACR,GAAA,CAAI,EAAE,IAAA,EAAM,eAAA,EAAiB,IAAA,KAAS,IAAA,EAAM,CAAA;AAAA,EAE9C,UAAA,EAAY,CAAC,OAAA,KACX,GAAA,CAAI;AAAA,IACF,OAAA;AAAA,IACA,IAAA,EAAM,SAAS,IAAA,IAAQ,IAAA;AAAA,IACvB,iBAAiB,OAAA,KAAY,IAAA;AAAA;AAAA;AAAA,IAG7B,GAAI,OAAA,GAAU,EAAE,mBAAA,EAAqB,IAAA,KAAS;AAAC,GAChD,CAAA;AAAA,EAEH,YAAY,CAAC,SAAA,KAAc,GAAA,CAAI,EAAE,WAAW,CAAA;AAAA,EAE5C,UAAU,CAAC,KAAA,KAAU,GAAA,CAAI,EAAE,OAAO,CAAA;AAAA,EAElC,wBAAwB,CAAC,mBAAA,KAAwB,GAAA,CAAI,EAAE,qBAAqB,CAAA;AAAA,EAE5E,KAAA,EAAO,MAAM,GAAA,CAAI,YAAY;AAC/B,CAAA,CAAE","file":"chunk-OI74ER2Z.js","sourcesContent":["import { create } from 'zustand'\nimport type { AuthUser, AuthSession } from '@fayz-ai/core'\n\nexport interface AuthState {\n user: AuthUser | null\n session: AuthSession | null\n isLoading: boolean\n isAuthenticated: boolean\n error: Error | null\n /**\n * Set when a sign-up succeeded but the account cannot be used until the\n * address is confirmed. Deliberately NOT a session: an account in this state\n * has no access token, and treating it as signed in is what used to let\n * someone into the app where every request came back 401.\n */\n pendingVerification: { email: string } | null\n}\n\nexport interface AuthStore extends AuthState {\n setUser: (user: AuthUser | null) => void\n setSession: (session: AuthSession | null) => void\n setLoading: (isLoading: boolean) => void\n setError: (error: Error | null) => void\n setPendingVerification: (pending: { email: string } | null) => void\n reset: () => void\n}\n\nconst initialState: AuthState = {\n user: null,\n session: null,\n isLoading: true,\n isAuthenticated: false,\n error: null,\n pendingVerification: null,\n}\n\nexport const useAuthStore = create<AuthStore>((set) => ({\n ...initialState,\n\n setUser: (user) =>\n set({ user, isAuthenticated: user !== null }),\n\n setSession: (session) =>\n set({\n session,\n user: session?.user ?? null,\n isAuthenticated: session !== null,\n // A real session arriving is the confirmation landing — the notice it\n // would otherwise keep showing is now about an address already verified.\n ...(session ? { pendingVerification: null } : {}),\n }),\n\n setLoading: (isLoading) => set({ isLoading }),\n\n setError: (error) => set({ error }),\n\n setPendingVerification: (pendingVerification) => set({ pendingVerification }),\n\n reset: () => set(initialState),\n}))\n"]}
|