@rxdrag/website-lib-core 0.0.49 → 0.0.51

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 (41) hide show
  1. package/package.json +10 -9
  2. package/src/astro/README.md +1 -0
  3. package/src/astro/animation.ts +146 -0
  4. package/src/astro/background.ts +53 -0
  5. package/src/astro/grid/consts.ts +80 -0
  6. package/src/astro/grid/index.ts +2 -0
  7. package/src/astro/grid/types.ts +35 -0
  8. package/src/astro/index.ts +7 -0
  9. package/src/astro/media.ts +109 -0
  10. package/src/astro/section/index.ts +12 -0
  11. package/src/entify/Entify.ts +32 -2
  12. package/src/entify/IEntify.ts +30 -6
  13. package/src/entify/lib/createUploadCredentials.ts +56 -0
  14. package/src/entify/lib/index.ts +30 -29
  15. package/src/entify/lib/newQueryProductOptions.ts +1 -0
  16. package/src/entify/lib/queryLangs.ts +5 -5
  17. package/src/entify/lib/queryLatestPosts.ts +9 -1
  18. package/src/entify/lib/queryOneTheme.ts +12 -12
  19. package/src/index.ts +1 -0
  20. package/src/react/components/Analytics/eventHandlers.ts +173 -0
  21. package/src/react/components/Analytics/index.tsx +21 -0
  22. package/src/react/components/Analytics/singleton.ts +214 -0
  23. package/src/react/components/Analytics/tracking.ts +221 -0
  24. package/src/react/components/Analytics/types.ts +60 -0
  25. package/src/react/components/Analytics/utils.ts +95 -0
  26. package/src/react/components/BackgroundHlsVideoPlayer.tsx +68 -0
  27. package/src/react/components/BackgroundVideoPlayer.tsx +32 -0
  28. package/src/react/components/ContactForm/ContactForm.tsx +286 -0
  29. package/src/react/components/ContactForm/FileUpload.tsx +430 -0
  30. package/src/react/components/ContactForm/Input.tsx +6 -10
  31. package/src/react/components/ContactForm/Input2.tsx +64 -0
  32. package/src/react/components/ContactForm/Submit.tsx +25 -10
  33. package/src/react/components/ContactForm/Textarea.tsx +7 -10
  34. package/src/react/components/ContactForm/Textarea2.tsx +64 -0
  35. package/src/react/components/ContactForm/factory.tsx +49 -0
  36. package/src/react/components/ContactForm/funcs.ts +64 -0
  37. package/src/react/components/ContactForm/index.ts +7 -0
  38. package/src/react/components/ContactForm/types.ts +67 -0
  39. package/src/react/components/ContactForm/useVisitorInfo.ts +31 -0
  40. package/src/react/components/index.ts +3 -0
  41. package/src/react/components/ContactForm/index.tsx +0 -351
@@ -1,29 +1,30 @@
1
- export * from "./toQueryOptions";
2
- export * from "./createEntifyClient";
3
- export * from "./newAvatarQueryOptions";
4
- export * from "./newOgImageQueryOptions";
5
- export * from "./newQueryPostOptions";
6
- export * from "./newQueryProductOptions";
7
- export * from "./newQueryProductsMediaOptions";
8
- export * from "./queryEntityList";
9
- export * from "./queryFeaturedProducts";
10
- export * from "./queryLangs";
11
- export * from "./queryLatestPosts";
12
- export * from "./queryOneEntity";
13
- export * from "./queryOnePostById";
14
- export * from "./queryOnePostCategoryBySlug";
15
- export * from "./queryOnePostBySlug";
16
- export * from "./queryOneProductById";
17
- export * from "./queryOneProductBySlug";
18
- export * from "./queryOneProductCategoryBySlug";
19
- export * from "./queryOneUser";
20
- export * from "./queryPostCategories";
21
- export * from "./queryPosts";
22
- export * from "./queryProductCategories";
23
- export * from "./queryProducts";
24
- export * from "./queryProductsInMenu";
25
- export * from "./queryUserPosts";
26
- export * from "./queryWebSiteSettings";
27
- export * from "./upsertEntity";
28
- export * from "./fulltextSearch";
29
- export * from "./sendEmail";
1
+ export * from "./toQueryOptions";
2
+ export * from "./createEntifyClient";
3
+ export * from "./newAvatarQueryOptions";
4
+ export * from "./newOgImageQueryOptions";
5
+ export * from "./newQueryPostOptions";
6
+ export * from "./newQueryProductOptions";
7
+ export * from "./newQueryProductsMediaOptions";
8
+ export * from "./queryEntityList";
9
+ export * from "./queryFeaturedProducts";
10
+ export * from "./queryLangs";
11
+ export * from "./queryLatestPosts";
12
+ export * from "./queryOneEntity";
13
+ export * from "./queryOnePostById";
14
+ export * from "./queryOnePostCategoryBySlug";
15
+ export * from "./queryOnePostBySlug";
16
+ export * from "./queryOneProductById";
17
+ export * from "./queryOneProductBySlug";
18
+ export * from "./queryOneProductCategoryBySlug";
19
+ export * from "./queryOneUser";
20
+ export * from "./queryPostCategories";
21
+ export * from "./queryPosts";
22
+ export * from "./queryProductCategories";
23
+ export * from "./queryProducts";
24
+ export * from "./queryProductsInMenu";
25
+ export * from "./queryUserPosts";
26
+ export * from "./queryWebSiteSettings";
27
+ export * from "./upsertEntity";
28
+ export * from "./fulltextSearch";
29
+ export * from "./sendEmail";
30
+ export * from "./createUploadCredentials";
@@ -66,6 +66,7 @@ export function newQueryProductOptions(imagSize?: TSize) {
66
66
  }).attachment(
67
67
  new MediaQueryOptions([
68
68
  MediaFields.id,
69
+ MediaFields.mediaRef,
69
70
  MediaFields.description,
70
71
  MediaFields.name,
71
72
  MediaFields.extName,
@@ -5,10 +5,10 @@ import {
5
5
  LangOrderBy,
6
6
  LangQueryOptions,
7
7
  LangAssciations,
8
- ThemeQueryOptions,
9
- ThemeFields,
8
+ ThemeBranchQueryOptions,
9
+ ThemeBranchFields,
10
10
  ThemeConfigFields,
11
- ThemeAssciations,
11
+ ThemeBranchAssciations,
12
12
  } from "@rxdrag/rxcms-models";
13
13
  import { ListResult } from "@rxdrag/entify-lib";
14
14
  import { EnvVariables } from "../types";
@@ -34,9 +34,9 @@ export async function queryLangs(envVariables: EnvVariables) {
34
34
  },
35
35
  })
36
36
  .themes(
37
- new ThemeQueryOptions([ThemeFields.id, ThemeFields.name], {
37
+ new ThemeBranchQueryOptions([ThemeBranchFields.id, ThemeBranchFields.name], {
38
38
  where: {
39
- [ThemeAssciations.website]: {
39
+ [ThemeBranchAssciations.website]: {
40
40
  id: {
41
41
  _eq: envVariables.websiteId,
42
42
  },
@@ -10,6 +10,7 @@ import {
10
10
  UserQueryOptions,
11
11
  UserFields,
12
12
  PublishableStatus,
13
+ PostCategoryFields,
13
14
  } from "@rxdrag/rxcms-models";
14
15
  import { queryEntityList } from "./queryEntityList";
15
16
  import { EnvVariables, TSize } from "../types";
@@ -54,10 +55,17 @@ export async function queryLatestPosts(
54
55
  },
55
56
  }
56
57
  )
58
+ .category([
59
+ PostCategoryFields.id,
60
+ PostCategoryFields.slug,
61
+ PostCategoryFields.name,
62
+ ])
57
63
  .cover(
58
64
  new MediaQueryOptions().file([
59
65
  "thumbnail",
60
- `resize(width:${coverSize?.width || 480}, height:${coverSize?.height || 180})`,
66
+ `resize(width:${coverSize?.width || 480}, height:${
67
+ coverSize?.height || 180
68
+ })`,
61
69
  ])
62
70
  )
63
71
  .author(
@@ -1,10 +1,10 @@
1
1
  import {
2
- Theme,
3
- ThemeBoolExp,
4
- ThemeOrderBy,
5
- ThemeDistinctExp,
6
- ThemeQueryOptions,
7
- ThemeFields,
2
+ ThemeBranch,
3
+ ThemeBranchBoolExp,
4
+ ThemeBranchOrderBy,
5
+ ThemeBranchDistinctExp,
6
+ ThemeBranchQueryOptions,
7
+ ThemeBranchFields,
8
8
  ThemeConfigQueryOptions,
9
9
  ThemeConfigFields,
10
10
  MediaQueryOptions,
@@ -15,13 +15,13 @@ import { queryOneEntity } from "./queryOneEntity";
15
15
 
16
16
  export async function queryOneTheme(envVariables: EnvVariables) {
17
17
  return await queryOneEntity<
18
- Theme,
19
- ThemeBoolExp,
20
- ThemeOrderBy,
21
- ThemeDistinctExp
18
+ ThemeBranch,
19
+ ThemeBranchBoolExp,
20
+ ThemeBranchOrderBy,
21
+ ThemeBranchDistinctExp
22
22
  >(
23
- new ThemeQueryOptions(
24
- [ThemeFields.id, ThemeFields.name, ThemeFields.settings],
23
+ new ThemeBranchQueryOptions(
24
+ [ThemeBranchFields.id, ThemeBranchFields.name, ThemeBranchFields.settings],
25
25
  {
26
26
  where: {
27
27
  lang: {
package/src/index.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * from "./astro";
1
2
  export * from "./entify";
2
3
  export * from "./component-logic";
3
4
  export * from "./motion";
@@ -0,0 +1,173 @@
1
+ // Analytics 事件处理函数
2
+ import type { AnalyticsState, PageData } from './types';
3
+ import { trackPageEvent, trackPageVisit } from './tracking';
4
+
5
+ // 页面离开事件处理
6
+ export function createPageLeaveHandler(
7
+ state: AnalyticsState,
8
+ pageData: PageData,
9
+ apiEndpoint: string,
10
+ debugLog: (...args: unknown[]) => void
11
+ ) {
12
+ return function handlePageLeave(eventSource?: string): void {
13
+ // 检查当前页面是否已经被跟踪离开
14
+ if (state.pageLeaveTracked) {
15
+ console.log(`Page leave already tracked, skipping (source: ${eventSource || 'unknown'})`);
16
+ return;
17
+ }
18
+
19
+ // 检查是否有页面访问记录,如果从来没有跟踪过任何页面则不发送离开事件
20
+ if (state.lastTrackTime === 0) {
21
+ console.log(`No page visit ever tracked, skipping page leave (source: ${eventSource || 'unknown'})`);
22
+ return;
23
+ }
24
+
25
+ console.log(`Page leaving, tracking pageLeave event (source: ${eventSource || 'unknown'})`);
26
+ state.pageLeaveTracked = true;
27
+ trackPageEvent("pageLeave", pageData, state, apiEndpoint, debugLog);
28
+ };
29
+ }
30
+
31
+ // Astro before-swap 事件处理
32
+ export function createAstroBeforeSwapHandler(
33
+ handlePageLeave: (eventSource?: string) => void
34
+ ) {
35
+ return function handleAstroBeforeSwap(): void {
36
+ console.log("astro:before-swap triggered - page leaving");
37
+ handlePageLeave('astro:before-swap');
38
+ };
39
+ }
40
+
41
+ // Astro after-swap 事件处理
42
+ export function createAstroAfterSwapHandler(
43
+ state: AnalyticsState,
44
+ pageData: PageData,
45
+ apiEndpoint: string,
46
+ debugLog: (...args: unknown[]) => void
47
+ ) {
48
+ return function handleAstroAfterSwap(): void {
49
+ console.log("astro:after-swap triggered");
50
+ state.isAstroEnvironment = true;
51
+
52
+ // 直接处理页面切换,不依赖 resetPageTracking
53
+ const newUrl = window.location.href;
54
+ if (newUrl !== state.currentPageUrl) {
55
+ console.log(
56
+ "URL changed in astro:after-swap from",
57
+ state.currentPageUrl,
58
+ "to",
59
+ newUrl
60
+ );
61
+
62
+ // 更新 referrer:页面切换时,referrer 是上一个页面
63
+ state.currentReferrer = state.currentPageUrl;
64
+ debugLog("Updated referrer to:", state.currentReferrer);
65
+
66
+ // 更新页面数据
67
+ // 更新页面状态
68
+ state.currentPageUrl = newUrl;
69
+ pageData.url = newUrl;
70
+ pageData.path = window.location.pathname;
71
+ pageData.start_time = Date.now();
72
+ state.pageLoadTime = Date.now();
73
+ state.isPageTracked = false; // 重置跟踪状态
74
+ // 注意:不重置 pageLeaveTracked,让它保持当前状态,避免影响离开事件
75
+ // 重置活跃时间追踪
76
+ state.activeTime = 0;
77
+ state.lastActiveTime = Date.now();
78
+ state.isPageVisible = !document.hidden;
79
+
80
+ // 直接发送统计
81
+ trackPageVisit(pageData, state, apiEndpoint, debugLog);
82
+
83
+ // 新页面开始跟踪后,重置页面离开状态,为下次离开做准备
84
+ state.pageLeaveTracked = false;
85
+
86
+ // 标记初始加载已处理,防止后续的初始加载事件重复处理
87
+ state.initialLoadHandled = true;
88
+ }
89
+ };
90
+ }
91
+
92
+ // 初始加载事件处理
93
+ export function createInitialLoadHandler(
94
+ state: AnalyticsState,
95
+ pageData: PageData,
96
+ apiEndpoint: string,
97
+ debugLog: (...args: unknown[]) => void
98
+ ) {
99
+ return function handleInitialLoad(eventType: string): void {
100
+ console.log(
101
+ eventType + " triggered, isAstroEnvironment:",
102
+ state.isAstroEnvironment,
103
+ "initialLoadHandled:",
104
+ state.initialLoadHandled,
105
+ "isPageTracked:",
106
+ state.isPageTracked
107
+ );
108
+
109
+ // 如果初始加载已经处理过,跳过(可能是 astro:after-swap 已经处理了)
110
+ if (state.initialLoadHandled) {
111
+ console.log(`Skipping initial load - already handled (${eventType})`);
112
+ return;
113
+ }
114
+
115
+ // 如果页面已经被跟踪(可能是 astro:after-swap 已经处理了),跳过
116
+ if (state.isPageTracked) {
117
+ console.log(`Skipping initial load - page already tracked (${eventType})`);
118
+ return;
119
+ }
120
+
121
+ // 页面刷新或直接访问时,确保统计
122
+ state.initialLoadHandled = true;
123
+ console.log("Handling initial page load via", eventType);
124
+ trackPageVisit(pageData, state, apiEndpoint, debugLog);
125
+ };
126
+ }
127
+
128
+ // 页面可见性变化事件处理
129
+ export function createVisibilityChangeHandler(state: AnalyticsState) {
130
+ return function handleVisibilityChange(): void {
131
+ const now = Date.now();
132
+
133
+ if (document.visibilityState === "visible") {
134
+ // 页面变为可见
135
+ console.log("Page became visible");
136
+ state.isPageVisible = true;
137
+ state.lastActiveTime = now;
138
+ } else {
139
+ // 页面变为隐藏
140
+ console.log("Page became hidden");
141
+ if (state.isPageVisible) {
142
+ // 更新活跃时间到隐藏前
143
+ state.activeTime += now - state.lastActiveTime;
144
+ console.log("Updated active time:", state.activeTime, "ms");
145
+ }
146
+ state.isPageVisible = false;
147
+ }
148
+ };
149
+ }
150
+
151
+ // 用户交互事件处理
152
+ export function createUserInteractionHandler(state: AnalyticsState) {
153
+ return function handleUserInteraction(): void {
154
+ if (!state.isPageVisible || state.interactionThrottled) return;
155
+
156
+ const now = Date.now();
157
+ // 节流:最多每秒检查一次
158
+ if (now - state.lastInteractionTime < 1000) return;
159
+
160
+ state.lastInteractionTime = now;
161
+ state.interactionThrottled = true;
162
+
163
+ // 如果超过30秒没有交互,重置活跃时间计算
164
+ if (now - state.lastActiveTime > 30000) {
165
+ state.lastActiveTime = now;
166
+ }
167
+
168
+ // 解除节流
169
+ setTimeout(() => {
170
+ state.interactionThrottled = false;
171
+ }, 1000);
172
+ };
173
+ }
@@ -0,0 +1,21 @@
1
+ import { useEffect } from 'react';
2
+ import type { AnalyticsProps } from './types';
3
+ import AnalyticsSingleton from './singleton';
4
+
5
+ export function Analytics({
6
+ apiEndpoint = "/api/track-visitor"
7
+ }: AnalyticsProps) {
8
+ useEffect(() => {
9
+ // 获取单例实例并初始化
10
+ const analytics = AnalyticsSingleton.getInstance(apiEndpoint);
11
+ analytics.init();
12
+
13
+ // 组件卸载时不清理单例,让它继续工作
14
+ return () => {
15
+ // 不做任何清理,让单例继续工作
16
+ };
17
+ }, [apiEndpoint]);
18
+
19
+ // 组件不渲染任何可见内容
20
+ return null;
21
+ }
@@ -0,0 +1,214 @@
1
+ // Analytics 单例管理器
2
+ import type { AnalyticsState, PageData } from './types';
3
+ import {
4
+ createDebugLogger,
5
+ generateId,
6
+ getVisitorId
7
+ } from './utils';
8
+ import { trackPageEvent } from './tracking';
9
+
10
+ class AnalyticsSingleton {
11
+ private static instance: AnalyticsSingleton | null = null;
12
+ private initialized = false;
13
+ private state: AnalyticsState;
14
+ private pageData: PageData;
15
+ private apiEndpoint: string;
16
+ private debugLog: (...args: any[]) => void;
17
+ private eventHandlers: Array<() => void> = [];
18
+
19
+ private constructor(apiEndpoint: string) {
20
+ this.apiEndpoint = apiEndpoint;
21
+ this.debugLog = createDebugLogger();
22
+
23
+ // 初始化访客和会话信息
24
+ const visitorId = getVisitorId();
25
+ let sessionId = sessionStorage.getItem('session_id');
26
+ if (!sessionId) {
27
+ sessionId = generateId('s');
28
+ sessionStorage.setItem('session_id', sessionId);
29
+ }
30
+
31
+ // 页面信息
32
+ this.pageData = {
33
+ visitor_id: visitorId,
34
+ session_id: sessionId,
35
+ url: window.location.href,
36
+ path: window.location.pathname,
37
+ referrer: document.referrer || null,
38
+ user_agent: navigator.userAgent,
39
+ start_time: Date.now(),
40
+ };
41
+
42
+ // 状态管理
43
+ this.state = {
44
+ isPageTracked: false,
45
+ currentPageUrl: window.location.href,
46
+ pageLoadTime: Date.now(),
47
+ lastTrackTime: 0,
48
+ currentReferrer: document.referrer || null,
49
+ activeTime: 0,
50
+ lastActiveTime: Date.now(),
51
+ isPageVisible: !document.hidden,
52
+ requestQueue: [],
53
+ isRequestPending: false,
54
+ isAstroEnvironment: false,
55
+ pageLeaveTracked: false,
56
+ initialLoadHandled: false,
57
+ interactionThrottled: false,
58
+ lastInteractionTime: 0,
59
+ };
60
+
61
+ }
62
+
63
+ static getInstance(apiEndpoint = "/api/track-visitor"): AnalyticsSingleton {
64
+ if (!AnalyticsSingleton.instance) {
65
+ AnalyticsSingleton.instance = new AnalyticsSingleton(apiEndpoint);
66
+ }
67
+ return AnalyticsSingleton.instance;
68
+ }
69
+
70
+ static reset(): void {
71
+ if (AnalyticsSingleton.instance) {
72
+ AnalyticsSingleton.instance.cleanup();
73
+ AnalyticsSingleton.instance = null;
74
+ }
75
+ }
76
+
77
+ init(): void {
78
+ if (this.initialized) {
79
+ return;
80
+ }
81
+
82
+ this.initialized = true;
83
+ this.setupEventListeners();
84
+ this.handleInitialPageLoad();
85
+ }
86
+
87
+ private setupEventListeners(): void {
88
+ // 页面离开事件
89
+ const handlePageLeave = () => {
90
+ if (this.state.pageLeaveTracked || this.state.lastTrackTime === 0) {
91
+ return;
92
+ }
93
+
94
+ this.state.pageLeaveTracked = true;
95
+ trackPageEvent("pageLeave", this.pageData, this.state, this.apiEndpoint, this.debugLog);
96
+ };
97
+
98
+ // 页面离开事件监听器
99
+ const handleBeforeUnload = () => handlePageLeave();
100
+ const handlePageHide = () => handlePageLeave();
101
+
102
+ window.addEventListener('beforeunload', handleBeforeUnload);
103
+ window.addEventListener('pagehide', handlePageHide);
104
+
105
+ // Astro 事件监听
106
+ const handleAstroBeforeSwap = () => {
107
+ handlePageLeave();
108
+ };
109
+
110
+ const handleAstroAfterSwap = () => {
111
+ this.state.isAstroEnvironment = true;
112
+
113
+ const newUrl = window.location.href;
114
+ if (newUrl !== this.state.currentPageUrl) {
115
+ // 更新 referrer:页面切换时,referrer 是上一个页面
116
+ this.state.currentReferrer = this.state.currentPageUrl;
117
+
118
+ // 更新页面状态
119
+ this.state.currentPageUrl = newUrl;
120
+ this.pageData.url = newUrl;
121
+ this.pageData.path = window.location.pathname;
122
+ this.pageData.start_time = Date.now();
123
+ this.state.pageLoadTime = Date.now();
124
+ this.state.isPageTracked = false;
125
+ this.state.pageLeaveTracked = false;
126
+ this.state.activeTime = 0;
127
+ this.state.lastActiveTime = Date.now();
128
+ this.state.isPageVisible = !document.hidden;
129
+
130
+ // 发送新页面统计
131
+ this.trackPageVisit();
132
+ }
133
+ };
134
+
135
+ document.addEventListener('astro:before-swap', handleAstroBeforeSwap);
136
+ document.addEventListener('astro:after-swap', handleAstroAfterSwap);
137
+
138
+ // 页面可见性变化
139
+ const handleVisibilityChange = () => {
140
+ const now = Date.now();
141
+ if (document.visibilityState === 'visible') {
142
+ this.state.isPageVisible = true;
143
+ this.state.lastActiveTime = now;
144
+ } else {
145
+ if (this.state.isPageVisible) {
146
+ this.state.activeTime += now - this.state.lastActiveTime;
147
+ }
148
+ this.state.isPageVisible = false;
149
+ }
150
+ };
151
+
152
+ document.addEventListener('visibilitychange', handleVisibilityChange);
153
+
154
+ // 用户交互事件
155
+ const handleUserInteraction = () => {
156
+ if (!this.state.isPageVisible || this.state.interactionThrottled) return;
157
+
158
+ const now = Date.now();
159
+ if (now - this.state.lastInteractionTime < 1000) return;
160
+
161
+ this.state.lastInteractionTime = now;
162
+ this.state.interactionThrottled = true;
163
+
164
+ if (now - this.state.lastActiveTime > 30000) {
165
+ this.state.lastActiveTime = now;
166
+ }
167
+
168
+ setTimeout(() => {
169
+ this.state.interactionThrottled = false;
170
+ }, 1000);
171
+ };
172
+
173
+ const interactionEvents = ['click', 'keydown', 'scroll'];
174
+ interactionEvents.forEach((event) => {
175
+ document.addEventListener(event, handleUserInteraction, {
176
+ passive: true,
177
+ capture: false,
178
+ });
179
+ });
180
+
181
+ // 保存事件处理器引用,用于清理
182
+ this.eventHandlers = [
183
+ () => window.removeEventListener('beforeunload', handleBeforeUnload),
184
+ () => window.removeEventListener('pagehide', handlePageHide),
185
+ () => document.removeEventListener('astro:before-swap', handleAstroBeforeSwap),
186
+ () => document.removeEventListener('astro:after-swap', handleAstroAfterSwap),
187
+ () => document.removeEventListener('visibilitychange', handleVisibilityChange),
188
+ ...interactionEvents.map(event =>
189
+ () => document.removeEventListener(event, handleUserInteraction)
190
+ )
191
+ ];
192
+ }
193
+
194
+ private handleInitialPageLoad(): void {
195
+ if (this.state.isPageTracked || this.state.initialLoadHandled) {
196
+ return;
197
+ }
198
+
199
+ this.state.initialLoadHandled = true;
200
+ this.trackPageVisit();
201
+ }
202
+
203
+ private trackPageVisit(): void {
204
+ trackPageEvent("pageView", this.pageData, this.state, this.apiEndpoint, this.debugLog);
205
+ }
206
+
207
+ cleanup(): void {
208
+ this.eventHandlers.forEach(cleanup => cleanup());
209
+ this.eventHandlers = [];
210
+ this.initialized = false;
211
+ }
212
+ }
213
+
214
+ export default AnalyticsSingleton;