@solucx/react-native-solucx-widget 0.2.4 → 2.0.7

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 (256) hide show
  1. package/README.md +526 -182
  2. package/lib/SoluCXWidget.d.ts +50 -7
  3. package/lib/SoluCXWidget.d.ts.map +1 -1
  4. package/lib/SoluCXWidget.js +105 -100
  5. package/lib/SoluCXWidget.js.map +1 -1
  6. package/lib/SoluCXWidgetHost.d.ts +3 -0
  7. package/lib/SoluCXWidgetHost.d.ts.map +1 -0
  8. package/lib/SoluCXWidgetHost.js +34 -0
  9. package/lib/SoluCXWidgetHost.js.map +1 -0
  10. package/lib/SoluCXWidgetView.d.ts +12 -0
  11. package/lib/SoluCXWidgetView.d.ts.map +1 -0
  12. package/lib/SoluCXWidgetView.js +61 -0
  13. package/lib/SoluCXWidgetView.js.map +1 -0
  14. package/lib/components/CloseButton.d.ts +1 -1
  15. package/lib/components/CloseButton.d.ts.map +1 -1
  16. package/lib/components/CloseButton.js +4 -1
  17. package/lib/components/CloseButton.js.map +1 -1
  18. package/lib/components/InlineWidget.d.ts.map +1 -1
  19. package/lib/components/InlineWidget.js +2 -7
  20. package/lib/components/InlineWidget.js.map +1 -1
  21. package/lib/components/ModalWidget.d.ts +1 -1
  22. package/lib/components/ModalWidget.d.ts.map +1 -1
  23. package/lib/components/ModalWidget.js +3 -16
  24. package/lib/components/ModalWidget.js.map +1 -1
  25. package/lib/components/OverlayWidget.d.ts.map +1 -1
  26. package/lib/components/OverlayWidget.js +5 -15
  27. package/lib/components/OverlayWidget.js.map +1 -1
  28. package/lib/components/index.d.ts +5 -0
  29. package/lib/components/index.d.ts.map +1 -0
  30. package/lib/components/index.js +12 -0
  31. package/lib/components/index.js.map +1 -0
  32. package/lib/constants/Constants.d.ts +11 -0
  33. package/lib/constants/Constants.d.ts.map +1 -1
  34. package/lib/constants/Constants.js +16 -1
  35. package/lib/constants/Constants.js.map +1 -1
  36. package/lib/{interfaces → domain}/WidgetCallbacks.d.ts +2 -2
  37. package/lib/domain/WidgetCallbacks.d.ts.map +1 -0
  38. package/lib/domain/WidgetCallbacks.js.map +1 -0
  39. package/{src/interfaces/WidgetData.ts → lib/domain/WidgetData.d.ts} +5 -2
  40. package/lib/domain/WidgetData.d.ts.map +1 -0
  41. package/lib/{interfaces → domain}/WidgetData.js.map +1 -1
  42. package/lib/domain/WidgetDisplayResult.d.ts +6 -0
  43. package/lib/domain/WidgetDisplayResult.d.ts.map +1 -0
  44. package/lib/domain/WidgetDisplayResult.js +3 -0
  45. package/lib/domain/WidgetDisplayResult.js.map +1 -0
  46. package/lib/domain/WidgetOptions.d.ts +27 -0
  47. package/lib/domain/WidgetOptions.d.ts.map +1 -0
  48. package/lib/domain/WidgetOptions.js +30 -0
  49. package/lib/domain/WidgetOptions.js.map +1 -0
  50. package/lib/domain/WidgetResponse.d.ts +5 -0
  51. package/lib/domain/WidgetResponse.d.ts.map +1 -0
  52. package/lib/{interfaces/WidgetOptions.js → domain/WidgetResponse.js} +1 -1
  53. package/lib/domain/WidgetResponse.js.map +1 -0
  54. package/lib/domain/WidgetSamplerLog.d.ts +12 -0
  55. package/lib/domain/WidgetSamplerLog.d.ts.map +1 -0
  56. package/lib/domain/WidgetSamplerLog.js.map +1 -0
  57. package/lib/{interfaces → domain}/index.d.ts +1 -2
  58. package/lib/domain/index.d.ts.map +1 -0
  59. package/lib/{interfaces → domain}/index.js.map +1 -1
  60. package/lib/hooks/index.d.ts +2 -2
  61. package/lib/hooks/index.d.ts.map +1 -1
  62. package/lib/hooks/index.js +5 -5
  63. package/lib/hooks/index.js.map +1 -1
  64. package/lib/hooks/useClientVersionCollector.d.ts +3 -0
  65. package/lib/hooks/useClientVersionCollector.d.ts.map +1 -0
  66. package/lib/{services/ClientVersionCollector.js → hooks/useClientVersionCollector.js} +7 -2
  67. package/lib/hooks/useClientVersionCollector.js.map +1 -0
  68. package/lib/hooks/useHeightAnimation.d.ts +0 -1
  69. package/lib/hooks/useHeightAnimation.d.ts.map +1 -1
  70. package/lib/hooks/useHeightAnimation.js +4 -2
  71. package/lib/hooks/useHeightAnimation.js.map +1 -1
  72. package/lib/hooks/useWidget.d.ts +13 -0
  73. package/lib/hooks/useWidget.d.ts.map +1 -0
  74. package/lib/hooks/useWidget.js +44 -0
  75. package/lib/hooks/useWidget.js.map +1 -0
  76. package/lib/hooks/useWidgetBootstrap.d.ts +21 -0
  77. package/lib/hooks/useWidgetBootstrap.d.ts.map +1 -0
  78. package/lib/hooks/useWidgetBootstrap.js +87 -0
  79. package/lib/hooks/useWidgetBootstrap.js.map +1 -0
  80. package/lib/hooks/useWidgetServices.d.ts +19 -0
  81. package/lib/hooks/useWidgetServices.d.ts.map +1 -0
  82. package/lib/hooks/useWidgetServices.js +34 -0
  83. package/lib/hooks/useWidgetServices.js.map +1 -0
  84. package/lib/hooks/useWidgetUI.d.ts +9 -0
  85. package/lib/hooks/useWidgetUI.d.ts.map +1 -0
  86. package/lib/hooks/useWidgetUI.js +33 -0
  87. package/lib/hooks/useWidgetUI.js.map +1 -0
  88. package/lib/index.d.ts +10 -11
  89. package/lib/index.d.ts.map +1 -1
  90. package/lib/index.js +13 -38
  91. package/lib/index.js.map +1 -1
  92. package/lib/services/UserIdentificationService.d.ts +3 -0
  93. package/lib/services/UserIdentificationService.d.ts.map +1 -0
  94. package/lib/services/UserIdentificationService.js +17 -0
  95. package/lib/services/UserIdentificationService.js.map +1 -0
  96. package/lib/services/WidgetBootstrapService.d.ts +12 -0
  97. package/lib/services/WidgetBootstrapService.d.ts.map +1 -0
  98. package/lib/services/{widgetBootstrapService.js → WidgetBootstrapService.js} +36 -15
  99. package/lib/services/WidgetBootstrapService.js.map +1 -0
  100. package/lib/services/WidgetEventService.d.ts +8 -0
  101. package/lib/services/WidgetEventService.d.ts.map +1 -0
  102. package/lib/services/WidgetEventService.js +14 -0
  103. package/lib/services/WidgetEventService.js.map +1 -0
  104. package/lib/services/WidgetStateManager.d.ts +20 -0
  105. package/lib/services/WidgetStateManager.d.ts.map +1 -0
  106. package/lib/services/WidgetStateManager.js +93 -0
  107. package/lib/services/WidgetStateManager.js.map +1 -0
  108. package/lib/services/WidgetValidationService.d.ts +17 -0
  109. package/lib/services/WidgetValidationService.d.ts.map +1 -0
  110. package/lib/services/WidgetValidationService.js +132 -0
  111. package/lib/services/WidgetValidationService.js.map +1 -0
  112. package/lib/services/events/EventHandlerFactory.d.ts +18 -0
  113. package/lib/services/events/EventHandlerFactory.d.ts.map +1 -0
  114. package/lib/services/events/EventHandlerFactory.js +67 -0
  115. package/lib/services/events/EventHandlerFactory.js.map +1 -0
  116. package/lib/services/events/EventHandlers.d.ts +10 -0
  117. package/lib/services/events/EventHandlers.d.ts.map +1 -0
  118. package/lib/services/events/EventHandlers.js +72 -0
  119. package/lib/services/events/EventHandlers.js.map +1 -0
  120. package/lib/services/events/index.d.ts +3 -0
  121. package/lib/services/events/index.d.ts.map +1 -0
  122. package/lib/services/events/index.js +21 -0
  123. package/lib/services/events/index.js.map +1 -0
  124. package/lib/services/height/HeightStrategies.d.ts +3 -0
  125. package/lib/services/height/HeightStrategies.d.ts.map +1 -0
  126. package/lib/services/height/HeightStrategies.js +14 -0
  127. package/lib/services/height/HeightStrategies.js.map +1 -0
  128. package/lib/services/storage/AsyncStorageService.d.ts +13 -0
  129. package/lib/services/storage/AsyncStorageService.d.ts.map +1 -0
  130. package/lib/services/storage/AsyncStorageService.js +73 -0
  131. package/lib/services/storage/AsyncStorageService.js.map +1 -0
  132. package/lib/services/storage/IStorageService.d.ts +30 -0
  133. package/lib/services/storage/IStorageService.d.ts.map +1 -0
  134. package/lib/services/storage/IStorageService.js +3 -0
  135. package/lib/services/storage/IStorageService.js.map +1 -0
  136. package/lib/services/storage/StorageIdBuilder.d.ts +11 -0
  137. package/lib/services/storage/StorageIdBuilder.d.ts.map +1 -0
  138. package/lib/services/storage/StorageIdBuilder.js +17 -0
  139. package/lib/services/storage/StorageIdBuilder.js.map +1 -0
  140. package/lib/services/storage/index.d.ts +3 -0
  141. package/lib/services/storage/index.d.ts.map +1 -0
  142. package/lib/services/storage/index.js +6 -0
  143. package/lib/services/storage/index.js.map +1 -0
  144. package/lib/styles/widgetStyles.d.ts +1 -1
  145. package/lib/styles/widgetStyles.d.ts.map +1 -1
  146. package/package.json +8 -2
  147. package/src/SoluCXWidget.ts +144 -0
  148. package/src/SoluCXWidgetHost.tsx +44 -0
  149. package/src/SoluCXWidgetView.tsx +97 -0
  150. package/src/__tests__/ClientVersionCollector.test.ts +5 -5
  151. package/src/__tests__/OverlayWidget.rendering.test.tsx +12 -14
  152. package/src/__tests__/SoluCXWidget.rendering.test.tsx +103 -60
  153. package/src/__tests__/SoluCXWidget.test.ts +448 -0
  154. package/src/__tests__/WidgetValidationService.test.ts +408 -0
  155. package/src/__tests__/e2e/widget-lifecycle.test.tsx +14 -23
  156. package/src/__tests__/index.test.tsx +39 -0
  157. package/src/__tests__/integration/webview-communication-simple.test.tsx +8 -6
  158. package/src/__tests__/integration/webview-communication.test.tsx +127 -130
  159. package/src/__tests__/normalizeWidgetOptions.test.ts +80 -0
  160. package/src/__tests__/useWidgetBootstrap.test.ts +634 -0
  161. package/src/__tests__/useWidgetState.test.ts +56 -13
  162. package/src/__tests__/widgetBootstrapService.test.ts +15 -17
  163. package/src/components/CloseButton.tsx +6 -2
  164. package/src/components/InlineWidget.tsx +4 -9
  165. package/src/components/ModalWidget.tsx +15 -45
  166. package/src/components/OverlayWidget.tsx +5 -15
  167. package/src/components/index.ts +4 -0
  168. package/src/constants/Constants.ts +15 -0
  169. package/src/{interfaces → domain}/WidgetCallbacks.ts +2 -2
  170. package/{lib/interfaces/WidgetData.d.ts → src/domain/WidgetData.ts} +3 -2
  171. package/src/domain/WidgetDisplayResult.ts +16 -0
  172. package/src/domain/WidgetOptions.ts +53 -0
  173. package/src/domain/WidgetResponse.ts +5 -0
  174. package/src/domain/WidgetSamplerLog.ts +11 -0
  175. package/src/{interfaces → domain}/index.ts +1 -2
  176. package/src/hooks/index.ts +2 -2
  177. package/src/{services/ClientVersionCollector.ts → hooks/useClientVersionCollector.ts} +6 -0
  178. package/src/hooks/useHeightAnimation.ts +6 -3
  179. package/src/hooks/useWidget.ts +46 -0
  180. package/src/hooks/useWidgetBootstrap.ts +117 -0
  181. package/src/hooks/useWidgetServices.ts +44 -0
  182. package/src/hooks/useWidgetUI.ts +38 -0
  183. package/src/index.ts +16 -11
  184. package/src/services/UserIdentificationService.ts +14 -0
  185. package/src/services/{widgetBootstrapService.ts → WidgetBootstrapService.ts} +43 -19
  186. package/src/services/WidgetEventService.ts +15 -0
  187. package/src/services/WidgetStateManager.ts +115 -0
  188. package/src/services/WidgetValidationService.ts +149 -0
  189. package/src/services/events/EventHandlerFactory.ts +70 -0
  190. package/src/services/events/EventHandlers.ts +67 -0
  191. package/src/services/events/index.ts +2 -0
  192. package/src/services/height/HeightStrategies.ts +15 -0
  193. package/src/services/storage/AsyncStorageService.ts +74 -0
  194. package/src/services/storage/IStorageService.ts +32 -0
  195. package/src/services/storage/StorageIdBuilder.ts +15 -0
  196. package/src/services/storage/index.ts +2 -0
  197. package/src/styles/widgetStyles.ts +1 -1
  198. package/README.intern.md +0 -490
  199. package/lib/constants/webViewConstants.d.ts +0 -12
  200. package/lib/constants/webViewConstants.d.ts.map +0 -1
  201. package/lib/constants/webViewConstants.js +0 -19
  202. package/lib/constants/webViewConstants.js.map +0 -1
  203. package/lib/hooks/useWidgetHeight.d.ts +0 -13
  204. package/lib/hooks/useWidgetHeight.d.ts.map +0 -1
  205. package/lib/hooks/useWidgetHeight.js +0 -21
  206. package/lib/hooks/useWidgetHeight.js.map +0 -1
  207. package/lib/hooks/useWidgetState.d.ts +0 -15
  208. package/lib/hooks/useWidgetState.d.ts.map +0 -1
  209. package/lib/hooks/useWidgetState.js +0 -79
  210. package/lib/hooks/useWidgetState.js.map +0 -1
  211. package/lib/interfaces/WidgetCallbacks.d.ts.map +0 -1
  212. package/lib/interfaces/WidgetCallbacks.js.map +0 -1
  213. package/lib/interfaces/WidgetData.d.ts.map +0 -1
  214. package/lib/interfaces/WidgetOptions.d.ts +0 -9
  215. package/lib/interfaces/WidgetOptions.d.ts.map +0 -1
  216. package/lib/interfaces/WidgetOptions.js.map +0 -1
  217. package/lib/interfaces/WidgetResponse.d.ts +0 -10
  218. package/lib/interfaces/WidgetResponse.d.ts.map +0 -1
  219. package/lib/interfaces/WidgetResponse.js +0 -12
  220. package/lib/interfaces/WidgetResponse.js.map +0 -1
  221. package/lib/interfaces/WidgetSamplerLog.d.ts +0 -7
  222. package/lib/interfaces/WidgetSamplerLog.d.ts.map +0 -1
  223. package/lib/interfaces/WidgetSamplerLog.js.map +0 -1
  224. package/lib/interfaces/index.d.ts.map +0 -1
  225. package/lib/services/ClientVersionCollector.d.ts +0 -2
  226. package/lib/services/ClientVersionCollector.d.ts.map +0 -1
  227. package/lib/services/ClientVersionCollector.js.map +0 -1
  228. package/lib/services/storage.d.ts +0 -8
  229. package/lib/services/storage.d.ts.map +0 -1
  230. package/lib/services/storage.js +0 -23
  231. package/lib/services/storage.js.map +0 -1
  232. package/lib/services/widgetBootstrapService.d.ts +0 -6
  233. package/lib/services/widgetBootstrapService.d.ts.map +0 -1
  234. package/lib/services/widgetBootstrapService.js.map +0 -1
  235. package/lib/services/widgetEventService.d.ts +0 -19
  236. package/lib/services/widgetEventService.d.ts.map +0 -1
  237. package/lib/services/widgetEventService.js +0 -79
  238. package/lib/services/widgetEventService.js.map +0 -1
  239. package/lib/services/widgetValidationService.d.ts +0 -18
  240. package/lib/services/widgetValidationService.d.ts.map +0 -1
  241. package/lib/services/widgetValidationService.js +0 -71
  242. package/lib/services/widgetValidationService.js.map +0 -1
  243. package/src/SoluCXWidget.tsx +0 -178
  244. package/src/constants/webViewConstants.ts +0 -15
  245. package/src/hooks/useWidgetHeight.ts +0 -38
  246. package/src/hooks/useWidgetState.ts +0 -101
  247. package/src/interfaces/WidgetOptions.ts +0 -8
  248. package/src/interfaces/WidgetResponse.ts +0 -15
  249. package/src/interfaces/WidgetSamplerLog.ts +0 -6
  250. package/src/services/storage.ts +0 -21
  251. package/src/services/widgetEventService.ts +0 -110
  252. package/src/services/widgetValidationService.ts +0 -102
  253. /package/lib/{interfaces → domain}/WidgetCallbacks.js +0 -0
  254. /package/lib/{interfaces → domain}/WidgetData.js +0 -0
  255. /package/lib/{interfaces → domain}/WidgetSamplerLog.js +0 -0
  256. /package/lib/{interfaces → domain}/index.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"widgetStyles.d.ts","sourceRoot":"","sources":["../../src/styles/widgetStyles.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoCjB,CAAC;AAEH,eAAO,MAAM,mBAAmB,GAAI,YAAY,OAAO;;;CAKtD,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAS/C,CAAC"}
1
+ {"version":3,"file":"widgetStyles.d.ts","sourceRoot":"","sources":["../../src/styles/widgetStyles.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoCjB,CAAC;AAEH,eAAO,MAAM,mBAAmB,GAAI,YAAY,OAAO;;;CAKtD,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAS/C,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solucx/react-native-solucx-widget",
3
- "version": "0.2.4",
3
+ "version": "2.0.7",
4
4
  "description": "The React Native SDK for Solucx Widget",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -42,8 +42,14 @@
42
42
  "setupFilesAfterEnv": [
43
43
  "<rootDir>/src/setupTests.js"
44
44
  ],
45
+ "testRegex": ".*\\.test\\.(ts|tsx)$",
46
+ "testMatch": null,
45
47
  "testPathIgnorePatterns": [
46
- "/lib/"
48
+ "/lib/",
49
+ "/old_tests/",
50
+ "\\.old\\.spec\\.",
51
+ "\\.spec\\.(ts|tsx)$",
52
+ "node_modules"
47
53
  ],
48
54
  "moduleNameMapper": {
49
55
  "expo-modules-core/src/Refs": "<rootDir>/src/__mocks__/expo-modules-core.js",
@@ -0,0 +1,144 @@
1
+ import type { WidgetCallbacks, WidgetData, WidgetOptions, WidgetSamplerLog, WidgetType } from "./domain";
2
+ import { normalizeWidgetOptions } from "./domain/WidgetOptions";
3
+ import { AsyncStorageService } from "./services/storage/AsyncStorageService";
4
+ import { buildStorageId } from "./services/storage/StorageIdBuilder";
5
+ import { WidgetStateManager, type TimestampField } from "./services/WidgetStateManager";
6
+
7
+ export interface WidgetConfig {
8
+ instanceKey: string;
9
+ type: WidgetType;
10
+ data: WidgetData;
11
+ options?: WidgetOptions;
12
+ callbacks: WidgetCallbacks;
13
+ }
14
+
15
+ type ShowHandler = (config: WidgetConfig) => void;
16
+ type DismissHandler = () => void;
17
+
18
+ let registeredShowHandler: ShowHandler | null = null;
19
+ let registeredDismissHandler: DismissHandler | null = null;
20
+
21
+ export function _registerHost(show: ShowHandler, dismiss: DismissHandler) {
22
+ registeredShowHandler = show;
23
+ registeredDismissHandler = dismiss;
24
+ }
25
+
26
+ export function _unregisterHost() {
27
+ registeredShowHandler = null;
28
+ registeredDismissHandler = null;
29
+ }
30
+
31
+ export class SoluCXWidget {
32
+ private _instanceKey: string = "";
33
+ private _type: WidgetType = "bottom";
34
+ private _data: WidgetData = {};
35
+ private _options: WidgetOptions | null = {};
36
+ private _callbacks: WidgetCallbacks = {};
37
+
38
+ private constructor(instanceKey: string) {
39
+ this._instanceKey = instanceKey;
40
+ }
41
+
42
+ // --- Builder methods ---
43
+
44
+ static create(instanceKey: string): SoluCXWidget {
45
+ return new SoluCXWidget(instanceKey);
46
+ }
47
+
48
+ setData(data: WidgetData): this {
49
+ this._data = { ...data };
50
+ return this;
51
+ }
52
+
53
+ setOptions(options: WidgetOptions): this {
54
+ const isObjectValid = !!options && Object.keys(options).length > 0;
55
+ this._options = isObjectValid ? normalizeWidgetOptions(options) : null;
56
+ return this;
57
+ }
58
+
59
+ setCallbacks(callbacks: WidgetCallbacks): this {
60
+ this._callbacks = { ...callbacks };
61
+ return this;
62
+ }
63
+
64
+ setType(type: WidgetType): this {
65
+ this._type = type;
66
+ return this;
67
+ }
68
+
69
+ show(): void {
70
+ if (!registeredShowHandler) {
71
+ throw new Error("[SoluCXWidget] Cannot show widget — no <SoluCXWidgetHost /> is mounted. " + "Add <SoluCXWidgetHost /> at the root of your app.");
72
+ }
73
+
74
+ registeredShowHandler({
75
+ instanceKey: this._instanceKey,
76
+ type: this._type,
77
+ data: { ...this._data },
78
+ options: { ...this._options },
79
+ callbacks: { ...this._callbacks },
80
+ });
81
+
82
+ this._cleanup();
83
+ }
84
+
85
+ // --- Static: dismiss ---
86
+
87
+ static dismiss(): void {
88
+ registeredDismissHandler?.();
89
+ }
90
+
91
+ // --- Log management (instance methods) ---
92
+
93
+ /**
94
+ * Build the storage ID from the builder state.
95
+ * Uses instanceKey + journey (from data) + userId (from data).
96
+ */
97
+ private _buildStorageId(): string {
98
+ return buildStorageId(this._instanceKey, this._data);
99
+ }
100
+
101
+ private _createStateManager(): WidgetStateManager {
102
+ const storageId = this._buildStorageId();
103
+ const storageService = new AsyncStorageService(storageId);
104
+ return new WidgetStateManager(storageService, storageId);
105
+ }
106
+
107
+ /**
108
+ * Override a specific event timestamp.
109
+ * Uses instanceKey from create() and journey/userId from setData().
110
+ *
111
+ * @param field - The timestamp field to override (e.g., 'lastFirstAccess', 'lastDismiss')
112
+ * @param date - The date to set (Date object or timestamp in milliseconds). Use 0 to clear.
113
+ */
114
+ async overrideTimestamp(field: TimestampField, date: Date | number): Promise<this> {
115
+ await this._createStateManager().overrideTimestamp(field, date);
116
+ return this;
117
+ }
118
+
119
+ /**
120
+ * Get the current widget logs.
121
+ * Uses instanceKey from create() and journey/userId from setData().
122
+ */
123
+ async getWidgetLogs(): Promise<WidgetSamplerLog> {
124
+ return this._createStateManager().getLogs();
125
+ }
126
+
127
+ /**
128
+ * Clear all widget logs.
129
+ * Uses instanceKey from create() and journey/userId from setData().
130
+ */
131
+ async clearWidgetLogs(): Promise<this> {
132
+ await this._createStateManager().clearLogs();
133
+ return this;
134
+ }
135
+
136
+ // --- Private ---
137
+
138
+ private _cleanup(): void {
139
+ this._type = "bottom";
140
+ this._data = {};
141
+ this._options = {};
142
+ this._callbacks = {};
143
+ }
144
+ }
@@ -0,0 +1,44 @@
1
+ import React, { useEffect, useState, useCallback } from "react";
2
+ import { SoluCXWidgetView } from "./SoluCXWidgetView";
3
+ import { _registerHost, _unregisterHost } from "./SoluCXWidget";
4
+ import type { WidgetConfig } from "./SoluCXWidget";
5
+
6
+ export const SoluCXWidgetHost: React.FC = () => {
7
+ const [config, setConfig] = useState<WidgetConfig | null>(null);
8
+ const [refreshKey, setRefreshKey] = useState(0);
9
+
10
+ const handleShow = useCallback((newConfig: WidgetConfig) => {
11
+ setConfig(newConfig);
12
+ setRefreshKey((k) => k + 1);
13
+ }, []);
14
+
15
+ const handleDismiss = useCallback(() => {
16
+ setConfig(null);
17
+ }, []);
18
+
19
+ useEffect(() => {
20
+ _registerHost(handleShow, handleDismiss);
21
+ return () => _unregisterHost();
22
+ }, [handleShow, handleDismiss]);
23
+
24
+ if (!config) return null;
25
+
26
+ const wrappedCallbacks = {
27
+ ...config.callbacks,
28
+ onClosed: () => {
29
+ config.callbacks?.onClosed?.();
30
+ setConfig(null);
31
+ },
32
+ };
33
+
34
+ return (
35
+ <SoluCXWidgetView
36
+ key={refreshKey}
37
+ soluCXKey={config.instanceKey}
38
+ type={config.type}
39
+ data={config.data}
40
+ options={config.options}
41
+ callbacks={wrappedCallbacks}
42
+ />
43
+ );
44
+ };
@@ -0,0 +1,97 @@
1
+ import React, { useCallback, useEffect } from "react";
2
+ import { Dimensions } from "react-native";
3
+ import { WebView } from "react-native-webview";
4
+
5
+ import { InlineWidget } from "./components/InlineWidget";
6
+ import { ModalWidget } from "./components/ModalWidget";
7
+ import { OverlayWidget } from "./components/OverlayWidget";
8
+ import { WEB_VIEW_MESSAGE_LISTENER } from "./constants/Constants";
9
+ import type { SoluCXKey, WidgetCallbacks, WidgetData, WidgetOptions, WidgetType } from "./domain";
10
+ import { useWidget } from "./hooks/useWidget";
11
+ import { useWidgetBootstrap } from "./hooks/useWidgetBootstrap";
12
+ import { useWidgetServices } from "./hooks/useWidgetServices";
13
+
14
+ interface SoluCXWidgetProps {
15
+ soluCXKey: SoluCXKey;
16
+ type: WidgetType;
17
+ data: WidgetData;
18
+ options?: WidgetOptions;
19
+ callbacks?: WidgetCallbacks;
20
+ }
21
+
22
+ export const SoluCXWidgetView: React.FC<SoluCXWidgetProps> = ({ soluCXKey, type, data, options, callbacks }) => {
23
+ const { width } = Dimensions.get("window");
24
+
25
+ const { widgetHeight, isWidgetVisible, resize, open, hide, userId, stateManager } = useWidget(soluCXKey, data, options);
26
+
27
+ const { validationService, handleWebViewMessage } = useWidgetServices({
28
+ hide,
29
+ resize,
30
+ userId,
31
+ callbacks,
32
+ data,
33
+ stateManager,
34
+ });
35
+
36
+ const { widgetUri, bootstrap } = useWidgetBootstrap({
37
+ soluCXKey,
38
+ data,
39
+ userId,
40
+ options,
41
+ callbacks,
42
+ open,
43
+ hide,
44
+ validationService,
45
+ stateManager,
46
+ });
47
+
48
+ useEffect(() => {
49
+ bootstrap();
50
+ }, []);
51
+
52
+ const handleClose = useCallback(() => {
53
+ hide();
54
+ callbacks?.onClosed?.();
55
+ }, [hide, callbacks]);
56
+
57
+ if (!data) {
58
+ callbacks?.onError?.("Widget data is required but was not provided");
59
+ return null;
60
+ }
61
+
62
+ if (!widgetUri) {
63
+ return null;
64
+ }
65
+
66
+ const webView = (
67
+ <WebView
68
+ style={[{ height: widgetHeight }, { width }]}
69
+ source={{ uri: widgetUri }}
70
+ injectedJavaScript={WEB_VIEW_MESSAGE_LISTENER}
71
+ onMessage={event => handleWebViewMessage(event.nativeEvent.data)}
72
+ originWhitelist={["*"]}
73
+ />
74
+ );
75
+
76
+ if (type === "modal") {
77
+ return (
78
+ <ModalWidget visible={isWidgetVisible} height={widgetHeight} onClose={handleClose}>
79
+ {webView}
80
+ </ModalWidget>
81
+ );
82
+ }
83
+
84
+ if (type === "inline") {
85
+ return (
86
+ <InlineWidget visible={isWidgetVisible} height={widgetHeight} onClose={handleClose}>
87
+ {webView}
88
+ </InlineWidget>
89
+ );
90
+ }
91
+
92
+ return (
93
+ <OverlayWidget visible={isWidgetVisible} width={width} height={widgetHeight} position={type} onClose={handleClose}>
94
+ {webView}
95
+ </OverlayWidget>
96
+ );
97
+ };
@@ -10,7 +10,7 @@ describe('ClientVersionCollector', () => {
10
10
  },
11
11
  }), { virtual: true });
12
12
 
13
- const { getClientVersion } = require('../services/ClientVersionCollector');
13
+ const { getClientVersion } = require('../hooks/useClientVersionCollector');
14
14
  expect(getClientVersion()).toBe('3.0.0');
15
15
  });
16
16
 
@@ -19,7 +19,7 @@ describe('ClientVersionCollector', () => {
19
19
  getVersion: () => '4.0.0',
20
20
  }), { virtual: true });
21
21
 
22
- const { getClientVersion } = require('../services/ClientVersionCollector');
22
+ const { getClientVersion } = require('../hooks/useClientVersionCollector');
23
23
  expect(getClientVersion()).toBe('4.0.0');
24
24
  });
25
25
 
@@ -28,7 +28,7 @@ describe('ClientVersionCollector', () => {
28
28
  throw new Error('Module not found');
29
29
  }, { virtual: true });
30
30
 
31
- const { getClientVersion } = require('../services/ClientVersionCollector');
31
+ const { getClientVersion } = require('../hooks/useClientVersionCollector');
32
32
  expect(getClientVersion()).toBe('unknown');
33
33
  });
34
34
 
@@ -37,7 +37,7 @@ describe('ClientVersionCollector', () => {
37
37
  default: {},
38
38
  }), { virtual: true });
39
39
 
40
- const { getClientVersion } = require('../services/ClientVersionCollector');
40
+ const { getClientVersion } = require('../hooks/useClientVersionCollector');
41
41
  expect(getClientVersion()).toBe('unknown');
42
42
  });
43
43
 
@@ -49,7 +49,7 @@ describe('ClientVersionCollector', () => {
49
49
  getVersion: () => '6.0.0',
50
50
  }), { virtual: true });
51
51
 
52
- const { getClientVersion } = require('../services/ClientVersionCollector');
52
+ const { getClientVersion } = require('../hooks/useClientVersionCollector');
53
53
  expect(getClientVersion()).toBe('5.0.0');
54
54
  });
55
55
  });
@@ -47,41 +47,39 @@ describe('OverlayWidget rendering', () => {
47
47
  expect(mockOnClose).toHaveBeenCalledTimes(1);
48
48
  });
49
49
 
50
- it('should hide entirely after close button is pressed', () => {
51
- const { getByText, queryByText } = render(
52
- <OverlayWidget visible={true} width={390} height={300} position="bottom" onClose={jest.fn()}>
50
+ it('should call onClose when close button is pressed and component is controlled by parent', () => {
51
+ const mockOnClose = jest.fn();
52
+ const { getByText } = render(
53
+ <OverlayWidget visible={true} width={390} height={300} position="bottom" onClose={mockOnClose}>
53
54
  <Text>Dismissible Content</Text>
54
55
  </OverlayWidget>
55
56
  );
56
57
 
57
58
  fireEvent.press(getByText('✕'));
58
59
 
59
- expect(queryByText('Dismissible Content')).toBeNull();
60
+ expect(mockOnClose).toHaveBeenCalledTimes(1);
60
61
  });
61
62
 
62
- it('should not render content when internal visibility is set to false after close', () => {
63
- const { getByText, queryByText } = render(
64
- <OverlayWidget visible={true} width={390} height={300} position="top" onClose={jest.fn()}>
63
+ it('should not render when visible prop is false', () => {
64
+ const { queryByText } = render(
65
+ <OverlayWidget visible={false} width={390} height={300} position="top" onClose={jest.fn()}>
65
66
  <Text>Top Content</Text>
66
67
  </OverlayWidget>
67
68
  );
68
69
 
69
- fireEvent.press(getByText(''));
70
-
70
+ expect(queryByText('Top Content')).toBeNull();
71
71
  expect(queryByText('✕')).toBeNull();
72
72
  });
73
73
 
74
- it('should not reopen after internal state is set to false even if rerendered', () => {
75
- const { getByText, queryByText, rerender } = render(
74
+ it('should hide content when visible prop changes to false', () => {
75
+ const { queryByText, rerender } = render(
76
76
  <OverlayWidget visible={true} width={390} height={300} position="bottom" onClose={jest.fn()}>
77
77
  <Text>Content</Text>
78
78
  </OverlayWidget>
79
79
  );
80
80
 
81
- fireEvent.press(getByText('✕'));
82
-
83
81
  rerender(
84
- <OverlayWidget visible={true} width={390} height={300} position="bottom" onClose={jest.fn()}>
82
+ <OverlayWidget visible={false} width={390} height={300} position="bottom" onClose={jest.fn()}>
85
83
  <Text>Content</Text>
86
84
  </OverlayWidget>
87
85
  );