@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,304 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import parse from 'html-react-parser';
3
+ import {
4
+ addDiscountText,
5
+ colorLuminance,
6
+ getSegmentDetails,
7
+ updateSegmentWidth,
8
+ } from './utility';
9
+ import { ISTWTemplate } from './stw1';
10
+ import SVGFactory, { SVGName } from './components/svgFactory';
11
+ import { decodeTextHelper } from '../utility';
12
+ import {
13
+ BACKGROUND_TYPE,
14
+ ISTWWidgetCustomisation,
15
+ LANGUAGE_VALUES,
16
+ LANGUAGE_ISO_CODES,
17
+ } from '@bikdotai/bik-models/dm';
18
+ import useIsMobile from '../../hooks/useIsMobile';
19
+ import { ComponentStyleMap, injectFontLink } from '../../utilities/styleUtils';
20
+ import { LanguageUtils } from 'utilities/languageUtilities';
21
+
22
+ const Wheel = (props: ISTWTemplate) => {
23
+ const {
24
+ widgetCustomisation,
25
+ onSpinHandle,
26
+ onCloseHandle,
27
+ preview,
28
+ isMobile,
29
+ templateName,
30
+ } = props;
31
+ const {
32
+ fontFamily,
33
+ fontColour,
34
+ backgroundType,
35
+ backgroundColour,
36
+ backgroundImageMobile,
37
+ backgroundImageDesktop,
38
+ playScreenHeading,
39
+ playScreenSubHeading,
40
+ spinnerColor,
41
+ spinnerTextColor,
42
+ spikesCount,
43
+ segmentColor1,
44
+ segmentTextColor1,
45
+ segmentTextColor2,
46
+ segmentColor2,
47
+ discountCodeTitle,
48
+ multiLingualConfigurations,
49
+ } = widgetCustomisation as ISTWWidgetCustomisation;
50
+ const [segmentWidth, setSegmentWidth] = useState<number>(null);
51
+ const [segmentDetailsFinal, setSegmentDetailsFinal] = useState<any[]>([]);
52
+ const [segmentDividerAngle, setSegmentDividerAngle] = useState<number>(null);
53
+ const [currentStyle, setCurrentStyle] = useState<any>(null);
54
+ const isMobileDevice = useIsMobile();
55
+ const languageUtils = new LanguageUtils();
56
+ const [widgetLanguage, setWidgetLanguage] = useState(LANGUAGE_VALUES.ENGLISH);
57
+
58
+ useEffect(() => {
59
+ setSegmentDividerAngle(90 - 360 / (spikesCount * 2));
60
+ setSegmentWidth(
61
+ updateSegmentWidth(spikesCount, preview, isMobile, templateName),
62
+ );
63
+ let segmentDetailsTemp = getSegmentDetails(
64
+ spikesCount,
65
+ segmentColor1,
66
+ segmentColor2,
67
+ discountCodeTitle,
68
+ );
69
+ if (
70
+ discountCodeTitle &&
71
+ Object.keys(discountCodeTitle)?.length &&
72
+ segmentDetailsTemp?.length
73
+ ) {
74
+ segmentDetailsTemp = addDiscountText(
75
+ discountCodeTitle,
76
+ segmentDetailsTemp,
77
+ );
78
+ }
79
+ setSegmentDetailsFinal(segmentDetailsTemp);
80
+ }, [
81
+ preview,
82
+ isMobile,
83
+ spikesCount,
84
+ segmentColor1,
85
+ segmentColor2,
86
+ discountCodeTitle,
87
+ ]);
88
+
89
+ useEffect(() => {
90
+ if (fontFamily && fontFamily?.link) {
91
+ injectFontLink([fontFamily?.link]);
92
+ }
93
+ }, [fontFamily]);
94
+
95
+ const addTextLuminance = color => {
96
+ return colorLuminance(color, -0.5);
97
+ };
98
+
99
+ useEffect(() => {
100
+ if (preview) {
101
+ if (isMobile) {
102
+ ComponentStyleMap[templateName]?.wheelPreviewMobile
103
+ .then()
104
+ .then(async style => {
105
+ setCurrentStyle((await style()).default);
106
+ });
107
+ } else {
108
+ ComponentStyleMap[templateName]?.wheelPreviewDesktop
109
+ .then()
110
+ .then(async style => {
111
+ setCurrentStyle((await style()).default);
112
+ });
113
+ }
114
+ } else {
115
+ ComponentStyleMap[templateName]?.globalStyle.then().then(async style => {
116
+ setCurrentStyle((await style()).default);
117
+ });
118
+ }
119
+ }, [preview, isMobile]);
120
+
121
+ useEffect(() => {
122
+ const isBikURL =
123
+ window.location.href?.includes('https://dashboard.bik.ai/') ||
124
+ window.location.href?.includes('https://staging.dashboard.bik.ai/');
125
+ const previewLanguage = props?.widgetCustomisation?.previewLanguage;
126
+ const storeLanguage =
127
+ (isBikURL ? previewLanguage : window?.Shopify?.locale) ??
128
+ previewLanguage ??
129
+ LANGUAGE_ISO_CODES.EN;
130
+ setWidgetLanguage(languageUtils.getStoreLanguage(storeLanguage));
131
+ }, [window.location.href, props?.widgetCustomisation?.previewLanguage]);
132
+
133
+ if (!currentStyle) {
134
+ return <></>;
135
+ }
136
+
137
+ return (
138
+ <>
139
+ {/* <button onClick={() => setIsMobile(!isMobile)}>Toggle</button> */}
140
+ <div className={currentStyle.bikSpinOverlay}>
141
+ <div className={currentStyle.bikMainWrapper}>
142
+ <div
143
+ className={
144
+ currentStyle.bikCloseBtnWrapper +
145
+ ' ' +
146
+ currentStyle.bikCloseAbsolute
147
+ }
148
+ >
149
+ <div
150
+ className={currentStyle.bikCloseBtn}
151
+ onClick={() => onCloseHandle('wheel')}
152
+ >
153
+ <svg
154
+ width="32"
155
+ height="32"
156
+ viewBox="0 0 32 32"
157
+ fill="none"
158
+ xmlns="http://www.w3.org/2000/svg"
159
+ >
160
+ <path
161
+ d="M24.9428 8.94265C25.4635 8.42195 25.4635 7.57773 24.9428 7.05703C24.4221 6.53633 23.5778 6.53633 23.0572 7.05703L16 14.1142L8.94277 7.05703C8.42207 6.53633 7.57785 6.53633 7.05715 7.05703C6.53645 7.57773 6.53645 8.42195 7.05715 8.94265L14.1143 15.9998L7.05715 23.057C6.53645 23.5777 6.53645 24.4219 7.05715 24.9426C7.57785 25.4633 8.42207 25.4633 8.94277 24.9426L16 17.8855L23.0572 24.9426C23.5778 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"
162
+ fill="#142236"
163
+ />
164
+ </svg>
165
+ </div>
166
+ </div>
167
+ <div
168
+ className={
169
+ currentStyle.bikWrapper + ' ' + currentStyle.bikContainerPadding
170
+ }
171
+ style={
172
+ backgroundType === BACKGROUND_TYPE.COLOUR
173
+ ? { backgroundColor: backgroundColour }
174
+ : {
175
+ background: `url(${isMobileDevice || isMobile ? backgroundImageMobile : backgroundImageDesktop})`,
176
+ backgroundSize: 'contain',
177
+ backgroundRepeat: 'round',
178
+ backgroundPosition: 'top',
179
+ }
180
+ }
181
+ >
182
+ <div id="bik-header1" className={currentStyle.bikHeaderContainer}>
183
+ <div
184
+ id={currentStyle.bikHeader}
185
+ style={{ fontFamily: fontFamily.name, color: fontColour }}
186
+ >
187
+ {parse(
188
+ decodeTextHelper(
189
+ multiLingualConfigurations?.[widgetLanguage]
190
+ ?.playScreenHeading ?? playScreenHeading,
191
+ ),
192
+ )}{' '}
193
+ </div>
194
+ <div
195
+ id={currentStyle.bikSubheader}
196
+ className={`${currentStyle.font16}, ${currentStyle.fontWeight400}`}
197
+ style={{
198
+ fontFamily: fontFamily.name,
199
+ color: fontColour,
200
+ opacity: 0.8,
201
+ }}
202
+ >
203
+ {' '}
204
+ {parse(
205
+ decodeTextHelper(
206
+ multiLingualConfigurations?.[widgetLanguage]
207
+ ?.playScreenSubHeading ?? playScreenSubHeading,
208
+ ),
209
+ )}{' '}
210
+ </div>
211
+ <div
212
+ className={currentStyle.poweredBy}
213
+ style={{ opacity: 0.4 }}
214
+ onClick={() =>
215
+ window.open(
216
+ 'https://bik.ai/?utm_campaign=Spin_The_Wheel_1&utm_medium=Widgets&utm_source=Powered_by_bik',
217
+ )
218
+ }
219
+ >
220
+ <a
221
+ target="_blank"
222
+ rel="noreferrer"
223
+ href="https://bik.ai/?utm_campaign=Spin_The_Wheel_1&utm_medium=Widgets&utm_source=Powered_by_bik"
224
+ style={{ color: fontColour }}
225
+ >
226
+ {languageUtils.getPoweredByMessage(widgetLanguage)}
227
+ </a>
228
+ <SVGFactory name={SVGName.BIK} color={fontColour} />
229
+ </div>
230
+ </div>
231
+ <div className={currentStyle.bikMainContainer}>
232
+ <div className={currentStyle.bikContainerSpinner}>
233
+ <div
234
+ className={currentStyle.bikContainerInner}
235
+ style={{ fontFamily: fontFamily.name }}
236
+ >
237
+ <div className={currentStyle.bikContainerOverlay}></div>
238
+ {segmentDetailsFinal.map((details, index) => {
239
+ return (
240
+ <div
241
+ key={JSON.stringify(details)}
242
+ className={
243
+ currentStyle.bikSegment + ' ' + details.class
244
+ }
245
+ style={{
246
+ backgroundColor: details.color,
247
+ transform: `rotate(${details.rotationValue}deg)`,
248
+ width: `${segmentWidth}px`,
249
+ color:
250
+ (index % 2 === 0
251
+ ? segmentTextColor1
252
+ : segmentTextColor2) ??
253
+ addTextLuminance(details.color),
254
+ }}
255
+ >
256
+ <span
257
+ style={{
258
+ color: 'inherit',
259
+ }}
260
+ className={currentStyle.bikCouponText}
261
+ >
262
+ {details.text}
263
+ </span>
264
+ <span
265
+ id="testing"
266
+ className={currentStyle.bikSegmentDivider}
267
+ style={{
268
+ transform: `rotate(-${segmentDividerAngle}deg)`,
269
+ }}
270
+ ></span>
271
+ </div>
272
+ );
273
+ })}
274
+ </div>
275
+ </div>
276
+ <div
277
+ className={currentStyle.bikContainerSpin}
278
+ onClick={onSpinHandle}
279
+ >
280
+ <div className={currentStyle.bikSpinArrow}></div>
281
+ <div
282
+ id="spin"
283
+ className={currentStyle.bikSpinContent}
284
+ style={{ backgroundColor: spinnerColor }}
285
+ >
286
+ <div
287
+ className={currentStyle.bikSpinLogo}
288
+ style={{
289
+ color: spinnerTextColor ?? addTextLuminance(spinnerColor),
290
+ }}
291
+ >
292
+ SPIN
293
+ </div>
294
+ </div>
295
+ </div>
296
+ </div>
297
+ </div>
298
+ </div>
299
+ </div>
300
+ </>
301
+ );
302
+ };
303
+
304
+ export default Wheel;
@@ -0,0 +1,157 @@
1
+ import React, { Component, ReactNode, RefObject } from 'react';
2
+
3
+ interface ScratchOffProps {
4
+ width?: number;
5
+ height?: number;
6
+ coverImage?: string;
7
+ brushImage?: string;
8
+ children?: ReactNode;
9
+ onScratched: () => void;
10
+ scratchThreshold?: number; //0 to 1
11
+ }
12
+
13
+ interface ScratchOffState {
14
+ isScratching: boolean;
15
+ scratched: boolean;
16
+ }
17
+
18
+ const defaultScratchCover =
19
+ 'data:image/png;base64,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';
20
+ const defaultBrush =
21
+ 'data:image/png;base64,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';
22
+
23
+ class ScratchOff extends Component<ScratchOffProps, ScratchOffState> {
24
+ private canvasRef: RefObject<HTMLCanvasElement>;
25
+ private imageRef: RefObject<HTMLImageElement>;
26
+ private brushImage: HTMLImageElement;
27
+ private scratchThreshold: number;
28
+
29
+ constructor(props) {
30
+ super(props);
31
+ this.state = {
32
+ isScratching: false,
33
+ scratched: false,
34
+ };
35
+
36
+ this.canvasRef = React.createRef();
37
+ this.imageRef = React.createRef();
38
+ this.brushImage = new Image();
39
+ this.brushImage.src = defaultBrush;
40
+ this.scratchThreshold =
41
+ (this.props.width || 100) * (this.props.height || 40) * 0.5;
42
+ }
43
+
44
+ componentDidMount() {
45
+ this.initializeCanvas();
46
+ }
47
+
48
+ initializeCanvas() {
49
+ const canvas = this.canvasRef.current;
50
+ const ctx = canvas.getContext('2d');
51
+
52
+ // Set the size of the canvas
53
+ canvas.width = this.props.width || 200;
54
+ canvas.height = this.props.height || 40;
55
+
56
+ // Load the cover image
57
+ const image = new Image();
58
+ image.src = this.props.coverImage || defaultScratchCover;
59
+ image.onload = () => {
60
+ // Draw the image on the canvas
61
+ ctx!.drawImage(image, 0, 0, canvas.width, canvas.height);
62
+ };
63
+
64
+ // Set up event listeners for both mouse and touch events
65
+ canvas.addEventListener('mousedown', this.startScratching);
66
+ canvas.addEventListener('mousemove', this.handleScratching);
67
+ canvas.addEventListener('mouseup', this.stopScratching);
68
+ //canvas.addEventListener('mouseleave', this.stopScratching);
69
+
70
+ canvas.addEventListener('touchstart', this.startScratching);
71
+ canvas.addEventListener('touchmove', this.handleTouchScratching);
72
+ canvas.addEventListener('touchend', this.stopScratching);
73
+ }
74
+
75
+ startScratching = () => {
76
+ this.setState({ isScratching: true });
77
+ };
78
+
79
+ stopScratching = () => {
80
+ this.setState({ isScratching: false });
81
+ };
82
+
83
+ handleScratching = e => {
84
+ if (this.state.isScratching) {
85
+ this.scratch(e);
86
+ }
87
+ };
88
+
89
+ handleTouchScratching = e => {
90
+ if (this.state.isScratching) {
91
+ // Prevent the default touch move behavior, which may scroll the page
92
+ e.preventDefault();
93
+ this.scratch(e.touches[0]);
94
+ }
95
+ };
96
+
97
+ scratch(touch) {
98
+ const canvas = this.canvasRef.current;
99
+ const ctx = canvas.getContext('2d');
100
+ const { clientX, clientY } = touch;
101
+ const { left, top } = canvas.getBoundingClientRect();
102
+
103
+ // Calculate the position of the touch relative to the canvas
104
+ const x = clientX - left;
105
+ const y = clientY - top;
106
+
107
+ // Save the current context state to restore later
108
+ ctx!.save();
109
+
110
+ // Change the global composite operation to source-over for drawing the brush
111
+ ctx!.globalCompositeOperation = 'destination-out';
112
+
113
+ // Draw the brush image at the current touch position
114
+ ctx!.drawImage(
115
+ this.brushImage,
116
+ x - this.brushImage.width / 2,
117
+ y - this.brushImage.height / 2,
118
+ );
119
+
120
+ // Restore the previous context state
121
+ ctx!.restore();
122
+
123
+ // Check if the entire canvas has been scratched off (no visible cover)
124
+ const imageData = ctx!.getImageData(0, 0, canvas.width, canvas.height);
125
+ const clearedPixels = Array.from(imageData.data).filter(
126
+ value => value === 0,
127
+ ).length;
128
+
129
+ if (clearedPixels >= this.scratchThreshold) {
130
+ // If the threshold is met, automatically scratch the remaining area
131
+ this.autoScratch(canvas, ctx);
132
+ }
133
+ }
134
+
135
+ autoScratch(canvas, ctx) {
136
+ // Clear the entire canvas to reveal the content
137
+ ctx!.clearRect(0, 0, canvas.width, canvas.height);
138
+ // Draw the text or content
139
+ this.setState({ scratched: true });
140
+ this.props.onScratched();
141
+ }
142
+
143
+ render() {
144
+ const { scratched } = this.state;
145
+ const { children } = this.props;
146
+ return (
147
+ <div>
148
+ <canvas ref={this.canvasRef} style={{ cursor: 'pointer' }}>
149
+ Your browser does not support the HTML5 canvas element.
150
+ </canvas>
151
+ {scratched && children}
152
+ </div>
153
+ );
154
+ }
155
+ }
156
+
157
+ export default ScratchOff;
@@ -0,0 +1,152 @@
1
+ const config = {
2
+ preview: false,
3
+ id: 'id',
4
+ environment: 'staging',
5
+ visibility: {
6
+ visiblePages: ['/*'],
7
+ triggers: {
8
+ fabButtonVisibility: true,
9
+ hasFAbButton: true,
10
+ isPlayable: false,
11
+ pageScroll: 10,
12
+ viewLimit: 2000,
13
+ playLimit: null,
14
+ timeDelay: null,
15
+ frequency: 24,
16
+ exitIntentTimeDelay: 1,
17
+ },
18
+ },
19
+ leadGeneration: {
20
+ mandatoryOption: {
21
+ isEmail: false,
22
+ isSms: false,
23
+ isWhatsapp: true,
24
+ },
25
+ optionalOption: {
26
+ isSms: true,
27
+ isWhatsapp: false,
28
+ isEmail: true,
29
+ },
30
+ optionalOptions: {
31
+ isSms: true,
32
+ isWhatsapp: false,
33
+ isEmail: true,
34
+ },
35
+ },
36
+ info: {
37
+ storeId: 'storeId',
38
+ },
39
+ widgetCustomisation: {
40
+ postPlayScreenBackgroundColour: '#ffffff',
41
+ winningScreenBackgroundColour: '#ffffff',
42
+ cardTitle: 'Scratch & Win!',
43
+ cardTheme: 'linear-gradient(220.24deg, #E8465E 26.59%, #FED56E 88.17%)',
44
+ cardDesktopImg:
45
+ 'https://firebasestorage.googleapis.com/v0/b/bikayi-chat.appspot.com/o/images-uid%2Fb14f911b-25e7-47f1-b8f4-59b1fdb11288?alt=media&token=2074d0e7-f7b4-4779-94dd-d24b77340dca',
46
+ cardMobileImg:
47
+ 'https://firebasestorage.googleapis.com/v0/b/bikayi-chat.appspot.com/o/images-uid%2F03395f2c-c8d6-44e1-86f2-e45429da2621?alt=media&token=818eee8d-3157-4a33-ad3c-86b7e22dfd28',
48
+ fabBackgroundColor: '#000000',
49
+ fabMobileSize: 50,
50
+ fabWebSize: 50,
51
+ fabPosition: 'BOTTOM_RIGHT',
52
+ fabPositioner: {
53
+ bottom: '30px',
54
+ right: '30px',
55
+ },
56
+ iconColor: '#ffffff',
57
+ fabIconLink:
58
+ 'https://storage.googleapis.com/bik-widget-mfe/bap%2Ffab-assets%2Ficons%2Fbik%2Fgift.svg',
59
+ imageType: 'TEXT_BASED',
60
+ backgroundImage:
61
+ 'https://firebasestorage.googleapis.com/v0/b/bikayi-chat.appspot.com/o/images-uid%2Fb14f911b-25e7-47f1-b8f4-59b1fdb11288?alt=media&token=2074d0e7-f7b4-4779-94dd-d24b77340dca',
62
+ scratchLayerColor: '#F5F5F5',
63
+ postPlayScreenTitle: '<p><strong>Special prize only for you!</strong></p>',
64
+ postPlayScreenSubTitle: '<p>You have won discount code</p>',
65
+ postPlayScreenButtonText: 'Claim the price',
66
+ postPlayScreenButtonTextColour: '#ffffff',
67
+ postPlayScreenButtonColour: '#000000',
68
+ winningScreenTitle: '<p><strong>Congratulations!</strong></p>',
69
+ winningScreenSubTitle: '<p>To claim prize fill the details below</p>',
70
+ winningScreenCouponBgColour: '#ffffff',
71
+ winningScreenCouponTextColour: '#000000',
72
+ winningScreenButtonColour: '#000000',
73
+ winningScreenButtonTextColour: '#ffffff',
74
+ winningScreenButtonText: 'Copy and use discount',
75
+ winningScreenIcon:
76
+ 'https://storage.googleapis.com/bik-widget-mfe/bap%2Fpost-play-screen-assets%2Fimages%2Fbik%2FconfettiOne.png',
77
+ widgetName: 'Scratch the card sxmo',
78
+ backgroundType: 'colour',
79
+ backgroundColour: '#ffffff',
80
+ fontFamily: {
81
+ name: 'Inter',
82
+ link: 'https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&display=swap',
83
+ },
84
+ fontColour: '#000000',
85
+ multiLingualConfigurations: {
86
+ ENGLISH: {
87
+ cardTitle: 'Scratch & Win!',
88
+ postPlayScreenTitle:
89
+ '<p><strong>Special prize only for you!</strong></p>',
90
+ postPlayScreenSubTitle: '<p>You have won discount code</p>',
91
+ postPlayScreenButtonText: 'Claim the price',
92
+ winningScreenTitle: '<p><strong>Congratulations!</strong></p>',
93
+ winningScreenSubTitle: '<p>To claim prize fill the details below</p>',
94
+ winningScreenButtonText: 'Copy and use discount',
95
+ },
96
+ ARABIC: {
97
+ cardTitle: 'خدش واربح!',
98
+ postPlayScreenTitle: '<p><strong>جائزة خاصة فقط لك!</strong></p>',
99
+ postPlayScreenSubTitle: '<p>لقد فزت برمز خصم</p>',
100
+ postPlayScreenButtonText: 'ادعي السعر',
101
+ winningScreenTitle: '<p><strong>تهانينا!</strong></p>',
102
+ winningScreenSubTitle:
103
+ '<p>للحصول على الجائزة، قم بملء التفاصيل أدناه</p>',
104
+ winningScreenButtonText: 'انسخ واستخدم الخصم',
105
+ },
106
+ FRENCH: {
107
+ cardTitle: 'Grattez et gagnez!',
108
+ postPlayScreenTitle:
109
+ '<p><strong>Prix spécial uniquement pour vous!</strong></p>',
110
+ postPlayScreenSubTitle: '<p>Vous avez gagné un code de réduction</p>',
111
+ postPlayScreenButtonText: 'Réclamer le prix',
112
+ winningScreenTitle: '<p><strong>Félicitations!</strong></p>',
113
+ winningScreenSubTitle:
114
+ '<p>Pour réclamer le prix, remplissez les détails ci-dessous</p>',
115
+ winningScreenButtonText: 'Copier et utiliser la réduction',
116
+ },
117
+ SPANISH: {
118
+ cardTitle: '¡Rasca y gana!',
119
+ postPlayScreenTitle:
120
+ '<p><strong>¡Premio especial solo para ti!</strong></p>',
121
+ postPlayScreenSubTitle: '<p>Has ganado un código de descuento</p>',
122
+ postPlayScreenButtonText: 'Reclama el precio',
123
+ winningScreenTitle: '<p><strong>¡Felicidades!</strong></p>',
124
+ winningScreenSubTitle:
125
+ '<p>Para reclamar el premio, complete los detalles a continuación</p>',
126
+ winningScreenButtonText: 'Copiar y usar el descuento',
127
+ },
128
+ MALAY: {
129
+ cardTitle: 'Gores dan Menang!',
130
+ postPlayScreenTitle:
131
+ '<p><strong>Hadiah istimewa hanya untuk anda!</strong></p>',
132
+ postPlayScreenSubTitle: '<p>Anda telah memenangi kod diskaun</p>',
133
+ postPlayScreenButtonText: 'Tuntut hadiah',
134
+ winningScreenTitle: '<p><strong>Tahniah!</strong></p>',
135
+ winningScreenSubTitle:
136
+ '<p>Untuk menuntut hadiah, isikan butiran di bawah</p>',
137
+ winningScreenButtonText: 'Salin dan gunakan diskaun',
138
+ },
139
+ },
140
+ discountTitle: 'af',
141
+ },
142
+ storeWidgetConfig: {
143
+ '/*': [
144
+ {
145
+ widgetId: 'id',
146
+ fabPosition: 'BOTTOM_LEFT',
147
+ },
148
+ ],
149
+ },
150
+ };
151
+
152
+ export default config;