@bikdotai/bik-widgets 1.0.0 → 1.0.2

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 (207) hide show
  1. package/dist-package/index.css +95 -0
  2. package/dist-package/index.js +2 -0
  3. package/package.json +17 -4
  4. package/.eslintrc +0 -22
  5. package/.eslintrc.js +0 -19
  6. package/.github/workflows/main.yml +0 -293
  7. package/.prettierignore +0 -13
  8. package/.prettierrc +0 -10
  9. package/cypress/apiHelper/endpoints.ts +0 -21
  10. package/cypress/apiHelper/executor.ts +0 -42
  11. package/cypress/e2e/bottomDrawer.cy.ts +0 -49
  12. package/cypress/e2e/directReward.cy.ts +0 -67
  13. package/cypress/e2e/scratchTheCard.cy.ts +0 -68
  14. package/cypress/e2e/stw.cy.ts +0 -82
  15. package/cypress/e2e/waRedirection.cy.ts +0 -46
  16. package/cypress/fixtures/payloads.ts +0 -330
  17. package/cypress/support/commands.ts +0 -37
  18. package/cypress/support/e2e.ts +0 -20
  19. package/cypress.staging.config.ts +0 -23
  20. package/jsconfig.json +0 -6
  21. package/localtest.sh +0 -10
  22. package/log-server.js +0 -86
  23. package/postcss.config.js +0 -8
  24. package/src/Globals.d.ts +0 -2
  25. package/src/assets/lottie/santa.json +0 -11722
  26. package/src/assets/svg/CalendarClockIcon.tsx +0 -30
  27. package/src/assets/svg/CalendarIcon.tsx +0 -24
  28. package/src/assets/svg/CheckIcon.tsx +0 -17
  29. package/src/assets/svg/ChevronIcon.tsx +0 -21
  30. package/src/assets/svg/Close.tsx +0 -39
  31. package/src/assets/svg/Confetti.tsx +0 -140
  32. package/src/assets/svg/Copy.tsx +0 -26
  33. package/src/assets/svg/DropdownCheckIcon.tsx +0 -35
  34. package/src/assets/svg/ErrorIcon.tsx +0 -27
  35. package/src/assets/svg/RadioIcon.tsx +0 -25
  36. package/src/assets/svg/UncheckedCheckboxIcon.tsx +0 -28
  37. package/src/assets/svg/UncheckedRadioIcon.tsx +0 -26
  38. package/src/assets/svg/info.tsx +0 -30
  39. package/src/assets/svg/qrcode.svg +0 -14
  40. package/src/bootstrap.tsx +0 -8
  41. package/src/components/CtaCard/index.tsx +0 -37
  42. package/src/components/CtaCard/preview.module.css +0 -32
  43. package/src/components/CtaCard/style.module.css +0 -32
  44. package/src/components/EmailInput/emailInputBox.tsx +0 -95
  45. package/src/components/Fab/index.tsx +0 -224
  46. package/src/components/Fab/preview.module.css +0 -28
  47. package/src/components/Fab/style.module.css +0 -37
  48. package/src/components/Icons/Call.tsx +0 -26
  49. package/src/components/Icons/Cross.tsx +0 -24
  50. package/src/components/Icons/Gmail.tsx +0 -61
  51. package/src/components/Icons/Instagram.tsx +0 -60
  52. package/src/components/Icons/LiveChat.tsx +0 -43
  53. package/src/components/Icons/Messenger.tsx +0 -57
  54. package/src/components/Icons/Send.tsx +0 -22
  55. package/src/components/Icons/Whatsapp.tsx +0 -24
  56. package/src/components/Shimmer/index.tsx +0 -12
  57. package/src/components/Shimmer/style.module.css +0 -37
  58. package/src/components/SmsInput/smsInputBox.tsx +0 -135
  59. package/src/components/UserDetailsV2/userDetailsV2.desktop.module.css +0 -52
  60. package/src/components/UserDetailsV2/userDetailsV2.mobile.module.css +0 -52
  61. package/src/components/UserDetailsV2/userDetailsV2.module.css +0 -81
  62. package/src/components/UserDetailsV2/userDetailsV2.tsx +0 -527
  63. package/src/components/WhatsappInput/Spinner.tsx +0 -26
  64. package/src/components/WhatsappInput/whatsappInput.module.css +0 -106
  65. package/src/components/WhatsappInput/whatsappInputBox.tsx +0 -155
  66. package/src/components/WhatsappInput/whatsappInputPreviewDesktop.module.css +0 -71
  67. package/src/components/WhatsappInput/whatsappInputPreviewMobile.module.css +0 -65
  68. package/src/components/checkbox/checkbox.module.css +0 -19
  69. package/src/components/checkbox/checkbox.tsx +0 -88
  70. package/src/components/countryCodePicker/countriesDropdown.module.css +0 -77
  71. package/src/components/countryCodePicker/countriesDropdown.tsx +0 -81
  72. package/src/components/couponDetails/coupon.module.css +0 -208
  73. package/src/components/couponDetails/coupon.tsx +0 -210
  74. package/src/components/couponDetails/couponPreviewDesktop.module.css +0 -158
  75. package/src/components/couponDetails/couponPreviewMobile.module.css +0 -164
  76. package/src/components/index.ts +0 -3
  77. package/src/components/inputComponents/Checkbox.module.css +0 -197
  78. package/src/components/inputComponents/Checkbox.tsx +0 -85
  79. package/src/components/inputComponents/DatePicker.module.css +0 -565
  80. package/src/components/inputComponents/DatePicker.tsx +0 -278
  81. package/src/components/inputComponents/Dropdown.module.css +0 -796
  82. package/src/components/inputComponents/Dropdown.tsx +0 -630
  83. package/src/components/inputComponents/InputBox.module.css +0 -401
  84. package/src/components/inputComponents/InputBox.tsx +0 -209
  85. package/src/components/selectedCountry/selectedCountry.module.css +0 -76
  86. package/src/components/selectedCountry/selectedCountry.tsx +0 -76
  87. package/src/components/selectedCountry/selectedCountryPreviewDesktop.module.css +0 -56
  88. package/src/components/selectedCountry/selectedCountryPreviewMobile.module.css +0 -57
  89. package/src/components/userDetailsForm/RenderCustomFields.tsx +0 -333
  90. package/src/components/userDetailsForm/userDetailsForm.tsx +0 -675
  91. package/src/hooks/index.ts +0 -4
  92. package/src/hooks/useExitIntent.ts +0 -452
  93. package/src/hooks/useIsMobile.tsx +0 -21
  94. package/src/hooks/useMessageEvent.ts +0 -8
  95. package/src/hooks/useTriggeredIntentDetails.ts +0 -43
  96. package/src/hooks/useUrlListerner.ts +0 -30
  97. package/src/hooks/useWebSocketLogger.ts +0 -59
  98. package/src/hooks/useWindowEvent.ts +0 -8
  99. package/src/icons/copyIcon.tsx +0 -26
  100. package/src/icons/crossIconDesktop.tsx +0 -20
  101. package/src/icons/crossIconMobile.tsx +0 -20
  102. package/src/index.html +0 -30
  103. package/src/index.ts +0 -32
  104. package/src/index.tsx +0 -1
  105. package/src/repo/widgetRepo.ts +0 -21
  106. package/src/types/customFields.ts +0 -73
  107. package/src/utilities/cookie.ts +0 -70
  108. package/src/utilities/customFieldTypeMapping.ts +0 -67
  109. package/src/utilities/customFieldValidation.ts +0 -201
  110. package/src/utilities/encryption.ts +0 -21
  111. package/src/utilities/exitIntentUtils.ts +0 -31
  112. package/src/utilities/global.css +0 -11
  113. package/src/utilities/languageUtilities.ts +0 -235
  114. package/src/utilities/localRunner.js +0 -26
  115. package/src/utilities/localRunner.ts +0 -27
  116. package/src/utilities/localStorage.ts +0 -40
  117. package/src/utilities/script.tsx +0 -15
  118. package/src/utilities/stringUtils.ts +0 -5
  119. package/src/utilities/styleUtils.ts +0 -134
  120. package/src/utilities/variables.ts +0 -11
  121. package/src/utilities/widgetUtils.js +0 -342
  122. package/src/utilities/widgetUtils.ts +0 -313
  123. package/src/widgets/BottomDrawer/config.ts +0 -41
  124. package/src/widgets/BottomDrawer/index.tsx +0 -116
  125. package/src/widgets/BottomDrawer/modal.tsx +0 -286
  126. package/src/widgets/BottomDrawer/preview.module.css +0 -122
  127. package/src/widgets/BottomDrawer/previewMobile.module.css +0 -124
  128. package/src/widgets/BottomDrawer/style.module.css +0 -279
  129. package/src/widgets/CaptivateBanner/captivateBanner.tsx +0 -200
  130. package/src/widgets/CaptivateBanner/config.ts +0 -72
  131. package/src/widgets/CaptivateBanner/index.tsx +0 -204
  132. package/src/widgets/CaptivateBanner/previewDesktop.module.css +0 -51
  133. package/src/widgets/CaptivateBanner/previewMobile.module.css +0 -51
  134. package/src/widgets/CaptivateBanner/style.module.css +0 -77
  135. package/src/widgets/CaptivateBanner/utils.ts +0 -104
  136. package/src/widgets/CentrallyAlignedPopup/config.ts +0 -42
  137. package/src/widgets/CentrallyAlignedPopup/index.tsx +0 -109
  138. package/src/widgets/CentrallyAlignedPopup/modal.tsx +0 -269
  139. package/src/widgets/CentrallyAlignedPopup/preview.module.css +0 -153
  140. package/src/widgets/CentrallyAlignedPopup/previewMobile.module.css +0 -153
  141. package/src/widgets/CentrallyAlignedPopup/style.module.css +0 -283
  142. package/src/widgets/DirectReward/components/couponDetails.tsx +0 -265
  143. package/src/widgets/DirectReward/components/userDetails.tsx +0 -117
  144. package/src/widgets/DirectReward/config.ts +0 -186
  145. package/src/widgets/DirectReward/directReward.tsx +0 -350
  146. package/src/widgets/DirectReward/index.tsx +0 -579
  147. package/src/widgets/DirectReward/previewStyles/thankYouPreviewDesktop.module.css +0 -276
  148. package/src/widgets/DirectReward/previewStyles/thankYouPreviewMobile.module.css +0 -303
  149. package/src/widgets/DirectReward/previewStyles/userDetailsPreviewDesktop.module.css +0 -511
  150. package/src/widgets/DirectReward/previewStyles/userDetailsPreviewMobile.module.css +0 -462
  151. package/src/widgets/DirectReward/style.module.css +0 -836
  152. package/src/widgets/ExitIntentHook.tsx +0 -28
  153. package/src/widgets/STW/api.ts +0 -70
  154. package/src/widgets/STW/components/svgFactory.tsx +0 -44
  155. package/src/widgets/STW/config.ts +0 -193
  156. package/src/widgets/STW/context.ts +0 -7
  157. package/src/widgets/STW/couponDetails.tsx +0 -121
  158. package/src/widgets/STW/index.tsx +0 -733
  159. package/src/widgets/STW/previewStyles/thankyouPreviewDesktop.module.css +0 -215
  160. package/src/widgets/STW/previewStyles/thankyouPreviewMobile.module.css +0 -205
  161. package/src/widgets/STW/previewStyles/userInputsPreviewDesktop.module.css +0 -732
  162. package/src/widgets/STW/previewStyles/userInputsPreviewMobile.module.css +0 -661
  163. package/src/widgets/STW/previewStyles/wheelPreviewDesktop.module.css +0 -498
  164. package/src/widgets/STW/previewStyles/wheelPreviewMobile.module.css +0 -497
  165. package/src/widgets/STW/stw1.tsx +0 -119
  166. package/src/widgets/STW/stw2Components/wheelDesign.tsx +0 -183
  167. package/src/widgets/STW/stw2Pages/couponDetails.tsx +0 -72
  168. package/src/widgets/STW/stw2Pages/stw2.tsx +0 -212
  169. package/src/widgets/STW/stw2Pages/style.module.css +0 -1226
  170. package/src/widgets/STW/stw2Pages/userDetails.tsx +0 -86
  171. package/src/widgets/STW/stw2Pages/wheel.tsx +0 -117
  172. package/src/widgets/STW/stw2PreviewStyles/thankyouPreviewDesktop.module.css +0 -835
  173. package/src/widgets/STW/stw2PreviewStyles/thankyouPreviewMobile.module.css +0 -787
  174. package/src/widgets/STW/stw2PreviewStyles/userInputsPreviewDesktop.module.css +0 -867
  175. package/src/widgets/STW/stw2PreviewStyles/userInputsPreviewMobile.module.css +0 -798
  176. package/src/widgets/STW/stw2PreviewStyles/wheelPreviewDesktop.module.css +0 -572
  177. package/src/widgets/STW/stw2PreviewStyles/wheelPreviewMobile.module.css +0 -559
  178. package/src/widgets/STW/style.module.css +0 -901
  179. package/src/widgets/STW/userDetails.tsx +0 -150
  180. package/src/widgets/STW/utility.ts +0 -664
  181. package/src/widgets/STW/wheel.tsx +0 -304
  182. package/src/widgets/ScratchCard/ScratchOff/scratchOff.tsx +0 -157
  183. package/src/widgets/ScratchCard/config.ts +0 -152
  184. package/src/widgets/ScratchCard/globalStyle.module.css +0 -931
  185. package/src/widgets/ScratchCard/index.tsx +0 -546
  186. package/src/widgets/ScratchCard/modal.tsx +0 -225
  187. package/src/widgets/ScratchCard/preview.module.css +0 -250
  188. package/src/widgets/ScratchCard/previewMobile.module.css +0 -247
  189. package/src/widgets/ScratchCard/previewStyles/userDetailsPreviewDesktop.module.css +0 -537
  190. package/src/widgets/ScratchCard/previewStyles/userDetailsPreviewMobile.module.css +0 -463
  191. package/src/widgets/ScratchCard/style.module.css +0 -220
  192. package/src/widgets/ShopifyForm/config.ts +0 -168
  193. package/src/widgets/ShopifyForm/index.tsx +0 -214
  194. package/src/widgets/ShopifyForm/previewDesktop.module.css +0 -117
  195. package/src/widgets/ShopifyForm/previewMobile.module.css +0 -131
  196. package/src/widgets/ShopifyForm/shopifyForm.tsx +0 -445
  197. package/src/widgets/ShopifyForm/style.module.css +0 -161
  198. package/src/widgets/SingleButtonRedirection/config.ts +0 -47
  199. package/src/widgets/SingleButtonRedirection/index.tsx +0 -121
  200. package/src/widgets/WebStories/config.ts +0 -105
  201. package/src/widgets/WebStories/index.css +0 -3
  202. package/src/widgets/WebStories/index.tsx +0 -282
  203. package/src/widgets/WebStories/style.module.css +0 -26
  204. package/src/widgets/index.tsx +0 -3
  205. package/src/widgets/utility.ts +0 -31
  206. package/tsconfig.json +0 -12
  207. package/webpack.config.js +0 -239
@@ -1,452 +0,0 @@
1
- import { useEffect, useRef, useCallback } from 'react';
2
- import useIsMobile from './useIsMobile';
3
- import { getCookie, setCookie } from '../widgets/STW/utility';
4
- import {
5
- EXIT_INTENT_LEVEL,
6
- TRIGGERED_INTENT_TYPE,
7
- } from '@bikdotai/bik-models/dm/models/analytics';
8
-
9
- const EXIT_INTENT_CONFIG = {
10
- SCROLL_THRESHOLD: 300, // pixels from top where exit intent triggers
11
- SCROLL_VELOCITY_THRESHOLD: 3.0, // pixels per ms for fast scroll detection
12
- MIN_SCROLL_DISTANCE: 50, // minimum pixels scrolled up to trigger
13
- DELAY: 300, // milliseconds delay before trigger
14
- TRIGGER_BUFFER: 30 * 60 * 1000, // 30 minutes between triggers
15
- MIN_CONSECUTIVE_UP_SCROLLS: 2, // minimum consecutive up scrolls
16
- SCROLL_TIME_FRAME: { min: 16, max: 100 }, // valid time frame for scroll detection
17
- } as const;
18
-
19
- const getCurrentScrollTop = (): number => {
20
- return window.pageYOffset || document.documentElement.scrollTop || 0;
21
- };
22
-
23
- interface ExitIntentConfig {
24
- exitIntentTimeDelay?: number;
25
- exitIntentViewLimit?: number;
26
- exitIntentFastUpScroll?: boolean;
27
- showExitIntentOn?: EXIT_INTENT_LEVEL;
28
- }
29
-
30
- interface ExitIntentOptions {
31
- onExitIntent: (exitIntentType: TRIGGERED_INTENT_TYPE) => void;
32
- config?: ExitIntentConfig;
33
- widgetId?: string;
34
- }
35
-
36
- enum ExitIntentCookie {
37
- SitePopupStartTime = 'bik-site-popup-start-time',
38
- PopupExitIntentCount = 'bik-popup-exit-intent-count',
39
- PopupLastExitIntentTrigger = 'bik-popup-last-exit-intent-trigger',
40
- HistoryPushed = 'bik-exit-intent-history-pushed',
41
- }
42
-
43
- const getWidgetSpecificCookieKey = (
44
- key: ExitIntentCookie,
45
- widgetId?: string,
46
- ): string => {
47
- return widgetId ? `${key}-${widgetId}` : key;
48
- };
49
-
50
- const getCookieNumber = (
51
- key: ExitIntentCookie,
52
- defaultValue = 0,
53
- widgetId?: string,
54
- ): number => {
55
- const cookieKey = getWidgetSpecificCookieKey(key, widgetId);
56
- const value = getCookie(cookieKey);
57
- return value ? parseInt(value, 10) : defaultValue;
58
- };
59
-
60
- const setCookieNumber = (
61
- key: ExitIntentCookie,
62
- value: number,
63
- hours: number,
64
- widgetId?: string,
65
- ) => {
66
- const cookieKey = getWidgetSpecificCookieKey(key, widgetId);
67
- setCookie(cookieKey, value.toString(), hours);
68
- };
69
-
70
- const checkTimeDelay = (
71
- config?: ExitIntentConfig,
72
- widgetId?: string,
73
- ): boolean => {
74
- if (!config?.exitIntentTimeDelay) {
75
- return true;
76
- }
77
- const startTime = getCookieNumber(
78
- ExitIntentCookie.SitePopupStartTime,
79
- Date.now(),
80
- widgetId,
81
- );
82
- const elapsedTime = (Date.now() - startTime) / 1000;
83
- return elapsedTime >= config.exitIntentTimeDelay;
84
- };
85
-
86
- const checkViewLimit = (
87
- config?: ExitIntentConfig,
88
- widgetId?: string,
89
- ): boolean => {
90
- if (!config?.exitIntentViewLimit) {
91
- return true;
92
- }
93
- const currentCount = getCookieNumber(
94
- ExitIntentCookie.PopupExitIntentCount,
95
- 0,
96
- widgetId,
97
- );
98
- return currentCount < config.exitIntentViewLimit;
99
- };
100
-
101
- const checkBuffer = (widgetId?: string): boolean => {
102
- const lastTrigger = getCookieNumber(
103
- ExitIntentCookie.PopupLastExitIntentTrigger,
104
- 0,
105
- widgetId,
106
- );
107
- if (!lastTrigger) {
108
- return true;
109
- }
110
- const timeSinceLastTrigger = Date.now() - lastTrigger;
111
- return timeSinceLastTrigger >= EXIT_INTENT_CONFIG.TRIGGER_BUFFER;
112
- };
113
-
114
- const recordTrigger = (config?: ExitIntentConfig, widgetId?: string) => {
115
- setCookieNumber(
116
- ExitIntentCookie.PopupLastExitIntentTrigger,
117
- Date.now(),
118
- 24,
119
- widgetId,
120
- );
121
-
122
- if (config?.exitIntentViewLimit) {
123
- const currentCount = getCookieNumber(
124
- ExitIntentCookie.PopupExitIntentCount,
125
- 0,
126
- widgetId,
127
- );
128
- setCookieNumber(
129
- ExitIntentCookie.PopupExitIntentCount,
130
- currentCount + 1,
131
- 1,
132
- widgetId,
133
- );
134
- }
135
- };
136
-
137
- const setHistoryPushedCookie = (widgetId?: string) => {
138
- const cookieKey = getWidgetSpecificCookieKey(
139
- ExitIntentCookie.HistoryPushed,
140
- widgetId,
141
- );
142
- setCookie(cookieKey, '1', 1);
143
- };
144
-
145
- const isHistoryPushed = (widgetId?: string): boolean => {
146
- const cookieKey = getWidgetSpecificCookieKey(
147
- ExitIntentCookie.HistoryPushed,
148
- widgetId,
149
- );
150
- return getCookie(cookieKey) === '1';
151
- };
152
-
153
- const initializeSiteStartTime = (widgetId?: string) => {
154
- const cookieKey = getWidgetSpecificCookieKey(
155
- ExitIntentCookie.SitePopupStartTime,
156
- widgetId,
157
- );
158
- if (!getCookie(cookieKey)) {
159
- setCookieNumber(
160
- ExitIntentCookie.SitePopupStartTime,
161
- Date.now(),
162
- 24,
163
- widgetId,
164
- );
165
- }
166
- };
167
-
168
- const canTriggerExitIntent = (
169
- config?: ExitIntentConfig,
170
- widgetId?: string,
171
- ): boolean => {
172
- return (
173
- checkTimeDelay(config, widgetId) &&
174
- checkViewLimit(config, widgetId) &&
175
- checkBuffer(widgetId)
176
- );
177
- };
178
-
179
- const isFirstPageForWebsiteLevel = (
180
- config?: ExitIntentConfig,
181
- widgetId?: string,
182
- ): boolean => {
183
- if (config?.showExitIntentOn !== EXIT_INTENT_LEVEL.WEBSITE) {
184
- return true;
185
- }
186
-
187
- const cookieKey = getWidgetSpecificCookieKey(
188
- ExitIntentCookie.SitePopupStartTime,
189
- widgetId,
190
- );
191
- return !getCookie(cookieKey);
192
- };
193
-
194
- const useDesktopExitIntent = ({
195
- onExitIntent,
196
- config,
197
- widgetId,
198
- }: ExitIntentOptions) => {
199
- const timeoutRef = useRef<NodeJS.Timeout | null>(null);
200
- const hasTriggeredRef = useRef(false);
201
-
202
- const triggerExitIntent = useCallback(
203
- (type: TRIGGERED_INTENT_TYPE) => {
204
- if (hasTriggeredRef.current || !canTriggerExitIntent(config, widgetId)) {
205
- return;
206
- }
207
- hasTriggeredRef.current = true;
208
- recordTrigger(config, widgetId);
209
- onExitIntent(type);
210
- },
211
- [onExitIntent, config, widgetId],
212
- );
213
-
214
- const handleMouseLeave = useCallback(
215
- (event: MouseEvent) => {
216
- if (hasTriggeredRef.current) {
217
- return;
218
- }
219
- // Trigger if mouse leaves from the top of the viewport
220
- if (event.relatedTarget === null && event.clientY <= 0) {
221
- if (timeoutRef.current) clearTimeout(timeoutRef.current);
222
- timeoutRef.current = setTimeout(
223
- () => triggerExitIntent(TRIGGERED_INTENT_TYPE.MOUSE_EXIT),
224
- EXIT_INTENT_CONFIG.DELAY,
225
- );
226
- }
227
- },
228
- [triggerExitIntent],
229
- );
230
-
231
- const handleVisibilityChange = useCallback(() => {
232
- if (document.hidden && !hasTriggeredRef.current) {
233
- triggerExitIntent(TRIGGERED_INTENT_TYPE.VISIBILITY_CHANGE);
234
- }
235
- }, [triggerExitIntent]);
236
-
237
- useEffect(() => {
238
- // Skip listeners if not the first page for website-level exit intent
239
- if (!isFirstPageForWebsiteLevel(config, widgetId)) {
240
- return;
241
- }
242
-
243
- initializeSiteStartTime(widgetId);
244
-
245
- const abortController = new AbortController();
246
- const { signal } = abortController;
247
-
248
- document.addEventListener('mouseout', handleMouseLeave, { signal });
249
- document.addEventListener('visibilitychange', handleVisibilityChange, {
250
- signal,
251
- });
252
-
253
- return () => {
254
- abortController.abort();
255
- if (timeoutRef.current) clearTimeout(timeoutRef.current);
256
- };
257
- }, [handleMouseLeave, handleVisibilityChange, config, widgetId]);
258
-
259
- const reset = useCallback(() => {
260
- hasTriggeredRef.current = false;
261
- if (timeoutRef.current) {
262
- clearTimeout(timeoutRef.current);
263
- timeoutRef.current = null;
264
- }
265
- }, []);
266
-
267
- return { reset };
268
- };
269
-
270
- const useMobileExitIntent = ({
271
- onExitIntent,
272
- config,
273
- widgetId,
274
- }: ExitIntentOptions) => {
275
- const hasTriggeredRef = useRef(false);
276
- const lastScrollTopRef = useRef(getCurrentScrollTop());
277
- const scrollTimeRef = useRef(Date.now());
278
- const scrollDirectionRef = useRef<'up' | 'down' | null>(null);
279
- const consecutiveUpScrollsRef = useRef(0);
280
- const historyStateAddedRef = useRef(false);
281
-
282
- const triggerExitIntent = useCallback(
283
- (type: TRIGGERED_INTENT_TYPE) => {
284
- if (hasTriggeredRef.current || !canTriggerExitIntent(config, widgetId)) {
285
- return;
286
- }
287
- hasTriggeredRef.current = true;
288
- recordTrigger(config, widgetId);
289
- onExitIntent(type);
290
- },
291
- [onExitIntent, config, widgetId],
292
- );
293
-
294
- const handlePopState = useCallback(() => {
295
- if (!hasTriggeredRef.current && historyStateAddedRef.current) {
296
- window.history.replaceState(null, '', window.location.href);
297
- historyStateAddedRef.current = false;
298
- triggerExitIntent(TRIGGERED_INTENT_TYPE.BACK_NAVIGATION);
299
- }
300
- }, [triggerExitIntent]);
301
-
302
- const updateScrollDirection = useCallback((scrollDiff: number) => {
303
- const currentDirection =
304
- scrollDiff > 0 ? 'up' : scrollDiff < 0 ? 'down' : null;
305
-
306
- if (currentDirection === 'up') {
307
- consecutiveUpScrollsRef.current =
308
- scrollDirectionRef.current === 'up'
309
- ? consecutiveUpScrollsRef.current + 1
310
- : 1;
311
- } else {
312
- consecutiveUpScrollsRef.current = 0;
313
- }
314
-
315
- scrollDirectionRef.current = currentDirection;
316
- }, []);
317
-
318
- const shouldTriggerFastScroll = useCallback(
319
- (
320
- currentScrollTop: number,
321
- scrollDiff: number,
322
- timeDiff: number,
323
- ): boolean => {
324
- if (
325
- currentScrollTop > EXIT_INTENT_CONFIG.SCROLL_THRESHOLD ||
326
- scrollDiff < EXIT_INTENT_CONFIG.MIN_SCROLL_DISTANCE ||
327
- timeDiff < EXIT_INTENT_CONFIG.SCROLL_TIME_FRAME.min ||
328
- timeDiff > EXIT_INTENT_CONFIG.SCROLL_TIME_FRAME.max ||
329
- consecutiveUpScrollsRef.current <
330
- EXIT_INTENT_CONFIG.MIN_CONSECUTIVE_UP_SCROLLS
331
- ) {
332
- return false;
333
- }
334
-
335
- const velocity = scrollDiff / timeDiff;
336
- return velocity > EXIT_INTENT_CONFIG.SCROLL_VELOCITY_THRESHOLD;
337
- },
338
- [],
339
- );
340
-
341
- const handleScroll = useCallback(() => {
342
- const fastUpScrollEnabled = config?.exitIntentFastUpScroll !== false;
343
- if (hasTriggeredRef.current || !fastUpScrollEnabled) {
344
- return;
345
- }
346
-
347
- const currentScrollTop = getCurrentScrollTop();
348
- const currentTime = Date.now();
349
- const timeDiff = currentTime - scrollTimeRef.current;
350
- const scrollDiff = lastScrollTopRef.current - currentScrollTop;
351
-
352
- updateScrollDirection(scrollDiff);
353
-
354
- if (shouldTriggerFastScroll(currentScrollTop, scrollDiff, timeDiff)) {
355
- triggerExitIntent(TRIGGERED_INTENT_TYPE.FAST_UP_SCROLL_PAGE);
356
- }
357
-
358
- lastScrollTopRef.current = currentScrollTop;
359
- scrollTimeRef.current = currentTime;
360
- }, [
361
- config?.exitIntentFastUpScroll,
362
- triggerExitIntent,
363
- updateScrollDirection,
364
- shouldTriggerFastScroll,
365
- ]);
366
-
367
- const handleVisibilityChange = useCallback(() => {
368
- if (document.hidden && !hasTriggeredRef.current) {
369
- triggerExitIntent(TRIGGERED_INTENT_TYPE.VISIBILITY_CHANGE);
370
- }
371
- }, [triggerExitIntent]);
372
-
373
- const shouldAddHistoryState = useCallback((): boolean => {
374
- if (historyStateAddedRef.current) return false;
375
-
376
- const isWebsiteLevel =
377
- config?.showExitIntentOn === EXIT_INTENT_LEVEL.WEBSITE;
378
- const isWebpageLevel =
379
- config?.showExitIntentOn === EXIT_INTENT_LEVEL.WEBPAGE;
380
-
381
- return (
382
- (isWebsiteLevel && !isHistoryPushed(widgetId)) ||
383
- (isWebpageLevel && window.history.state === null)
384
- );
385
- }, [config?.showExitIntentOn, widgetId]);
386
-
387
- const addHistoryState = useCallback(() => {
388
- if (!shouldAddHistoryState()) return;
389
-
390
- window.history.pushState({ exitIntent: true }, '', window.location.href);
391
- historyStateAddedRef.current = true;
392
-
393
- if (config?.showExitIntentOn === EXIT_INTENT_LEVEL.WEBSITE) {
394
- setHistoryPushedCookie(widgetId);
395
- }
396
- }, [shouldAddHistoryState, config?.showExitIntentOn, widgetId]);
397
-
398
- useEffect(() => {
399
- // Skip listeners if not the first page for website-level exit intent
400
- if (!isFirstPageForWebsiteLevel(config, widgetId)) {
401
- return;
402
- }
403
-
404
- initializeSiteStartTime(widgetId);
405
- addHistoryState();
406
-
407
- const abortController = new AbortController();
408
- const { signal } = abortController;
409
-
410
- window.addEventListener('popstate', handlePopState, { signal });
411
- document.addEventListener('visibilitychange', handleVisibilityChange, {
412
- signal,
413
- });
414
-
415
- const fastUpScrollEnabled = config?.exitIntentFastUpScroll !== false;
416
- if (fastUpScrollEnabled) {
417
- window.addEventListener('scroll', handleScroll, {
418
- passive: true,
419
- signal,
420
- });
421
- }
422
-
423
- return () => {
424
- abortController.abort();
425
- };
426
- }, [
427
- handlePopState,
428
- handleVisibilityChange,
429
- handleScroll,
430
- addHistoryState,
431
- config,
432
- widgetId,
433
- ]);
434
-
435
- const reset = useCallback(() => {
436
- hasTriggeredRef.current = false;
437
- scrollDirectionRef.current = null;
438
- consecutiveUpScrollsRef.current = 0;
439
- lastScrollTopRef.current = getCurrentScrollTop();
440
- scrollTimeRef.current = Date.now();
441
- }, []);
442
-
443
- return { reset };
444
- };
445
-
446
- export const useExitIntent = (options: ExitIntentOptions) => {
447
- const isMobileDevice = useIsMobile();
448
-
449
- return isMobileDevice
450
- ? useMobileExitIntent(options)
451
- : useDesktopExitIntent(options);
452
- };
@@ -1,21 +0,0 @@
1
- import { useState, useEffect } from 'react';
2
-
3
- const useIsMobile = () => {
4
- const [isMobile, setIsMobile] = useState(false);
5
-
6
- useEffect(() => {
7
- const handleResize = () => {
8
- const regex =
9
- /Mobi|Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;
10
- setIsMobile(regex.test(navigator.userAgent));
11
- };
12
- window.addEventListener('resize', handleResize);
13
- handleResize();
14
- return () => {
15
- window.removeEventListener('resize', handleResize);
16
- };
17
- }, []);
18
- return isMobile;
19
- };
20
-
21
- export default useIsMobile;
@@ -1,8 +0,0 @@
1
- import { useWindowEvent } from './useWindowEvent';
2
-
3
- export const useMessageEvent = callback => {
4
- useWindowEvent('message', event => {
5
- if (typeof event.data !== 'string') return null;
6
- callback(JSON.parse(event.data));
7
- });
8
- };
@@ -1,43 +0,0 @@
1
- import { storeDataInLocalStorage } from '../utilities/localStorage';
2
- import { decryptBikData } from '../utilities/encryption';
3
- import {
4
- EXIT_INTENT_LEVEL,
5
- TRIGGERED_INTENT_SOURCE,
6
- TRIGGERED_PAGE_TYPE,
7
- } from '@bikdotai/bik-models/dm/models/analytics';
8
-
9
- export interface ITriggeredIntentDetails {
10
- triggerSource: TRIGGERED_INTENT_SOURCE;
11
- triggeredPage: TRIGGERED_PAGE_TYPE;
12
- triggerType?: string;
13
- exitIntentLevel?: EXIT_INTENT_LEVEL;
14
- }
15
-
16
- const TRIGGERED_INTENT_KEY = 'bik-triggered-intent-details';
17
-
18
- export const useTriggeredIntentDetails = (widgetId: string) => {
19
- const setTriggeredIntentDetails = (details: ITriggeredIntentDetails) => {
20
- const key = `${TRIGGERED_INTENT_KEY}-${widgetId}`;
21
- storeDataInLocalStorage(key, JSON.stringify(details), true);
22
- };
23
-
24
- const getTriggeredIntentDetails = (): ITriggeredIntentDetails | null => {
25
- try {
26
- const key = `${TRIGGERED_INTENT_KEY}-${widgetId}`;
27
- const storedData = localStorage.getItem(key);
28
-
29
- if (storedData) {
30
- const decryptedData = decryptBikData(storedData);
31
- const parsedData = JSON.parse(decryptedData);
32
- return parsedData;
33
- }
34
- return null;
35
- } catch (error) {
36
- return null;
37
- }
38
- };
39
- return {
40
- setTriggeredIntentDetails,
41
- getTriggeredIntentDetails,
42
- };
43
- };
@@ -1,30 +0,0 @@
1
- import { useEffect } from 'react';
2
-
3
- /** Hook to detect url change even in custom side rendering **/
4
- export const useUrlListerner = (
5
- ref,
6
- callback,
7
- options = {
8
- attributes: true,
9
- characterData: true,
10
- childList: true,
11
- subtree: true,
12
- },
13
- ) => {
14
- let currentUrl;
15
- useEffect(() => {
16
- if (ref.current) {
17
- const observer = new MutationObserver(function (mutations) {
18
- mutations.forEach(function (mutation) {
19
- if (mutation.type === 'childList' && mutation.addedNodes.length) {
20
- if (window.location.href !== currentUrl) {
21
- currentUrl = window.location.href;
22
- callback(currentUrl);
23
- }
24
- }
25
- });
26
- });
27
- observer.observe(document.getElementById(ref), options);
28
- }
29
- }, [callback, options]);
30
- };
@@ -1,59 +0,0 @@
1
- import { useEffect, useRef, useCallback } from 'react';
2
-
3
- export type LogLevel = 'info' | 'warn' | 'error' | 'debug';
4
-
5
- export const useWebSocketLogger = (isWebSocketServerStarted: boolean) => {
6
- const wsRef = useRef<WebSocket | null>(null);
7
- const queueRef = useRef([]);
8
-
9
- const connect = useCallback(async () => {
10
- try {
11
- // Replace with your WebSocket server IP and port
12
- const wsUrl = `ws://192.168.103.109:4040`;
13
- wsRef.current = new WebSocket(wsUrl);
14
- wsRef.current.onopen = () => {
15
- while (queueRef.current.length > 0) {
16
- wsRef.current?.send(JSON.stringify(queueRef.current.shift()));
17
- }
18
- };
19
- wsRef.current.onclose = () => setTimeout(connect, 5000);
20
- wsRef.current.onerror = () => setTimeout(connect, 5000);
21
- } catch {
22
- setTimeout(connect, 5000);
23
- }
24
- }, []);
25
-
26
- const sendLog = useCallback(
27
- (level: LogLevel, message: string, data?: unknown) => {
28
- const log = {
29
- level,
30
- message,
31
- timestamp: new Date().toISOString(),
32
- data,
33
- source: 'client',
34
- };
35
-
36
- if (wsRef.current?.readyState === WebSocket.OPEN) {
37
- wsRef.current.send(JSON.stringify(log));
38
- } else {
39
- queueRef.current.push(log);
40
- if (queueRef.current.length > 100) queueRef.current.shift();
41
- }
42
- },
43
- [],
44
- );
45
-
46
- useEffect(() => {
47
- if (isWebSocketServerStarted) {
48
- connect();
49
- return () => wsRef.current?.close();
50
- }
51
- }, [connect]);
52
-
53
- return {
54
- log: (msg: string, data?: unknown) => sendLog('info', msg, data),
55
- warn: (msg: string, data?: unknown) => sendLog('warn', msg, data),
56
- error: (msg: string, data?: unknown) => sendLog('error', msg, data),
57
- debug: (msg: string, data?: unknown) => sendLog('debug', msg, data),
58
- };
59
- };
@@ -1,8 +0,0 @@
1
- import { useEffect } from 'react';
2
-
3
- export const useWindowEvent = (event, callback) => {
4
- useEffect(() => {
5
- window.addEventListener(event, callback);
6
- return () => window.removeEventListener(event, callback);
7
- }, [event, callback]);
8
- };
@@ -1,26 +0,0 @@
1
- import React from 'react';
2
-
3
- const CopyIcon: React.FC<{ colour?: string }> = ({ colour }) => {
4
- return (
5
- <svg
6
- width="21"
7
- height="20"
8
- viewBox="0 0 21 20"
9
- fill="none"
10
- xmlns="http://www.w3.org/2000/svg"
11
- >
12
- <path
13
- d="M3.24409 2.74412C3.40037 2.58784 3.61233 2.50004 3.83334 2.50004H11.3333C11.5544 2.50004 11.7663 2.58784 11.9226 2.74412C12.0789 2.9004 12.1667 3.11236 12.1667 3.33337V4.16671C12.1667 4.62694 12.5398 5.00004 13 5.00004C13.4602 5.00004 13.8333 4.62694 13.8333 4.16671V3.33337C13.8333 2.67033 13.5699 2.03445 13.1011 1.56561C12.6323 1.09677 11.9964 0.833374 11.3333 0.833374H3.83334C3.1703 0.833374 2.53442 1.09677 2.06558 1.56561C1.59674 2.03445 1.33334 2.67033 1.33334 3.33337V10.8334C1.33334 11.4964 1.59674 12.1323 2.06558 12.6011C2.53442 13.07 3.1703 13.3334 3.83334 13.3334H4.66668C5.12691 13.3334 5.50001 12.9603 5.50001 12.5C5.50001 12.0398 5.12691 11.6667 4.66668 11.6667H3.83334C3.61233 11.6667 3.40037 11.5789 3.24409 11.4226C3.08781 11.2663 3.00001 11.0544 3.00001 10.8334V3.33337C3.00001 3.11236 3.08781 2.9004 3.24409 2.74412Z"
14
- fill={colour ?? 'white'}
15
- />
16
- <path
17
- fillRule="evenodd"
18
- clipRule="evenodd"
19
- d="M9.66668 6.66671C8.28596 6.66671 7.16668 7.78599 7.16668 9.16671V16.6667C7.16668 18.0474 8.28596 19.1667 9.66668 19.1667H17.1667C18.5474 19.1667 19.6667 18.0474 19.6667 16.6667V9.16671C19.6667 7.78599 18.5474 6.66671 17.1667 6.66671H9.66668ZM8.83334 9.16671C8.83334 8.70647 9.20644 8.33337 9.66668 8.33337H17.1667C17.6269 8.33337 18 8.70647 18 9.16671V16.6667C18 17.1269 17.6269 17.5 17.1667 17.5H9.66668C9.20644 17.5 8.83334 17.1269 8.83334 16.6667V9.16671Z"
20
- fill={colour ?? 'white'}
21
- />
22
- </svg>
23
- );
24
- };
25
-
26
- export default CopyIcon;
@@ -1,20 +0,0 @@
1
- import React from 'react';
2
-
3
- const CrossIconDesktop: React.FC<{ color?: string }> = ({ color }) => {
4
- return (
5
- <svg
6
- width="32"
7
- height="32"
8
- viewBox="0 0 32 32"
9
- fill="none"
10
- xmlns="http://www.w3.org/2000/svg"
11
- >
12
- <path
13
- d="M24.9428 8.94265C25.4635 8.42195 25.4635 7.57773 24.9428 7.05703C24.4221 6.53633 23.5779 6.53633 23.0572 7.05703L16 14.1142L8.9428 7.05703C8.4221 6.53633 7.57788 6.53633 7.05718 7.05703C6.53648 7.57773 6.53648 8.42195 7.05718 8.94265L14.1144 15.9998L7.05718 23.057C6.53648 23.5777 6.53648 24.4219 7.05718 24.9426C7.57788 25.4633 8.4221 25.4633 8.9428 24.9426L16 17.8855L23.0572 24.9426C23.5779 25.4633 24.4221 25.4633 24.9428 24.9426C25.4635 24.4219 25.4635 23.5777 24.9428 23.057L17.8856 15.9998L24.9428 8.94265Z"
14
- fill={color ?? '#212121'}
15
- />
16
- </svg>
17
- );
18
- };
19
-
20
- export default CrossIconDesktop;
@@ -1,20 +0,0 @@
1
- import React from 'react';
2
-
3
- const CrossIconMobile = () => {
4
- return (
5
- <svg
6
- width="24"
7
- height="24"
8
- viewBox="0 0 24 24"
9
- fill="none"
10
- xmlns="http://www.w3.org/2000/svg"
11
- >
12
- <path
13
- d="M18.7071 6.70711C19.0976 6.31658 19.0976 5.68342 18.7071 5.29289C18.3166 4.90237 17.6834 4.90237 17.2929 5.29289L12 10.5858L6.70711 5.29289C6.31658 4.90237 5.68342 4.90237 5.29289 5.29289C4.90237 5.68342 4.90237 6.31658 5.29289 6.70711L10.5858 12L5.29289 17.2929C4.90237 17.6834 4.90237 18.3166 5.29289 18.7071C5.68342 19.0976 6.31658 19.0976 6.70711 18.7071L12 13.4142L17.2929 18.7071C17.6834 19.0976 18.3166 19.0976 18.7071 18.7071C19.0976 18.3166 19.0976 17.6834 18.7071 17.2929L13.4142 12L18.7071 6.70711Z"
14
- fill="#616161"
15
- />
16
- </svg>
17
- );
18
- };
19
-
20
- export default CrossIconMobile;