@ollaid/native-sso 1.0.7 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -125,8 +125,13 @@ function DialogContent({ children, className = "" }) {
125
125
  /* @__PURE__ */ jsx(
126
126
  "div",
127
127
  {
128
- style: { position: "fixed", inset: 0, backgroundColor: "rgba(0,0,0,0.5)" },
129
- onClick: () => onOpenChange(false)
128
+ style: {
129
+ position: "fixed",
130
+ inset: 0,
131
+ backgroundColor: "rgba(0,0,0,0.5)",
132
+ backdropFilter: "blur(4px)",
133
+ animation: "ollaid-overlay-in 0.25s ease-out"
134
+ }
130
135
  }
131
136
  ),
132
137
  /* @__PURE__ */ jsxs(
@@ -139,19 +144,21 @@ function DialogContent({ children, className = "" }) {
139
144
  width: "100%",
140
145
  maxWidth: "28rem",
141
146
  margin: "1rem",
142
- padding: "1.5rem",
147
+ padding: "1rem",
143
148
  borderRadius: "0.75rem",
144
149
  backgroundColor: "white",
145
150
  boxShadow: "0 25px 50px -12px rgba(0,0,0,0.25)",
146
151
  maxHeight: "90vh",
147
- overflowY: "auto"
152
+ display: "flex",
153
+ flexDirection: "column",
154
+ animation: "ollaid-modal-in 0.3s ease-out"
148
155
  },
149
156
  children: [
150
157
  /* @__PURE__ */ jsx(
151
158
  "button",
152
159
  {
153
160
  onClick: () => onOpenChange(false),
154
- style: { position: "absolute", right: "1rem", top: "1rem", background: "none", border: "none", cursor: "pointer", fontSize: "1.25rem", color: "#9ca3af", lineHeight: 1 },
161
+ style: { position: "absolute", right: "0.75rem", top: "0.75rem", background: "none", border: "none", cursor: "pointer", fontSize: "1.25rem", color: "#9ca3af", lineHeight: 1, zIndex: 2 },
155
162
  "aria-label": "Close",
156
163
  children: "✕"
157
164
  }
@@ -162,8 +169,14 @@ function DialogContent({ children, className = "" }) {
162
169
  )
163
170
  ] });
164
171
  }
172
+ function DialogBody({ children, className = "", style }) {
173
+ return /* @__PURE__ */ jsx("div", { className, style: { flex: 1, overflowY: "auto", paddingBottom: "0.5rem", minHeight: 0, ...style }, children });
174
+ }
175
+ function DialogFooter({ children, className = "", style }) {
176
+ return /* @__PURE__ */ jsx("div", { className, style: { flexShrink: 0, paddingTop: "0.75rem", borderTop: "1px solid #e5e7eb", display: "flex", flexDirection: "column", gap: "0.5rem", ...style }, children });
177
+ }
165
178
  function DialogHeader({ children, className = "", style }) {
166
- return /* @__PURE__ */ jsx("div", { className, style: { marginBottom: "0.5rem", ...style }, children });
179
+ return /* @__PURE__ */ jsx("div", { className, style: { marginBottom: "0.5rem", flexShrink: 0, ...style }, children });
167
180
  }
168
181
  function DialogTitle({ children, className = "" }) {
169
182
  return /* @__PURE__ */ jsx("h2", { className, style: { fontSize: "1.25rem", fontWeight: 600, color: "#111827" }, children });
@@ -263,7 +276,7 @@ if (typeof document !== "undefined") {
263
276
  if (!document.getElementById(styleId)) {
264
277
  const style = document.createElement("style");
265
278
  style.id = styleId;
266
- style.textContent = `@keyframes spin { to { transform: rotate(360deg); } }`;
279
+ style.textContent = `@keyframes spin { to { transform: rotate(360deg); } } @keyframes ollaid-overlay-in { from { opacity: 0; } to { opacity: 1; } } @keyframes ollaid-modal-in { from { opacity: 0; transform: translateY(20px) scale(0.97); } to { opacity: 1; transform: translateY(0) scale(1); } }`;
267
280
  document.head.appendChild(style);
268
281
  }
269
282
  }
@@ -481,7 +494,8 @@ const STORAGE = {
481
494
  TOKEN: "token",
482
495
  USER: "user",
483
496
  ACCOUNT_TYPE: "account_type",
484
- ALIAS_REFERENCE: "alias_reference"
497
+ ALIAS_REFERENCE: "alias_reference",
498
+ APP_ACCESS_TOKEN_REF: "app_access_token_ref"
485
499
  };
486
500
  const setAuthToken = (token) => {
487
501
  if (typeof localStorage !== "undefined") {
@@ -500,8 +514,14 @@ const clearAuthToken = () => {
500
514
  localStorage.removeItem(STORAGE.USER);
501
515
  localStorage.removeItem(STORAGE.ACCOUNT_TYPE);
502
516
  localStorage.removeItem(STORAGE.ALIAS_REFERENCE);
517
+ localStorage.removeItem(STORAGE.APP_ACCESS_TOKEN_REF);
503
518
  }
504
519
  };
520
+ const logout = async () => {
521
+ const { nativeAuthService: nativeAuthService2 } = await Promise.resolve().then(() => nativeAuth);
522
+ const token = getAuthToken();
523
+ return nativeAuthService2.logout(token || void 0);
524
+ };
505
525
  const setAuthUser = (user) => {
506
526
  if (typeof localStorage !== "undefined") {
507
527
  localStorage.setItem(STORAGE.USER, JSON.stringify(user));
@@ -795,7 +815,7 @@ const nativeAuthService = {
795
815
  );
796
816
  },
797
817
  async exchange(callbackToken) {
798
- var _a;
818
+ var _a, _b;
799
819
  const config2 = getNativeAuthConfig();
800
820
  if (!config2.saasApiUrl) {
801
821
  throw new ApiError("saasApiUrl non configurée", "unknown");
@@ -817,9 +837,16 @@ const nativeAuthService = {
817
837
  if (response.user) {
818
838
  setAuthUser(response.user);
819
839
  }
840
+ if (response.app_access_token_ref && typeof localStorage !== "undefined") {
841
+ localStorage.setItem(STORAGE.APP_ACCESS_TOKEN_REF, response.app_access_token_ref);
842
+ }
843
+ const aliasRef = ((_a = response.user) == null ? void 0 : _a.alias_reference) || response.alias_reference;
844
+ if (aliasRef && typeof localStorage !== "undefined") {
845
+ localStorage.setItem(STORAGE.ALIAS_REFERENCE, aliasRef);
846
+ }
820
847
  }
821
848
  if (isDebugMode()) {
822
- console.log("✅ [SaaS] Session établie:", { user: (_a = response.user) == null ? void 0 : _a.name });
849
+ console.log("✅ [SaaS] Session établie:", { user: (_b = response.user) == null ? void 0 : _b.name });
823
850
  }
824
851
  return response;
825
852
  },
@@ -840,7 +867,13 @@ const nativeAuthService = {
840
867
  },
841
868
  1e4
842
869
  );
843
- return { valid: response.valid !== false, user_infos: response.user_infos };
870
+ if (response.status === "connected" && response.user) {
871
+ return { valid: true, user: response.user };
872
+ }
873
+ if (response.success !== false) {
874
+ return { valid: true, user: response.user };
875
+ }
876
+ return { valid: false };
844
877
  } catch (err) {
845
878
  if (err instanceof ApiError && err.statusCode === 401) {
846
879
  return { valid: false };
@@ -850,28 +883,53 @@ const nativeAuthService = {
850
883
  },
851
884
  async logout(token) {
852
885
  const config2 = getNativeAuthConfig();
853
- if (!config2.saasApiUrl) {
854
- throw new ApiError("saasApiUrl non configurée", "unknown");
886
+ const iamToken = typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE.AUTH_TOKEN) || localStorage.getItem(STORAGE.TOKEN) : null;
887
+ const appAccessTokenRef = typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE.APP_ACCESS_TOKEN_REF) : null;
888
+ const promises = [];
889
+ if (config2.saasApiUrl && token) {
890
+ promises.push(
891
+ fetchWithTimeout(
892
+ `${config2.saasApiUrl}/native/logout`,
893
+ {
894
+ method: "POST",
895
+ headers: getHeaders(token, true)
896
+ },
897
+ config2.timeout || 3e4
898
+ ).catch((err) => {
899
+ if (isDebugMode()) {
900
+ console.warn("⚠️ [SaaS] Échec logout (non-bloquant):", err instanceof Error ? err.message : err);
901
+ }
902
+ })
903
+ );
855
904
  }
856
- try {
857
- const response = await fetchWithTimeout(
858
- `${config2.saasApiUrl}/native/logout`,
859
- {
860
- method: "POST",
861
- headers: getHeaders(token, true)
862
- },
863
- config2.timeout || 3e4
905
+ if (config2.iamApiUrl && (iamToken || appAccessTokenRef)) {
906
+ const payload = {};
907
+ if (iamToken) payload.sanctum_token = iamToken;
908
+ if (appAccessTokenRef) payload.app_access_token_ref = appAccessTokenRef;
909
+ promises.push(
910
+ fetchWithTimeout(
911
+ `${config2.iamApiUrl}/iam/disconnect`,
912
+ {
913
+ method: "POST",
914
+ headers: { "Content-Type": "application/json", "Accept": "application/json" },
915
+ body: JSON.stringify(payload)
916
+ },
917
+ 5e3
918
+ ).catch((err) => {
919
+ if (isDebugMode()) {
920
+ console.warn("⚠️ [IAM] Échec disconnect (non-bloquant):", err instanceof Error ? err.message : err);
921
+ }
922
+ })
864
923
  );
865
- clearAuthToken();
866
- credentials = null;
867
- credentialsLoadedAt = 0;
868
- return response;
869
- } catch {
870
- clearAuthToken();
871
- credentials = null;
872
- credentialsLoadedAt = 0;
873
- return { success: true };
874
924
  }
925
+ await Promise.allSettled(promises);
926
+ if (isDebugMode()) {
927
+ console.log("✅ [Logout] Double revocation terminée — nettoyage local");
928
+ }
929
+ clearAuthToken();
930
+ credentials = null;
931
+ credentialsLoadedAt = 0;
932
+ return { success: true };
875
933
  },
876
934
  clearCredentials() {
877
935
  credentials = null;
@@ -932,6 +990,10 @@ const nativeAuthService = {
932
990
  return this.init(native_token);
933
991
  }
934
992
  };
993
+ const nativeAuth = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
994
+ __proto__: null,
995
+ nativeAuthService
996
+ }, Symbol.toStringTag, { value: "Module" }));
935
997
  function getIAMHeaders() {
936
998
  const creds = nativeAuthService.getCredentials();
937
999
  if (!creds) {
@@ -939,7 +1001,8 @@ function getIAMHeaders() {
939
1001
  }
940
1002
  return {
941
1003
  "Content-Type": "application/json",
942
- "Accept": "application/json"
1004
+ "Accept": "application/json",
1005
+ "X-IAM-App-Key": creds.appKey
943
1006
  };
944
1007
  }
945
1008
  const mobilePasswordService = {
@@ -1427,7 +1490,7 @@ function PasswordRecoveryModal({ open, onOpenChange, onSuccess, saasApiUrl, iamA
1427
1490
  /* @__PURE__ */ jsx(DialogTitle, { children: "Mot de passe modifié !" }),
1428
1491
  /* @__PURE__ */ jsx(DialogDescription, { children: "Votre mot de passe a été changé avec succès." })
1429
1492
  ] }),
1430
- /* @__PURE__ */ jsx(Button, { onClick: handleBackToLogin, style: { width: "100%", marginTop: "1rem" }, children: "Retour à la connexion" })
1493
+ /* @__PURE__ */ jsx(DialogFooter, { style: { borderTop: "none" }, children: /* @__PURE__ */ jsx(Button, { onClick: handleBackToLogin, style: { width: "100%" }, children: "Retour à la connexion" }) })
1431
1494
  ] }) });
1432
1495
  }
1433
1496
  return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(DialogContent, { children: [
@@ -1447,49 +1510,35 @@ function PasswordRecoveryModal({ open, onOpenChange, onSuccess, saasApiUrl, iamA
1447
1510
  step === "password" && "Définissez votre nouveau mot de passe"
1448
1511
  ] })
1449
1512
  ] }),
1450
- /* @__PURE__ */ jsxs("div", { style: { marginTop: "1rem", display: "flex", flexDirection: "column", gap: "1rem" }, children: [
1513
+ /* @__PURE__ */ jsx(DialogBody, { children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "1rem" }, children: [
1451
1514
  error && /* @__PURE__ */ jsx("div", { style: { padding: "0.75rem", borderRadius: "0.375rem", backgroundColor: C$3.redBg, color: C$3.red, fontSize: "0.875rem" }, children: error }),
1452
- step === "email" && /* @__PURE__ */ jsxs(Fragment, { children: [
1453
- /* @__PURE__ */ jsxs("div", { children: [
1454
- /* @__PURE__ */ jsx(Label, { htmlFor: "recovery-email", children: "Adresse email" }),
1455
- /* @__PURE__ */ jsx(Input, { id: "recovery-email", type: "email", placeholder: "vous@exemple.com", value: email, onChange: (e) => setEmail(e.target.value), disabled: pwLoading })
1456
- ] }),
1457
- /* @__PURE__ */ jsx(Button, { onClick: handleEmailSubmit, disabled: pwLoading, style: { width: "100%" }, children: pwLoading ? /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
1458
- /* @__PURE__ */ jsx(IconLoader2, { style: { width: "1rem", height: "1rem" } }),
1459
- " Vérification..."
1460
- ] }) : "Continuer" }),
1461
- /* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: handleBackToLogin, style: { width: "100%" }, children: "Retour à la connexion" })
1515
+ step === "email" && /* @__PURE__ */ jsxs("div", { children: [
1516
+ /* @__PURE__ */ jsx(Label, { htmlFor: "recovery-email", children: "Adresse email" }),
1517
+ /* @__PURE__ */ jsx(Input, { id: "recovery-email", type: "email", placeholder: "vous@exemple.com", value: email, onChange: (e) => setEmail(e.target.value), disabled: pwLoading })
1462
1518
  ] }),
1463
- step === "method-choice" && /* @__PURE__ */ jsxs(Fragment, { children: [
1464
- /* @__PURE__ */ jsx(RadioGroup, { value: selectedMethod, onValueChange: (v) => setSelectedMethod(v), children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
1465
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.75rem", padding: "1rem", borderRadius: "0.5rem", border: `2px solid ${selectedMethod === "email" ? C$3.primary : C$3.gray200}`, cursor: "pointer" }, onClick: () => setSelectedMethod("email"), children: [
1466
- /* @__PURE__ */ jsx(RadioGroupItem, { value: "email", id: "method-email" }),
1467
- /* @__PURE__ */ jsxs("div", { children: [
1468
- /* @__PURE__ */ jsx("div", { style: { fontWeight: 500 }, children: "Par email" }),
1469
- /* @__PURE__ */ jsx("div", { style: { fontSize: "0.75rem", color: C$3.gray500 }, children: maskedEmail })
1470
- ] })
1471
- ] }),
1472
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.75rem", padding: "1rem", borderRadius: "0.5rem", border: `2px solid ${selectedMethod === "phone" ? C$3.primary : C$3.gray200}`, cursor: "pointer" }, onClick: () => setSelectedMethod("phone"), children: [
1473
- /* @__PURE__ */ jsx(RadioGroupItem, { value: "phone", id: "method-phone" }),
1474
- /* @__PURE__ */ jsxs("div", { children: [
1475
- /* @__PURE__ */ jsx("div", { style: { fontWeight: 500 }, children: "Par SMS" }),
1476
- /* @__PURE__ */ jsx("div", { style: { fontSize: "0.75rem", color: C$3.gray500 }, children: maskedPhone })
1477
- ] })
1519
+ step === "method-choice" && /* @__PURE__ */ jsx(RadioGroup, { value: selectedMethod, onValueChange: (v) => setSelectedMethod(v), children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
1520
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.75rem", padding: "1rem", borderRadius: "0.5rem", border: `2px solid ${selectedMethod === "email" ? C$3.primary : C$3.gray200}`, cursor: "pointer" }, onClick: () => setSelectedMethod("email"), children: [
1521
+ /* @__PURE__ */ jsx(RadioGroupItem, { value: "email", id: "method-email" }),
1522
+ /* @__PURE__ */ jsxs("div", { children: [
1523
+ /* @__PURE__ */ jsx("div", { style: { fontWeight: 500 }, children: "Par email" }),
1524
+ /* @__PURE__ */ jsx("div", { style: { fontSize: "0.75rem", color: C$3.gray500 }, children: maskedEmail })
1478
1525
  ] })
1479
- ] }) }),
1480
- /* @__PURE__ */ jsx(Button, { onClick: handleMethodSubmit, disabled: pwLoading, style: { width: "100%" }, children: pwLoading ? /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
1481
- /* @__PURE__ */ jsx(IconLoader2, { style: { width: "1rem", height: "1rem" } }),
1482
- " Envoi..."
1483
- ] }) : "Envoyer le code" })
1484
- ] }),
1526
+ ] }),
1527
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.75rem", padding: "1rem", borderRadius: "0.5rem", border: `2px solid ${selectedMethod === "phone" ? C$3.primary : C$3.gray200}`, cursor: "pointer" }, onClick: () => setSelectedMethod("phone"), children: [
1528
+ /* @__PURE__ */ jsx(RadioGroupItem, { value: "phone", id: "method-phone" }),
1529
+ /* @__PURE__ */ jsxs("div", { children: [
1530
+ /* @__PURE__ */ jsx("div", { style: { fontWeight: 500 }, children: "Par SMS" }),
1531
+ /* @__PURE__ */ jsx("div", { style: { fontSize: "0.75rem", color: C$3.gray500 }, children: maskedPhone })
1532
+ ] })
1533
+ ] })
1534
+ ] }) }),
1485
1535
  step === "otp" && /* @__PURE__ */ jsxs(Fragment, { children: [
1486
1536
  /* @__PURE__ */ jsx(OTPInput, { value: otp, onChange: setOtp, disabled: pwLoading }),
1487
1537
  /* @__PURE__ */ jsx("div", { style: { textAlign: "center", fontSize: "0.875rem" }, children: resendCooldown > 0 ? /* @__PURE__ */ jsxs("span", { style: { color: C$3.gray500 }, children: [
1488
1538
  "Renvoyer dans ",
1489
1539
  resendCooldown,
1490
1540
  "s"
1491
- ] }) : /* @__PURE__ */ jsx("button", { type: "button", style: { color: C$3.primary, background: "none", border: "none", cursor: "pointer", textDecoration: "underline" }, onClick: handleResendOTP, children: "Code non reçu ? Renvoyer" }) }),
1492
- /* @__PURE__ */ jsx(Button, { onClick: handleOTPSubmit, disabled: otp.length !== 6, style: { width: "100%" }, children: "Vérifier" })
1541
+ ] }) : /* @__PURE__ */ jsx("button", { type: "button", style: { color: C$3.primary, background: "none", border: "none", cursor: "pointer", textDecoration: "underline" }, onClick: handleResendOTP, children: "Code non reçu ? Renvoyer" }) })
1493
1542
  ] }),
1494
1543
  step === "password" && /* @__PURE__ */ jsxs(Fragment, { children: [
1495
1544
  /* @__PURE__ */ jsxs("div", { children: [
@@ -1499,17 +1548,31 @@ function PasswordRecoveryModal({ open, onOpenChange, onSuccess, saasApiUrl, iamA
1499
1548
  /* @__PURE__ */ jsxs("div", { children: [
1500
1549
  /* @__PURE__ */ jsx(Label, { children: "Confirmer le mot de passe" }),
1501
1550
  /* @__PURE__ */ jsx(Input, { type: "password", placeholder: "Retapez votre mot de passe", value: confirmPassword, onChange: (e) => setConfirmPassword(e.target.value), disabled: pwLoading })
1502
- ] }),
1503
- /* @__PURE__ */ jsx(Button, { onClick: handlePasswordSubmit, disabled: pwLoading || !password || !confirmPassword, style: { width: "100%" }, children: pwLoading ? /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
1504
- /* @__PURE__ */ jsx(IconLoader2, { style: { width: "1rem", height: "1rem" } }),
1505
- " Modification..."
1506
- ] }) : "Modifier le mot de passe" })
1551
+ ] })
1507
1552
  ] })
1553
+ ] }) }),
1554
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [
1555
+ step === "email" && /* @__PURE__ */ jsxs(Fragment, { children: [
1556
+ /* @__PURE__ */ jsx(Button, { onClick: handleEmailSubmit, disabled: pwLoading, style: { width: "100%" }, children: pwLoading ? /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
1557
+ /* @__PURE__ */ jsx(IconLoader2, { style: { width: "1rem", height: "1rem" } }),
1558
+ " Vérification..."
1559
+ ] }) : "Continuer" }),
1560
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: handleBackToLogin, style: { width: "100%" }, children: "Retour à la connexion" })
1561
+ ] }),
1562
+ step === "method-choice" && /* @__PURE__ */ jsx(Button, { onClick: handleMethodSubmit, disabled: pwLoading, style: { width: "100%" }, children: pwLoading ? /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
1563
+ /* @__PURE__ */ jsx(IconLoader2, { style: { width: "1rem", height: "1rem" } }),
1564
+ " Envoi..."
1565
+ ] }) : "Envoyer le code" }),
1566
+ step === "otp" && /* @__PURE__ */ jsx(Button, { onClick: handleOTPSubmit, disabled: otp.length !== 6, style: { width: "100%" }, children: "Vérifier" }),
1567
+ step === "password" && /* @__PURE__ */ jsx(Button, { onClick: handlePasswordSubmit, disabled: pwLoading || !password || !confirmPassword, style: { width: "100%" }, children: pwLoading ? /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
1568
+ /* @__PURE__ */ jsx(IconLoader2, { style: { width: "1rem", height: "1rem" } }),
1569
+ " Modification..."
1570
+ ] }) : "Modifier le mot de passe" })
1508
1571
  ] })
1509
1572
  ] }) });
1510
1573
  }
1511
- const FIRST_CHECK_DELAY = 2 * 60 * 1e3;
1512
- const INTERVAL_DELAY = 5 * 60 * 1e3;
1574
+ const FIRST_CHECK_DELAY = 60 * 1e3;
1575
+ const INTERVAL_DELAY = 2 * 60 * 1e3;
1513
1576
  async function checkTokenValidity(saasApiUrl, token, debug) {
1514
1577
  if (typeof navigator !== "undefined" && !navigator.onLine) {
1515
1578
  if (debug) console.log("🔄 [HealthCheck] Offline — skip");
@@ -1529,7 +1592,7 @@ async function checkTokenValidity(saasApiUrl, token, debug) {
1529
1592
  });
1530
1593
  clearTimeout(timeoutId);
1531
1594
  if (response.status === 401) {
1532
- if (debug) console.log("🔄 [HealthCheck] Token invalide (401)");
1595
+ if (debug) console.log("🔄 [HealthCheck] Token invalide (401) — déconnexion");
1533
1596
  return { valid: false };
1534
1597
  }
1535
1598
  if (!response.ok) {
@@ -1537,11 +1600,15 @@ async function checkTokenValidity(saasApiUrl, token, debug) {
1537
1600
  throw new Error(`server_error_${response.status}`);
1538
1601
  }
1539
1602
  const data = await response.json();
1540
- if (debug) console.log("🔄 [HealthCheck] Token valide ✅");
1541
- return {
1542
- valid: data.valid !== false,
1543
- user_infos: data.user_infos
1544
- };
1603
+ if (data.status === "connected" && data.user) {
1604
+ if (debug) console.log("🔄 [HealthCheck] Token valide ✅ — user_infos mis à jour");
1605
+ return { valid: true, user: data.user };
1606
+ }
1607
+ if (data.success !== false) {
1608
+ if (debug) console.log("🔄 [HealthCheck] Token valide ✅");
1609
+ return { valid: true, user: data.user };
1610
+ }
1611
+ return { valid: false };
1545
1612
  } catch (error) {
1546
1613
  clearTimeout(timeoutId);
1547
1614
  if (error instanceof Error && error.message === "offline") {
@@ -1554,8 +1621,34 @@ async function checkTokenValidity(saasApiUrl, token, debug) {
1554
1621
  throw error;
1555
1622
  }
1556
1623
  }
1624
+ function revokeOnIam(iamApiUrl, sanctumToken, debug) {
1625
+ try {
1626
+ const controller = new AbortController();
1627
+ setTimeout(() => controller.abort(), 5e3);
1628
+ const appAccessTokenRef = typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE.APP_ACCESS_TOKEN_REF) : null;
1629
+ const payload = { sanctum_token: sanctumToken };
1630
+ if (appAccessTokenRef) {
1631
+ payload.app_access_token_ref = appAccessTokenRef;
1632
+ }
1633
+ if (debug) {
1634
+ console.log("🔄 [HealthCheck] Revocation IAM:", { hasRef: !!appAccessTokenRef });
1635
+ }
1636
+ fetch(`${iamApiUrl}/iam/disconnect`, {
1637
+ method: "POST",
1638
+ headers: {
1639
+ "Content-Type": "application/json",
1640
+ "Accept": "application/json"
1641
+ },
1642
+ body: JSON.stringify(payload),
1643
+ signal: controller.signal
1644
+ }).catch(() => {
1645
+ if (debug) console.log("🔄 [HealthCheck] Échec revocation IAM (non-bloquant)");
1646
+ });
1647
+ } catch {
1648
+ }
1649
+ }
1557
1650
  function useTokenHealthCheck(options) {
1558
- const { enabled, saasApiUrl, onTokenInvalid, onUserUpdated, debug = false } = options;
1651
+ const { enabled, saasApiUrl, iamApiUrl, onTokenInvalid, onUserUpdated, debug = false } = options;
1559
1652
  const timerRef = useRef(null);
1560
1653
  const intervalRef = useRef(null);
1561
1654
  const enabledRef = useRef(enabled);
@@ -1572,15 +1665,19 @@ function useTokenHealthCheck(options) {
1572
1665
  try {
1573
1666
  const result = await checkTokenValidity(saasApiUrl, token, debug);
1574
1667
  if (!result.valid) {
1668
+ if (iamApiUrl) {
1669
+ if (debug) console.log("🔄 [HealthCheck] Revocation IAM avec sanctum_token...");
1670
+ revokeOnIam(iamApiUrl, token, debug);
1671
+ }
1575
1672
  callbacksRef.current.onTokenInvalid();
1576
1673
  return;
1577
1674
  }
1578
- if (result.user_infos && callbacksRef.current.onUserUpdated) {
1579
- callbacksRef.current.onUserUpdated(result.user_infos);
1675
+ if (result.user && callbacksRef.current.onUserUpdated) {
1676
+ callbacksRef.current.onUserUpdated(result.user);
1580
1677
  }
1581
1678
  } catch {
1582
1679
  }
1583
- }, [saasApiUrl, debug]);
1680
+ }, [saasApiUrl, iamApiUrl, debug]);
1584
1681
  useEffect(() => {
1585
1682
  if (timerRef.current) {
1586
1683
  clearTimeout(timerRef.current);
@@ -1591,7 +1688,7 @@ function useTokenHealthCheck(options) {
1591
1688
  intervalRef.current = null;
1592
1689
  }
1593
1690
  if (!enabled || !saasApiUrl) return;
1594
- if (debug) console.log("🔄 [HealthCheck] Activé — premier check dans 2 min");
1691
+ if (debug) console.log("🔄 [HealthCheck] Activé — premier check dans 60s, puis toutes les 2 min");
1595
1692
  timerRef.current = setTimeout(() => {
1596
1693
  performCheck();
1597
1694
  intervalRef.current = setInterval(performCheck, INTERVAL_DELAY);
@@ -1618,6 +1715,9 @@ function saveSession(exchangeResult, accountType) {
1618
1715
  if (aliasRef) {
1619
1716
  localStorage.setItem(STORAGE.ALIAS_REFERENCE, aliasRef);
1620
1717
  }
1718
+ if (exchangeResult.app_access_token_ref) {
1719
+ localStorage.setItem(STORAGE.APP_ACCESS_TOKEN_REF, exchangeResult.app_access_token_ref);
1720
+ }
1621
1721
  const acctType = typeof accountType === "string" ? accountType : "user";
1622
1722
  localStorage.setItem(STORAGE.USER, JSON.stringify(userToStore));
1623
1723
  localStorage.setItem(STORAGE.ACCOUNT_TYPE, acctType);
@@ -1629,6 +1729,7 @@ function clearSession() {
1629
1729
  localStorage.removeItem(STORAGE.USER);
1630
1730
  localStorage.removeItem(STORAGE.ACCOUNT_TYPE);
1631
1731
  localStorage.removeItem(STORAGE.ALIAS_REFERENCE);
1732
+ localStorage.removeItem(STORAGE.APP_ACCESS_TOKEN_REF);
1632
1733
  }
1633
1734
  function getErrorMessage$1(err, context) {
1634
1735
  if (err instanceof Error) {
@@ -1702,6 +1803,7 @@ function useNativeAuth(options) {
1702
1803
  useTokenHealthCheck({
1703
1804
  enabled: state.status === "completed" && state.user !== null,
1704
1805
  saasApiUrl,
1806
+ iamApiUrl,
1705
1807
  onTokenInvalid: handleTokenInvalid,
1706
1808
  onUserUpdated: handleUserUpdated,
1707
1809
  debug: isDebug
@@ -1871,7 +1973,7 @@ function useNativeAuth(options) {
1871
1973
  await nativeAuthService.loadCredentials();
1872
1974
  }
1873
1975
  const response = await nativeAuthService.loginAccessOtp(otpCode);
1874
- if (response.success && response.needs_access && response.process_token) {
1976
+ if ((response.needs_access || response.status === "needs_access") && response.process_token) {
1875
1977
  setState((prev) => ({
1876
1978
  ...prev,
1877
1979
  processToken: response.process_token,
@@ -2178,7 +2280,7 @@ function useNativeAuth(options) {
2178
2280
  processToken: null
2179
2281
  }));
2180
2282
  }, [defaultAccountType]);
2181
- const logout = useCallback(async () => {
2283
+ const logout2 = useCallback(async () => {
2182
2284
  const token = localStorage.getItem(STORAGE.AUTH_TOKEN) || localStorage.getItem(STORAGE.TOKEN);
2183
2285
  try {
2184
2286
  if (token) {
@@ -2250,7 +2352,7 @@ function useNativeAuth(options) {
2250
2352
  grantAccess,
2251
2353
  resendOtp,
2252
2354
  setSession,
2253
- logout,
2355
+ logout: logout2,
2254
2356
  reset,
2255
2357
  clearError,
2256
2358
  register,
@@ -2339,7 +2441,8 @@ function LoginModal({
2339
2441
  iamApiUrl,
2340
2442
  loading,
2341
2443
  showSwitchToSignup = true,
2342
- defaultAccountType
2444
+ defaultAccountType,
2445
+ initialPhone
2343
2446
  }) {
2344
2447
  const {
2345
2448
  status,
@@ -2418,6 +2521,12 @@ function LoginModal({
2418
2521
  useEffect(() => {
2419
2522
  if (!open) resetState();
2420
2523
  }, [open]);
2524
+ useEffect(() => {
2525
+ if (open && initialPhone) {
2526
+ setStep("phone-input");
2527
+ setPhone(initialPhone);
2528
+ }
2529
+ }, [open, initialPhone]);
2421
2530
  const exchangeCallbackToken = async (callbackToken) => {
2422
2531
  try {
2423
2532
  const response = await nativeAuthService.exchange(callbackToken);
@@ -2574,23 +2683,25 @@ function LoginModal({
2574
2683
  "."
2575
2684
  ] })
2576
2685
  ] }),
2577
- /* @__PURE__ */ jsxs("div", { style: { marginTop: "1rem" }, children: [
2578
- /* @__PURE__ */ jsxs("div", { style: { padding: "1rem", backgroundColor: C$2.gray100, borderRadius: "0.5rem", marginBottom: "1rem", fontSize: "0.875rem", color: C$2.gray500 }, children: [
2686
+ /* @__PURE__ */ jsxs(DialogBody, { children: [
2687
+ /* @__PURE__ */ jsxs("div", { style: { padding: "1rem", backgroundColor: C$2.gray100, borderRadius: "0.5rem", fontSize: "0.875rem", color: C$2.gray500 }, children: [
2579
2688
  "Votre compte ",
2580
2689
  /* @__PURE__ */ jsx("strong", { style: { color: C$2.primary }, children: "iam.ollaid.com" }),
2581
2690
  " existe déjà. Cliquez sur Confirmer pour créer votre accès à ",
2582
2691
  /* @__PURE__ */ jsx("strong", { style: { color: C$2.gray900 }, children: application.name }),
2583
2692
  "."
2584
2693
  ] }),
2585
- renderError(),
2586
- /* @__PURE__ */ jsx(Button, { onClick: handleGrantAccess, disabled: isSubmitting, style: { width: "100%", marginTop: "0.75rem" }, children: isSubmitting ? /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
2694
+ renderError()
2695
+ ] }),
2696
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [
2697
+ /* @__PURE__ */ jsx(Button, { onClick: handleGrantAccess, disabled: isSubmitting, style: { width: "100%" }, children: isSubmitting ? /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
2587
2698
  /* @__PURE__ */ jsx(IconLoader2, { style: { width: "1rem", height: "1rem" } }),
2588
2699
  "Création en cours..."
2589
2700
  ] }) : "Confirmer la création de mon compte" }),
2590
2701
  /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => {
2591
2702
  resetAuth();
2592
2703
  setStep("choice");
2593
- }, disabled: isSubmitting, style: { width: "100%", marginTop: "0.5rem" }, children: "Annuler" })
2704
+ }, disabled: isSubmitting, style: { width: "100%" }, children: "Annuler" })
2594
2705
  ] })
2595
2706
  ] }) : alternativeMethod ? /* @__PURE__ */ jsxs(Fragment, { children: [
2596
2707
  /* @__PURE__ */ jsxs(DialogHeader, { style: { textAlign: "center" }, children: [
@@ -2598,21 +2709,21 @@ function LoginModal({
2598
2709
  /* @__PURE__ */ jsx(DialogTitle, { children: "Moyen de connexion désactivé" }),
2599
2710
  /* @__PURE__ */ jsx(DialogDescription, { children: "Vos identifiants sont corrects, mais vous avez désactivé ce moyen de connexion depuis votre compte IAM." })
2600
2711
  ] }),
2601
- /* @__PURE__ */ jsxs("div", { style: { marginTop: "1rem" }, children: [
2602
- alternativeMethod.value && /* @__PURE__ */ jsxs("div", { style: { padding: "1rem", backgroundColor: C$2.gray100, borderRadius: "0.5rem", marginBottom: "1rem" }, children: [
2603
- /* @__PURE__ */ jsx("p", { style: { fontSize: "0.875rem", color: C$2.gray500, marginBottom: "0.75rem" }, children: "Vous pouvez vous connecter avec :" }),
2604
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem", fontSize: "0.875rem", fontWeight: 500, color: C$2.gray900 }, children: [
2605
- alternativeMethod.type === "phone" ? /* @__PURE__ */ jsx(IconPhone, { style: { width: "1rem", height: "1rem", color: C$2.primary } }) : /* @__PURE__ */ jsx(IconMail, { style: { width: "1rem", height: "1rem", color: C$2.primary } }),
2606
- /* @__PURE__ */ jsx("span", { children: alternativeMethod.value })
2607
- ] })
2608
- ] }),
2712
+ /* @__PURE__ */ jsx(DialogBody, { children: alternativeMethod.value && /* @__PURE__ */ jsxs("div", { style: { padding: "1rem", backgroundColor: C$2.gray100, borderRadius: "0.5rem" }, children: [
2713
+ /* @__PURE__ */ jsx("p", { style: { fontSize: "0.875rem", color: C$2.gray500, marginBottom: "0.75rem" }, children: "Vous pouvez vous connecter avec :" }),
2714
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem", fontSize: "0.875rem", fontWeight: 500, color: C$2.gray900 }, children: [
2715
+ alternativeMethod.type === "phone" ? /* @__PURE__ */ jsx(IconPhone, { style: { width: "1rem", height: "1rem", color: C$2.primary } }) : /* @__PURE__ */ jsx(IconMail, { style: { width: "1rem", height: "1rem", color: C$2.primary } }),
2716
+ /* @__PURE__ */ jsx("span", { children: alternativeMethod.value })
2717
+ ] })
2718
+ ] }) }),
2719
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [
2609
2720
  /* @__PURE__ */ jsx(Button, { onClick: () => {
2610
2721
  if (alternativeMethod.type === "phone") setStep("phone-input");
2611
2722
  else setStep("email-check");
2612
2723
  resetAuth();
2613
2724
  }, style: { width: "100%" }, children: alternativeMethod.type === "phone" ? "Se connecter par téléphone" : "Se connecter par email" }),
2614
- /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => window.open("https://iam.ollaid.com", "_blank"), style: { width: "100%", marginTop: "0.5rem" }, children: "Réactiver depuis iam.ollaid.com" }),
2615
- /* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: () => onOpenChange(false), style: { width: "100%", marginTop: "0.5rem" }, children: "Annuler" })
2725
+ /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => window.open("https://iam.ollaid.com", "_blank"), style: { width: "100%" }, children: "Réactiver depuis iam.ollaid.com" }),
2726
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: () => onOpenChange(false), style: { width: "100%" }, children: "Annuler" })
2616
2727
  ] })
2617
2728
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2618
2729
  step !== "choice" && renderBackBtn(),
@@ -2622,7 +2733,7 @@ function LoginModal({
2622
2733
  /* @__PURE__ */ jsx(DialogTitle, { children: "Connexion" }),
2623
2734
  /* @__PURE__ */ jsx(DialogDescription, { children: "Choisissez votre méthode de connexion" })
2624
2735
  ] }),
2625
- /* @__PURE__ */ jsxs("div", { style: { marginTop: "1rem", display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
2736
+ /* @__PURE__ */ jsx(DialogBody, { children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
2626
2737
  renderError(),
2627
2738
  /* @__PURE__ */ jsxs(Button, { variant: "outline", onClick: () => setStep("email-check"), style: methodBtnStyle, children: [
2628
2739
  /* @__PURE__ */ jsx("div", { style: methodIconStyle(C$2.accent), children: /* @__PURE__ */ jsx(IconMail, { style: { width: "1.25rem", height: "1.25rem", color: C$2.white } }) }),
@@ -2657,7 +2768,7 @@ function LoginModal({
2657
2768
  /* @__PURE__ */ jsx("span", { style: { color: C$2.gray500 }, children: "Pas encore de compte ? " }),
2658
2769
  /* @__PURE__ */ jsx("button", { type: "button", style: linkStyle$1, onClick: onSwitchToSignup, children: "Inscrivez-vous" })
2659
2770
  ] })
2660
- ] })
2771
+ ] }) })
2661
2772
  ] }),
2662
2773
  step === "email-check" && /* @__PURE__ */ jsxs(Fragment, { children: [
2663
2774
  /* @__PURE__ */ jsxs(DialogHeader, { style: { textAlign: "center" }, children: [
@@ -2665,7 +2776,7 @@ function LoginModal({
2665
2776
  /* @__PURE__ */ jsx(DialogTitle, { children: "Connexion par email" }),
2666
2777
  /* @__PURE__ */ jsx(DialogDescription, { children: "Entrez votre adresse email" })
2667
2778
  ] }),
2668
- /* @__PURE__ */ jsxs("div", { style: { marginTop: "1rem", display: "flex", flexDirection: "column", gap: "1rem" }, children: [
2779
+ /* @__PURE__ */ jsx(DialogBody, { children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "1rem" }, children: [
2669
2780
  renderError(),
2670
2781
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.25rem" }, children: [
2671
2782
  /* @__PURE__ */ jsx(Label, { htmlFor: "email", children: "Adresse email" }),
@@ -2687,7 +2798,9 @@ function LoginModal({
2687
2798
  }
2688
2799
  )
2689
2800
  ] }),
2690
- /* @__PURE__ */ jsx("div", { style: { textAlign: "right" }, children: /* @__PURE__ */ jsx("button", { type: "button", style: { ...linkStyle$1, fontSize: "0.75rem" }, onClick: () => setShowPasswordRecovery(true), children: "Mot de passe oublié ?" }) }),
2801
+ /* @__PURE__ */ jsx("div", { style: { textAlign: "right" }, children: /* @__PURE__ */ jsx("button", { type: "button", style: { ...linkStyle$1, fontSize: "0.75rem" }, onClick: () => setShowPasswordRecovery(true), children: "Mot de passe oublié ?" }) })
2802
+ ] }) }),
2803
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [
2691
2804
  renderLoaderBtn("Continuer", "Vérification...", handleEmailCheck, !email.trim()),
2692
2805
  showSwitchToSignup && /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", fontSize: "0.875rem" }, children: [
2693
2806
  /* @__PURE__ */ jsx("span", { style: { color: C$2.gray500 }, children: "Pas encore de compte ? " }),
@@ -2705,41 +2818,43 @@ function LoginModal({
2705
2818
  ] }),
2706
2819
  /* @__PURE__ */ jsx(DialogDescription, { children: email })
2707
2820
  ] }),
2708
- /* @__PURE__ */ jsxs("form", { onSubmit: handleEmailPasswordSubmit, style: { marginTop: "1rem", display: "flex", flexDirection: "column", gap: "1rem" }, children: [
2709
- renderError(),
2710
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.25rem" }, children: [
2711
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
2712
- /* @__PURE__ */ jsx(Label, { htmlFor: "password", children: "Mot de passe" }),
2713
- /* @__PURE__ */ jsx("button", { type: "button", style: { ...linkStyle$1, fontSize: "0.75rem" }, onClick: () => setShowPasswordRecovery(true), children: "Mot de passe oublié ?" })
2714
- ] }),
2715
- /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
2716
- /* @__PURE__ */ jsx(
2717
- Input,
2718
- {
2719
- id: "password",
2720
- type: showPassword ? "text" : "password",
2721
- placeholder: "••••••••",
2722
- value: password,
2723
- onChange: (e) => setPassword(e.target.value),
2724
- disabled: isSubmitting,
2725
- style: { paddingRight: "2.5rem" }
2726
- }
2727
- ),
2728
- /* @__PURE__ */ jsx(
2729
- "button",
2730
- {
2731
- type: "button",
2732
- onClick: () => setShowPassword(!showPassword),
2733
- style: { position: "absolute", right: 0, top: 0, height: "100%", padding: "0 0.75rem", background: "none", border: "none", cursor: "pointer" },
2734
- children: showPassword ? /* @__PURE__ */ jsx(IconEyeOff, { style: { width: "1rem", height: "1rem", color: C$2.gray500 } }) : /* @__PURE__ */ jsx(IconEye, { style: { width: "1rem", height: "1rem", color: C$2.gray500 } })
2735
- }
2736
- )
2821
+ /* @__PURE__ */ jsxs("form", { onSubmit: handleEmailPasswordSubmit, style: { display: "flex", flexDirection: "column", flex: 1, minHeight: 0 }, children: [
2822
+ /* @__PURE__ */ jsx(DialogBody, { children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "1rem" }, children: [
2823
+ renderError(),
2824
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.25rem" }, children: [
2825
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
2826
+ /* @__PURE__ */ jsx(Label, { htmlFor: "password", children: "Mot de passe" }),
2827
+ /* @__PURE__ */ jsx("button", { type: "button", style: { ...linkStyle$1, fontSize: "0.75rem" }, onClick: () => setShowPasswordRecovery(true), children: "Mot de passe oublié ?" })
2828
+ ] }),
2829
+ /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
2830
+ /* @__PURE__ */ jsx(
2831
+ Input,
2832
+ {
2833
+ id: "password",
2834
+ type: showPassword ? "text" : "password",
2835
+ placeholder: "••••••••",
2836
+ value: password,
2837
+ onChange: (e) => setPassword(e.target.value),
2838
+ disabled: isSubmitting,
2839
+ style: { paddingRight: "2.5rem" }
2840
+ }
2841
+ ),
2842
+ /* @__PURE__ */ jsx(
2843
+ "button",
2844
+ {
2845
+ type: "button",
2846
+ onClick: () => setShowPassword(!showPassword),
2847
+ style: { position: "absolute", right: 0, top: 0, height: "100%", padding: "0 0.75rem", background: "none", border: "none", cursor: "pointer" },
2848
+ children: showPassword ? /* @__PURE__ */ jsx(IconEyeOff, { style: { width: "1rem", height: "1rem", color: C$2.gray500 } }) : /* @__PURE__ */ jsx(IconEye, { style: { width: "1rem", height: "1rem", color: C$2.gray500 } })
2849
+ }
2850
+ )
2851
+ ] })
2737
2852
  ] })
2738
- ] }),
2739
- /* @__PURE__ */ jsx(Button, { type: "submit", disabled: isSubmitting || !password, style: { width: "100%" }, children: isSubmitting ? /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
2853
+ ] }) }),
2854
+ /* @__PURE__ */ jsx(DialogFooter, { children: /* @__PURE__ */ jsx(Button, { type: "submit", disabled: isSubmitting || !password, style: { width: "100%" }, children: isSubmitting ? /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
2740
2855
  /* @__PURE__ */ jsx(IconLoader2, { style: { width: "1rem", height: "1rem" } }),
2741
2856
  "Connexion..."
2742
- ] }) : "Se connecter" })
2857
+ ] }) : "Se connecter" }) })
2743
2858
  ] })
2744
2859
  ] }),
2745
2860
  step === "email-otp" && /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -2752,12 +2867,12 @@ function LoginModal({
2752
2867
  /* @__PURE__ */ jsx("strong", { style: { color: C$2.gray900 }, children: email })
2753
2868
  ] })
2754
2869
  ] }),
2755
- /* @__PURE__ */ jsxs("div", { style: { marginTop: "1rem", display: "flex", flexDirection: "column", gap: "1rem" }, children: [
2870
+ /* @__PURE__ */ jsx(DialogBody, { children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "1rem" }, children: [
2756
2871
  renderError(),
2757
2872
  /* @__PURE__ */ jsx(OTPInput, { value: emailOtpCode, onChange: setEmailOtpCode, disabled: isSubmitting }),
2758
- renderResendLink(),
2759
- renderLoaderBtn("Vérifier", "Vérification...", handleEmailOtpVerify, emailOtpCode.length !== 6)
2760
- ] })
2873
+ renderResendLink()
2874
+ ] }) }),
2875
+ /* @__PURE__ */ jsx(DialogFooter, { children: renderLoaderBtn("Vérifier", "Vérification...", handleEmailOtpVerify, emailOtpCode.length !== 6) })
2761
2876
  ] }),
2762
2877
  step === "phone-input" && /* @__PURE__ */ jsxs(Fragment, { children: [
2763
2878
  /* @__PURE__ */ jsxs(DialogHeader, { style: { textAlign: "center" }, children: [
@@ -2765,7 +2880,7 @@ function LoginModal({
2765
2880
  /* @__PURE__ */ jsx(DialogTitle, { children: "Connexion par téléphone" }),
2766
2881
  /* @__PURE__ */ jsx(DialogDescription, { children: "Entrez votre numéro pour recevoir un code SMS" })
2767
2882
  ] }),
2768
- /* @__PURE__ */ jsxs("div", { style: { marginTop: "1rem", display: "flex", flexDirection: "column", gap: "1rem" }, children: [
2883
+ /* @__PURE__ */ jsx(DialogBody, { children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "1rem" }, children: [
2769
2884
  renderError(),
2770
2885
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.25rem" }, children: [
2771
2886
  /* @__PURE__ */ jsx(Label, { children: "Indicatif" }),
@@ -2802,7 +2917,9 @@ function LoginModal({
2802
2917
  phone.replace(/\D/g, "").length,
2803
2918
  "/9)"
2804
2919
  ] })
2805
- ] }),
2920
+ ] })
2921
+ ] }) }),
2922
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [
2806
2923
  renderLoaderBtn("Recevoir le code SMS", "Envoi en cours...", handlePhoneInit, phone.replace(/\D/g, "").length !== 9),
2807
2924
  showSwitchToSignup && /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", fontSize: "0.875rem" }, children: [
2808
2925
  /* @__PURE__ */ jsx("span", { style: { color: C$2.gray500 }, children: "Pas encore de compte ? " }),
@@ -2825,12 +2942,12 @@ function LoginModal({
2825
2942
  ] })
2826
2943
  ] })
2827
2944
  ] }),
2828
- /* @__PURE__ */ jsxs("div", { style: { marginTop: "1rem", display: "flex", flexDirection: "column", gap: "1rem" }, children: [
2945
+ /* @__PURE__ */ jsx(DialogBody, { children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "1rem" }, children: [
2829
2946
  renderError(),
2830
2947
  /* @__PURE__ */ jsx(OTPInput, { value: phoneOtpCode, onChange: setPhoneOtpCode, disabled: isSubmitting }),
2831
- renderResendLink(),
2832
- renderLoaderBtn("Se connecter", "Vérification...", handlePhoneVerify, phoneOtpCode.length !== 6)
2833
- ] })
2948
+ renderResendLink()
2949
+ ] }) }),
2950
+ /* @__PURE__ */ jsx(DialogFooter, { children: renderLoaderBtn("Se connecter", "Vérification...", handlePhoneVerify, phoneOtpCode.length !== 6) })
2834
2951
  ] }),
2835
2952
  step === "access-otp" && /* @__PURE__ */ jsxs(Fragment, { children: [
2836
2953
  /* @__PURE__ */ jsxs(DialogHeader, { style: { textAlign: "center" }, children: [
@@ -2838,7 +2955,7 @@ function LoginModal({
2838
2955
  /* @__PURE__ */ jsx(DialogTitle, { children: "Code d'accès" }),
2839
2956
  /* @__PURE__ */ jsx(DialogDescription, { children: "Entrez le code d'accès à 8 chiffres" })
2840
2957
  ] }),
2841
- /* @__PURE__ */ jsxs("div", { style: { marginTop: "1rem", display: "flex", flexDirection: "column", gap: "1rem" }, children: [
2958
+ /* @__PURE__ */ jsx(DialogBody, { children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "1rem" }, children: [
2842
2959
  renderError(),
2843
2960
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.25rem" }, children: [
2844
2961
  /* @__PURE__ */ jsx(Label, { children: "Code d'accès (8 chiffres)" }),
@@ -2855,9 +2972,9 @@ function LoginModal({
2855
2972
  maxLength: 8
2856
2973
  }
2857
2974
  )
2858
- ] }),
2859
- renderLoaderBtn("Se connecter", "Vérification...", handleAccessOtpSubmit, accessOtpCode.length !== 8)
2860
- ] })
2975
+ ] })
2976
+ ] }) }),
2977
+ /* @__PURE__ */ jsx(DialogFooter, { children: renderLoaderBtn("Se connecter", "Vérification...", handleAccessOtpSubmit, accessOtpCode.length !== 8) })
2861
2978
  ] })
2862
2979
  ] }) }) }),
2863
2980
  /* @__PURE__ */ jsx(
@@ -3054,6 +3171,7 @@ const COUNTRIES = [
3054
3171
  ];
3055
3172
  const DEFAULT_COUNTRY_CODE = "SN";
3056
3173
  const DEFAULT_DIAL_CODE = "+221";
3174
+ const COUNTRIES_SORTED_BY_CODE = [...COUNTRIES].sort((a, b) => a.code.localeCompare(b.code));
3057
3175
  const getCountryByCode = (code) => COUNTRIES.find((c) => c.code.toLowerCase() === code.toLowerCase());
3058
3176
  const getCountryByDialCode = (dialCode) => COUNTRIES.find((c) => c.dialCode === dialCode);
3059
3177
  const getDefaultCountry = () => COUNTRIES.find((c) => c.code === DEFAULT_COUNTRY_CODE);
@@ -3074,7 +3192,17 @@ function PhoneInput({
3074
3192
  placeholder = "77 123 45 67",
3075
3193
  lockCcphone = false
3076
3194
  }) {
3077
- const selectedCountry = getCountryByDialCode(ccphone) || COUNTRIES[0];
3195
+ const selectedCountry = getCountryByDialCode(ccphone) || COUNTRIES_SORTED_BY_CODE[0];
3196
+ const [dropdownOpen, setDropdownOpen] = useState(false);
3197
+ const dropdownRef = useRef(null);
3198
+ useEffect(() => {
3199
+ if (!dropdownOpen) return;
3200
+ const handler = (e) => {
3201
+ if (dropdownRef.current && !dropdownRef.current.contains(e.target)) setDropdownOpen(false);
3202
+ };
3203
+ document.addEventListener("mousedown", handler);
3204
+ return () => document.removeEventListener("mousedown", handler);
3205
+ }, [dropdownOpen]);
3078
3206
  const handleChange = (e) => {
3079
3207
  const cleaned = e.target.value.replace(/\D/g, "");
3080
3208
  onChange(cleaned.slice(0, selectedCountry.digits));
@@ -3085,33 +3213,96 @@ function PhoneInput({
3085
3213
  if (phone.length <= 7) return `${phone.slice(0, 2)} ${phone.slice(2, 5)} ${phone.slice(5)}`;
3086
3214
  return `${phone.slice(0, 2)} ${phone.slice(2, 5)} ${phone.slice(5, 7)} ${phone.slice(7)}`;
3087
3215
  };
3216
+ const handleSelect = (dialCode) => {
3217
+ if (onCcphoneChange) onCcphoneChange(dialCode);
3218
+ setDropdownOpen(false);
3219
+ };
3088
3220
  return /* @__PURE__ */ jsxs("div", { children: [
3089
3221
  /* @__PURE__ */ jsxs("div", { style: {
3090
3222
  display: "flex",
3091
3223
  alignItems: "center",
3092
3224
  border: `2px solid ${error ? "#ef4444" : "#d1d5db"}`,
3093
3225
  borderRadius: "0.5rem",
3094
- overflow: "hidden",
3226
+ overflow: "visible",
3095
3227
  opacity: disabled ? 0.5 : 1,
3096
- backgroundColor: disabled ? "#f3f4f6" : "white"
3228
+ backgroundColor: disabled ? "#f3f4f6" : "white",
3229
+ position: "relative"
3097
3230
  }, children: [
3098
- onCcphoneChange && !lockCcphone ? /* @__PURE__ */ jsx(
3099
- "select",
3100
- {
3101
- value: ccphone,
3102
- onChange: (e) => onCcphoneChange(e.target.value),
3103
- disabled,
3104
- style: { padding: "0.75rem", backgroundColor: "#f9fafb", borderRight: "1px solid #e5e7eb", fontWeight: 500, color: "#374151", outline: "none", border: "none", maxWidth: "7rem" },
3105
- children: COUNTRIES.map((c) => /* @__PURE__ */ jsxs("option", { value: c.dialCode, children: [
3106
- c.flag,
3107
- " ",
3108
- c.dialCode
3109
- ] }, `${c.code}-${c.dialCode}`))
3110
- }
3111
- ) : /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem", padding: "0.75rem", backgroundColor: "#f9fafb", borderRight: "1px solid #e5e7eb" }, children: [
3112
- /* @__PURE__ */ jsx("span", { style: { fontSize: "1.125rem" }, children: selectedCountry.flag }),
3113
- /* @__PURE__ */ jsx("span", { style: { fontWeight: 500, color: "#374151" }, children: selectedCountry.dialCode })
3114
- ] }),
3231
+ onCcphoneChange && !lockCcphone ? /* @__PURE__ */ jsxs("div", { ref: dropdownRef, style: { position: "relative" }, children: [
3232
+ /* @__PURE__ */ jsxs(
3233
+ "button",
3234
+ {
3235
+ type: "button",
3236
+ onClick: () => !disabled && setDropdownOpen(!dropdownOpen),
3237
+ disabled,
3238
+ style: {
3239
+ display: "flex",
3240
+ alignItems: "center",
3241
+ gap: "0.375rem",
3242
+ padding: "0.75rem",
3243
+ backgroundColor: "#f9fafb",
3244
+ borderRight: "1px solid #e5e7eb",
3245
+ border: "none",
3246
+ cursor: disabled ? "not-allowed" : "pointer",
3247
+ fontWeight: 500,
3248
+ color: "#374151",
3249
+ fontSize: "0.9375rem",
3250
+ whiteSpace: "nowrap"
3251
+ },
3252
+ children: [
3253
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "1.125rem" }, children: selectedCountry.flag }),
3254
+ /* @__PURE__ */ jsx("span", { children: selectedCountry.dialCode }),
3255
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "0.625rem", marginLeft: "0.125rem" }, children: "▼" })
3256
+ ]
3257
+ }
3258
+ ),
3259
+ dropdownOpen && /* @__PURE__ */ jsx("div", { style: {
3260
+ position: "absolute",
3261
+ top: "100%",
3262
+ left: 0,
3263
+ zIndex: 50,
3264
+ backgroundColor: "white",
3265
+ border: "1px solid #d1d5db",
3266
+ borderRadius: "0.375rem",
3267
+ boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
3268
+ maxHeight: "15rem",
3269
+ overflowY: "auto",
3270
+ minWidth: "12rem",
3271
+ marginTop: "0.25rem"
3272
+ }, children: COUNTRIES_SORTED_BY_CODE.map((c) => /* @__PURE__ */ jsxs(
3273
+ "button",
3274
+ {
3275
+ type: "button",
3276
+ onClick: () => handleSelect(c.dialCode),
3277
+ style: {
3278
+ display: "flex",
3279
+ alignItems: "center",
3280
+ gap: "0.5rem",
3281
+ width: "100%",
3282
+ padding: "0.5rem 0.75rem",
3283
+ border: "none",
3284
+ cursor: "pointer",
3285
+ fontSize: "0.875rem",
3286
+ backgroundColor: c.dialCode === ccphone ? "#f3f4f6" : "transparent",
3287
+ textAlign: "left"
3288
+ },
3289
+ onMouseEnter: (e) => e.currentTarget.style.backgroundColor = "#f3f4f6",
3290
+ onMouseLeave: (e) => e.currentTarget.style.backgroundColor = c.dialCode === ccphone ? "#f3f4f6" : "transparent",
3291
+ children: [
3292
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 600, color: "#374151", minWidth: "1.75rem" }, children: c.code }),
3293
+ /* @__PURE__ */ jsx("span", { children: c.flag }),
3294
+ /* @__PURE__ */ jsx("span", { style: { color: "#6b7280" }, children: c.dialCode })
3295
+ ]
3296
+ },
3297
+ `${c.code}-${c.dialCode}`
3298
+ )) })
3299
+ ] }) : (
3300
+ /* Locked view: only flag + dialCode */
3301
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.375rem", padding: "0.75rem", backgroundColor: "#f9fafb", borderRight: "1px solid #e5e7eb" }, children: [
3302
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "1.125rem" }, children: selectedCountry.flag }),
3303
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 500, color: "#374151" }, children: selectedCountry.dialCode })
3304
+ ] })
3305
+ ),
3115
3306
  /* @__PURE__ */ jsx(
3116
3307
  "input",
3117
3308
  {
@@ -3414,6 +3605,18 @@ function useMobileRegistration(options) {
3414
3605
  }));
3415
3606
  return { success: false, error_type: response.error_type };
3416
3607
  } catch (err) {
3608
+ if (err instanceof ApiError && err.statusCode === 409 && err.response) {
3609
+ const resp = err.response;
3610
+ if (resp.conflict) {
3611
+ setState((prev) => ({
3612
+ ...prev,
3613
+ loading: false,
3614
+ error: resp.message || "Ce compte existe déjà",
3615
+ conflict: resp.conflict
3616
+ }));
3617
+ return { success: false, error_type: resp.error_type };
3618
+ }
3619
+ }
3417
3620
  const message = getErrorMessage(err, "l'inscription");
3418
3621
  setState((prev) => ({ ...prev, loading: false, error: message, conflict: null }));
3419
3622
  return { success: false };
@@ -3559,6 +3762,7 @@ const C$1 = {
3559
3762
  gray900: "#111827",
3560
3763
  red: "#dc2626",
3561
3764
  redBg: "#fef2f2",
3765
+ amber: "#f59e0b",
3562
3766
  amberBg: "#fef3c7",
3563
3767
  white: "#ffffff"
3564
3768
  };
@@ -3651,12 +3855,14 @@ function SuccessOrbit() {
3651
3855
  })
3652
3856
  ] });
3653
3857
  }
3654
- function SignupModal({ open, onOpenChange, onSwitchToLogin, onSignupSuccess, saasApiUrl, iamApiUrl, defaultAccountType }) {
3858
+ function SignupModal({ open, onOpenChange, onSwitchToLogin, onSignupSuccess, saasApiUrl, iamApiUrl, defaultAccountType, onSwitchToLoginWithPhone }) {
3859
+ var _a, _b, _c, _d, _e, _f;
3655
3860
  const {
3656
3861
  status,
3657
3862
  formData,
3658
3863
  loading: regLoading,
3659
3864
  error: regError,
3865
+ conflict,
3660
3866
  accountType,
3661
3867
  setAccountType,
3662
3868
  isPhoneOnly,
@@ -3668,6 +3874,7 @@ function SignupModal({ open, onOpenChange, onSwitchToLogin, onSignupSuccess, saa
3668
3874
  reset: resetReg,
3669
3875
  clearError
3670
3876
  } = useMobileRegistration({ saasApiUrl, iamApiUrl });
3877
+ const [showPasswordRecovery, setShowPasswordRecovery] = useState(false);
3671
3878
  const [step, setStep] = useState("intro");
3672
3879
  const [otpCode, setOtpCode] = useState("");
3673
3880
  const [password, setPassword] = useState("");
@@ -3720,31 +3927,35 @@ function SignupModal({ open, onOpenChange, onSwitchToLogin, onSignupSuccess, saa
3720
3927
  }
3721
3928
  };
3722
3929
  const handleInfoSubmit = async (e) => {
3723
- var _a, _b, _c, _d, _e, _f;
3930
+ var _a2, _b2, _c2, _d2, _e2, _f2, _g;
3724
3931
  e.preventDefault();
3725
3932
  setLocalError(null);
3726
3933
  clearError();
3727
- if (!((_a = formData.name) == null ? void 0 : _a.trim())) {
3934
+ if (!((_a2 = formData.name) == null ? void 0 : _a2.trim())) {
3728
3935
  setLocalError("Le nom est requis");
3729
3936
  return;
3730
3937
  }
3731
- if (!isPhoneOnly && !((_b = formData.email) == null ? void 0 : _b.trim())) {
3938
+ if (!isPhoneOnly && !((_b2 = formData.email) == null ? void 0 : _b2.trim())) {
3732
3939
  setLocalError("L'adresse email est requise");
3733
3940
  return;
3734
3941
  }
3735
- if (!((_c = formData.phone) == null ? void 0 : _c.trim()) || (((_d = formData.phone) == null ? void 0 : _d.length) || 0) < 6) {
3942
+ if (!((_c2 = formData.phone) == null ? void 0 : _c2.trim()) || (((_d2 = formData.phone) == null ? void 0 : _d2.length) || 0) < 6) {
3736
3943
  setLocalError("Numéro de téléphone invalide");
3737
3944
  return;
3738
3945
  }
3946
+ if (formData.ccphone === "+221" && ((_e2 = formData.phone) == null ? void 0 : _e2.length) !== 9) {
3947
+ setLocalError("Le numéro sénégalais doit contenir exactement 9 chiffres");
3948
+ return;
3949
+ }
3739
3950
  if (isPhoneOnly && formData.ccphone !== "+221") {
3740
3951
  setLocalError("L'inscription par téléphone est réservée aux numéros sénégalais (+221)");
3741
3952
  return;
3742
3953
  }
3743
- if (!((_e = formData.town) == null ? void 0 : _e.trim())) {
3954
+ if (!((_f2 = formData.town) == null ? void 0 : _f2.trim())) {
3744
3955
  setLocalError("La ville est requise");
3745
3956
  return;
3746
3957
  }
3747
- if (!((_f = formData.country) == null ? void 0 : _f.trim())) {
3958
+ if (!((_g = formData.country) == null ? void 0 : _g.trim())) {
3748
3959
  setLocalError("Le pays est requis");
3749
3960
  return;
3750
3961
  }
@@ -3796,197 +4007,281 @@ function SignupModal({ open, onOpenChange, onSwitchToLogin, onSignupSuccess, saa
3796
4007
  goToStep("info");
3797
4008
  };
3798
4009
  const renderError = () => error ? /* @__PURE__ */ jsx("div", { style: { padding: "0.75rem", borderRadius: "0.375rem", backgroundColor: C$1.redBg, color: C$1.red, fontSize: "0.875rem" }, children: error }) : null;
3799
- return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsx(DialogContent, { children: signupSuccess && signupData ? /* @__PURE__ */ jsxs(DialogHeader, { style: { textAlign: "center" }, children: [
3800
- /* @__PURE__ */ jsx(SuccessOrbit, {}),
3801
- /* @__PURE__ */ jsx(DialogTitle, { children: "Félicitations !" }),
3802
- /* @__PURE__ */ jsxs(DialogDescription, { children: [
3803
- "Votre compte a été créé avec succès. Bienvenue ",
3804
- formData.name,
3805
- " !"
3806
- ] }),
3807
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", gap: "0.5rem", fontSize: "0.875rem", color: C$1.gray500, marginTop: "1rem" }, children: [
3808
- /* @__PURE__ */ jsx(IconLoader2, { style: { width: "1rem", height: "1rem" } }),
3809
- "Connexion automatique en cours..."
3810
- ] })
3811
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
3812
- step === "intro" && /* @__PURE__ */ jsxs(Fragment, { children: [
3813
- /* @__PURE__ */ jsxs(DialogHeader, { style: { textAlign: "center" }, children: [
3814
- /* @__PURE__ */ jsx("div", { style: iconCircle(C$1.accent + "1a", "4rem"), children: /* @__PURE__ */ jsx(IconShieldCheck, { style: { width: "2rem", height: "2rem", color: C$1.accent } }) }),
3815
- /* @__PURE__ */ jsx(DialogTitle, { children: "Ouvrez un compte Ollaid" }),
3816
- /* @__PURE__ */ jsx(DialogDescription, { children: "Un compte unique qui vous donne accès à toutes les applications" })
4010
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
4011
+ /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsx(DialogContent, { children: signupSuccess && signupData ? /* @__PURE__ */ jsxs(DialogHeader, { style: { textAlign: "center" }, children: [
4012
+ /* @__PURE__ */ jsx(SuccessOrbit, {}),
4013
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Félicitations !" }),
4014
+ /* @__PURE__ */ jsxs(DialogDescription, { children: [
4015
+ "Votre compte a été créé avec succès. Bienvenue ",
4016
+ formData.name,
4017
+ " !"
3817
4018
  ] }),
3818
- /* @__PURE__ */ jsx(AppsLogoSlider, { iamApiUrl }),
3819
- /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "0.75rem", fontSize: "0.875rem", color: C$1.gray500, margin: "1rem 0" }, children: ["Un seul compte pour toutes les applications", "Plus besoin de multiples mots de passe", "Connexion simplifiée et sécurisée"].map((text) => /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.75rem" }, children: [
3820
- /* @__PURE__ */ jsx(IconCheckCircle2, { style: { width: "1.25rem", height: "1.25rem", color: C$1.green, flexShrink: 0 } }),
3821
- text
3822
- ] }, text)) }),
3823
- /* @__PURE__ */ jsx(StepIndicator, { current: 1 }),
3824
- /* @__PURE__ */ jsx(Button, { onClick: () => goToStep("account-type"), style: { width: "100%", marginTop: "1rem" }, children: "Suivant →" }),
3825
- /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", fontSize: "0.875rem", marginTop: "1rem" }, children: [
3826
- /* @__PURE__ */ jsx("span", { style: { color: C$1.gray500 }, children: "Déjà un compte ? " }),
3827
- /* @__PURE__ */ jsx("button", { type: "button", style: linkStyle, onClick: onSwitchToLogin, children: "Connectez-vous" })
4019
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", gap: "0.5rem", fontSize: "0.875rem", color: C$1.gray500, marginTop: "1rem" }, children: [
4020
+ /* @__PURE__ */ jsx(IconLoader2, { style: { width: "1rem", height: "1rem" } }),
4021
+ "Connexion automatique en cours..."
3828
4022
  ] })
3829
- ] }),
3830
- step === "account-type" && /* @__PURE__ */ jsxs(Fragment, { children: [
3831
- /* @__PURE__ */ jsx("button", { onClick: () => goToStep("intro"), style: backBtnStyle, type: "button", children: /* @__PURE__ */ jsx(IconArrowLeft, { style: { width: "1rem", height: "1rem" } }) }),
3832
- /* @__PURE__ */ jsxs(DialogHeader, { style: { textAlign: "center" }, children: [
3833
- /* @__PURE__ */ jsx("div", { style: iconCircle(C$1.gray100), children: /* @__PURE__ */ jsx(IconShieldCheck, { style: { width: "1.5rem", height: "1.5rem", color: C$1.primary } }) }),
3834
- /* @__PURE__ */ jsx(DialogTitle, { children: "Choisissez votre type de compte" })
3835
- ] }),
3836
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.75rem", marginTop: "1rem" }, children: [
3837
- /* @__PURE__ */ jsxs(
3838
- "button",
3839
- {
3840
- type: "button",
3841
- onClick: () => handleAccountTypeSelect("email"),
3842
- style: { width: "100%", padding: "1rem", border: `2px solid ${C$1.gray200}`, borderRadius: "0.5rem", textAlign: "left", cursor: "pointer", background: C$1.white, display: "flex", alignItems: "center", gap: "0.75rem" },
3843
- children: [
3844
- /* @__PURE__ */ jsx("div", { style: { width: "2.5rem", height: "2.5rem", backgroundColor: C$1.accent, borderRadius: "0.5rem", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }, children: /* @__PURE__ */ jsx(IconMail, { style: { width: "1.25rem", height: "1.25rem", color: C$1.white } }) }),
3845
- /* @__PURE__ */ jsxs("div", { children: [
3846
- /* @__PURE__ */ jsx("div", { style: { fontWeight: 600, color: C$1.gray900 }, children: "Email + Téléphone" }),
3847
- /* @__PURE__ */ jsx("div", { style: { fontSize: "0.875rem", color: C$1.gray500 }, children: "Compte complet" })
3848
- ] })
3849
- ]
3850
- }
3851
- ),
3852
- /* @__PURE__ */ jsxs(
3853
- "button",
3854
- {
3855
- type: "button",
3856
- onClick: () => handleAccountTypeSelect("phone-only"),
3857
- style: { width: "100%", padding: "1rem", border: `2px solid ${C$1.gray200}`, borderRadius: "0.5rem", textAlign: "left", cursor: "pointer", background: C$1.white, display: "flex", alignItems: "center", gap: "0.75rem" },
3858
- children: [
3859
- /* @__PURE__ */ jsx("div", { style: { width: "2.5rem", height: "2.5rem", backgroundColor: C$1.accent, borderRadius: "0.5rem", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }, children: /* @__PURE__ */ jsx(IconSmartphone, { style: { width: "1.25rem", height: "1.25rem", color: C$1.white } }) }),
3860
- /* @__PURE__ */ jsxs("div", { children: [
3861
- /* @__PURE__ */ jsx("div", { style: { fontWeight: 600, color: C$1.gray900 }, children: "Téléphone uniquement" }),
3862
- /* @__PURE__ */ jsx("div", { style: { fontSize: "0.875rem", color: C$1.gray500 }, children: "🇸🇳 Sénégal uniquement" })
3863
- ] })
3864
- ]
3865
- }
3866
- )
3867
- ] }),
3868
- /* @__PURE__ */ jsx(StepIndicator, { current: 2 })
3869
- ] }),
3870
- step === "info" && /* @__PURE__ */ jsxs(Fragment, { children: [
3871
- /* @__PURE__ */ jsx("button", { onClick: () => goToStep("account-type"), style: backBtnStyle, type: "button", children: /* @__PURE__ */ jsx(IconArrowLeft, { style: { width: "1rem", height: "1rem" } }) }),
3872
- /* @__PURE__ */ jsxs(DialogHeader, { style: { textAlign: "center" }, children: [
3873
- /* @__PURE__ */ jsx("div", { style: iconCircle(C$1.primary + "1a"), children: /* @__PURE__ */ jsx(IconShieldCheck, { style: { width: "1.5rem", height: "1.5rem", color: C$1.primary } }) }),
3874
- /* @__PURE__ */ jsx(DialogTitle, { children: "Créer votre compte" })
3875
- ] }),
3876
- isPhoneOnly && /* @__PURE__ */ jsx("div", { style: { padding: "0.75rem", borderRadius: "0.375rem", backgroundColor: C$1.accent + "1a", color: C$1.accent, fontSize: "0.8125rem", marginTop: "0.5rem", textAlign: "center" }, children: "📱 Inscription par téléphone — 🇸🇳 Sénégal uniquement" }),
3877
- !isPhoneOnly && /* @__PURE__ */ jsx("div", { style: { padding: "0.75rem", borderRadius: "0.375rem", backgroundColor: C$1.amberBg, color: "#92400e", fontSize: "0.8125rem", marginTop: "0.5rem", textAlign: "center" }, children: "⚠️ Un code OTP sera envoyé par email pour vérification" }),
3878
- /* @__PURE__ */ jsxs("form", { onSubmit: handleInfoSubmit, style: { display: "flex", flexDirection: "column", gap: "0.75rem", marginTop: "0.75rem" }, children: [
3879
- renderError(),
3880
- /* @__PURE__ */ jsxs("div", { children: [
3881
- /* @__PURE__ */ jsx(Label, { children: "Nom complet" }),
3882
- /* @__PURE__ */ jsx(Input, { placeholder: "Jean Dupont", value: formData.name || "", onChange: (e) => updateFormData({ name: e.target.value }), disabled: regLoading })
4023
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
4024
+ step === "intro" && /* @__PURE__ */ jsxs(Fragment, { children: [
4025
+ /* @__PURE__ */ jsxs(DialogHeader, { style: { textAlign: "center" }, children: [
4026
+ /* @__PURE__ */ jsx("div", { style: iconCircle(C$1.accent + "1a", "4rem"), children: /* @__PURE__ */ jsx(IconShieldCheck, { style: { width: "2rem", height: "2rem", color: C$1.accent } }) }),
4027
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Ouvrez un compte Ollaid" }),
4028
+ /* @__PURE__ */ jsx(DialogDescription, { children: "Un compte unique qui vous donne accès à toutes les applications" })
3883
4029
  ] }),
3884
- !isPhoneOnly && /* @__PURE__ */ jsxs("div", { children: [
3885
- /* @__PURE__ */ jsx(Label, { children: "Adresse email" }),
3886
- /* @__PURE__ */ jsx(Input, { type: "email", placeholder: "vous@exemple.com", value: formData.email || "", onChange: (e) => updateFormData({ email: e.target.value }), disabled: regLoading })
4030
+ /* @__PURE__ */ jsxs(DialogBody, { children: [
4031
+ /* @__PURE__ */ jsx(AppsLogoSlider, { iamApiUrl }),
4032
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "0.75rem", fontSize: "0.875rem", color: C$1.gray500, margin: "0.75rem 0" }, children: ["Un seul compte pour toutes les applications", "Plus besoin de multiples mots de passe", "Connexion simplifiée et sécurisée"].map((text) => /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.75rem" }, children: [
4033
+ /* @__PURE__ */ jsx(IconCheckCircle2, { style: { width: "1.25rem", height: "1.25rem", color: C$1.green, flexShrink: 0 } }),
4034
+ text
4035
+ ] }, text)) }),
4036
+ /* @__PURE__ */ jsx(StepIndicator, { current: 1 })
3887
4037
  ] }),
3888
- /* @__PURE__ */ jsxs("div", { children: [
3889
- /* @__PURE__ */ jsx(Label, { children: "Numéro de téléphone" }),
3890
- /* @__PURE__ */ jsx(PhoneInput, { value: formData.phone || "", onChange: (p) => updateFormData({ phone: p }), ccphone: formData.ccphone || "+221", onCcphoneChange: (c) => updateFormData({ ccphone: c }), disabled: regLoading, lockCcphone: isPhoneOnly })
4038
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [
4039
+ /* @__PURE__ */ jsx(Button, { onClick: () => goToStep("account-type"), style: { width: "100%" }, children: "Suivant →" }),
4040
+ /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", fontSize: "0.875rem" }, children: [
4041
+ /* @__PURE__ */ jsx("span", { style: { color: C$1.gray500 }, children: "Déjà un compte ? " }),
4042
+ /* @__PURE__ */ jsx("button", { type: "button", style: linkStyle, onClick: onSwitchToLogin, children: "Connectez-vous" })
4043
+ ] })
4044
+ ] })
4045
+ ] }),
4046
+ step === "account-type" && /* @__PURE__ */ jsxs(Fragment, { children: [
4047
+ /* @__PURE__ */ jsx("button", { onClick: () => goToStep("intro"), style: backBtnStyle, type: "button", children: /* @__PURE__ */ jsx(IconArrowLeft, { style: { width: "1rem", height: "1rem" } }) }),
4048
+ /* @__PURE__ */ jsxs(DialogHeader, { style: { textAlign: "center" }, children: [
4049
+ /* @__PURE__ */ jsx("div", { style: iconCircle(C$1.gray100), children: /* @__PURE__ */ jsx(IconShieldCheck, { style: { width: "1.5rem", height: "1.5rem", color: C$1.primary } }) }),
4050
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Choisissez votre type de compte" })
3891
4051
  ] }),
3892
- /* @__PURE__ */ jsxs("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "0.75rem" }, children: [
3893
- /* @__PURE__ */ jsxs("div", { children: [
3894
- /* @__PURE__ */ jsx(Label, { children: "Ville" }),
3895
- /* @__PURE__ */ jsx(Input, { placeholder: "Dakar", value: formData.town || "", onChange: (e) => updateFormData({ town: e.target.value }), disabled: regLoading })
4052
+ /* @__PURE__ */ jsxs(DialogBody, { children: [
4053
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
4054
+ /* @__PURE__ */ jsxs(
4055
+ "button",
4056
+ {
4057
+ type: "button",
4058
+ onClick: () => handleAccountTypeSelect("email"),
4059
+ style: { width: "100%", padding: "1rem", border: `2px solid ${C$1.gray200}`, borderRadius: "0.5rem", textAlign: "left", cursor: "pointer", background: C$1.white, display: "flex", alignItems: "center", gap: "0.75rem" },
4060
+ children: [
4061
+ /* @__PURE__ */ jsx("div", { style: { width: "2.5rem", height: "2.5rem", backgroundColor: C$1.accent, borderRadius: "0.5rem", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }, children: /* @__PURE__ */ jsx(IconMail, { style: { width: "1.25rem", height: "1.25rem", color: C$1.white } }) }),
4062
+ /* @__PURE__ */ jsxs("div", { children: [
4063
+ /* @__PURE__ */ jsx("div", { style: { fontWeight: 600, color: C$1.gray900 }, children: "Email + Téléphone" }),
4064
+ /* @__PURE__ */ jsx("div", { style: { fontSize: "0.875rem", color: C$1.gray500 }, children: "Compte complet" })
4065
+ ] })
4066
+ ]
4067
+ }
4068
+ ),
4069
+ /* @__PURE__ */ jsxs(
4070
+ "button",
4071
+ {
4072
+ type: "button",
4073
+ onClick: () => handleAccountTypeSelect("phone-only"),
4074
+ style: { width: "100%", padding: "1rem", border: `2px solid ${C$1.gray200}`, borderRadius: "0.5rem", textAlign: "left", cursor: "pointer", background: C$1.white, display: "flex", alignItems: "center", gap: "0.75rem" },
4075
+ children: [
4076
+ /* @__PURE__ */ jsx("div", { style: { width: "2.5rem", height: "2.5rem", backgroundColor: C$1.accent, borderRadius: "0.5rem", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }, children: /* @__PURE__ */ jsx(IconSmartphone, { style: { width: "1.25rem", height: "1.25rem", color: C$1.white } }) }),
4077
+ /* @__PURE__ */ jsxs("div", { children: [
4078
+ /* @__PURE__ */ jsx("div", { style: { fontWeight: 600, color: C$1.gray900 }, children: "Téléphone uniquement" }),
4079
+ /* @__PURE__ */ jsx("div", { style: { fontSize: "0.875rem", color: C$1.gray500 }, children: "🇸🇳 Sénégal uniquement" })
4080
+ ] })
4081
+ ]
4082
+ }
4083
+ )
3896
4084
  ] }),
3897
- /* @__PURE__ */ jsxs("div", { children: [
3898
- /* @__PURE__ */ jsx(Label, { children: "Pays" }),
3899
- /* @__PURE__ */ jsx(
3900
- "select",
4085
+ /* @__PURE__ */ jsx(StepIndicator, { current: 2 })
4086
+ ] })
4087
+ ] }),
4088
+ step === "info" && /* @__PURE__ */ jsxs(Fragment, { children: [
4089
+ /* @__PURE__ */ jsx("button", { onClick: () => goToStep("account-type"), style: backBtnStyle, type: "button", children: /* @__PURE__ */ jsx(IconArrowLeft, { style: { width: "1rem", height: "1rem" } }) }),
4090
+ conflict ? /* @__PURE__ */ jsxs(Fragment, { children: [
4091
+ /* @__PURE__ */ jsxs(DialogHeader, { style: { textAlign: "center" }, children: [
4092
+ /* @__PURE__ */ jsx("div", { style: iconCircle(C$1.amberBg), children: /* @__PURE__ */ jsx(IconShieldCheck, { style: { width: "1.5rem", height: "1.5rem", color: C$1.amber } }) }),
4093
+ /* @__PURE__ */ jsx(DialogTitle, { children: conflict.type === "phone" ? "Numéro déjà utilisé" : "Email déjà utilisé" }),
4094
+ /* @__PURE__ */ jsxs(DialogDescription, { children: [
4095
+ conflict.type === "phone" ? `Le numéro ${formData.ccphone || ""} ${formData.phone || ""} est déjà associé à un compte.` : `L'adresse ${formData.email || ""} est déjà associée à un compte.`,
4096
+ " ",
4097
+ "S'il s'agit du vôtre, connectez-vous."
4098
+ ] })
4099
+ ] }),
4100
+ /* @__PURE__ */ jsxs(DialogFooter, { style: { borderTop: "none" }, children: [
4101
+ conflict.type === "phone" && formData.ccphone === "+221" && ((_a = conflict.options) == null ? void 0 : _a.can_login) && /* @__PURE__ */ jsxs(
4102
+ Button,
3901
4103
  {
3902
- value: formData.country || DEFAULT_COUNTRY_CODE,
3903
- onChange: (e) => {
3904
- const country = getCountryByCode(e.target.value);
3905
- updateFormData({ country: e.target.value, ccphone: (country == null ? void 0 : country.dialCode) || "+221" });
4104
+ onClick: () => {
4105
+ const fullPhone = formData.phone || "";
4106
+ if (onSwitchToLoginWithPhone) onSwitchToLoginWithPhone(fullPhone);
4107
+ else onSwitchToLogin();
3906
4108
  },
3907
- disabled: regLoading || isPhoneOnly,
3908
- style: { width: "100%", padding: "0.5rem", borderRadius: "0.375rem", border: "1px solid #d1d5db", backgroundColor: regLoading || isPhoneOnly ? "#f3f4f6" : "white", fontSize: "0.875rem" },
3909
- children: COUNTRIES.map((c) => /* @__PURE__ */ jsxs("option", { value: c.code, children: [
3910
- c.flag,
3911
- " ",
3912
- c.name
3913
- ] }, c.code))
4109
+ style: { width: "100%" },
4110
+ children: [
4111
+ /* @__PURE__ */ jsx(IconSmartphone, { style: { width: "1rem", height: "1rem" } }),
4112
+ "Se connecter par téléphone"
4113
+ ]
3914
4114
  }
3915
- )
4115
+ ),
4116
+ (conflict.type === "email" || conflict.type === "phone" && formData.ccphone !== "+221") && ((_b = conflict.options) == null ? void 0 : _b.can_login) && /* @__PURE__ */ jsx(Button, { onClick: onSwitchToLogin, style: { width: "100%" }, children: "Se connecter" }),
4117
+ !isPhoneOnly && (((_c = conflict.options) == null ? void 0 : _c.can_recover_by_email) || ((_d = conflict.options) == null ? void 0 : _d.can_recover_by_sms)) && /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => setShowPasswordRecovery(true), style: { width: "100%" }, children: "Récupérer mon compte" }),
4118
+ /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => clearError(), style: { width: "100%" }, children: conflict.type === "phone" ? "Changer le numéro" : "Changer l'email" }),
4119
+ ((_e = conflict.options) == null ? void 0 : _e.masked_email) && /* @__PURE__ */ jsxs("div", { style: { padding: "0.75rem", backgroundColor: C$1.gray100, borderRadius: "0.375rem", fontSize: "0.8125rem", color: C$1.gray500, textAlign: "center" }, children: [
4120
+ "Email lié : ",
4121
+ /* @__PURE__ */ jsx("strong", { style: { color: C$1.gray900 }, children: conflict.options.masked_email })
4122
+ ] }),
4123
+ ((_f = conflict.options) == null ? void 0 : _f.masked_phone) && /* @__PURE__ */ jsxs("div", { style: { padding: "0.75rem", backgroundColor: C$1.gray100, borderRadius: "0.375rem", fontSize: "0.8125rem", color: C$1.gray500, textAlign: "center" }, children: [
4124
+ "Téléphone lié : ",
4125
+ /* @__PURE__ */ jsx("strong", { style: { color: C$1.gray900 }, children: conflict.options.masked_phone })
4126
+ ] })
3916
4127
  ] })
3917
- ] }),
3918
- /* @__PURE__ */ jsx(StepIndicator, { current: 3 }),
3919
- /* @__PURE__ */ jsx(Button, { type: "submit", disabled: regLoading, style: { width: "100%" }, children: regLoading ? /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
3920
- /* @__PURE__ */ jsx(IconLoader2, { style: { width: "1rem", height: "1rem" } }),
3921
- " Vérification..."
3922
- ] }) : "Continuer" })
3923
- ] })
3924
- ] }),
3925
- step === "otp" && /* @__PURE__ */ jsxs(Fragment, { children: [
3926
- /* @__PURE__ */ jsx("button", { onClick: () => goToStep("info"), style: backBtnStyle, type: "button", children: /* @__PURE__ */ jsx(IconArrowLeft, { style: { width: "1rem", height: "1rem" } }) }),
3927
- /* @__PURE__ */ jsxs(DialogHeader, { style: { textAlign: "center" }, children: [
3928
- /* @__PURE__ */ jsx("div", { style: iconCircle(C$1.accent), children: /* @__PURE__ */ jsx(IconKeyRound, { style: { width: "1.5rem", height: "1.5rem", color: C$1.white } }) }),
3929
- /* @__PURE__ */ jsx(DialogTitle, { children: "Vérification" }),
3930
- /* @__PURE__ */ jsxs(DialogDescription, { children: [
3931
- "Entrez le code envoyé ",
3932
- isPhoneOnly ? `au ${formData.ccphone} ${formData.phone}` : `à ${formData.email}`
3933
- ] })
4128
+ ] }) : (
4129
+ /* ---- NORMAL INFO FORM ---- */
4130
+ /* @__PURE__ */ jsxs(Fragment, { children: [
4131
+ /* @__PURE__ */ jsxs(DialogHeader, { style: { textAlign: "center" }, children: [
4132
+ /* @__PURE__ */ jsx("div", { style: iconCircle(C$1.primary + "1a"), children: /* @__PURE__ */ jsx(IconShieldCheck, { style: { width: "1.5rem", height: "1.5rem", color: C$1.primary } }) }),
4133
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Créer votre compte" })
4134
+ ] }),
4135
+ /* @__PURE__ */ jsxs("form", { onSubmit: handleInfoSubmit, style: { display: "flex", flexDirection: "column", flex: 1, minHeight: 0 }, children: [
4136
+ /* @__PURE__ */ jsxs(DialogBody, { children: [
4137
+ isPhoneOnly && /* @__PURE__ */ jsx("div", { style: { padding: "0.75rem", borderRadius: "0.375rem", backgroundColor: C$1.accent + "1a", color: C$1.accent, fontSize: "0.8125rem", marginBottom: "0.5rem", textAlign: "center" }, children: "📱 Inscription par téléphone — 🇸🇳 Sénégal uniquement" }),
4138
+ !isPhoneOnly && /* @__PURE__ */ jsx("div", { style: { padding: "0.75rem", borderRadius: "0.375rem", backgroundColor: C$1.amberBg, color: "#92400e", fontSize: "0.8125rem", marginBottom: "0.5rem", textAlign: "center" }, children: "⚠️ Un code OTP sera envoyé par email pour vérification" }),
4139
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
4140
+ renderError(),
4141
+ /* @__PURE__ */ jsxs("div", { children: [
4142
+ /* @__PURE__ */ jsxs(Label, { children: [
4143
+ "Nom complet ",
4144
+ /* @__PURE__ */ jsx("span", { style: { color: C$1.red }, children: "*" })
4145
+ ] }),
4146
+ /* @__PURE__ */ jsx(Input, { placeholder: "Jean Dupont", value: formData.name || "", onChange: (e) => updateFormData({ name: e.target.value }), disabled: regLoading })
4147
+ ] }),
4148
+ !isPhoneOnly && /* @__PURE__ */ jsxs("div", { children: [
4149
+ /* @__PURE__ */ jsxs(Label, { children: [
4150
+ "Adresse email ",
4151
+ /* @__PURE__ */ jsx("span", { style: { color: C$1.red }, children: "*" })
4152
+ ] }),
4153
+ /* @__PURE__ */ jsx(Input, { type: "email", placeholder: "vous@exemple.com", value: formData.email || "", onChange: (e) => updateFormData({ email: e.target.value }), disabled: regLoading })
4154
+ ] }),
4155
+ /* @__PURE__ */ jsxs("div", { children: [
4156
+ /* @__PURE__ */ jsxs(Label, { children: [
4157
+ "Numéro de téléphone ",
4158
+ /* @__PURE__ */ jsx("span", { style: { color: C$1.red }, children: "*" })
4159
+ ] }),
4160
+ /* @__PURE__ */ jsx(PhoneInput, { value: formData.phone || "", onChange: (p) => updateFormData({ phone: p }), ccphone: formData.ccphone || "+221", onCcphoneChange: (c) => updateFormData({ ccphone: c }), disabled: regLoading, lockCcphone: isPhoneOnly })
4161
+ ] }),
4162
+ /* @__PURE__ */ jsxs("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "0.75rem" }, children: [
4163
+ /* @__PURE__ */ jsxs("div", { children: [
4164
+ /* @__PURE__ */ jsxs(Label, { children: [
4165
+ "Ville ",
4166
+ /* @__PURE__ */ jsx("span", { style: { color: C$1.red }, children: "*" })
4167
+ ] }),
4168
+ /* @__PURE__ */ jsx(Input, { placeholder: "Dakar", value: formData.town || "", onChange: (e) => updateFormData({ town: e.target.value }), disabled: regLoading })
4169
+ ] }),
4170
+ /* @__PURE__ */ jsxs("div", { children: [
4171
+ /* @__PURE__ */ jsxs(Label, { children: [
4172
+ "Pays ",
4173
+ /* @__PURE__ */ jsx("span", { style: { color: C$1.red }, children: "*" })
4174
+ ] }),
4175
+ /* @__PURE__ */ jsx(
4176
+ "select",
4177
+ {
4178
+ value: formData.country || DEFAULT_COUNTRY_CODE,
4179
+ onChange: (e) => {
4180
+ const country = getCountryByCode(e.target.value);
4181
+ updateFormData({ country: e.target.value, ccphone: (country == null ? void 0 : country.dialCode) || "+221" });
4182
+ },
4183
+ disabled: regLoading || isPhoneOnly,
4184
+ style: { width: "100%", padding: "0.5rem", borderRadius: "0.375rem", border: "1px solid #d1d5db", backgroundColor: regLoading || isPhoneOnly ? "#f3f4f6" : "white", fontSize: "0.875rem" },
4185
+ children: COUNTRIES_SORTED_BY_CODE.map((c) => /* @__PURE__ */ jsxs("option", { value: c.code, children: [
4186
+ c.code,
4187
+ " ",
4188
+ c.flag,
4189
+ " ",
4190
+ c.name
4191
+ ] }, c.code))
4192
+ }
4193
+ )
4194
+ ] })
4195
+ ] }),
4196
+ /* @__PURE__ */ jsx(StepIndicator, { current: 3 })
4197
+ ] })
4198
+ ] }),
4199
+ /* @__PURE__ */ jsx(DialogFooter, { children: /* @__PURE__ */ jsx(Button, { type: "submit", disabled: regLoading, style: { width: "100%" }, children: regLoading ? /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
4200
+ /* @__PURE__ */ jsx(IconLoader2, { style: { width: "1rem", height: "1rem" } }),
4201
+ " Vérification..."
4202
+ ] }) : "Continuer" }) })
4203
+ ] })
4204
+ ] })
4205
+ )
3934
4206
  ] }),
3935
- /* @__PURE__ */ jsxs("div", { style: { marginTop: "1rem", display: "flex", flexDirection: "column", gap: "1rem" }, children: [
3936
- renderError(),
3937
- /* @__PURE__ */ jsx(OTPInput, { value: otpCode, onChange: setOtpCode, disabled: regLoading }),
3938
- /* @__PURE__ */ jsx("div", { style: { textAlign: "center", fontSize: "0.875rem" }, children: resendCooldown > 0 ? /* @__PURE__ */ jsxs("span", { style: { color: C$1.gray500 }, children: [
3939
- "Renvoyer dans ",
3940
- resendCooldown,
3941
- "s"
3942
- ] }) : /* @__PURE__ */ jsx("button", { type: "button", onClick: handleResendOTP, style: linkStyle, children: "Code non reçu ? Renvoyer" }) }),
3943
- /* @__PURE__ */ jsx(StepIndicator, { current: 4 }),
3944
- /* @__PURE__ */ jsx(Button, { onClick: handleOTPSubmit, disabled: regLoading || otpCode.length !== 6, style: { width: "100%" }, children: regLoading ? /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
4207
+ step === "otp" && /* @__PURE__ */ jsxs(Fragment, { children: [
4208
+ /* @__PURE__ */ jsx("button", { onClick: () => goToStep("info"), style: backBtnStyle, type: "button", children: /* @__PURE__ */ jsx(IconArrowLeft, { style: { width: "1rem", height: "1rem" } }) }),
4209
+ /* @__PURE__ */ jsxs(DialogHeader, { style: { textAlign: "center" }, children: [
4210
+ /* @__PURE__ */ jsx("div", { style: iconCircle(C$1.accent), children: /* @__PURE__ */ jsx(IconKeyRound, { style: { width: "1.5rem", height: "1.5rem", color: C$1.white } }) }),
4211
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Vérification" }),
4212
+ /* @__PURE__ */ jsxs(DialogDescription, { children: [
4213
+ "Entrez le code envoyé ",
4214
+ isPhoneOnly ? `au ${formData.ccphone} ${formData.phone}` : ${formData.email}`
4215
+ ] })
4216
+ ] }),
4217
+ /* @__PURE__ */ jsx(DialogBody, { children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "1rem" }, children: [
4218
+ renderError(),
4219
+ /* @__PURE__ */ jsx(OTPInput, { value: otpCode, onChange: setOtpCode, disabled: regLoading }),
4220
+ /* @__PURE__ */ jsx("div", { style: { textAlign: "center", fontSize: "0.875rem" }, children: resendCooldown > 0 ? /* @__PURE__ */ jsxs("span", { style: { color: C$1.gray500 }, children: [
4221
+ "Renvoyer dans ",
4222
+ resendCooldown,
4223
+ "s"
4224
+ ] }) : /* @__PURE__ */ jsx("button", { type: "button", onClick: handleResendOTP, style: linkStyle, children: "Code non reçu ? Renvoyer" }) }),
4225
+ /* @__PURE__ */ jsx(StepIndicator, { current: 4 })
4226
+ ] }) }),
4227
+ /* @__PURE__ */ jsx(DialogFooter, { children: /* @__PURE__ */ jsx(Button, { onClick: handleOTPSubmit, disabled: regLoading || otpCode.length !== 6, style: { width: "100%" }, children: regLoading ? /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
3945
4228
  /* @__PURE__ */ jsx(IconLoader2, { style: { width: "1rem", height: "1rem" } }),
3946
4229
  " Vérification..."
3947
- ] }) : "Vérifier" })
3948
- ] })
3949
- ] }),
3950
- step === "password" && /* @__PURE__ */ jsxs(Fragment, { children: [
3951
- /* @__PURE__ */ jsx("button", { onClick: () => goToStep("otp"), style: backBtnStyle, type: "button", children: /* @__PURE__ */ jsx(IconArrowLeft, { style: { width: "1rem", height: "1rem" } }) }),
3952
- /* @__PURE__ */ jsxs(DialogHeader, { style: { textAlign: "center" }, children: [
3953
- /* @__PURE__ */ jsx("div", { style: iconCircle(C$1.accent), children: /* @__PURE__ */ jsx(IconLock, { style: { width: "1.5rem", height: "1.5rem", color: C$1.white } }) }),
3954
- /* @__PURE__ */ jsx(DialogTitle, { children: "Créer un mot de passe" })
4230
+ ] }) : "Vérifier" }) })
3955
4231
  ] }),
3956
- /* @__PURE__ */ jsxs("form", { onSubmit: handlePasswordSubmit, style: { display: "flex", flexDirection: "column", gap: "0.75rem", marginTop: "0.75rem" }, children: [
3957
- renderError(),
3958
- /* @__PURE__ */ jsxs("div", { children: [
3959
- /* @__PURE__ */ jsx(Label, { children: "Mot de passe" }),
3960
- /* @__PURE__ */ jsx(Input, { type: "password", placeholder: "Minimum 8 caractères", value: password, onChange: (e) => setPassword(e.target.value), disabled: regLoading })
3961
- ] }),
3962
- /* @__PURE__ */ jsxs("div", { children: [
3963
- /* @__PURE__ */ jsx(Label, { children: "Confirmer le mot de passe" }),
3964
- /* @__PURE__ */ jsx(Input, { type: "password", placeholder: "••••••••", value: passwordConfirm, onChange: (e) => setPasswordConfirm(e.target.value), disabled: regLoading })
4232
+ step === "password" && /* @__PURE__ */ jsxs(Fragment, { children: [
4233
+ /* @__PURE__ */ jsx("button", { onClick: () => goToStep("otp"), style: backBtnStyle, type: "button", children: /* @__PURE__ */ jsx(IconArrowLeft, { style: { width: "1rem", height: "1rem" } }) }),
4234
+ /* @__PURE__ */ jsxs(DialogHeader, { style: { textAlign: "center" }, children: [
4235
+ /* @__PURE__ */ jsx("div", { style: iconCircle(C$1.accent), children: /* @__PURE__ */ jsx(IconLock, { style: { width: "1.5rem", height: "1.5rem", color: C$1.white } }) }),
4236
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Créer un mot de passe" })
3965
4237
  ] }),
3966
- /* @__PURE__ */ jsx(StepIndicator, { current: 5 }),
3967
- /* @__PURE__ */ jsx(Button, { type: "submit", disabled: regLoading, style: { width: "100%" }, children: "Continuer" })
3968
- ] })
3969
- ] }),
3970
- step === "confirm" && /* @__PURE__ */ jsxs(Fragment, { children: [
3971
- /* @__PURE__ */ jsx("button", { onClick: () => goToStep("password"), style: backBtnStyle, type: "button", children: /* @__PURE__ */ jsx(IconArrowLeft, { style: { width: "1rem", height: "1rem" } }) }),
3972
- /* @__PURE__ */ jsxs(DialogHeader, { style: { textAlign: "center" }, children: [
3973
- /* @__PURE__ */ jsx("div", { style: iconCircle(C$1.primary + "1a"), children: /* @__PURE__ */ jsx(IconShieldCheck, { style: { width: "1.5rem", height: "1.5rem", color: C$1.primary } }) }),
3974
- /* @__PURE__ */ jsx(DialogTitle, { children: "Confirmer votre inscription" })
4238
+ /* @__PURE__ */ jsxs("form", { onSubmit: handlePasswordSubmit, style: { display: "flex", flexDirection: "column", flex: 1, minHeight: 0 }, children: [
4239
+ /* @__PURE__ */ jsx(DialogBody, { children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
4240
+ renderError(),
4241
+ /* @__PURE__ */ jsxs("div", { children: [
4242
+ /* @__PURE__ */ jsx(Label, { children: "Mot de passe" }),
4243
+ /* @__PURE__ */ jsx(Input, { type: "password", placeholder: "Minimum 8 caractères", value: password, onChange: (e) => setPassword(e.target.value), disabled: regLoading })
4244
+ ] }),
4245
+ /* @__PURE__ */ jsxs("div", { children: [
4246
+ /* @__PURE__ */ jsx(Label, { children: "Confirmer le mot de passe" }),
4247
+ /* @__PURE__ */ jsx(Input, { type: "password", placeholder: "••••••••", value: passwordConfirm, onChange: (e) => setPasswordConfirm(e.target.value), disabled: regLoading })
4248
+ ] }),
4249
+ /* @__PURE__ */ jsx(StepIndicator, { current: 5 })
4250
+ ] }) }),
4251
+ /* @__PURE__ */ jsx(DialogFooter, { children: /* @__PURE__ */ jsx(Button, { type: "submit", disabled: regLoading, style: { width: "100%" }, children: "Continuer" }) })
4252
+ ] })
3975
4253
  ] }),
3976
- /* @__PURE__ */ jsxs("div", { style: { marginTop: "1rem", display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
3977
- renderError(),
3978
- /* @__PURE__ */ jsx("div", { style: { backgroundColor: C$1.gray100, borderRadius: "0.5rem", padding: "1rem" }, children: [["Nom", formData.name], ...!isPhoneOnly ? [["Email", formData.email]] : [], ["Téléphone", `${formData.ccphone} ${formData.phone}`], ["Ville", formData.town], ["Pays", formData.country]].map(([label, value]) => /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", padding: "0.375rem 0" }, children: [
3979
- /* @__PURE__ */ jsx("span", { style: { fontSize: "0.875rem", color: C$1.gray500 }, children: label }),
3980
- /* @__PURE__ */ jsx("span", { style: { fontSize: "0.875rem", fontWeight: 500 }, children: value })
3981
- ] }, label)) }),
3982
- /* @__PURE__ */ jsx(StepIndicator, { current: 6 }),
3983
- /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, disabled: regLoading, style: { width: "100%" }, children: regLoading ? /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
4254
+ step === "confirm" && /* @__PURE__ */ jsxs(Fragment, { children: [
4255
+ /* @__PURE__ */ jsx("button", { onClick: () => goToStep("password"), style: backBtnStyle, type: "button", children: /* @__PURE__ */ jsx(IconArrowLeft, { style: { width: "1rem", height: "1rem" } }) }),
4256
+ /* @__PURE__ */ jsxs(DialogHeader, { style: { textAlign: "center" }, children: [
4257
+ /* @__PURE__ */ jsx("div", { style: iconCircle(C$1.primary + "1a"), children: /* @__PURE__ */ jsx(IconShieldCheck, { style: { width: "1.5rem", height: "1.5rem", color: C$1.primary } }) }),
4258
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Confirmer votre inscription" })
4259
+ ] }),
4260
+ /* @__PURE__ */ jsx(DialogBody, { children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
4261
+ renderError(),
4262
+ /* @__PURE__ */ jsx("div", { style: { backgroundColor: C$1.gray100, borderRadius: "0.5rem", padding: "1rem" }, children: [["Nom", formData.name], ...!isPhoneOnly ? [["Email", formData.email]] : [], ["Téléphone", `${formData.ccphone} ${formData.phone}`], ["Ville", formData.town], ["Pays", formData.country]].map(([label, value]) => /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", padding: "0.375rem 0" }, children: [
4263
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "0.875rem", color: C$1.gray500 }, children: label }),
4264
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "0.875rem", fontWeight: 500 }, children: value })
4265
+ ] }, label)) }),
4266
+ /* @__PURE__ */ jsx(StepIndicator, { current: 6 })
4267
+ ] }) }),
4268
+ /* @__PURE__ */ jsx(DialogFooter, { children: /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, disabled: regLoading, style: { width: "100%" }, children: regLoading ? /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
3984
4269
  /* @__PURE__ */ jsx(IconLoader2, { style: { width: "1rem", height: "1rem" } }),
3985
4270
  " Création du compte..."
3986
- ] }) : "Créer mon compte" })
4271
+ ] }) : "Créer mon compte" }) })
3987
4272
  ] })
3988
- ] })
3989
- ] }) }) });
4273
+ ] }) }) }),
4274
+ /* @__PURE__ */ jsx(
4275
+ PasswordRecoveryModal,
4276
+ {
4277
+ open: showPasswordRecovery,
4278
+ onOpenChange: setShowPasswordRecovery,
4279
+ onSuccess: () => setShowPasswordRecovery(false),
4280
+ saasApiUrl,
4281
+ iamApiUrl
4282
+ }
4283
+ )
4284
+ ] });
3990
4285
  }
3991
4286
  const C = {
3992
4287
  primary: "#002147",
@@ -4053,7 +4348,7 @@ function OnboardingModal({ open, onOpenChange, user, onComplete, onSkip }) {
4053
4348
  ] }),
4054
4349
  /* @__PURE__ */ jsx(DialogDescription, { children: "Ajoutez les informations manquantes pour finaliser votre compte." })
4055
4350
  ] }),
4056
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "1.25rem", marginTop: "1rem" }, children: [
4351
+ /* @__PURE__ */ jsx(DialogBody, { children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "1.25rem", marginTop: "0.75rem" }, children: [
4057
4352
  needsPhoto && /* @__PURE__ */ jsxs("div", { children: [
4058
4353
  /* @__PURE__ */ jsx(Label, { style: { display: "block", marginBottom: "0.5rem", color: C.gray700, fontWeight: 500 }, children: "Photo de profil" }),
4059
4354
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "1rem" }, children: [
@@ -4085,15 +4380,7 @@ function OnboardingModal({ open, onOpenChange, user, onComplete, onSkip }) {
4085
4380
  fontWeight: 500
4086
4381
  }, children: [
4087
4382
  "Choisir une photo",
4088
- /* @__PURE__ */ jsx(
4089
- "input",
4090
- {
4091
- type: "file",
4092
- accept: "image/*",
4093
- onChange: handleFileChange,
4094
- style: { display: "none" }
4095
- }
4096
- )
4383
+ /* @__PURE__ */ jsx("input", { type: "file", accept: "image/*", onChange: handleFileChange, style: { display: "none" } })
4097
4384
  ] }),
4098
4385
  /* @__PURE__ */ jsx("p", { style: { fontSize: "0.75rem", color: fileError ? "#dc2626" : C.gray500, marginTop: "0.25rem" }, children: fileError || "JPG, PNG. Max 2 Mo." })
4099
4386
  ] })
@@ -4101,15 +4388,7 @@ function OnboardingModal({ open, onOpenChange, user, onComplete, onSkip }) {
4101
4388
  ] }),
4102
4389
  needsPhone && /* @__PURE__ */ jsxs("div", { children: [
4103
4390
  /* @__PURE__ */ jsx(Label, { style: { display: "block", marginBottom: "0.5rem", color: C.gray700, fontWeight: 500 }, children: "Numéro de téléphone" }),
4104
- /* @__PURE__ */ jsx(
4105
- PhoneInput,
4106
- {
4107
- value: phone,
4108
- onChange: setPhone,
4109
- ccphone,
4110
- onCcphoneChange: setCcphone
4111
- }
4112
- )
4391
+ /* @__PURE__ */ jsx(PhoneInput, { value: phone, onChange: setPhone, ccphone, onCcphoneChange: setCcphone })
4113
4392
  ] }),
4114
4393
  needsEmail && /* @__PURE__ */ jsxs("div", { children: [
4115
4394
  /* @__PURE__ */ jsxs(Label, { style: { display: "block", marginBottom: "0.5rem", color: C.gray700, fontWeight: 500 }, children: [
@@ -4151,38 +4430,32 @@ function OnboardingModal({ open, onOpenChange, user, onComplete, onSkip }) {
4151
4430
  type: "checkbox",
4152
4431
  checked: confirmed,
4153
4432
  onChange: (e) => setConfirmed(e.target.checked),
4154
- style: {
4155
- width: "1rem",
4156
- height: "1rem",
4157
- marginTop: "0.125rem",
4158
- accentColor: C.primary,
4159
- cursor: "pointer"
4160
- }
4433
+ style: { width: "1rem", height: "1rem", marginTop: "0.125rem", accentColor: C.primary, cursor: "pointer" }
4161
4434
  }
4162
4435
  ),
4163
4436
  /* @__PURE__ */ jsx("span", { children: "Je confirme que ces informations sont exactes" })
4164
- ] }),
4165
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
4166
- /* @__PURE__ */ jsx(
4167
- Button,
4168
- {
4169
- onClick: handleSubmit,
4170
- disabled: !canSubmit || submitting,
4171
- style: { width: "100%", height: "2.75rem", opacity: canSubmit && !submitting ? 1 : 0.5 },
4172
- children: submitting ? "Enregistrement..." : "Valider"
4173
- }
4174
- ),
4175
- /* @__PURE__ */ jsx(
4176
- Button,
4177
- {
4178
- variant: "outline",
4179
- onClick: onSkip,
4180
- disabled: submitting,
4181
- style: { width: "100%", height: "2.75rem" },
4182
- children: "Passer pour l'instant"
4183
- }
4184
- )
4185
4437
  ] })
4438
+ ] }) }),
4439
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [
4440
+ /* @__PURE__ */ jsx(
4441
+ Button,
4442
+ {
4443
+ onClick: handleSubmit,
4444
+ disabled: !canSubmit || submitting,
4445
+ style: { width: "100%", height: "2.75rem", opacity: canSubmit && !submitting ? 1 : 0.5 },
4446
+ children: submitting ? "Enregistrement..." : "Valider"
4447
+ }
4448
+ ),
4449
+ /* @__PURE__ */ jsx(
4450
+ Button,
4451
+ {
4452
+ variant: "outline",
4453
+ onClick: onSkip,
4454
+ disabled: submitting,
4455
+ style: { width: "100%", height: "2.75rem" },
4456
+ children: "Passer pour l'instant"
4457
+ }
4458
+ )
4186
4459
  ] })
4187
4460
  ] }) });
4188
4461
  }
@@ -4433,6 +4706,7 @@ function NativeSSOPage({
4433
4706
  redirectAfterLogout
4434
4707
  }) {
4435
4708
  const [modal, setModal] = useState("none");
4709
+ const [loginInitialPhone, setLoginInitialPhone] = useState();
4436
4710
  const [showOnboarding, setShowOnboarding] = useState(false);
4437
4711
  const [pendingSession, setPendingSession] = useState(null);
4438
4712
  const [session, setSession] = useState(() => {
@@ -4474,13 +4748,23 @@ function NativeSSOPage({
4474
4748
  }, []);
4475
4749
  const openLogin = useCallback(() => setModal("login"), []);
4476
4750
  const openSignup = useCallback(() => setModal("signup"), []);
4477
- const closeModal = useCallback(() => setModal("none"), []);
4751
+ const closeModal = useCallback(() => {
4752
+ setModal("none");
4753
+ setLoginInitialPhone(void 0);
4754
+ }, []);
4478
4755
  const switchToSignup = useCallback(() => {
4479
4756
  setModal("none");
4757
+ setLoginInitialPhone(void 0);
4480
4758
  setTimeout(() => setModal("signup"), 150);
4481
4759
  }, []);
4482
4760
  const switchToLogin = useCallback(() => {
4483
4761
  setModal("none");
4762
+ setLoginInitialPhone(void 0);
4763
+ setTimeout(() => setModal("login"), 150);
4764
+ }, []);
4765
+ const switchToLoginWithPhone = useCallback((phone) => {
4766
+ setModal("none");
4767
+ setLoginInitialPhone(phone);
4484
4768
  setTimeout(() => setModal("login"), 150);
4485
4769
  }, []);
4486
4770
  const handleLoginSuccess = useCallback((token, user) => {
@@ -4522,12 +4806,8 @@ function NativeSSOPage({
4522
4806
  onLoginSuccess == null ? void 0 : onLoginSuccess(pendingSession.token, pendingSession.user);
4523
4807
  if (redirectAfterLogin) window.location.href = redirectAfterLogin;
4524
4808
  }, [pendingSession, onLoginSuccess, redirectAfterLogin]);
4525
- const handleLogout = useCallback(() => {
4526
- localStorage.removeItem(STORAGE.AUTH_TOKEN);
4527
- localStorage.removeItem(STORAGE.TOKEN);
4528
- localStorage.removeItem(STORAGE.USER);
4529
- localStorage.removeItem(STORAGE.ACCOUNT_TYPE);
4530
- localStorage.removeItem(STORAGE.ALIAS_REFERENCE);
4809
+ const handleLogout = useCallback(async () => {
4810
+ await logout();
4531
4811
  setSession(null);
4532
4812
  onLogout == null ? void 0 : onLogout();
4533
4813
  if (redirectAfterLogout) window.location.href = redirectAfterLogout;
@@ -4631,7 +4911,8 @@ function NativeSSOPage({
4631
4911
  onLoginSuccess: handleLoginSuccess,
4632
4912
  saasApiUrl,
4633
4913
  iamApiUrl,
4634
- defaultAccountType: accountType
4914
+ defaultAccountType: accountType,
4915
+ initialPhone: loginInitialPhone
4635
4916
  }
4636
4917
  ),
4637
4918
  /* @__PURE__ */ jsx(
@@ -4642,6 +4923,7 @@ function NativeSSOPage({
4642
4923
  if (!open) closeModal();
4643
4924
  },
4644
4925
  onSwitchToLogin: switchToLogin,
4926
+ onSwitchToLoginWithPhone: switchToLoginWithPhone,
4645
4927
  onSignupSuccess: handleLoginSuccess,
4646
4928
  saasApiUrl,
4647
4929
  iamApiUrl,
@@ -4681,6 +4963,26 @@ function useNativeSSOConfig() {
4681
4963
  }
4682
4964
  return ctx;
4683
4965
  }
4966
+ const useLogout = (options) => {
4967
+ const [loading, setLoading] = useState(false);
4968
+ const [error, setError] = useState(null);
4969
+ const handleLogout = useCallback(async () => {
4970
+ var _a, _b;
4971
+ setLoading(true);
4972
+ setError(null);
4973
+ try {
4974
+ await logout();
4975
+ (_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options);
4976
+ } catch (err) {
4977
+ const message = err instanceof Error ? err.message : "Erreur de déconnexion";
4978
+ setError(message);
4979
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(options, err instanceof Error ? err : new Error(message));
4980
+ } finally {
4981
+ setLoading(false);
4982
+ }
4983
+ }, [options]);
4984
+ return { logout: handleLogout, loading, error };
4985
+ };
4684
4986
  function getCredentialsOrThrow(params) {
4685
4987
  const app_key = params.app_key;
4686
4988
  const secret_key = params.secret_key;
@@ -4851,10 +5153,12 @@ export {
4851
5153
  getDefaultCountry,
4852
5154
  getNativeAuthConfig,
4853
5155
  iamAccountService,
5156
+ logout,
4854
5157
  mobilePasswordService,
4855
5158
  nativeAuthService,
4856
5159
  searchCountries,
4857
5160
  setNativeAuthConfig,
5161
+ useLogout,
4858
5162
  useMobilePassword,
4859
5163
  useMobileRegistration,
4860
5164
  useNativeAuth,