@ollaid/native-sso 2.7.8 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Version réécrite from scratch pour éviter les états qui bloquent le bouton Valider.
5
5
  *
6
- * @version 2.7.0
6
+ * @version 2.7.9
7
7
  */
8
8
  export interface AvatarCropModalProps {
9
9
  open: boolean;
@@ -2,7 +2,7 @@
2
2
  * DebugPanel — Panneau de debug flottant pour @ollaid/native-sso
3
3
  * Affiche l'historique des appels API en temps réel (style terminal)
4
4
  * N'apparaît que quand debug=true
5
- * @version 2.7.0
5
+ * @version 2.7.9
6
6
  */
7
7
  export type DebugOnboardingPreset = 'current' | 'photo' | 'phone' | 'email' | 'all';
8
8
  interface DebugPanelProps {
@@ -11,7 +11,8 @@ interface DebugPanelProps {
11
11
  onOpenLogin?: () => void;
12
12
  onOpenSignup?: () => void;
13
13
  onOpenOnboarding?: (preset: DebugOnboardingPreset) => void;
14
+ onOpenPassword?: () => void;
14
15
  onResetProfilePrompt?: () => void;
15
16
  }
16
- export declare function DebugPanel({ saasApiUrl, iamApiUrl, onOpenLogin, onOpenSignup, onOpenOnboarding, onResetProfilePrompt }: DebugPanelProps): import("react/jsx-runtime").JSX.Element;
17
+ export declare function DebugPanel({ saasApiUrl, iamApiUrl, onOpenLogin, onOpenSignup, onOpenOnboarding, onOpenPassword, onResetProfilePrompt }: DebugPanelProps): import("react/jsx-runtime").JSX.Element;
17
18
  export default DebugPanel;
@@ -2,7 +2,7 @@
2
2
  * Login Modal for @ollaid/native-sso
3
3
  * Complete login flow aligned with Native SSO design
4
4
  *
5
- * @version 2.7.8
5
+ * @version 2.7.9
6
6
  */
7
7
  import type { UserInfos } from '../types/native';
8
8
  export interface LoginModalProps {
@@ -15,7 +15,7 @@ export interface LoginModalProps {
15
15
  logoUrl?: string;
16
16
  loading?: boolean;
17
17
  showSwitchToSignup?: boolean;
18
- /** Type de compte par défaut à persister dans localStorage */
18
+ /** Type de compte par défaut à persister dans le storage du package */
19
19
  defaultAccountType?: 'user' | 'client';
20
20
  /** Pre-fill phone number and go directly to phone-input step */
21
21
  initialPhone?: string;
@@ -2,7 +2,7 @@
2
2
  * NativeSSOPage — Page autonome complète pour @ollaid/native-sso
3
3
  * Design aligné sur le parcours Native SSO (fond primary, card blanche, ShieldCheck branding)
4
4
  *
5
- * @version 2.7.8
5
+ * @version 2.7.9
6
6
  */
7
7
  import type { UserInfos } from '../types/native';
8
8
  import type { NativeStorageAdapter } from '../services/api';
@@ -3,7 +3,7 @@
3
3
  * Mode `missing` : champs absents uniquement
4
4
  * Mode `edit` : édition complète du profil depuis le SaaS
5
5
  *
6
- * @version 2.7.8
6
+ * @version 2.7.9
7
7
  */
8
8
  import type { NativeUser, UserInfos } from '../types/native';
9
9
  export interface OnboardingModalProps {
@@ -3,7 +3,7 @@
3
3
  * Flow: email → method-choice → OTP → new password → success
4
4
  * Design aligned with web SSO
5
5
  *
6
- * @version 2.7.0
6
+ * @version 2.7.9
7
7
  */
8
8
  export interface PasswordRecoveryModalProps {
9
9
  open: boolean;
@@ -0,0 +1,12 @@
1
+ interface PasswordRedirectModalProps {
2
+ open: boolean;
3
+ onOpenChange: (open: boolean) => void;
4
+ saasApiUrl?: string;
5
+ /**
6
+ * @deprecated Gardé pour compatibilité ascendante.
7
+ * Préférer `saasApiUrl` car le flux mot de passe passe désormais par le backend SaaS.
8
+ */
9
+ iamApiUrl?: string;
10
+ }
11
+ declare const PasswordRedirectModal: ({ open, onOpenChange, saasApiUrl, iamApiUrl }: PasswordRedirectModalProps) => import("react/jsx-runtime").JSX.Element;
12
+ export default PasswordRedirectModal;
@@ -2,7 +2,7 @@
2
2
  * Signup Modal for @ollaid/native-sso — Design aligned with web SSO
3
3
  * Full signup flow: intro → account-type → info → OTP → password → confirm → success
4
4
  *
5
- * @version 2.7.8
5
+ * @version 2.7.9
6
6
  */
7
7
  import type { UserInfos } from '../types/native';
8
8
  export interface SignupModalProps {
@@ -13,7 +13,7 @@ export interface SignupModalProps {
13
13
  saasApiUrl: string;
14
14
  iamApiUrl: string;
15
15
  logoUrl?: string;
16
- /** Type de compte par défaut à persister dans localStorage */
16
+ /** Type de compte par défaut à persister dans le storage du package */
17
17
  defaultAccountType?: 'user' | 'client';
18
18
  /** Called when conflict resolution wants to switch to login with a pre-filled phone */
19
19
  onSwitchToLoginWithPhone?: (phone: string) => void;
@@ -3,7 +3,7 @@
3
3
  * Lightweight replacements for shadcn/ui components + inline SVG icons
4
4
  * No external dependencies required
5
5
  *
6
- * @version 2.7.0
6
+ * @version 2.7.9
7
7
  */
8
8
  import React from 'react';
9
9
  export declare function IconShieldCheck(props: React.SVGProps<SVGSVGElement>): import("react/jsx-runtime").JSX.Element;
@@ -22,7 +22,7 @@
22
22
  * };
23
23
  * ```
24
24
  *
25
- * @version 2.7.0
25
+ * @version 2.7.9
26
26
  */
27
27
  export interface UseLogoutOptions {
28
28
  /** Callback appelé après une déconnexion réussie (redirection, toast, etc.) */
@@ -2,7 +2,7 @@
2
2
  * Hook de récupération de mot de passe v1.0
3
3
  * Architecture Frontend-First avec appels directs à l'IAM
4
4
  *
5
- * @version 2.7.0
5
+ * @version 2.7.9
6
6
  */
7
7
  export interface UseMobilePasswordOptions {
8
8
  saasApiUrl: string;
@@ -2,7 +2,7 @@
2
2
  * Hook d'inscription Mobile SSO v1.0
3
3
  * Gère le flow: init → verify-otp → complete
4
4
  *
5
- * @version 2.7.0
5
+ * @version 2.7.9
6
6
  */
7
7
  import type { MobileRegistrationFormData, AccountType } from '../types/mobile';
8
8
  interface RegistrationConflict {
@@ -2,10 +2,10 @@
2
2
  * Hook d'authentification Native SSO v1.0
3
3
  * Architecture Frontend-First avec appels directs à l'IAM
4
4
  *
5
- * @version 2.7.0
5
+ * @version 2.7.9
6
6
  */
7
7
  import { type NativeStorageAdapter } from '../services/api';
8
- import type { NativeAuthStatus, NativeExchangeResponse, AccountType } from '../types/native';
8
+ import type { NativeAuthStatus, NativeExchangeResponse, AccountType, NativeUser } from '../types/native';
9
9
  export interface UseNativeAuthOptions {
10
10
  /** URL du Backend SaaS */
11
11
  saasApiUrl: string;
@@ -27,7 +27,7 @@ export declare function useNativeAuth(options: UseNativeAuthOptions): {
27
27
  credentialsLoaded: boolean;
28
28
  processToken: string | null;
29
29
  status: NativeAuthStatus | null;
30
- user: import("..").NativeUser | null;
30
+ user: NativeUser | null;
31
31
  application: {
32
32
  id: number;
33
33
  name: string;
@@ -6,11 +6,11 @@
6
6
  *
7
7
  * - Premier check 60s après login
8
8
  * - Checks suivants toutes les 2 min
9
- * - Si status === 'connected' → met à jour user_infos en localStorage
9
+ * - Si status === 'connected' → met à jour user_infos via le storage du package
10
10
  * - Si 401 → révoque l'IAM (POST /iam/disconnect) + nettoie le frontend
11
11
  * - Ne déconnecte PAS si offline ou serveur inaccessible
12
12
  *
13
- * @version 2.7.0
13
+ * @version 2.7.9
14
14
  */
15
15
  import type { UserInfos } from '../types/native';
16
16
  export interface UseTokenHealthCheckOptions {
package/dist/index.cjs CHANGED
@@ -8890,6 +8890,25 @@ function useTokenHealthCheck(options) {
8890
8890
  };
8891
8891
  }, [enabled, saasApiUrl, performCheck, debug]);
8892
8892
  }
8893
+ function normalizeNativeUser(user) {
8894
+ if (!user) return null;
8895
+ const input = user;
8896
+ return {
8897
+ reference: input.reference ?? input.iam_reference ?? input.alias_reference ?? "",
8898
+ name: input.name ?? "",
8899
+ email: input.email ?? void 0,
8900
+ phone: input.phone,
8901
+ ccphone: input.ccphone,
8902
+ image_url: input.image_url ?? input.image,
8903
+ account_type: input.account_type,
8904
+ town: input.town,
8905
+ country: input.country,
8906
+ address: input.address,
8907
+ auth_2fa: input.auth_2fa,
8908
+ alias_reference: input.alias_reference,
8909
+ iam_reference: input.iam_reference
8910
+ };
8911
+ }
8893
8912
  function saveSession(exchangeResult, accountType) {
8894
8913
  var _a, _b;
8895
8914
  const storage = getNativeStorage();
@@ -9006,7 +9025,8 @@ function useNativeAuth(options) {
9006
9025
  if (storedRaw) {
9007
9026
  try {
9008
9027
  const stored = JSON.parse(storedRaw);
9009
- const merged = { ...stored, ...userInfos };
9028
+ const merged = normalizeNativeUser({ ...stored, ...userInfos });
9029
+ if (!merged) return;
9010
9030
  getNativeStorage().setItem(STORAGE.USER, JSON.stringify(merged));
9011
9031
  setState((prev) => ({ ...prev, user: merged }));
9012
9032
  } catch {
@@ -9029,13 +9049,10 @@ function useNativeAuth(options) {
9029
9049
  }
9030
9050
  const res = await nativeAuthService.refresh();
9031
9051
  if (res.success) {
9032
- const storedUser = getNativeStorage().getItem(STORAGE.USER);
9033
- if (storedUser) {
9034
- try {
9035
- const user = JSON.parse(storedUser);
9036
- setState((prev) => ({ ...prev, user, status: "completed" }));
9037
- } catch {
9038
- }
9052
+ const snapshot = getSsoSessionSnapshot();
9053
+ const user = normalizeNativeUser(snapshot.user);
9054
+ if (user) {
9055
+ setState((prev) => ({ ...prev, user, status: "completed" }));
9039
9056
  }
9040
9057
  return "recovered";
9041
9058
  }
@@ -9074,16 +9091,10 @@ function useNativeAuth(options) {
9074
9091
  return () => clearTimeout(t);
9075
9092
  }, [state.status, state.user, tryRefreshSession]);
9076
9093
  react.useEffect(() => {
9077
- const storage2 = getNativeStorage();
9078
- const storedToken = storage2.getItem(STORAGE.AUTH_TOKEN) || storage2.getItem(STORAGE.TOKEN);
9079
- const storedUser = storage2.getItem(STORAGE.USER);
9080
- if (storedToken && storedUser) {
9081
- try {
9082
- const user = JSON.parse(storedUser);
9083
- setState((prev) => ({ ...prev, user, status: "completed" }));
9084
- } catch {
9085
- clearSession();
9086
- }
9094
+ const snapshot = getSsoSessionSnapshot();
9095
+ const user = normalizeNativeUser(snapshot.user);
9096
+ if (snapshot.authToken && user) {
9097
+ setState((prev) => ({ ...prev, user, status: "completed" }));
9087
9098
  }
9088
9099
  }, []);
9089
9100
  react.useEffect(() => {
@@ -11243,7 +11254,7 @@ function SuccessOrbit() {
11243
11254
  justifyContent: "center",
11244
11255
  zIndex: 2
11245
11256
  }, children: /* @__PURE__ */ jsxRuntime.jsx(IconLink, { style: { width: "1.7rem", height: "1.7rem", color: C$1.green } }) }),
11246
- orbitIcons.map((Icon, i) => {
11257
+ orbitIcons.map((Icon2, i) => {
11247
11258
  const angle = i * 360 / orbitIcons.length;
11248
11259
  return /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
11249
11260
  position: "absolute",
@@ -11262,7 +11273,7 @@ function SuccessOrbit() {
11262
11273
  display: "flex",
11263
11274
  alignItems: "center",
11264
11275
  justifyContent: "center"
11265
- }, children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { style: { width: "1rem", height: "1rem", color: C$1.gray500 } }) }) }, i);
11276
+ }, children: /* @__PURE__ */ jsxRuntime.jsx(Icon2, { style: { width: "1rem", height: "1rem", color: C$1.gray500 } }) }) }, i);
11266
11277
  })
11267
11278
  ] });
11268
11279
  }
@@ -13300,7 +13311,248 @@ function OnboardingModal({
13300
13311
  renderConfirmDialog()
13301
13312
  ] });
13302
13313
  }
13303
- function DebugPanel({ saasApiUrl, iamApiUrl, onOpenLogin, onOpenSignup, onOpenOnboarding, onResetProfilePrompt }) {
13314
+ /**
13315
+ * @license lucide-react v0.462.0 - ISC
13316
+ *
13317
+ * This source code is licensed under the ISC license.
13318
+ * See the LICENSE file in the root directory of this source tree.
13319
+ */
13320
+ const toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
13321
+ const mergeClasses = (...classes) => classes.filter((className, index, array) => {
13322
+ return Boolean(className) && className.trim() !== "" && array.indexOf(className) === index;
13323
+ }).join(" ").trim();
13324
+ /**
13325
+ * @license lucide-react v0.462.0 - ISC
13326
+ *
13327
+ * This source code is licensed under the ISC license.
13328
+ * See the LICENSE file in the root directory of this source tree.
13329
+ */
13330
+ var defaultAttributes = {
13331
+ xmlns: "http://www.w3.org/2000/svg",
13332
+ width: 24,
13333
+ height: 24,
13334
+ viewBox: "0 0 24 24",
13335
+ fill: "none",
13336
+ stroke: "currentColor",
13337
+ strokeWidth: 2,
13338
+ strokeLinecap: "round",
13339
+ strokeLinejoin: "round"
13340
+ };
13341
+ /**
13342
+ * @license lucide-react v0.462.0 - ISC
13343
+ *
13344
+ * This source code is licensed under the ISC license.
13345
+ * See the LICENSE file in the root directory of this source tree.
13346
+ */
13347
+ const Icon = react.forwardRef(
13348
+ ({
13349
+ color = "currentColor",
13350
+ size = 24,
13351
+ strokeWidth = 2,
13352
+ absoluteStrokeWidth,
13353
+ className = "",
13354
+ children,
13355
+ iconNode,
13356
+ ...rest
13357
+ }, ref) => {
13358
+ return react.createElement(
13359
+ "svg",
13360
+ {
13361
+ ref,
13362
+ ...defaultAttributes,
13363
+ width: size,
13364
+ height: size,
13365
+ stroke: color,
13366
+ strokeWidth: absoluteStrokeWidth ? Number(strokeWidth) * 24 / Number(size) : strokeWidth,
13367
+ className: mergeClasses("lucide", className),
13368
+ ...rest
13369
+ },
13370
+ [
13371
+ ...iconNode.map(([tag, attrs]) => react.createElement(tag, attrs)),
13372
+ ...Array.isArray(children) ? children : [children]
13373
+ ]
13374
+ );
13375
+ }
13376
+ );
13377
+ /**
13378
+ * @license lucide-react v0.462.0 - ISC
13379
+ *
13380
+ * This source code is licensed under the ISC license.
13381
+ * See the LICENSE file in the root directory of this source tree.
13382
+ */
13383
+ const createLucideIcon = (iconName, iconNode) => {
13384
+ const Component = react.forwardRef(
13385
+ ({ className, ...props }, ref) => react.createElement(Icon, {
13386
+ ref,
13387
+ iconNode,
13388
+ className: mergeClasses(`lucide-${toKebabCase(iconName)}`, className),
13389
+ ...props
13390
+ })
13391
+ );
13392
+ Component.displayName = `${iconName}`;
13393
+ return Component;
13394
+ };
13395
+ /**
13396
+ * @license lucide-react v0.462.0 - ISC
13397
+ *
13398
+ * This source code is licensed under the ISC license.
13399
+ * See the LICENSE file in the root directory of this source tree.
13400
+ */
13401
+ const ExternalLink = createLucideIcon("ExternalLink", [
13402
+ ["path", { d: "M15 3h6v6", key: "1q9fwt" }],
13403
+ ["path", { d: "M10 14 21 3", key: "gplh6r" }],
13404
+ ["path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6", key: "a6xqqp" }]
13405
+ ]);
13406
+ /**
13407
+ * @license lucide-react v0.462.0 - ISC
13408
+ *
13409
+ * This source code is licensed under the ISC license.
13410
+ * See the LICENSE file in the root directory of this source tree.
13411
+ */
13412
+ const LoaderCircle = createLucideIcon("LoaderCircle", [
13413
+ ["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]
13414
+ ]);
13415
+ /**
13416
+ * @license lucide-react v0.462.0 - ISC
13417
+ *
13418
+ * This source code is licensed under the ISC license.
13419
+ * See the LICENSE file in the root directory of this source tree.
13420
+ */
13421
+ const LockKeyhole = createLucideIcon("LockKeyhole", [
13422
+ ["circle", { cx: "12", cy: "16", r: "1", key: "1au0dj" }],
13423
+ ["rect", { x: "3", y: "10", width: "18", height: "12", rx: "2", key: "6s8ecr" }],
13424
+ ["path", { d: "M7 10V7a5 5 0 0 1 10 0v3", key: "1pqi11" }]
13425
+ ]);
13426
+ /**
13427
+ * @license lucide-react v0.462.0 - ISC
13428
+ *
13429
+ * This source code is licensed under the ISC license.
13430
+ * See the LICENSE file in the root directory of this source tree.
13431
+ */
13432
+ const ShieldCheck = createLucideIcon("ShieldCheck", [
13433
+ [
13434
+ "path",
13435
+ {
13436
+ d: "M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",
13437
+ key: "oel41y"
13438
+ }
13439
+ ],
13440
+ ["path", { d: "m9 12 2 2 4-4", key: "dzmm74" }]
13441
+ ]);
13442
+ const PasswordRedirectModal = ({ open, onOpenChange, saasApiUrl, iamApiUrl }) => {
13443
+ const [confirmOpen, setConfirmOpen] = react.useState(false);
13444
+ const [loading, setLoading] = react.useState(false);
13445
+ const [errorMessage, setErrorMessage] = react.useState(null);
13446
+ const apiBaseUrl = react.useMemo(() => {
13447
+ const source = saasApiUrl || iamApiUrl;
13448
+ if (!source) {
13449
+ return "";
13450
+ }
13451
+ const normalized = source.replace(/\/$/, "");
13452
+ return normalized.endsWith("/api") ? normalized : `${normalized}/api`;
13453
+ }, [saasApiUrl, iamApiUrl]);
13454
+ const buildUrl = (redirectUrl, magicToken) => {
13455
+ if (redirectUrl) {
13456
+ return redirectUrl;
13457
+ }
13458
+ if (magicToken) {
13459
+ const fallbackUrl = new URL("/auth/auto-connect", "https://iam.ollaid.com");
13460
+ fallbackUrl.searchParams.set("magic_token", magicToken);
13461
+ return fallbackUrl.toString();
13462
+ }
13463
+ return "";
13464
+ };
13465
+ const handleRedirect = async () => {
13466
+ if (loading) return;
13467
+ setLoading(true);
13468
+ setErrorMessage(null);
13469
+ try {
13470
+ const authToken = getAuthToken();
13471
+ const appAccessTokenRef = getNativeStorage().getItem(STORAGE.APP_ACCESS_TOKEN_REF);
13472
+ if (!authToken && !appAccessTokenRef) {
13473
+ throw new Error("Session Native SSO introuvable");
13474
+ }
13475
+ if (!apiBaseUrl) {
13476
+ throw new Error("saasApiUrl non configurée");
13477
+ }
13478
+ const result = await fetchWithTimeout(
13479
+ `${apiBaseUrl}/native/password-link`,
13480
+ {
13481
+ method: "POST",
13482
+ headers: getHeaders(authToken || void 0, true)
13483
+ },
13484
+ 2e4
13485
+ );
13486
+ if (!result.success) {
13487
+ throw new Error(result.message || "Impossible de générer le lien");
13488
+ }
13489
+ const redirectUrl = buildUrl(
13490
+ typeof result.redirect_url === "string" && result.redirect_url.length > 0 ? result.redirect_url : typeof result.sso_url === "string" && result.sso_url.length > 0 ? result.sso_url : "",
13491
+ result.magic_token
13492
+ );
13493
+ if (!redirectUrl) {
13494
+ throw new Error("URL de redirection manquante");
13495
+ }
13496
+ window.open(redirectUrl, "_blank", "noopener,noreferrer");
13497
+ onOpenChange(false);
13498
+ setConfirmOpen(false);
13499
+ } catch (error) {
13500
+ const message = error instanceof ApiError ? error.message : (error == null ? void 0 : error.message) || "Impossible de lancer le flux de mot de passe";
13501
+ setErrorMessage(message);
13502
+ } finally {
13503
+ setLoading(false);
13504
+ }
13505
+ };
13506
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
13507
+ /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { style: { maxWidth: "28rem", borderRadius: "16px", background: "#fff" }, children: [
13508
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
13509
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { margin: "0 auto 12px", width: 56, height: 56, borderRadius: "50%", background: "rgba(232, 67, 10, 0.1)", display: "flex", alignItems: "center", justifyContent: "center", color: "#e8430a" }, children: /* @__PURE__ */ jsxRuntime.jsx(LockKeyhole, { size: 28 }) }),
13510
+ /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { className: "text-center", children: "Mot de passe géré par OLLAID SSO" }),
13511
+ /* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { className: "text-center", children: "Ce bouton sert à tester la redirection vers IAM et l'ouverture du modal de changement de mot de passe." })
13512
+ ] }),
13513
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { border: "1px solid #e5e7eb", borderRadius: 12, padding: 16, background: "#f8fafc", color: "#475569", fontSize: 13, display: "grid", gap: 8 }, children: [
13514
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 8, alignItems: "flex-start" }, children: [
13515
+ /* @__PURE__ */ jsxRuntime.jsx(ShieldCheck, { size: 16, color: "#e8430a" }),
13516
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Le SaaS agit comme relais. Le backend SaaS appelle IAM côté serveur, puis renvoie l'URL de redirection." })
13517
+ ] }),
13518
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 8, alignItems: "flex-start" }, children: [
13519
+ /* @__PURE__ */ jsxRuntime.jsx(ExternalLink, { size: 16, color: "#e8430a" }),
13520
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Une fenêtre IAM va s'ouvrir avec auto-connexion temporaire, sans appel direct du navigateur vers IAM." })
13521
+ ] })
13522
+ ] }),
13523
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogFooter, { style: { gap: 12 }, children: [
13524
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), style: { flex: 1 }, disabled: loading, children: "Fermer" }),
13525
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: () => setConfirmOpen(true), disabled: loading, style: { flex: 1 }, children: loading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
13526
+ /* @__PURE__ */ jsxRuntime.jsx(LoaderCircle, { size: 16, style: { marginRight: 8, animation: "spin 1s linear infinite" } }),
13527
+ "Préparation..."
13528
+ ] }) : "Changer mon mot de passe" })
13529
+ ] })
13530
+ ] }) }),
13531
+ /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: confirmOpen, onOpenChange: (nextOpen) => {
13532
+ if (!loading) {
13533
+ setConfirmOpen(nextOpen);
13534
+ }
13535
+ }, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { style: { maxWidth: "26rem", borderRadius: "16px", background: "#fff" }, children: [
13536
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
13537
+ /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { className: "text-center", children: "Êtes-vous sûr de rediriger vers le SSO ?" }),
13538
+ /* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { className: "text-center", children: "Cette action ouvre IAM dans un nouvel onglet et prépare l'auto-connexion pour tester le changement de mot de passe." })
13539
+ ] }),
13540
+ errorMessage && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { border: "1px solid #fecaca", background: "#fef2f2", color: "#b91c1c", borderRadius: 12, padding: 12, fontSize: 13 }, children: errorMessage }),
13541
+ loading && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 10, padding: "8px 0 4px" }, children: [
13542
+ /* @__PURE__ */ jsxRuntime.jsx(LoaderCircle, { size: 26, style: { animation: "spin 1s linear infinite", color: "#e8430a" } }),
13543
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 13, color: "#475569", textAlign: "center" }, children: "Création de la session en cours..." })
13544
+ ] }),
13545
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogFooter, { style: { gap: 12 }, children: [
13546
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", onClick: () => setConfirmOpen(false), style: { flex: 1 }, disabled: loading, children: "Annuler" }),
13547
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: handleRedirect, style: { flex: 1 }, disabled: loading, children: loading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
13548
+ /* @__PURE__ */ jsxRuntime.jsx(LoaderCircle, { size: 16, style: { marginRight: 8, animation: "spin 1s linear infinite" } }),
13549
+ "Confirmer..."
13550
+ ] }) : "Confirmer" })
13551
+ ] })
13552
+ ] }) })
13553
+ ] });
13554
+ };
13555
+ function DebugPanel({ saasApiUrl, iamApiUrl, onOpenLogin, onOpenSignup, onOpenOnboarding, onOpenPassword, onResetProfilePrompt }) {
13304
13556
  const [logs, setLogs] = react.useState([]);
13305
13557
  const [expanded, setExpanded] = react.useState(true);
13306
13558
  const [selectedLog, setSelectedLog] = react.useState(null);
@@ -13440,6 +13692,18 @@ function DebugPanel({ saasApiUrl, iamApiUrl, onOpenLogin, onOpenSignup, onOpenOn
13440
13692
  children: "Infos profile"
13441
13693
  }
13442
13694
  ),
13695
+ /* @__PURE__ */ jsxRuntime.jsx(
13696
+ "button",
13697
+ {
13698
+ onClick: (e) => {
13699
+ e.stopPropagation();
13700
+ onOpenPassword == null ? void 0 : onOpenPassword();
13701
+ },
13702
+ disabled: !onOpenPassword,
13703
+ style: { background: "#334155", color: "#e2e8f0", border: "none", borderRadius: "4px", padding: "2px 8px", cursor: onOpenPassword ? "pointer" : "not-allowed", fontSize: "11px", opacity: onOpenPassword ? 1 : 0.5 },
13704
+ children: "Mot de passe"
13705
+ }
13706
+ ),
13443
13707
  /* @__PURE__ */ jsxRuntime.jsx(
13444
13708
  "button",
13445
13709
  {
@@ -13633,6 +13897,7 @@ function NativeSSOPage({
13633
13897
  const [showOnboarding, setShowOnboarding] = react.useState(false);
13634
13898
  const [pendingSession, setPendingSession] = react.useState(null);
13635
13899
  const [debugOnboardingState, setDebugOnboardingState] = react.useState(null);
13900
+ const [passwordRedirectOpen, setPasswordRedirectOpen] = react.useState(false);
13636
13901
  const [redirectingTarget, setRedirectingTarget] = react.useState(null);
13637
13902
  const [redirectingReason, setRedirectingReason] = react.useState(null);
13638
13903
  const [session, setSession] = react.useState(() => {
@@ -14005,6 +14270,9 @@ function NativeSSOPage({
14005
14270
  setShowOnboarding(true);
14006
14271
  }
14007
14272
  }, [session, clearOnboardingTimers]);
14273
+ const openDebugPassword = react.useCallback(() => {
14274
+ setPasswordRedirectOpen(true);
14275
+ }, []);
14008
14276
  react.useEffect(() => {
14009
14277
  syncProfilePrompt(session);
14010
14278
  return () => {
@@ -14152,8 +14420,18 @@ function NativeSSOPage({
14152
14420
  onOpenLogin: openDebugLogin,
14153
14421
  onOpenSignup: openDebugSignup,
14154
14422
  onOpenOnboarding: openDebugOnboarding,
14423
+ onOpenPassword: openDebugPassword,
14155
14424
  onResetProfilePrompt: resetDebugProfilePrompt
14156
14425
  }
14426
+ ),
14427
+ /* @__PURE__ */ jsxRuntime.jsx(
14428
+ PasswordRedirectModal,
14429
+ {
14430
+ open: passwordRedirectOpen,
14431
+ onOpenChange: setPasswordRedirectOpen,
14432
+ saasApiUrl,
14433
+ iamApiUrl
14434
+ }
14157
14435
  )
14158
14436
  ] });
14159
14437
  }
@@ -14233,8 +14511,18 @@ function NativeSSOPage({
14233
14511
  onOpenLogin: openDebugLogin,
14234
14512
  onOpenSignup: openDebugSignup,
14235
14513
  onOpenOnboarding: openDebugOnboarding,
14514
+ onOpenPassword: openDebugPassword,
14236
14515
  onResetProfilePrompt: resetDebugProfilePrompt
14237
14516
  }
14517
+ ),
14518
+ /* @__PURE__ */ jsxRuntime.jsx(
14519
+ PasswordRedirectModal,
14520
+ {
14521
+ open: passwordRedirectOpen,
14522
+ onOpenChange: setPasswordRedirectOpen,
14523
+ saasApiUrl,
14524
+ iamApiUrl
14525
+ }
14238
14526
  )
14239
14527
  ] });
14240
14528
  }