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