@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.
- package/dist/index.js +696 -75
- 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
|
|
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:
|
|
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:
|
|
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(
|
|
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}
|
|
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
|
|
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 ? `${
|
|
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
|
|
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__ */
|
|
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
|
|
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
|
-
|
|
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 [
|
|
709
|
-
const [password, setPassword] =
|
|
710
|
-
const [error, setError] =
|
|
711
|
-
const [submitting, setSubmitting] =
|
|
712
|
-
const [ready, setReady] =
|
|
713
|
-
|
|
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
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
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(
|
|
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: "
|
|
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__ */
|
|
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__ */
|
|
834
|
-
/* @__PURE__ */
|
|
835
|
-
|
|
836
|
-
|
|
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__ */
|
|
841
|
-
/* @__PURE__ */
|
|
842
|
-
/* @__PURE__ */
|
|
843
|
-
/* @__PURE__ */
|
|
844
|
-
|
|
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
|
-
|
|
847
|
-
value:
|
|
848
|
-
onChange:
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
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__ */
|
|
858
|
-
/* @__PURE__ */
|
|
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__ */
|
|
1462
|
+
/* @__PURE__ */ jsx5(
|
|
871
1463
|
"button",
|
|
872
1464
|
{
|
|
873
1465
|
type: "submit",
|
|
874
1466
|
style: S.button,
|
|
875
|
-
disabled: submitting ||
|
|
1467
|
+
disabled: submitting || !phoneValue || !password,
|
|
876
1468
|
children: submitting ? "Signing in\u2026" : "Sign in"
|
|
877
1469
|
}
|
|
878
1470
|
)
|
|
879
1471
|
] }),
|
|
880
|
-
error && /* @__PURE__ */
|
|
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
|
-
|
|
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.
|
|
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
|
},
|