@bikdotai/bik-widgets 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/.eslintrc +22 -0
  2. package/.eslintrc.js +19 -0
  3. package/.github/workflows/main.yml +293 -0
  4. package/.prettierignore +13 -0
  5. package/.prettierrc +10 -0
  6. package/README.md +128 -0
  7. package/cypress/apiHelper/endpoints.ts +21 -0
  8. package/cypress/apiHelper/executor.ts +42 -0
  9. package/cypress/e2e/bottomDrawer.cy.ts +49 -0
  10. package/cypress/e2e/directReward.cy.ts +67 -0
  11. package/cypress/e2e/scratchTheCard.cy.ts +68 -0
  12. package/cypress/e2e/stw.cy.ts +82 -0
  13. package/cypress/e2e/waRedirection.cy.ts +46 -0
  14. package/cypress/fixtures/payloads.ts +330 -0
  15. package/cypress/support/commands.ts +37 -0
  16. package/cypress/support/e2e.ts +20 -0
  17. package/cypress.staging.config.ts +23 -0
  18. package/jsconfig.json +6 -0
  19. package/localtest.sh +10 -0
  20. package/log-server.js +86 -0
  21. package/package.json +79 -0
  22. package/postcss.config.js +8 -0
  23. package/src/Globals.d.ts +2 -0
  24. package/src/assets/lottie/santa.json +11722 -0
  25. package/src/assets/svg/CalendarClockIcon.tsx +30 -0
  26. package/src/assets/svg/CalendarIcon.tsx +24 -0
  27. package/src/assets/svg/CheckIcon.tsx +17 -0
  28. package/src/assets/svg/ChevronIcon.tsx +21 -0
  29. package/src/assets/svg/Close.tsx +39 -0
  30. package/src/assets/svg/Confetti.tsx +140 -0
  31. package/src/assets/svg/Copy.tsx +26 -0
  32. package/src/assets/svg/DropdownCheckIcon.tsx +35 -0
  33. package/src/assets/svg/ErrorIcon.tsx +27 -0
  34. package/src/assets/svg/RadioIcon.tsx +25 -0
  35. package/src/assets/svg/UncheckedCheckboxIcon.tsx +28 -0
  36. package/src/assets/svg/UncheckedRadioIcon.tsx +26 -0
  37. package/src/assets/svg/info.tsx +30 -0
  38. package/src/assets/svg/qrcode.svg +14 -0
  39. package/src/bootstrap.tsx +8 -0
  40. package/src/components/CtaCard/index.tsx +37 -0
  41. package/src/components/CtaCard/preview.module.css +32 -0
  42. package/src/components/CtaCard/style.module.css +32 -0
  43. package/src/components/EmailInput/emailInputBox.tsx +95 -0
  44. package/src/components/Fab/index.tsx +224 -0
  45. package/src/components/Fab/preview.module.css +28 -0
  46. package/src/components/Fab/style.module.css +37 -0
  47. package/src/components/Icons/Call.tsx +26 -0
  48. package/src/components/Icons/Cross.tsx +24 -0
  49. package/src/components/Icons/Gmail.tsx +61 -0
  50. package/src/components/Icons/Instagram.tsx +60 -0
  51. package/src/components/Icons/LiveChat.tsx +43 -0
  52. package/src/components/Icons/Messenger.tsx +57 -0
  53. package/src/components/Icons/Send.tsx +22 -0
  54. package/src/components/Icons/Whatsapp.tsx +24 -0
  55. package/src/components/Shimmer/index.tsx +12 -0
  56. package/src/components/Shimmer/style.module.css +37 -0
  57. package/src/components/SmsInput/smsInputBox.tsx +135 -0
  58. package/src/components/UserDetailsV2/userDetailsV2.desktop.module.css +52 -0
  59. package/src/components/UserDetailsV2/userDetailsV2.mobile.module.css +52 -0
  60. package/src/components/UserDetailsV2/userDetailsV2.module.css +81 -0
  61. package/src/components/UserDetailsV2/userDetailsV2.tsx +527 -0
  62. package/src/components/WhatsappInput/Spinner.tsx +26 -0
  63. package/src/components/WhatsappInput/whatsappInput.module.css +106 -0
  64. package/src/components/WhatsappInput/whatsappInputBox.tsx +155 -0
  65. package/src/components/WhatsappInput/whatsappInputPreviewDesktop.module.css +71 -0
  66. package/src/components/WhatsappInput/whatsappInputPreviewMobile.module.css +65 -0
  67. package/src/components/checkbox/checkbox.module.css +19 -0
  68. package/src/components/checkbox/checkbox.tsx +88 -0
  69. package/src/components/countryCodePicker/countriesDropdown.module.css +77 -0
  70. package/src/components/countryCodePicker/countriesDropdown.tsx +81 -0
  71. package/src/components/couponDetails/coupon.module.css +208 -0
  72. package/src/components/couponDetails/coupon.tsx +210 -0
  73. package/src/components/couponDetails/couponPreviewDesktop.module.css +158 -0
  74. package/src/components/couponDetails/couponPreviewMobile.module.css +164 -0
  75. package/src/components/index.ts +3 -0
  76. package/src/components/inputComponents/Checkbox.module.css +197 -0
  77. package/src/components/inputComponents/Checkbox.tsx +85 -0
  78. package/src/components/inputComponents/DatePicker.module.css +565 -0
  79. package/src/components/inputComponents/DatePicker.tsx +278 -0
  80. package/src/components/inputComponents/Dropdown.module.css +796 -0
  81. package/src/components/inputComponents/Dropdown.tsx +630 -0
  82. package/src/components/inputComponents/InputBox.module.css +401 -0
  83. package/src/components/inputComponents/InputBox.tsx +209 -0
  84. package/src/components/selectedCountry/selectedCountry.module.css +76 -0
  85. package/src/components/selectedCountry/selectedCountry.tsx +76 -0
  86. package/src/components/selectedCountry/selectedCountryPreviewDesktop.module.css +56 -0
  87. package/src/components/selectedCountry/selectedCountryPreviewMobile.module.css +57 -0
  88. package/src/components/userDetailsForm/RenderCustomFields.tsx +333 -0
  89. package/src/components/userDetailsForm/userDetailsForm.tsx +675 -0
  90. package/src/hooks/index.ts +4 -0
  91. package/src/hooks/useExitIntent.ts +452 -0
  92. package/src/hooks/useIsMobile.tsx +21 -0
  93. package/src/hooks/useMessageEvent.ts +8 -0
  94. package/src/hooks/useTriggeredIntentDetails.ts +43 -0
  95. package/src/hooks/useUrlListerner.ts +30 -0
  96. package/src/hooks/useWebSocketLogger.ts +59 -0
  97. package/src/hooks/useWindowEvent.ts +8 -0
  98. package/src/icons/copyIcon.tsx +26 -0
  99. package/src/icons/crossIconDesktop.tsx +20 -0
  100. package/src/icons/crossIconMobile.tsx +20 -0
  101. package/src/index.html +30 -0
  102. package/src/index.ts +32 -0
  103. package/src/index.tsx +1 -0
  104. package/src/repo/widgetRepo.ts +21 -0
  105. package/src/types/customFields.ts +73 -0
  106. package/src/utilities/cookie.ts +70 -0
  107. package/src/utilities/customFieldTypeMapping.ts +67 -0
  108. package/src/utilities/customFieldValidation.ts +201 -0
  109. package/src/utilities/encryption.ts +21 -0
  110. package/src/utilities/exitIntentUtils.ts +31 -0
  111. package/src/utilities/global.css +11 -0
  112. package/src/utilities/languageUtilities.ts +235 -0
  113. package/src/utilities/localRunner.js +26 -0
  114. package/src/utilities/localRunner.ts +27 -0
  115. package/src/utilities/localStorage.ts +40 -0
  116. package/src/utilities/script.tsx +15 -0
  117. package/src/utilities/stringUtils.ts +5 -0
  118. package/src/utilities/styleUtils.ts +134 -0
  119. package/src/utilities/variables.ts +11 -0
  120. package/src/utilities/widgetUtils.js +342 -0
  121. package/src/utilities/widgetUtils.ts +313 -0
  122. package/src/widgets/BottomDrawer/config.ts +41 -0
  123. package/src/widgets/BottomDrawer/index.tsx +116 -0
  124. package/src/widgets/BottomDrawer/modal.tsx +286 -0
  125. package/src/widgets/BottomDrawer/preview.module.css +122 -0
  126. package/src/widgets/BottomDrawer/previewMobile.module.css +124 -0
  127. package/src/widgets/BottomDrawer/style.module.css +279 -0
  128. package/src/widgets/CaptivateBanner/captivateBanner.tsx +200 -0
  129. package/src/widgets/CaptivateBanner/config.ts +72 -0
  130. package/src/widgets/CaptivateBanner/index.tsx +204 -0
  131. package/src/widgets/CaptivateBanner/previewDesktop.module.css +51 -0
  132. package/src/widgets/CaptivateBanner/previewMobile.module.css +51 -0
  133. package/src/widgets/CaptivateBanner/style.module.css +77 -0
  134. package/src/widgets/CaptivateBanner/utils.ts +104 -0
  135. package/src/widgets/CentrallyAlignedPopup/config.ts +42 -0
  136. package/src/widgets/CentrallyAlignedPopup/index.tsx +109 -0
  137. package/src/widgets/CentrallyAlignedPopup/modal.tsx +269 -0
  138. package/src/widgets/CentrallyAlignedPopup/preview.module.css +153 -0
  139. package/src/widgets/CentrallyAlignedPopup/previewMobile.module.css +153 -0
  140. package/src/widgets/CentrallyAlignedPopup/style.module.css +283 -0
  141. package/src/widgets/DirectReward/components/couponDetails.tsx +265 -0
  142. package/src/widgets/DirectReward/components/userDetails.tsx +117 -0
  143. package/src/widgets/DirectReward/config.ts +186 -0
  144. package/src/widgets/DirectReward/directReward.tsx +350 -0
  145. package/src/widgets/DirectReward/index.tsx +579 -0
  146. package/src/widgets/DirectReward/previewStyles/thankYouPreviewDesktop.module.css +276 -0
  147. package/src/widgets/DirectReward/previewStyles/thankYouPreviewMobile.module.css +303 -0
  148. package/src/widgets/DirectReward/previewStyles/userDetailsPreviewDesktop.module.css +511 -0
  149. package/src/widgets/DirectReward/previewStyles/userDetailsPreviewMobile.module.css +462 -0
  150. package/src/widgets/DirectReward/style.module.css +836 -0
  151. package/src/widgets/ExitIntentHook.tsx +28 -0
  152. package/src/widgets/STW/api.ts +70 -0
  153. package/src/widgets/STW/components/svgFactory.tsx +44 -0
  154. package/src/widgets/STW/config.ts +193 -0
  155. package/src/widgets/STW/context.ts +7 -0
  156. package/src/widgets/STW/couponDetails.tsx +121 -0
  157. package/src/widgets/STW/index.tsx +733 -0
  158. package/src/widgets/STW/previewStyles/thankyouPreviewDesktop.module.css +215 -0
  159. package/src/widgets/STW/previewStyles/thankyouPreviewMobile.module.css +205 -0
  160. package/src/widgets/STW/previewStyles/userInputsPreviewDesktop.module.css +732 -0
  161. package/src/widgets/STW/previewStyles/userInputsPreviewMobile.module.css +661 -0
  162. package/src/widgets/STW/previewStyles/wheelPreviewDesktop.module.css +498 -0
  163. package/src/widgets/STW/previewStyles/wheelPreviewMobile.module.css +497 -0
  164. package/src/widgets/STW/stw1.tsx +119 -0
  165. package/src/widgets/STW/stw2Components/wheelDesign.tsx +183 -0
  166. package/src/widgets/STW/stw2Pages/couponDetails.tsx +72 -0
  167. package/src/widgets/STW/stw2Pages/stw2.tsx +212 -0
  168. package/src/widgets/STW/stw2Pages/style.module.css +1226 -0
  169. package/src/widgets/STW/stw2Pages/userDetails.tsx +86 -0
  170. package/src/widgets/STW/stw2Pages/wheel.tsx +117 -0
  171. package/src/widgets/STW/stw2PreviewStyles/thankyouPreviewDesktop.module.css +835 -0
  172. package/src/widgets/STW/stw2PreviewStyles/thankyouPreviewMobile.module.css +787 -0
  173. package/src/widgets/STW/stw2PreviewStyles/userInputsPreviewDesktop.module.css +867 -0
  174. package/src/widgets/STW/stw2PreviewStyles/userInputsPreviewMobile.module.css +798 -0
  175. package/src/widgets/STW/stw2PreviewStyles/wheelPreviewDesktop.module.css +572 -0
  176. package/src/widgets/STW/stw2PreviewStyles/wheelPreviewMobile.module.css +559 -0
  177. package/src/widgets/STW/style.module.css +901 -0
  178. package/src/widgets/STW/userDetails.tsx +150 -0
  179. package/src/widgets/STW/utility.ts +664 -0
  180. package/src/widgets/STW/wheel.tsx +304 -0
  181. package/src/widgets/ScratchCard/ScratchOff/scratchOff.tsx +157 -0
  182. package/src/widgets/ScratchCard/config.ts +152 -0
  183. package/src/widgets/ScratchCard/globalStyle.module.css +931 -0
  184. package/src/widgets/ScratchCard/index.tsx +546 -0
  185. package/src/widgets/ScratchCard/modal.tsx +225 -0
  186. package/src/widgets/ScratchCard/preview.module.css +250 -0
  187. package/src/widgets/ScratchCard/previewMobile.module.css +247 -0
  188. package/src/widgets/ScratchCard/previewStyles/userDetailsPreviewDesktop.module.css +537 -0
  189. package/src/widgets/ScratchCard/previewStyles/userDetailsPreviewMobile.module.css +463 -0
  190. package/src/widgets/ScratchCard/style.module.css +220 -0
  191. package/src/widgets/ShopifyForm/config.ts +168 -0
  192. package/src/widgets/ShopifyForm/index.tsx +214 -0
  193. package/src/widgets/ShopifyForm/previewDesktop.module.css +117 -0
  194. package/src/widgets/ShopifyForm/previewMobile.module.css +131 -0
  195. package/src/widgets/ShopifyForm/shopifyForm.tsx +445 -0
  196. package/src/widgets/ShopifyForm/style.module.css +161 -0
  197. package/src/widgets/SingleButtonRedirection/config.ts +47 -0
  198. package/src/widgets/SingleButtonRedirection/index.tsx +121 -0
  199. package/src/widgets/WebStories/config.ts +105 -0
  200. package/src/widgets/WebStories/index.css +3 -0
  201. package/src/widgets/WebStories/index.tsx +282 -0
  202. package/src/widgets/WebStories/style.module.css +26 -0
  203. package/src/widgets/index.tsx +3 -0
  204. package/src/widgets/utility.ts +31 -0
  205. package/tsconfig.json +12 -0
  206. package/webpack.config.js +239 -0
@@ -0,0 +1,733 @@
1
+ import React, { useEffect, useState, Suspense } from 'react';
2
+ import { IUserInputs } from './userDetails';
3
+ import {
4
+ generateRotationValues,
5
+ setCookie,
6
+ getCookie,
7
+ cookieClickHandler,
8
+ getScrollPercent,
9
+ } from './utility';
10
+ import STWStyle from './style.module.css';
11
+ import STW2Style from './stw2Pages/style.module.css';
12
+ import { fetchCouponCode, IChannelInfo, IPayloadFetchCouponCode } from './api';
13
+ import Fab, { IFab } from 'components/Fab';
14
+ import Send from 'components/Icons/Send';
15
+ import includeMe from 'utilities/script';
16
+ import { IPageConfigProcessed, WidgetUtils } from '../../utilities/widgetUtils';
17
+ import { shouldShowExitIntent } from '../../utilities/exitIntentUtils';
18
+ import {
19
+ ISTWWidgetCustomisation,
20
+ WIDGET_NAME,
21
+ WidgetSchema,
22
+ ISTWWidgetLeadGeneration,
23
+ WidgetInfo,
24
+ ISTWWidgetVisibility,
25
+ ISO_CODES_VALUES,
26
+ } from '@bikdotai/bik-models/dm';
27
+ import {
28
+ LOCAL_STORAGE_KEYS,
29
+ storeDataInLocalStorage,
30
+ } from '../../utilities/localStorage';
31
+ import { v4 as uuidV4 } from 'uuid';
32
+ import { decryptBikData } from '../../utilities/encryption';
33
+ import useIsMobile from '../../hooks/useIsMobile';
34
+ import {
35
+ TRIGGERED_INTENT_SOURCE,
36
+ TRIGGERED_INTENT_TYPE,
37
+ EXIT_INTENT_LEVEL,
38
+ } from '@bikdotai/bik-models/dm/models/analytics';
39
+ import { getTriggeredPageFromUrl } from '../utility';
40
+ import { useTriggeredIntentDetails } from 'hooks/useTriggeredIntentDetails';
41
+ import { CUSTOM_FIELDS } from 'utilities/customFieldTypeMapping';
42
+ import { LEAD_GENERATION_CHANNELS } from '../../types/customFields';
43
+
44
+ const ExitIntentHook = React.lazy(() => import('../ExitIntentHook'));
45
+
46
+ export interface ISTW extends WidgetSchema {
47
+ id: string;
48
+ widgetCustomisation: ISTWWidgetCustomisation;
49
+ storeWidgetConfig: IPageConfigProcessed;
50
+ environment: string;
51
+ preview?: boolean;
52
+ templateName?: WIDGET_NAME;
53
+ isMobile?: boolean;
54
+ countryCode?: string;
55
+ previewLanguage?: ISO_CODES_VALUES;
56
+ }
57
+
58
+ let isModalOpened = false;
59
+ const STW = (props: ISTW) => {
60
+ const { widgetCustomisation, info, environment, leadGeneration, visibility } =
61
+ props;
62
+ const { spikesCount } = widgetCustomisation as ISTWWidgetCustomisation;
63
+ const { mandatoryOption, optionalOptions } =
64
+ leadGeneration as ISTWWidgetLeadGeneration;
65
+ const {
66
+ storeId,
67
+ templateId,
68
+ templateName = WIDGET_NAME.STW2,
69
+ } = info as WidgetInfo;
70
+ const { triggers } = visibility as ISTWWidgetVisibility;
71
+ const { fabButtonVisibility, pageScroll } = triggers;
72
+ const widgetUtils = new WidgetUtils();
73
+ const viewLimit = (triggers.frequency ? triggers.frequency : 0) / 24;
74
+ const timeDelay = (triggers.timeDelay ? triggers.timeDelay : 0) * 1000;
75
+ const playLimit = (triggers.playLimit ? triggers.playLimit : 0) / 24;
76
+
77
+ const [showComponents, setShowComponents] = useState({
78
+ wheel: false,
79
+ userDetails: false,
80
+ couponDetails: false,
81
+ showFab: false,
82
+ });
83
+ const [STWJSX, setSTWJSX] = useState<any>();
84
+ const [error, setError] = useState<string>(null);
85
+ const [isLoading, setIsLoading] = useState<boolean>(false);
86
+ const [isWheelSpinning, setIsWheelSpinning] = useState<boolean>(false);
87
+ const [session, setSession] = useState<string>();
88
+ const [sameMobileNumberTooglers, setSameMobileNumberTogglers] = useState<{
89
+ sameSMSNo: boolean;
90
+ sameWhatsappNumber: boolean;
91
+ }>({
92
+ sameSMSNo: false,
93
+ sameWhatsappNumber: false,
94
+ });
95
+ const [couponCodeDetails, setCouponCodeDetails] = useState<{
96
+ code: string;
97
+ description: string;
98
+ }>({
99
+ code: 'SND20OFF',
100
+ description:
101
+ '20% off on entire order | Minimum purchase of ₹500.00 One time use only | Expiry date : 5th Aug, 2022',
102
+ });
103
+ const isMobileDevice = useIsMobile();
104
+ const { setTriggeredIntentDetails, getTriggeredIntentDetails } =
105
+ useTriggeredIntentDetails(props.id);
106
+
107
+ useEffect(() => {
108
+ loadSTWOnDemand();
109
+ }, []);
110
+
111
+ useEffect(() => {
112
+ cookieClickHandler(
113
+ `bik-${props.id}-visitor`,
114
+ 'bikvisitor',
115
+ 'WIDGET_VISITED',
116
+ 1,
117
+ props.id,
118
+ environment,
119
+ );
120
+ const shouldShow = widgetUtils.showWidget(
121
+ {
122
+ currentUrl: window.location.href.replace(window.location.origin, ''),
123
+ customUrls: props.storeWidgetConfig,
124
+ currentWidgetId: props.id,
125
+ },
126
+ props.info.isAutomationTesting,
127
+ );
128
+ if (
129
+ !shouldShow ||
130
+ (getCookie(`bik-${props.id}-claimed`) && triggers?.hideAfterClaimed) ||
131
+ (getCookie(`bik-${props.id}-modalopened`) && triggers?.frequency)
132
+ ) {
133
+ return;
134
+ }
135
+ if (fabButtonVisibility) {
136
+ setShowComponents({
137
+ ...showComponents,
138
+ showFab: fabButtonVisibility,
139
+ });
140
+ }
141
+ launchModalOnTimeDelay();
142
+ const cleanupScrollListener = launchModalOnScroll();
143
+
144
+ return () => {
145
+ if (cleanupScrollListener) {
146
+ cleanupScrollListener();
147
+ }
148
+ };
149
+ }, [window.location.href]);
150
+
151
+ const loadSTWOnDemand = () => {
152
+ if (templateName === WIDGET_NAME.STW1) {
153
+ import('./stw1').then(Component => {
154
+ setSTWJSX(Component);
155
+ });
156
+ } else if (templateName === WIDGET_NAME.STW2) {
157
+ import('./stw2Pages/stw2').then(Component => {
158
+ setSTWJSX(Component);
159
+ });
160
+ }
161
+ };
162
+
163
+ const launchModalOnTimeDelay = () => {
164
+ if (
165
+ timeDelay &&
166
+ !(getCookie(`bik-${props.id}-spinned`) === 'bikspinned') &&
167
+ !isModalOpened
168
+ ) {
169
+ setTimeout(() => {
170
+ if (!isModalOpened) {
171
+ setTriggeredIntentDetails({
172
+ triggerSource: TRIGGERED_INTENT_SOURCE.AUTO_POPULATE,
173
+ triggerType: TRIGGERED_INTENT_TYPE.TIME_DELAY,
174
+ triggeredPage: getTriggeredPageFromUrl(window.location.href),
175
+ });
176
+ launchModal();
177
+ }
178
+ }, timeDelay);
179
+ }
180
+ };
181
+
182
+ const launchModalOnScroll = () => {
183
+ const handleScrollEnd = () => {
184
+ if (
185
+ getCookie(`bik-${props.id}-spinned`) === 'bikspinned' ||
186
+ isModalOpened
187
+ ) {
188
+ return;
189
+ }
190
+ if (
191
+ !pageScroll ||
192
+ (getCookie(`bik-${props.id}-claimed`) &&
193
+ visibility?.triggers?.hideAfterClaimed) ||
194
+ (getCookie(`bik-${props.id}-modalopened`) &&
195
+ visibility?.triggers?.frequency)
196
+ ) {
197
+ return;
198
+ }
199
+ if (pageScroll && getScrollPercent() >= pageScroll) {
200
+ setTriggeredIntentDetails({
201
+ triggerSource: TRIGGERED_INTENT_SOURCE.AUTO_POPULATE,
202
+ triggerType: TRIGGERED_INTENT_TYPE.PAGE_SCROLL,
203
+ triggeredPage: getTriggeredPageFromUrl(window.location.href),
204
+ });
205
+ launchModal();
206
+ }
207
+ };
208
+
209
+ window.addEventListener('scrollend', handleScrollEnd);
210
+
211
+ return () => {
212
+ window.removeEventListener('scrollend', handleScrollEnd);
213
+ };
214
+ };
215
+
216
+ const launchModal = () => {
217
+ isModalOpened = true;
218
+ cookieClickHandler(
219
+ `bik-${props.id}-clicked`,
220
+ 'bikview',
221
+ 'WIDGET_CLICKED',
222
+ 1,
223
+ props.id,
224
+ environment,
225
+ );
226
+ setCookie(`bik-${props.id}-modalopened`, 'bikmodalopened', viewLimit);
227
+ setShowComponents({ ...showComponents, wheel: true, showFab: false });
228
+ document.body.style.overflow = 'hidden';
229
+ };
230
+
231
+ const handleExitIntent = (exitIntentType: string) => {
232
+ if (!isModalOpened) {
233
+ setTriggeredIntentDetails({
234
+ triggerSource: TRIGGERED_INTENT_SOURCE.EXIT_INTENT,
235
+ triggerType: exitIntentType,
236
+ triggeredPage: getTriggeredPageFromUrl(window.location.href),
237
+ exitIntentLevel:
238
+ triggers?.showExitIntentOn ?? EXIT_INTENT_LEVEL.WEBPAGE,
239
+ });
240
+ launchModal();
241
+ }
242
+ };
243
+
244
+ // Only render exit intent node if exitIntent trigger is enabled
245
+ const getExitIntentHook = () => {
246
+ if (props.preview) {
247
+ return false;
248
+ }
249
+
250
+ const pathname = window.location.pathname;
251
+ const location = window.location.href;
252
+ const visiblePages = visibility?.visiblePages ?? [];
253
+
254
+ if (
255
+ shouldShowExitIntent({
256
+ visiblePages,
257
+ currentLocation: location,
258
+ currentPathname: pathname,
259
+ isMobileDevice,
260
+ triggers,
261
+ })
262
+ ) {
263
+ return (
264
+ <Suspense fallback={null}>
265
+ <ExitIntentHook
266
+ onExitIntent={handleExitIntent}
267
+ config={{
268
+ exitIntentTimeDelay: triggers?.exitIntentTimeDelay,
269
+ exitIntentViewLimit: triggers?.exitIntentViewLimit,
270
+ exitIntentFastUpScroll: triggers?.exitIntentFastUpScroll,
271
+ showExitIntentOn: triggers?.showExitIntentOn,
272
+ }}
273
+ widgetId={props.id}
274
+ />
275
+ </Suspense>
276
+ );
277
+ } else {
278
+ return null;
279
+ }
280
+ };
281
+
282
+ const onSpinHandle = async () => {
283
+ if (isWheelSpinning) {
284
+ return;
285
+ }
286
+
287
+ const style = templateName === WIDGET_NAME.STW1 ? STWStyle : STW2Style;
288
+ let container = document.getElementsByClassName(
289
+ style.bikContainerSpinner,
290
+ )[0];
291
+ if (getCookie(`bik-${props.id}-spinned`) === 'bikspinned') {
292
+ const header = document.getElementById(style.bikHeader);
293
+ header.innerHTML = `Sorry, you are out of spin! come back later`;
294
+ const subheader = document.getElementById(style.bikSubheader);
295
+ subheader.innerHTML = `Since you have spined now, please come back after some time`;
296
+ return;
297
+ }
298
+
299
+ setIsWheelSpinning(true);
300
+
301
+ const number = 360 * 7;
302
+ setCookie(`bik-${props.id}-spinned`, 'bikspinned', playLimit);
303
+ container.style.transitionDuration = '5s';
304
+ container.style.transform = 'rotate(' + number + 'deg)';
305
+
306
+ try {
307
+ return await getWinningSector(container);
308
+ } finally {
309
+ setTimeout(() => {
310
+ setIsWheelSpinning(false);
311
+ }, 6000);
312
+ }
313
+ };
314
+
315
+ const getWinningSector = async container => {
316
+ const uuid = uuidV4();
317
+ setSession(uuid);
318
+ const response = await fetch(
319
+ `${environment}/publicApiFunctions-fetchProbabilityIndex`,
320
+ {
321
+ method: 'POST',
322
+ headers: {
323
+ Accept: 'application/json',
324
+ 'Content-Type': 'application/json',
325
+ },
326
+ body: JSON.stringify({
327
+ widgetId: props.id,
328
+ session: uuid,
329
+ }),
330
+ },
331
+ );
332
+ const responseJson = await response.json();
333
+
334
+ if (templateName === WIDGET_NAME.STW1) {
335
+ processRotationValueSTW1(container, responseJson.winningSector);
336
+ } else {
337
+ processRotationValueSTW2(container, responseJson.winningSector);
338
+ }
339
+ return true;
340
+ };
341
+
342
+ const processRotationValueSTW1 = (container, winningSector) => {
343
+ const rotationValues = generateRotationValues(
344
+ spikesCount,
345
+ templateName,
346
+ ) as any[];
347
+ let finalSectorTemp = winningSector + 1;
348
+ let random = null;
349
+ let number = 360 * 7;
350
+ if (finalSectorTemp === 1) {
351
+ random =
352
+ 360 -
353
+ Math.floor(
354
+ Math.random() *
355
+ (rotationValues[winningSector].maxDegree -
356
+ rotationValues[winningSector].minDegree +
357
+ 1),
358
+ );
359
+ } else if (finalSectorTemp > 1 && finalSectorTemp <= spikesCount / 2 + 1) {
360
+ random =
361
+ 360 -
362
+ rotationValues[winningSector].minDegree -
363
+ Math.floor(
364
+ Math.random() *
365
+ (rotationValues[winningSector].maxDegree -
366
+ rotationValues[winningSector].minDegree +
367
+ 1),
368
+ );
369
+ } else {
370
+ random =
371
+ Math.floor(
372
+ Math.random() *
373
+ (rotationValues[winningSector].maxDegree -
374
+ rotationValues[winningSector].minDegree +
375
+ 1),
376
+ ) + Math.abs(360 - rotationValues[winningSector].maxDegree);
377
+ }
378
+ number = random + number;
379
+ container.style.transform = 'rotate(' + number + 'deg)';
380
+ valueGenerator();
381
+ };
382
+
383
+ const processRotationValueSTW2 = (container, winningSector) => {
384
+ const rotationValues: any[] = generateRotationValues(
385
+ spikesCount,
386
+ templateName,
387
+ ) as any[];
388
+ let finalSector = winningSector + 1;
389
+ let random = null;
390
+ let idx = rotationValues.findIndex(el => el.value === finalSector);
391
+ if (document.body.clientWidth > 450) {
392
+ if (finalSector >= spikesCount / 2 && finalSector <= spikesCount - 1) {
393
+ random =
394
+ 180 +
395
+ rotationValues[idx].minDegree -
396
+ 180 +
397
+ Math.floor(
398
+ Math.random() *
399
+ (rotationValues[idx].maxDegree -
400
+ rotationValues[idx].minDegree +
401
+ 1),
402
+ );
403
+ } else {
404
+ random =
405
+ rotationValues[idx].minDegree +
406
+ Math.floor(
407
+ Math.random() *
408
+ (rotationValues[idx].maxDegree -
409
+ rotationValues[idx].minDegree +
410
+ 1),
411
+ );
412
+ }
413
+ } else {
414
+ if (finalSector === 1) {
415
+ random =
416
+ 360 -
417
+ Math.floor(
418
+ Math.random() *
419
+ (rotationValues[winningSector].maxDegree -
420
+ rotationValues[winningSector].minDegree +
421
+ 1),
422
+ );
423
+ } else if (finalSector > 1 && finalSector <= spikesCount + 1) {
424
+ random =
425
+ 360 -
426
+ rotationValues[winningSector].minDegree -
427
+ Math.floor(
428
+ Math.random() *
429
+ (rotationValues[winningSector].maxDegree -
430
+ rotationValues[winningSector].minDegree +
431
+ 1),
432
+ );
433
+ } else {
434
+ random =
435
+ Math.floor(
436
+ Math.random() *
437
+ (rotationValues[winningSector].maxDegree -
438
+ rotationValues[winningSector].minDegree +
439
+ 1),
440
+ ) + Math.abs(360 - rotationValues[winningSector].maxDegree);
441
+ }
442
+ }
443
+ let number = 360 * 7;
444
+ number = random + number;
445
+ container.style.transform = 'rotate(' + number + 'deg)';
446
+ valueGenerator();
447
+ };
448
+
449
+ const valueGenerator = () => {
450
+ setTimeout(() => {
451
+ setShowComponents({ ...showComponents, wheel: false, userDetails: true });
452
+ }, 6000);
453
+ };
454
+
455
+ const claimPrizeHandle = async (userInputs: IUserInputs) => {
456
+ let primaryPhoneNumber: string,
457
+ secondaryPhoneNumber: string,
458
+ emailId: string;
459
+ const primaryInfo: IChannelInfo[] = [];
460
+ const secondaryInfo: IChannelInfo[] = [];
461
+ Object.keys(mandatoryOption).map(key => {
462
+ if (mandatoryOption[key]) {
463
+ if (key === CUSTOM_FIELDS) {
464
+ const customFields = userInputs[key];
465
+ Object.keys(customFields || {}).forEach(fieldKey => {
466
+ const fieldId = Number(fieldKey);
467
+ const fieldValue = customFields[fieldKey];
468
+ if (
469
+ mandatoryOption.customFields &&
470
+ Array.isArray(mandatoryOption.customFields) &&
471
+ mandatoryOption.customFields.some(field => field.id === fieldId)
472
+ ) {
473
+ primaryInfo.push({
474
+ channel: 'customField',
475
+ value: fieldValue,
476
+ customFieldId: fieldId,
477
+ });
478
+ }
479
+ });
480
+ } else {
481
+ const value = userInputs[key].countryCodeData
482
+ ? userInputs[key].countryCodeData.dial + userInputs[key].value
483
+ : userInputs[key].value;
484
+ let channel: LEAD_GENERATION_CHANNELS;
485
+ if (key === 'isEmail') {
486
+ channel = LEAD_GENERATION_CHANNELS.EMAIL;
487
+ emailId = value;
488
+ } else if (key === 'isSms') {
489
+ channel = LEAD_GENERATION_CHANNELS.SMS;
490
+ secondaryPhoneNumber = value;
491
+ } else if (key === 'isWhatsapp') {
492
+ channel = LEAD_GENERATION_CHANNELS.WHATSAPP;
493
+ primaryPhoneNumber = value;
494
+ }
495
+ primaryInfo.push({
496
+ channel: channel,
497
+ value: value,
498
+ });
499
+ }
500
+ }
501
+ });
502
+ sameMobileNumberTooglers.sameSMSNo
503
+ ? (userInputs['isWhatsapp'] = {
504
+ ...userInputs['isWhatsapp'],
505
+ countryCodeData: userInputs['isSms'].countryCodeData,
506
+ value: userInputs['isSms'].value,
507
+ })
508
+ : sameMobileNumberTooglers.sameWhatsappNumber
509
+ ? (userInputs['isSms'] = {
510
+ ...userInputs['isSms'],
511
+ countryCodeData: userInputs['isWhatsapp'].countryCodeData,
512
+ value: userInputs['isWhatsapp'].value,
513
+ })
514
+ : '';
515
+
516
+ Object.keys(optionalOptions).map(key => {
517
+ if (optionalOptions[key]) {
518
+ if (key === CUSTOM_FIELDS) {
519
+ const customFields = userInputs[key];
520
+ Object.keys(customFields || {}).forEach(fieldKey => {
521
+ const fieldId = Number(fieldKey);
522
+ const fieldValue = customFields[fieldKey];
523
+ if (
524
+ optionalOptions.customFields &&
525
+ Array.isArray(optionalOptions.customFields) &&
526
+ optionalOptions.customFields.some(field => field.id === fieldId)
527
+ ) {
528
+ secondaryInfo.push({
529
+ channel: 'customField',
530
+ value: fieldValue,
531
+ customFieldId: fieldId,
532
+ });
533
+ }
534
+ });
535
+ } else {
536
+ const value = userInputs[key].countryCodeData
537
+ ? userInputs[key].countryCodeData.dial + userInputs[key].value
538
+ : userInputs[key].value;
539
+ let channel: LEAD_GENERATION_CHANNELS;
540
+ if (key === 'isEmail') {
541
+ channel = LEAD_GENERATION_CHANNELS.EMAIL;
542
+ emailId = value;
543
+ } else if (key === 'isSms') {
544
+ channel = LEAD_GENERATION_CHANNELS.SMS;
545
+ secondaryPhoneNumber = value;
546
+ } else if (key === 'isWhatsapp') {
547
+ channel = LEAD_GENERATION_CHANNELS.WHATSAPP;
548
+ primaryPhoneNumber = value;
549
+ }
550
+ secondaryInfo.push({
551
+ channel: channel,
552
+ value: value,
553
+ });
554
+ }
555
+ }
556
+ });
557
+ setIsLoading(true);
558
+ let disbursedCoupon = undefined;
559
+ if (primaryPhoneNumber) {
560
+ disbursedCoupon = localStorage.getItem(
561
+ `${LOCAL_STORAGE_KEYS.BIK_COUPON_DISBURSED}-${props.id}-${primaryPhoneNumber}`,
562
+ );
563
+ }
564
+ if (!disbursedCoupon && secondaryPhoneNumber) {
565
+ disbursedCoupon = localStorage.getItem(
566
+ `${LOCAL_STORAGE_KEYS.BIK_COUPON_DISBURSED}-${props.id}-${secondaryPhoneNumber}`,
567
+ );
568
+ }
569
+ if (!disbursedCoupon && emailId) {
570
+ disbursedCoupon = localStorage.getItem(
571
+ `${LOCAL_STORAGE_KEYS.BIK_COUPON_DISBURSED}-${props.id}-${emailId}`,
572
+ );
573
+ }
574
+ if (disbursedCoupon) {
575
+ const decryptedData = JSON.parse(decryptBikData(disbursedCoupon));
576
+ setError(
577
+ `Sorry, You already claimed the coupon code "${decryptedData.code}"`,
578
+ );
579
+ setIsLoading(false);
580
+ return;
581
+ }
582
+
583
+ const triggeredIntentDetails = getTriggeredIntentDetails();
584
+
585
+ const data: IPayloadFetchCouponCode = {
586
+ storeId: storeId,
587
+ widgetId: props.id,
588
+ primaryInfo: primaryInfo,
589
+ secondaryInfo: secondaryInfo,
590
+ templateId: templateId,
591
+ session: session,
592
+ triggeredIntentDetails,
593
+ };
594
+ setIsLoading(true);
595
+ const response: any = await fetchCouponCode(data, environment);
596
+ setIsLoading(false);
597
+ if (response.status === 404) {
598
+ setSession(uuidV4());
599
+ if (response.error == 'Customer already exist!') {
600
+ setError('Sorry, You already claimed the prize.');
601
+ } else {
602
+ setError(response.error);
603
+ }
604
+ }
605
+ if (response.status === 403) {
606
+ setSession(uuidV4());
607
+ setError('Session expired! Please try again.');
608
+ }
609
+ if (response.code && response.description) {
610
+ storeDataInLocalStorage(
611
+ LOCAL_STORAGE_KEYS.BIK_PHONE_NUMBER,
612
+ primaryPhoneNumber,
613
+ );
614
+ storeDataInLocalStorage(LOCAL_STORAGE_KEYS.BIK_EMAIL, emailId);
615
+ if (triggers.hideAfterClaimed) {
616
+ setCookie(`bik-${props.id}-claimed`, response.code, 24820);
617
+ }
618
+ setCouponCodeDetails({
619
+ code: response.code,
620
+ description: response.description,
621
+ });
622
+ const stringifiedCouponData = JSON.stringify({
623
+ code: response.code,
624
+ description: response.description,
625
+ });
626
+ if (primaryPhoneNumber) {
627
+ storeDataInLocalStorage(
628
+ `${LOCAL_STORAGE_KEYS.BIK_COUPON_DISBURSED}-${props.id}-${primaryPhoneNumber}`,
629
+ stringifiedCouponData,
630
+ );
631
+ }
632
+ if (secondaryPhoneNumber) {
633
+ storeDataInLocalStorage(
634
+ `${LOCAL_STORAGE_KEYS.BIK_COUPON_DISBURSED}-${props.id}-${secondaryPhoneNumber}`,
635
+ stringifiedCouponData,
636
+ );
637
+ }
638
+ if (emailId) {
639
+ storeDataInLocalStorage(
640
+ `${LOCAL_STORAGE_KEYS.BIK_COUPON_DISBURSED}-${props.id}-${emailId}`,
641
+ stringifiedCouponData,
642
+ );
643
+ }
644
+ setShowComponents({
645
+ ...showComponents,
646
+ wheel: false,
647
+ userDetails: false,
648
+ couponDetails: true,
649
+ });
650
+ }
651
+ };
652
+
653
+ const fabStyle: IFab = {
654
+ icon: <Send color={props.widgetCustomisation?.iconColor} />,
655
+ onClick() {
656
+ setTriggeredIntentDetails({
657
+ triggerSource: TRIGGERED_INTENT_SOURCE.FAB,
658
+ triggerType: TRIGGERED_INTENT_TYPE.FAB_CLICK,
659
+ triggeredPage: getTriggeredPageFromUrl(window.location.href),
660
+ });
661
+ launchModal();
662
+ },
663
+ isMobile: props.isMobile,
664
+ preview: props.preview ?? false,
665
+ widgetCustomisation: {
666
+ iconColor: props.widgetCustomisation?.iconColor,
667
+ fabPositioner: props.widgetCustomisation?.fabPositioner,
668
+ fabBackgroundColor: props.widgetCustomisation?.fabBackgroundColor,
669
+ fabIconLink: props.widgetCustomisation?.fabIconLink,
670
+ fabTransform: props.widgetCustomisation?.fabTransform,
671
+ fabLottie: props.widgetCustomisation?.fabLottie,
672
+ fabAnimationRun: props.widgetCustomisation?.fabAnimationRun,
673
+ fabImage: props.widgetCustomisation?.fabImage,
674
+ fabWebSize: props.widgetCustomisation?.fabWebSize,
675
+ fabMobileSize: props.widgetCustomisation?.fabMobileSize,
676
+ },
677
+ };
678
+
679
+ const onCloseHandle = (
680
+ component: 'wheel' | 'userDetails' | 'couponDetails',
681
+ ) => {
682
+ setShowComponents({
683
+ ...showComponents,
684
+ [component]: false,
685
+ showFab:
686
+ showComponents.couponDetails === true
687
+ ? !!(
688
+ triggers?.fabButtonVisibility &&
689
+ !getCookie(`bik-${props.id}-claimed`) &&
690
+ triggers?.hideAfterClaimed &&
691
+ !getCookie(`bik-${props.id}-modalopened`) &&
692
+ triggers?.frequency
693
+ )
694
+ : triggers?.fabButtonVisibility,
695
+ });
696
+ isModalOpened = !viewLimit;
697
+ document.body.style.overflow = 'unset';
698
+ setError(null);
699
+ };
700
+ return (
701
+ <>
702
+ {getExitIntentHook()}
703
+ {showComponents.showFab && (
704
+ <Fab {...fabStyle} id={`bik-stw-${props.id}-fab`} />
705
+ )}
706
+ {(showComponents.wheel ||
707
+ showComponents.couponDetails ||
708
+ showComponents.userDetails) &&
709
+ STWJSX ? (
710
+ <STWJSX.default
711
+ {...props}
712
+ onSpinHandle={onSpinHandle}
713
+ onCloseHandle={onCloseHandle}
714
+ claimPrizeHandle={claimPrizeHandle}
715
+ error={error}
716
+ isLoading={isLoading}
717
+ setSameMobileNumberTogglers={setSameMobileNumberTogglers}
718
+ sameMobileNumberTogglers={sameMobileNumberTooglers}
719
+ couponCodeDetails={couponCodeDetails}
720
+ showComponents={showComponents}
721
+ templateName={templateName}
722
+ />
723
+ ) : (
724
+ <></>
725
+ )}
726
+ </>
727
+ );
728
+ };
729
+ export default STW;
730
+
731
+ if (process.env.NODE_ENV !== 'development') {
732
+ includeMe(STW);
733
+ }