@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,76 @@
1
+ import React, { useContext, useState, useEffect } from 'react';
2
+ import { STWContext } from '../../widgets/STW/context';
3
+ import useIsMobile from '../../hooks/useIsMobile';
4
+
5
+ const SelectedCountry: React.FC<{
6
+ toggleDropDown: (flag: boolean) => void;
7
+ showDropdown: boolean;
8
+ fontColour: string;
9
+ selectedCountryData: { code: string; dial: string };
10
+ }> = ({ toggleDropDown, showDropdown, selectedCountryData, fontColour }) => {
11
+ const { preview, isMobile } = useContext(STWContext);
12
+ const isMobileDevice = useIsMobile();
13
+ const [currentStyle, setCurrentStyle] = useState<null | {
14
+ [key: string]: string;
15
+ }>(null);
16
+
17
+ useEffect(() => {
18
+ const importStyles = async () => {
19
+ let stylesModule;
20
+ if (preview) {
21
+ if (isMobile) {
22
+ stylesModule = await import(
23
+ './selectedCountryPreviewMobile.module.css'
24
+ );
25
+ } else {
26
+ stylesModule = await import(
27
+ './selectedCountryPreviewDesktop.module.css'
28
+ );
29
+ }
30
+ } else {
31
+ stylesModule = await import('./selectedCountry.module.css');
32
+ }
33
+ setCurrentStyle(stylesModule.default);
34
+ };
35
+ importStyles().then();
36
+ }, [preview, isMobile]);
37
+
38
+ if (!currentStyle) {
39
+ return <></>;
40
+ }
41
+
42
+ return (
43
+ <div
44
+ className={currentStyle.bikStwCountryCodePicker}
45
+ onClick={() => toggleDropDown(!showDropdown)}
46
+ style={
47
+ preview
48
+ ? {}
49
+ : {
50
+ height: isMobileDevice ? 50 : 58,
51
+ paddingLeft: '20px',
52
+ paddingRight: '20px',
53
+ }
54
+ }
55
+ >
56
+ <div className={currentStyle.bikStwCountryCodeContainer}>
57
+ <img
58
+ alt={''}
59
+ className={currentStyle.bikStwCountryFlag}
60
+ src={`https://flagcdn.com/${selectedCountryData.code.toLowerCase()}.svg`}
61
+ />
62
+ <div
63
+ className={currentStyle.bikStwH2}
64
+ style={{ color: fontColour, margin: 0 }}
65
+ >
66
+ {selectedCountryData.dial}
67
+ </div>
68
+ <div
69
+ className={currentStyle.bikStwDownArrow}
70
+ style={{ borderTopColor: fontColour }}
71
+ ></div>
72
+ </div>
73
+ </div>
74
+ );
75
+ };
76
+ export default SelectedCountry;
@@ -0,0 +1,56 @@
1
+ .bikStwCountryCodePicker {
2
+ pointer-events: none;
3
+ height: 18px;
4
+ border-radius: 8px;
5
+ border-width: 1px;
6
+ border-style: solid;
7
+ align-items: center;
8
+ border-color: #e0e0e0;
9
+ padding: 2px 4px;
10
+ gap: 8px;
11
+ display: flex;
12
+ flex-direction: row;
13
+ font-family: inherit;
14
+ background-color: rgba(256, 256, 256, 0.3);
15
+ }
16
+
17
+ .bikStwCountryCodeContainer {
18
+ gap: 4px;
19
+ display: flex;
20
+ align-items: center;
21
+ flex-direction: row;
22
+ font-family: inherit;
23
+ }
24
+
25
+ .bikStwCountryFlag {
26
+ width: 12px;
27
+ height: auto;
28
+ position: unset;
29
+ }
30
+
31
+ .bikStwH2 {
32
+ font-family: inherit;
33
+ font-style: normal;
34
+ font-weight: 400;
35
+ font-size: 8px;
36
+ line-height: 10px;
37
+ font-feature-settings:
38
+ 'tnum' on,
39
+ 'lnum' on,
40
+ 'case' on,
41
+ 'ss04' on;
42
+ color: #212121;
43
+ margin-bottom: 0;
44
+ }
45
+
46
+ .bikStwDownArrow {
47
+ width: 0;
48
+ height: 0;
49
+ border-left: 3px solid transparent;
50
+ border-right: 3px solid transparent;
51
+ border-top: 4px solid #616161;
52
+ font-size: 0;
53
+ line-height: 0;
54
+ float: left;
55
+ display: block !important;
56
+ }
@@ -0,0 +1,57 @@
1
+ .bikStwCountryCodePicker {
2
+ pointer-events: none;
3
+ height: 22px;
4
+ border-radius: 8px;
5
+ margin-top: 4px;
6
+ border-width: 1px;
7
+ border-style: solid;
8
+ align-items: center;
9
+ border-color: #e0e0e0;
10
+ padding: 8px 6px;
11
+ gap: 8px;
12
+ display: flex;
13
+ flex-direction: row;
14
+ font-family: inherit;
15
+ background-color: rgba(256, 256, 256, 0.3);
16
+ }
17
+
18
+ .bikStwCountryCodeContainer {
19
+ gap: 4px;
20
+ display: flex;
21
+ align-items: center;
22
+ flex-direction: row;
23
+ font-family: inherit;
24
+ }
25
+
26
+ .bikStwCountryFlag {
27
+ width: 12px;
28
+ height: auto;
29
+ position: unset;
30
+ }
31
+
32
+ .bikStwH2 {
33
+ font-family: inherit;
34
+ font-style: normal;
35
+ font-weight: 400;
36
+ font-size: 8px;
37
+ line-height: 10px;
38
+ font-feature-settings:
39
+ 'tnum' on,
40
+ 'lnum' on,
41
+ 'case' on,
42
+ 'ss04' on;
43
+ color: #212121;
44
+ margin-bottom: 0;
45
+ }
46
+
47
+ .bikStwDownArrow {
48
+ width: 0;
49
+ height: 0;
50
+ border-left: 3px solid transparent;
51
+ border-right: 3px solid transparent;
52
+ border-top: 4px solid #616161;
53
+ font-size: 0;
54
+ line-height: 0;
55
+ float: left;
56
+ display: block !important;
57
+ }
@@ -0,0 +1,333 @@
1
+ import React, { useContext, useMemo } from 'react';
2
+ import Checkbox from 'components/inputComponents/Checkbox';
3
+ import { InputBox } from 'components/inputComponents/InputBox';
4
+ import { Dropdown } from 'components/inputComponents/Dropdown';
5
+ import DatePicker from 'components/inputComponents/DatePicker';
6
+ import {
7
+ CustomField,
8
+ UserFields,
9
+ CustomFieldError,
10
+ CustomFieldValue,
11
+ } from '../../types/customFields';
12
+ import { STWContext } from '../../widgets/STW/context';
13
+ import useIsMobile from '../../hooks/useIsMobile';
14
+
15
+ type RenderCustomFieldsProps = {
16
+ id?: string;
17
+ customFields: CustomField[];
18
+ userInputs?: UserFields;
19
+ setUserInputs?: (
20
+ inputs: UserFields | ((prev: UserFields) => UserFields),
21
+ ) => void;
22
+ isRequired: boolean;
23
+ customFieldErrors?: CustomFieldError;
24
+ setCustomFieldErrors?: (
25
+ errors: CustomFieldError | ((prev: CustomFieldError) => CustomFieldError),
26
+ ) => void;
27
+ fontColour?: string;
28
+ onFocusColour?: string;
29
+ backgroundColor?: string;
30
+ };
31
+
32
+ const RenderCustomFields: React.FC<RenderCustomFieldsProps> = ({
33
+ id,
34
+ customFields,
35
+ userInputs,
36
+ setUserInputs,
37
+ isRequired,
38
+ customFieldErrors,
39
+ setCustomFieldErrors,
40
+ fontColour,
41
+ backgroundColor = '#F2F9FF',
42
+ }) => {
43
+ const { preview, isMobile } = useContext(STWContext);
44
+ const isMobileDevice = useIsMobile();
45
+
46
+ const inputHeight = useMemo(() => {
47
+ if (preview) {
48
+ return 20;
49
+ }
50
+
51
+ return isMobileDevice ? 48 : 56;
52
+ }, [preview, isMobileDevice]);
53
+
54
+ // Container style for each custom field
55
+ const containerStyle = useMemo<React.CSSProperties>(
56
+ () => ({
57
+ marginTop: preview ? 4 : 12,
58
+ fontFamily: 'inherit',
59
+ fontSize: preview ? '8px' : '14px',
60
+ }),
61
+ [preview],
62
+ );
63
+
64
+ // Returns style object for InputBox, highlighting errors if present
65
+ const getInputBoxStyle = (
66
+ fieldError?: string,
67
+ ): React.CSSProperties & Record<string, string> => ({
68
+ '--bik-inputBox-text-color': fieldError ? '#b92321' : fontColour,
69
+ '--bik-inputBox-label-color': fieldError ? '#b92321' : fontColour,
70
+ '--bik-inputBox-border-color': fieldError ? '#b92321' : '#e0e0e0',
71
+ '--bik-inputBox-error-border-color': '#b92321',
72
+ '--bik-inputBox-min-height': `${inputHeight}px`,
73
+ });
74
+
75
+ const getFieldValue = (
76
+ field: CustomField,
77
+ defaultValue: CustomFieldValue = '',
78
+ ) => {
79
+ const value = userInputs?.customFields?.[field.id];
80
+ const fieldExists =
81
+ userInputs?.customFields && field.id in userInputs.customFields;
82
+
83
+ if (fieldExists) {
84
+ if (field.fieldType === 'number' && value === null) {
85
+ return '';
86
+ }
87
+ return value;
88
+ }
89
+
90
+ switch (field.fieldType) {
91
+ case 'checkbox':
92
+ return false;
93
+ case 'multiselect_dropdown':
94
+ return [];
95
+ case 'number':
96
+ return defaultValue === '' ? '' : defaultValue;
97
+ default:
98
+ return defaultValue;
99
+ }
100
+ };
101
+
102
+ const updateFieldValue = (fieldId: number, value: CustomFieldValue) => {
103
+ setUserInputs?.((prevInputs: UserFields) => ({
104
+ ...prevInputs,
105
+ customFields: {
106
+ ...prevInputs?.customFields,
107
+ [fieldId]: value,
108
+ },
109
+ }));
110
+
111
+ if (setCustomFieldErrors) {
112
+ setCustomFieldErrors((prevErrors: CustomFieldError) => {
113
+ const newErrors = { ...prevErrors };
114
+ delete newErrors[fieldId];
115
+ return newErrors;
116
+ });
117
+ }
118
+ };
119
+
120
+ return (
121
+ <div>
122
+ {customFields.map((field, index) => {
123
+ const fieldError = customFieldErrors?.[field.id];
124
+ const fieldId = `bik-${id}-custom-field-${field.fieldType}-${field.id}`;
125
+
126
+ switch (field.fieldType) {
127
+ case 'single_line':
128
+ return (
129
+ <div
130
+ key={`${field.id}-single-line-${index}`}
131
+ style={containerStyle}
132
+ >
133
+ <div style={getInputBoxStyle(fieldError)}>
134
+ <InputBox
135
+ id={fieldId}
136
+ value={getFieldValue(field) as string}
137
+ labelText={field.fieldName}
138
+ onChange={(value: string) => {
139
+ updateFieldValue(field.id, value);
140
+ }}
141
+ inputType="text"
142
+ isRequired={isRequired}
143
+ maxCharacters={50}
144
+ errorMessage={fieldError || undefined}
145
+ inputHeight={inputHeight}
146
+ fontColour={fieldError ? '#b92321' : fontColour}
147
+ isPreview={preview}
148
+ />
149
+ </div>
150
+ </div>
151
+ );
152
+
153
+ case 'multi_line':
154
+ return (
155
+ <div
156
+ key={`${field.id}-multi-line-${index}`}
157
+ style={containerStyle}
158
+ >
159
+ <div style={getInputBoxStyle(fieldError)}>
160
+ <InputBox
161
+ id={fieldId}
162
+ value={getFieldValue(field) as string}
163
+ labelText={field.fieldName}
164
+ onChange={(value: string) => {
165
+ updateFieldValue(field.id, value);
166
+ }}
167
+ inputType="text"
168
+ isMultiline
169
+ isRequired={isRequired}
170
+ maxCharacters={500}
171
+ textareaRows={preview ? 2 : 3}
172
+ errorMessage={fieldError || undefined}
173
+ inputHeight={inputHeight}
174
+ fontColour={fieldError ? '#b92321' : fontColour}
175
+ backgroundColor={backgroundColor}
176
+ isPreview={preview}
177
+ />
178
+ </div>
179
+ </div>
180
+ );
181
+
182
+ case 'number':
183
+ return (
184
+ <div key={`${field.id}-number-${index}`} style={containerStyle}>
185
+ <div style={getInputBoxStyle(fieldError)}>
186
+ <InputBox
187
+ id={fieldId}
188
+ value={getFieldValue(field) as string}
189
+ labelText={field.fieldName}
190
+ onChange={(value: string) => {
191
+ const numericValue =
192
+ value.trim() === '' ? null : Number(value);
193
+ updateFieldValue(field.id, numericValue);
194
+ }}
195
+ inputType="number"
196
+ isRequired={isRequired}
197
+ minValue={Number.MIN_SAFE_INTEGER}
198
+ maxValue={Number.MAX_SAFE_INTEGER}
199
+ stepValue={1}
200
+ errorMessage={fieldError || undefined}
201
+ inputHeight={inputHeight}
202
+ fontColour={fieldError ? '#b92321' : fontColour}
203
+ isPreview={preview}
204
+ />
205
+ </div>
206
+ </div>
207
+ );
208
+
209
+ case 'checkbox': {
210
+ return (
211
+ <div key={`${field.id}-checkbox-${index}`} style={containerStyle}>
212
+ <Checkbox
213
+ id={fieldId}
214
+ label={field.fieldName}
215
+ checked={getFieldValue(field) as boolean}
216
+ onChange={(checked: boolean) => {
217
+ updateFieldValue(field.id, checked);
218
+ }}
219
+ iconSize={preview ? (isMobile ? 8 : 10) : 14}
220
+ isPreview={preview}
221
+ fontColour={fieldError ? '#b92321' : fontColour}
222
+ />
223
+ </div>
224
+ );
225
+ }
226
+
227
+ case 'date':
228
+ return (
229
+ <div key={`${field.id}-date-${index}`} style={containerStyle}>
230
+ <DatePicker
231
+ id={fieldId}
232
+ label={field.fieldName}
233
+ value={getFieldValue(field) as string}
234
+ onChange={(value: string) => {
235
+ updateFieldValue(field.id, value);
236
+ }}
237
+ isRequired={isRequired}
238
+ error={fieldError || undefined}
239
+ isPreview={preview}
240
+ fontColour={fieldError ? '#b92321' : fontColour}
241
+ />
242
+ </div>
243
+ );
244
+
245
+ case 'date_time':
246
+ return (
247
+ <div
248
+ key={`${field.id}-date-time-${index}`}
249
+ style={containerStyle}
250
+ >
251
+ <DatePicker
252
+ id={fieldId}
253
+ label={field.fieldName}
254
+ value={getFieldValue(field) as string}
255
+ onChange={(value: string) => {
256
+ updateFieldValue(field.id, value);
257
+ }}
258
+ isRequired={isRequired}
259
+ includeTime={true}
260
+ error={fieldError || undefined}
261
+ isPreview={preview}
262
+ fontColour={fieldError ? '#b92321' : fontColour}
263
+ />
264
+ </div>
265
+ );
266
+
267
+ case 'dropdown':
268
+ return (
269
+ <div key={`${field.id}-dropdown-${index}`} style={containerStyle}>
270
+ <Dropdown
271
+ id={fieldId}
272
+ label={field.fieldName}
273
+ value={(() => {
274
+ const value = getFieldValue(field);
275
+ return Array.isArray(value)
276
+ ? value
277
+ : value != null && value !== ''
278
+ ? [value as string]
279
+ : [];
280
+ })()}
281
+ options={(field.options || []).map((option: string) => ({
282
+ value: option,
283
+ label: option,
284
+ }))}
285
+ onChange={(value: string[]) => {
286
+ const selectedValue = value.length > 0 ? value[0] : null;
287
+ updateFieldValue(field.id, selectedValue);
288
+ }}
289
+ isRequired={isRequired}
290
+ isMultiSelect={false}
291
+ closeOnSelect={true}
292
+ error={fieldError || undefined}
293
+ isPreview={preview}
294
+ fontColour={fieldError ? '#b92321' : fontColour}
295
+ />
296
+ </div>
297
+ );
298
+
299
+ case 'multiselect_dropdown':
300
+ return (
301
+ <div
302
+ key={`${field.id}-multiselect-dropdown-${index}`}
303
+ style={containerStyle}
304
+ >
305
+ <Dropdown
306
+ id={fieldId}
307
+ label={field.fieldName}
308
+ value={getFieldValue(field, []) as string[]}
309
+ options={(field?.options ?? []).map((option: string) => ({
310
+ value: option,
311
+ label: option,
312
+ }))}
313
+ onChange={(value: string[]) => {
314
+ updateFieldValue(field.id, value);
315
+ }}
316
+ isRequired={isRequired}
317
+ isMultiSelect={true}
318
+ showSelectAll={true}
319
+ error={fieldError || undefined}
320
+ isPreview={preview}
321
+ fontColour={fieldError ? '#b92321' : fontColour}
322
+ />
323
+ </div>
324
+ );
325
+
326
+ default:
327
+ return null;
328
+ }
329
+ })}
330
+ </div>
331
+ );
332
+ };
333
+ export default RenderCustomFields;