@solucx/react-native-solucx-widget 0.2.5 → 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 -101
  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 -179
  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
package/README.md CHANGED
@@ -1,285 +1,629 @@
1
1
  # @solucx/react-native-solucx-widget
2
2
 
3
- [![npm version](https://badge.fury.io/js/@solucx%2Freact-native-solucx-widget.svg)](https://badge.fury.io/js/@solucx%2Freact-native-solucx-widget)
4
3
  [![React Native](https://img.shields.io/badge/React%20Native-0.70+-blue.svg)](https://reactnative.dev/)
5
4
  [![Expo](https://img.shields.io/badge/Expo-50+-lightgrey.svg)](https://expo.dev/)
6
5
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)
7
- [![iOS](https://img.shields.io/badge/iOS-11+-lightgrey.svg)](https://developer.apple.com/ios/)
8
- [![Android](https://img.shields.io/badge/Android-API%2021+-green.svg)](https://developer.android.com/)
9
- [![License](https://img.shields.io/badge/License-Proprietary-red.svg)](LICENSE)
10
6
 
11
- Um widget React Native modular para coleta de feedback e pesquisas de satisfação, desenvolvido pela SoluCX seguindo princípios de Clean Code e arquitetura escalável.
7
+ Widget React Native para coleta de feedback e pesquisas de satisfacao, desenvolvido pela SoluCX.
12
8
 
13
- ## 🛠️ Tecnologias
9
+ ---
14
10
 
15
- ![React Native](https://img.shields.io/badge/React_Native-20232A?style=for-the-badge&logo=react&logoColor=61DAFB)
16
- ![TypeScript](https://img.shields.io/badge/TypeScript-007ACC?style=for-the-badge&logo=typescript&logoColor=white)
17
- ![WebView](https://img.shields.io/badge/WebView-4285F4?style=for-the-badge&logo=googlechrome&logoColor=white)
18
- ![AsyncStorage](https://img.shields.io/badge/AsyncStorage-FF6B6B?style=for-the-badge&logo=react&logoColor=white)
19
- ![Jest](https://img.shields.io/badge/Jest-C21325?style=for-the-badge&logo=jest&logoColor=white)
11
+ ## Instalacao
20
12
 
21
- ## 📋 Visão Geral
13
+ ```bash
14
+ npm install @solucx/react-native-solucx-widget
15
+ ```
22
16
 
23
- O SoluCX Widget permite integrar pesquisas de satisfação diretamente em aplicações React Native/Expo de forma simples e flexível. Desenvolvido para empresas que precisam coletar feedback em tempo real através de diferentes modalidades de apresentação.
17
+ ---
24
18
 
25
- ### 🎯 Principais Características
19
+ ## Inicio Rapido
26
20
 
27
- - **4 Modos de Renderização**: Bottom, Top, Modal e Inline
28
- - **Persistência Automática**: Controle inteligente de frequência
29
- - **Comunicação WebView**: Integração transparente com plataforma SoluCX
30
- - **TypeScript**: Totalmente tipado para melhor experiência de desenvolvimento
31
- - **Performático**: Carregamento otimizado e cache local
21
+ Voce pode integrar o widget de duas formas:
32
22
 
33
- ## 🚀 Instalação
23
+ - **Por funcao**: monta um `SoluCXWidgetHost` no root e dispara a exibicao com `SoluCXWidget.create(...).show()`.
24
+ - **Por componente**: renderiza `SoluCXWidget` diretamente no JSX, no ponto exato em que o widget deve aparecer.
34
25
 
35
- ```bash
36
- npm install @solucx/react-native-solucx-widget
26
+ ### 1. Uso por funcao: adicione o `SoluCXWidgetHost` no root do app
27
+
28
+ O `SoluCXWidgetHost` deve ser montado **uma unica vez** no componente raiz da aplicacao. Ele e responsavel por renderizar o widget quando solicitado via `SoluCXWidget.create(...).show()`.
29
+
30
+ ```tsx
31
+ // App.tsx
32
+ import { SoluCXWidgetHost } from '@solucx/react-native-solucx-widget';
33
+
34
+ export default function App() {
35
+ return (
36
+ <>
37
+ <NavigationContainer>
38
+ <Stack.Navigator>{/* suas telas */}</Stack.Navigator>
39
+ </NavigationContainer>
40
+
41
+ {/* Obrigatorio: monte uma vez no root */}
42
+ <SoluCXWidgetHost />
43
+ </>
44
+ );
45
+ }
37
46
  ```
38
47
 
39
- ## 🎛️ Uso Básico
48
+ ### 2. Uso por funcao: dispare o widget em qualquer tela
49
+
50
+ Use `SoluCXWidget.create()` para construir e exibir o widget. **As opcoes de supressao (dias de espera) sao opcionais** — se nao forem passadas, o widget as busca automaticamente do painel de configuracao da jornada (configurado remotamente).
40
51
 
41
52
  ```tsx
42
- import React from 'react';
53
+ // CheckoutScreen.tsx
43
54
  import { SoluCXWidget } from '@solucx/react-native-solucx-widget';
44
55
 
45
- export default function MyScreen() {
56
+ function onCheckoutComplete() {
57
+ SoluCXWidget
58
+ .create('SUA_CHAVE_SOLUCX')
59
+ .setType('modal')
60
+ .setData({
61
+ journey: 'pos_venda',
62
+ user_id: 'user_123',
63
+ email: 'cliente@email.com',
64
+ name: 'Joao Silva',
65
+ })
66
+ .show();
67
+ }
68
+ ```
69
+
70
+ Pronto! O widget vai buscar as configuracoes de supressao remotamente e decidir se deve exibir ou nao.
71
+
72
+ ### 3. Uso por componente: renderize o widget diretamente no JSX
73
+
74
+ Quando voce quiser controlar a exibicao pelo proprio componente React, use `SoluCXWidget`. Nesse modo, nao e necessario montar `SoluCXWidgetHost`.
75
+
76
+ ```tsx
77
+ // CheckoutScreen.tsx
78
+ import { SoluCXWidget } from '@solucx/react-native-solucx-widget';
79
+
80
+ export function CheckoutScreen() {
46
81
  return (
47
82
  <SoluCXWidget
48
- soluCXKey='sua-chave-solucx'
49
- type='bottom'
83
+ soluCXKey="SUA_CHAVE_SOLUCX"
84
+ type="inline"
50
85
  data={{
51
- journey: 'checkout_flow',
52
- name: 'João Silva',
53
- email: 'joao@email.com',
54
- store_id: 'loja_01',
55
- amount: 150.0
86
+ journey: 'pos_venda',
87
+ user_id: 'user_123',
88
+ email: 'cliente@email.com',
89
+ name: 'Joao Silva',
56
90
  }}
57
- options={{
58
- height: 400
91
+ callbacks={{
92
+ onOpened: (userId) => {
93
+ console.log('Widget exibido para:', userId);
94
+ },
59
95
  }}
60
96
  />
61
97
  );
62
98
  }
63
99
  ```
64
100
 
65
- ## 📱 Modos de Renderização
101
+ ---
102
+
103
+ ## Exemplos Completos
66
104
 
67
- ### Bottom (Padrão)
105
+ ### Exemplo 1: Uso minimo (opcoes configuradas remotamente)
68
106
 
69
- Widget fixo na parte inferior da tela, ideal para feedback não intrusivo.
107
+ Este e o caso de uso mais comum. As regras de supressao (quantos dias esperar apos cada evento) sao configuradas no **painel de configuracao da jornada** e buscadas automaticamente pelo widget. Voce nao precisa passar nenhuma opcao.
70
108
 
71
109
  ```tsx
72
- <SoluCXWidget type='bottom' {...props} />
110
+ import { SoluCXWidget } from '@solucx/react-native-solucx-widget';
111
+
112
+ // Disparar apos uma compra
113
+ function afterPurchase() {
114
+ SoluCXWidget
115
+ .create('SUA_CHAVE_SOLUCX')
116
+ .setType('bottom')
117
+ .setData({
118
+ journey: 'pos_venda',
119
+ user_id: 'user_123',
120
+ email: 'cliente@email.com',
121
+ name: 'Joao Silva',
122
+ store_id: 'loja_01',
123
+ })
124
+ .show();
125
+ // As opcoes de supressao serao buscadas automaticamente da API
126
+ // com base na configuracao da jornada "pos_venda"
127
+ }
73
128
  ```
74
129
 
75
- ### Top
130
+ ### Exemplo 2: Com callbacks para monitorar eventos
76
131
 
77
- Widget fixo no topo da tela, perfeito para notificações importantes.
132
+ ```tsx
133
+ import { SoluCXWidget } from '@solucx/react-native-solucx-widget';
134
+
135
+ function showSurvey() {
136
+ SoluCXWidget
137
+ .create('SUA_CHAVE_SOLUCX')
138
+ .setType('modal')
139
+ .setData({
140
+ journey: 'atendimento',
141
+ user_id: 'user_456',
142
+ email: 'maria@email.com',
143
+ name: 'Maria Santos',
144
+ employee_id: 'atendente_01',
145
+ employee_name: 'Carlos',
146
+ })
147
+ .setCallbacks({
148
+ onPreOpen: (userId) => {
149
+ console.log('Preparando widget para:', userId);
150
+ },
151
+ onOpened: (userId) => {
152
+ console.log('Widget exibido para:', userId);
153
+ analytics.track('survey_shown', { userId });
154
+ },
155
+ onBlocked: (reason) => {
156
+ // Widget nao foi exibido por causa de uma regra de supressao
157
+ console.log('Widget bloqueado:', reason);
158
+ // Ex: "BLOCKED_BY_WIDGET_DISMISS_INTERVAL"
159
+ },
160
+ onClosed: () => {
161
+ console.log('Usuario fechou o widget');
162
+ },
163
+ onCompleted: (userId) => {
164
+ console.log('Pesquisa respondida por:', userId);
165
+ analytics.track('survey_completed', { userId });
166
+ },
167
+ onPartialCompleted: (userId) => {
168
+ console.log('Pesquisa parcialmente respondida por:', userId);
169
+ },
170
+ onError: (message) => {
171
+ console.error('Erro no widget:', message);
172
+ },
173
+ })
174
+ .show();
175
+ }
176
+ ```
177
+
178
+ ### Exemplo 3: Com opcoes locais (sobrescrevendo configuracao remota)
179
+
180
+ Se voce precisar sobrescrever as configuracoes da jornada para um caso especifico, passe as opcoes diretamente. Quando `setOptions()` e chamado, o widget **nao busca configuracoes da API** e usa os valores fornecidos.
78
181
 
79
182
  ```tsx
80
- <SoluCXWidget type='top' {...props} />
183
+ import { SoluCXWidget } from '@solucx/react-native-solucx-widget';
184
+
185
+ function showUrgentSurvey() {
186
+ SoluCXWidget
187
+ .create('SUA_CHAVE_SOLUCX')
188
+ .setType('modal')
189
+ .setData({
190
+ journey: 'nps_trimestral',
191
+ user_id: 'user_789',
192
+ email: 'pedro@email.com',
193
+ })
194
+ .setOptions({
195
+ height: 600,
196
+ maxAttemptsAfterDismiss: 5, // Máximo de 5 tentativas para essa jornada
197
+ waitDaysAfterWidgetDismiss: 90, // Esperar 90 dias após o usuário fechar
198
+ waitDaysAfterWidgetSubmit: 30, // Esperar 30 dias após resposta completa
199
+ waitDaysAfterWidgetDisplay: 7, // Esperar 7 dias após qualquer exibição
200
+ })
201
+ .setCallbacks({
202
+ onOpened: (userId) => console.log('Abriu:', userId),
203
+ onCompleted: (userId) => console.log('Respondeu:', userId),
204
+ })
205
+ .show();
206
+ }
81
207
  ```
82
208
 
83
- ### Modal
209
+ ### Exemplo 4: Diferentes tipos de widget
210
+
211
+ ```tsx
212
+ import { SoluCXWidget } from '@solucx/react-native-solucx-widget';
213
+
214
+ const data = {
215
+ journey: 'pos_venda',
216
+ user_id: 'user_123',
217
+ email: 'cliente@email.com',
218
+ };
219
+
220
+ // Bottom: barra fixa na parte inferior (padrao)
221
+ SoluCXWidget.create('KEY').setType('bottom').setData(data).show();
222
+
223
+ // Top: barra fixa no topo
224
+ SoluCXWidget.create('KEY').setType('top').setData(data).show();
225
+
226
+ // Modal: sobreposicao centralizada que bloqueia o fundo
227
+ SoluCXWidget.create('KEY').setType('modal').setData(data).show();
228
+
229
+ // Inline: integrado ao fluxo do layout (respeita a posicao no JSX)
230
+ SoluCXWidget.create('KEY').setType('inline').setData(data).show();
231
+ ```
84
232
 
85
- Sobreposição centralizada que bloqueia interação com o fundo.
233
+ ### Exemplo 5: Fechar o widget programaticamente
86
234
 
87
235
  ```tsx
88
- <SoluCXWidget type='modal' {...props} />
236
+ import { SoluCXWidget } from '@solucx/react-native-solucx-widget';
237
+
238
+ // Fechar o widget a qualquer momento
239
+ function handleTimeout() {
240
+ SoluCXWidget.dismiss();
241
+ }
89
242
  ```
90
243
 
91
- ### Inline
244
+ ### Exemplo 6: Consultar logs de supressao
92
245
 
93
- Integrado ao fluxo normal do layout, respeitando a posição no código.
246
+ Os metodos de log sao **metodos de instancia** — usam os dados do builder (`instanceKey` do `create()`, `journey` e `userId` do `setData()`) para identificar automaticamente qual registro acessar. Nao e necessario passar esses parametros novamente.
94
247
 
95
248
  ```tsx
96
- <SoluCXWidget type='inline' {...props} />
249
+ import { SoluCXWidget } from '@solucx/react-native-solucx-widget';
250
+
251
+ // Cria a instancia com os dados que identificam o registro
252
+ const widget = SoluCXWidget
253
+ .create('SUA_CHAVE_SOLUCX')
254
+ .setData({ journey: 'pos_venda', user_id: 'user_123' });
255
+
256
+ // Consultar os logs de supressao
257
+ const logs = await widget.getWidgetLogs();
258
+ console.log(logs);
259
+ // {
260
+ // attempts: 3, // quantas vezes o widget foi exibido nesta experiencia
261
+ // answeredTransactionIds: ['txn-1'], // transacoes que ja responderam e nao devem reabrir o widget
262
+ // lastExperienceId: 'pos_venda', // ultima jornada associada ao contador
263
+ // lastDisplayAttempt: 1741000000000, // ultima tentativa de exibicao bloqueada
264
+ // lastFirstAccess: 1740000000000, // primeira vez que o widget foi exibido
265
+ // lastDisplay: 1741000000000, // ultima exibicao do widget
266
+ // lastDismiss: 1741000000000, // ultima vez que o usuario fechou
267
+ // lastSubmit: 0, // ultimo envio completo
268
+ // lastPartialSubmit: 0, // ultimo envio parcial
269
+ // }
97
270
  ```
98
271
 
99
- ## 🔧 API Completa
272
+ ### Exemplo 7: Sobrescrever datas de eventos (debug/teste)
100
273
 
101
- ### Props
274
+ Use `overrideTimestamp` para simular cenarios de teste sem esperar os dias reais.
102
275
 
103
- | Propriedade | Tipo | Obrigatório | Descrição |
104
- | ----------- | --------------- | ----------- | ---------------------------- |
105
- | `soluCXKey` | `string` | ✅ | Chave de autenticação SoluCX |
106
- | `type` | `WidgetType` | ✅ | Modo de renderização |
107
- | `data` | `WidgetData` | ✅ | Dados do cliente/transação |
108
- | `options` | `WidgetOptions` | ✅ | Configurações do widget |
276
+ ```tsx
277
+ import { SoluCXWidget } from '@solucx/react-native-solucx-widget';
109
278
 
110
- ### WidgetData
279
+ const widget = SoluCXWidget
280
+ .create('SUA_CHAVE_SOLUCX')
281
+ .setData({ journey: 'pos_venda', user_id: 'user_123' });
111
282
 
112
- ```typescript
113
- interface WidgetData {
114
- // Identificadores
115
- transaction_id?: string;
116
- customer_id?: string;
117
-
118
- // Dados do cliente
119
- name?: string;
120
- email?: string;
121
- phone?: string;
122
- birth_date?: string; // Formato: YYYY-MM-DD
123
- document?: string;
124
-
125
- // Contexto da transação
126
- store_id?: string;
127
- store_name?: string;
128
- employee_id?: string;
129
- employee_name?: string;
130
- amount?: number;
131
- score?: number;
132
- journey?: string; // Nome da jornada/fluxo
133
-
134
- // Parâmetros customizados (prefixo param_)
135
- param_REGIAO?: string;
136
- [key: string]: string | number | undefined;
137
- }
138
- ```
283
+ // Informar primeiro acesso do usuário
284
+ await widget.overrideTimestamp('lastFirstAccess', new Date('2026-01-01T00:00:00Z'));
139
285
 
140
- ### WidgetOptions
286
+ // Ou usar timestamp em milissegundos diretamente
287
+ await widget.overrideTimestamp('lastFirstAccess', 1700000000000);
141
288
 
142
- ```typescript
143
- interface WidgetOptions {
144
- height?: number; // Altura fixa em pontos (points, não pixels)
145
- // Se não fornecido, será dinâmica baseada em eventos de resize
146
- // Se fornecido, será fixa independente do tipo de widget
147
- retry?: {
148
- attempts?: number; // Tentativas (padrão: 3)
149
- interval?: number; // Intervalo em ms (padrão: 1000)
150
- };
151
- waitDelayAfterRating?: number; // Delay após avaliação
152
- }
289
+ // Resetar um campo para "nunca aconteceu" (valor 0)
290
+ await widget.overrideTimestamp('lastSubmit', 0);
291
+
292
+ // Depois de sobrescrever, pode exibir o widget normalmente
293
+ widget.show();
153
294
  ```
154
295
 
155
- **Comportamento da Altura (height):**
296
+ **Campos disponiveis para `overrideTimestamp`:**
156
297
 
157
- - **Altura Dinâmica (padrão)**: Quando `height` não é fornecido, o widget se ajusta automaticamente baseado em eventos de resize do conteúdo. Isso funciona para todos os tipos: `bottom`, `top`, `inline` e `modal`.
298
+ | Campo | Descricao |
299
+ |---|---|
300
+ | `lastDisplayAttempt` | Ultima tentativa de exibicao (widget foi bloqueado) |
301
+ | `lastFirstAccess` | Primeira vez que o widget foi exibido para o usuario |
302
+ | `lastDisplay` | Ultima exibicao do widget |
303
+ | `lastDismiss` | Ultima vez que o usuario fechou o widget |
304
+ | `lastSubmit` | Ultimo envio completo da pesquisa |
305
+ | `lastPartialSubmit` | Ultimo envio parcial da pesquisa |
306
+ | `answeredTransactionIds` | Lista de `transaction_id` que ja responderam e devem ser bloqueados localmente |
158
307
 
159
- ```tsx
160
- // Altura dinâmica - se adapta ao conteúdo
161
- <SoluCXWidget
162
- type='bottom'
163
- options={{}} // ou options={{ retry: { attempts: 3 } }}
164
- {...props}
165
- />
166
- ```
308
+ ### Exemplo 8: Limpar logs de supressao
167
309
 
168
- - **Altura Fixa**: Quando `height` é especificado, o valor é fixo e eventos de resize são ignorados. Funciona para todos os tipos de widget.
310
+ ```tsx
311
+ import { SoluCXWidget } from '@solucx/react-native-solucx-widget';
169
312
 
170
- ```tsx
171
- // Altura fixa de 400 pontos
172
- <SoluCXWidget type='modal' options={{ height: 400 }} {...props} />
173
- ```
313
+ const widget = SoluCXWidget
314
+ .create('SUA_CHAVE_SOLUCX')
315
+ .setData({ journey: 'pos_venda', user_id: 'user_123' });
174
316
 
175
- **⚠️ Importante**: O valor de `height` é sempre em **pontos** (points), não pixels, seguindo o padrão do React e React Native. O sistema operacional converte automaticamente para pixels considerando a densidade da tela.
317
+ // Limpar TODOS os logs (reseta contadores e timestamps)
318
+ await widget.clearWidgetLogs();
176
319
 
177
- ### WidgetType
320
+ // Apos limpar, o widget vai se comportar como se nunca tivesse sido exibido
321
+ widget.show();
322
+ ```
178
323
 
179
- ```typescript
180
- type WidgetType = 'bottom' | 'top' | 'inline' | 'modal';
324
+ ### Exemplo 9: Forcar exibicao do widget (ignorar bloqueio)
325
+
326
+ Se o widget esta sendo bloqueado por uma regra de supressao e voce quer forca-lo a exibir (por exemplo, para testes), sobrescreva a data do evento que esta bloqueando:
327
+
328
+ ```tsx
329
+ import { SoluCXWidget } from '@solucx/react-native-solucx-widget';
330
+
331
+ const widget = SoluCXWidget
332
+ .create('SUA_CHAVE_SOLUCX')
333
+ .setData({ journey: 'pos_venda', user_id: 'user_123' });
334
+
335
+ // Verificar qual evento esta bloqueando
336
+ const logs = await widget.getWidgetLogs();
337
+ console.log('Ultimo dismiss:', new Date(logs.lastDismiss));
338
+ console.log('Tentativas:', logs.attempts);
339
+
340
+ // Resetar o dismiss para desbloquear
341
+ await widget.overrideTimestamp('lastDismiss', 0);
342
+
343
+ // Agora o widget vai exibir (se nao houver outra regra bloqueando)
344
+ widget.show();
181
345
  ```
182
346
 
183
- ## 🔄 Sistema de Eventos
347
+ ### Exemplo 10: Isolamento por jornada — dois widgets independentes
184
348
 
185
- O widget processa automaticamente os seguintes eventos da pesquisa:
349
+ Cada combinacao de `instanceKey + journey + userId` tem seus proprios logs. Widgets de jornadas diferentes nao interferem entre si.
186
350
 
187
- - `FORM_OPENED` - Widget foi aberto
188
- - `FORM_CLOSE` - Usuário fechou o widget
189
- - `FORM_COMPLETED` - Pesquisa concluída
190
- - `FORM_PARTIALCOMPLETED` - Completada parcialmente
191
- - `FORM_RESIZE` - Widget redimensionado
192
- - `FORM_ERROR` - Erro no carregamento
351
+ ```tsx
352
+ import { SoluCXWidget } from '@solucx/react-native-solucx-widget';
193
353
 
194
- ## 💾 Persistência Inteligente
354
+ // Widget da jornada "pos_venda"
355
+ const widgetPosVenda = SoluCXWidget
356
+ .create('SUA_CHAVE_SOLUCX')
357
+ .setData({ journey: 'pos_venda', user_id: 'user_123' });
195
358
 
196
- O widget controla automaticamente:
359
+ // Widget da jornada "atendimento"
360
+ const widgetAtendimento = SoluCXWidget
361
+ .create('SUA_CHAVE_SOLUCX')
362
+ .setData({ journey: 'atendimento', user_id: 'user_123' });
197
363
 
198
- - **Histórico de tentativas**: Evita spam de widgets
199
- - **Última avaliação**: Data da última interação
200
- - **Controle de frequência**: Respeita configurações de exibição
201
- - **Armazenamento local**: Dados persistem entre sessões
364
+ // Os logs sao independentes:
365
+ const logsPosVenda = await widgetPosVenda.getWidgetLogs();
366
+ const logsAtendimento = await widgetAtendimento.getWidgetLogs();
367
+ // logsPosVenda pode ter 5 tentativas enquanto logsAtendimento tem 0
368
+
369
+ // Limpar os logs de uma jornada NAO afeta a outra
370
+ await widgetPosVenda.clearWidgetLogs();
371
+ // Apenas os logs de pos_venda foram resetados
372
+ ```
202
373
 
203
- ## ⚙️ Múltiplos Widgets
374
+ ### Exemplo 11: Widget sem userId (dispositivo anonimo)
375
+
376
+ Quando nao ha `user_id`, `email` ou `cpf`, os logs sao compartilhados por todos os usuarios daquela jornada naquele dispositivo.
204
377
 
205
378
  ```tsx
206
- const widgets = ['bottom', 'top'] as WidgetType[];
207
-
208
- return (
209
- <>
210
- {widgets.map((type) => (
211
- <SoluCXWidget
212
- key={type}
213
- soluCXKey={key}
214
- type={type}
215
- data={data}
216
- options={options}
217
- />
218
- ))}
219
- </>
220
- );
379
+ import { SoluCXWidget } from '@solucx/react-native-solucx-widget';
380
+
381
+ // Sem userId — logs sao por instanceKey:journey (compartilhado no dispositivo)
382
+ const widget = SoluCXWidget
383
+ .create('SUA_CHAVE_SOLUCX')
384
+ .setData({ journey: 'pos_venda' });
385
+
386
+ const logs = await widget.getWidgetLogs();
387
+ // Chave de armazenamento: "SUA_CHAVE_SOLUCX:pos_venda"
388
+
389
+ // Com userId — logs sao por instanceKey:journey:userId (isolado por usuario)
390
+ const widgetComUser = SoluCXWidget
391
+ .create('SUA_CHAVE_SOLUCX')
392
+ .setData({ journey: 'pos_venda', user_id: 'user_123' });
393
+
394
+ const logsComUser = await widgetComUser.getWidgetLogs();
395
+ // Chave de armazenamento: "SUA_CHAVE_SOLUCX:pos_venda:user_123"
221
396
  ```
222
397
 
223
- ## 🚨 Considerações Importantes
398
+ ---
399
+
400
+ ## Opcoes de Supressao (waitDays)
401
+
402
+ > **Importante:** Voce **nao precisa passar essas opcoes no codigo**. Elas podem (e devem) ser configuradas remotamente no painel de configuracao da jornada. O widget busca automaticamente as configuracoes da API quando `setOptions()` nao e chamado.
403
+
404
+ As opcoes controlam quantos dias o widget deve esperar apos cada tipo de evento antes de exibir novamente:
405
+
406
+ | Opcao | Descricao |
407
+ |---|---|
408
+ | `enabled` | Habilita/desabilita o widget. Quando `false`, bloqueia imediatamente sem validar outras regras |
409
+ | `samplingPercentage` | Porcentagem de usuarios que verao o widget (0-100). Valor 100 ou undefined = sem amostragem |
410
+ | `maxAttemptsAfterDismiss` | Numero maximo de tentativas de exibicao por experiencia |
411
+ | `waitDaysAfterWidgetDisplayAttempt` | Dias apos uma tentativa de exibicao bloqueada |
412
+ | `waitDaysAfterWidgetFirstAccess` | Dias apos o primeiro acesso do usuario a jornada |
413
+ | `waitDaysAfterWidgetDisplay` | Dias apos qualquer exibicao do widget |
414
+ | `waitDaysAfterWidgetDismiss` | Dias apos o usuario fechar o widget |
415
+ | `waitDaysAfterWidgetSubmit` | Dias apos o usuario responder a pesquisa |
416
+ | `waitDaysAfterWidgetPartialSubmit` | Dias apos o usuario responder parcialmente |
417
+
418
+ **Regras:**
419
+ - `enabled: false` bloqueia o widget **imediatamente** com `BLOCKED_BY_DISABLED`, sem verificar nenhuma outra regra
420
+ - `enabled: true` ou `undefined` = widget habilitado (comportamento padrao)
421
+ - `samplingPercentage`: sorteia se o usuario vera o widget. Ex: `50` = 50% de chance. Valor `100` ou `undefined` = todos veem. Valor `0` = ninguem ve
422
+ - Valor `0` ou `undefined` nos campos de dias = sem restricao (o campo nao bloqueia)
423
+ - Se **qualquer** regra bloquear, o widget nao exibe e chama `onBlocked(reason)`
424
+ - Quando bloqueado, o `reason` indica qual regra bloqueou (ex: `"BLOCKED_BY_WIDGET_DISMISS_INTERVAL"`)
425
+ - `maxAttemptsAfterDismiss` conta quantas vezes o widget foi exibido para aquela experiencia (jornada). Se o ID da experiencia (`journey` ou `form_id`) mudar, o contador de tentativas e resetado automaticamente
426
+ - Quando o usuario engaja na pesquisa (`QUESTION_ANSWERED`, envio completo ou envio parcial), o contador de tentativas tambem e resetado para nao bloquear exibicoes futuras por tentativas antigas
427
+ - Quando existe `transaction_id` e essa transacao ja foi concluida ou parcialmente concluida antes, o widget bloqueia localmente e nao faz chamadas de opcoes nem de preflight
428
+
429
+ ---
430
+
431
+ ## API Completa
432
+
433
+ ### `SoluCXWidget` (classe principal)
434
+
435
+ #### Metodos de construcao (builder pattern)
436
+
437
+ | Metodo | Descricao |
438
+ |---|---|
439
+ | `SoluCXWidget.create(soluCXKey)` | Cria uma nova instancia do widget |
440
+ | `.setType(type)` | Define o tipo: `'bottom'`, `'top'`, `'modal'`, `'inline'` |
441
+ | `.setData(data)` | Define os dados do usuario/transacao |
442
+ | `.setOptions(options)` | Define opcoes locais (**opcional** - se nao chamar, busca da API) |
443
+ | `.setCallbacks(callbacks)` | Define callbacks de eventos |
444
+ | `.show()` | Exibe o widget |
445
+
446
+ #### Metodos estaticos
447
+
448
+ | Metodo | Descricao |
449
+ |---|---|
450
+ | `SoluCXWidget.dismiss()` | Fecha o widget programaticamente |
224
451
 
225
- ### Posicionamento
452
+ #### Metodos de instancia (log management)
226
453
 
227
- ⚠️ **Comportamento Crítico**: A posição no JSX **não determina** onde widgets `top`, `bottom` e `modal` aparecem:
454
+ Usam os dados do builder (instanceKey, journey, userId) para acessar os logs da combinacao correta.
455
+
456
+ | Metodo | Descricao |
457
+ |---|---|
458
+ | `.getWidgetLogs()` | Retorna os logs de supressao |
459
+ | `.overrideTimestamp(field, date)` | Sobrescreve uma data de evento (debug/teste) |
460
+ | `.clearWidgetLogs()` | Limpa todos os logs |
461
+
462
+ > **Isolamento de armazenamento:** Os logs sao isolados por `instanceKey:journey:userId`. Um app com 2 widgets de jornadas diferentes tera dados de supressao independentes. O `userId` e opcional — quando presente, os logs sao por usuario.
463
+
464
+ ### `SoluCXWidgetHost` (componente React)
465
+
466
+ Componente que deve ser montado **uma vez** no root do app quando a integracao for feita por funcao com `SoluCXWidget.create(...).show()`. Nao e necessario ao usar `SoluCXWidgetView` diretamente.
228
467
 
229
468
  ```tsx
230
- // Widget "bottom" sempre aparece embaixo, independente da posição
231
- <Text>Conteúdo antes</Text>
232
- <SoluCXWidget type="bottom" {...props} />
233
- <Text>Conteúdo depois</Text>
234
-
235
- // ✅ Apenas "inline" respeita a posição no código
236
- <Text>Conteúdo antes</Text>
237
- <SoluCXWidget type="inline" {...props} />
238
- <Text>Conteúdo depois</Text>
469
+ import { SoluCXWidgetHost } from '@solucx/react-native-solucx-widget';
470
+
471
+ // No root do app
472
+ <SoluCXWidgetHost />
239
473
  ```
240
474
 
241
- ## 🔍 Troubleshooting
475
+ ### `SoluCXWidgetView` (componente React)
242
476
 
243
- ### Widget não aparece
477
+ Componente para uso direto no JSX. Pode ser usado no lugar do fluxo por funcao quando fizer mais sentido controlar a renderizacao pelo componente.
244
478
 
245
- ```typescript
246
- // Verificações essenciais:
247
- // ✅ Chave SoluCX válida?
248
- // ✅ Conectividade com internet?
249
- // ✅ Logs do WebView no console?
250
- // ✅ Dados obrigatórios preenchidos?
479
+ ```tsx
480
+ import { SoluCXWidgetView } from '@solucx/react-native-solucx-widget';
481
+
482
+ <SoluCXWidgetView
483
+ soluCXKey="SUA_CHAVE_SOLUCX"
484
+ type="inline"
485
+ data={{ journey: 'pos_venda', user_id: 'user_123' }}
486
+ />
251
487
  ```
252
488
 
253
- ### Eventos não funcionam
489
+ **Props:**
490
+
491
+ | Prop | Descricao |
492
+ |---|---|
493
+ | `soluCXKey` | Chave de instancia do widget |
494
+ | `type` | Tipo do widget: `'bottom'`, `'top'`, `'modal'`, `'inline'` |
495
+ | `data` | Dados do usuario/transacao |
496
+ | `options` | Opcoes locais de configuracao e supressao |
497
+ | `callbacks` | Callbacks de ciclo de vida e eventos |
498
+
499
+ ### WidgetData
254
500
 
255
501
  ```typescript
256
- // Debug de comunicação:
257
- const handleMessage = (message: string) => {
258
- console.log('Widget event:', message);
259
- };
502
+ interface WidgetData {
503
+ journey?: string; // Nome da jornada (obrigatorio na pratica)
504
+ user_id?: string; // ID do usuario
505
+ email?: string; // Email do usuario
506
+ name?: string; // Nome do usuario
507
+ cpf?: string; // CPF
508
+ document?: string; // Documento
509
+ phone?: string; // Telefone
510
+ phone2?: string; // Telefone secundario
511
+ birth_date?: string; // Data de nascimento (YYYY-MM-DD)
512
+ transaction_id?: string; // ID da transacao
513
+ customer_id?: string; // ID do cliente
514
+ store_id?: string; // ID da loja
515
+ store_name?: string; // Nome da loja
516
+ employee_id?: string; // ID do funcionario
517
+ employee_name?: string; // Nome do funcionario
518
+ amount?: number; // Valor da transacao
519
+ score?: number; // Score
520
+ [key: `param_${string}`]: string | number | undefined; // Parametros customizados
521
+ }
522
+ ```
523
+
524
+ ### WidgetCallbacks
260
525
 
261
- // Verificar se JavaScript foi injetado corretamente
526
+ ```typescript
527
+ interface WidgetCallbacks {
528
+ onPreOpen?: (userId: string) => void; // Antes de abrir
529
+ onOpened?: (userId: string) => void; // Widget aberto
530
+ onBlocked?: (reason: BlockReason) => void; // Widget bloqueado por regra de supressao
531
+ onClosed?: () => void; // Usuario fechou
532
+ onCompleted?: (userId: string) => void; // Pesquisa respondida
533
+ onPartialCompleted?: (userId: string) => void; // Pesquisa parcialmente respondida
534
+ onError?: (message: string) => void; // Erro no widget
535
+ onPageChanged?: (page: string) => void; // Pagina mudou
536
+ onQuestionAnswered?: () => void; // Pergunta respondida
537
+ onResize?: (height: string) => void; // Widget redimensionou
538
+ }
262
539
  ```
263
540
 
264
- ### Layout quebrado
541
+ ### WidgetOptions
265
542
 
266
543
  ```typescript
267
- // Ajustar dimensões para o dispositivo:
268
- const { height } = Dimensions.get('window');
544
+ interface WidgetOptions {
545
+ enabled?: boolean; // Habilita/desabilita o widget (default: true). Quando false, bloqueia sem validar.
546
+ samplingPercentage?: number; // Porcentagem de usuarios que verao o widget (0-100). Default: 100 (todos).
547
+ height?: number; // Altura fixa em pontos (se nao informado, altura dinamica)
548
+ maxAttemptsAfterDismiss?: number; // Maximo de tentativas por experiencia (0 ou undefined = sem limite)
549
+ // Regras de supressao (opcionais - configuradas remotamente pelo painel da jornada):
550
+ waitDaysAfterWidgetDisplayAttempt?: number;
551
+ waitDaysAfterWidgetFirstAccess?: number;
552
+ waitDaysAfterWidgetDisplay?: number;
553
+ waitDaysAfterWidgetDismiss?: number;
554
+ waitDaysAfterWidgetSubmit?: number;
555
+ waitDaysAfterWidgetPartialSubmit?: number;
556
+ }
557
+ ```
269
558
 
270
- const options = {
271
- height: Math.min(height * 0.6, 400)
272
- };
559
+ ### BlockReason
560
+
561
+ Valores possiveis retornados no callback `onBlocked`:
562
+
563
+ | Valor | Significado |
564
+ |---|---|
565
+ | `BLOCKED_BY_DISABLED` | Widget desabilitado (enabled: false) |
566
+ | `BLOCKED_BY_SAMPLING` | Usuario nao foi selecionado pela amostragem (samplingPercentage) |
567
+ | `BLOCKED_BY_MAX_ATTEMPTS` | Numero maximo de tentativas atingido para esta experiencia |
568
+ | `BLOCKED_BY_WIDGET_DISPLAY_ATTEMPT_INTERVAL` | Dentro do intervalo apos tentativa de exibicao |
569
+ | `BLOCKED_BY_WIDGET_FIRST_ACCESS_INTERVAL` | Dentro do intervalo apos primeira visualizacao |
570
+ | `BLOCKED_BY_WIDGET_DISPLAY_INTERVAL` | Dentro do intervalo apos exibicao |
571
+ | `BLOCKED_BY_WIDGET_DISMISS_INTERVAL` | Dentro do intervalo apos fechamento |
572
+ | `BLOCKED_BY_WIDGET_SUBMIT_INTERVAL` | Dentro do intervalo apos envio completo |
573
+ | `BLOCKED_BY_WIDGET_PARTIAL_SUBMIT_INTERVAL` | Dentro do intervalo apos envio parcial |
574
+
575
+ ---
576
+
577
+ ## Fluxo Interno
578
+
579
+ ```
580
+ App chama SoluCXWidget.create('KEY').setData({...}).show()
581
+ |
582
+ v
583
+ SoluCXWidgetHost recebe a configuracao
584
+ |
585
+ v
586
+ Widget monta e executa bootstrap():
587
+ |
588
+ +-- Se setOptions() FOI chamado --> usa opcoes locais
589
+ +-- Se setOptions() NAO foi chamado --> busca opcoes da API (painel da jornada)
590
+ |
591
+ +-- shouldDisplayWidget() verifica enabled + maxAttemptsAfterDismiss + 6 regras de supressao
592
+ +-- (validacao LOCAL, antes de chamar a API, para reduzir carga no servidor):
593
+ | +-- Se transaction_id ja respondido --> onBlocked('BLOCKED_BY_TRANSACTION_ALREADY_ANSWERED'), widget NAO exibe
594
+ | +-- Se enabled === false --> onBlocked('BLOCKED_BY_DISABLED'), widget NAO exibe
595
+ | +-- Sorteia baseado em samplingPercentage --> se nao selecionado, onBlocked('BLOCKED_BY_SAMPLING')
596
+ | +-- Se experiencia mudou --> reseta contador de tentativas
597
+ | +-- Se tentativas >= maxAttemptsAfterDismiss --> onBlocked('BLOCKED_BY_MAX_ATTEMPTS')
598
+ | +-- Para cada regra: timestamp do evento + dias de espera > agora?
599
+ | +-- Se QUALQUER regra bloqueia --> onBlocked(reason), widget NAO exibe
600
+ | +-- Se NENHUMA bloqueia --> continua
601
+ |
602
+ +-- Busca URL do formulario na API (preflight)
603
+ |
604
+ +-- Se EXIBE:
605
+ | +-- Incrementa contador de tentativas
606
+ | +-- Salva lastDisplay (e lastFirstAccess na primeira vez)
607
+ | +-- Renderiza WebView com o formulario
608
+ | +-- onOpened(userId)
609
+ |
610
+ +-- Eventos do usuario:
611
+ +-- Fecha widget --> salva lastDismiss, onClosed()
612
+ +-- Responde pergunta --> zera contador de tentativas, onQuestionAnswered()
613
+ +-- Responde pesquisa --> zera contador de tentativas, salva transaction_id respondido, salva lastSubmit, onCompleted(userId)
614
+ +-- Resposta parcial --> zera contador de tentativas, salva transaction_id respondido, salva lastPartialSubmit, onPartialCompleted(userId)
273
615
  ```
274
616
 
275
- ## 📚 Compatibilidade
617
+ ---
618
+
619
+ ## Compatibilidade
276
620
 
277
- | Versão | React Native | Expo | iOS | Android |
278
- | ------ | ------------ | ---- | --- | ------- |
279
- | 1.0.x | 0.70+ | 50+ | 11+ | API 21+ |
621
+ | Versao | React Native | Expo | iOS | Android |
622
+ |---|---|---|---|---|
623
+ | 1.0.x | 0.70+ | 50+ | 11+ | API 21+ |
280
624
 
281
- ## 📄 Licença
625
+ ## Licenca
282
626
 
283
- Este pacote é proprietário da SoluCX. O uso é restrito a clientes licenciados da plataforma SoluCX.
627
+ Proprietario - SoluCX. Uso restrito a clientes licenciados.
284
628
 
285
629
  ---