@passgage/sdk-react-native 1.0.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/README.md +156 -0
- package/dist/index.d.mts +251 -0
- package/dist/index.d.ts +251 -0
- package/dist/index.js +721 -0
- package/dist/index.mjs +685 -0
- package/package.json +84 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,685 @@
|
|
|
1
|
+
// src/providers/PassgageAccessProvider.tsx
|
|
2
|
+
import React, { createContext, useContext, useMemo } from "react";
|
|
3
|
+
import {
|
|
4
|
+
createApiClient,
|
|
5
|
+
AuthService,
|
|
6
|
+
QRAccessService,
|
|
7
|
+
NFCAccessService,
|
|
8
|
+
CheckInService,
|
|
9
|
+
RemoteWorkService,
|
|
10
|
+
DeviceAccessService,
|
|
11
|
+
LocationService
|
|
12
|
+
} from "@passgage/sdk-core";
|
|
13
|
+
|
|
14
|
+
// src/utils/secureStorage.ts
|
|
15
|
+
import * as Keychain from "react-native-keychain";
|
|
16
|
+
var STORAGE_KEYS = {
|
|
17
|
+
TOKENS: "passgage_auth_tokens",
|
|
18
|
+
USER: "passgage_user_info"
|
|
19
|
+
};
|
|
20
|
+
var SecureStorage = class {
|
|
21
|
+
/**
|
|
22
|
+
* Save tokens to secure storage
|
|
23
|
+
*/
|
|
24
|
+
async saveTokens(tokens) {
|
|
25
|
+
try {
|
|
26
|
+
await Keychain.setGenericPassword(
|
|
27
|
+
STORAGE_KEYS.TOKENS,
|
|
28
|
+
JSON.stringify(tokens),
|
|
29
|
+
{
|
|
30
|
+
service: STORAGE_KEYS.TOKENS,
|
|
31
|
+
accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
} catch (error) {
|
|
35
|
+
console.error("Failed to save tokens to secure storage:", error);
|
|
36
|
+
throw new Error("Failed to save tokens");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Get tokens from secure storage
|
|
41
|
+
*/
|
|
42
|
+
async getTokens() {
|
|
43
|
+
try {
|
|
44
|
+
const credentials = await Keychain.getGenericPassword({
|
|
45
|
+
service: STORAGE_KEYS.TOKENS
|
|
46
|
+
});
|
|
47
|
+
if (!credentials) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
const tokens = JSON.parse(credentials.password);
|
|
51
|
+
return tokens;
|
|
52
|
+
} catch (error) {
|
|
53
|
+
console.error("Failed to get tokens from secure storage:", error);
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Clear tokens from secure storage
|
|
59
|
+
*/
|
|
60
|
+
async clearTokens() {
|
|
61
|
+
try {
|
|
62
|
+
await Keychain.resetGenericPassword({
|
|
63
|
+
service: STORAGE_KEYS.TOKENS
|
|
64
|
+
});
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error("Failed to clear tokens from secure storage:", error);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Save user information
|
|
71
|
+
*/
|
|
72
|
+
async saveUser(user) {
|
|
73
|
+
try {
|
|
74
|
+
await Keychain.setGenericPassword(
|
|
75
|
+
STORAGE_KEYS.USER,
|
|
76
|
+
JSON.stringify(user),
|
|
77
|
+
{
|
|
78
|
+
service: STORAGE_KEYS.USER,
|
|
79
|
+
accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error("Failed to save user to secure storage:", error);
|
|
84
|
+
throw new Error("Failed to save user");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Get user information
|
|
89
|
+
*/
|
|
90
|
+
async getUser() {
|
|
91
|
+
try {
|
|
92
|
+
const credentials = await Keychain.getGenericPassword({
|
|
93
|
+
service: STORAGE_KEYS.USER
|
|
94
|
+
});
|
|
95
|
+
if (!credentials) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
const user = JSON.parse(credentials.password);
|
|
99
|
+
return user;
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.error("Failed to get user from secure storage:", error);
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Clear user information
|
|
107
|
+
*/
|
|
108
|
+
async clearUser() {
|
|
109
|
+
try {
|
|
110
|
+
await Keychain.resetGenericPassword({
|
|
111
|
+
service: STORAGE_KEYS.USER
|
|
112
|
+
});
|
|
113
|
+
} catch (error) {
|
|
114
|
+
console.error("Failed to clear user from secure storage:", error);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Clear all data (tokens + user)
|
|
119
|
+
*/
|
|
120
|
+
async clearAll() {
|
|
121
|
+
await this.clearTokens();
|
|
122
|
+
await this.clearUser();
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
function createSecureStorage() {
|
|
126
|
+
return new SecureStorage();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// src/providers/PassgageAccessProvider.tsx
|
|
130
|
+
var PassgageAccessContext = createContext(void 0);
|
|
131
|
+
function PassgageAccessProvider({
|
|
132
|
+
children,
|
|
133
|
+
baseURL,
|
|
134
|
+
token,
|
|
135
|
+
apiVersion = "v2",
|
|
136
|
+
timeout = 3e4,
|
|
137
|
+
onUnauthorized,
|
|
138
|
+
onError
|
|
139
|
+
}) {
|
|
140
|
+
const config = {
|
|
141
|
+
baseURL,
|
|
142
|
+
token,
|
|
143
|
+
apiVersion,
|
|
144
|
+
timeout,
|
|
145
|
+
onUnauthorized,
|
|
146
|
+
onError
|
|
147
|
+
};
|
|
148
|
+
const { apiClient, services } = useMemo(() => {
|
|
149
|
+
const secureStorage = createSecureStorage();
|
|
150
|
+
let authService;
|
|
151
|
+
const client = createApiClient({
|
|
152
|
+
baseURL: config.baseURL,
|
|
153
|
+
token: config.token,
|
|
154
|
+
apiVersion: config.apiVersion,
|
|
155
|
+
timeout: config.timeout,
|
|
156
|
+
onUnauthorized: config.onUnauthorized,
|
|
157
|
+
onError: config.onError,
|
|
158
|
+
onTokenRefreshNeeded: async () => {
|
|
159
|
+
const storedTokens = await authService.getStoredTokens();
|
|
160
|
+
if (!storedTokens) {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
const result = await authService.refreshToken(storedTokens.refresh.token);
|
|
164
|
+
if (result.success) {
|
|
165
|
+
return result.tokens.access.token;
|
|
166
|
+
}
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
authService = new AuthService(client);
|
|
171
|
+
authService.setTokenStorage(secureStorage);
|
|
172
|
+
const allServices = {
|
|
173
|
+
authService,
|
|
174
|
+
qrAccessService: new QRAccessService(client),
|
|
175
|
+
nfcAccessService: new NFCAccessService(client),
|
|
176
|
+
checkInService: new CheckInService(client),
|
|
177
|
+
remoteWorkService: new RemoteWorkService(client),
|
|
178
|
+
deviceAccessService: new DeviceAccessService(client),
|
|
179
|
+
locationService: new LocationService(client)
|
|
180
|
+
};
|
|
181
|
+
return {
|
|
182
|
+
apiClient: client,
|
|
183
|
+
services: allServices
|
|
184
|
+
};
|
|
185
|
+
}, [config.baseURL, config.token, config.apiVersion, config.timeout, config.onUnauthorized, config.onError]);
|
|
186
|
+
const setToken = (newToken) => {
|
|
187
|
+
apiClient.setToken(newToken);
|
|
188
|
+
};
|
|
189
|
+
const clearToken = () => {
|
|
190
|
+
apiClient.clearToken();
|
|
191
|
+
};
|
|
192
|
+
const contextValue = {
|
|
193
|
+
apiClient,
|
|
194
|
+
...services,
|
|
195
|
+
config,
|
|
196
|
+
setToken,
|
|
197
|
+
clearToken
|
|
198
|
+
};
|
|
199
|
+
return /* @__PURE__ */ React.createElement(PassgageAccessContext.Provider, { value: contextValue }, children);
|
|
200
|
+
}
|
|
201
|
+
function usePassgageAccess() {
|
|
202
|
+
const context = useContext(PassgageAccessContext);
|
|
203
|
+
if (!context) {
|
|
204
|
+
throw new Error(
|
|
205
|
+
"usePassgageAccess must be used within a PassgageAccessProvider"
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
return context;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// src/hooks/usePassgageAuth.ts
|
|
212
|
+
import { useState, useEffect, useCallback } from "react";
|
|
213
|
+
function usePassgageAuth(options = {}) {
|
|
214
|
+
const {
|
|
215
|
+
onLoginSuccess,
|
|
216
|
+
onLoginError,
|
|
217
|
+
onLogoutSuccess,
|
|
218
|
+
autoRestore = true
|
|
219
|
+
} = options;
|
|
220
|
+
const { authService } = usePassgageAccess();
|
|
221
|
+
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
|
222
|
+
const [user, setUser] = useState(null);
|
|
223
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
224
|
+
const [error, setError] = useState(null);
|
|
225
|
+
useEffect(() => {
|
|
226
|
+
if (!autoRestore) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const restoreAuth = async () => {
|
|
230
|
+
try {
|
|
231
|
+
setIsLoading(true);
|
|
232
|
+
const authenticated = await authService.isAuthenticated();
|
|
233
|
+
if (authenticated) {
|
|
234
|
+
const storedTokens = await authService.getStoredTokens();
|
|
235
|
+
const storedUser = await authService.getStoredUser();
|
|
236
|
+
if (storedTokens && storedUser) {
|
|
237
|
+
authService["apiClient"].setToken(storedTokens.access.token);
|
|
238
|
+
setIsAuthenticated(true);
|
|
239
|
+
setUser(storedUser);
|
|
240
|
+
try {
|
|
241
|
+
const userResult = await authService.getCurrentUser();
|
|
242
|
+
if (userResult.success) {
|
|
243
|
+
setUser(userResult.user);
|
|
244
|
+
}
|
|
245
|
+
} catch (error2) {
|
|
246
|
+
console.warn("Failed to fetch fresh user info:", error2);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
} catch (error2) {
|
|
251
|
+
console.error("Failed to restore authentication:", error2);
|
|
252
|
+
setError(error2.message || "Failed to restore authentication");
|
|
253
|
+
} finally {
|
|
254
|
+
setIsLoading(false);
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
restoreAuth();
|
|
258
|
+
}, [authService, autoRestore]);
|
|
259
|
+
const login = useCallback(
|
|
260
|
+
async (credentials) => {
|
|
261
|
+
try {
|
|
262
|
+
setIsLoading(true);
|
|
263
|
+
setError(null);
|
|
264
|
+
const result = await authService.login(credentials);
|
|
265
|
+
if (result.success) {
|
|
266
|
+
setIsAuthenticated(true);
|
|
267
|
+
setUser(result.user || null);
|
|
268
|
+
if (onLoginSuccess) {
|
|
269
|
+
onLoginSuccess(result.user);
|
|
270
|
+
}
|
|
271
|
+
} else {
|
|
272
|
+
setError(result.error);
|
|
273
|
+
if (onLoginError) {
|
|
274
|
+
onLoginError(result.error);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return result;
|
|
278
|
+
} catch (error2) {
|
|
279
|
+
const errorMessage = error2.message || "An error occurred during login";
|
|
280
|
+
setError(errorMessage);
|
|
281
|
+
if (onLoginError) {
|
|
282
|
+
onLoginError(errorMessage);
|
|
283
|
+
}
|
|
284
|
+
return {
|
|
285
|
+
success: false,
|
|
286
|
+
error: errorMessage,
|
|
287
|
+
code: "UNKNOWN_ERROR"
|
|
288
|
+
};
|
|
289
|
+
} finally {
|
|
290
|
+
setIsLoading(false);
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
[authService, onLoginSuccess, onLoginError]
|
|
294
|
+
);
|
|
295
|
+
const logout = useCallback(async () => {
|
|
296
|
+
try {
|
|
297
|
+
setIsLoading(true);
|
|
298
|
+
setError(null);
|
|
299
|
+
await authService.logout();
|
|
300
|
+
setIsAuthenticated(false);
|
|
301
|
+
setUser(null);
|
|
302
|
+
if (onLogoutSuccess) {
|
|
303
|
+
onLogoutSuccess();
|
|
304
|
+
}
|
|
305
|
+
} catch (error2) {
|
|
306
|
+
const errorMessage = error2.message || "An error occurred during logout";
|
|
307
|
+
setError(errorMessage);
|
|
308
|
+
console.error("Logout failed:", error2);
|
|
309
|
+
} finally {
|
|
310
|
+
setIsLoading(false);
|
|
311
|
+
}
|
|
312
|
+
}, [authService, onLogoutSuccess]);
|
|
313
|
+
const refreshToken = useCallback(async () => {
|
|
314
|
+
try {
|
|
315
|
+
const storedTokens = await authService.getStoredTokens();
|
|
316
|
+
if (!storedTokens) {
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
const result = await authService.refreshToken(storedTokens.refresh.token);
|
|
320
|
+
if (result.success) {
|
|
321
|
+
return true;
|
|
322
|
+
} else {
|
|
323
|
+
await logout();
|
|
324
|
+
return false;
|
|
325
|
+
}
|
|
326
|
+
} catch (error2) {
|
|
327
|
+
console.error("Token refresh failed:", error2);
|
|
328
|
+
await logout();
|
|
329
|
+
return false;
|
|
330
|
+
}
|
|
331
|
+
}, [authService, logout]);
|
|
332
|
+
const clearError = useCallback(() => {
|
|
333
|
+
setError(null);
|
|
334
|
+
}, []);
|
|
335
|
+
return {
|
|
336
|
+
login,
|
|
337
|
+
logout,
|
|
338
|
+
refreshToken,
|
|
339
|
+
isAuthenticated,
|
|
340
|
+
user,
|
|
341
|
+
isLoading,
|
|
342
|
+
error,
|
|
343
|
+
clearError
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// src/hooks/useQRScanner.ts
|
|
348
|
+
import { useState as useState3, useCallback as useCallback3 } from "react";
|
|
349
|
+
|
|
350
|
+
// src/hooks/useLocation.ts
|
|
351
|
+
import { useState as useState2, useEffect as useEffect2, useCallback as useCallback2 } from "react";
|
|
352
|
+
import Geolocation from "@react-native-community/geolocation";
|
|
353
|
+
function useLocation(options = {}) {
|
|
354
|
+
const [location, setLocation] = useState2(null);
|
|
355
|
+
const [error, setError] = useState2(null);
|
|
356
|
+
const [isLoading, setIsLoading] = useState2(true);
|
|
357
|
+
const config = {
|
|
358
|
+
enableHighAccuracy: options.enableHighAccuracy ?? true,
|
|
359
|
+
timeout: options.timeout ?? 15e3,
|
|
360
|
+
maximumAge: options.maximumAge ?? 1e4
|
|
361
|
+
};
|
|
362
|
+
const refreshLocation = useCallback2(async () => {
|
|
363
|
+
setIsLoading(true);
|
|
364
|
+
setError(null);
|
|
365
|
+
return new Promise((resolve) => {
|
|
366
|
+
Geolocation.getCurrentPosition(
|
|
367
|
+
(position) => {
|
|
368
|
+
setLocation({
|
|
369
|
+
latitude: position.coords.latitude,
|
|
370
|
+
longitude: position.coords.longitude,
|
|
371
|
+
accuracy: position.coords.accuracy,
|
|
372
|
+
altitude: position.coords.altitude ?? void 0,
|
|
373
|
+
altitudeAccuracy: position.coords.altitudeAccuracy ?? void 0,
|
|
374
|
+
heading: position.coords.heading ?? void 0,
|
|
375
|
+
speed: position.coords.speed ?? void 0
|
|
376
|
+
});
|
|
377
|
+
setIsLoading(false);
|
|
378
|
+
resolve();
|
|
379
|
+
},
|
|
380
|
+
(err) => {
|
|
381
|
+
setError(new Error(err.message));
|
|
382
|
+
setIsLoading(false);
|
|
383
|
+
resolve();
|
|
384
|
+
},
|
|
385
|
+
config
|
|
386
|
+
);
|
|
387
|
+
});
|
|
388
|
+
}, [config.enableHighAccuracy, config.timeout, config.maximumAge]);
|
|
389
|
+
useEffect2(() => {
|
|
390
|
+
refreshLocation();
|
|
391
|
+
if (options.watchPosition) {
|
|
392
|
+
const watchId = Geolocation.watchPosition(
|
|
393
|
+
(position) => {
|
|
394
|
+
setLocation({
|
|
395
|
+
latitude: position.coords.latitude,
|
|
396
|
+
longitude: position.coords.longitude,
|
|
397
|
+
accuracy: position.coords.accuracy,
|
|
398
|
+
altitude: position.coords.altitude ?? void 0,
|
|
399
|
+
altitudeAccuracy: position.coords.altitudeAccuracy ?? void 0,
|
|
400
|
+
heading: position.coords.heading ?? void 0,
|
|
401
|
+
speed: position.coords.speed ?? void 0
|
|
402
|
+
});
|
|
403
|
+
},
|
|
404
|
+
(err) => {
|
|
405
|
+
setError(new Error(err.message));
|
|
406
|
+
},
|
|
407
|
+
config
|
|
408
|
+
);
|
|
409
|
+
return () => {
|
|
410
|
+
Geolocation.clearWatch(watchId);
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
return void 0;
|
|
414
|
+
}, [options.watchPosition, refreshLocation]);
|
|
415
|
+
return {
|
|
416
|
+
location,
|
|
417
|
+
error,
|
|
418
|
+
isLoading,
|
|
419
|
+
refreshLocation
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// src/hooks/useQRScanner.ts
|
|
424
|
+
function useQRScanner(options = {}) {
|
|
425
|
+
const { qrAccessService, deviceAccessService } = usePassgageAccess();
|
|
426
|
+
const { location } = useLocation();
|
|
427
|
+
const [isLoading, setIsLoading] = useState3(false);
|
|
428
|
+
const [error, setError] = useState3(null);
|
|
429
|
+
const scan = useCallback3(
|
|
430
|
+
async (qrCode, device) => {
|
|
431
|
+
setIsLoading(true);
|
|
432
|
+
setError(null);
|
|
433
|
+
try {
|
|
434
|
+
let qrDevice = device;
|
|
435
|
+
if (!qrDevice) {
|
|
436
|
+
qrDevice = await deviceAccessService.findDeviceByQRCode(qrCode);
|
|
437
|
+
if (!qrDevice) {
|
|
438
|
+
throw new Error("QR device not found");
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
const result = await qrAccessService.validateQR({
|
|
442
|
+
qrCode,
|
|
443
|
+
device: qrDevice,
|
|
444
|
+
userLocation: location || void 0,
|
|
445
|
+
skipLocationCheck: options.skipLocationCheck,
|
|
446
|
+
skipRepetitiveCheck: options.skipRepetitiveCheck
|
|
447
|
+
});
|
|
448
|
+
if (!result.success) {
|
|
449
|
+
throw new Error(result.message);
|
|
450
|
+
}
|
|
451
|
+
options.onSuccess?.(result.entrance);
|
|
452
|
+
} catch (err) {
|
|
453
|
+
const error2 = err;
|
|
454
|
+
setError(error2);
|
|
455
|
+
options.onError?.(error2);
|
|
456
|
+
} finally {
|
|
457
|
+
setIsLoading(false);
|
|
458
|
+
}
|
|
459
|
+
},
|
|
460
|
+
[qrAccessService, deviceAccessService, location, options]
|
|
461
|
+
);
|
|
462
|
+
return {
|
|
463
|
+
scan,
|
|
464
|
+
isLoading,
|
|
465
|
+
error
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// src/hooks/useNFCScanner.ts
|
|
470
|
+
import { useState as useState4, useCallback as useCallback4, useEffect as useEffect3 } from "react";
|
|
471
|
+
import NfcManager, { NfcTech } from "react-native-nfc-manager";
|
|
472
|
+
function reversedHexToDec(hexString) {
|
|
473
|
+
const hex = hexString.replace(/:/g, "");
|
|
474
|
+
return parseInt(hex, 16).toString();
|
|
475
|
+
}
|
|
476
|
+
function useNFCScanner(options = {}) {
|
|
477
|
+
const { nfcAccessService, deviceAccessService } = usePassgageAccess();
|
|
478
|
+
const { location } = useLocation();
|
|
479
|
+
const [isScanning, setIsScanning] = useState4(false);
|
|
480
|
+
const [error, setError] = useState4(null);
|
|
481
|
+
const stopScanning = useCallback4(async () => {
|
|
482
|
+
try {
|
|
483
|
+
await NfcManager.cancelTechnologyRequest();
|
|
484
|
+
setIsScanning(false);
|
|
485
|
+
} catch {
|
|
486
|
+
}
|
|
487
|
+
}, []);
|
|
488
|
+
const handleNFCTag = useCallback4(
|
|
489
|
+
async (tag) => {
|
|
490
|
+
if (!tag.id) {
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
try {
|
|
494
|
+
const nfcCode = reversedHexToDec(tag.id);
|
|
495
|
+
const device = await deviceAccessService.findDeviceByNFCCode(nfcCode);
|
|
496
|
+
if (!device) {
|
|
497
|
+
throw new Error("NFC device not found");
|
|
498
|
+
}
|
|
499
|
+
const result = await nfcAccessService.validateNFC({
|
|
500
|
+
nfcCode,
|
|
501
|
+
device,
|
|
502
|
+
userLocation: location || void 0,
|
|
503
|
+
skipLocationCheck: options.skipLocationCheck,
|
|
504
|
+
skipRepetitiveCheck: options.skipRepetitiveCheck
|
|
505
|
+
});
|
|
506
|
+
if (!result.success) {
|
|
507
|
+
throw new Error(result.message);
|
|
508
|
+
}
|
|
509
|
+
options.onSuccess?.(result.entrance);
|
|
510
|
+
await stopScanning();
|
|
511
|
+
} catch (err) {
|
|
512
|
+
const error2 = err;
|
|
513
|
+
setError(error2);
|
|
514
|
+
options.onError?.(error2);
|
|
515
|
+
await stopScanning();
|
|
516
|
+
}
|
|
517
|
+
},
|
|
518
|
+
[nfcAccessService, deviceAccessService, location, options, stopScanning]
|
|
519
|
+
);
|
|
520
|
+
const startScanning = useCallback4(async () => {
|
|
521
|
+
setIsScanning(true);
|
|
522
|
+
setError(null);
|
|
523
|
+
try {
|
|
524
|
+
await NfcManager.requestTechnology(NfcTech.Ndef, {
|
|
525
|
+
invalidateAfterFirstRead: true
|
|
526
|
+
});
|
|
527
|
+
const tag = await NfcManager.getTag();
|
|
528
|
+
await handleNFCTag(tag || {});
|
|
529
|
+
} catch (err) {
|
|
530
|
+
const error2 = err;
|
|
531
|
+
setError(error2);
|
|
532
|
+
options.onError?.(error2);
|
|
533
|
+
setIsScanning(false);
|
|
534
|
+
}
|
|
535
|
+
}, [handleNFCTag, options]);
|
|
536
|
+
useEffect3(() => {
|
|
537
|
+
if (options.autoStart) {
|
|
538
|
+
startScanning();
|
|
539
|
+
}
|
|
540
|
+
return () => {
|
|
541
|
+
stopScanning();
|
|
542
|
+
};
|
|
543
|
+
}, [options.autoStart, startScanning, stopScanning]);
|
|
544
|
+
return {
|
|
545
|
+
startScanning,
|
|
546
|
+
stopScanning,
|
|
547
|
+
isScanning,
|
|
548
|
+
error
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// src/hooks/useCheckIn.ts
|
|
553
|
+
import { useState as useState5, useEffect as useEffect4, useCallback as useCallback5 } from "react";
|
|
554
|
+
function useCheckIn(options = {}) {
|
|
555
|
+
const { checkInService, config: _config } = usePassgageAccess();
|
|
556
|
+
const { location } = useLocation();
|
|
557
|
+
const [nearbyBranches, setNearbyBranches] = useState5([]);
|
|
558
|
+
const [isLoading, setIsLoading] = useState5(false);
|
|
559
|
+
const [error, setError] = useState5(null);
|
|
560
|
+
const fetchNearbyBranches = useCallback5(async () => {
|
|
561
|
+
if (!location) {
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
setIsLoading(true);
|
|
565
|
+
setError(null);
|
|
566
|
+
try {
|
|
567
|
+
const response = await checkInService.getNearbyBranches({
|
|
568
|
+
latitude: location.latitude,
|
|
569
|
+
longitude: location.longitude,
|
|
570
|
+
radius: options.radius
|
|
571
|
+
});
|
|
572
|
+
if (response.success && response.data) {
|
|
573
|
+
setNearbyBranches(response.data);
|
|
574
|
+
}
|
|
575
|
+
} catch (err) {
|
|
576
|
+
setError(err);
|
|
577
|
+
} finally {
|
|
578
|
+
setIsLoading(false);
|
|
579
|
+
}
|
|
580
|
+
}, [checkInService, location, options.radius]);
|
|
581
|
+
const checkIn = useCallback5(
|
|
582
|
+
async (params) => {
|
|
583
|
+
setIsLoading(true);
|
|
584
|
+
setError(null);
|
|
585
|
+
try {
|
|
586
|
+
const userId = "";
|
|
587
|
+
const result = await checkInService.checkIn({
|
|
588
|
+
...params,
|
|
589
|
+
userId,
|
|
590
|
+
userLocation: location || void 0
|
|
591
|
+
});
|
|
592
|
+
if (!result.success) {
|
|
593
|
+
throw new Error(result.message);
|
|
594
|
+
}
|
|
595
|
+
return result.entrance;
|
|
596
|
+
} catch (err) {
|
|
597
|
+
setError(err);
|
|
598
|
+
throw err;
|
|
599
|
+
} finally {
|
|
600
|
+
setIsLoading(false);
|
|
601
|
+
}
|
|
602
|
+
},
|
|
603
|
+
[checkInService, location]
|
|
604
|
+
);
|
|
605
|
+
useEffect4(() => {
|
|
606
|
+
if (options.autoFetch && location) {
|
|
607
|
+
fetchNearbyBranches();
|
|
608
|
+
}
|
|
609
|
+
}, [options.autoFetch, location, fetchNearbyBranches]);
|
|
610
|
+
return {
|
|
611
|
+
nearbyBranches,
|
|
612
|
+
fetchNearbyBranches,
|
|
613
|
+
checkIn,
|
|
614
|
+
isLoading,
|
|
615
|
+
error
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// src/hooks/useRemoteWork.ts
|
|
620
|
+
import { useState as useState6, useCallback as useCallback6 } from "react";
|
|
621
|
+
import { EntranceType } from "@passgage/sdk-core";
|
|
622
|
+
function useRemoteWork() {
|
|
623
|
+
const { remoteWorkService } = usePassgageAccess();
|
|
624
|
+
const [isLoading, setIsLoading] = useState6(false);
|
|
625
|
+
const [error, setError] = useState6(null);
|
|
626
|
+
const logRemoteWork = useCallback6(
|
|
627
|
+
async (entranceType, options = {}) => {
|
|
628
|
+
setIsLoading(true);
|
|
629
|
+
setError(null);
|
|
630
|
+
try {
|
|
631
|
+
const userId = "";
|
|
632
|
+
const result = await remoteWorkService.logRemoteWork({
|
|
633
|
+
userId,
|
|
634
|
+
entranceType,
|
|
635
|
+
timestamp: options.timestamp,
|
|
636
|
+
description: options.description
|
|
637
|
+
});
|
|
638
|
+
if (!result.success) {
|
|
639
|
+
throw new Error(result.message);
|
|
640
|
+
}
|
|
641
|
+
return result.entrance;
|
|
642
|
+
} catch (err) {
|
|
643
|
+
const error2 = err;
|
|
644
|
+
setError(error2);
|
|
645
|
+
throw error2;
|
|
646
|
+
} finally {
|
|
647
|
+
setIsLoading(false);
|
|
648
|
+
}
|
|
649
|
+
},
|
|
650
|
+
[remoteWorkService]
|
|
651
|
+
);
|
|
652
|
+
const logEntry = useCallback6(
|
|
653
|
+
async (options) => {
|
|
654
|
+
return logRemoteWork(EntranceType.ENTRY, options);
|
|
655
|
+
},
|
|
656
|
+
[logRemoteWork]
|
|
657
|
+
);
|
|
658
|
+
const logExit = useCallback6(
|
|
659
|
+
async (options) => {
|
|
660
|
+
return logRemoteWork(EntranceType.EXIT, options);
|
|
661
|
+
},
|
|
662
|
+
[logRemoteWork]
|
|
663
|
+
);
|
|
664
|
+
return {
|
|
665
|
+
logEntry,
|
|
666
|
+
logExit,
|
|
667
|
+
logRemoteWork,
|
|
668
|
+
isLoading,
|
|
669
|
+
error
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// src/index.tsx
|
|
674
|
+
var SDK_VERSION = "1.0.0";
|
|
675
|
+
export {
|
|
676
|
+
PassgageAccessProvider,
|
|
677
|
+
SDK_VERSION,
|
|
678
|
+
useCheckIn,
|
|
679
|
+
useLocation,
|
|
680
|
+
useNFCScanner,
|
|
681
|
+
usePassgageAccess,
|
|
682
|
+
usePassgageAuth,
|
|
683
|
+
useQRScanner,
|
|
684
|
+
useRemoteWork
|
|
685
|
+
};
|