@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.
@@ -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
  }
@@ -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;CAClD;AAED,wBAAgB,SAAS,CAAC,EAAE,SAAS,EAAE,gBAAgB,EAAE,SAAS,EAAE,cAAc,EAAE,EAAE,cAAc,qBA0CnG;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;CAC3B;AAED,wBAAgB,kBAAkB,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,uBAAuB,qBAqChG;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB;AAED,wBAAgB,iBAAiB,CAAC,EAAE,SAAS,EAAE,EAAE,sBAAsB,qBA4CtE"}
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
@@ -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,GACb,MAAM,eAAe,CAAA;AACtB,YAAY,EACV,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,UAAU,EACV,YAAY,GACb,MAAM,SAAS,CAAA;AAChB,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,IAAI,aAAa,EAAE,MAAM,eAAe,CAAA"}
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
- resetPasswordUrl: options.supabase?.resetPasswordUrl ?? absoluteUrl(options.routes?.resetPassword ?? "/auth/reset-password")
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
- resetPassword: options.routes?.resetPassword ?? "/auth/reset-password",
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({ onSuccess, onForgotPassword, showOAuth, oauthProviders }) {
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("input", { className: fieldClass(), type: "email", autoComplete: "username", required: true, value: email, onChange: (e) => setEmail(e.target.value), disabled })
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({ redirectTo, onSent, onBackToLogin }) {
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: "Email" }),
188
- /* @__PURE__ */ jsx("input", { className: fieldClass(), type: "email", autoComplete: "username", required: true, value: email, onChange: (e) => setEmail(e.target.value), disabled })
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: "Password reset instructions sent." }),
192
- /* @__PURE__ */ jsx("button", { className: buttonClass(), type: "submit", disabled, children: disabled ? "Sending..." : "Send reset link" }),
193
- onBackToLogin && /* @__PURE__ */ jsx("button", { type: "button", className: buttonClass("ghost"), onClick: onBackToLogin, children: "Back to login" })
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(ForgotPasswordForm, { redirectTo: resetPasswordUrl, onBackToLogin: () => setView("login") });
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("div", { className: "flex min-h-screen items-center justify-center bg-background p-4", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-md rounded-2xl border bg-card p-8 shadow-xl", children: [
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