@phygitallabs/tapquest-core 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +210 -0
  2. package/index.ts +1 -0
  3. package/package.json +43 -0
  4. package/src/constants/firebase.ts +36 -0
  5. package/src/constants/service.ts +30 -0
  6. package/src/helper/helpers.ts +3 -0
  7. package/src/helper/index.ts +1 -0
  8. package/src/index.ts +25 -0
  9. package/src/modules/achievement/helpers/index.ts +98 -0
  10. package/src/modules/achievement/hooks/index.ts +171 -0
  11. package/src/modules/achievement/index.ts +5 -0
  12. package/src/modules/achievement/types/index.ts +45 -0
  13. package/src/modules/achivementWithReward/hooks/achivementPlusRewardModel.ts +83 -0
  14. package/src/modules/achivementWithReward/hooks/index.ts +5 -0
  15. package/src/modules/achivementWithReward/index.ts +5 -0
  16. package/src/modules/auth/README.md +527 -0
  17. package/src/modules/auth/constants/index.ts +9 -0
  18. package/src/modules/auth/helpers/index.ts +161 -0
  19. package/src/modules/auth/helpers/refreshToken.ts +63 -0
  20. package/src/modules/auth/index.ts +20 -0
  21. package/src/modules/auth/providers/AuthProvider.tsx +207 -0
  22. package/src/modules/auth/providers/index.ts +1 -0
  23. package/src/modules/auth/services/FirebaseAuthService.ts +290 -0
  24. package/src/modules/auth/services/authServiceFactory.ts +22 -0
  25. package/src/modules/auth/services/index.ts +3 -0
  26. package/src/modules/auth/store/authSlice.ts +137 -0
  27. package/src/modules/auth/types/index.ts +109 -0
  28. package/src/modules/campaign/hooks/index.ts +6 -0
  29. package/src/modules/campaign/hooks/useCampaignService.ts +7 -0
  30. package/src/modules/campaign/index.tsx +7 -0
  31. package/src/modules/campaign/types/campaign.ts +51 -0
  32. package/src/modules/campaign/types/enums.ts +4 -0
  33. package/src/modules/campaign/types/index.ts +4 -0
  34. package/src/modules/campaign/types/requests.ts +46 -0
  35. package/src/modules/data-tracking/hooks/index.ts +67 -0
  36. package/src/modules/data-tracking/index.ts +1 -0
  37. package/src/modules/generate-certificate/hooks/index.ts +8 -0
  38. package/src/modules/generate-certificate/index.ts +3 -0
  39. package/src/modules/generate-certificate/types/generateCertificate.ts +7 -0
  40. package/src/modules/generate-certificate/types/index.ts +7 -0
  41. package/src/modules/location/hooks/index.ts +8 -0
  42. package/src/modules/location/hooks/useLocationService.ts +8 -0
  43. package/src/modules/location/index.tsx +11 -0
  44. package/src/modules/location/types/index.ts +18 -0
  45. package/src/modules/location/types/locationModel.ts +21 -0
  46. package/src/modules/location/utils/index.ts +5 -0
  47. package/src/modules/location/utils/locationHelpers.ts +13 -0
  48. package/src/modules/memory/hooks/index.ts +3 -0
  49. package/src/modules/memory/index.ts +3 -0
  50. package/src/modules/memory/types/index.ts +3 -0
  51. package/src/modules/notification/index.ts +2 -0
  52. package/src/modules/notification/providers/index.tsx +50 -0
  53. package/src/modules/notification/types/index.ts +3 -0
  54. package/src/modules/reward/hooks/index.ts +14 -0
  55. package/src/modules/reward/hooks/useRewardService.ts +14 -0
  56. package/src/modules/reward/index.tsx +16 -0
  57. package/src/modules/reward/types/enums.ts +13 -0
  58. package/src/modules/reward/types/index.ts +4 -0
  59. package/src/modules/reward/types/requests.ts +281 -0
  60. package/src/modules/reward/types/reward.ts +90 -0
  61. package/src/modules/scan-chip/hooks/index.tsx +67 -0
  62. package/src/modules/scan-chip/index.ts +2 -0
  63. package/src/modules/scan-chip/types/index.ts +25 -0
  64. package/src/modules/send-email/hooks/index.ts +2 -0
  65. package/src/modules/send-email/index.ts +1 -0
  66. package/src/modules/user-profile/hooks/index.ts +3 -0
  67. package/src/modules/user-profile/index.ts +3 -0
  68. package/src/modules/user-profile/types/index.ts +3 -0
  69. package/src/providers/ServicesProvider.tsx +173 -0
  70. package/src/providers/TapquestCoreProvider.tsx +64 -0
  71. package/src/providers/index.ts +1 -0
  72. package/src/store/hooks.ts +6 -0
  73. package/src/store/index.ts +45 -0
  74. package/src/types/common.d.ts +8 -0
  75. package/src/types/media.ts +26 -0
  76. package/src/types/service.d.ts +34 -0
  77. package/tsconfig.json +28 -0
  78. package/tsup.config.ts +10 -0
@@ -0,0 +1,161 @@
1
+ import {
2
+ deviceUIDKey,
3
+ chipAuthTokenKey,
4
+ retryAttemptsRefreshToken,
5
+ accessTokenKey,
6
+ refreshTokenKey,
7
+ userInfoKey,
8
+ } from "../constants";
9
+
10
+ import { v4 as uuidv4 } from "uuid";
11
+
12
+ export const generateDeviceId = async (): Promise<string> => {
13
+ try {
14
+ const deviceFingerprint = await generateDeviceFingerprint();
15
+ return deviceFingerprint;
16
+ } catch (error) {
17
+ console.error("Error generating device fingerprint:", error);
18
+ return uuidv4();
19
+ }
20
+ };
21
+
22
+ const generateDeviceFingerprint = async (): Promise<string> => {
23
+ const timestamp = new Date().toISOString(); // UTC timestamp
24
+
25
+ const fingerprintRaw = [
26
+ navigator.userAgent,
27
+ navigator.language,
28
+ screen.width,
29
+ screen.height,
30
+ screen.colorDepth,
31
+ Intl.DateTimeFormat().resolvedOptions().timeZone,
32
+ navigator.platform,
33
+ navigator.hardwareConcurrency,
34
+ timestamp, // Include timestamp
35
+ ].join("::");
36
+
37
+ const encoder = new TextEncoder();
38
+ const data = encoder.encode(fingerprintRaw);
39
+ const hashBuffer = await crypto.subtle.digest("SHA-256", data);
40
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
41
+ const fingerprint = hashArray
42
+ .map((b) => b.toString(16).padStart(2, "0"))
43
+ .join("");
44
+ return fingerprint;
45
+ };
46
+
47
+ export default generateDeviceFingerprint;
48
+
49
+
50
+ export const getDeviceUid = () => {
51
+ if (typeof window === "undefined") return null;
52
+ return localStorage.getItem(deviceUIDKey);
53
+ };
54
+
55
+ export const setDeviceUid = (deviceId: string) => {
56
+ if (typeof window === "undefined") return;
57
+ localStorage.setItem(deviceUIDKey, deviceId);
58
+ };
59
+
60
+ export const removeDeviceUid = () => {
61
+ if (typeof window === "undefined") return;
62
+ localStorage.removeItem(deviceUIDKey);
63
+ };
64
+
65
+ export const checkDeviceUid = async (): Promise<string> => {
66
+ // if (typeof window === "undefined") return null;
67
+
68
+ let deviceUID = getDeviceUid();
69
+
70
+ if (!deviceUID) {
71
+ deviceUID = await generateDeviceId();
72
+ setDeviceUid(deviceUID);
73
+ }
74
+
75
+ return deviceUID;
76
+ };
77
+
78
+ // CHIP AUTH TOKEN
79
+ export const getChipAuthToken = () => {
80
+ if (typeof window === "undefined") return null;
81
+ return localStorage.getItem(chipAuthTokenKey);
82
+ };
83
+
84
+ export const setChipAuthToken = (value: string) => {
85
+ if (typeof window === "undefined") return;
86
+ localStorage.setItem(chipAuthTokenKey, value);
87
+ };
88
+
89
+ export const removeChipAuthToken = () => {
90
+ if (typeof window === "undefined") return;
91
+ localStorage.removeItem(chipAuthTokenKey);
92
+ };
93
+
94
+ // RETRY ATTEMPTS
95
+ export const getRetryAttemptsRefreshToken = () => {
96
+ if (typeof window === "undefined") return null;
97
+ return localStorage.getItem(retryAttemptsRefreshToken);
98
+ };
99
+
100
+ export const setRetryAttemptsRefreshToken = (value: string) => {
101
+ if (typeof window === "undefined") return;
102
+ localStorage.setItem(retryAttemptsRefreshToken, value);
103
+ };
104
+
105
+ // ACCESS TOKEN
106
+ export const getAccessToken = () => {
107
+ if (typeof window === "undefined") return null;
108
+ return localStorage.getItem(accessTokenKey);
109
+ };
110
+
111
+ export const setAccessToken = (value: string) => {
112
+ if (typeof window === "undefined") return;
113
+ localStorage.setItem(accessTokenKey, value);
114
+ };
115
+
116
+ export const removeAccessToken = () => {
117
+ if (typeof window === "undefined") return;
118
+ localStorage.removeItem(accessTokenKey);
119
+ };
120
+
121
+ // REFRESH TOKEN
122
+ export const getRefreshToken = () => {
123
+ if (typeof window === "undefined") return null;
124
+ return localStorage.getItem(refreshTokenKey);
125
+ };
126
+
127
+ export const setRefreshToken = (value: string) => {
128
+ if (typeof window === "undefined") return;
129
+ localStorage.setItem(refreshTokenKey, value);
130
+ };
131
+
132
+ export const removeRefreshToken = () => {
133
+ if (typeof window === "undefined") return;
134
+ localStorage.removeItem(refreshTokenKey);
135
+ };
136
+
137
+ // USER INFO
138
+ export const getUserInfo = () => {
139
+ if (typeof window === "undefined") return null;
140
+ const userInfo = localStorage.getItem(userInfoKey);
141
+ if (!userInfo) return null;
142
+ try {
143
+ return JSON.parse(userInfo);
144
+ } catch (error) {
145
+ console.error("Failed to parse stored user data:", error);
146
+ return null;
147
+ }
148
+ };
149
+
150
+ export const setUserInfo = (userData: any) => {
151
+ if (typeof window === "undefined") return;
152
+ localStorage.setItem(userInfoKey, JSON.stringify(userData));
153
+ };
154
+
155
+ export const removeUserInfo = () => {
156
+ if (typeof window === "undefined") return;
157
+ localStorage.removeItem(userInfoKey);
158
+ };
159
+
160
+ export { createRefreshTokenFunction } from "./refreshToken";
161
+ export type { RefreshTokenConfig } from "./refreshToken";
@@ -0,0 +1,63 @@
1
+ import mem from "mem";
2
+ import { setUserInfo, removeUserInfo, getUserInfo, getRefreshToken } from "./index";
3
+
4
+ // Internal configuration - managed by tapquest-core
5
+ const REFRESH_TOKEN_CONFIG = {
6
+ maxAge: 10000, // 10 seconds cache
7
+ } as const;
8
+
9
+ export interface RefreshTokenConfig {
10
+ firebaseApiKey: string;
11
+ }
12
+
13
+ const createRefreshTokenFunction = (config: RefreshTokenConfig) => {
14
+ const refreshTokenFn = async () => {
15
+ try {
16
+ const session = getUserInfo();
17
+ const refreshToken = getRefreshToken();
18
+
19
+ if (!refreshToken) {
20
+ removeUserInfo();
21
+ return;
22
+ }
23
+
24
+ const params = new URLSearchParams();
25
+ params.append("grant_type", "refresh_token");
26
+ params.append("refresh_token", refreshToken);
27
+
28
+ const fetchData = {
29
+ method: "POST",
30
+ headers: new Headers({
31
+ "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
32
+ }),
33
+ body: params,
34
+ };
35
+
36
+ const response = await fetch(
37
+ `https://securetoken.googleapis.com/v1/token?key=${config.firebaseApiKey}`,
38
+ fetchData
39
+ );
40
+ const data = await response.json();
41
+
42
+ if (data.error) {
43
+ removeUserInfo();
44
+ return;
45
+ }
46
+
47
+ const newSession = {
48
+ ...session,
49
+ accessToken: data.access_token,
50
+ refreshToken: data.refresh_token,
51
+ };
52
+ setUserInfo(newSession);
53
+
54
+ return newSession;
55
+ } catch {
56
+ removeUserInfo();
57
+ }
58
+ };
59
+
60
+ return mem(refreshTokenFn, { maxAge: REFRESH_TOKEN_CONFIG.maxAge });
61
+ };
62
+
63
+ export { createRefreshTokenFunction };
@@ -0,0 +1,20 @@
1
+ // Export types
2
+ export type {
3
+ UserData,
4
+ UserRole,
5
+ SignInProvider,
6
+ AuthResponse,
7
+ AuthService,
8
+ FirebaseConfig,
9
+ UseAuthReturn,
10
+ AuthProviderProps,
11
+ AuthCallbacks,
12
+ } from './types';
13
+
14
+ // Export hooks and providers
15
+ // export { useAuth } from './hooks';
16
+ export { useAuth, AuthProvider } from './providers';
17
+
18
+ // Export constants and helpers
19
+ export * from './constants';
20
+ export * from './helpers';
@@ -0,0 +1,207 @@
1
+ import { createContext, useEffect, ReactNode, useContext } from 'react';
2
+ import { AuthService, AuthCallbacks } from '../types';
3
+
4
+ import { useAppSelector, useAppDispatch } from '../../../store/hooks';
5
+ import {
6
+ selectUser,
7
+ selectIsSignedIn,
8
+ selectIsLoading,
9
+ signIn as signInAction,
10
+ signOut as signOutAction,
11
+ updateScanStatus as updateScanStatusAction,
12
+ refreshUser as refreshUserAction,
13
+ setPending,
14
+ initializeFromStorage,
15
+ } from '../store/authSlice';
16
+
17
+ import { AuthResponse, UserData } from '../types';
18
+
19
+ export interface AuthContextType {
20
+ authService: AuthService;
21
+ authCallbacks?: AuthCallbacks;
22
+ // User state
23
+ user: UserData;
24
+ isSignedIn: boolean;
25
+ isLoading: boolean;
26
+
27
+ // Auth actions
28
+ signInWithCredential: (email: string, password: string) => Promise<AuthResponse>;
29
+ signInWithGoogle: () => Promise<AuthResponse | null>;
30
+ signUp: (email: string, password: string) => Promise<AuthResponse>;
31
+ signOut: () => Promise<void>;
32
+
33
+ // Password actions
34
+ forgotPassword: (email: string) => Promise<void>;
35
+ sendEmailVerification: () => Promise<void>;
36
+ changePassword: (newPassword: string) => Promise<void>;
37
+
38
+ // User management
39
+ updateScanStatus: (status: boolean) => void;
40
+ refreshUser: (userData: UserData) => void;
41
+
42
+ }
43
+
44
+ export const AuthContext = createContext<AuthContextType | null>(null);
45
+
46
+ export interface AuthProviderProps {
47
+ children: ReactNode;
48
+ authService: AuthService;
49
+ authCallbacks?: AuthCallbacks;
50
+ }
51
+
52
+ export function AuthProvider({ children, authService, authCallbacks }: AuthProviderProps) {
53
+ const dispatch = useAppDispatch();
54
+
55
+ useEffect(() => {
56
+ // Initialize auth state from localStorage
57
+ dispatch(initializeFromStorage());
58
+
59
+ // Set up auth state listener
60
+ const unsubscribe = authService.onAuthStateChanged((user) => {
61
+ if (user) {
62
+ dispatch(signInAction(user));
63
+
64
+ // Use auth callback for user identification
65
+ if (authCallbacks?.onUserIdentify && user.email) {
66
+ authCallbacks.onUserIdentify({
67
+ email: user.email,
68
+ name: user.displayName,
69
+ avatar: user.avatar,
70
+ uid: user.uid,
71
+ });
72
+ }
73
+
74
+ // Notify about successful sign in
75
+ if (authCallbacks?.onSignInSuccess) {
76
+ authCallbacks.onSignInSuccess(user);
77
+ }
78
+ } else {
79
+ dispatch(signOutAction());
80
+
81
+ // Use auth callback for reset
82
+ if (authCallbacks?.onTrackingReset) {
83
+ authCallbacks.onTrackingReset();
84
+ }
85
+ }
86
+ dispatch(setPending(false));
87
+ });
88
+
89
+ return () => {
90
+ unsubscribe();
91
+ };
92
+ }, [authService, dispatch, authCallbacks]);
93
+
94
+ // Redux selectors
95
+ const user = useAppSelector(selectUser);
96
+ const isSignedIn = useAppSelector(selectIsSignedIn);
97
+ const isLoading = useAppSelector(selectIsLoading);
98
+
99
+ // Auth actions with auth callbacks
100
+ const signInWithCredential = async (email: string, password: string): Promise<AuthResponse> => {
101
+ const result = await authService.signInWithEmailAndPassword(email, password);
102
+
103
+ if (result.data && authCallbacks?.onSignInSuccess) {
104
+ authCallbacks.onSignInSuccess(result.data);
105
+ } else if (result.errorCode && authCallbacks?.onSignInError) {
106
+ authCallbacks.onSignInError(result.errorCode);
107
+ }
108
+
109
+ return result;
110
+ };
111
+
112
+ const signInWithGoogle = async (): Promise<AuthResponse | null> => {
113
+ const result = await authService.signInWithGoogle();
114
+
115
+ if (result.data && authCallbacks?.onSignInSuccess) {
116
+ authCallbacks.onSignInSuccess(result.data);
117
+ return result;
118
+
119
+ } else if (result.errorCode && authCallbacks?.onSignInError) {
120
+ authCallbacks.onSignInError(result.errorCode);
121
+ }
122
+
123
+ return null;
124
+ };
125
+
126
+ const signUp = async (email: string, password: string): Promise<AuthResponse> => {
127
+ const result = await authService.signUp(email, password);
128
+
129
+ if (result.data && authCallbacks?.onSignUpSuccess) {
130
+ authCallbacks.onSignUpSuccess(result.data);
131
+ } else if (result.errorCode && authCallbacks?.onSignUpError) {
132
+ authCallbacks.onSignUpError(result.errorCode);
133
+ }
134
+
135
+ return result;
136
+ };
137
+
138
+ const signOut = async (): Promise<void> => {
139
+ await authService.signOut();
140
+ dispatch(signOutAction());
141
+
142
+ if (authCallbacks?.onSignOutSuccess) {
143
+ authCallbacks.onSignOutSuccess();
144
+ }
145
+ };
146
+
147
+ // Password actions
148
+ const forgotPassword = async (email: string): Promise<void> => {
149
+ return await authService.sendPasswordResetEmail(email);
150
+ };
151
+
152
+ const sendEmailVerification = async (): Promise<void> => {
153
+ return await authService.sendEmailVerification();
154
+ };
155
+
156
+ const changePassword = async (newPassword: string): Promise<void> => {
157
+ return await authService.changePassword(newPassword);
158
+ };
159
+
160
+ // User management
161
+ const updateScanStatus = (status: boolean): void => {
162
+ dispatch(updateScanStatusAction(status));
163
+ };
164
+
165
+ const refreshUser = (userData: UserData): void => {
166
+ dispatch(refreshUserAction(userData));
167
+ };
168
+
169
+ const contextValue: AuthContextType = {
170
+ authService,
171
+ authCallbacks,
172
+ // User state
173
+ user,
174
+ isSignedIn,
175
+ isLoading,
176
+
177
+ // Auth actions
178
+ signInWithCredential,
179
+ signInWithGoogle,
180
+ signUp,
181
+ signOut,
182
+
183
+ // Password actions
184
+ forgotPassword,
185
+ sendEmailVerification,
186
+ changePassword,
187
+
188
+ // User management
189
+ updateScanStatus,
190
+ refreshUser,
191
+ };
192
+
193
+ return (
194
+ <AuthContext.Provider value={contextValue}>
195
+ {children}
196
+ </AuthContext.Provider>
197
+ );
198
+ }
199
+
200
+ export const useAuth = () => {
201
+ const authContext = useContext(AuthContext);
202
+ if (!authContext) {
203
+ throw new Error('useAuth must be used within an AuthProvider');
204
+ }
205
+
206
+ return authContext;
207
+ };
@@ -0,0 +1 @@
1
+ export * from './AuthProvider';