@fayz-ai/plugin-auth 0.8.0 → 0.9.0-next.1
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/AmbassadorBubbles.d.ts +9 -0
- package/dist/AmbassadorBubbles.d.ts.map +1 -0
- package/dist/forms.d.ts +16 -2
- package/dist/forms.d.ts.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +273 -25
- package/dist/index.js.map +1 -1
- package/dist/pages.d.ts +9 -2
- package/dist/pages.d.ts.map +1 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/set-password.d.ts +32 -0
- package/dist/set-password.d.ts.map +1 -0
- package/dist/types.d.ts +11 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +12 -12
- package/src/AmbassadorBubbles.tsx +61 -0
- package/src/forms.tsx +65 -10
- package/src/index.ts +7 -0
- package/src/pages.tsx +28 -15
- package/src/runtime.ts +10 -2
- package/src/set-password.tsx +229 -0
- package/src/types.ts +12 -0
- package/dist/index.cjs +0 -399
- package/dist/index.cjs.map +0 -1
- package/dist/website/index.cjs +0 -275
- package/dist/website/index.cjs.map +0 -1
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { LoginAmbassador } from './types';
|
|
3
|
+
export interface AmbassadorBubblesProps {
|
|
4
|
+
ambassadors?: LoginAmbassador[];
|
|
5
|
+
/** Optional social-proof caption shown beside the avatars, e.g. "+2 mil profissionais". */
|
|
6
|
+
label?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function AmbassadorBubbles({ ambassadors, label }: AmbassadorBubblesProps): React.JSX.Element | null;
|
|
9
|
+
//# sourceMappingURL=AmbassadorBubbles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AmbassadorBubbles.d.ts","sourceRoot":"","sources":["../src/AmbassadorBubbles.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAwB9C,MAAM,WAAW,sBAAsB;IACrC,WAAW,CAAC,EAAE,eAAe,EAAE,CAAA;IAC/B,2FAA2F;IAC3F,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAgB,iBAAiB,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,sBAAsB,4BA6B/E"}
|
package/dist/forms.d.ts
CHANGED
|
@@ -11,8 +11,12 @@ export interface LoginFormProps {
|
|
|
11
11
|
onForgotPassword?: () => void;
|
|
12
12
|
showOAuth?: boolean;
|
|
13
13
|
oauthProviders?: Exclude<AuthProvider, 'email'>[];
|
|
14
|
+
/** Seeds the field, so switching between login and recovery never asks for the
|
|
15
|
+
* e-mail the user already typed. */
|
|
16
|
+
initialEmail?: string;
|
|
17
|
+
onEmailChange?: (email: string) => void;
|
|
14
18
|
}
|
|
15
|
-
export declare function LoginForm({ onSuccess, onForgotPassword, showOAuth, oauthProviders }: LoginFormProps): React.JSX.Element;
|
|
19
|
+
export declare function LoginForm({ onSuccess, onForgotPassword, showOAuth, oauthProviders, initialEmail, onEmailChange, }: LoginFormProps): React.JSX.Element;
|
|
16
20
|
export interface SignupFormProps {
|
|
17
21
|
onSuccess?: () => void;
|
|
18
22
|
}
|
|
@@ -21,8 +25,18 @@ export interface ForgotPasswordFormProps {
|
|
|
21
25
|
redirectTo?: string;
|
|
22
26
|
onSent?: (email: string) => void;
|
|
23
27
|
onBackToLogin?: () => void;
|
|
28
|
+
/** Pre-filled with whatever the user already typed on the login form. */
|
|
29
|
+
initialEmail?: string;
|
|
30
|
+
onEmailChange?: (email: string) => void;
|
|
31
|
+
/** Copy overrides — the set-password screen reuses this form to hand out a
|
|
32
|
+
* fresh link, where "Send reset link" is the wrong label. */
|
|
33
|
+
emailLabel?: string;
|
|
34
|
+
submitLabel?: string;
|
|
35
|
+
sendingLabel?: string;
|
|
36
|
+
sentLabel?: string;
|
|
37
|
+
backLabel?: string;
|
|
24
38
|
}
|
|
25
|
-
export declare function ForgotPasswordForm({ redirectTo, onSent, onBackToLogin }: ForgotPasswordFormProps): React.JSX.Element;
|
|
39
|
+
export declare function ForgotPasswordForm({ redirectTo, onSent, onBackToLogin, initialEmail, onEmailChange, emailLabel, submitLabel, sendingLabel, sentLabel, backLabel, }: ForgotPasswordFormProps): React.JSX.Element;
|
|
26
40
|
export interface ResetPasswordFormProps {
|
|
27
41
|
onSuccess?: () => void;
|
|
28
42
|
}
|
package/dist/forms.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forms.d.ts","sourceRoot":"","sources":["../src/forms.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAkBjD,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,EAAE,CAAA;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACnE;AAED,wBAAgB,YAAY,CAAC,EAAE,SAAsB,EAAE,QAAQ,EAAE,eAAe,EAAE,EAAE,iBAAiB,qBAmBpG;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAA;IAC7B,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"forms.d.ts","sourceRoot":"","sources":["../src/forms.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAkBjD,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,EAAE,CAAA;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACnE;AAED,wBAAgB,YAAY,CAAC,EAAE,SAAsB,EAAE,QAAQ,EAAE,eAAe,EAAE,EAAE,iBAAiB,qBAmBpG;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAA;IAC7B,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,EAAE,CAAA;IACjD;yCACqC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACxC;AAED,wBAAgB,SAAS,CAAC,EACxB,SAAS,EACT,gBAAgB,EAChB,SAAS,EACT,cAAc,EACd,YAAiB,EACjB,aAAa,GACd,EAAE,cAAc,qBAqDhB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB;AAED,wBAAgB,UAAU,CAAC,EAAE,SAAS,EAAE,EAAE,eAAe,qBAsDxD;AAED,MAAM,WAAW,uBAAuB;IACtC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,aAAa,CAAC,EAAE,MAAM,IAAI,CAAA;IAC1B,yEAAyE;IACzE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC;kEAC8D;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,kBAAkB,CAAC,EACjC,UAAU,EACV,MAAM,EACN,aAAa,EACb,YAAiB,EACjB,aAAa,EACb,UAAoB,EACpB,WAA+B,EAC/B,YAA2B,EAC3B,SAA+C,EAC/C,SAA2B,GAC5B,EAAE,uBAAuB,qBAiDzB;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB;AAED,wBAAgB,iBAAiB,CAAC,EAAE,SAAS,EAAE,EAAE,sBAAsB,qBA4CtE"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
export { createAuthPlugin, createAuthRuntime, resolveAuthAdapter, } from './runtime';
|
|
2
2
|
export { AuthGate, LoginPage, AuthCallbackPage, ResetPasswordPage, } from './pages';
|
|
3
3
|
export type { AuthCallbackPageProps, AuthGateProps, LoginPageProps, ResetPasswordPageProps, } from './pages';
|
|
4
|
+
export { SetPasswordPage, usePasswordSetupGate } from './set-password';
|
|
5
|
+
export type { SetPasswordPageProps, SetPasswordReason, PasswordSetupGate } from './set-password';
|
|
6
|
+
export { AmbassadorBubbles } from './AmbassadorBubbles';
|
|
7
|
+
export type { AmbassadorBubblesProps } from './AmbassadorBubbles';
|
|
4
8
|
export { LoginForm, SignupForm, ForgotPasswordForm, ResetPasswordForm, OAuthButtons, } from './forms';
|
|
5
9
|
export type { ForgotPasswordFormProps, LoginFormProps, OAuthButtonsProps, ResetPasswordFormProps, SignupFormProps, } from './forms';
|
|
6
|
-
export { createMockAuthAdapter, createSupabaseAuthAdapter, AuthProvider, useAuth, useAuthStore, } from '@fayz-ai/auth';
|
|
7
|
-
export type { AuthPluginOptions, ResolvedAuthPlugin, AuthRoutesConfig, AuthOAuthConfig, AuthSupabaseConfig, AuthProviderKey, AuthLayout, AuthFormView, } from './types';
|
|
10
|
+
export { createMockAuthAdapter, createSupabaseAuthAdapter, AuthProvider, useAuth, useAuthStore, readAuthUrlIntent, clearAuthUrlTokens, } from '@fayz-ai/auth';
|
|
11
|
+
export type { AuthPluginOptions, ResolvedAuthPlugin, AuthRoutesConfig, AuthOAuthConfig, AuthSupabaseConfig, AuthProviderKey, AuthLayout, AuthFormView, LoginAmbassador, } from './types';
|
|
8
12
|
export type { AuthAdapter, AuthSession, AuthUser, AuthProvider as OAuthProvider } from '@fayz-ai/core';
|
|
9
13
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,WAAW,CAAA;AAClB,OAAO,EACL,QAAQ,EACR,SAAS,EACT,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,SAAS,CAAA;AAChB,YAAY,EACV,qBAAqB,EACrB,aAAa,EACb,cAAc,EACd,sBAAsB,GACvB,MAAM,SAAS,CAAA;AAChB,OAAO,EACL,SAAS,EACT,UAAU,EACV,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,GACb,MAAM,SAAS,CAAA;AAChB,YAAY,EACV,uBAAuB,EACvB,cAAc,EACd,iBAAiB,EACjB,sBAAsB,EACtB,eAAe,GAChB,MAAM,SAAS,CAAA;AAChB,OAAO,EACL,qBAAqB,EACrB,yBAAyB,EACzB,YAAY,EACZ,OAAO,EACP,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,WAAW,CAAA;AAClB,OAAO,EACL,QAAQ,EACR,SAAS,EACT,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,SAAS,CAAA;AAChB,YAAY,EACV,qBAAqB,EACrB,aAAa,EACb,cAAc,EACd,sBAAsB,GACvB,MAAM,SAAS,CAAA;AAChB,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AACtE,YAAY,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAChG,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACvD,YAAY,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AACjE,OAAO,EACL,SAAS,EACT,UAAU,EACV,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,GACb,MAAM,SAAS,CAAA;AAChB,YAAY,EACV,uBAAuB,EACvB,cAAc,EACd,iBAAiB,EACjB,sBAAsB,EACtB,eAAe,GAChB,MAAM,SAAS,CAAA;AAChB,OAAO,EACL,qBAAqB,EACrB,yBAAyB,EACzB,YAAY,EACZ,OAAO,EACP,YAAY,EACZ,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,eAAe,CAAA;AACtB,YAAY,EACV,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,UAAU,EACV,YAAY,EACZ,eAAe,GAChB,MAAM,SAAS,CAAA;AAChB,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,IAAI,aAAa,EAAE,MAAM,eAAe,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { createSupabaseAuthAdapter, createMockAuthAdapter, useAuth } from '@fayz-ai/auth';
|
|
2
|
-
export { AuthProvider, createMockAuthAdapter, createSupabaseAuthAdapter, useAuth, useAuthStore } from '@fayz-ai/auth';
|
|
1
|
+
import { createSupabaseAuthAdapter, createMockAuthAdapter, useAuth, readAuthUrlIntent, clearAuthUrlTokens, decidePasswordSetup } from '@fayz-ai/auth';
|
|
2
|
+
export { AuthProvider, clearAuthUrlTokens, createMockAuthAdapter, createSupabaseAuthAdapter, readAuthUrlIntent, useAuth, useAuthStore } from '@fayz-ai/auth';
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
|
+
import { useTranslation } from '@fayz-ai/core';
|
|
5
6
|
|
|
6
7
|
// src/runtime.ts
|
|
7
8
|
function absoluteUrl(path) {
|
|
@@ -24,7 +25,10 @@ function resolveAuthAdapter(options = {}) {
|
|
|
24
25
|
supabaseAnonKey: anonKey,
|
|
25
26
|
supabaseClient: options.supabase?.client,
|
|
26
27
|
callbackUrl: options.supabase?.callbackUrl ?? absoluteUrl(options.routes?.callback ?? "/auth/callback"),
|
|
27
|
-
|
|
28
|
+
// Only when the host asked for a specific URL. Left undefined, the adapter
|
|
29
|
+
// points recovery at the app root, which needs no route and no extra entry
|
|
30
|
+
// in Supabase's redirect allow-list.
|
|
31
|
+
resetPasswordUrl: options.supabase?.resetPasswordUrl ?? (options.routes?.resetPassword ? absoluteUrl(options.routes.resetPassword) : void 0)
|
|
28
32
|
});
|
|
29
33
|
}
|
|
30
34
|
return createMockAuthAdapter();
|
|
@@ -38,6 +42,8 @@ function createAuthRuntime(options = {}) {
|
|
|
38
42
|
logo: options.logo,
|
|
39
43
|
tagline: options.tagline,
|
|
40
44
|
description: options.description,
|
|
45
|
+
loginAmbassadors: options.loginAmbassadors,
|
|
46
|
+
loginAmbassadorsLabel: options.loginAmbassadorsLabel,
|
|
41
47
|
oauth: {
|
|
42
48
|
enabled: options.oauth?.enabled ?? false,
|
|
43
49
|
providers: options.oauth?.providers ?? ["google"]
|
|
@@ -45,7 +51,9 @@ function createAuthRuntime(options = {}) {
|
|
|
45
51
|
routes: {
|
|
46
52
|
login: options.routes?.login ?? "/login",
|
|
47
53
|
callback: options.routes?.callback ?? "/auth/callback",
|
|
48
|
-
|
|
54
|
+
// The app root — recovery links are recognised by their own params, not by
|
|
55
|
+
// the path they land on. See resetPassword() in the Supabase adapter.
|
|
56
|
+
resetPassword: options.routes?.resetPassword ?? "/",
|
|
49
57
|
afterSignIn: options.routes?.afterSignIn ?? "/"
|
|
50
58
|
}
|
|
51
59
|
};
|
|
@@ -85,9 +93,16 @@ function OAuthButtons({ providers = ["google"], disabled, onProviderClick }) {
|
|
|
85
93
|
provider
|
|
86
94
|
)) });
|
|
87
95
|
}
|
|
88
|
-
function LoginForm({
|
|
96
|
+
function LoginForm({
|
|
97
|
+
onSuccess,
|
|
98
|
+
onForgotPassword,
|
|
99
|
+
showOAuth,
|
|
100
|
+
oauthProviders,
|
|
101
|
+
initialEmail = "",
|
|
102
|
+
onEmailChange
|
|
103
|
+
}) {
|
|
89
104
|
const { signIn, error, isLoading } = useAuth();
|
|
90
|
-
const [email, setEmail] = React.useState(
|
|
105
|
+
const [email, setEmail] = React.useState(initialEmail);
|
|
91
106
|
const [password, setPassword] = React.useState("");
|
|
92
107
|
const [busy, setBusy] = React.useState(false);
|
|
93
108
|
const disabled = busy || isLoading;
|
|
@@ -104,7 +119,21 @@ function LoginForm({ onSuccess, onForgotPassword, showOAuth, oauthProviders }) {
|
|
|
104
119
|
return /* @__PURE__ */ jsxs("form", { onSubmit: submit, className: "space-y-4", children: [
|
|
105
120
|
/* @__PURE__ */ jsxs("label", { className: "block space-y-1.5 text-sm font-medium", children: [
|
|
106
121
|
/* @__PURE__ */ jsx("span", { children: "Email" }),
|
|
107
|
-
/* @__PURE__ */ jsx(
|
|
122
|
+
/* @__PURE__ */ jsx(
|
|
123
|
+
"input",
|
|
124
|
+
{
|
|
125
|
+
className: fieldClass(),
|
|
126
|
+
type: "email",
|
|
127
|
+
autoComplete: "username",
|
|
128
|
+
required: true,
|
|
129
|
+
value: email,
|
|
130
|
+
onChange: (e) => {
|
|
131
|
+
setEmail(e.target.value);
|
|
132
|
+
onEmailChange?.(e.target.value);
|
|
133
|
+
},
|
|
134
|
+
disabled
|
|
135
|
+
}
|
|
136
|
+
)
|
|
108
137
|
] }),
|
|
109
138
|
/* @__PURE__ */ jsxs("label", { className: "block space-y-1.5 text-sm font-medium", children: [
|
|
110
139
|
/* @__PURE__ */ jsx("span", { children: "Password" }),
|
|
@@ -165,9 +194,20 @@ function SignupForm({ onSuccess }) {
|
|
|
165
194
|
/* @__PURE__ */ jsx("button", { className: buttonClass(), type: "submit", disabled, children: disabled ? "Creating account..." : "Create account" })
|
|
166
195
|
] });
|
|
167
196
|
}
|
|
168
|
-
function ForgotPasswordForm({
|
|
197
|
+
function ForgotPasswordForm({
|
|
198
|
+
redirectTo,
|
|
199
|
+
onSent,
|
|
200
|
+
onBackToLogin,
|
|
201
|
+
initialEmail = "",
|
|
202
|
+
onEmailChange,
|
|
203
|
+
emailLabel = "Email",
|
|
204
|
+
submitLabel = "Send reset link",
|
|
205
|
+
sendingLabel = "Sending...",
|
|
206
|
+
sentLabel = "Password reset instructions sent.",
|
|
207
|
+
backLabel = "Back to login"
|
|
208
|
+
}) {
|
|
169
209
|
const { resetPassword, error, isLoading } = useAuth();
|
|
170
|
-
const [email, setEmail] = React.useState(
|
|
210
|
+
const [email, setEmail] = React.useState(initialEmail);
|
|
171
211
|
const [sent, setSent] = React.useState(false);
|
|
172
212
|
const [busy, setBusy] = React.useState(false);
|
|
173
213
|
const disabled = busy || isLoading;
|
|
@@ -184,13 +224,28 @@ function ForgotPasswordForm({ redirectTo, onSent, onBackToLogin }) {
|
|
|
184
224
|
}
|
|
185
225
|
return /* @__PURE__ */ jsxs("form", { onSubmit: submit, className: "space-y-4", children: [
|
|
186
226
|
/* @__PURE__ */ jsxs("label", { className: "block space-y-1.5 text-sm font-medium", children: [
|
|
187
|
-
/* @__PURE__ */ jsx("span", { children:
|
|
188
|
-
/* @__PURE__ */ jsx(
|
|
227
|
+
/* @__PURE__ */ jsx("span", { children: emailLabel }),
|
|
228
|
+
/* @__PURE__ */ jsx(
|
|
229
|
+
"input",
|
|
230
|
+
{
|
|
231
|
+
className: fieldClass(),
|
|
232
|
+
type: "email",
|
|
233
|
+
autoComplete: "username",
|
|
234
|
+
required: true,
|
|
235
|
+
autoFocus: !email,
|
|
236
|
+
value: email,
|
|
237
|
+
onChange: (e) => {
|
|
238
|
+
setEmail(e.target.value);
|
|
239
|
+
onEmailChange?.(e.target.value);
|
|
240
|
+
},
|
|
241
|
+
disabled
|
|
242
|
+
}
|
|
243
|
+
)
|
|
189
244
|
] }),
|
|
190
245
|
error && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: error.message }),
|
|
191
|
-
sent && /* @__PURE__ */ jsx("p", { className: "text-sm text-emerald-600", children:
|
|
192
|
-
/* @__PURE__ */ jsx("button", { className: buttonClass(), type: "submit", disabled, children: disabled ?
|
|
193
|
-
onBackToLogin && /* @__PURE__ */ jsx("button", { type: "button", className: buttonClass("ghost"), onClick: onBackToLogin, children:
|
|
246
|
+
sent && /* @__PURE__ */ jsx("p", { className: "text-sm text-emerald-600", children: sentLabel }),
|
|
247
|
+
/* @__PURE__ */ jsx("button", { className: buttonClass(), type: "submit", disabled, children: disabled ? sendingLabel : submitLabel }),
|
|
248
|
+
onBackToLogin && /* @__PURE__ */ jsx("button", { type: "button", className: buttonClass("ghost"), onClick: onBackToLogin, children: backLabel })
|
|
194
249
|
] });
|
|
195
250
|
}
|
|
196
251
|
function ResetPasswordForm({ onSuccess }) {
|
|
@@ -232,6 +287,191 @@ function ResetPasswordForm({ onSuccess }) {
|
|
|
232
287
|
/* @__PURE__ */ jsx("button", { className: buttonClass(), type: "submit", disabled, children: disabled ? "Saving..." : "Update password" })
|
|
233
288
|
] });
|
|
234
289
|
}
|
|
290
|
+
var MIN_LENGTH = 8;
|
|
291
|
+
function fieldClass2() {
|
|
292
|
+
return "h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm outline-none focus:ring-2 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50";
|
|
293
|
+
}
|
|
294
|
+
function buttonClass2() {
|
|
295
|
+
return "inline-flex h-10 w-full items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50";
|
|
296
|
+
}
|
|
297
|
+
function useTr() {
|
|
298
|
+
const t = useTranslation();
|
|
299
|
+
return React.useCallback(
|
|
300
|
+
(key, fallback, params) => {
|
|
301
|
+
const value = t(key, params);
|
|
302
|
+
return !value || value === key ? fallback : value;
|
|
303
|
+
},
|
|
304
|
+
[t]
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
function usePasswordSetupGate() {
|
|
308
|
+
const { user, isLoading, isAuthenticated } = useAuth();
|
|
309
|
+
const [done, setDone] = React.useState(false);
|
|
310
|
+
const intent = React.useMemo(() => readAuthUrlIntent(), []);
|
|
311
|
+
const complete = React.useCallback(() => {
|
|
312
|
+
clearAuthUrlTokens();
|
|
313
|
+
setDone(true);
|
|
314
|
+
}, []);
|
|
315
|
+
if (done) return { reason: null, expired: false, checking: false, complete };
|
|
316
|
+
const decision = decidePasswordSetup({
|
|
317
|
+
intent,
|
|
318
|
+
isLoading,
|
|
319
|
+
isAuthenticated,
|
|
320
|
+
mustSetPassword: user?.mustSetPassword
|
|
321
|
+
});
|
|
322
|
+
return { ...decision, complete };
|
|
323
|
+
}
|
|
324
|
+
function SetPasswordPage({
|
|
325
|
+
reason,
|
|
326
|
+
appName = "App",
|
|
327
|
+
logo,
|
|
328
|
+
expired,
|
|
329
|
+
checking,
|
|
330
|
+
onSuccess
|
|
331
|
+
}) {
|
|
332
|
+
const tr = useTr();
|
|
333
|
+
const { user, updatePassword, signOut, error, isLoading } = useAuth();
|
|
334
|
+
const [password, setPassword] = React.useState("");
|
|
335
|
+
const [confirmPassword, setConfirmPassword] = React.useState("");
|
|
336
|
+
const [localError, setLocalError] = React.useState(null);
|
|
337
|
+
const [busy, setBusy] = React.useState(false);
|
|
338
|
+
const disabled = busy || isLoading;
|
|
339
|
+
const invite = reason === "invite";
|
|
340
|
+
const title = invite ? tr("auth.setPassword.welcomeTitle", `Welcome to ${appName}`, { appName }) : tr("auth.setPassword.recoveryTitle", "Choose a new password");
|
|
341
|
+
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.");
|
|
342
|
+
async function submit(event) {
|
|
343
|
+
event.preventDefault();
|
|
344
|
+
setLocalError(null);
|
|
345
|
+
if (password.length < MIN_LENGTH) {
|
|
346
|
+
setLocalError(tr("auth.setPassword.tooShort", `Password must be at least ${MIN_LENGTH} characters.`));
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
if (password !== confirmPassword) {
|
|
350
|
+
setLocalError(tr("auth.setPassword.mismatch", "Passwords do not match."));
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
setBusy(true);
|
|
354
|
+
try {
|
|
355
|
+
await updatePassword(password);
|
|
356
|
+
onSuccess?.();
|
|
357
|
+
} catch {
|
|
358
|
+
} finally {
|
|
359
|
+
setBusy(false);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
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: [
|
|
363
|
+
logo && /* @__PURE__ */ jsx("div", { className: "mb-6 flex justify-center", children: logo }),
|
|
364
|
+
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: [
|
|
365
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-6", children: [
|
|
366
|
+
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold text-foreground", children: tr("auth.setPassword.expiredTitle", "This link has expired") }),
|
|
367
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: tr(
|
|
368
|
+
"auth.setPassword.expiredSubtitle",
|
|
369
|
+
"Reset links can only be used once. Enter your e-mail and we will send a new one."
|
|
370
|
+
) })
|
|
371
|
+
] }),
|
|
372
|
+
/* @__PURE__ */ jsx(
|
|
373
|
+
ForgotPasswordForm,
|
|
374
|
+
{
|
|
375
|
+
initialEmail: user?.email,
|
|
376
|
+
submitLabel: tr("auth.setPassword.sendNewLink", "Send new link"),
|
|
377
|
+
sendingLabel: tr("auth.setPassword.sending", "Sending..."),
|
|
378
|
+
sentLabel: tr("auth.setPassword.sent", "Check your inbox \u2014 a new link is on the way."),
|
|
379
|
+
emailLabel: tr("auth.setPassword.email", "E-mail"),
|
|
380
|
+
backLabel: tr("auth.setPassword.backToLogin", "Back to sign in"),
|
|
381
|
+
onBackToLogin: onSuccess
|
|
382
|
+
}
|
|
383
|
+
)
|
|
384
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
385
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-6", children: [
|
|
386
|
+
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold text-foreground", children: title }),
|
|
387
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: subtitle })
|
|
388
|
+
] }),
|
|
389
|
+
/* @__PURE__ */ jsxs("form", { onSubmit: submit, className: "space-y-4", children: [
|
|
390
|
+
/* @__PURE__ */ jsxs("label", { className: "block space-y-1.5 text-sm font-medium", children: [
|
|
391
|
+
/* @__PURE__ */ jsx("span", { children: tr("auth.setPassword.newPassword", "New password") }),
|
|
392
|
+
/* @__PURE__ */ jsx(
|
|
393
|
+
"input",
|
|
394
|
+
{
|
|
395
|
+
className: fieldClass2(),
|
|
396
|
+
type: "password",
|
|
397
|
+
autoComplete: "new-password",
|
|
398
|
+
autoFocus: true,
|
|
399
|
+
required: true,
|
|
400
|
+
value: password,
|
|
401
|
+
onChange: (e) => setPassword(e.target.value),
|
|
402
|
+
disabled
|
|
403
|
+
}
|
|
404
|
+
)
|
|
405
|
+
] }),
|
|
406
|
+
/* @__PURE__ */ jsxs("label", { className: "block space-y-1.5 text-sm font-medium", children: [
|
|
407
|
+
/* @__PURE__ */ jsx("span", { children: tr("auth.setPassword.confirmPassword", "Confirm password") }),
|
|
408
|
+
/* @__PURE__ */ jsx(
|
|
409
|
+
"input",
|
|
410
|
+
{
|
|
411
|
+
className: fieldClass2(),
|
|
412
|
+
type: "password",
|
|
413
|
+
autoComplete: "new-password",
|
|
414
|
+
required: true,
|
|
415
|
+
value: confirmPassword,
|
|
416
|
+
onChange: (e) => setConfirmPassword(e.target.value),
|
|
417
|
+
disabled
|
|
418
|
+
}
|
|
419
|
+
)
|
|
420
|
+
] }),
|
|
421
|
+
(localError || error) && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: localError ?? error?.message }),
|
|
422
|
+
/* @__PURE__ */ jsx("button", { className: buttonClass2(), type: "submit", disabled, children: disabled ? tr("auth.setPassword.saving", "Saving...") : tr("auth.setPassword.submit", "Save password") })
|
|
423
|
+
] }),
|
|
424
|
+
/* @__PURE__ */ jsx(
|
|
425
|
+
"button",
|
|
426
|
+
{
|
|
427
|
+
type: "button",
|
|
428
|
+
className: "mt-4 w-full text-center text-sm text-muted-foreground hover:text-foreground",
|
|
429
|
+
onClick: () => {
|
|
430
|
+
void signOut().finally(() => onSuccess?.());
|
|
431
|
+
},
|
|
432
|
+
children: tr("auth.setPassword.backToLogin", "Back to sign in")
|
|
433
|
+
}
|
|
434
|
+
)
|
|
435
|
+
] })
|
|
436
|
+
] }) });
|
|
437
|
+
}
|
|
438
|
+
var FLOAT_STYLES = `
|
|
439
|
+
@keyframes fayz-amb-drift {
|
|
440
|
+
0%, 100% { transform: translateY(0); }
|
|
441
|
+
50% { transform: translateY(-2px); }
|
|
442
|
+
}
|
|
443
|
+
@media (prefers-reduced-motion: reduce) {
|
|
444
|
+
.fayz-amb-avatar { animation: none !important; }
|
|
445
|
+
}
|
|
446
|
+
`;
|
|
447
|
+
function AmbassadorBubbles({ ambassadors, label }) {
|
|
448
|
+
const items = (ambassadors ?? []).filter((a) => a && typeof a.image === "string" && a.image.trim() !== "");
|
|
449
|
+
if (items.length === 0) return null;
|
|
450
|
+
const shown = items.slice(0, 5);
|
|
451
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
452
|
+
/* @__PURE__ */ jsx("style", { children: FLOAT_STYLES }),
|
|
453
|
+
/* @__PURE__ */ jsx("div", { className: "flex -space-x-2", children: shown.map((ambassador, index) => /* @__PURE__ */ jsx(
|
|
454
|
+
"div",
|
|
455
|
+
{
|
|
456
|
+
title: ambassador.role ? `${ambassador.name} \xB7 ${ambassador.role}` : ambassador.name,
|
|
457
|
+
className: "fayz-amb-avatar relative h-10 w-10 shrink-0 overflow-hidden rounded-full border-2 border-sidebar bg-sidebar-accent shadow-md ring-1 ring-sidebar-foreground/10 transition-transform duration-200 hover:z-10 hover:scale-110",
|
|
458
|
+
style: { animation: `fayz-amb-drift 4s ease-in-out ${index * 0.4}s infinite` },
|
|
459
|
+
children: /* @__PURE__ */ jsx(
|
|
460
|
+
"img",
|
|
461
|
+
{
|
|
462
|
+
src: ambassador.image,
|
|
463
|
+
alt: ambassador.name,
|
|
464
|
+
className: "h-full w-full object-cover",
|
|
465
|
+
loading: "lazy",
|
|
466
|
+
draggable: false
|
|
467
|
+
}
|
|
468
|
+
)
|
|
469
|
+
},
|
|
470
|
+
`${ambassador.name}-${index}`
|
|
471
|
+
)) }),
|
|
472
|
+
label ? /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-sidebar-foreground/80", children: label }) : null
|
|
473
|
+
] });
|
|
474
|
+
}
|
|
235
475
|
function LoginPage({
|
|
236
476
|
appName = "App",
|
|
237
477
|
logo,
|
|
@@ -239,12 +479,15 @@ function LoginPage({
|
|
|
239
479
|
layout = "split",
|
|
240
480
|
tagline,
|
|
241
481
|
description,
|
|
482
|
+
loginAmbassadors,
|
|
483
|
+
loginAmbassadorsLabel,
|
|
242
484
|
showOAuth,
|
|
243
485
|
oauthProviders,
|
|
244
486
|
resetPasswordUrl,
|
|
245
487
|
onSuccess
|
|
246
488
|
}) {
|
|
247
489
|
const [view, setView] = React.useState("login");
|
|
490
|
+
const [email, setEmail] = React.useState("");
|
|
248
491
|
const brandLogo = loginLogo ?? logo;
|
|
249
492
|
const heading = view === "login" ? "Welcome back" : view === "signup" ? "Create account" : "Reset password";
|
|
250
493
|
const subtitle = view === "login" ? "Enter your credentials to continue" : view === "signup" ? "Create your account to get started" : "Enter your email and we will send reset instructions";
|
|
@@ -254,9 +497,19 @@ function LoginPage({
|
|
|
254
497
|
onSuccess,
|
|
255
498
|
onForgotPassword: () => setView("recovery"),
|
|
256
499
|
showOAuth,
|
|
257
|
-
oauthProviders
|
|
500
|
+
oauthProviders,
|
|
501
|
+
initialEmail: email,
|
|
502
|
+
onEmailChange: setEmail
|
|
258
503
|
}
|
|
259
|
-
) : view === "signup" ? /* @__PURE__ */ jsx(SignupForm, { onSuccess }) : /* @__PURE__ */ jsx(
|
|
504
|
+
) : view === "signup" ? /* @__PURE__ */ jsx(SignupForm, { onSuccess }) : /* @__PURE__ */ jsx(
|
|
505
|
+
ForgotPasswordForm,
|
|
506
|
+
{
|
|
507
|
+
redirectTo: resetPasswordUrl,
|
|
508
|
+
onBackToLogin: () => setView("login"),
|
|
509
|
+
initialEmail: email,
|
|
510
|
+
onEmailChange: setEmail
|
|
511
|
+
}
|
|
512
|
+
);
|
|
260
513
|
const switcher = view === "login" ? /* @__PURE__ */ jsxs("p", { className: "text-center text-sm text-muted-foreground", children: [
|
|
261
514
|
"Do not have an account?",
|
|
262
515
|
" ",
|
|
@@ -282,7 +535,8 @@ function LoginPage({
|
|
|
282
535
|
return /* @__PURE__ */ jsxs("div", { className: "flex min-h-screen bg-sidebar", children: [
|
|
283
536
|
/* @__PURE__ */ jsxs("div", { className: "relative hidden w-1/2 overflow-hidden lg:block", children: [
|
|
284
537
|
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-gradient-to-br from-sidebar-accent/50 via-transparent to-sidebar/80" }),
|
|
285
|
-
/* @__PURE__ */ jsx("div", { className: "relative flex h-full flex-col justify-end p-12", children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
538
|
+
/* @__PURE__ */ jsx("div", { className: "relative z-20 flex h-full flex-col justify-end p-12", children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
539
|
+
/* @__PURE__ */ jsx(AmbassadorBubbles, { ambassadors: loginAmbassadors, label: loginAmbassadorsLabel }),
|
|
286
540
|
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-sidebar-muted", children: appName }),
|
|
287
541
|
/* @__PURE__ */ jsx("h2", { className: "text-3xl font-bold text-sidebar-foreground", children: tagline ?? `Welcome to ${appName}` }),
|
|
288
542
|
description && /* @__PURE__ */ jsx("p", { className: "max-w-md text-sm leading-relaxed text-sidebar-muted", children: description })
|
|
@@ -333,15 +587,9 @@ function AuthCallbackPage({ onSuccess, onError }) {
|
|
|
333
587
|
] }) });
|
|
334
588
|
}
|
|
335
589
|
function ResetPasswordPage({ onSuccess }) {
|
|
336
|
-
return /* @__PURE__ */ jsx(
|
|
337
|
-
/* @__PURE__ */ jsxs("div", { className: "mb-6", children: [
|
|
338
|
-
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold text-foreground", children: "Update password" }),
|
|
339
|
-
/* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "Choose a new password for your account." })
|
|
340
|
-
] }),
|
|
341
|
-
/* @__PURE__ */ jsx(ResetPasswordForm, { onSuccess })
|
|
342
|
-
] }) });
|
|
590
|
+
return /* @__PURE__ */ jsx(SetPasswordPage, { reason: "recovery", onSuccess });
|
|
343
591
|
}
|
|
344
592
|
|
|
345
|
-
export { AuthCallbackPage, AuthGate, ForgotPasswordForm, LoginForm, LoginPage, OAuthButtons, ResetPasswordForm, ResetPasswordPage, SignupForm, createAuthPlugin, createAuthRuntime, resolveAuthAdapter };
|
|
593
|
+
export { AmbassadorBubbles, AuthCallbackPage, AuthGate, ForgotPasswordForm, LoginForm, LoginPage, OAuthButtons, ResetPasswordForm, ResetPasswordPage, SetPasswordPage, SignupForm, createAuthPlugin, createAuthRuntime, resolveAuthAdapter, usePasswordSetupGate };
|
|
346
594
|
//# sourceMappingURL=index.js.map
|
|
347
595
|
//# sourceMappingURL=index.js.map
|