@sanvika/auth 2.9.5 → 2.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +696 -75
  2. package/package.json +8 -2
package/dist/index.js CHANGED
@@ -16,11 +16,224 @@ var STORAGE_KEYS = {
16
16
  USER: "sanvika_user"
17
17
  };
18
18
  var DEFAULT_AVATAR_SVG = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 40'%3E%3Ccircle cx='20' cy='20' r='20' fill='%23e5e7eb'/%3E%3Ccircle cx='20' cy='15' r='7' fill='%23adb5bd'/%3E%3Cellipse cx='20' cy='35' rx='12' ry='8' fill='%23adb5bd'/%3E%3C/svg%3E`;
19
+ var AUTH_API = Object.freeze({
20
+ CHECK_MOBILE: "/api/auth/check-mobile",
21
+ LOGIN: "/api/auth/login",
22
+ LOGOUT: "/api/auth/logout",
23
+ VERIFY_TOKEN: "/api/auth/verify-token",
24
+ SEND_OTP: "/api/auth/send-otp",
25
+ VERIFY_OTP: "/api/auth/verify-otp",
26
+ AUTHORIZE: "/api/auth/authorize"
27
+ });
28
+ var CLIENT_MOBILE_POLICIES = Object.freeze({
29
+ freeadpostkaro: {
30
+ format: "SOUTH_ASIA_E164",
31
+ defaultCountryCode: "91",
32
+ allowedDialCodes: ["91", "92", "880"]
33
+ },
34
+ venerationlove: {
35
+ format: "E164",
36
+ defaultCountryCode: "91"
37
+ },
38
+ IN_10: {
39
+ format: "IN_10",
40
+ defaultCountryCode: "91",
41
+ allowedDialCodes: ["91"]
42
+ }
43
+ });
44
+
45
+ // mobilePolicy.js
46
+ var MOBILE_FORMAT = Object.freeze({
47
+ IN_10: "IN_10",
48
+ SOUTH_ASIA_E164: "SOUTH_ASIA_E164",
49
+ E164: "E164"
50
+ });
51
+ var DEFAULT_DIAL_CODES_SOUTH_ASIA = Object.freeze(["91", "92", "880"]);
52
+ var DEFAULT_MOBILE_POLICY = Object.freeze({
53
+ format: MOBILE_FORMAT.IN_10,
54
+ defaultCountryCode: "91",
55
+ allowedDialCodes: ["91"]
56
+ });
57
+ var E164_MIN_DIGITS = 7;
58
+ var E164_MAX_DIGITS = 15;
59
+ function digitsOnly(raw) {
60
+ return String(raw ?? "").replace(/\D/g, "");
61
+ }
62
+ function isValidIndiaNational(n10) {
63
+ return /^[6-9]\d{9}$/.test(n10);
64
+ }
65
+ function extractIndiaNational(d) {
66
+ let n = d;
67
+ if (n.startsWith("91") && n.length >= 12) n = n.slice(2);
68
+ if (n.length === 11 && n.startsWith("0")) n = n.slice(1);
69
+ if (n.length > 10) n = n.slice(-10);
70
+ if (!isValidIndiaNational(n)) return null;
71
+ return n;
72
+ }
73
+ function extractPakistanNational(d) {
74
+ let n = d;
75
+ if (n.startsWith("92") && n.length >= 12) n = n.slice(2);
76
+ if (n.length === 11 && n.startsWith("0")) n = n.slice(1);
77
+ if (n.length > 10) n = n.slice(-10);
78
+ if (n.length !== 10 || n[0] !== "3") return null;
79
+ return n;
80
+ }
81
+ function extractBangladeshNational(d) {
82
+ let n = d;
83
+ if (n.startsWith("880")) n = n.slice(3);
84
+ if (n.length === 11 && n.startsWith("0")) n = n.slice(1);
85
+ if (n.length > 10) n = n.slice(-10);
86
+ if (n.length !== 10 || n[0] !== "1") return null;
87
+ return n;
88
+ }
89
+ function mergeMobilePolicy(raw) {
90
+ if (!raw || typeof raw !== "object") {
91
+ return { ...DEFAULT_MOBILE_POLICY };
92
+ }
93
+ const format = Object.values(MOBILE_FORMAT).includes(raw.format) ? raw.format : DEFAULT_MOBILE_POLICY.format;
94
+ const explicitCodes = Array.isArray(raw.allowedDialCodes) ? raw.allowedDialCodes.map(String).filter(Boolean) : null;
95
+ const allowedDialCodes = (explicitCodes == null ? void 0 : explicitCodes.length) > 0 ? explicitCodes : format === MOBILE_FORMAT.SOUTH_ASIA_E164 ? [...DEFAULT_DIAL_CODES_SOUTH_ASIA] : format === MOBILE_FORMAT.E164 ? [] : ["91"];
96
+ const defaultCountryCode = raw.defaultCountryCode != null ? String(raw.defaultCountryCode).replace(/\D/g, "") : allowedDialCodes[0] || "91";
97
+ return {
98
+ format,
99
+ defaultCountryCode,
100
+ allowedDialCodes
101
+ };
102
+ }
103
+ function normalizeIn10(raw) {
104
+ return extractIndiaNational(digitsOnly(raw));
105
+ }
106
+ function normalizeSouthAsiaE164(raw, policy) {
107
+ var _a;
108
+ let d = digitsOnly(raw);
109
+ if (!d) return null;
110
+ if (d.startsWith("00") && d.length > 4) d = d.slice(2);
111
+ const allowed = ((_a = policy.allowedDialCodes) == null ? void 0 : _a.length) > 0 ? policy.allowedDialCodes : DEFAULT_DIAL_CODES_SOUTH_ASIA;
112
+ const byCode = [...allowed].sort((a, b) => b.length - a.length);
113
+ for (const code of byCode) {
114
+ if (!d.startsWith(code)) continue;
115
+ const rest = d.slice(code.length);
116
+ if (code === "91") {
117
+ const n = extractIndiaNational(rest.length >= 10 ? rest : d);
118
+ if (n) return `91${n}`;
119
+ }
120
+ if (code === "92") {
121
+ const n = extractPakistanNational(rest.length >= 10 ? rest : d);
122
+ if (n) return `92${n}`;
123
+ }
124
+ if (code === "880") {
125
+ const n = extractBangladeshNational(rest.length >= 6 ? rest : d);
126
+ if (n) return `880${n}`;
127
+ }
128
+ }
129
+ if (allowed.includes("91")) {
130
+ const n = extractIndiaNational(d);
131
+ if (n) return `91${n}`;
132
+ }
133
+ if (allowed.includes("92")) {
134
+ const n = extractPakistanNational(d);
135
+ if (n) return `92${n}`;
136
+ }
137
+ if (allowed.includes("880")) {
138
+ const n = extractBangladeshNational(d);
139
+ if (n) return `880${n}`;
140
+ }
141
+ return null;
142
+ }
143
+ function normalizeE164(raw) {
144
+ let d = digitsOnly(raw);
145
+ if (!d) return null;
146
+ if (d.startsWith("00") && d.length > 4) d = d.slice(2);
147
+ if (d.length >= E164_MIN_DIGITS && d.length <= E164_MAX_DIGITS) return d;
148
+ return null;
149
+ }
150
+ function normalizeMobileWithPolicy(raw, policy = DEFAULT_MOBILE_POLICY) {
151
+ const p = mergeMobilePolicy(policy);
152
+ switch (p.format) {
153
+ case MOBILE_FORMAT.SOUTH_ASIA_E164:
154
+ return normalizeSouthAsiaE164(raw, p);
155
+ case MOBILE_FORMAT.E164:
156
+ return normalizeE164(raw);
157
+ case MOBILE_FORMAT.IN_10:
158
+ default:
159
+ return normalizeIn10(raw);
160
+ }
161
+ }
162
+ function isValidMobileWithPolicy(raw, policy = DEFAULT_MOBILE_POLICY) {
163
+ return normalizeMobileWithPolicy(raw, policy) != null;
164
+ }
165
+ function getMobileLookupValues(normalized, policy = DEFAULT_MOBILE_POLICY) {
166
+ if (!normalized) return [];
167
+ const p = mergeMobilePolicy(policy);
168
+ const values = /* @__PURE__ */ new Set([normalized]);
169
+ if (p.format !== MOBILE_FORMAT.IN_10) {
170
+ if (normalized.startsWith("91") && normalized.length === 12) {
171
+ values.add(normalized.slice(2));
172
+ }
173
+ if (/^\d{10}$/.test(normalized)) {
174
+ values.add(`91${normalized}`);
175
+ }
176
+ }
177
+ return [...values];
178
+ }
179
+ function formatMobileForDisplay(normalized, policy = DEFAULT_MOBILE_POLICY) {
180
+ if (!normalized) return "";
181
+ const p = mergeMobilePolicy(policy);
182
+ if (p.format === MOBILE_FORMAT.IN_10) {
183
+ return `+91 ${normalized}`;
184
+ }
185
+ return `+${normalized}`;
186
+ }
187
+ function invalidMobileMessage(policy = DEFAULT_MOBILE_POLICY) {
188
+ const p = mergeMobilePolicy(policy);
189
+ if (p.format === MOBILE_FORMAT.IN_10) {
190
+ return "Valid 10-digit mobile number required.";
191
+ }
192
+ if (p.format === MOBILE_FORMAT.SOUTH_ASIA_E164) {
193
+ return "Valid mobile number required (India, Pakistan, or Bangladesh with country code).";
194
+ }
195
+ return "Valid mobile number with country code required.";
196
+ }
197
+ function mobilePolicyToClientConfig(policy = DEFAULT_MOBILE_POLICY) {
198
+ const p = mergeMobilePolicy(policy);
199
+ return {
200
+ format: p.format,
201
+ defaultCountryCode: p.defaultCountryCode,
202
+ allowedDialCodes: p.allowedDialCodes
203
+ };
204
+ }
205
+ function isLegacyIndianIn10(mobile) {
206
+ const d = digitsOnly(mobile);
207
+ return /^[6-9]\d{9}$/.test(d);
208
+ }
209
+ function toIndiaE164FromLegacyIn10(mobile) {
210
+ const d = digitsOnly(mobile);
211
+ if (!isLegacyIndianIn10(d)) return null;
212
+ if (d.length === 12 && d.startsWith("91")) return d;
213
+ return `91${d}`;
214
+ }
215
+ function mobilesMatchIdentity(stored, candidate) {
216
+ const policy = { format: MOBILE_FORMAT.E164 };
217
+ const a = digitsOnly(stored);
218
+ const b = digitsOnly(candidate);
219
+ if (!a || !b) return false;
220
+ if (a === b) return true;
221
+ const aliasA = new Set(getMobileLookupValues(a, policy));
222
+ return getMobileLookupValues(b, policy).some((v) => aliasA.has(v));
223
+ }
19
224
 
20
225
  // authFlow.js
21
226
  var DEFAULT_AUTH_URL = "https://auth.sanvikaproduction.com";
22
227
  var DEVICE_ID_STORAGE_KEY = "sanvika_deviceId";
23
228
  var MOBILE_DEVICE_ID_STORAGE_KEY = "deviceId";
229
+ function authApiUrl(path, authBaseUrl = DEFAULT_AUTH_URL) {
230
+ return `${String(authBaseUrl).replace(/\/$/, "")}${path}`;
231
+ }
232
+ function resolveMobileForApi(mobile, mobilePolicy) {
233
+ const policy = mergeMobilePolicy(mobilePolicy || DEFAULT_MOBILE_POLICY);
234
+ const raw = String(mobile ?? "").trim();
235
+ return normalizeMobileWithPolicy(raw, policy) || raw;
236
+ }
24
237
  function randomDeviceId() {
25
238
  try {
26
239
  if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
@@ -66,13 +279,15 @@ async function checkMobile({
66
279
  mobile,
67
280
  deviceId,
68
281
  clientId,
69
- callbackUrl
282
+ callbackUrl,
283
+ mobilePolicy
70
284
  }) {
71
- const res = await fetch(`${authBaseUrl}/api/auth/check-mobile`, {
285
+ const normalized = resolveMobileForApi(mobile, mobilePolicy);
286
+ const res = await fetch(authApiUrl(AUTH_API.CHECK_MOBILE, authBaseUrl), {
72
287
  method: "POST",
73
288
  headers: { "Content-Type": "application/json" },
74
289
  body: JSON.stringify({
75
- mobile: String(mobile).trim(),
290
+ mobile: normalized,
76
291
  deviceId,
77
292
  clientId,
78
293
  ...callbackUrl ? { callbackUrl } : {}
@@ -93,10 +308,11 @@ async function postLogin({
93
308
  deviceId,
94
309
  userAgent,
95
310
  clientId,
96
- deviceName
311
+ deviceName,
312
+ mobilePolicy
97
313
  }) {
98
314
  const body = {
99
- mobile: String(mobile).trim(),
315
+ mobile: resolveMobileForApi(mobile, mobilePolicy),
100
316
  deviceId,
101
317
  clientId,
102
318
  userAgent: userAgent || deviceName || "Sanvika App"
@@ -104,7 +320,7 @@ async function postLogin({
104
320
  if (password) {
105
321
  body.password = password;
106
322
  }
107
- const res = await fetch(`${authBaseUrl}/api/auth/login`, {
323
+ const res = await fetch(authApiUrl(AUTH_API.LOGIN, authBaseUrl), {
108
324
  method: "POST",
109
325
  headers: { "Content-Type": "application/json" },
110
326
  body: JSON.stringify(body)
@@ -126,6 +342,7 @@ async function deviceAwareLogin({
126
342
  deviceName,
127
343
  clientId,
128
344
  callbackUrl,
345
+ mobilePolicy,
129
346
  resolveDeviceId
130
347
  }) {
131
348
  const resolvedDeviceId = deviceId || (typeof resolveDeviceId === "function" ? await resolveDeviceId() : getOrCreateWebDeviceId());
@@ -134,7 +351,8 @@ async function deviceAwareLogin({
134
351
  mobile,
135
352
  deviceId: resolvedDeviceId,
136
353
  clientId,
137
- callbackUrl
354
+ callbackUrl,
355
+ mobilePolicy
138
356
  });
139
357
  if (!check.exists) {
140
358
  const err = new Error("Mobile number not registered.");
@@ -154,7 +372,8 @@ async function deviceAwareLogin({
154
372
  deviceId: resolvedDeviceId,
155
373
  userAgent,
156
374
  deviceName,
157
- clientId
375
+ clientId,
376
+ mobilePolicy
158
377
  });
159
378
  }
160
379
 
@@ -184,7 +403,9 @@ function SanvikaAuthProvider({
184
403
  embeddedLogin = false,
185
404
  dashboardPath,
186
405
  authBaseUrl = DEFAULT_AUTH_URL,
187
- persistence: persistenceProp
406
+ persistence: persistenceProp,
407
+ /** Client mobilePolicy — E164 / SOUTH_ASIA_E164 / IN_10 (see CLIENT_MOBILE_POLICIES). */
408
+ mobileConfig
188
409
  }) {
189
410
  const apiCallbackUrl = embeddedLogin ? void 0 : redirectUri;
190
411
  const persistence = useMemo(() => {
@@ -235,10 +456,11 @@ function SanvikaAuthProvider({
235
456
  mobile,
236
457
  deviceId: resolvedDeviceId,
237
458
  clientId,
238
- callbackUrl: apiCallbackUrl
459
+ callbackUrl: apiCallbackUrl,
460
+ mobilePolicy: mobileConfig
239
461
  });
240
462
  },
241
- [authBaseUrl, clientId, apiCallbackUrl]
463
+ [authBaseUrl, clientId, apiCallbackUrl, mobileConfig]
242
464
  );
243
465
  const login = async ({
244
466
  mobile,
@@ -258,7 +480,8 @@ function SanvikaAuthProvider({
258
480
  deviceId: deviceId || randomDeviceId(),
259
481
  userAgent: userAgent || deviceName,
260
482
  clientId,
261
- deviceName
483
+ deviceName,
484
+ mobilePolicy: mobileConfig
262
485
  });
263
486
  } else {
264
487
  data = await deviceAwareLogin({
@@ -270,6 +493,7 @@ function SanvikaAuthProvider({
270
493
  deviceName,
271
494
  clientId,
272
495
  callbackUrl: apiCallbackUrl,
496
+ mobilePolicy: mobileConfig,
273
497
  resolveDeviceId
274
498
  });
275
499
  }
@@ -288,7 +512,7 @@ function SanvikaAuthProvider({
288
512
  const logout = async () => {
289
513
  try {
290
514
  const deviceId = await resolveLogoutDeviceId(persistence);
291
- await fetch(`${authBaseUrl}/api/auth/logout`, {
515
+ await fetch(`${authBaseUrl}${AUTH_API.LOGOUT}`, {
292
516
  method: "POST",
293
517
  headers: {
294
518
  "Content-Type": "application/json",
@@ -348,7 +572,8 @@ function SanvikaAuthProvider({
348
572
  clientId,
349
573
  redirectUri,
350
574
  dashboardPath,
351
- authBaseUrl
575
+ authBaseUrl,
576
+ mobileConfig
352
577
  };
353
578
  return /* @__PURE__ */ jsx(SanvikaAuthContext.Provider, { value, children });
354
579
  }
@@ -386,7 +611,6 @@ styleInject("@keyframes snvk-shimmer {\n 0% {\n background-position: 200% 0;
386
611
 
387
612
  // SanvikaAccountButton.jsx
388
613
  import { jsx as jsx2, jsxs } from "react/jsx-runtime";
389
- var S_AUTH_URL = "https://auth.sanvikaproduction.com";
390
614
  var SanvikaAccountButtonErrorBoundary = class extends Component {
391
615
  constructor(props) {
392
616
  super(props);
@@ -470,7 +694,7 @@ function SanvikaAccountButtonContent({
470
694
  className,
471
695
  layout = "default"
472
696
  }) {
473
- var _a, _b;
697
+ var _a;
474
698
  const isNavbarChip = layout === "navbarChip";
475
699
  const guestBtnClass = `snvk-guestBtn${isNavbarChip ? " snvk-layout-navbarChip" : ""}${className ? ` ${className}` : ""}`;
476
700
  const wrapperClass = `snvk-wrapper${isNavbarChip ? " snvk-layout-navbarChip" : ""}${className ? ` ${className}` : ""}`;
@@ -523,7 +747,7 @@ function SanvikaAccountButtonContent({
523
747
  if (!isAuthenticated || loading) {
524
748
  const { clientId } = auth;
525
749
  const redirectUri = auth.redirectUri || (typeof window !== "undefined" && window.location ? window.location.origin + "/auth/callback" : "");
526
- const authorizeUrl = clientId && redirectUri ? `${S_AUTH_URL}/authorize?client_id=${encodeURIComponent(clientId)}&redirect_uri=${encodeURIComponent(redirectUri)}` : `${S_AUTH_URL}/authorize`;
750
+ const authorizeUrl = clientId && redirectUri ? `${DEFAULT_AUTH_URL}/authorize?client_id=${encodeURIComponent(clientId)}&redirect_uri=${encodeURIComponent(redirectUri)}` : `${DEFAULT_AUTH_URL}/authorize`;
527
751
  return /* @__PURE__ */ jsxs(
528
752
  "button",
529
753
  {
@@ -549,7 +773,9 @@ function SanvikaAccountButtonContent({
549
773
  }
550
774
  );
551
775
  }
552
- const displayName = user.firstName || ((_b = user.mobile) == null ? void 0 : _b.slice(-4)) || "Me";
776
+ const mobileDigits = String(user.mobile || "").replace(/\D/g, "");
777
+ const displayName = user.firstName || mobileDigits.slice(-4) || "Me";
778
+ const mobileLabel = user.mobile ? formatMobileForDisplay(user.mobile, { format: MOBILE_FORMAT.E164 }) : "";
553
779
  const imageSrc = !imgError && user.image ? user.image : DEFAULT_AVATAR_SVG;
554
780
  const handleProfileClick = () => {
555
781
  if (onProfileClick) return onProfileClick();
@@ -602,10 +828,7 @@ function SanvikaAccountButtonContent({
602
828
  ),
603
829
  /* @__PURE__ */ jsxs("div", { children: [
604
830
  /* @__PURE__ */ jsx2("div", { className: "snvk-dropdownName", children: [user.firstName, user.lastName].filter(Boolean).join(" ") }),
605
- /* @__PURE__ */ jsxs("div", { className: "snvk-dropdownMobile", children: [
606
- "+91 ",
607
- user.mobile
608
- ] })
831
+ /* @__PURE__ */ jsx2("div", { className: "snvk-dropdownMobile", children: mobileLabel })
609
832
  ] })
610
833
  ] }),
611
834
  /* @__PURE__ */ jsx2("div", { className: "snvk-divider" }),
@@ -659,11 +882,370 @@ function SanvikaAccountButton(props) {
659
882
  }
660
883
 
661
884
  // SanvikaAdminLogin.jsx
662
- import { useState as useState3, useEffect as useEffect3 } from "react";
885
+ import { useState as useState4, useEffect as useEffect4 } from "react";
663
886
  import { useRouter } from "next/navigation";
887
+
888
+ // MobilePolicyPhoneInput.jsx
889
+ import PhoneInput from "react-phone-number-input";
890
+ import flags from "react-phone-number-input/flags";
891
+ import en from "react-phone-number-input/locale/en.json";
892
+ import { parsePhoneNumber } from "libphonenumber-js/min";
893
+
894
+ // phoneInputPolicy.js
895
+ var DIAL_CODE_TO_COUNTRY = Object.freeze({
896
+ "1": "US",
897
+ "44": "GB",
898
+ "91": "IN",
899
+ "92": "PK",
900
+ "880": "BD",
901
+ "971": "AE",
902
+ "61": "AU",
903
+ "49": "DE",
904
+ "33": "FR"
905
+ });
906
+ var SOUTH_ASIA_DEFAULTS = Object.freeze(["IN", "PK", "BD"]);
907
+ function countriesForPolicy(config) {
908
+ var _a;
909
+ const p = mergeMobilePolicy(config);
910
+ if (p.format === MOBILE_FORMAT.IN_10) return ["IN"];
911
+ if (p.format === MOBILE_FORMAT.SOUTH_ASIA_E164) {
912
+ const codes = ((_a = p.allowedDialCodes) == null ? void 0 : _a.length) > 0 ? p.allowedDialCodes : ["91", "92", "880"];
913
+ const iso = codes.map((c) => DIAL_CODE_TO_COUNTRY[String(c).replace(/\D/g, "")]).filter(Boolean);
914
+ return iso.length ? iso : [...SOUTH_ASIA_DEFAULTS];
915
+ }
916
+ return void 0;
917
+ }
918
+ function defaultCountryForPolicy(config) {
919
+ const p = mergeMobilePolicy(config);
920
+ const dc = String(p.defaultCountryCode || "91").replace(/\D/g, "");
921
+ return DIAL_CODE_TO_COUNTRY[dc] || "IN";
922
+ }
923
+ function isCountryLocked(config) {
924
+ const list = countriesForPolicy(config);
925
+ return Array.isArray(list) && list.length === 1;
926
+ }
927
+ function countryOptionsOrderForPolicy(config) {
928
+ const list = countriesForPolicy(config);
929
+ if (Array.isArray(list) && list.length <= 1) return void 0;
930
+ const top = defaultCountryForPolicy(config);
931
+ return top ? [top, "|"] : void 0;
932
+ }
933
+ function toPhoneInputValue(raw, config) {
934
+ if (!raw) return void 0;
935
+ const s = String(raw).trim();
936
+ if (s.startsWith("+")) return s;
937
+ const dc = defaultCountryForPolicy(config);
938
+ const digits = s.replace(/\D/g, "");
939
+ if (!digits) return void 0;
940
+ return `+${digits}`;
941
+ }
942
+
943
+ // PolicySearchableCountrySelect.jsx
944
+ import { useEffect as useEffect3, useMemo as useMemo2, useRef as useRef2, useState as useState3 } from "react";
945
+ import { getCountryCallingCode } from "react-phone-number-input";
946
+
947
+ // unicodeCountryFlag.js
948
+ function unicodeCountryFlag(countryCode) {
949
+ if (!countryCode || countryCode === "ZZ" || countryCode.length !== 2) return "";
950
+ const upper = countryCode.toUpperCase();
951
+ if (!/^[A-Z]{2}$/.test(upper)) return "";
952
+ return String.fromCodePoint(
953
+ ...[...upper].map((char) => 127397 + char.charCodeAt(0))
954
+ );
955
+ }
956
+
957
+ // PolicySearchableCountrySelect.jsx
664
958
  import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
665
- var AUTH_BASE_URL = "https://auth.sanvikaproduction.com";
959
+ function dialCodeFor(country) {
960
+ if (!country) return "";
961
+ try {
962
+ return `+${getCountryCallingCode(country)}`;
963
+ } catch {
964
+ return "";
965
+ }
966
+ }
967
+ function countryWords(label) {
968
+ return String(label || "").toLowerCase().split(/[\s,().-]+/).filter(Boolean);
969
+ }
970
+ function matchScore(label, q, code, dialDigits, qDigits) {
971
+ const normalized = String(label || "").toLowerCase();
972
+ if (normalized.startsWith(q)) return 0;
973
+ if (countryWords(label).some((word) => word.startsWith(q))) return 1;
974
+ if (code.startsWith(q)) return 2;
975
+ if (qDigits && dialDigits.startsWith(qDigits)) return 3;
976
+ return -1;
977
+ }
978
+ function PolicySearchableCountrySelect({
979
+ value,
980
+ onChange,
981
+ options,
982
+ disabled,
983
+ readOnly
984
+ }) {
985
+ const [open, setOpen] = useState3(false);
986
+ const [query, setQuery] = useState3("");
987
+ const rootRef = useRef2(null);
988
+ const searchRef = useRef2(null);
989
+ const selectable = useMemo2(
990
+ () => options.filter((o) => !o.divider && o.value),
991
+ [options]
992
+ );
993
+ const filtered = useMemo2(() => {
994
+ const q = query.trim().toLowerCase();
995
+ if (!q) return selectable;
996
+ const qDigits = q.replace(/\D/g, "");
997
+ return selectable.map((o) => ({
998
+ option: o,
999
+ score: matchScore(
1000
+ o.label,
1001
+ q,
1002
+ (o.value || "").toLowerCase(),
1003
+ dialCodeFor(o.value).replace(/\D/g, ""),
1004
+ qDigits
1005
+ )
1006
+ })).filter((row) => row.score >= 0).sort((a, b) => a.score - b.score || a.option.label.localeCompare(b.option.label)).map((row) => row.option);
1007
+ }, [query, selectable]);
1008
+ useEffect3(() => {
1009
+ if (!open) return void 0;
1010
+ const onDoc = (event) => {
1011
+ if (rootRef.current && !rootRef.current.contains(event.target)) {
1012
+ setOpen(false);
1013
+ }
1014
+ };
1015
+ document.addEventListener("click", onDoc);
1016
+ return () => document.removeEventListener("click", onDoc);
1017
+ }, [open]);
1018
+ useEffect3(() => {
1019
+ if (!open) return;
1020
+ setQuery("");
1021
+ requestAnimationFrame(() => {
1022
+ var _a;
1023
+ return (_a = searchRef.current) == null ? void 0 : _a.focus();
1024
+ });
1025
+ }, [open]);
1026
+ const locked = disabled || readOnly;
1027
+ const flag = value ? unicodeCountryFlag(value) : "\u{1F310}";
1028
+ const dial = dialCodeFor(value);
1029
+ const pick = (code) => {
1030
+ if (!code || code === value) {
1031
+ setOpen(false);
1032
+ setQuery("");
1033
+ return;
1034
+ }
1035
+ onChange(code);
1036
+ setOpen(false);
1037
+ setQuery("");
1038
+ };
1039
+ return /* @__PURE__ */ jsx3("div", { className: "PhoneInputCountry", children: /* @__PURE__ */ jsxs2("div", { className: "sa-country-picker", ref: rootRef, children: [
1040
+ /* @__PURE__ */ jsxs2(
1041
+ "button",
1042
+ {
1043
+ type: "button",
1044
+ className: "sa-country-picker__trigger",
1045
+ disabled: locked,
1046
+ "aria-expanded": open,
1047
+ "aria-haspopup": "listbox",
1048
+ "aria-label": value ? `Country ${value}` : "Select country",
1049
+ onClick: (event) => {
1050
+ event.stopPropagation();
1051
+ if (!locked) setOpen((v) => !v);
1052
+ },
1053
+ children: [
1054
+ /* @__PURE__ */ jsx3("span", { className: "sa-country-picker__flag", "aria-hidden": "true", children: flag }),
1055
+ dial ? /* @__PURE__ */ jsx3("span", { className: "sa-country-picker__dial", children: dial }) : null,
1056
+ !locked ? /* @__PURE__ */ jsx3("span", { className: "sa-country-picker__chev", "aria-hidden": "true", children: "\u25BE" }) : null
1057
+ ]
1058
+ }
1059
+ ),
1060
+ open && !locked ? /* @__PURE__ */ jsxs2(
1061
+ "div",
1062
+ {
1063
+ className: "sa-country-picker__panel",
1064
+ role: "listbox",
1065
+ onMouseDown: (event) => event.stopPropagation(),
1066
+ children: [
1067
+ /* @__PURE__ */ jsx3(
1068
+ "input",
1069
+ {
1070
+ ref: searchRef,
1071
+ type: "search",
1072
+ className: "sa-country-picker__search",
1073
+ placeholder: "Search country",
1074
+ value: query,
1075
+ onChange: (e) => setQuery(e.target.value),
1076
+ "aria-label": "Search country",
1077
+ autoComplete: "off"
1078
+ }
1079
+ ),
1080
+ /* @__PURE__ */ jsxs2("ul", { className: "sa-country-picker__list", children: [
1081
+ filtered.map((o) => /* @__PURE__ */ jsx3("li", { children: /* @__PURE__ */ jsxs2(
1082
+ "button",
1083
+ {
1084
+ type: "button",
1085
+ role: "option",
1086
+ "aria-selected": o.value === value,
1087
+ className: `sa-country-picker__option${o.value === value ? " sa-country-picker__option--active" : ""}`,
1088
+ onMouseDown: (event) => {
1089
+ event.preventDefault();
1090
+ event.stopPropagation();
1091
+ pick(o.value);
1092
+ },
1093
+ children: [
1094
+ /* @__PURE__ */ jsx3("span", { className: "sa-country-picker__option-flag", "aria-hidden": "true", children: unicodeCountryFlag(o.value) }),
1095
+ /* @__PURE__ */ jsx3("span", { className: "sa-country-picker__name", children: o.label }),
1096
+ /* @__PURE__ */ jsx3("span", { className: "sa-country-picker__code", children: dialCodeFor(o.value) })
1097
+ ]
1098
+ }
1099
+ ) }, o.value)),
1100
+ !filtered.length ? /* @__PURE__ */ jsx3("li", { className: "sa-country-picker__empty", children: "No matches" }) : null
1101
+ ] })
1102
+ ]
1103
+ }
1104
+ ) : null
1105
+ ] }) });
1106
+ }
1107
+
1108
+ // MobilePolicyPhoneInput.jsx
1109
+ import "react-phone-number-input/style.css";
1110
+
1111
+ // MobilePolicyPhoneInput.css
1112
+ styleInject(".sa-phone-field {\n margin-bottom: 16px;\n}\n.sa-phone-input {\n display: block;\n}\n.sa-phone-input .PhoneInput {\n display: flex;\n align-items: stretch;\n border-radius: 8px;\n overflow: hidden;\n border: 1px solid #dddddd;\n background: #ffffff;\n}\n.sa-phone-input--searchable-country .PhoneInput {\n overflow: visible;\n}\n.sa-phone-input--dark .PhoneInput {\n border-color: #333333;\n background: #222222;\n}\n.sa-phone-input .PhoneInputCountry {\n position: relative;\n flex: 0 0 auto;\n align-self: stretch;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0;\n min-width: 5.25rem;\n max-width: 6.75rem;\n border-right: 1px solid #dddddd;\n background: #f5f5f5;\n}\n.sa-phone-input--dark .PhoneInputCountry {\n border-right-color: #333333;\n background: #2a2a2a;\n}\n.sa-phone-input--searchable-country .PhoneInputCountryIcon,\n.sa-phone-input--searchable-country .PhoneInputCountryIconUnicode,\n.sa-phone-input--searchable-country .PhoneInputCountrySelectArrow {\n display: none !important;\n}\n.sa-phone-input .PhoneInputInput {\n flex: 1 1 auto;\n min-width: 0;\n width: 100%;\n border: none;\n outline: none;\n padding: 10px 12px;\n font-size: 15px;\n background: transparent;\n color: #222222;\n}\n.sa-phone-input--dark .PhoneInputInput {\n color: #ffffff;\n}\n.sa-phone-input .PhoneInputInput::placeholder {\n color: #999999;\n}\n.sa-phone-input--dark .PhoneInputInput::placeholder {\n color: #666666;\n}\n.sa-country-picker {\n position: relative;\n width: 100%;\n height: 100%;\n min-height: 42px;\n}\n.sa-country-picker__trigger {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 4px;\n width: 100%;\n height: 100%;\n min-height: 42px;\n padding: 0 8px;\n margin: 0;\n border: none;\n background: transparent;\n cursor: pointer;\n color: inherit;\n font: inherit;\n}\n.sa-country-picker__trigger:disabled {\n cursor: default;\n opacity: 0.65;\n}\n.sa-country-picker__flag {\n font-size: 1.15rem;\n line-height: 1;\n flex-shrink: 0;\n}\n.sa-country-picker__dial {\n font-size: 13px;\n font-weight: 600;\n white-space: nowrap;\n flex-shrink: 0;\n}\n.sa-country-picker__chev {\n font-size: 10px;\n opacity: 0.7;\n flex-shrink: 0;\n margin-left: 1px;\n}\n.sa-country-picker__panel {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n z-index: 50;\n width: min(20rem, calc(100vw - 2rem));\n max-height: min(20rem, 55vh);\n display: flex;\n flex-direction: column;\n border-radius: 10px;\n border: 1px solid #dddddd;\n background: #ffffff;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);\n overflow: hidden;\n}\n.sa-phone-input--dark .sa-country-picker__panel {\n border-color: #444444;\n background: #1e1e1e;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);\n}\n.sa-country-picker__search {\n flex-shrink: 0;\n width: 100%;\n padding: 10px 12px;\n border: none;\n border-bottom: 1px solid #eeeeee;\n outline: none;\n font-size: 14px;\n background: #fafafa;\n color: #222222;\n}\n.sa-phone-input--dark .sa-country-picker__search {\n border-bottom-color: #333333;\n background: #252525;\n color: #ffffff;\n}\n.sa-country-picker__list {\n list-style: none;\n margin: 0;\n padding: 4px 0;\n overflow-y: auto;\n flex: 1;\n min-height: 0;\n}\n.sa-country-picker__option {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n padding: 8px 12px;\n border: none;\n background: transparent;\n cursor: pointer;\n text-align: left;\n font-size: 14px;\n color: #222222;\n}\n.sa-phone-input--dark .sa-country-picker__option {\n color: #eeeeee;\n}\n.sa-country-picker__option:hover,\n.sa-country-picker__option--active {\n background: #f0f4ff;\n}\n.sa-phone-input--dark .sa-country-picker__option:hover,\n.sa-phone-input--dark .sa-country-picker__option--active {\n background: #2a3344;\n}\n.sa-country-picker__option-flag {\n font-size: 1.1rem;\n line-height: 1;\n flex-shrink: 0;\n}\n.sa-country-picker__name {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.sa-country-picker__code {\n flex-shrink: 0;\n font-size: 12px;\n font-weight: 600;\n color: #666666;\n}\n.sa-phone-input--dark .sa-country-picker__code {\n color: #999999;\n}\n.sa-country-picker__empty {\n padding: 12px;\n font-size: 13px;\n color: #888888;\n text-align: center;\n}\n.sa-phone-preview {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px 10px;\n margin-top: 8px;\n padding: 8px 10px;\n border-radius: 6px;\n font-size: 12px;\n background: #f0f7ff;\n border: 1px solid #cce4ff;\n}\n.sa-phone-preview--dark {\n background: #1a2433;\n border-color: #2a3f5f;\n}\n.sa-phone-preview__label {\n font-weight: 600;\n color: #555555;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n font-size: 10px;\n}\n.sa-phone-preview--dark .sa-phone-preview__label {\n color: #8899aa;\n}\n.sa-phone-preview__value {\n color: #0984e3;\n font-weight: 500;\n}\n.sa-phone-preview--dark .sa-phone-preview__value {\n color: #88c5ff;\n}\n.sa-phone-preview__e164 {\n font-family:\n ui-monospace,\n SFMono-Regular,\n Menlo,\n monospace;\n color: #333333;\n background: rgba(0, 0, 0, 0.05);\n padding: 2px 6px;\n border-radius: 4px;\n}\n.sa-phone-preview--dark .sa-phone-preview__e164 {\n color: #cccccc;\n background: rgba(255, 255, 255, 0.06);\n}\n");
1113
+
1114
+ // MobilePolicyPhoneInput.jsx
1115
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1116
+ function MobilePolicyPhoneInput({
1117
+ config,
1118
+ value,
1119
+ onChange,
1120
+ theme = "dark",
1121
+ inputRef,
1122
+ id = "mobile-phone-input",
1123
+ placeholder = "Enter phone number",
1124
+ showPreview = true
1125
+ }) {
1126
+ const policy = mergeMobilePolicy(config);
1127
+ const countries = countriesForPolicy(config);
1128
+ const defaultCountry = defaultCountryForPolicy(config);
1129
+ const countryLocked = isCountryLocked(config);
1130
+ const countryOrder = countryOptionsOrderForPolicy(config);
1131
+ let e164Display = "";
1132
+ if (value) {
1133
+ try {
1134
+ const parsed = parsePhoneNumber(value);
1135
+ if (parsed == null ? void 0 : parsed.isValid()) {
1136
+ e164Display = parsed.number;
1137
+ } else {
1138
+ const digits = normalizeMobileWithPolicy(value, policy) || String(value).replace(/\D/g, "");
1139
+ e164Display = digits ? `+${digits}` : "";
1140
+ }
1141
+ } catch {
1142
+ e164Display = "";
1143
+ }
1144
+ }
1145
+ return /* @__PURE__ */ jsxs3("div", { className: "sa-phone-field", children: [
1146
+ /* @__PURE__ */ jsx4(
1147
+ "div",
1148
+ {
1149
+ className: `sa-phone-input sa-phone-input--${theme} sa-phone-input--searchable-country`,
1150
+ "data-theme": theme,
1151
+ children: /* @__PURE__ */ jsx4(
1152
+ PhoneInput,
1153
+ {
1154
+ id,
1155
+ international: false,
1156
+ countryCallingCodeEditable: false,
1157
+ defaultCountry,
1158
+ countries,
1159
+ countryOptionsOrder: countryOrder,
1160
+ addInternationalOption: false,
1161
+ countrySelectComponent: PolicySearchableCountrySelect,
1162
+ flags,
1163
+ labels: en,
1164
+ value,
1165
+ onChange,
1166
+ placeholder,
1167
+ smartCaret: true,
1168
+ inputRef,
1169
+ focusInputOnCountrySelection: Boolean(inputRef),
1170
+ countrySelectProps: {
1171
+ unicodeFlags: true,
1172
+ ...countryLocked ? { disabled: true } : {}
1173
+ },
1174
+ numberInputProps: {
1175
+ autoComplete: "tel",
1176
+ inputMode: "tel",
1177
+ "aria-label": "Phone number"
1178
+ }
1179
+ }
1180
+ )
1181
+ }
1182
+ ),
1183
+ showPreview && value && e164Display ? /* @__PURE__ */ jsxs3("div", { className: `sa-phone-preview sa-phone-preview--${theme}`, children: [
1184
+ /* @__PURE__ */ jsx4("span", { className: "sa-phone-preview__label", children: "E.164" }),
1185
+ /* @__PURE__ */ jsx4("span", { className: "sa-phone-preview__e164", children: e164Display })
1186
+ ] }) : null
1187
+ ] });
1188
+ }
1189
+
1190
+ // mobileInput.js
1191
+ var DIAL_CODE_LABELS = Object.freeze({
1192
+ "91": "+91 India",
1193
+ "92": "+92 Pakistan",
1194
+ "880": "+880 Bangladesh"
1195
+ });
1196
+ function dialCodeOptions(config) {
1197
+ const p = mergeMobilePolicy(config);
1198
+ return (p.allowedDialCodes || ["91"]).map((code) => ({
1199
+ code,
1200
+ label: DIAL_CODE_LABELS[code] || `+${code}`
1201
+ }));
1202
+ }
1203
+ function buildRawMobile({ config, national, dialCode, e164Input }) {
1204
+ const p = mergeMobilePolicy(config);
1205
+ if (p.format === MOBILE_FORMAT.E164) {
1206
+ return String(e164Input ?? national ?? "").trim();
1207
+ }
1208
+ if (p.format === MOBILE_FORMAT.SOUTH_ASIA_E164) {
1209
+ const n = String(national ?? "").replace(/\D/g, "");
1210
+ const dc = String(dialCode || p.defaultCountryCode || "91").replace(/\D/g, "");
1211
+ return `${dc}${n}`;
1212
+ }
1213
+ return String(national ?? "").replace(/\D/g, "");
1214
+ }
1215
+ function validateMobileInput(config, raw) {
1216
+ return isValidMobileWithPolicy(raw, config);
1217
+ }
1218
+ function normalizeForSubmit(config, raw) {
1219
+ return normalizeMobileWithPolicy(raw, config);
1220
+ }
1221
+ function displayMobileLabel(config, rawOrNational) {
1222
+ const p = mergeMobilePolicy(config);
1223
+ if (p.format === MOBILE_FORMAT.IN_10) {
1224
+ return formatMobileForDisplay(rawOrNational, config);
1225
+ }
1226
+ const normalized = normalizeMobileWithPolicy(
1227
+ buildRawMobile({ config, national: rawOrNational, dialCode: p.defaultCountryCode }),
1228
+ config
1229
+ );
1230
+ return formatMobileForDisplay(normalized || rawOrNational, config);
1231
+ }
1232
+ function nationalMaxLength(config) {
1233
+ const p = mergeMobilePolicy(config);
1234
+ if (p.format === MOBILE_FORMAT.IN_10) return 10;
1235
+ if (p.format === MOBILE_FORMAT.SOUTH_ASIA_E164) return 11;
1236
+ return 15;
1237
+ }
1238
+ function mobilePlaceholder(config) {
1239
+ const p = mergeMobilePolicy(config);
1240
+ if (p.format === MOBILE_FORMAT.IN_10) return "Enter mobile number";
1241
+ if (p.format === MOBILE_FORMAT.SOUTH_ASIA_E164) return "National number";
1242
+ return "Include country code, e.g. +1 415 555 0100";
1243
+ }
1244
+
1245
+ // SanvikaAdminLogin.jsx
1246
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
666
1247
  var DEVICE_ID_KEY = "sanvika_admin_device_id";
1248
+ var ADMIN_MOBILE_POLICY = CLIENT_MOBILE_POLICIES.IN_10;
667
1249
  function getDeviceId() {
668
1250
  var _a;
669
1251
  if (typeof window === "undefined") return "";
@@ -701,16 +1283,17 @@ function friendlyError(code) {
701
1283
  function SanvikaAdminLogin({
702
1284
  serviceName = "Sanvika",
703
1285
  dashboardPath = "/dashboard/admin",
704
- homePath = "/"
1286
+ homePath = "/",
1287
+ authBaseUrl = DEFAULT_AUTH_URL
705
1288
  }) {
706
1289
  const router = useRouter();
707
- const { isAuthenticated, loading, user, setAuth } = useSanvikaAuth();
708
- const [mobile, setMobile] = useState3("");
709
- const [password, setPassword] = useState3("");
710
- const [error, setError] = useState3("");
711
- const [submitting, setSubmitting] = useState3(false);
712
- const [ready, setReady] = useState3(false);
713
- useEffect3(() => {
1290
+ const { isAuthenticated, loading, user, setAuth, clientId } = useSanvikaAuth();
1291
+ const [phoneValue, setPhoneValue] = useState4(void 0);
1292
+ const [password, setPassword] = useState4("");
1293
+ const [error, setError] = useState4("");
1294
+ const [submitting, setSubmitting] = useState4(false);
1295
+ const [ready, setReady] = useState4(false);
1296
+ useEffect4(() => {
714
1297
  if (loading) return;
715
1298
  if (isAuthenticated && (user == null ? void 0 : user.role) === "superadmin") {
716
1299
  router.replace(dashboardPath);
@@ -722,24 +1305,26 @@ function SanvikaAdminLogin({
722
1305
  var _a;
723
1306
  e.preventDefault();
724
1307
  setError("");
1308
+ if (!phoneValue || !validateMobileInput(ADMIN_MOBILE_POLICY, phoneValue)) {
1309
+ setError(invalidMobileMessage(ADMIN_MOBILE_POLICY));
1310
+ return;
1311
+ }
1312
+ if (!password) {
1313
+ setError("Please enter your password.");
1314
+ return;
1315
+ }
725
1316
  setSubmitting(true);
726
1317
  try {
727
- const res = await fetch(`${AUTH_BASE_URL}/api/auth/login`, {
728
- method: "POST",
729
- headers: { "Content-Type": "application/json" },
730
- body: JSON.stringify({
731
- mobile,
732
- password,
733
- deviceId: getDeviceId(),
734
- deviceName: "Browser"
735
- })
1318
+ const mobile = normalizeForSubmit(ADMIN_MOBILE_POLICY, phoneValue);
1319
+ const data = await postLogin({
1320
+ authBaseUrl,
1321
+ mobile,
1322
+ password,
1323
+ deviceId: getDeviceId(),
1324
+ deviceName: "Browser",
1325
+ clientId,
1326
+ mobilePolicy: ADMIN_MOBILE_POLICY
736
1327
  });
737
- const data = await res.json().catch(() => ({}));
738
- if (!data.success) {
739
- setError(friendlyError(data.error));
740
- setPassword("");
741
- return;
742
- }
743
1328
  if (((_a = data.user) == null ? void 0 : _a.role) !== "superadmin") {
744
1329
  setError("This account does not have admin access.");
745
1330
  setPassword("");
@@ -747,8 +1332,9 @@ function SanvikaAdminLogin({
747
1332
  }
748
1333
  setAuth(data.accessToken, data.user);
749
1334
  router.replace(dashboardPath);
750
- } catch {
751
- setError("Could not reach the auth service. Please try again.");
1335
+ } catch (err) {
1336
+ setError(friendlyError(err == null ? void 0 : err.code) || (err == null ? void 0 : err.message) || "Login failed.");
1337
+ setPassword("");
752
1338
  } finally {
753
1339
  setSubmitting(false);
754
1340
  }
@@ -766,7 +1352,7 @@ function SanvikaAdminLogin({
766
1352
  card: {
767
1353
  position: "relative",
768
1354
  width: "100%",
769
- maxWidth: "380px",
1355
+ maxWidth: "420px",
770
1356
  background: "#1e293b",
771
1357
  borderRadius: "16px",
772
1358
  padding: "36px 32px",
@@ -828,34 +1414,40 @@ function SanvikaAdminLogin({
828
1414
  }
829
1415
  };
830
1416
  if (loading || !ready) {
831
- return /* @__PURE__ */ jsx3("div", { style: S.page, children: /* @__PURE__ */ jsx3("div", { style: S.card, children: /* @__PURE__ */ jsx3("p", { style: S.subtitle, children: "Loading\u2026" }) }) });
1417
+ return /* @__PURE__ */ jsx5("div", { style: S.page, children: /* @__PURE__ */ jsx5("div", { style: S.card, children: /* @__PURE__ */ jsx5("p", { style: S.subtitle, children: "Loading\u2026" }) }) });
832
1418
  }
833
- return /* @__PURE__ */ jsx3("div", { style: S.page, children: /* @__PURE__ */ jsxs2("div", { style: S.card, children: [
834
- /* @__PURE__ */ jsx3("button", { style: S.closeBtn, onClick: () => router.push(homePath), "aria-label": "Close", children: "\u2715" }),
835
- /* @__PURE__ */ jsx3("div", { style: S.logo, children: "\u{1F6E1}\uFE0F" }),
836
- /* @__PURE__ */ jsxs2("h1", { style: S.title, children: [
1419
+ return /* @__PURE__ */ jsx5("div", { style: S.page, children: /* @__PURE__ */ jsxs4("div", { style: S.card, children: [
1420
+ /* @__PURE__ */ jsx5(
1421
+ "button",
1422
+ {
1423
+ style: S.closeBtn,
1424
+ onClick: () => router.push(homePath),
1425
+ "aria-label": "Close",
1426
+ children: "\u2715"
1427
+ }
1428
+ ),
1429
+ /* @__PURE__ */ jsx5("div", { style: S.logo, children: "\u{1F6E1}\uFE0F" }),
1430
+ /* @__PURE__ */ jsxs4("h1", { style: S.title, children: [
837
1431
  serviceName,
838
1432
  " Admin"
839
1433
  ] }),
840
- /* @__PURE__ */ jsx3("p", { style: S.subtitle, children: "SuperAdmin access \u2014 Sanvika Accounts SSO" }),
841
- /* @__PURE__ */ jsxs2("form", { onSubmit: handleLogin, style: S.form, autoComplete: "off", children: [
842
- /* @__PURE__ */ jsx3("label", { style: S.label, children: "Mobile Number" }),
843
- /* @__PURE__ */ jsx3(
844
- "input",
1434
+ /* @__PURE__ */ jsx5("p", { style: S.subtitle, children: "SuperAdmin access \u2014 Sanvika Accounts SSO" }),
1435
+ /* @__PURE__ */ jsxs4("form", { onSubmit: handleLogin, style: S.form, autoComplete: "off", children: [
1436
+ /* @__PURE__ */ jsx5("label", { style: S.label, htmlFor: "admin-mobile-phone", children: "Mobile Number" }),
1437
+ /* @__PURE__ */ jsx5(
1438
+ MobilePolicyPhoneInput,
845
1439
  {
846
- type: "tel",
847
- value: mobile,
848
- onChange: (e) => setMobile(e.target.value.replace(/\D/g, "").slice(0, 10)),
849
- placeholder: "10-digit mobile",
850
- style: S.input,
851
- maxLength: 10,
852
- required: true,
853
- autoFocus: true,
854
- autoComplete: "off"
1440
+ config: ADMIN_MOBILE_POLICY,
1441
+ value: phoneValue,
1442
+ onChange: setPhoneValue,
1443
+ theme: "dark",
1444
+ id: "admin-mobile-phone",
1445
+ placeholder: "Enter phone number",
1446
+ showPreview: false
855
1447
  }
856
1448
  ),
857
- /* @__PURE__ */ jsx3("label", { style: S.label, children: "Password" }),
858
- /* @__PURE__ */ jsx3(
1449
+ /* @__PURE__ */ jsx5("label", { style: S.label, children: "Password" }),
1450
+ /* @__PURE__ */ jsx5(
859
1451
  "input",
860
1452
  {
861
1453
  type: "password",
@@ -867,19 +1459,20 @@ function SanvikaAdminLogin({
867
1459
  autoComplete: "new-password"
868
1460
  }
869
1461
  ),
870
- /* @__PURE__ */ jsx3(
1462
+ /* @__PURE__ */ jsx5(
871
1463
  "button",
872
1464
  {
873
1465
  type: "submit",
874
1466
  style: S.button,
875
- disabled: submitting || mobile.length !== 10 || !password,
1467
+ disabled: submitting || !phoneValue || !password,
876
1468
  children: submitting ? "Signing in\u2026" : "Sign in"
877
1469
  }
878
1470
  )
879
1471
  ] }),
880
- error && /* @__PURE__ */ jsx3("p", { style: S.error, children: error })
1472
+ error && /* @__PURE__ */ jsx5("p", { style: S.error, children: error })
881
1473
  ] }) });
882
1474
  }
1475
+ var ADMIN_LOGIN_API_URL = authApiUrl(AUTH_API.LOGIN, DEFAULT_AUTH_URL);
883
1476
 
884
1477
  // authFetchResult.js
885
1478
  function isAuthFetchOk(response) {
@@ -904,24 +1497,52 @@ function getAuthFetchData(response) {
904
1497
  return payload;
905
1498
  }
906
1499
  export {
1500
+ AUTH_API,
1501
+ CLIENT_MOBILE_POLICIES,
907
1502
  DEFAULT_AUTH_URL,
908
1503
  DEFAULT_AVATAR_SVG,
1504
+ DEFAULT_MOBILE_POLICY,
909
1505
  DEVICE_ID_STORAGE_KEY,
1506
+ DIAL_CODE_TO_COUNTRY,
910
1507
  MOBILE_DEVICE_ID_STORAGE_KEY,
1508
+ MOBILE_FORMAT,
1509
+ MobilePolicyPhoneInput,
911
1510
  STORAGE_KEYS,
912
1511
  SanvikaAccountButton,
913
1512
  SanvikaAdminLogin,
914
1513
  SanvikaAuthContext,
915
1514
  SanvikaAuthProvider,
1515
+ authApiUrl,
1516
+ buildRawMobile,
916
1517
  checkMobile,
1518
+ countriesForPolicy,
1519
+ defaultCountryForPolicy,
917
1520
  deviceAwareLogin,
1521
+ dialCodeOptions,
1522
+ displayMobileLabel,
1523
+ formatMobileForDisplay,
918
1524
  getAuthFetchData,
919
1525
  getAuthFetchMessage,
920
1526
  getAuthFetchPayload,
921
1527
  getOrCreateWebDeviceId,
1528
+ invalidMobileMessage,
922
1529
  isAuthFetchOk,
1530
+ isCountryLocked,
1531
+ isLegacyIndianIn10,
1532
+ isValidMobileWithPolicy,
1533
+ mergeMobilePolicy,
1534
+ mobilePlaceholder,
1535
+ mobilePolicyToClientConfig,
1536
+ mobilesMatchIdentity,
1537
+ nationalMaxLength,
1538
+ normalizeForSubmit,
1539
+ normalizeMobileWithPolicy,
923
1540
  postLogin,
924
1541
  randomDeviceId,
925
1542
  resolveLogoutDeviceId,
926
- useSanvikaAuth
1543
+ resolveMobileForApi,
1544
+ toIndiaE164FromLegacyIn10,
1545
+ toPhoneInputValue,
1546
+ useSanvikaAuth,
1547
+ validateMobileInput
927
1548
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanvika/auth",
3
- "version": "2.9.5",
3
+ "version": "2.10.1",
4
4
  "description": "Sanvika Auth SDK — React components/hooks + server-side token verification and user proxy",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -14,7 +14,9 @@
14
14
  ],
15
15
  "scripts": {
16
16
  "build": "tsup",
17
- "prepublishOnly": "npm run build"
17
+ "prepublishOnly": "npm run build",
18
+ "test:curl:local": "bash ../../scripts/sdk-curl-auth-test.sh local",
19
+ "test:curl:production": "bash ../../scripts/sdk-curl-auth-test.sh production"
18
20
  },
19
21
  "publishConfig": {
20
22
  "access": "public"
@@ -28,6 +30,10 @@
28
30
  "optional": true
29
31
  }
30
32
  },
33
+ "dependencies": {
34
+ "libphonenumber-js": "^1.13.6",
35
+ "react-phone-number-input": "^3.4.17"
36
+ },
31
37
  "devDependencies": {
32
38
  "tsup": "^8.5.1"
33
39
  },