@phygitallabs/tapquest-core 6.7.9 → 6.7.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phygitallabs/tapquest-core",
3
- "version": "6.7.9",
3
+ "version": "6.7.10",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -9,9 +9,12 @@ type GtagConsent = (
9
9
  params: Record<string, string>
10
10
  ) => void;
11
11
 
12
+ /** Consent Mode v2: block analytics and ad tags until user accepts. */
12
13
  const GTAG_CONSENT_DENIED = {
13
14
  analytics_storage: "denied",
14
15
  ad_storage: "denied",
16
+ ad_user_data: "denied",
17
+ ad_personalization: "denied",
15
18
  } as const;
16
19
 
17
20
  const GTAG_CONSENT_GRANTED_ANALYTICS = {
@@ -19,13 +22,18 @@ const GTAG_CONSENT_GRANTED_ANALYTICS = {
19
22
  } as const;
20
23
 
21
24
  /**
22
- * Sets gtag consent default to denied on mount and updates to granted
25
+ * Sets gtag/GTM consent default to denied on mount and updates to granted
23
26
  * when user has accepted analytics (must be under PhygitalConsentProvider).
27
+ *
28
+ * When using GTM: add the script from getGtmConsentDefaultSnippet() in your
29
+ * HTML before the GTM container script (gtm.js) so consent is denied before
30
+ * any tags run. This component then pushes consent update when the user accepts.
24
31
  * Renders nothing.
25
32
  */
26
33
  export function GtagConsentSync() {
27
34
  const consent = usePhygitalConsent();
28
- const isAnalyticsAllowed = (consent as { isAnalyticsAllowed?: boolean }).isAnalyticsAllowed ?? false;
35
+ const isAnalyticsAllowed =
36
+ (consent as { isAnalyticsAllowed?: boolean }).isAnalyticsAllowed ?? false;
29
37
 
30
38
  useEffect(() => {
31
39
  if (typeof window === "undefined") return;
@@ -3,93 +3,95 @@ import posthog from "posthog-js";
3
3
  import { useSessionReplay } from "../../../modules/session-replay";
4
4
 
5
5
  declare global {
6
- interface Window {
7
- dataLayer: unknown[];
8
- }
6
+ interface Window {
7
+ dataLayer: unknown[];
8
+ }
9
9
  }
10
10
 
11
11
  declare function gtag(
12
- command: "event",
13
- eventName: string,
14
- eventParameters: Record<string, any>
12
+ command: "event",
13
+ eventName: string,
14
+ eventParameters: Record<string, any>
15
15
  ): void;
16
16
 
17
-
18
17
  // GTM
19
18
  const pushEventToDataLayer = (event: string, data: Record<string, any>) => {
20
- try {
21
- window.dataLayer = window.dataLayer || [];
22
-
23
- (window.dataLayer as Record<string, unknown>[]).push({
24
- event,
25
- ...data,
26
- });
27
-
28
- } catch (error) {
29
- console.error(error);
30
- }
19
+ try {
20
+ window.dataLayer = window.dataLayer || [];
21
+
22
+ (window.dataLayer as Record<string, unknown>[]).push({
23
+ event,
24
+ ...data,
25
+ });
26
+ } catch (error) {
27
+ console.error(error);
28
+ }
31
29
  };
32
30
 
33
31
  // GA
34
32
  const pushEventToGA = (eventName: string, eventData: Record<string, any>) => {
35
- if (typeof gtag != "function") {
36
- console.error("gtag is not a function");
37
- return;
38
- }
39
- gtag("event", eventName, eventData);
33
+ if (typeof gtag != "function") {
34
+ console.error("gtag is not a function");
35
+ return;
36
+ }
37
+ gtag("event", eventName, eventData);
40
38
  };
41
39
 
42
40
  // Posthog
43
41
  const pushEventToPosthog = (eventName: string, eventData: Record<string, any>) => {
44
- posthog.capture(eventName, eventData);
42
+ posthog.capture(eventName, eventData);
45
43
  };
46
44
 
47
45
  function useDataTracking() {
48
- const { setUserId, setMetadata } = useSessionReplay();
49
- const consent = usePhygitalConsent();
50
- const isAnalyticsAllowed = (consent as { isAnalyticsAllowed?: boolean }).isAnalyticsAllowed ?? false;
51
-
52
- const trackEvent = (eventName: string, eventData: Record<string, any>, useTools?: ("gtm" | "ga" | "posthog")[]) => {
53
- console.log("trackEvent ", eventName, eventData);
54
-
55
- useTools = useTools || ["gtm"];
56
-
57
- if (useTools.includes("gtm") && typeof window !== "undefined") {
58
- pushEventToDataLayer(eventName, eventData);
59
- }
60
- if (useTools.includes("ga") && isAnalyticsAllowed && typeof gtag == "function") {
61
- pushEventToGA(eventName, eventData);
62
- }
63
- if (useTools.includes("posthog") && typeof posthog == "function") {
64
- pushEventToPosthog(eventName, eventData);
65
- }
66
- };
67
-
68
- const trackUserIdentify = (userInfo: Record<string, any>) => {
69
- posthog.identify(userInfo.email, {
70
- email: userInfo.email,
71
- name: userInfo.name,
72
- avatar: userInfo.avatar,
73
- uid: userInfo.uid,
74
- });
75
-
76
- setUserId(userInfo.id);
77
-
78
- setMetadata({
79
- user_email: userInfo.email
80
- })
81
- }
46
+ const { setUserId, setMetadata } = useSessionReplay();
47
+ const consent = usePhygitalConsent();
48
+ const isAnalyticsAllowed =
49
+ (consent as { isAnalyticsAllowed?: boolean }).isAnalyticsAllowed ?? false;
82
50
 
83
- const trackLogoutEvent = () => {
84
- posthog.capture("user_signed_out");
85
- }
51
+ const trackEvent = (
52
+ eventName: string,
53
+ eventData: Record<string, any>,
54
+ useTools?: ("gtm" | "ga" | "posthog")[]
55
+ ) => {
56
+ console.log("trackEvent ", eventName, eventData);
86
57
 
87
- return {
88
- trackEvent,
89
- trackUserIdentify,
90
- trackLogoutEvent
91
- };
58
+ useTools = useTools || ["gtm"];
59
+
60
+ if (useTools.includes("gtm") && typeof window !== "undefined") {
61
+ pushEventToDataLayer(eventName, eventData);
62
+ }
63
+ if (useTools.includes("ga") && isAnalyticsAllowed && typeof gtag == "function") {
64
+ pushEventToGA(eventName, eventData);
65
+ }
66
+ if (useTools.includes("posthog") && typeof posthog == "function") {
67
+ pushEventToPosthog(eventName, eventData);
68
+ }
69
+ };
70
+
71
+ const trackUserIdentify = (userInfo: Record<string, any>) => {
72
+ posthog.identify(userInfo.email, {
73
+ email: userInfo.email,
74
+ name: userInfo.name,
75
+ avatar: userInfo.avatar,
76
+ uid: userInfo.uid,
77
+ });
78
+
79
+ setUserId(userInfo.id);
80
+
81
+ setMetadata({
82
+ user_email: userInfo.email,
83
+ });
84
+ };
85
+
86
+ const trackLogoutEvent = () => {
87
+ posthog.capture("user_signed_out");
88
+ };
89
+
90
+ return {
91
+ trackEvent,
92
+ trackUserIdentify,
93
+ trackLogoutEvent,
94
+ };
92
95
  }
93
96
 
94
97
  export { useDataTracking };
95
-
@@ -1,2 +1,2 @@
1
1
  export * from "./GtagConsentSync";
2
- export * from "./hooks";
2
+ export * from "./hooks";
@@ -21,143 +21,142 @@ import { tokenStorage } from "@phygitallabs/authentication";
21
21
  import axios from "axios";
22
22
 
23
23
  interface ServicesProviderProps {
24
- children: React.ReactNode;
25
- queryClient: QueryClient;
26
- apiConfig: APIConfig;
27
- firebaseConfig?: any;
24
+ children: React.ReactNode;
25
+ queryClient: QueryClient;
26
+ apiConfig: APIConfig;
27
+ firebaseConfig?: any;
28
28
  }
29
29
 
30
30
  export const ServicesProvider: React.FC<ServicesProviderProps> = ({
31
- children,
32
- queryClient,
33
- apiConfig = {
34
- environment: "dev",
35
- version: "v1"
36
- },
31
+ children,
32
+ queryClient,
33
+ apiConfig = {
34
+ environment: "dev",
35
+ version: "v1",
36
+ },
37
37
  }) => {
38
- const { signOut, refreshToken } = useAuth();
39
- const { environment, version } = apiConfig;
40
- const [commonServiceConfig, setCommonServiceConfig] = useState<ServiceConfig | null>(null);
41
-
42
- const [deviceUid, setDeviceUid] = useState<string>("");
43
-
44
- useEffect(() => {
45
- const initDeviceUid = async () => {
46
- const deviceUid = await checkDeviceUid();
47
- setDeviceUid(deviceUid);
48
- }
49
- initDeviceUid();
50
- }, []);
51
-
52
- // Init client
53
- useEffect(() => {
54
- const initClient = async () => {
55
- try {
56
- const deviceUid = await checkDeviceUid();
57
-
58
- const responseInterceptors = ({
59
- onFulfilled: (response: any) => response,
60
- onRejected: async (error: any) => {
61
- const originalRequest = error.config;
62
- const token = tokenStorage.getAuthToken();
63
-
64
- if (error.response?.status === 401 && !originalRequest._retry) {
65
- const retryAttempts = parseInt(getFromLS(retryAttemptsRefreshToken) || "0", 10);
66
- if (retryAttempts >= httpMaxRetries) {
67
- await signOut();
68
- setToLS(retryAttemptsRefreshToken, 0);
69
- return Promise.reject(error);
70
- }
71
-
72
- setToLS(retryAttemptsRefreshToken, `${retryAttempts + 1}`);
73
- originalRequest._retry = true;
74
-
75
- if (token) {
76
- try {
77
- const result = await refreshToken();
78
- if (result?.data?.idToken) {
79
- originalRequest.headers.Authorization = `Bearer ${result?.data?.idToken}`;
80
- return axios(originalRequest);
81
- }
82
- } catch (refreshError) {
83
- console.error("Failed to refresh token:", refreshError);
84
- await signOut();
85
- return Promise.reject(refreshError);
86
- }
87
- }
88
- }
89
- }
90
- })
91
-
92
- const requestInterceptors = ({
93
- onFulfilled: (config: any) => config,
94
- onRejected: (error: any) => Promise.reject(error),
95
- })
96
-
97
- const axiosConfig = {
98
- headers: {
99
- "Content-Type": "application/json",
100
- "Device-UID": deviceUid,
101
- }
38
+ const { signOut, refreshToken } = useAuth();
39
+ const { environment, version } = apiConfig;
40
+ const [commonServiceConfig, setCommonServiceConfig] = useState<ServiceConfig | null>(null);
41
+
42
+ const [deviceUid, setDeviceUid] = useState<string>("");
43
+
44
+ useEffect(() => {
45
+ const initDeviceUid = async () => {
46
+ const deviceUid = await checkDeviceUid();
47
+ setDeviceUid(deviceUid);
48
+ };
49
+ initDeviceUid();
50
+ }, []);
51
+
52
+ // Init client
53
+ useEffect(() => {
54
+ const initClient = async () => {
55
+ try {
56
+ const deviceUid = await checkDeviceUid();
57
+
58
+ const responseInterceptors = {
59
+ onFulfilled: (response: any) => response,
60
+ onRejected: async (error: any) => {
61
+ const originalRequest = error.config;
62
+ const token = tokenStorage.getAuthToken();
63
+
64
+ if (error.response?.status === 401 && !originalRequest._retry) {
65
+ const retryAttempts = parseInt(getFromLS(retryAttemptsRefreshToken) || "0", 10);
66
+ if (retryAttempts >= httpMaxRetries) {
67
+ await signOut();
68
+ setToLS(retryAttemptsRefreshToken, 0);
69
+ return Promise.reject(error);
70
+ }
71
+
72
+ setToLS(retryAttemptsRefreshToken, `${retryAttempts + 1}`);
73
+ originalRequest._retry = true;
74
+
75
+ if (token) {
76
+ try {
77
+ const result = await refreshToken();
78
+ if (result?.data?.idToken) {
79
+ originalRequest.headers.Authorization = `Bearer ${result?.data?.idToken}`;
80
+ return axios(originalRequest);
81
+ }
82
+ } catch (refreshError) {
83
+ console.error("Failed to refresh token:", refreshError);
84
+ await signOut();
85
+ return Promise.reject(refreshError);
102
86
  }
103
-
104
- const config: ServiceConfig = {
105
- queryClient,
106
- axiosConfig,
107
- responseInterceptors,
108
- requestInterceptors,
109
- useDevTool: true,
110
- };
111
-
112
- setCommonServiceConfig(config);
113
-
114
- } catch (error) {
115
- console.error(error);
87
+ }
116
88
  }
117
- }
118
-
119
- initClient();
120
- }, [queryClient]);
121
-
122
- if (!commonServiceConfig) {
123
- return <></>
124
- }
125
-
126
- return (
127
- <PGLCoreServiceProvider
128
- {...commonServiceConfig}
129
- baseURL={`${serviceApiUrl[environment].API_BASE_URL}/${version}`}
130
- baseCoreURL={`${serviceApiUrl[environment].API_BASE_CORE_URL}/${version}`}
89
+ },
90
+ };
91
+
92
+ const requestInterceptors = {
93
+ onFulfilled: (config: any) => config,
94
+ onRejected: (error: any) => Promise.reject(error),
95
+ };
96
+
97
+ const axiosConfig = {
98
+ headers: {
99
+ "Content-Type": "application/json",
100
+ "Device-UID": deviceUid,
101
+ },
102
+ };
103
+
104
+ const config: ServiceConfig = {
105
+ queryClient,
106
+ axiosConfig,
107
+ responseInterceptors,
108
+ requestInterceptors,
109
+ useDevTool: true,
110
+ };
111
+
112
+ setCommonServiceConfig(config);
113
+ } catch (error) {
114
+ console.error(error);
115
+ }
116
+ };
117
+
118
+ initClient();
119
+ }, [queryClient]);
120
+
121
+ if (!commonServiceConfig) {
122
+ return <></>;
123
+ }
124
+
125
+ return (
126
+ <PGLCoreServiceProvider
127
+ {...commonServiceConfig}
128
+ baseURL={`${serviceApiUrl[environment].API_BASE_URL}/${version}`}
129
+ baseCoreURL={`${serviceApiUrl[environment].API_BASE_CORE_URL}/${version}`}
130
+ >
131
+ <RewardServiceProvider
132
+ {...commonServiceConfig}
133
+ // baseURL={`${serviceApiUrl[environment].API_REWARD_URL}/${version}`}
134
+ baseURL={`${serviceApiUrl[environment].API_REWARD_URL}/v1`} // todo: using v1 until backend fully migrate
135
+ >
136
+ <AchievementServiceProvider
137
+ {...commonServiceConfig}
138
+ baseURL={`${serviceApiUrl[environment].API_ACHIEVEMENT_URL}/${version}`}
131
139
  >
132
- <RewardServiceProvider
133
- {...commonServiceConfig}
134
- // baseURL={`${serviceApiUrl[environment].API_REWARD_URL}/${version}`}
135
- baseURL={`${serviceApiUrl[environment].API_REWARD_URL}/v1`} // todo: using v1 until backend fully migrate
140
+ <GenerateCertificateServiceProvider
141
+ {...commonServiceConfig}
142
+ baseURL={`${serviceApiUrl[environment].API_GENERATE_CERTIFICATE_URL}/v1`}
143
+ >
144
+ <PhygitalConsentProvider
145
+ {...commonServiceConfig}
146
+ deviceId={deviceUid}
147
+ baseURL={`${serviceApiUrl[environment].API_CONSENT_URL}/v1`}
148
+ axiosConfig={{
149
+ headers: {
150
+ "Content-Type": "application/json",
151
+ },
152
+ }}
136
153
  >
137
- <AchievementServiceProvider
138
- {...commonServiceConfig}
139
- baseURL={`${serviceApiUrl[environment].API_ACHIEVEMENT_URL}/${version}`}
140
- >
141
- <GenerateCertificateServiceProvider
142
- {...commonServiceConfig}
143
- baseURL={`${serviceApiUrl[environment].API_GENERATE_CERTIFICATE_URL}/v1`}
144
- >
145
- <PhygitalConsentProvider
146
- {...commonServiceConfig}
147
- deviceId={deviceUid}
148
- baseURL={`${serviceApiUrl[environment].API_CONSENT_URL}/v1`}
149
- axiosConfig={{
150
- headers: {
151
- "Content-Type": "application/json",
152
- }
153
- }}
154
- >
155
- <GtagConsentSync />
156
- {children}
157
- </PhygitalConsentProvider>
158
- </GenerateCertificateServiceProvider>
159
- </AchievementServiceProvider>
160
- </RewardServiceProvider>
161
- </PGLCoreServiceProvider>
162
- );
163
- };
154
+ <GtagConsentSync />
155
+ {children}
156
+ </PhygitalConsentProvider>
157
+ </GenerateCertificateServiceProvider>
158
+ </AchievementServiceProvider>
159
+ </RewardServiceProvider>
160
+ </PGLCoreServiceProvider>
161
+ );
162
+ };