@passgage/sdk-react-native 1.0.4 → 1.0.6
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/README.md +409 -147
- package/dist/index.d.mts +166 -424
- package/dist/index.d.ts +166 -424
- package/dist/index.js +933 -1197
- package/dist/index.mjs +868 -1132
- package/package.json +8 -4
package/dist/index.js
CHANGED
|
@@ -1,75 +1,91 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var axios = require('axios');
|
|
4
|
+
var React = require('react');
|
|
5
|
+
var zustand = require('zustand');
|
|
6
|
+
var Keychain = require('react-native-keychain');
|
|
7
|
+
var Geolocation2 = require('react-native-geolocation-service');
|
|
8
|
+
var RNPermissions = require('react-native-permissions');
|
|
9
|
+
var reactNative = require('react-native');
|
|
10
|
+
var NfcManager = require('react-native-nfc-manager');
|
|
11
|
+
|
|
12
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
|
+
|
|
14
|
+
function _interopNamespace(e) {
|
|
15
|
+
if (e && e.__esModule) return e;
|
|
16
|
+
var n = Object.create(null);
|
|
17
|
+
if (e) {
|
|
18
|
+
Object.keys(e).forEach(function (k) {
|
|
19
|
+
if (k !== 'default') {
|
|
20
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
21
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
get: function () { return e[k]; }
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
n.default = e;
|
|
29
|
+
return Object.freeze(n);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
var axios__default = /*#__PURE__*/_interopDefault(axios);
|
|
33
|
+
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
34
|
+
var Keychain__namespace = /*#__PURE__*/_interopNamespace(Keychain);
|
|
35
|
+
var Geolocation2__default = /*#__PURE__*/_interopDefault(Geolocation2);
|
|
36
|
+
var RNPermissions__default = /*#__PURE__*/_interopDefault(RNPermissions);
|
|
37
|
+
var NfcManager__default = /*#__PURE__*/_interopDefault(NfcManager);
|
|
38
|
+
|
|
3
39
|
var __defProp = Object.defineProperty;
|
|
4
|
-
var
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
40
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
41
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
42
|
+
}) : x)(function(x) {
|
|
43
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
44
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
45
|
+
});
|
|
8
46
|
var __export = (target, all) => {
|
|
9
47
|
for (var name in all)
|
|
10
48
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
49
|
};
|
|
12
|
-
var
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
50
|
+
var httpClient = axios__default.default.create();
|
|
51
|
+
var createHttpClient = ({
|
|
52
|
+
baseURL,
|
|
53
|
+
apiVersion,
|
|
54
|
+
timeout = 3e3
|
|
55
|
+
}) => {
|
|
56
|
+
httpClient = axios__default.default.create({
|
|
57
|
+
baseURL: `${baseURL}/api/${apiVersion}`,
|
|
58
|
+
timeout,
|
|
59
|
+
headers: {
|
|
60
|
+
"Content-Type": "application/json",
|
|
61
|
+
Accept: "application/json"
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
httpClient.interceptors.request.use(
|
|
65
|
+
(config) => {
|
|
66
|
+
return config;
|
|
67
|
+
},
|
|
68
|
+
(error) => {
|
|
69
|
+
return Promise.reject(error);
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
httpClient.interceptors.response.use(
|
|
73
|
+
(response) => {
|
|
74
|
+
const originalRequest = response.config;
|
|
75
|
+
if (response.status === 401 && originalRequest) {
|
|
76
|
+
return new Promise(async (resolve, _reject) => {
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return response.data;
|
|
80
|
+
},
|
|
81
|
+
(err) => {
|
|
82
|
+
return Promise.reject(err);
|
|
83
|
+
}
|
|
84
|
+
);
|
|
85
|
+
};
|
|
86
|
+
var setTokenToHttpClient = (token) => {
|
|
87
|
+
httpClient.defaults.headers["Authorization"] = token ? `Bearer ${token}` : "";
|
|
19
88
|
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
|
|
30
|
-
// src/index.ts
|
|
31
|
-
var index_exports = {};
|
|
32
|
-
__export(index_exports, {
|
|
33
|
-
ApiClient: () => ApiClient,
|
|
34
|
-
AuthService: () => AuthService,
|
|
35
|
-
CheckInService: () => CheckInService,
|
|
36
|
-
DeviceAccessService: () => DeviceAccessService,
|
|
37
|
-
DeviceDirection: () => DeviceDirection,
|
|
38
|
-
DeviceUsage: () => DeviceUsage,
|
|
39
|
-
Endpoints: () => endpoints_exports,
|
|
40
|
-
EntranceType: () => EntranceType,
|
|
41
|
-
LocationService: () => LocationService,
|
|
42
|
-
NFCAccessService: () => NFCAccessService,
|
|
43
|
-
PassgageAccessProvider: () => PassgageAccessProvider,
|
|
44
|
-
QRAccessService: () => QRAccessService,
|
|
45
|
-
RemoteWorkService: () => RemoteWorkService,
|
|
46
|
-
SDK_VERSION: () => SDK_VERSION,
|
|
47
|
-
calculateDistance: () => calculateDistance,
|
|
48
|
-
checkOnLocation: () => checkOnLocation,
|
|
49
|
-
checkRepetitiveRead: () => checkRepetitiveRead,
|
|
50
|
-
clearReadRecords: () => clearReadRecords,
|
|
51
|
-
createApiClient: () => createApiClient,
|
|
52
|
-
formatDate: () => formatDate,
|
|
53
|
-
formatDateTime: () => formatDateTime,
|
|
54
|
-
formatISO: () => formatISO,
|
|
55
|
-
formatTime: () => formatTime,
|
|
56
|
-
parseISO: () => parseISO,
|
|
57
|
-
useLocation: () => useLocation,
|
|
58
|
-
usePassgageAccess: () => usePassgageAccess,
|
|
59
|
-
usePassgageAuth: () => usePassgageAuth,
|
|
60
|
-
usePassgageCheckIn: () => usePassgageCheckIn,
|
|
61
|
-
usePassgageNFCScanner: () => usePassgageNFCScanner,
|
|
62
|
-
usePassgageQRScanner: () => usePassgageQRScanner,
|
|
63
|
-
usePassgageRemoteWork: () => usePassgageRemoteWork,
|
|
64
|
-
validateCoordinates: () => validateCoordinates,
|
|
65
|
-
validateDeviceId: () => validateDeviceId,
|
|
66
|
-
validateNFCCode: () => validateNFCCode,
|
|
67
|
-
validateQRCode: () => validateQRCode
|
|
68
|
-
});
|
|
69
|
-
module.exports = __toCommonJS(index_exports);
|
|
70
|
-
|
|
71
|
-
// src/api/client.ts
|
|
72
|
-
var import_axios = __toESM(require("axios"));
|
|
73
89
|
var ApiClient = class {
|
|
74
90
|
constructor(config) {
|
|
75
91
|
this.isRefreshing = false;
|
|
@@ -79,7 +95,7 @@ var ApiClient = class {
|
|
|
79
95
|
apiVersion: "v2",
|
|
80
96
|
...config
|
|
81
97
|
};
|
|
82
|
-
this.axiosInstance =
|
|
98
|
+
this.axiosInstance = axios__default.default.create({
|
|
83
99
|
baseURL: `${this.config.baseURL}/api/${this.config.apiVersion}`,
|
|
84
100
|
timeout: this.config.timeout,
|
|
85
101
|
headers: {
|
|
@@ -230,32 +246,24 @@ var ApiClient = class {
|
|
|
230
246
|
* Generic PUT request
|
|
231
247
|
*/
|
|
232
248
|
async put(options) {
|
|
233
|
-
const response = await this.axiosInstance.put(
|
|
234
|
-
options.
|
|
235
|
-
options.
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
...options.config,
|
|
240
|
-
skipAuth: options.skipAuth
|
|
241
|
-
}
|
|
242
|
-
);
|
|
249
|
+
const response = await this.axiosInstance.put(options.endpoint, options.data, {
|
|
250
|
+
params: options.params,
|
|
251
|
+
headers: options.headers,
|
|
252
|
+
...options.config,
|
|
253
|
+
skipAuth: options.skipAuth
|
|
254
|
+
});
|
|
243
255
|
return response.data;
|
|
244
256
|
}
|
|
245
257
|
/**
|
|
246
258
|
* Generic PATCH request
|
|
247
259
|
*/
|
|
248
260
|
async patch(options) {
|
|
249
|
-
const response = await this.axiosInstance.patch(
|
|
250
|
-
options.
|
|
251
|
-
options.
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
...options.config,
|
|
256
|
-
skipAuth: options.skipAuth
|
|
257
|
-
}
|
|
258
|
-
);
|
|
261
|
+
const response = await this.axiosInstance.patch(options.endpoint, options.data, {
|
|
262
|
+
params: options.params,
|
|
263
|
+
headers: options.headers,
|
|
264
|
+
...options.config,
|
|
265
|
+
skipAuth: options.skipAuth
|
|
266
|
+
});
|
|
259
267
|
return response.data;
|
|
260
268
|
}
|
|
261
269
|
/**
|
|
@@ -278,6 +286,7 @@ function createApiClient(config) {
|
|
|
278
286
|
// src/api/endpoints.ts
|
|
279
287
|
var endpoints_exports = {};
|
|
280
288
|
__export(endpoints_exports, {
|
|
289
|
+
EP_AZURE_AUTH: () => EP_AZURE_AUTH,
|
|
281
290
|
EP_BRANCHES: () => EP_BRANCHES,
|
|
282
291
|
EP_CREATE_QR: () => EP_CREATE_QR,
|
|
283
292
|
EP_DEVICES: () => EP_DEVICES,
|
|
@@ -295,6 +304,7 @@ __export(endpoints_exports, {
|
|
|
295
304
|
});
|
|
296
305
|
var EP_LOGIN = "users/sign_in";
|
|
297
306
|
var EP_TOKEN = "token";
|
|
307
|
+
var EP_AZURE_AUTH = "auth/azure";
|
|
298
308
|
var EP_DEVICES = "devices";
|
|
299
309
|
var EP_QR_DEVICES = "devices/qr_devices";
|
|
300
310
|
var EP_QR_ACCESS = "qr_access/accessible_qrs";
|
|
@@ -328,17 +338,7 @@ var DeviceDirection = /* @__PURE__ */ ((DeviceDirection2) => {
|
|
|
328
338
|
})(DeviceDirection || {});
|
|
329
339
|
|
|
330
340
|
// src/services/AuthService.ts
|
|
331
|
-
var AuthService =
|
|
332
|
-
constructor(apiClient) {
|
|
333
|
-
this.apiClient = apiClient;
|
|
334
|
-
}
|
|
335
|
-
/**
|
|
336
|
-
* Set token storage implementation
|
|
337
|
-
* This is used by platform-specific implementations (React Native, Android, iOS)
|
|
338
|
-
*/
|
|
339
|
-
setTokenStorage(storage) {
|
|
340
|
-
this.tokenStorage = storage;
|
|
341
|
-
}
|
|
341
|
+
var AuthService = {
|
|
342
342
|
/**
|
|
343
343
|
* Login with credentials
|
|
344
344
|
*
|
|
@@ -359,7 +359,7 @@ var AuthService = class {
|
|
|
359
359
|
* }
|
|
360
360
|
* ```
|
|
361
361
|
*/
|
|
362
|
-
async
|
|
362
|
+
login: async (credentials) => {
|
|
363
363
|
try {
|
|
364
364
|
const requestBody = {
|
|
365
365
|
user: {
|
|
@@ -367,12 +367,7 @@ var AuthService = class {
|
|
|
367
367
|
password: credentials.password
|
|
368
368
|
}
|
|
369
369
|
};
|
|
370
|
-
const response = await
|
|
371
|
-
endpoint: "/api/v2/users/sign_in",
|
|
372
|
-
data: requestBody,
|
|
373
|
-
skipAuth: true
|
|
374
|
-
// Don't send auth header for login
|
|
375
|
-
});
|
|
370
|
+
const response = await httpClient.post(EP_LOGIN, requestBody);
|
|
376
371
|
if (!response.success || !response.data?.tokens) {
|
|
377
372
|
return {
|
|
378
373
|
success: false,
|
|
@@ -381,18 +376,12 @@ var AuthService = class {
|
|
|
381
376
|
};
|
|
382
377
|
}
|
|
383
378
|
const tokens = response.data.tokens;
|
|
384
|
-
|
|
385
|
-
await this.tokenStorage.saveTokens(tokens);
|
|
386
|
-
}
|
|
387
|
-
this.apiClient.setToken(tokens.access.token);
|
|
379
|
+
setTokenToHttpClient(tokens.access.token);
|
|
388
380
|
let user;
|
|
389
381
|
try {
|
|
390
|
-
const userResult = await
|
|
382
|
+
const userResult = await AuthService.getCurrentUser();
|
|
391
383
|
if (userResult.success) {
|
|
392
384
|
user = userResult.user;
|
|
393
|
-
if (this.tokenStorage) {
|
|
394
|
-
await this.tokenStorage.saveUser(user);
|
|
395
|
-
}
|
|
396
385
|
}
|
|
397
386
|
} catch (error) {
|
|
398
387
|
console.warn("Failed to fetch user info after login:", error);
|
|
@@ -409,7 +398,68 @@ var AuthService = class {
|
|
|
409
398
|
code: error.code || "NETWORK_ERROR"
|
|
410
399
|
};
|
|
411
400
|
}
|
|
412
|
-
}
|
|
401
|
+
},
|
|
402
|
+
/**
|
|
403
|
+
* Login with Azure AD token
|
|
404
|
+
*
|
|
405
|
+
* @param credentials - Azure AD login credentials (id_token and optional device_type)
|
|
406
|
+
* @returns Login result with tokens on success
|
|
407
|
+
*
|
|
408
|
+
* @example
|
|
409
|
+
* ```typescript
|
|
410
|
+
* const result = await authService.loginWithAzure({
|
|
411
|
+
* id_token: 'azure_id_token_here',
|
|
412
|
+
* device_type: 'ios'
|
|
413
|
+
* });
|
|
414
|
+
*
|
|
415
|
+
* if (result.success) {
|
|
416
|
+
* console.log('Access token:', result.tokens.access.token);
|
|
417
|
+
* } else {
|
|
418
|
+
* console.error('Azure login failed:', result.error);
|
|
419
|
+
* }
|
|
420
|
+
* ```
|
|
421
|
+
*/
|
|
422
|
+
loginWithAzure: async (credentials) => {
|
|
423
|
+
try {
|
|
424
|
+
const response = await httpClient.post(
|
|
425
|
+
EP_AZURE_AUTH,
|
|
426
|
+
{
|
|
427
|
+
id_token: credentials.id_token,
|
|
428
|
+
device_type: credentials.device_type || "android"
|
|
429
|
+
},
|
|
430
|
+
{ skipAuth: true }
|
|
431
|
+
);
|
|
432
|
+
if (!response.success || !response.data?.tokens) {
|
|
433
|
+
return {
|
|
434
|
+
success: false,
|
|
435
|
+
error: response.message || "Azure login failed",
|
|
436
|
+
code: "AZURE_LOGIN_FAILED"
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
const tokens = response.data.tokens;
|
|
440
|
+
setTokenToHttpClient(tokens.access.token);
|
|
441
|
+
let user;
|
|
442
|
+
try {
|
|
443
|
+
const userResult = await AuthService.getCurrentUser();
|
|
444
|
+
if (userResult.success) {
|
|
445
|
+
user = userResult.user;
|
|
446
|
+
}
|
|
447
|
+
} catch (error) {
|
|
448
|
+
console.warn("Failed to fetch user info after Azure login:", error);
|
|
449
|
+
}
|
|
450
|
+
return {
|
|
451
|
+
success: true,
|
|
452
|
+
tokens,
|
|
453
|
+
user
|
|
454
|
+
};
|
|
455
|
+
} catch (error) {
|
|
456
|
+
return {
|
|
457
|
+
success: false,
|
|
458
|
+
error: error.message || "An error occurred during Azure login",
|
|
459
|
+
code: error.code || "NETWORK_ERROR"
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
},
|
|
413
463
|
/**
|
|
414
464
|
* Refresh access token using refresh token
|
|
415
465
|
*
|
|
@@ -425,16 +475,18 @@ var AuthService = class {
|
|
|
425
475
|
* }
|
|
426
476
|
* ```
|
|
427
477
|
*/
|
|
428
|
-
async
|
|
478
|
+
refreshToken: async (refreshToken) => {
|
|
429
479
|
try {
|
|
430
480
|
const requestBody = {
|
|
431
481
|
refresh_token: refreshToken
|
|
432
482
|
};
|
|
433
|
-
const response = await
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
483
|
+
const response = await httpClient.post(
|
|
484
|
+
"/token",
|
|
485
|
+
{
|
|
486
|
+
data: requestBody
|
|
487
|
+
},
|
|
488
|
+
{ skipAuth: true }
|
|
489
|
+
);
|
|
438
490
|
if (!response.success || !response.data?.token || !response.data?.refresh_token) {
|
|
439
491
|
return {
|
|
440
492
|
success: false,
|
|
@@ -444,18 +496,14 @@ var AuthService = class {
|
|
|
444
496
|
}
|
|
445
497
|
const tokens = {
|
|
446
498
|
access: {
|
|
447
|
-
token: response.data.token,
|
|
499
|
+
token: response.data.token ?? "",
|
|
448
500
|
expiresIn: "30 days"
|
|
449
501
|
},
|
|
450
502
|
refresh: {
|
|
451
|
-
token: response.data.refresh_token,
|
|
503
|
+
token: response.data.refresh_token ?? "",
|
|
452
504
|
expiresIn: "30 days"
|
|
453
505
|
}
|
|
454
506
|
};
|
|
455
|
-
if (this.tokenStorage) {
|
|
456
|
-
await this.tokenStorage.saveTokens(tokens);
|
|
457
|
-
}
|
|
458
|
-
this.apiClient.setToken(tokens.access.token);
|
|
459
507
|
return {
|
|
460
508
|
success: true,
|
|
461
509
|
tokens
|
|
@@ -467,7 +515,7 @@ var AuthService = class {
|
|
|
467
515
|
code: error.code || "NETWORK_ERROR"
|
|
468
516
|
};
|
|
469
517
|
}
|
|
470
|
-
}
|
|
518
|
+
},
|
|
471
519
|
/**
|
|
472
520
|
* Get current user information
|
|
473
521
|
*
|
|
@@ -482,12 +530,10 @@ var AuthService = class {
|
|
|
482
530
|
* }
|
|
483
531
|
* ```
|
|
484
532
|
*/
|
|
485
|
-
async
|
|
533
|
+
getCurrentUser: async () => {
|
|
486
534
|
try {
|
|
487
|
-
const response = await
|
|
488
|
-
|
|
489
|
-
});
|
|
490
|
-
if (!response.success || !response.data) {
|
|
535
|
+
const response = await httpClient.get(EP_ME);
|
|
536
|
+
if (!response || !response.data) {
|
|
491
537
|
return {
|
|
492
538
|
success: false,
|
|
493
539
|
error: response.message || "Failed to fetch user information"
|
|
@@ -521,69 +567,40 @@ var AuthService = class {
|
|
|
521
567
|
};
|
|
522
568
|
}
|
|
523
569
|
}
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
// src/services/QRAccessService.ts
|
|
573
|
+
var QRAccessService = {
|
|
524
574
|
/**
|
|
525
|
-
*
|
|
526
|
-
* Clears tokens from storage and API client
|
|
527
|
-
*
|
|
528
|
-
* @example
|
|
529
|
-
* ```typescript
|
|
530
|
-
* await authService.logout();
|
|
531
|
-
* console.log('User logged out');
|
|
532
|
-
* ```
|
|
533
|
-
*/
|
|
534
|
-
async logout() {
|
|
535
|
-
if (this.tokenStorage) {
|
|
536
|
-
await this.tokenStorage.clearTokens();
|
|
537
|
-
await this.tokenStorage.clearUser();
|
|
538
|
-
}
|
|
539
|
-
this.apiClient.setToken(null);
|
|
540
|
-
}
|
|
541
|
-
/**
|
|
542
|
-
* Check if user is authenticated
|
|
543
|
-
*
|
|
544
|
-
* @returns True if user has valid tokens
|
|
545
|
-
*/
|
|
546
|
-
async isAuthenticated() {
|
|
547
|
-
if (!this.tokenStorage) {
|
|
548
|
-
return false;
|
|
549
|
-
}
|
|
550
|
-
const tokens = await this.tokenStorage.getTokens();
|
|
551
|
-
return tokens !== null && tokens.access.token.length > 0;
|
|
552
|
-
}
|
|
553
|
-
/**
|
|
554
|
-
* Get stored tokens
|
|
555
|
-
*
|
|
556
|
-
* @returns Stored tokens or null
|
|
575
|
+
* Trigger IoT device
|
|
557
576
|
*/
|
|
558
|
-
async
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
}
|
|
577
|
+
triggerIoTDevice: async (deviceId, config) => {
|
|
578
|
+
return httpClient.post(
|
|
579
|
+
`${EP_TRIGGER_IOT}/${deviceId}`,
|
|
580
|
+
config
|
|
581
|
+
);
|
|
582
|
+
},
|
|
564
583
|
/**
|
|
565
|
-
*
|
|
566
|
-
*
|
|
567
|
-
* @returns Stored user or null
|
|
584
|
+
* Create entrance from QR code
|
|
568
585
|
*/
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
586
|
+
createEntranceFromQR: (request2) => {
|
|
587
|
+
return httpClient.post(
|
|
588
|
+
EP_CREATE_QR,
|
|
589
|
+
request2
|
|
590
|
+
);
|
|
574
591
|
}
|
|
575
592
|
};
|
|
576
593
|
|
|
577
594
|
// src/utils/location.ts
|
|
578
595
|
function calculateDistance(lat1, lon1, lat2, lon2) {
|
|
579
|
-
|
|
580
|
-
const
|
|
581
|
-
const
|
|
582
|
-
const
|
|
583
|
-
const
|
|
584
|
-
const a = Math.sin(
|
|
596
|
+
let earthRadiusKm = 6371;
|
|
597
|
+
const lat1Rad = lat1 * Math.PI / 180;
|
|
598
|
+
const lat2Rad = lat2 * Math.PI / 180;
|
|
599
|
+
const dLat = (lat2 - lat1) * Math.PI / 180;
|
|
600
|
+
const dLon = (lon2 - lon1) * Math.PI / 180;
|
|
601
|
+
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(lat1Rad) * Math.cos(lat2Rad) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
|
|
585
602
|
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
586
|
-
return
|
|
603
|
+
return earthRadiusKm * c;
|
|
587
604
|
}
|
|
588
605
|
function checkOnLocation(targetLat, targetLon, allowedRange, userPosition) {
|
|
589
606
|
if (!userPosition) {
|
|
@@ -609,20 +626,27 @@ function validateCoordinates(coords) {
|
|
|
609
626
|
}
|
|
610
627
|
|
|
611
628
|
// src/utils/validation.ts
|
|
612
|
-
var READ_TIMEOUT =
|
|
629
|
+
var READ_TIMEOUT = 3e4;
|
|
613
630
|
var readRecords = [];
|
|
614
631
|
function checkRepetitiveRead(code) {
|
|
615
632
|
const now = Date.now();
|
|
616
|
-
readRecords = readRecords.filter(
|
|
633
|
+
readRecords = readRecords.filter(
|
|
634
|
+
(record) => now - record.timestamp < READ_TIMEOUT
|
|
635
|
+
);
|
|
617
636
|
const recentRead = readRecords.find(
|
|
618
637
|
(record) => record.code === code && now - record.timestamp < READ_TIMEOUT
|
|
619
638
|
);
|
|
620
639
|
if (recentRead) {
|
|
621
640
|
return false;
|
|
622
641
|
}
|
|
623
|
-
readRecords.push({ code, timestamp: now });
|
|
624
642
|
return true;
|
|
625
643
|
}
|
|
644
|
+
var addQrReadRecord = (code) => {
|
|
645
|
+
const now = Date.now();
|
|
646
|
+
if (code) {
|
|
647
|
+
readRecords.push({ code, timestamp: now });
|
|
648
|
+
}
|
|
649
|
+
};
|
|
626
650
|
function clearReadRecords() {
|
|
627
651
|
readRecords = [];
|
|
628
652
|
}
|
|
@@ -636,6 +660,27 @@ function validateDeviceId(id) {
|
|
|
636
660
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
637
661
|
return uuidRegex.test(id);
|
|
638
662
|
}
|
|
663
|
+
var shouldValidateLocation = (device) => {
|
|
664
|
+
return device.range_matter === "1" && !!device.latitude && !!device.longitude;
|
|
665
|
+
};
|
|
666
|
+
var validateLocation = (device, userLocation) => {
|
|
667
|
+
if (!shouldValidateLocation(device)) {
|
|
668
|
+
return { valid: true };
|
|
669
|
+
}
|
|
670
|
+
if (!userLocation) {
|
|
671
|
+
return { valid: false };
|
|
672
|
+
}
|
|
673
|
+
const locationCheck = checkOnLocation(
|
|
674
|
+
device.latitude,
|
|
675
|
+
device.longitude,
|
|
676
|
+
device.range || 100,
|
|
677
|
+
userLocation
|
|
678
|
+
);
|
|
679
|
+
return {
|
|
680
|
+
valid: locationCheck.ok,
|
|
681
|
+
distance: locationCheck.distance
|
|
682
|
+
};
|
|
683
|
+
};
|
|
639
684
|
|
|
640
685
|
// src/utils/date.ts
|
|
641
686
|
function formatISO(date = /* @__PURE__ */ new Date()) {
|
|
@@ -662,442 +707,162 @@ function parseISO(isoString) {
|
|
|
662
707
|
return new Date(isoString);
|
|
663
708
|
}
|
|
664
709
|
|
|
665
|
-
// src/services/
|
|
666
|
-
var
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
}
|
|
676
|
-
/**
|
|
677
|
-
* Check if location validation is required
|
|
678
|
-
*/
|
|
679
|
-
shouldValidateLocation(device) {
|
|
680
|
-
return device.range_matter === "1" && !!device.latitude && !!device.longitude;
|
|
681
|
-
}
|
|
682
|
-
/**
|
|
683
|
-
* Validate user location against device location
|
|
684
|
-
*/
|
|
685
|
-
validateLocation(device, userLocation) {
|
|
686
|
-
if (!this.shouldValidateLocation(device)) {
|
|
710
|
+
// src/services/NFCAccessService.ts
|
|
711
|
+
var NfcAccessService = {
|
|
712
|
+
validateNFCFormat: (code) => {
|
|
713
|
+
return validateNFCCode(code);
|
|
714
|
+
},
|
|
715
|
+
shouldValidateLocation: (device) => {
|
|
716
|
+
return device?.nfc_range_matter === "1" && !!device?.latitude && !!device.longitude;
|
|
717
|
+
},
|
|
718
|
+
validateLocation: (device, userLocation) => {
|
|
719
|
+
if (!NfcAccessService.shouldValidateLocation(device)) {
|
|
687
720
|
return { valid: true };
|
|
688
721
|
}
|
|
689
722
|
if (!userLocation) {
|
|
690
723
|
return { valid: false };
|
|
691
724
|
}
|
|
692
725
|
const locationCheck = checkOnLocation(
|
|
693
|
-
device
|
|
694
|
-
device
|
|
695
|
-
device
|
|
726
|
+
device?.latitude,
|
|
727
|
+
device?.longitude,
|
|
728
|
+
device?.nfc_range || 100,
|
|
696
729
|
userLocation
|
|
697
730
|
);
|
|
698
731
|
return {
|
|
699
732
|
valid: locationCheck.ok,
|
|
700
733
|
distance: locationCheck.distance
|
|
701
734
|
};
|
|
702
|
-
}
|
|
735
|
+
},
|
|
703
736
|
/**
|
|
704
|
-
* Validate
|
|
737
|
+
* Validate NFC code with full checks
|
|
705
738
|
*/
|
|
706
|
-
async
|
|
707
|
-
const {
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
if (!skipLocationCheck) {
|
|
723
|
-
const locationValidation = this.validateLocation(device, userLocation);
|
|
724
|
-
if (!locationValidation.valid) {
|
|
739
|
+
async validateNFC(options) {
|
|
740
|
+
const { device } = options;
|
|
741
|
+
const onlineRequestBody = {
|
|
742
|
+
device_id: device.id
|
|
743
|
+
};
|
|
744
|
+
if (device.is_iot) {
|
|
745
|
+
try {
|
|
746
|
+
const enteranceQrRes = await QRAccessService.createEntranceFromQR(
|
|
747
|
+
onlineRequestBody
|
|
748
|
+
);
|
|
749
|
+
return {
|
|
750
|
+
success: !!enteranceQrRes?.success,
|
|
751
|
+
message: "QR code validated successfully",
|
|
752
|
+
entrance: enteranceQrRes.data
|
|
753
|
+
};
|
|
754
|
+
} catch (error) {
|
|
725
755
|
return {
|
|
726
756
|
success: false,
|
|
727
|
-
message:
|
|
728
|
-
error: {
|
|
729
|
-
code: "LOCATION_OUT_OF_RANGE",
|
|
730
|
-
details: locationValidation.distance ? `Distance: ${locationValidation.distance.toFixed(2)}m` : void 0
|
|
731
|
-
}
|
|
757
|
+
message: error.message || "Failed to validate QR code",
|
|
758
|
+
error: { code: "NETWORK_ERROR" }
|
|
732
759
|
};
|
|
733
760
|
}
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
761
|
+
} else {
|
|
762
|
+
try {
|
|
763
|
+
const enteranceQrRes = await QRAccessService.createEntranceFromQR(
|
|
764
|
+
onlineRequestBody
|
|
765
|
+
);
|
|
766
|
+
return {
|
|
767
|
+
success: !!enteranceQrRes?.success,
|
|
768
|
+
message: "QR code validated successfully",
|
|
769
|
+
entrance: enteranceQrRes.data
|
|
770
|
+
};
|
|
771
|
+
} catch (error) {
|
|
741
772
|
return {
|
|
742
773
|
success: false,
|
|
743
|
-
message:
|
|
744
|
-
error: { code: "
|
|
774
|
+
message: error.message || "Failed to validate QR code",
|
|
775
|
+
error: { code: "NETWORK_ERROR" }
|
|
745
776
|
};
|
|
746
777
|
}
|
|
747
|
-
return {
|
|
748
|
-
success: true,
|
|
749
|
-
message: "QR code validated successfully",
|
|
750
|
-
entrance: response.data
|
|
751
|
-
};
|
|
752
|
-
} catch (error) {
|
|
753
|
-
return {
|
|
754
|
-
success: false,
|
|
755
|
-
message: error.message || "Failed to validate QR code",
|
|
756
|
-
error: { code: "NETWORK_ERROR" }
|
|
757
|
-
};
|
|
758
778
|
}
|
|
759
779
|
}
|
|
780
|
+
};
|
|
781
|
+
|
|
782
|
+
// src/services/DeviceAccessService.ts
|
|
783
|
+
var DeviceAccessService = {
|
|
760
784
|
/**
|
|
761
|
-
*
|
|
785
|
+
* Get all devices
|
|
762
786
|
*/
|
|
763
|
-
async
|
|
764
|
-
return
|
|
765
|
-
|
|
766
|
-
data: request
|
|
787
|
+
getDevices: async (params) => {
|
|
788
|
+
return httpClient.get(EP_DEVICES, {
|
|
789
|
+
params: params || { per_page: 100 }
|
|
767
790
|
});
|
|
768
|
-
}
|
|
791
|
+
},
|
|
769
792
|
/**
|
|
770
|
-
*
|
|
793
|
+
* Get all QR devices
|
|
771
794
|
*/
|
|
772
|
-
async
|
|
773
|
-
return
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
var NFCAccessService = class {
|
|
781
|
-
constructor(apiClient) {
|
|
782
|
-
this.apiClient = apiClient;
|
|
783
|
-
}
|
|
795
|
+
getQRDevices: async (params) => {
|
|
796
|
+
return httpClient.get(
|
|
797
|
+
EP_QR_DEVICES,
|
|
798
|
+
{
|
|
799
|
+
params: params || { per_page: 100 }
|
|
800
|
+
}
|
|
801
|
+
);
|
|
802
|
+
},
|
|
784
803
|
/**
|
|
785
|
-
*
|
|
804
|
+
* Get all QR devices with pagination support
|
|
786
805
|
*/
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
806
|
+
getAllQRDevices: async () => {
|
|
807
|
+
const perPage = 50;
|
|
808
|
+
let currentPage = 1;
|
|
809
|
+
let allData = [];
|
|
810
|
+
while (true) {
|
|
811
|
+
const response = await DeviceAccessService.getQRDevices({
|
|
812
|
+
page: currentPage,
|
|
813
|
+
per_page: perPage
|
|
814
|
+
});
|
|
815
|
+
if (!response.success || !response.data) {
|
|
816
|
+
break;
|
|
817
|
+
}
|
|
818
|
+
allData = [...allData, ...response.data];
|
|
819
|
+
if (!response.meta || !response.meta.total_pages) {
|
|
820
|
+
break;
|
|
821
|
+
}
|
|
822
|
+
if (currentPage >= response.meta.total_pages) {
|
|
823
|
+
break;
|
|
824
|
+
}
|
|
825
|
+
currentPage++;
|
|
826
|
+
}
|
|
827
|
+
return allData;
|
|
828
|
+
},
|
|
790
829
|
/**
|
|
791
|
-
*
|
|
830
|
+
* Get accessible QR codes for current user
|
|
792
831
|
*/
|
|
793
|
-
|
|
794
|
-
return
|
|
795
|
-
|
|
832
|
+
getAccessibleQRs: async () => {
|
|
833
|
+
return httpClient.get(
|
|
834
|
+
EP_QR_ACCESS
|
|
835
|
+
);
|
|
836
|
+
},
|
|
796
837
|
/**
|
|
797
|
-
*
|
|
838
|
+
* Get user devices
|
|
798
839
|
*/
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
device.longitude,
|
|
809
|
-
device.nfc_range || 100,
|
|
810
|
-
userLocation
|
|
811
|
-
);
|
|
812
|
-
return {
|
|
813
|
-
valid: locationCheck.ok,
|
|
814
|
-
distance: locationCheck.distance
|
|
815
|
-
};
|
|
816
|
-
}
|
|
817
|
-
/**
|
|
818
|
-
* Validate NFC code with full checks
|
|
819
|
-
*/
|
|
820
|
-
async validateNFC(options) {
|
|
821
|
-
const { nfcCode, device, userLocation, skipLocationCheck, skipRepetitiveCheck } = options;
|
|
822
|
-
if (!this.validateNFCFormat(nfcCode)) {
|
|
823
|
-
return {
|
|
824
|
-
success: false,
|
|
825
|
-
message: "Invalid NFC code format",
|
|
826
|
-
error: { code: "INVALID_NFC_FORMAT" }
|
|
827
|
-
};
|
|
828
|
-
}
|
|
829
|
-
if (!skipRepetitiveCheck && !checkRepetitiveRead(nfcCode)) {
|
|
830
|
-
return {
|
|
831
|
-
success: false,
|
|
832
|
-
message: "NFC card was recently scanned. Please wait before scanning again.",
|
|
833
|
-
error: { code: "REPETITIVE_READ" }
|
|
834
|
-
};
|
|
835
|
-
}
|
|
836
|
-
if (!skipLocationCheck) {
|
|
837
|
-
const locationValidation = this.validateLocation(device, userLocation);
|
|
838
|
-
if (!locationValidation.valid) {
|
|
839
|
-
return {
|
|
840
|
-
success: false,
|
|
841
|
-
message: "You are not within the allowed range of this device",
|
|
842
|
-
error: {
|
|
843
|
-
code: "LOCATION_OUT_OF_RANGE",
|
|
844
|
-
details: locationValidation.distance ? `Distance: ${locationValidation.distance.toFixed(2)}m` : void 0
|
|
845
|
-
}
|
|
846
|
-
};
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
try {
|
|
850
|
-
const response = await this.apiClient.post({
|
|
851
|
-
endpoint: EP_NFC_CHECK,
|
|
852
|
-
data: { nfc_code: nfcCode }
|
|
853
|
-
});
|
|
854
|
-
if (!response.success) {
|
|
855
|
-
return {
|
|
856
|
-
success: false,
|
|
857
|
-
message: response.message || "NFC validation failed",
|
|
858
|
-
error: { code: "API_ERROR" }
|
|
859
|
-
};
|
|
860
|
-
}
|
|
861
|
-
return {
|
|
862
|
-
success: true,
|
|
863
|
-
message: "NFC card validated successfully",
|
|
864
|
-
entrance: response.data
|
|
865
|
-
};
|
|
866
|
-
} catch (error) {
|
|
867
|
-
return {
|
|
868
|
-
success: false,
|
|
869
|
-
message: error.message || "Failed to validate NFC card",
|
|
870
|
-
error: { code: "NETWORK_ERROR" }
|
|
871
|
-
};
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
};
|
|
875
|
-
|
|
876
|
-
// src/services/CheckInService.ts
|
|
877
|
-
var CheckInService = class {
|
|
878
|
-
constructor(apiClient) {
|
|
879
|
-
this.apiClient = apiClient;
|
|
880
|
-
}
|
|
881
|
-
/**
|
|
882
|
-
* Get nearby branches based on user location
|
|
883
|
-
*/
|
|
884
|
-
async getNearbyBranches(request) {
|
|
885
|
-
const { latitude, longitude, radius } = request;
|
|
886
|
-
if (!validateCoordinates({ latitude, longitude })) {
|
|
887
|
-
throw new Error("Invalid coordinates provided");
|
|
888
|
-
}
|
|
889
|
-
return this.apiClient.get({
|
|
890
|
-
endpoint: EP_BRANCHES,
|
|
891
|
-
params: {
|
|
892
|
-
latitude,
|
|
893
|
-
longitude,
|
|
894
|
-
...radius && { radius }
|
|
895
|
-
}
|
|
896
|
-
});
|
|
897
|
-
}
|
|
898
|
-
/**
|
|
899
|
-
* Check in to a branch
|
|
900
|
-
*/
|
|
901
|
-
async checkIn(options) {
|
|
902
|
-
const { branchId, entranceType, userId, userLocation: _userLocation } = options;
|
|
903
|
-
try {
|
|
904
|
-
const entranceRequest = {
|
|
905
|
-
user_id: userId,
|
|
906
|
-
branch_id: branchId,
|
|
907
|
-
entrance_type: entranceType,
|
|
908
|
-
is_manual_recording: false
|
|
909
|
-
};
|
|
910
|
-
const response = await this.apiClient.post({
|
|
911
|
-
endpoint: EP_ENTRANCES,
|
|
912
|
-
data: entranceRequest
|
|
913
|
-
});
|
|
914
|
-
if (!response.success) {
|
|
915
|
-
return {
|
|
916
|
-
success: false,
|
|
917
|
-
message: response.message || "Check-in failed",
|
|
918
|
-
error: { code: "API_ERROR" }
|
|
919
|
-
};
|
|
920
|
-
}
|
|
921
|
-
return {
|
|
922
|
-
success: true,
|
|
923
|
-
message: "Check-in successful",
|
|
924
|
-
entrance: response.data
|
|
925
|
-
};
|
|
926
|
-
} catch (error) {
|
|
927
|
-
return {
|
|
928
|
-
success: false,
|
|
929
|
-
message: error.message || "Failed to check-in",
|
|
930
|
-
error: { code: "NETWORK_ERROR" }
|
|
931
|
-
};
|
|
932
|
-
}
|
|
933
|
-
}
|
|
934
|
-
/**
|
|
935
|
-
* Get branch by ID
|
|
936
|
-
*/
|
|
937
|
-
async getBranchById(branchId) {
|
|
938
|
-
return this.apiClient.get({
|
|
939
|
-
endpoint: `${EP_BRANCHES}/${branchId}`
|
|
940
|
-
});
|
|
941
|
-
}
|
|
942
|
-
/**
|
|
943
|
-
* Get all branches (with pagination)
|
|
944
|
-
*/
|
|
945
|
-
async getAllBranches(params) {
|
|
946
|
-
return this.apiClient.get({
|
|
947
|
-
endpoint: EP_BRANCHES,
|
|
948
|
-
params
|
|
949
|
-
});
|
|
950
|
-
}
|
|
951
|
-
};
|
|
952
|
-
|
|
953
|
-
// src/services/RemoteWorkService.ts
|
|
954
|
-
var RemoteWorkService = class {
|
|
955
|
-
constructor(apiClient) {
|
|
956
|
-
this.apiClient = apiClient;
|
|
957
|
-
}
|
|
958
|
-
/**
|
|
959
|
-
* Log remote work entry or exit
|
|
960
|
-
*/
|
|
961
|
-
async logRemoteWork(options) {
|
|
962
|
-
const { userId, entranceType, timestamp, description } = options;
|
|
963
|
-
try {
|
|
964
|
-
const createdAt = timestamp ? typeof timestamp === "string" ? timestamp : formatISO(timestamp) : formatISO();
|
|
965
|
-
const entranceRequest = {
|
|
966
|
-
user_id: userId,
|
|
967
|
-
entrance_type: entranceType,
|
|
968
|
-
is_manual_recording: true,
|
|
969
|
-
is_remote_work: true,
|
|
970
|
-
created_at: createdAt,
|
|
971
|
-
description
|
|
972
|
-
};
|
|
973
|
-
const response = await this.apiClient.post({
|
|
974
|
-
endpoint: EP_ENTRANCES,
|
|
975
|
-
data: { entrance: entranceRequest }
|
|
976
|
-
});
|
|
977
|
-
if (!response.success) {
|
|
978
|
-
return {
|
|
979
|
-
success: false,
|
|
980
|
-
message: response.message || "Failed to log remote work",
|
|
981
|
-
error: { code: "API_ERROR" }
|
|
982
|
-
};
|
|
983
|
-
}
|
|
984
|
-
return {
|
|
985
|
-
success: true,
|
|
986
|
-
message: "Remote work logged successfully",
|
|
987
|
-
entrance: response.data
|
|
988
|
-
};
|
|
989
|
-
} catch (error) {
|
|
990
|
-
return {
|
|
991
|
-
success: false,
|
|
992
|
-
message: error.message || "Failed to log remote work",
|
|
993
|
-
error: { code: "NETWORK_ERROR" }
|
|
994
|
-
};
|
|
995
|
-
}
|
|
996
|
-
}
|
|
997
|
-
/**
|
|
998
|
-
* Log remote work entry
|
|
999
|
-
*/
|
|
1000
|
-
async logEntry(options) {
|
|
1001
|
-
return this.logRemoteWork({
|
|
1002
|
-
...options,
|
|
1003
|
-
entranceType: 0 /* ENTRY */
|
|
1004
|
-
});
|
|
1005
|
-
}
|
|
1006
|
-
/**
|
|
1007
|
-
* Log remote work exit
|
|
1008
|
-
*/
|
|
1009
|
-
async logExit(options) {
|
|
1010
|
-
return this.logRemoteWork({
|
|
1011
|
-
...options,
|
|
1012
|
-
entranceType: 1 /* EXIT */
|
|
1013
|
-
});
|
|
1014
|
-
}
|
|
1015
|
-
};
|
|
1016
|
-
|
|
1017
|
-
// src/services/DeviceAccessService.ts
|
|
1018
|
-
var DeviceAccessService = class {
|
|
1019
|
-
constructor(apiClient) {
|
|
1020
|
-
this.apiClient = apiClient;
|
|
1021
|
-
}
|
|
1022
|
-
/**
|
|
1023
|
-
* Get all devices
|
|
1024
|
-
*/
|
|
1025
|
-
async getDevices(params) {
|
|
1026
|
-
return this.apiClient.get({
|
|
1027
|
-
endpoint: EP_DEVICES,
|
|
1028
|
-
params: params || { per_page: 100 }
|
|
1029
|
-
});
|
|
1030
|
-
}
|
|
1031
|
-
/**
|
|
1032
|
-
* Get all QR devices
|
|
1033
|
-
*/
|
|
1034
|
-
async getQRDevices(params) {
|
|
1035
|
-
return this.apiClient.get({
|
|
1036
|
-
endpoint: EP_QR_DEVICES,
|
|
1037
|
-
params: params || { per_page: 100 }
|
|
1038
|
-
});
|
|
1039
|
-
}
|
|
1040
|
-
/**
|
|
1041
|
-
* Get all QR devices with pagination support
|
|
1042
|
-
*/
|
|
1043
|
-
async getAllQRDevices() {
|
|
1044
|
-
const perPage = 50;
|
|
1045
|
-
let currentPage = 1;
|
|
1046
|
-
let allData = [];
|
|
1047
|
-
while (true) {
|
|
1048
|
-
const response = await this.getQRDevices({
|
|
1049
|
-
page: currentPage,
|
|
1050
|
-
per_page: perPage
|
|
1051
|
-
});
|
|
1052
|
-
if (!response.success || !response.data) {
|
|
1053
|
-
break;
|
|
1054
|
-
}
|
|
1055
|
-
allData = [...allData, ...response.data];
|
|
1056
|
-
if (!response.meta || !response.meta.total_pages) {
|
|
1057
|
-
break;
|
|
1058
|
-
}
|
|
1059
|
-
if (currentPage >= response.meta.total_pages) {
|
|
1060
|
-
break;
|
|
1061
|
-
}
|
|
1062
|
-
currentPage++;
|
|
1063
|
-
}
|
|
1064
|
-
return allData;
|
|
1065
|
-
}
|
|
1066
|
-
/**
|
|
1067
|
-
* Get accessible QR codes for current user
|
|
1068
|
-
*/
|
|
1069
|
-
async getAccessibleQRs() {
|
|
1070
|
-
return this.apiClient.get({
|
|
1071
|
-
endpoint: EP_QR_ACCESS
|
|
1072
|
-
});
|
|
1073
|
-
}
|
|
1074
|
-
/**
|
|
1075
|
-
* Get user devices
|
|
1076
|
-
*/
|
|
1077
|
-
async getUserDevices(request) {
|
|
1078
|
-
const { userId, page, per_page } = request;
|
|
1079
|
-
return this.apiClient.get({
|
|
1080
|
-
endpoint: `${EP_USERS}/${userId}/devices`,
|
|
1081
|
-
params: {
|
|
1082
|
-
...page && { page },
|
|
1083
|
-
...per_page && { per_page }
|
|
840
|
+
getUserDevices: async (request2) => {
|
|
841
|
+
const { userId, page, per_page } = request2;
|
|
842
|
+
return httpClient.get(
|
|
843
|
+
`${EP_USERS}/${userId}/devices`,
|
|
844
|
+
{
|
|
845
|
+
params: {
|
|
846
|
+
...page && { page },
|
|
847
|
+
...per_page && { per_page }
|
|
848
|
+
}
|
|
1084
849
|
}
|
|
1085
|
-
|
|
1086
|
-
}
|
|
850
|
+
);
|
|
851
|
+
},
|
|
1087
852
|
/**
|
|
1088
853
|
* Get device by ID
|
|
1089
854
|
*/
|
|
1090
|
-
async
|
|
1091
|
-
return
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
}
|
|
855
|
+
getDeviceById: async (deviceId) => {
|
|
856
|
+
return httpClient.get(
|
|
857
|
+
`${EP_DEVICES}/${deviceId}`
|
|
858
|
+
);
|
|
859
|
+
},
|
|
1095
860
|
/**
|
|
1096
861
|
* Check if user has access to a device
|
|
1097
862
|
*/
|
|
1098
|
-
async
|
|
863
|
+
checkDeviceAccess: async (deviceId) => {
|
|
1099
864
|
try {
|
|
1100
|
-
const response = await
|
|
865
|
+
const response = await DeviceAccessService.getAccessibleQRs();
|
|
1101
866
|
if (!response.success || !response.data) {
|
|
1102
867
|
return false;
|
|
1103
868
|
}
|
|
@@ -1105,24 +870,25 @@ var DeviceAccessService = class {
|
|
|
1105
870
|
} catch {
|
|
1106
871
|
return false;
|
|
1107
872
|
}
|
|
1108
|
-
}
|
|
873
|
+
},
|
|
1109
874
|
/**
|
|
1110
875
|
* Find QR device by QR code ID
|
|
1111
876
|
*/
|
|
1112
|
-
async
|
|
877
|
+
findDeviceByQRCode: async (qrCodeId) => {
|
|
1113
878
|
try {
|
|
1114
|
-
const devices = await
|
|
1115
|
-
|
|
879
|
+
const devices = await DeviceAccessService.getAllQRDevices();
|
|
880
|
+
const qr = devices.find((device) => device.qr_code_id === qrCodeId);
|
|
881
|
+
return qr;
|
|
1116
882
|
} catch {
|
|
1117
883
|
return void 0;
|
|
1118
884
|
}
|
|
1119
|
-
}
|
|
885
|
+
},
|
|
1120
886
|
/**
|
|
1121
887
|
* Find QR device by NFC code
|
|
1122
888
|
*/
|
|
1123
|
-
async
|
|
889
|
+
findDeviceByNFCCode: async (nfcCode) => {
|
|
1124
890
|
try {
|
|
1125
|
-
const devices = await
|
|
891
|
+
const devices = await DeviceAccessService.getAllQRDevices();
|
|
1126
892
|
return devices.find((device) => device.nfc_code === nfcCode);
|
|
1127
893
|
} catch {
|
|
1128
894
|
return void 0;
|
|
@@ -1217,41 +983,35 @@ var LocationService = class {
|
|
|
1217
983
|
return this.logLocationVerification(log);
|
|
1218
984
|
}
|
|
1219
985
|
};
|
|
1220
|
-
|
|
1221
|
-
// src/providers/PassgageAccessProvider.tsx
|
|
1222
|
-
var import_react = __toESM(require("react"));
|
|
1223
|
-
|
|
1224
|
-
// src/utils/secureStorage.ts
|
|
1225
|
-
var Keychain = __toESM(require("react-native-keychain"));
|
|
1226
986
|
var STORAGE_KEYS = {
|
|
1227
987
|
TOKENS: "passgage_auth_tokens",
|
|
1228
988
|
USER: "passgage_user_info"
|
|
1229
989
|
};
|
|
1230
|
-
var SecureStorage =
|
|
990
|
+
var SecureStorage = {
|
|
1231
991
|
/**
|
|
1232
992
|
* Save tokens to secure storage
|
|
1233
993
|
*/
|
|
1234
|
-
async
|
|
994
|
+
saveTokens: async (tokens) => {
|
|
1235
995
|
try {
|
|
1236
|
-
await
|
|
996
|
+
await Keychain__namespace.setGenericPassword(
|
|
1237
997
|
STORAGE_KEYS.TOKENS,
|
|
1238
998
|
JSON.stringify(tokens),
|
|
1239
999
|
{
|
|
1240
1000
|
service: STORAGE_KEYS.TOKENS,
|
|
1241
|
-
accessible:
|
|
1001
|
+
accessible: Keychain__namespace.ACCESSIBLE.WHEN_UNLOCKED
|
|
1242
1002
|
}
|
|
1243
1003
|
);
|
|
1244
1004
|
} catch (error) {
|
|
1245
1005
|
console.error("Failed to save tokens to secure storage:", error);
|
|
1246
1006
|
throw new Error("Failed to save tokens");
|
|
1247
1007
|
}
|
|
1248
|
-
}
|
|
1008
|
+
},
|
|
1249
1009
|
/**
|
|
1250
1010
|
* Get tokens from secure storage
|
|
1251
1011
|
*/
|
|
1252
|
-
async
|
|
1012
|
+
getTokens: async () => {
|
|
1253
1013
|
try {
|
|
1254
|
-
const credentials = await
|
|
1014
|
+
const credentials = await Keychain__namespace.getGenericPassword({
|
|
1255
1015
|
service: STORAGE_KEYS.TOKENS
|
|
1256
1016
|
});
|
|
1257
1017
|
if (!credentials) {
|
|
@@ -1263,43 +1023,43 @@ var SecureStorage = class {
|
|
|
1263
1023
|
console.error("Failed to get tokens from secure storage:", error);
|
|
1264
1024
|
return null;
|
|
1265
1025
|
}
|
|
1266
|
-
}
|
|
1026
|
+
},
|
|
1267
1027
|
/**
|
|
1268
1028
|
* Clear tokens from secure storage
|
|
1269
1029
|
*/
|
|
1270
|
-
async
|
|
1030
|
+
clearTokens: async () => {
|
|
1271
1031
|
try {
|
|
1272
|
-
await
|
|
1032
|
+
await Keychain__namespace.resetGenericPassword({
|
|
1273
1033
|
service: STORAGE_KEYS.TOKENS
|
|
1274
1034
|
});
|
|
1275
1035
|
} catch (error) {
|
|
1276
1036
|
console.error("Failed to clear tokens from secure storage:", error);
|
|
1277
1037
|
}
|
|
1278
|
-
}
|
|
1038
|
+
},
|
|
1279
1039
|
/**
|
|
1280
1040
|
* Save user information
|
|
1281
1041
|
*/
|
|
1282
|
-
async
|
|
1042
|
+
saveUser: async (user) => {
|
|
1283
1043
|
try {
|
|
1284
|
-
await
|
|
1044
|
+
await Keychain__namespace.setGenericPassword(
|
|
1285
1045
|
STORAGE_KEYS.USER,
|
|
1286
1046
|
JSON.stringify(user),
|
|
1287
1047
|
{
|
|
1288
1048
|
service: STORAGE_KEYS.USER,
|
|
1289
|
-
accessible:
|
|
1049
|
+
accessible: Keychain__namespace.ACCESSIBLE.WHEN_UNLOCKED
|
|
1290
1050
|
}
|
|
1291
1051
|
);
|
|
1292
1052
|
} catch (error) {
|
|
1293
1053
|
console.error("Failed to save user to secure storage:", error);
|
|
1294
1054
|
throw new Error("Failed to save user");
|
|
1295
1055
|
}
|
|
1296
|
-
}
|
|
1056
|
+
},
|
|
1297
1057
|
/**
|
|
1298
1058
|
* Get user information
|
|
1299
1059
|
*/
|
|
1300
|
-
async
|
|
1060
|
+
getUser: async () => {
|
|
1301
1061
|
try {
|
|
1302
|
-
const credentials = await
|
|
1062
|
+
const credentials = await Keychain__namespace.getGenericPassword({
|
|
1303
1063
|
service: STORAGE_KEYS.USER
|
|
1304
1064
|
});
|
|
1305
1065
|
if (!credentials) {
|
|
@@ -1311,269 +1071,579 @@ var SecureStorage = class {
|
|
|
1311
1071
|
console.error("Failed to get user from secure storage:", error);
|
|
1312
1072
|
return null;
|
|
1313
1073
|
}
|
|
1314
|
-
}
|
|
1074
|
+
},
|
|
1315
1075
|
/**
|
|
1316
1076
|
* Clear user information
|
|
1317
1077
|
*/
|
|
1318
|
-
async
|
|
1078
|
+
clearUser: async () => {
|
|
1319
1079
|
try {
|
|
1320
|
-
await
|
|
1080
|
+
await Keychain__namespace.resetGenericPassword({
|
|
1321
1081
|
service: STORAGE_KEYS.USER
|
|
1322
1082
|
});
|
|
1323
1083
|
} catch (error) {
|
|
1324
1084
|
console.error("Failed to clear user from secure storage:", error);
|
|
1325
1085
|
}
|
|
1326
|
-
}
|
|
1086
|
+
},
|
|
1327
1087
|
/**
|
|
1328
1088
|
* Clear all data (tokens + user)
|
|
1329
1089
|
*/
|
|
1330
|
-
async
|
|
1331
|
-
await
|
|
1332
|
-
await
|
|
1090
|
+
clearAll: async () => {
|
|
1091
|
+
await SecureStorage.clearTokens();
|
|
1092
|
+
await SecureStorage.clearUser();
|
|
1333
1093
|
}
|
|
1334
1094
|
};
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1095
|
+
var qrScannerStore = zustand.create((set) => ({
|
|
1096
|
+
loading: false,
|
|
1097
|
+
error: null,
|
|
1098
|
+
qrDevices: [],
|
|
1099
|
+
qrAccessDevices: [],
|
|
1100
|
+
handleQrAccess: async () => {
|
|
1101
|
+
const res = await DeviceAccessService.getAccessibleQRs();
|
|
1102
|
+
if (res.data) {
|
|
1103
|
+
set({ qrAccessDevices: res.data.qr_ids });
|
|
1104
|
+
}
|
|
1105
|
+
},
|
|
1106
|
+
fetchQrDevicesAndAccess: async () => {
|
|
1107
|
+
try {
|
|
1108
|
+
const [qrDevicesRes, qrAccessRes] = await Promise.all([
|
|
1109
|
+
DeviceAccessService.getAllQRDevices(),
|
|
1110
|
+
DeviceAccessService.getAccessibleQRs()
|
|
1111
|
+
]);
|
|
1112
|
+
if (qrDevicesRes && qrDevicesRes.length > 0 && qrAccessRes) {
|
|
1113
|
+
set({
|
|
1114
|
+
qrDevices: qrDevicesRes,
|
|
1115
|
+
qrAccessDevices: qrAccessRes.data?.qr_ids
|
|
1116
|
+
});
|
|
1117
|
+
}
|
|
1118
|
+
} catch (error) {
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
}));
|
|
1122
|
+
var locationStore = zustand.create((set) => ({
|
|
1123
|
+
location: null,
|
|
1124
|
+
error: null,
|
|
1125
|
+
loading: false,
|
|
1126
|
+
refreshLocation: (config = {
|
|
1127
|
+
enableHighAccuracy: true,
|
|
1128
|
+
timeout: 15e3,
|
|
1129
|
+
maximumAge: 1e4
|
|
1130
|
+
}) => {
|
|
1131
|
+
Geolocation2__default.default.getCurrentPosition(
|
|
1132
|
+
(position) => {
|
|
1133
|
+
set({
|
|
1134
|
+
loading: false,
|
|
1135
|
+
error: null,
|
|
1136
|
+
location: {
|
|
1137
|
+
latitude: position.coords.latitude,
|
|
1138
|
+
longitude: position.coords.longitude,
|
|
1139
|
+
accuracy: position.coords.accuracy,
|
|
1140
|
+
altitude: position.coords.altitude ?? void 0,
|
|
1141
|
+
altitudeAccuracy: position.coords.altitudeAccuracy ?? void 0,
|
|
1142
|
+
heading: position.coords.heading ?? void 0,
|
|
1143
|
+
speed: position.coords.speed ?? void 0
|
|
1144
|
+
}
|
|
1145
|
+
});
|
|
1146
|
+
},
|
|
1147
|
+
(err) => {
|
|
1148
|
+
set({
|
|
1149
|
+
loading: false,
|
|
1150
|
+
error: err
|
|
1151
|
+
});
|
|
1152
|
+
},
|
|
1153
|
+
config
|
|
1154
|
+
);
|
|
1155
|
+
}
|
|
1156
|
+
}));
|
|
1338
1157
|
|
|
1339
|
-
// src/
|
|
1340
|
-
var
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
}
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
const { apiClient, services } = (0, import_react.useMemo)(() => {
|
|
1359
|
-
const secureStorage = createSecureStorage();
|
|
1360
|
-
let authService;
|
|
1361
|
-
const client = createApiClient({
|
|
1362
|
-
baseURL: config.baseURL,
|
|
1363
|
-
token: config.token,
|
|
1364
|
-
apiVersion: config.apiVersion,
|
|
1365
|
-
timeout: config.timeout,
|
|
1366
|
-
onUnauthorized: config.onUnauthorized,
|
|
1367
|
-
onError: config.onError,
|
|
1368
|
-
onTokenRefreshNeeded: async () => {
|
|
1369
|
-
const storedTokens = await authService.getStoredTokens();
|
|
1370
|
-
if (!storedTokens) {
|
|
1371
|
-
return null;
|
|
1372
|
-
}
|
|
1373
|
-
const result = await authService.refreshToken(storedTokens.refresh.token);
|
|
1374
|
-
if (result.success) {
|
|
1375
|
-
return result.tokens.access.token;
|
|
1376
|
-
}
|
|
1377
|
-
return null;
|
|
1158
|
+
// src/utils/flowHelpers.ts
|
|
1159
|
+
var enteranceFlow = async (data, options) => {
|
|
1160
|
+
const location = locationStore.getState().location;
|
|
1161
|
+
const qrAccessDevices = qrScannerStore.getState().qrAccessDevices;
|
|
1162
|
+
const { qrCode, device, isQrCode, nfcCode = "" } = data;
|
|
1163
|
+
if (isQrCode ? !validateQRCode(qrCode) : validateNFCCode(nfcCode)) {
|
|
1164
|
+
return {
|
|
1165
|
+
success: false,
|
|
1166
|
+
message: "Invalid QR code format",
|
|
1167
|
+
error: { code: "INVALID_QR_FORMAT" }
|
|
1168
|
+
};
|
|
1169
|
+
}
|
|
1170
|
+
const checkAccessible = isQrCode ? qrAccessDevices.find((qrAccessDevice) => qrAccessDevice === qrCode) : qrAccessDevices.find((qrAccessDevice) => qrAccessDevice === nfcCode);
|
|
1171
|
+
if (!checkAccessible) {
|
|
1172
|
+
return {
|
|
1173
|
+
success: false,
|
|
1174
|
+
message: "You do not have permission. Please contact your administrator",
|
|
1175
|
+
error: {
|
|
1176
|
+
code: "QR_ACCESS_DENIED"
|
|
1378
1177
|
}
|
|
1379
|
-
});
|
|
1380
|
-
authService = new AuthService(client);
|
|
1381
|
-
authService.setTokenStorage(secureStorage);
|
|
1382
|
-
const allServices = {
|
|
1383
|
-
authService,
|
|
1384
|
-
qrAccessService: new QRAccessService(client),
|
|
1385
|
-
nfcAccessService: new NFCAccessService(client),
|
|
1386
|
-
checkInService: new CheckInService(client),
|
|
1387
|
-
remoteWorkService: new RemoteWorkService(client),
|
|
1388
|
-
deviceAccessService: new DeviceAccessService(client),
|
|
1389
|
-
locationService: new LocationService(client)
|
|
1390
1178
|
};
|
|
1179
|
+
}
|
|
1180
|
+
if (!options.skipRepetitiveCheck && !checkRepetitiveRead(isQrCode ? qrCode : nfcCode)) {
|
|
1391
1181
|
return {
|
|
1392
|
-
|
|
1393
|
-
|
|
1182
|
+
success: false,
|
|
1183
|
+
message: "QR code was recently scanned. Please wait before scanning again.",
|
|
1184
|
+
error: { code: "REPETITIVE_READ" }
|
|
1394
1185
|
};
|
|
1395
|
-
}, [config.baseURL, config.token, config.apiVersion, config.timeout, config.onUnauthorized, config.onError]);
|
|
1396
|
-
const setToken = (newToken) => {
|
|
1397
|
-
apiClient.setToken(newToken);
|
|
1398
|
-
};
|
|
1399
|
-
const clearToken = () => {
|
|
1400
|
-
apiClient.clearToken();
|
|
1401
|
-
};
|
|
1402
|
-
const contextValue = {
|
|
1403
|
-
apiClient,
|
|
1404
|
-
...services,
|
|
1405
|
-
config,
|
|
1406
|
-
setToken,
|
|
1407
|
-
clearToken
|
|
1408
|
-
};
|
|
1409
|
-
return /* @__PURE__ */ import_react.default.createElement(PassgageAccessContext.Provider, { value: contextValue }, children);
|
|
1410
|
-
}
|
|
1411
|
-
function usePassgageAccess() {
|
|
1412
|
-
const context = (0, import_react.useContext)(PassgageAccessContext);
|
|
1413
|
-
if (!context) {
|
|
1414
|
-
throw new Error(
|
|
1415
|
-
"usePassgageAccess must be used within a PassgageAccessProvider"
|
|
1416
|
-
);
|
|
1417
1186
|
}
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
onLogoutSuccess,
|
|
1428
|
-
autoRestore = true
|
|
1429
|
-
} = options;
|
|
1430
|
-
const { authService } = usePassgageAccess();
|
|
1431
|
-
const [isAuthenticated, setIsAuthenticated] = (0, import_react2.useState)(false);
|
|
1432
|
-
const [user, setUser] = (0, import_react2.useState)(null);
|
|
1433
|
-
const [isLoading, setIsLoading] = (0, import_react2.useState)(false);
|
|
1434
|
-
const [error, setError] = (0, import_react2.useState)(null);
|
|
1435
|
-
(0, import_react2.useEffect)(() => {
|
|
1436
|
-
if (!autoRestore) {
|
|
1437
|
-
return;
|
|
1438
|
-
}
|
|
1439
|
-
const restoreAuth = async () => {
|
|
1440
|
-
try {
|
|
1441
|
-
setIsLoading(true);
|
|
1442
|
-
const authenticated = await authService.isAuthenticated();
|
|
1443
|
-
if (authenticated) {
|
|
1444
|
-
const storedTokens = await authService.getStoredTokens();
|
|
1445
|
-
const storedUser = await authService.getStoredUser();
|
|
1446
|
-
if (storedTokens && storedUser) {
|
|
1447
|
-
authService["apiClient"].setToken(storedTokens.access.token);
|
|
1448
|
-
setIsAuthenticated(true);
|
|
1449
|
-
setUser(storedUser);
|
|
1450
|
-
try {
|
|
1451
|
-
const userResult = await authService.getCurrentUser();
|
|
1452
|
-
if (userResult.success) {
|
|
1453
|
-
setUser(userResult.user);
|
|
1454
|
-
}
|
|
1455
|
-
} catch (error2) {
|
|
1456
|
-
console.warn("Failed to fetch fresh user info:", error2);
|
|
1457
|
-
}
|
|
1458
|
-
}
|
|
1187
|
+
if (!options.skipLocationCheck) {
|
|
1188
|
+
const locationValidation = validateLocation(device, location ?? void 0);
|
|
1189
|
+
if (!locationValidation.valid) {
|
|
1190
|
+
return {
|
|
1191
|
+
success: false,
|
|
1192
|
+
message: `You are not within the allowed range of this device${location?.latitude},${location?.longitude}`,
|
|
1193
|
+
error: {
|
|
1194
|
+
code: "LOCATION_OUT_OF_RANGE",
|
|
1195
|
+
details: locationValidation.distance ? `Distance: ${locationValidation.distance.toFixed(2)}m` : void 0
|
|
1459
1196
|
}
|
|
1460
|
-
}
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
const onlineRequestBody = {
|
|
1201
|
+
device_id: device?.id ?? ""
|
|
1202
|
+
};
|
|
1203
|
+
if (device?.is_iot) {
|
|
1204
|
+
try {
|
|
1205
|
+
const enteranceResIot = await QRAccessService.triggerIoTDevice(device.id);
|
|
1206
|
+
if (enteranceResIot.success) {
|
|
1207
|
+
try {
|
|
1208
|
+
const enteranceQrRes = await QRAccessService.createEntranceFromQR(
|
|
1209
|
+
onlineRequestBody
|
|
1210
|
+
);
|
|
1211
|
+
if (enteranceQrRes.success) {
|
|
1212
|
+
addQrReadRecord(qrCode);
|
|
1213
|
+
return {
|
|
1214
|
+
success: !!enteranceQrRes?.success,
|
|
1215
|
+
message: enteranceQrRes.success ? "Enterance validated successfully" : "Enterance validation failed",
|
|
1216
|
+
entrance: enteranceQrRes.data
|
|
1217
|
+
};
|
|
1218
|
+
} else {
|
|
1219
|
+
return {
|
|
1220
|
+
success: false,
|
|
1221
|
+
message: enteranceQrRes.message ?? "Trigger IOT validation failed"
|
|
1222
|
+
};
|
|
1485
1223
|
}
|
|
1224
|
+
} catch (error) {
|
|
1225
|
+
return {
|
|
1226
|
+
success: false,
|
|
1227
|
+
message: error?.message ?? "Qr enterance failed"
|
|
1228
|
+
};
|
|
1486
1229
|
}
|
|
1487
|
-
|
|
1488
|
-
} catch (error2) {
|
|
1489
|
-
const errorMessage = error2.message || "An error occurred during login";
|
|
1490
|
-
setError(errorMessage);
|
|
1491
|
-
if (onLoginError) {
|
|
1492
|
-
onLoginError(errorMessage);
|
|
1493
|
-
}
|
|
1230
|
+
} else {
|
|
1494
1231
|
return {
|
|
1495
1232
|
success: false,
|
|
1496
|
-
|
|
1497
|
-
code: "UNKNOWN_ERROR"
|
|
1233
|
+
message: enteranceResIot.message ?? "Trigger IOT validation failed"
|
|
1498
1234
|
};
|
|
1499
|
-
} finally {
|
|
1500
|
-
setIsLoading(false);
|
|
1501
|
-
}
|
|
1502
|
-
},
|
|
1503
|
-
[authService, onLoginSuccess, onLoginError]
|
|
1504
|
-
);
|
|
1505
|
-
const logout = (0, import_react2.useCallback)(async () => {
|
|
1506
|
-
try {
|
|
1507
|
-
setIsLoading(true);
|
|
1508
|
-
setError(null);
|
|
1509
|
-
await authService.logout();
|
|
1510
|
-
setIsAuthenticated(false);
|
|
1511
|
-
setUser(null);
|
|
1512
|
-
if (onLogoutSuccess) {
|
|
1513
|
-
onLogoutSuccess();
|
|
1514
1235
|
}
|
|
1515
|
-
} catch (
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
setIsLoading(false);
|
|
1236
|
+
} catch (error) {
|
|
1237
|
+
return {
|
|
1238
|
+
success: false,
|
|
1239
|
+
message: error ?? "Trigger IOT validation failed"
|
|
1240
|
+
};
|
|
1521
1241
|
}
|
|
1522
|
-
}
|
|
1523
|
-
const refreshToken = (0, import_react2.useCallback)(async () => {
|
|
1242
|
+
} else {
|
|
1524
1243
|
try {
|
|
1525
|
-
const
|
|
1526
|
-
|
|
1244
|
+
const enteranceQrRes = await QRAccessService.createEntranceFromQR(
|
|
1245
|
+
onlineRequestBody
|
|
1246
|
+
);
|
|
1247
|
+
addQrReadRecord(qrCode);
|
|
1248
|
+
return {
|
|
1249
|
+
success: !!enteranceQrRes?.success,
|
|
1250
|
+
message: enteranceQrRes.success ? "QR code validated successfully" : "QR code validation failed",
|
|
1251
|
+
entrance: enteranceQrRes.data
|
|
1252
|
+
};
|
|
1253
|
+
} catch (error) {
|
|
1254
|
+
return {
|
|
1255
|
+
success: false,
|
|
1256
|
+
message: error.message || "Failed to validate QR code",
|
|
1257
|
+
error: { code: "NETWORK_ERROR" }
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
};
|
|
1262
|
+
var loginSuccessFlow = async (result) => {
|
|
1263
|
+
qrScannerStore.getState().fetchQrDevicesAndAccess();
|
|
1264
|
+
if (result.success) {
|
|
1265
|
+
await SecureStorage.saveTokens(result.tokens);
|
|
1266
|
+
if (result.user) {
|
|
1267
|
+
await SecureStorage.saveUser?.(result.user);
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
};
|
|
1271
|
+
|
|
1272
|
+
// src/stores/authStore.ts
|
|
1273
|
+
var useAuthStore = zustand.create((set, get) => ({
|
|
1274
|
+
loading: false,
|
|
1275
|
+
error: null,
|
|
1276
|
+
authStatus: false,
|
|
1277
|
+
user: null,
|
|
1278
|
+
restoreAuth: async () => {
|
|
1279
|
+
const tokens = await SecureStorage.getTokens?.();
|
|
1280
|
+
try {
|
|
1281
|
+
set({ loading: true });
|
|
1282
|
+
const isAuthenticated = tokens !== null && tokens?.access?.token?.length > 0;
|
|
1283
|
+
if (isAuthenticated) {
|
|
1284
|
+
const storedTokens = await SecureStorage.getTokens?.();
|
|
1285
|
+
const storedUser = await SecureStorage.getUser?.();
|
|
1286
|
+
if (storedTokens && storedUser) {
|
|
1287
|
+
setTokenToHttpClient(storedTokens.access.token);
|
|
1288
|
+
set({
|
|
1289
|
+
user: storedUser,
|
|
1290
|
+
authStatus: true
|
|
1291
|
+
});
|
|
1292
|
+
try {
|
|
1293
|
+
const userResult = await AuthService.getCurrentUser();
|
|
1294
|
+
if (userResult.success) {
|
|
1295
|
+
set({
|
|
1296
|
+
user: userResult.user
|
|
1297
|
+
});
|
|
1298
|
+
qrScannerStore.getState().fetchQrDevicesAndAccess();
|
|
1299
|
+
}
|
|
1300
|
+
} catch (error) {
|
|
1301
|
+
console.warn("Failed to fetch fresh user info:", error);
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
} catch (error) {
|
|
1306
|
+
console.error("Failed to restore authentication:", error);
|
|
1307
|
+
set({ error: error.message || "Failed to restore authentication" });
|
|
1308
|
+
} finally {
|
|
1309
|
+
set({ loading: false });
|
|
1310
|
+
}
|
|
1311
|
+
},
|
|
1312
|
+
login: async (credentials, resolve, reject) => {
|
|
1313
|
+
try {
|
|
1314
|
+
set({ loading: true, error: null });
|
|
1315
|
+
const result = await AuthService.login(credentials);
|
|
1316
|
+
if (result.success) {
|
|
1317
|
+
resolve?.(result.user);
|
|
1318
|
+
loginSuccessFlow(result);
|
|
1319
|
+
set({ authStatus: true, user: result.user || null });
|
|
1320
|
+
} else {
|
|
1321
|
+
get().logout();
|
|
1322
|
+
reject?.(result.error);
|
|
1323
|
+
set({ error: result.error });
|
|
1324
|
+
}
|
|
1325
|
+
} catch (error) {
|
|
1326
|
+
get().logout();
|
|
1327
|
+
const errorMessage = error.message || "An error occurred during login";
|
|
1328
|
+
set({ error: errorMessage });
|
|
1329
|
+
reject?.(errorMessage);
|
|
1330
|
+
} finally {
|
|
1331
|
+
set({ loading: false });
|
|
1332
|
+
}
|
|
1333
|
+
},
|
|
1334
|
+
loginWithAzure: async (credentials, resolve, reject) => {
|
|
1335
|
+
try {
|
|
1336
|
+
set({ loading: true, error: null });
|
|
1337
|
+
const result = await AuthService.loginWithAzure(credentials);
|
|
1338
|
+
if (result.success) {
|
|
1339
|
+
loginSuccessFlow(result);
|
|
1340
|
+
resolve?.(result.user);
|
|
1341
|
+
set({ authStatus: true, user: result.user || null });
|
|
1342
|
+
} else {
|
|
1343
|
+
reject?.(result.error);
|
|
1344
|
+
get().logout();
|
|
1345
|
+
set({ error: result.error });
|
|
1346
|
+
}
|
|
1347
|
+
} catch (error) {
|
|
1348
|
+
const errorMessage = error.message || "An error occurred during Azure login";
|
|
1349
|
+
get().logout();
|
|
1350
|
+
set({ error: errorMessage });
|
|
1351
|
+
reject?.(errorMessage);
|
|
1352
|
+
} finally {
|
|
1353
|
+
set({ loading: false });
|
|
1354
|
+
}
|
|
1355
|
+
},
|
|
1356
|
+
logout: async (resolve) => {
|
|
1357
|
+
try {
|
|
1358
|
+
set({
|
|
1359
|
+
loading: true,
|
|
1360
|
+
error: null
|
|
1361
|
+
});
|
|
1362
|
+
await SecureStorage.clearTokens?.();
|
|
1363
|
+
await SecureStorage.clearUser?.();
|
|
1364
|
+
set({ authStatus: false, user: null });
|
|
1365
|
+
resolve?.();
|
|
1366
|
+
} catch (error) {
|
|
1367
|
+
const errorMessage = error.message || "An error occurred during logout";
|
|
1368
|
+
set({ error: errorMessage });
|
|
1369
|
+
console.error("Logout failed:", error);
|
|
1370
|
+
} finally {
|
|
1371
|
+
set({ loading: false });
|
|
1372
|
+
}
|
|
1373
|
+
},
|
|
1374
|
+
refreshToken: async () => {
|
|
1375
|
+
try {
|
|
1376
|
+
const storedTokens = await SecureStorage.getTokens?.();
|
|
1377
|
+
if (!storedTokens) {
|
|
1527
1378
|
return false;
|
|
1528
1379
|
}
|
|
1529
|
-
const result = await
|
|
1380
|
+
const result = await AuthService.refreshToken(storedTokens.refresh.token);
|
|
1530
1381
|
if (result.success) {
|
|
1531
1382
|
return true;
|
|
1532
1383
|
} else {
|
|
1533
|
-
await logout();
|
|
1384
|
+
await get().logout();
|
|
1534
1385
|
return false;
|
|
1535
1386
|
}
|
|
1536
|
-
} catch (
|
|
1537
|
-
console.error("Token refresh failed:",
|
|
1538
|
-
await logout();
|
|
1387
|
+
} catch (error) {
|
|
1388
|
+
console.error("Token refresh failed:", error);
|
|
1389
|
+
await get().logout();
|
|
1539
1390
|
return false;
|
|
1540
1391
|
}
|
|
1541
|
-
},
|
|
1542
|
-
|
|
1543
|
-
|
|
1392
|
+
},
|
|
1393
|
+
clearError: () => {
|
|
1394
|
+
set({ error: null });
|
|
1395
|
+
}
|
|
1396
|
+
}));
|
|
1397
|
+
var PassgageAccessProvideContext = React.createContext(void 0);
|
|
1398
|
+
function PassgageAccessProvider(props) {
|
|
1399
|
+
const {
|
|
1400
|
+
children,
|
|
1401
|
+
baseURL,
|
|
1402
|
+
msalToken,
|
|
1403
|
+
apiVersion = "v2",
|
|
1404
|
+
timeout = 3e4,
|
|
1405
|
+
rememberUser = true,
|
|
1406
|
+
onUnauthorized = () => {
|
|
1407
|
+
},
|
|
1408
|
+
locationPermissionErrorCallback = () => {
|
|
1409
|
+
},
|
|
1410
|
+
getLocationErrorCallback = () => {
|
|
1411
|
+
}
|
|
1412
|
+
} = props;
|
|
1413
|
+
const useLocationStore = locationStore();
|
|
1414
|
+
const authStore = useAuthStore();
|
|
1415
|
+
React.useEffect(() => {
|
|
1416
|
+
const msalTokenInitFlow = async () => {
|
|
1417
|
+
try {
|
|
1418
|
+
await authStore.loginWithAzure(
|
|
1419
|
+
{
|
|
1420
|
+
id_token: msalToken ?? "",
|
|
1421
|
+
device_type: reactNative.Platform.OS === "ios" ? "ios" : "android"
|
|
1422
|
+
},
|
|
1423
|
+
() => {
|
|
1424
|
+
},
|
|
1425
|
+
(error) => {
|
|
1426
|
+
console.error("Failed to login with Azure:", error);
|
|
1427
|
+
authStore.logout();
|
|
1428
|
+
}
|
|
1429
|
+
);
|
|
1430
|
+
} catch (error) {
|
|
1431
|
+
console.error("Failed to login with Azure:", error);
|
|
1432
|
+
authStore.logout();
|
|
1433
|
+
}
|
|
1434
|
+
};
|
|
1435
|
+
const LocationPermission = reactNative.Platform.select({
|
|
1436
|
+
android: RNPermissions.PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION,
|
|
1437
|
+
ios: RNPermissions.PERMISSIONS.IOS.LOCATION_WHEN_IN_USE,
|
|
1438
|
+
default: RNPermissions.PERMISSIONS.IOS.LOCATION_WHEN_IN_USE
|
|
1439
|
+
});
|
|
1440
|
+
if (LocationPermission) {
|
|
1441
|
+
RNPermissions__default.default.check(LocationPermission).then((status) => {
|
|
1442
|
+
switch (status) {
|
|
1443
|
+
case RNPermissions.RESULTS.DENIED:
|
|
1444
|
+
RNPermissions.request(LocationPermission).then(() => {
|
|
1445
|
+
useLocationStore.refreshLocation();
|
|
1446
|
+
});
|
|
1447
|
+
break;
|
|
1448
|
+
case RNPermissions.RESULTS.BLOCKED:
|
|
1449
|
+
case RNPermissions.RESULTS.UNAVAILABLE:
|
|
1450
|
+
case RNPermissions.RESULTS.GRANTED:
|
|
1451
|
+
case RNPermissions.RESULTS.LIMITED:
|
|
1452
|
+
useLocationStore.refreshLocation();
|
|
1453
|
+
break;
|
|
1454
|
+
}
|
|
1455
|
+
}).catch((error) => {
|
|
1456
|
+
locationPermissionErrorCallback(error);
|
|
1457
|
+
console.error(error);
|
|
1458
|
+
});
|
|
1459
|
+
}
|
|
1460
|
+
createHttpClient({ apiVersion, baseURL, timeout });
|
|
1461
|
+
if (msalToken) {
|
|
1462
|
+
msalTokenInitFlow();
|
|
1463
|
+
} else {
|
|
1464
|
+
authStore.logout();
|
|
1465
|
+
onUnauthorized({
|
|
1466
|
+
name: "Unauthorized",
|
|
1467
|
+
message: "MSAL Token is required"
|
|
1468
|
+
});
|
|
1469
|
+
}
|
|
1470
|
+
if (rememberUser) {
|
|
1471
|
+
authStore.restoreAuth();
|
|
1472
|
+
}
|
|
1544
1473
|
}, []);
|
|
1474
|
+
React.useEffect(() => {
|
|
1475
|
+
if (useLocationStore.error) {
|
|
1476
|
+
getLocationErrorCallback(useLocationStore.error);
|
|
1477
|
+
}
|
|
1478
|
+
}, [useLocationStore.error]);
|
|
1479
|
+
return /* @__PURE__ */ React__default.default.createElement(PassgageAccessProvideContext.Provider, { value: { ...props } }, children);
|
|
1480
|
+
}
|
|
1481
|
+
var usePassgageAccessContext = () => {
|
|
1482
|
+
const ctx = React.useContext(PassgageAccessProvideContext);
|
|
1483
|
+
if (!ctx) {
|
|
1484
|
+
throw new Error(
|
|
1485
|
+
"usePassgageAccessContext must be used inside AuthProvider"
|
|
1486
|
+
);
|
|
1487
|
+
}
|
|
1488
|
+
return ctx;
|
|
1489
|
+
};
|
|
1490
|
+
var usePassgageQRScanner = (payload) => {
|
|
1491
|
+
const [isLoading, setIsLoading] = React.useState(false);
|
|
1492
|
+
const [error, setError] = React.useState(null);
|
|
1493
|
+
const { qrDevices } = qrScannerStore();
|
|
1494
|
+
const scan = async (qrCode, device) => {
|
|
1495
|
+
setIsLoading(true);
|
|
1496
|
+
setError(null);
|
|
1497
|
+
try {
|
|
1498
|
+
let qrDevice = device;
|
|
1499
|
+
if (!qrDevice) {
|
|
1500
|
+
qrDevice = qrDevices.find((item) => item.qr_code_id === qrCode);
|
|
1501
|
+
if (!qrDevice) {
|
|
1502
|
+
payload.onError?.(
|
|
1503
|
+
error ?? { message: "QR Device not found", success: false }
|
|
1504
|
+
);
|
|
1505
|
+
return;
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
const result = await enteranceFlow(
|
|
1509
|
+
{
|
|
1510
|
+
device: qrDevice,
|
|
1511
|
+
qrCode,
|
|
1512
|
+
isQrCode: true
|
|
1513
|
+
},
|
|
1514
|
+
payload.options
|
|
1515
|
+
);
|
|
1516
|
+
if (!result.success) {
|
|
1517
|
+
payload.onError?.(result);
|
|
1518
|
+
} else {
|
|
1519
|
+
payload.onSuccess?.(result.entrance);
|
|
1520
|
+
}
|
|
1521
|
+
} catch (err) {
|
|
1522
|
+
const errorObj = {
|
|
1523
|
+
success: false,
|
|
1524
|
+
message: err?.message || "Qr scan failed",
|
|
1525
|
+
error: { code: "QR_SCAN_FAILED" }
|
|
1526
|
+
};
|
|
1527
|
+
setError(errorObj);
|
|
1528
|
+
payload.onError?.(errorObj);
|
|
1529
|
+
} finally {
|
|
1530
|
+
setIsLoading(false);
|
|
1531
|
+
}
|
|
1532
|
+
};
|
|
1545
1533
|
return {
|
|
1546
|
-
|
|
1547
|
-
logout,
|
|
1548
|
-
refreshToken,
|
|
1549
|
-
isAuthenticated,
|
|
1550
|
-
user,
|
|
1534
|
+
scan,
|
|
1551
1535
|
isLoading,
|
|
1536
|
+
error
|
|
1537
|
+
};
|
|
1538
|
+
};
|
|
1539
|
+
var bigInt = __require("big-integer");
|
|
1540
|
+
var reversedHexToDec = (reversedHex) => {
|
|
1541
|
+
try {
|
|
1542
|
+
reversedHex = reversedHex.replace(/\s+/g, "");
|
|
1543
|
+
let originalHex = "";
|
|
1544
|
+
for (let i = reversedHex.length; i > 0; i -= 2) {
|
|
1545
|
+
originalHex += reversedHex.substring(i - 2, i);
|
|
1546
|
+
}
|
|
1547
|
+
let decimalValue = bigInt(originalHex, 16);
|
|
1548
|
+
return decimalValue.toString();
|
|
1549
|
+
} catch (error) {
|
|
1550
|
+
return reversedHex;
|
|
1551
|
+
}
|
|
1552
|
+
};
|
|
1553
|
+
function usePassgageNFCScanner(payload) {
|
|
1554
|
+
const [supportNFC, setSupportNFC] = React.useState();
|
|
1555
|
+
const [isScanning, setIsScanning] = React.useState(false);
|
|
1556
|
+
const [nfcData, setNfcData] = React.useState();
|
|
1557
|
+
const { qrDevices } = qrScannerStore();
|
|
1558
|
+
const [error, setError] = React.useState(null);
|
|
1559
|
+
React.useEffect(() => {
|
|
1560
|
+
NfcManager__default.default.isSupported().then((supported) => {
|
|
1561
|
+
if (supported) {
|
|
1562
|
+
setSupportNFC(true);
|
|
1563
|
+
} else {
|
|
1564
|
+
setSupportNFC(false);
|
|
1565
|
+
}
|
|
1566
|
+
});
|
|
1567
|
+
return () => {
|
|
1568
|
+
NfcManager__default.default.cancelTechnologyRequest();
|
|
1569
|
+
};
|
|
1570
|
+
}, []);
|
|
1571
|
+
const stopScanning = async () => {
|
|
1572
|
+
try {
|
|
1573
|
+
NfcManager__default.default.cancelTechnologyRequest().finally(() => {
|
|
1574
|
+
setIsScanning(false);
|
|
1575
|
+
});
|
|
1576
|
+
} catch {
|
|
1577
|
+
}
|
|
1578
|
+
};
|
|
1579
|
+
const handleNFCTag = async (tag) => {
|
|
1580
|
+
if (!tag.id) {
|
|
1581
|
+
return;
|
|
1582
|
+
}
|
|
1583
|
+
try {
|
|
1584
|
+
const nfcCode = reversedHexToDec(tag.id);
|
|
1585
|
+
if (reactNative.Platform.OS === "ios") {
|
|
1586
|
+
await NfcManager__default.default.cancelTechnologyRequest();
|
|
1587
|
+
}
|
|
1588
|
+
const device = qrDevices.find((device2) => device2.nfc_code === nfcCode);
|
|
1589
|
+
if (!device) {
|
|
1590
|
+
throw new Error("NFC device not found");
|
|
1591
|
+
}
|
|
1592
|
+
const result = await enteranceFlow(
|
|
1593
|
+
{
|
|
1594
|
+
device,
|
|
1595
|
+
nfcCode,
|
|
1596
|
+
isQrCode: false
|
|
1597
|
+
},
|
|
1598
|
+
payload.options
|
|
1599
|
+
);
|
|
1600
|
+
if (!result.success) {
|
|
1601
|
+
throw new Error(result.message);
|
|
1602
|
+
}
|
|
1603
|
+
payload.onSuccess?.(result.entrance);
|
|
1604
|
+
stopScanning();
|
|
1605
|
+
} catch (err) {
|
|
1606
|
+
const error2 = err;
|
|
1607
|
+
setError(error2);
|
|
1608
|
+
payload.onError?.(error2);
|
|
1609
|
+
stopScanning();
|
|
1610
|
+
}
|
|
1611
|
+
};
|
|
1612
|
+
const startScanning = async () => {
|
|
1613
|
+
await NfcManager__default.default.requestTechnology(NfcManager.NfcTech.Ndef, {
|
|
1614
|
+
invalidateAfterFirstRead: true
|
|
1615
|
+
});
|
|
1616
|
+
await NfcManager__default.default.getTag().then((tag) => {
|
|
1617
|
+
setNfcData(tag?.id ?? "");
|
|
1618
|
+
handleNFCTag(tag || {});
|
|
1619
|
+
}).catch(() => false);
|
|
1620
|
+
NfcManager__default.default.cancelTechnologyRequest();
|
|
1621
|
+
setIsScanning(true);
|
|
1622
|
+
setError(null);
|
|
1623
|
+
};
|
|
1624
|
+
return {
|
|
1625
|
+
nfcData,
|
|
1626
|
+
supportNFC,
|
|
1627
|
+
startScanning,
|
|
1628
|
+
stopScanning,
|
|
1552
1629
|
error,
|
|
1553
|
-
|
|
1630
|
+
isScanning
|
|
1554
1631
|
};
|
|
1555
1632
|
}
|
|
1556
|
-
|
|
1557
|
-
// src/hooks/usePassgageQRScanner.ts
|
|
1558
|
-
var import_react4 = require("react");
|
|
1559
|
-
|
|
1560
|
-
// src/hooks/useLocation.ts
|
|
1561
|
-
var import_react3 = require("react");
|
|
1562
|
-
var import_geolocation = __toESM(require("@react-native-community/geolocation"));
|
|
1563
1633
|
function useLocation(options = {}) {
|
|
1564
|
-
const [location, setLocation] =
|
|
1565
|
-
const [error, setError] =
|
|
1566
|
-
const [isLoading, setIsLoading] =
|
|
1634
|
+
const [location, setLocation] = React.useState(null);
|
|
1635
|
+
const [error, setError] = React.useState(null);
|
|
1636
|
+
const [isLoading, setIsLoading] = React.useState(true);
|
|
1567
1637
|
const config = {
|
|
1568
1638
|
enableHighAccuracy: options.enableHighAccuracy ?? true,
|
|
1569
1639
|
timeout: options.timeout ?? 15e3,
|
|
1570
1640
|
maximumAge: options.maximumAge ?? 1e4
|
|
1571
1641
|
};
|
|
1572
|
-
const refreshLocation =
|
|
1642
|
+
const refreshLocation = React.useCallback(async () => {
|
|
1573
1643
|
setIsLoading(true);
|
|
1574
1644
|
setError(null);
|
|
1575
1645
|
return new Promise((resolve) => {
|
|
1576
|
-
|
|
1646
|
+
Geolocation2__default.default.getCurrentPosition(
|
|
1577
1647
|
(position) => {
|
|
1578
1648
|
setLocation({
|
|
1579
1649
|
latitude: position.coords.latitude,
|
|
@@ -1596,10 +1666,10 @@ function useLocation(options = {}) {
|
|
|
1596
1666
|
);
|
|
1597
1667
|
});
|
|
1598
1668
|
}, [config.enableHighAccuracy, config.timeout, config.maximumAge]);
|
|
1599
|
-
|
|
1669
|
+
React.useEffect(() => {
|
|
1600
1670
|
refreshLocation();
|
|
1601
1671
|
if (options.watchPosition) {
|
|
1602
|
-
const watchId =
|
|
1672
|
+
const watchId = Geolocation2__default.default.watchPosition(
|
|
1603
1673
|
(position) => {
|
|
1604
1674
|
setLocation({
|
|
1605
1675
|
latitude: position.coords.latitude,
|
|
@@ -1617,7 +1687,7 @@ function useLocation(options = {}) {
|
|
|
1617
1687
|
config
|
|
1618
1688
|
);
|
|
1619
1689
|
return () => {
|
|
1620
|
-
|
|
1690
|
+
Geolocation2__default.default.clearWatch(watchId);
|
|
1621
1691
|
};
|
|
1622
1692
|
}
|
|
1623
1693
|
return void 0;
|
|
@@ -1630,377 +1700,43 @@ function useLocation(options = {}) {
|
|
|
1630
1700
|
};
|
|
1631
1701
|
}
|
|
1632
1702
|
|
|
1633
|
-
// src/hooks/usePassgageQRScanner.ts
|
|
1634
|
-
function usePassgageQRScanner(options = {}) {
|
|
1635
|
-
const { qrAccessService, deviceAccessService } = usePassgageAccess();
|
|
1636
|
-
const { location } = useLocation();
|
|
1637
|
-
const [isLoading, setIsLoading] = (0, import_react4.useState)(false);
|
|
1638
|
-
const [error, setError] = (0, import_react4.useState)(null);
|
|
1639
|
-
const scan = (0, import_react4.useCallback)(
|
|
1640
|
-
async (qrCode, device) => {
|
|
1641
|
-
setIsLoading(true);
|
|
1642
|
-
setError(null);
|
|
1643
|
-
try {
|
|
1644
|
-
let qrDevice = device;
|
|
1645
|
-
if (!qrDevice) {
|
|
1646
|
-
qrDevice = await deviceAccessService.findDeviceByQRCode(qrCode);
|
|
1647
|
-
if (!qrDevice) {
|
|
1648
|
-
throw new Error("QR device not found");
|
|
1649
|
-
}
|
|
1650
|
-
}
|
|
1651
|
-
const result = await qrAccessService.validateQR({
|
|
1652
|
-
qrCode,
|
|
1653
|
-
device: qrDevice,
|
|
1654
|
-
userLocation: location || void 0,
|
|
1655
|
-
skipLocationCheck: options.skipLocationCheck,
|
|
1656
|
-
skipRepetitiveCheck: options.skipRepetitiveCheck
|
|
1657
|
-
});
|
|
1658
|
-
if (!result.success) {
|
|
1659
|
-
throw new Error(result.message);
|
|
1660
|
-
}
|
|
1661
|
-
options.onSuccess?.(result.entrance);
|
|
1662
|
-
} catch (err) {
|
|
1663
|
-
const error2 = err;
|
|
1664
|
-
setError(error2);
|
|
1665
|
-
options.onError?.(error2);
|
|
1666
|
-
} finally {
|
|
1667
|
-
setIsLoading(false);
|
|
1668
|
-
}
|
|
1669
|
-
},
|
|
1670
|
-
[qrAccessService, deviceAccessService, location, options]
|
|
1671
|
-
);
|
|
1672
|
-
return {
|
|
1673
|
-
scan,
|
|
1674
|
-
isLoading,
|
|
1675
|
-
error
|
|
1676
|
-
};
|
|
1677
|
-
}
|
|
1678
|
-
|
|
1679
|
-
// src/hooks/usePassgageNFCScanner.ts
|
|
1680
|
-
var import_react5 = require("react");
|
|
1681
|
-
var import_react_native_nfc_manager = __toESM(require("react-native-nfc-manager"));
|
|
1682
|
-
function reversedHexToDec(hexString) {
|
|
1683
|
-
const hex = hexString.replace(/:/g, "");
|
|
1684
|
-
return parseInt(hex, 16).toString();
|
|
1685
|
-
}
|
|
1686
|
-
function usePassgageNFCScanner(options = {}) {
|
|
1687
|
-
const { nfcAccessService, deviceAccessService } = usePassgageAccess();
|
|
1688
|
-
const { location } = useLocation();
|
|
1689
|
-
const [isScanning, setIsScanning] = (0, import_react5.useState)(false);
|
|
1690
|
-
const [error, setError] = (0, import_react5.useState)(null);
|
|
1691
|
-
const stopScanning = (0, import_react5.useCallback)(async () => {
|
|
1692
|
-
try {
|
|
1693
|
-
await import_react_native_nfc_manager.default.cancelTechnologyRequest();
|
|
1694
|
-
setIsScanning(false);
|
|
1695
|
-
} catch {
|
|
1696
|
-
}
|
|
1697
|
-
}, []);
|
|
1698
|
-
const handleNFCTag = (0, import_react5.useCallback)(
|
|
1699
|
-
async (tag) => {
|
|
1700
|
-
if (!tag.id) {
|
|
1701
|
-
return;
|
|
1702
|
-
}
|
|
1703
|
-
try {
|
|
1704
|
-
const nfcCode = reversedHexToDec(tag.id);
|
|
1705
|
-
const device = await deviceAccessService.findDeviceByNFCCode(nfcCode);
|
|
1706
|
-
if (!device) {
|
|
1707
|
-
throw new Error("NFC device not found");
|
|
1708
|
-
}
|
|
1709
|
-
const result = await nfcAccessService.validateNFC({
|
|
1710
|
-
nfcCode,
|
|
1711
|
-
device,
|
|
1712
|
-
userLocation: location || void 0,
|
|
1713
|
-
skipLocationCheck: options.skipLocationCheck,
|
|
1714
|
-
skipRepetitiveCheck: options.skipRepetitiveCheck
|
|
1715
|
-
});
|
|
1716
|
-
if (!result.success) {
|
|
1717
|
-
throw new Error(result.message);
|
|
1718
|
-
}
|
|
1719
|
-
options.onSuccess?.(result.entrance);
|
|
1720
|
-
await stopScanning();
|
|
1721
|
-
} catch (err) {
|
|
1722
|
-
const error2 = err;
|
|
1723
|
-
setError(error2);
|
|
1724
|
-
options.onError?.(error2);
|
|
1725
|
-
await stopScanning();
|
|
1726
|
-
}
|
|
1727
|
-
},
|
|
1728
|
-
[nfcAccessService, deviceAccessService, location, options, stopScanning]
|
|
1729
|
-
);
|
|
1730
|
-
const startScanning = (0, import_react5.useCallback)(async () => {
|
|
1731
|
-
setIsScanning(true);
|
|
1732
|
-
setError(null);
|
|
1733
|
-
try {
|
|
1734
|
-
await import_react_native_nfc_manager.default.requestTechnology(import_react_native_nfc_manager.NfcTech.Ndef, {
|
|
1735
|
-
invalidateAfterFirstRead: true
|
|
1736
|
-
});
|
|
1737
|
-
const tag = await import_react_native_nfc_manager.default.getTag();
|
|
1738
|
-
await handleNFCTag(tag || {});
|
|
1739
|
-
} catch (err) {
|
|
1740
|
-
const error2 = err;
|
|
1741
|
-
setError(error2);
|
|
1742
|
-
options.onError?.(error2);
|
|
1743
|
-
setIsScanning(false);
|
|
1744
|
-
}
|
|
1745
|
-
}, [handleNFCTag, options]);
|
|
1746
|
-
(0, import_react5.useEffect)(() => {
|
|
1747
|
-
if (options.autoStart) {
|
|
1748
|
-
startScanning();
|
|
1749
|
-
}
|
|
1750
|
-
return () => {
|
|
1751
|
-
stopScanning();
|
|
1752
|
-
};
|
|
1753
|
-
}, [options.autoStart, startScanning, stopScanning]);
|
|
1754
|
-
return {
|
|
1755
|
-
startScanning,
|
|
1756
|
-
stopScanning,
|
|
1757
|
-
isScanning,
|
|
1758
|
-
error
|
|
1759
|
-
};
|
|
1760
|
-
}
|
|
1761
|
-
|
|
1762
|
-
// src/hooks/usePassgageCheckIn.ts
|
|
1763
|
-
var import_react6 = require("react");
|
|
1764
|
-
function usePassgageCheckIn(options = {}) {
|
|
1765
|
-
const { checkInService } = usePassgageAccess();
|
|
1766
|
-
const { location } = useLocation();
|
|
1767
|
-
const [isLoading, setIsLoading] = (0, import_react6.useState)(false);
|
|
1768
|
-
const [error, setError] = (0, import_react6.useState)(null);
|
|
1769
|
-
const getNearbyBranches = (0, import_react6.useCallback)(
|
|
1770
|
-
async (params) => {
|
|
1771
|
-
if (!location) {
|
|
1772
|
-
return {
|
|
1773
|
-
success: false,
|
|
1774
|
-
error: "Location not available"
|
|
1775
|
-
};
|
|
1776
|
-
}
|
|
1777
|
-
setIsLoading(true);
|
|
1778
|
-
setError(null);
|
|
1779
|
-
try {
|
|
1780
|
-
const response = await checkInService.getNearbyBranches({
|
|
1781
|
-
latitude: location.latitude,
|
|
1782
|
-
longitude: location.longitude,
|
|
1783
|
-
radius: params?.radius || options.radius
|
|
1784
|
-
});
|
|
1785
|
-
if (response.success && response.data) {
|
|
1786
|
-
return {
|
|
1787
|
-
success: true,
|
|
1788
|
-
data: response.data
|
|
1789
|
-
};
|
|
1790
|
-
}
|
|
1791
|
-
return {
|
|
1792
|
-
success: false,
|
|
1793
|
-
error: response.message || "Failed to fetch nearby branches"
|
|
1794
|
-
};
|
|
1795
|
-
} catch (err) {
|
|
1796
|
-
const error2 = err;
|
|
1797
|
-
setError(error2);
|
|
1798
|
-
return {
|
|
1799
|
-
success: false,
|
|
1800
|
-
error: error2.message || "Failed to fetch nearby branches"
|
|
1801
|
-
};
|
|
1802
|
-
} finally {
|
|
1803
|
-
setIsLoading(false);
|
|
1804
|
-
}
|
|
1805
|
-
},
|
|
1806
|
-
[checkInService, location, options.radius]
|
|
1807
|
-
);
|
|
1808
|
-
const checkInEntry = (0, import_react6.useCallback)(
|
|
1809
|
-
async (params) => {
|
|
1810
|
-
setIsLoading(true);
|
|
1811
|
-
setError(null);
|
|
1812
|
-
try {
|
|
1813
|
-
const result = await checkInService.checkIn({
|
|
1814
|
-
branchId: params.branchId,
|
|
1815
|
-
userId: params.userId,
|
|
1816
|
-
entranceType: 0 /* ENTRY */,
|
|
1817
|
-
userLocation: location || void 0
|
|
1818
|
-
});
|
|
1819
|
-
if (result.success) {
|
|
1820
|
-
return {
|
|
1821
|
-
success: true,
|
|
1822
|
-
data: result.entrance
|
|
1823
|
-
};
|
|
1824
|
-
}
|
|
1825
|
-
return {
|
|
1826
|
-
success: false,
|
|
1827
|
-
error: result.message || "Check-in failed"
|
|
1828
|
-
};
|
|
1829
|
-
} catch (err) {
|
|
1830
|
-
const error2 = err;
|
|
1831
|
-
setError(error2);
|
|
1832
|
-
return {
|
|
1833
|
-
success: false,
|
|
1834
|
-
error: error2.message || "Check-in failed"
|
|
1835
|
-
};
|
|
1836
|
-
} finally {
|
|
1837
|
-
setIsLoading(false);
|
|
1838
|
-
}
|
|
1839
|
-
},
|
|
1840
|
-
[checkInService, location]
|
|
1841
|
-
);
|
|
1842
|
-
const checkInExit = (0, import_react6.useCallback)(
|
|
1843
|
-
async (params) => {
|
|
1844
|
-
setIsLoading(true);
|
|
1845
|
-
setError(null);
|
|
1846
|
-
try {
|
|
1847
|
-
const result = await checkInService.checkIn({
|
|
1848
|
-
branchId: params.branchId,
|
|
1849
|
-
userId: params.userId,
|
|
1850
|
-
entranceType: 1 /* EXIT */,
|
|
1851
|
-
userLocation: location || void 0
|
|
1852
|
-
});
|
|
1853
|
-
if (result.success) {
|
|
1854
|
-
return {
|
|
1855
|
-
success: true,
|
|
1856
|
-
data: result.entrance
|
|
1857
|
-
};
|
|
1858
|
-
}
|
|
1859
|
-
return {
|
|
1860
|
-
success: false,
|
|
1861
|
-
error: result.message || "Check-out failed"
|
|
1862
|
-
};
|
|
1863
|
-
} catch (err) {
|
|
1864
|
-
const error2 = err;
|
|
1865
|
-
setError(error2);
|
|
1866
|
-
return {
|
|
1867
|
-
success: false,
|
|
1868
|
-
error: error2.message || "Check-out failed"
|
|
1869
|
-
};
|
|
1870
|
-
} finally {
|
|
1871
|
-
setIsLoading(false);
|
|
1872
|
-
}
|
|
1873
|
-
},
|
|
1874
|
-
[checkInService, location]
|
|
1875
|
-
);
|
|
1876
|
-
return {
|
|
1877
|
-
getNearbyBranches,
|
|
1878
|
-
checkInEntry,
|
|
1879
|
-
checkInExit,
|
|
1880
|
-
isLoading,
|
|
1881
|
-
error
|
|
1882
|
-
};
|
|
1883
|
-
}
|
|
1884
|
-
|
|
1885
|
-
// src/hooks/usePassgageRemoteWork.ts
|
|
1886
|
-
var import_react7 = require("react");
|
|
1887
|
-
function usePassgageRemoteWork() {
|
|
1888
|
-
const { remoteWorkService } = usePassgageAccess();
|
|
1889
|
-
const [isLoading, setIsLoading] = (0, import_react7.useState)(false);
|
|
1890
|
-
const [error, setError] = (0, import_react7.useState)(null);
|
|
1891
|
-
const logEntry = (0, import_react7.useCallback)(
|
|
1892
|
-
async (params) => {
|
|
1893
|
-
setIsLoading(true);
|
|
1894
|
-
setError(null);
|
|
1895
|
-
try {
|
|
1896
|
-
const result = await remoteWorkService.logRemoteWork({
|
|
1897
|
-
userId: params.userId,
|
|
1898
|
-
entranceType: 0 /* ENTRY */,
|
|
1899
|
-
timestamp: params.timestamp,
|
|
1900
|
-
description: params.description
|
|
1901
|
-
});
|
|
1902
|
-
if (result.success) {
|
|
1903
|
-
return {
|
|
1904
|
-
success: true,
|
|
1905
|
-
data: result.entrance
|
|
1906
|
-
};
|
|
1907
|
-
}
|
|
1908
|
-
return {
|
|
1909
|
-
success: false,
|
|
1910
|
-
error: result.message || "Failed to log entry"
|
|
1911
|
-
};
|
|
1912
|
-
} catch (err) {
|
|
1913
|
-
const error2 = err;
|
|
1914
|
-
setError(error2);
|
|
1915
|
-
return {
|
|
1916
|
-
success: false,
|
|
1917
|
-
error: error2.message || "Failed to log entry"
|
|
1918
|
-
};
|
|
1919
|
-
} finally {
|
|
1920
|
-
setIsLoading(false);
|
|
1921
|
-
}
|
|
1922
|
-
},
|
|
1923
|
-
[remoteWorkService]
|
|
1924
|
-
);
|
|
1925
|
-
const logExit = (0, import_react7.useCallback)(
|
|
1926
|
-
async (params) => {
|
|
1927
|
-
setIsLoading(true);
|
|
1928
|
-
setError(null);
|
|
1929
|
-
try {
|
|
1930
|
-
const result = await remoteWorkService.logRemoteWork({
|
|
1931
|
-
userId: params.userId,
|
|
1932
|
-
entranceType: 1 /* EXIT */,
|
|
1933
|
-
timestamp: params.timestamp,
|
|
1934
|
-
description: params.description
|
|
1935
|
-
});
|
|
1936
|
-
if (result.success) {
|
|
1937
|
-
return {
|
|
1938
|
-
success: true,
|
|
1939
|
-
data: result.entrance
|
|
1940
|
-
};
|
|
1941
|
-
}
|
|
1942
|
-
return {
|
|
1943
|
-
success: false,
|
|
1944
|
-
error: result.message || "Failed to log exit"
|
|
1945
|
-
};
|
|
1946
|
-
} catch (err) {
|
|
1947
|
-
const error2 = err;
|
|
1948
|
-
setError(error2);
|
|
1949
|
-
return {
|
|
1950
|
-
success: false,
|
|
1951
|
-
error: error2.message || "Failed to log exit"
|
|
1952
|
-
};
|
|
1953
|
-
} finally {
|
|
1954
|
-
setIsLoading(false);
|
|
1955
|
-
}
|
|
1956
|
-
},
|
|
1957
|
-
[remoteWorkService]
|
|
1958
|
-
);
|
|
1959
|
-
return {
|
|
1960
|
-
logEntry,
|
|
1961
|
-
logExit,
|
|
1962
|
-
isLoading,
|
|
1963
|
-
error
|
|
1964
|
-
};
|
|
1965
|
-
}
|
|
1966
|
-
|
|
1967
1703
|
// src/index.ts
|
|
1968
|
-
var SDK_VERSION = "1.0.
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
1704
|
+
var SDK_VERSION = "1.0.6";
|
|
1705
|
+
|
|
1706
|
+
exports.ApiClient = ApiClient;
|
|
1707
|
+
exports.AuthService = AuthService;
|
|
1708
|
+
exports.DeviceAccessService = DeviceAccessService;
|
|
1709
|
+
exports.DeviceDirection = DeviceDirection;
|
|
1710
|
+
exports.DeviceUsage = DeviceUsage;
|
|
1711
|
+
exports.Endpoints = endpoints_exports;
|
|
1712
|
+
exports.EntranceType = EntranceType;
|
|
1713
|
+
exports.LocationService = LocationService;
|
|
1714
|
+
exports.NfcAccessService = NfcAccessService;
|
|
1715
|
+
exports.PassgageAccessProvider = PassgageAccessProvider;
|
|
1716
|
+
exports.QRAccessService = QRAccessService;
|
|
1717
|
+
exports.SDK_VERSION = SDK_VERSION;
|
|
1718
|
+
exports.addQrReadRecord = addQrReadRecord;
|
|
1719
|
+
exports.calculateDistance = calculateDistance;
|
|
1720
|
+
exports.checkOnLocation = checkOnLocation;
|
|
1721
|
+
exports.checkRepetitiveRead = checkRepetitiveRead;
|
|
1722
|
+
exports.clearReadRecords = clearReadRecords;
|
|
1723
|
+
exports.createApiClient = createApiClient;
|
|
1724
|
+
exports.formatDate = formatDate;
|
|
1725
|
+
exports.formatDateTime = formatDateTime;
|
|
1726
|
+
exports.formatISO = formatISO;
|
|
1727
|
+
exports.formatTime = formatTime;
|
|
1728
|
+
exports.locationStore = locationStore;
|
|
1729
|
+
exports.parseISO = parseISO;
|
|
1730
|
+
exports.qrScannerStore = qrScannerStore;
|
|
1731
|
+
exports.reversedHexToDec = reversedHexToDec;
|
|
1732
|
+
exports.shouldValidateLocation = shouldValidateLocation;
|
|
1733
|
+
exports.useAuthStore = useAuthStore;
|
|
1734
|
+
exports.useLocation = useLocation;
|
|
1735
|
+
exports.usePassgageAccessContext = usePassgageAccessContext;
|
|
1736
|
+
exports.usePassgageNFCScanner = usePassgageNFCScanner;
|
|
1737
|
+
exports.usePassgageQRScanner = usePassgageQRScanner;
|
|
1738
|
+
exports.validateCoordinates = validateCoordinates;
|
|
1739
|
+
exports.validateDeviceId = validateDeviceId;
|
|
1740
|
+
exports.validateLocation = validateLocation;
|
|
1741
|
+
exports.validateNFCCode = validateNFCCode;
|
|
1742
|
+
exports.validateQRCode = validateQRCode;
|