@phygitallabs/tapquest-core 4.4.0 → 4.6.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.
- package/bun.lock +18 -5
- package/dist/index.cjs +3 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.mts +216 -23
- package/dist/index.d.ts +877 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/package.json +8 -6
- package/src/constants/firebase.ts +36 -0
- package/src/index.ts +4 -0
- package/src/modules/achievement/hooks/index.ts +0 -94
- package/src/modules/achivementWithReward/hooks/achivementPlusRewardModel.ts +30 -7
- package/src/modules/auth/hooks/useGoogleLogin.ts +5 -2
- package/src/modules/auth/hooks/useTokenRefresher.ts +3 -8
- package/src/modules/auth/providers/AuthProvider.tsx +3 -3
- package/src/modules/auth/services/FirebaseAuthService.ts +290 -0
- package/src/modules/auth/services/authServiceFactory.ts +22 -0
- package/src/modules/auth/services/index.ts +3 -0
- package/src/modules/auth/store/authStore.ts +30 -24
- package/src/modules/auth/utils/user.ts +11 -1
- package/src/modules/data-tracking/hooks/index.ts +2 -1
- package/src/modules/generate-certificate/hooks/index.ts +2 -0
- package/src/modules/reward/hooks/useRewardService.ts +1 -1
- package/src/modules/reward/types/requests.ts +1 -1
- package/src/providers/ServicesProvider.tsx +38 -2
- package/tsup.config.ts +12 -2
- package/dist/index.mjs +0 -3
- package/dist/index.mjs.map +0 -1
- package/src/store/hooks.ts +0 -6
- package/src/store/index.ts +0 -45
|
@@ -10,7 +10,20 @@ interface GroupRewardData {
|
|
|
10
10
|
reward_models: EntityRewardModel[][];
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
export interface AchievementWithRewardModel {
|
|
14
|
+
id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
reward_model: EntityRewardModel | null;
|
|
17
|
+
subAchievements: {
|
|
18
|
+
id: string;
|
|
19
|
+
reward_model: EntityRewardModel | null;
|
|
20
|
+
}[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function buildMappedAchievements(
|
|
24
|
+
achievements: Achievement[],
|
|
25
|
+
groupRewardData: GroupRewardData
|
|
26
|
+
) {
|
|
14
27
|
if (!groupRewardData?.reward_models) return [];
|
|
15
28
|
|
|
16
29
|
const rewardModels = groupRewardData.reward_models;
|
|
@@ -22,9 +35,9 @@ function buildMappedAchievements(achievements: Achievement[], groupRewardData: G
|
|
|
22
35
|
achievement.subAchievementIds?.map((subId: string, subIndex: number) => {
|
|
23
36
|
const reward =
|
|
24
37
|
rewardModels[
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
38
|
+
achievementIndex * (achievement.subAchievementIds?.length || 0) +
|
|
39
|
+
subIndex +
|
|
40
|
+
1
|
|
28
41
|
]?.[0] || null;
|
|
29
42
|
|
|
30
43
|
return {
|
|
@@ -42,7 +55,12 @@ function buildMappedAchievements(achievements: Achievement[], groupRewardData: G
|
|
|
42
55
|
});
|
|
43
56
|
}
|
|
44
57
|
|
|
45
|
-
const useAchivementPlusRewardModel = ({
|
|
58
|
+
const useAchivementPlusRewardModel = ({
|
|
59
|
+
campaignId,
|
|
60
|
+
}: UseAchivementPlusRewardModelParams): {
|
|
61
|
+
mappedAchievements: AchievementWithRewardModel[];
|
|
62
|
+
isLoading: boolean;
|
|
63
|
+
} => {
|
|
46
64
|
const { data: achievements, isLoading: isLoadingAchievements } =
|
|
47
65
|
useManyAchievements(
|
|
48
66
|
{
|
|
@@ -59,6 +77,7 @@ const useAchivementPlusRewardModel = ({ campaignId }: UseAchivementPlusRewardMod
|
|
|
59
77
|
.map((achievement) => achievement.groupRewardId)
|
|
60
78
|
.filter((id): id is string => id !== undefined);
|
|
61
79
|
}, [achievements?.data]);
|
|
80
|
+
|
|
62
81
|
const {
|
|
63
82
|
mutate: fetchGroupRewardModels,
|
|
64
83
|
data: groupRewardModelsData,
|
|
@@ -70,10 +89,14 @@ const useAchivementPlusRewardModel = ({ campaignId }: UseAchivementPlusRewardMod
|
|
|
70
89
|
}
|
|
71
90
|
}, [groupRewardIds, fetchGroupRewardModels]);
|
|
72
91
|
|
|
73
|
-
const mappedAchievements = useMemo(() => {
|
|
92
|
+
const mappedAchievements: AchievementWithRewardModel[] = useMemo(() => {
|
|
74
93
|
if (!groupRewardModelsData?.data || !achievements?.data) return [];
|
|
75
|
-
return buildMappedAchievements(
|
|
94
|
+
return buildMappedAchievements(
|
|
95
|
+
achievements.data,
|
|
96
|
+
groupRewardModelsData.data
|
|
97
|
+
);
|
|
76
98
|
}, [groupRewardModelsData, achievements?.data]);
|
|
99
|
+
|
|
77
100
|
return {
|
|
78
101
|
mappedAchievements,
|
|
79
102
|
isLoading: isLoadingAchievements || isPendingGroupRewardModels,
|
|
@@ -2,9 +2,10 @@ import { useRef, useCallback, useEffect } from "react";
|
|
|
2
2
|
import { useAuth } from "../store/authStore";
|
|
3
3
|
import { tokenStorage } from "@phygitallabs/authentication";
|
|
4
4
|
import { ALLOWED_ORIGINS } from "../constants";
|
|
5
|
+
import { decodeJWTToken } from "../utils/user";
|
|
5
6
|
|
|
6
7
|
export interface UseGoogleLoginOptions {
|
|
7
|
-
onSuccess?: () => void;
|
|
8
|
+
onSuccess?: (userData: any) => void;
|
|
8
9
|
onError?: (error: string) => void;
|
|
9
10
|
onPopupBlocked?: () => void;
|
|
10
11
|
onPopupClosed?: () => void;
|
|
@@ -36,9 +37,11 @@ export function useGoogleLogin(options: UseGoogleLoginOptions = {}): UseGoogleLo
|
|
|
36
37
|
refreshToken: newToken.data.refreshToken,
|
|
37
38
|
});
|
|
38
39
|
|
|
40
|
+
const userData = decodeJWTToken(newToken.data.idToken);
|
|
41
|
+
|
|
39
42
|
setIsSignedIn(true);
|
|
40
43
|
setIsLoading(false);
|
|
41
|
-
onSuccess?.();
|
|
44
|
+
onSuccess?.(userData);
|
|
42
45
|
}
|
|
43
46
|
} catch (error) {
|
|
44
47
|
const errorMessage = error instanceof Error ? error.message : "Token refresh failed";
|
|
@@ -8,17 +8,12 @@ export function useTokenRefresher() {
|
|
|
8
8
|
const handleRefreshToken = async () => {
|
|
9
9
|
try {
|
|
10
10
|
const isTokenExpired = tokenStorage.isTokenExpired();
|
|
11
|
+
|
|
11
12
|
if (!isTokenExpired) {
|
|
12
13
|
return;
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if(newToken.data?.idToken && newToken.data?.refreshToken){
|
|
17
|
-
tokenStorage.setTokens({
|
|
18
|
-
idToken: newToken.data?.idToken,
|
|
19
|
-
refreshToken: newToken.data?.refreshToken,
|
|
20
|
-
});
|
|
21
|
-
}
|
|
15
|
+
|
|
16
|
+
await refreshToken();
|
|
22
17
|
|
|
23
18
|
} catch (error) {
|
|
24
19
|
console.error("Failed to refresh token:", error);
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
tokenStorage,
|
|
5
5
|
} from "@phygitallabs/authentication";
|
|
6
6
|
import { useEffect } from "react";
|
|
7
|
-
import {
|
|
7
|
+
import {useAuthStore} from "../store/authStore";
|
|
8
8
|
import { transformProtoUserData } from "../utils/user";
|
|
9
9
|
import { userService } from "@phygitallabs/api-core";
|
|
10
10
|
import { QueryClient } from "@tanstack/react-query";
|
|
@@ -70,8 +70,8 @@ const AuthStateManager = () => {
|
|
|
70
70
|
let previousIsSignedIn = useAuthStore.getState().isSignedIn;
|
|
71
71
|
|
|
72
72
|
const unsub = useAuthStore.subscribe(
|
|
73
|
-
(state
|
|
74
|
-
async ([isSignedIn]
|
|
73
|
+
(state) => [state.isSignedIn, state.user],
|
|
74
|
+
async ([isSignedIn]) => {
|
|
75
75
|
// Only run when isSignedIn actually changes
|
|
76
76
|
if (isSignedIn === previousIsSignedIn) {
|
|
77
77
|
return;
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
// Client-side only imports
|
|
2
|
+
let firebaseApp: any;
|
|
3
|
+
let firebaseAuth: any;
|
|
4
|
+
|
|
5
|
+
// Dynamic imports for client-side only
|
|
6
|
+
const getFirebaseModules = async () => {
|
|
7
|
+
if (typeof window === 'undefined') {
|
|
8
|
+
throw new Error('Firebase can only be used in client environment');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (!firebaseApp || !firebaseAuth) {
|
|
12
|
+
const [
|
|
13
|
+
{ initializeApp, getApps },
|
|
14
|
+
{
|
|
15
|
+
getAuth,
|
|
16
|
+
signInWithEmailAndPassword,
|
|
17
|
+
createUserWithEmailAndPassword,
|
|
18
|
+
signInWithPopup,
|
|
19
|
+
GoogleAuthProvider,
|
|
20
|
+
signOut,
|
|
21
|
+
sendPasswordResetEmail,
|
|
22
|
+
sendEmailVerification,
|
|
23
|
+
updatePassword,
|
|
24
|
+
onAuthStateChanged,
|
|
25
|
+
}
|
|
26
|
+
] = await Promise.all([
|
|
27
|
+
import("firebase/app"),
|
|
28
|
+
import("firebase/auth")
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
firebaseApp = { initializeApp, getApps };
|
|
32
|
+
firebaseAuth = {
|
|
33
|
+
getAuth,
|
|
34
|
+
signInWithEmailAndPassword,
|
|
35
|
+
createUserWithEmailAndPassword,
|
|
36
|
+
signInWithPopup,
|
|
37
|
+
GoogleAuthProvider,
|
|
38
|
+
signOut,
|
|
39
|
+
sendPasswordResetEmail,
|
|
40
|
+
sendEmailVerification,
|
|
41
|
+
updatePassword,
|
|
42
|
+
onAuthStateChanged,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return { firebaseApp, firebaseAuth };
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
import { AuthService, FirebaseConfig, AuthResponse, UserData, SignInProvider } from "../types";
|
|
50
|
+
import { accessTokenKey, refreshTokenKey } from "../constants";
|
|
51
|
+
|
|
52
|
+
export class FirebaseAuthService implements AuthService {
|
|
53
|
+
private app: any;
|
|
54
|
+
private auth: any;
|
|
55
|
+
private googleProvider: any;
|
|
56
|
+
private config: FirebaseConfig;
|
|
57
|
+
private initialized = false;
|
|
58
|
+
|
|
59
|
+
constructor(config: FirebaseConfig) {
|
|
60
|
+
this.config = config;
|
|
61
|
+
// Initialization will be done lazily in client environment
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private async ensureInitialized() {
|
|
65
|
+
if (this.initialized) return;
|
|
66
|
+
|
|
67
|
+
const { firebaseApp, firebaseAuth } = await getFirebaseModules();
|
|
68
|
+
|
|
69
|
+
// Initialize Firebase app if not already initialized
|
|
70
|
+
if (!firebaseApp.getApps().length) {
|
|
71
|
+
this.app = firebaseApp.initializeApp(this.config);
|
|
72
|
+
} else {
|
|
73
|
+
this.app = firebaseApp.getApps()[0];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
this.auth = firebaseAuth.getAuth(this.app);
|
|
77
|
+
this.googleProvider = new firebaseAuth.GoogleAuthProvider();
|
|
78
|
+
this.initialized = true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private transformUserData(user: any): UserData {
|
|
82
|
+
return {
|
|
83
|
+
id: user.uid,
|
|
84
|
+
uid: user.uid,
|
|
85
|
+
userName: user.displayName || "",
|
|
86
|
+
displayName: user.displayName || "",
|
|
87
|
+
email: user.email || "",
|
|
88
|
+
refreshToken: user.refreshToken,
|
|
89
|
+
accessToken: (user as any).accessToken || "",
|
|
90
|
+
exp: (user as any).stsTokenManager?.expirationTime || 0,
|
|
91
|
+
emailVerified: user.emailVerified,
|
|
92
|
+
avatar: user.photoURL || "/images/default-avatar.jpg",
|
|
93
|
+
signInProvider: this.getSignInProvider(user),
|
|
94
|
+
role: undefined,
|
|
95
|
+
scanStatus: false,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private getSignInProvider(user: any): SignInProvider {
|
|
100
|
+
const providers = user.providerData.map((p: any) => p.providerId);
|
|
101
|
+
if (providers.includes("google.com")) return "google.com";
|
|
102
|
+
return "password";
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private translateErrorCode(errorCode: string): string {
|
|
106
|
+
switch (errorCode) {
|
|
107
|
+
case "auth/invalid-email":
|
|
108
|
+
return "Email không hợp lệ";
|
|
109
|
+
case "auth/user-disabled":
|
|
110
|
+
return "Tài khoản đã bị khóa";
|
|
111
|
+
case "auth/wrong-password":
|
|
112
|
+
return "Tài khoản/mật khẩu không đúng";
|
|
113
|
+
case "auth/user-not-found":
|
|
114
|
+
return "Tài khoản/mật khẩu không đúng";
|
|
115
|
+
case "auth/weak-password":
|
|
116
|
+
return "Weak password! Please use stronger password.";
|
|
117
|
+
case "auth/email-already-in-use":
|
|
118
|
+
return "Email đã được sử dụng";
|
|
119
|
+
case "auth/account-exists-with-different-credential":
|
|
120
|
+
return "Tài khoản email đã được sử dụng bởi một phương thức đăng nhập khác";
|
|
121
|
+
case "auth/email-not-verified":
|
|
122
|
+
return "Email chưa được xác thực";
|
|
123
|
+
default:
|
|
124
|
+
return "Đã có lỗi xảy ra";
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async signInWithEmailAndPassword(email: string, password: string): Promise<AuthResponse> {
|
|
129
|
+
try {
|
|
130
|
+
await this.ensureInitialized();
|
|
131
|
+
const { firebaseAuth } = await getFirebaseModules();
|
|
132
|
+
const signInResponse = await firebaseAuth.signInWithEmailAndPassword(this.auth, email, password);
|
|
133
|
+
const { user } = signInResponse;
|
|
134
|
+
const data = this.transformUserData(user);
|
|
135
|
+
|
|
136
|
+
const { emailVerified } = data;
|
|
137
|
+
if (!emailVerified) {
|
|
138
|
+
await this.signOut();
|
|
139
|
+
localStorage.removeItem("phygital-user-info");
|
|
140
|
+
localStorage.removeItem(accessTokenKey);
|
|
141
|
+
localStorage.removeItem(refreshTokenKey);
|
|
142
|
+
throw new Error("Email is not verified");
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
errorCode: "",
|
|
147
|
+
data,
|
|
148
|
+
};
|
|
149
|
+
} catch (err: any) {
|
|
150
|
+
const errorCode = this.translateErrorCode(err.code);
|
|
151
|
+
return {
|
|
152
|
+
errorCode,
|
|
153
|
+
data: null,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async signInWithGoogle(): Promise<AuthResponse> {
|
|
159
|
+
try {
|
|
160
|
+
await this.ensureInitialized();
|
|
161
|
+
const { firebaseAuth } = await getFirebaseModules();
|
|
162
|
+
const signInResponse = await firebaseAuth.signInWithPopup(this.auth, this.googleProvider);
|
|
163
|
+
const { user } = signInResponse;
|
|
164
|
+
const data = this.transformUserData(user);
|
|
165
|
+
|
|
166
|
+
const { emailVerified } = data;
|
|
167
|
+
if (!emailVerified) {
|
|
168
|
+
await this.signOut();
|
|
169
|
+
throw new Error("Email is not verified");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
errorCode: "",
|
|
174
|
+
data,
|
|
175
|
+
};
|
|
176
|
+
} catch (err: any) {
|
|
177
|
+
const errorCode = this.translateErrorCode(err.code);
|
|
178
|
+
return {
|
|
179
|
+
errorCode,
|
|
180
|
+
data: null,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async signUp(email: string, password: string): Promise<AuthResponse> {
|
|
186
|
+
try {
|
|
187
|
+
await this.ensureInitialized();
|
|
188
|
+
const { firebaseAuth } = await getFirebaseModules();
|
|
189
|
+
const signUpResponse = await firebaseAuth.createUserWithEmailAndPassword(this.auth, email, password);
|
|
190
|
+
const { user } = signUpResponse;
|
|
191
|
+
const data = this.transformUserData(user);
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
errorCode: "",
|
|
195
|
+
data,
|
|
196
|
+
};
|
|
197
|
+
} catch (err: any) {
|
|
198
|
+
const errorCode = this.translateErrorCode(err.code);
|
|
199
|
+
return {
|
|
200
|
+
errorCode,
|
|
201
|
+
data: null,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
async signOut(): Promise<void> {
|
|
207
|
+
try {
|
|
208
|
+
await this.ensureInitialized();
|
|
209
|
+
const { firebaseAuth } = await getFirebaseModules();
|
|
210
|
+
await firebaseAuth.signOut(this.auth);
|
|
211
|
+
// Tracking is now handled through callbacks in the consuming app
|
|
212
|
+
} catch (err) {
|
|
213
|
+
console.log("Firebase signOut error:", err);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
async sendPasswordResetEmail(email: string): Promise<void> {
|
|
218
|
+
await this.ensureInitialized();
|
|
219
|
+
const { firebaseAuth } = await getFirebaseModules();
|
|
220
|
+
const actionCodeSettings = {
|
|
221
|
+
url: window.location.origin,
|
|
222
|
+
handleCodeInApp: true,
|
|
223
|
+
};
|
|
224
|
+
await firebaseAuth.sendPasswordResetEmail(this.auth, email, actionCodeSettings);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
async sendEmailVerification(): Promise<void> {
|
|
228
|
+
await this.ensureInitialized();
|
|
229
|
+
const { firebaseAuth } = await getFirebaseModules();
|
|
230
|
+
if (!this.auth.currentUser) {
|
|
231
|
+
throw new Error("No current user");
|
|
232
|
+
}
|
|
233
|
+
const actionCodeSettings = {
|
|
234
|
+
url: window.location.origin,
|
|
235
|
+
handleCodeInApp: true,
|
|
236
|
+
};
|
|
237
|
+
await firebaseAuth.sendEmailVerification(this.auth.currentUser, actionCodeSettings);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
async changePassword(newPassword: string): Promise<void> {
|
|
241
|
+
await this.ensureInitialized();
|
|
242
|
+
const { firebaseAuth } = await getFirebaseModules();
|
|
243
|
+
const user = this.auth.currentUser;
|
|
244
|
+
if (!user) {
|
|
245
|
+
throw new Error("No current user");
|
|
246
|
+
}
|
|
247
|
+
return firebaseAuth.updatePassword(user, newPassword);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
onAuthStateChanged(callback: (user: UserData | null) => void): () => void {
|
|
251
|
+
// For client-side only usage, ensure initialization before setting up auth state listener
|
|
252
|
+
if (typeof window === 'undefined') {
|
|
253
|
+
return () => { }; // Return empty unsubscriber for server-side
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Set up the listener asynchronously
|
|
257
|
+
let unsubscriber: (() => void) | null = null;
|
|
258
|
+
|
|
259
|
+
this.ensureInitialized().then(async () => {
|
|
260
|
+
const { firebaseAuth } = await getFirebaseModules();
|
|
261
|
+
unsubscriber = firebaseAuth.onAuthStateChanged(this.auth, (user: any) => {
|
|
262
|
+
if (user && user.emailVerified) {
|
|
263
|
+
const userData = this.transformUserData(user);
|
|
264
|
+
callback(userData);
|
|
265
|
+
} else {
|
|
266
|
+
callback(null);
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// Return unsubscriber function
|
|
272
|
+
return () => {
|
|
273
|
+
if (unsubscriber) {
|
|
274
|
+
unsubscriber();
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
getCurrentUser(): UserData | null {
|
|
280
|
+
if (typeof window === 'undefined' || !this.initialized) {
|
|
281
|
+
return null; // Return null for server-side or before initialization
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const user = this.auth.currentUser;
|
|
285
|
+
if (user && user.emailVerified) {
|
|
286
|
+
return this.transformUserData(user);
|
|
287
|
+
}
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { FirebaseAuthService } from "./FirebaseAuthService";
|
|
2
|
+
|
|
3
|
+
interface AuthServiceConfig {
|
|
4
|
+
firebaseConfig: any;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
let authServiceInstance: FirebaseAuthService | null = null;
|
|
8
|
+
|
|
9
|
+
export const createAuthService = (config: AuthServiceConfig): FirebaseAuthService => {
|
|
10
|
+
if (!authServiceInstance) {
|
|
11
|
+
authServiceInstance = new FirebaseAuthService(config.firebaseConfig);
|
|
12
|
+
}
|
|
13
|
+
return authServiceInstance;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const getAuthService = (): FirebaseAuthService | null => {
|
|
17
|
+
return authServiceInstance;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const resetAuthService = (): void => {
|
|
21
|
+
authServiceInstance = null;
|
|
22
|
+
};
|
|
@@ -129,7 +129,7 @@ const initialState: AuthState = {
|
|
|
129
129
|
};
|
|
130
130
|
|
|
131
131
|
// Create the auth store
|
|
132
|
-
export const useAuthStore
|
|
132
|
+
export const useAuthStore = create<AuthStore>()(
|
|
133
133
|
devtools(
|
|
134
134
|
persist(
|
|
135
135
|
subscribeWithSelector(
|
|
@@ -203,14 +203,14 @@ export const useAuthStore :any = create<AuthStore>()(
|
|
|
203
203
|
return response;
|
|
204
204
|
} catch (error: any) {
|
|
205
205
|
// Check if error has code 7 (email not verified)
|
|
206
|
-
if (error?.response?.data?.code === 7) {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
}
|
|
206
|
+
// if (error?.response?.data?.code === 7) {
|
|
207
|
+
// // Return a special response for email verification needed
|
|
208
|
+
// return {
|
|
209
|
+
// data: undefined,
|
|
210
|
+
// message: "Email verification required",
|
|
211
|
+
// code: 7,
|
|
212
|
+
// };
|
|
213
|
+
// }
|
|
214
214
|
|
|
215
215
|
const errorMessage =
|
|
216
216
|
error instanceof Error ? error.message : "Login failed";
|
|
@@ -309,19 +309,18 @@ export const useAuthStore :any = create<AuthStore>()(
|
|
|
309
309
|
state.isSignedIn = false;
|
|
310
310
|
state.error = null;
|
|
311
311
|
});
|
|
312
|
+
|
|
313
|
+
const refreshToken = tokenStorage.getRefreshToken();
|
|
312
314
|
const isTokenExpired = tokenStorage.isTokenExpired();
|
|
313
|
-
|
|
315
|
+
|
|
316
|
+
if (isTokenExpired || !refreshToken) {
|
|
314
317
|
tokenStorage.clearTokens();
|
|
315
|
-
localStorage.clear();
|
|
316
318
|
return;
|
|
317
319
|
}
|
|
318
|
-
const refreshToken = tokenStorage.getRefreshToken();
|
|
319
|
-
if (refreshToken) {
|
|
320
|
-
await authService.logout({ refreshToken });
|
|
321
|
-
}
|
|
322
320
|
|
|
323
|
-
|
|
324
|
-
|
|
321
|
+
await authService.logout({
|
|
322
|
+
refreshToken,
|
|
323
|
+
});
|
|
325
324
|
tokenStorage.clearTokens();
|
|
326
325
|
|
|
327
326
|
// Execute default cleanup functions
|
|
@@ -485,6 +484,14 @@ export const useAuthStore :any = create<AuthStore>()(
|
|
|
485
484
|
refreshToken:
|
|
486
485
|
refreshToken ?? tokenStorage.getRefreshToken() ?? "",
|
|
487
486
|
});
|
|
487
|
+
|
|
488
|
+
if(refreshTokenResponse.data?.idToken && refreshTokenResponse.data?.refreshToken){
|
|
489
|
+
tokenStorage.setTokens({
|
|
490
|
+
idToken: refreshTokenResponse.data?.idToken,
|
|
491
|
+
refreshToken: refreshTokenResponse.data?.refreshToken,
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
|
|
488
495
|
return refreshTokenResponse;
|
|
489
496
|
},
|
|
490
497
|
|
|
@@ -561,12 +568,12 @@ export const useAuthStore :any = create<AuthStore>()(
|
|
|
561
568
|
);
|
|
562
569
|
|
|
563
570
|
export const useAuth = () => {
|
|
564
|
-
const user = useAuthStore((state
|
|
565
|
-
const isSignedIn = useAuthStore((state
|
|
566
|
-
const isInitialized = useAuthStore((state
|
|
567
|
-
const isLoading = useAuthStore((state
|
|
568
|
-
const error = useAuthStore((state
|
|
569
|
-
const actions = useAuthStore((state
|
|
571
|
+
const user = useAuthStore((state) => state.user);
|
|
572
|
+
const isSignedIn = useAuthStore((state) => state.isSignedIn);
|
|
573
|
+
const isInitialized = useAuthStore((state) => state.isInitialized);
|
|
574
|
+
const isLoading = useAuthStore((state) => state.isLoading);
|
|
575
|
+
const error = useAuthStore((state) => state.error);
|
|
576
|
+
const actions = useAuthStore((state) => state.actions);
|
|
570
577
|
|
|
571
578
|
return {
|
|
572
579
|
user,
|
|
@@ -577,4 +584,3 @@ export const useAuth = () => {
|
|
|
577
584
|
...actions,
|
|
578
585
|
};
|
|
579
586
|
};
|
|
580
|
-
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { UserData, UserRole, UserType } from "../types/user-data";
|
|
2
2
|
import { UserModel } from "@phygitallabs/api-core";
|
|
3
|
-
import
|
|
3
|
+
import jwtDecode from "jwt-decode";
|
|
4
4
|
|
|
5
5
|
export const transformProtoUserData = (user: UserModel, accessToken: string): UserData => {
|
|
6
6
|
const userData = { ...user } as UserData;
|
|
@@ -17,5 +17,15 @@ export const transformProtoUserData = (user: UserModel, accessToken: string): Us
|
|
|
17
17
|
userData.roles = tokenDecoded?.roles || [UserRole.USER];
|
|
18
18
|
userData.account_type = tokenDecoded?.account_type || UserType.C;
|
|
19
19
|
userData.picture = user.picture || "";
|
|
20
|
+
|
|
20
21
|
return userData;
|
|
21
22
|
};
|
|
23
|
+
|
|
24
|
+
export const decodeJWTToken = (token: string): any => {
|
|
25
|
+
try {
|
|
26
|
+
return jwtDecode(token);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.warn("Failed to decode token in decodeJWTToken:", error);
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
@@ -47,7 +47,8 @@ function useDataTracking() {
|
|
|
47
47
|
const { setUserId, setMetadata } = useSessionReplay();
|
|
48
48
|
|
|
49
49
|
const trackEvent = (eventName: string, eventData: Record<string, any>, useTools?: ("gtm" | "ga" | "posthog")[]) => {
|
|
50
|
-
|
|
50
|
+
console.log("trackEvent ", eventName, eventData);
|
|
51
|
+
|
|
51
52
|
useTools = useTools || ["gtm"];
|
|
52
53
|
|
|
53
54
|
if (useTools.includes("gtm") && typeof window !== "undefined") {
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
useCreateCertificate,
|
|
6
6
|
useCreateCertificateAnonymous,
|
|
7
7
|
useCreateCertificateWithMask,
|
|
8
|
+
useAddFrame,
|
|
8
9
|
} from "@phygitallabs/generate-certificate";
|
|
9
10
|
|
|
10
11
|
export {
|
|
@@ -14,4 +15,5 @@ export {
|
|
|
14
15
|
useCreateCertificate,
|
|
15
16
|
useCreateCertificateAnonymous,
|
|
16
17
|
useCreateCertificateWithMask,
|
|
18
|
+
useAddFrame,
|
|
17
19
|
};
|
|
@@ -3,11 +3,11 @@ export {
|
|
|
3
3
|
useManyUserRewards,
|
|
4
4
|
useGetUserRewards,
|
|
5
5
|
useClaimUserReward,
|
|
6
|
-
useListRewardModels,
|
|
7
6
|
useGetRewardModel,
|
|
8
7
|
useCreateRewardModel,
|
|
9
8
|
useUpdateRewardModel,
|
|
10
9
|
useDeleteRewardModel,
|
|
10
|
+
useListRewardModels,
|
|
11
11
|
useCreateModelGroupReward,
|
|
12
12
|
useClearUserRewardCache,
|
|
13
13
|
useV1ListRewards
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Define request types locally since they're not exported from reward package
|
|
2
|
-
import { PaginationRequest, GetManyResponse } from "@phygitallabs/api-core
|
|
2
|
+
import { PaginationRequest, GetManyResponse } from "@phygitallabs/api-core";
|
|
3
3
|
import { EntityRewardModel, UserReward } from "./reward";
|
|
4
4
|
|
|
5
5
|
// User Rewards API Requests
|