@billdog.io/react-native 1.0.0-beta.2

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 (309) hide show
  1. package/BillDogReactNative.podspec +30 -0
  2. package/LICENSE +21 -0
  3. package/README.md +330 -0
  4. package/android/build.gradle +99 -0
  5. package/android/src/main/AndroidManifest.xml +1 -0
  6. package/android/src/main/kotlin/io/billdog/reactnative/BillDogABTestModule.kt +317 -0
  7. package/android/src/main/kotlin/io/billdog/reactnative/BillDogAnalyticsModule.kt +389 -0
  8. package/android/src/main/kotlin/io/billdog/reactnative/BillDogModule.kt +817 -0
  9. package/android/src/main/kotlin/io/billdog/reactnative/BillDogPaywallViewManager.kt +383 -0
  10. package/android/src/main/kotlin/io/billdog/reactnative/BillDogSurveyModule.kt +427 -0
  11. package/android/src/main/kotlin/io/billdog/reactnative/BillDogVirtualCurrencyModule.kt +407 -0
  12. package/android/src/main/kotlin/io/billdog/virtualcurrency/BillDogVirtualCurrencyPackage.kt +44 -0
  13. package/dist/AdvancedPaywallCache.d.ts +70 -0
  14. package/dist/AdvancedPaywallCache.js +344 -0
  15. package/dist/BillDog.d.ts +255 -0
  16. package/dist/BillDog.js +918 -0
  17. package/dist/BillDogConfiguration.d.ts +145 -0
  18. package/dist/BillDogConfiguration.js +229 -0
  19. package/dist/ComponentRenderer.d.ts +17 -0
  20. package/dist/ComponentRenderer.js +886 -0
  21. package/dist/LayoutEngine.d.ts +101 -0
  22. package/dist/LayoutEngine.js +394 -0
  23. package/dist/LocalizationResolver.d.ts +99 -0
  24. package/dist/LocalizationResolver.js +266 -0
  25. package/dist/NativePaywallView.d.ts +36 -0
  26. package/dist/NativePaywallView.js +59 -0
  27. package/dist/PaywallCache.d.ts +74 -0
  28. package/dist/PaywallCache.js +293 -0
  29. package/dist/PaywallStateManager.d.ts +62 -0
  30. package/dist/PaywallStateManager.js +147 -0
  31. package/dist/PaywallView.d.ts +42 -0
  32. package/dist/PaywallView.js +275 -0
  33. package/dist/ProductVariableProvider.d.ts +60 -0
  34. package/dist/ProductVariableProvider.js +239 -0
  35. package/dist/VariableResolver.d.ts +120 -0
  36. package/dist/VariableResolver.js +379 -0
  37. package/dist/WebViewPaywall.d.ts +75 -0
  38. package/dist/WebViewPaywall.js +360 -0
  39. package/dist/animations/presets.d.ts +49 -0
  40. package/dist/animations/presets.js +367 -0
  41. package/dist/components/AccoladeCpsComponent.d.ts +13 -0
  42. package/dist/components/AccoladeCpsComponent.js +248 -0
  43. package/dist/components/AccordionComponent.d.ts +10 -0
  44. package/dist/components/AccordionComponent.js +187 -0
  45. package/dist/components/AnimatedWrapper.d.ts +35 -0
  46. package/dist/components/AnimatedWrapper.js +277 -0
  47. package/dist/components/CarouselComponent.d.ts +23 -0
  48. package/dist/components/CarouselComponent.js +484 -0
  49. package/dist/components/ChartCurveComponent.d.ts +13 -0
  50. package/dist/components/ChartCurveComponent.js +333 -0
  51. package/dist/components/CheckboxComponent.d.ts +9 -0
  52. package/dist/components/CheckboxComponent.js +172 -0
  53. package/dist/components/ConfettiComponent.d.ts +9 -0
  54. package/dist/components/ConfettiComponent.js +172 -0
  55. package/dist/components/CountdownComponent.d.ts +16 -0
  56. package/dist/components/CountdownComponent.js +414 -0
  57. package/dist/components/DelayedXComponent.d.ts +12 -0
  58. package/dist/components/DelayedXComponent.js +240 -0
  59. package/dist/components/DrawerModalComponent.d.ts +20 -0
  60. package/dist/components/DrawerModalComponent.js +286 -0
  61. package/dist/components/GradientView.d.ts +38 -0
  62. package/dist/components/GradientView.js +126 -0
  63. package/dist/components/HapticFeedbackComponent.d.ts +16 -0
  64. package/dist/components/HapticFeedbackComponent.js +64 -0
  65. package/dist/components/HorizontalProductsComponent.d.ts +17 -0
  66. package/dist/components/HorizontalProductsComponent.js +284 -0
  67. package/dist/components/MultiChoiceGridComponent.d.ts +13 -0
  68. package/dist/components/MultiChoiceGridComponent.js +234 -0
  69. package/dist/components/NPSScaleComponent.d.ts +16 -0
  70. package/dist/components/NPSScaleComponent.js +260 -0
  71. package/dist/components/NavigationComponent.d.ts +26 -0
  72. package/dist/components/NavigationComponent.js +302 -0
  73. package/dist/components/OAuthButtonComponent.d.ts +20 -0
  74. package/dist/components/OAuthButtonComponent.js +237 -0
  75. package/dist/components/ProgressLoaderComponent.d.ts +13 -0
  76. package/dist/components/ProgressLoaderComponent.js +308 -0
  77. package/dist/components/ProgressStepperComponent.d.ts +18 -0
  78. package/dist/components/ProgressStepperComponent.js +228 -0
  79. package/dist/components/SegmentedPickerComponent.d.ts +10 -0
  80. package/dist/components/SegmentedPickerComponent.js +221 -0
  81. package/dist/components/ShareButtonsComponent.d.ts +21 -0
  82. package/dist/components/ShareButtonsComponent.js +265 -0
  83. package/dist/components/ShareCodeComponent.d.ts +16 -0
  84. package/dist/components/ShareCodeComponent.js +274 -0
  85. package/dist/components/SingleChoiceGridComponent.d.ts +13 -0
  86. package/dist/components/SingleChoiceGridComponent.js +210 -0
  87. package/dist/components/SliderComponent.d.ts +9 -0
  88. package/dist/components/SliderComponent.js +263 -0
  89. package/dist/components/StarRatingInputComponent.d.ts +20 -0
  90. package/dist/components/StarRatingInputComponent.js +198 -0
  91. package/dist/components/StickerCompositeComponent.d.ts +13 -0
  92. package/dist/components/StickerCompositeComponent.js +136 -0
  93. package/dist/components/TabsComponent.d.ts +19 -0
  94. package/dist/components/TabsComponent.js +431 -0
  95. package/dist/components/TextInputComponent.d.ts +18 -0
  96. package/dist/components/TextInputComponent.js +227 -0
  97. package/dist/components/TimelineComponent.d.ts +19 -0
  98. package/dist/components/TimelineComponent.js +104 -0
  99. package/dist/components/ToggleComponent.d.ts +14 -0
  100. package/dist/components/ToggleComponent.js +132 -0
  101. package/dist/components/VerticalProductsComponent.d.ts +17 -0
  102. package/dist/components/VerticalProductsComponent.js +311 -0
  103. package/dist/dynamicValues.d.ts +36 -0
  104. package/dist/dynamicValues.js +142 -0
  105. package/dist/filters/dateFilters.d.ts +50 -0
  106. package/dist/filters/dateFilters.js +390 -0
  107. package/dist/filters/index.d.ts +18 -0
  108. package/dist/filters/index.js +253 -0
  109. package/dist/hooks/useOfferings.d.ts +76 -0
  110. package/dist/hooks/useOfferings.js +99 -0
  111. package/dist/hooks/usePaywall.d.ts +27 -0
  112. package/dist/hooks/usePaywall.js +114 -0
  113. package/dist/hooks/usePlacement.d.ts +34 -0
  114. package/dist/hooks/usePlacement.js +89 -0
  115. package/dist/hooks/useSubscription.d.ts +40 -0
  116. package/dist/hooks/useSubscription.js +97 -0
  117. package/dist/index.d.ts +98 -0
  118. package/dist/index.js +198 -0
  119. package/dist/models/BillDogError.d.ts +40 -0
  120. package/dist/models/BillDogError.js +11 -0
  121. package/dist/models/CacheFetchPolicy.d.ts +8 -0
  122. package/dist/models/CacheFetchPolicy.js +4 -0
  123. package/dist/models/CustomProduct.d.ts +32 -0
  124. package/dist/models/CustomProduct.js +15 -0
  125. package/dist/models/CustomerInfo.d.ts +17 -0
  126. package/dist/models/CustomerInfo.js +11 -0
  127. package/dist/models/Delegate.d.ts +20 -0
  128. package/dist/models/Delegate.js +11 -0
  129. package/dist/models/EntitlementInfo.d.ts +19 -0
  130. package/dist/models/EntitlementInfo.js +2 -0
  131. package/dist/models/Placement.d.ts +54 -0
  132. package/dist/models/Placement.js +15 -0
  133. package/dist/models/PurchaseParams.d.ts +39 -0
  134. package/dist/models/PurchaseParams.js +60 -0
  135. package/dist/models/PurchaseResult.d.ts +30 -0
  136. package/dist/models/PurchaseResult.js +15 -0
  137. package/dist/models/RestoreResult.d.ts +30 -0
  138. package/dist/models/RestoreResult.js +22 -0
  139. package/dist/models/RestoredItem.d.ts +26 -0
  140. package/dist/models/RestoredItem.js +13 -0
  141. package/dist/modules/ABTest.d.ts +65 -0
  142. package/dist/modules/ABTest.js +113 -0
  143. package/dist/modules/Analytics.d.ts +91 -0
  144. package/dist/modules/Analytics.js +182 -0
  145. package/dist/modules/Survey.d.ts +65 -0
  146. package/dist/modules/Survey.js +82 -0
  147. package/dist/modules/VirtualCurrency.d.ts +63 -0
  148. package/dist/modules/VirtualCurrency.js +147 -0
  149. package/dist/murmur.d.ts +23 -0
  150. package/dist/murmur.js +104 -0
  151. package/dist/notifications/LiveActivitiesManager.d.ts +47 -0
  152. package/dist/notifications/LiveActivitiesManager.js +106 -0
  153. package/dist/notifications/NotificationScheduler.d.ts +55 -0
  154. package/dist/notifications/NotificationScheduler.js +199 -0
  155. package/dist/notifications/PurchaseNotificationHandler.d.ts +24 -0
  156. package/dist/notifications/PurchaseNotificationHandler.js +55 -0
  157. package/dist/notifications/useDeviceToken.d.ts +36 -0
  158. package/dist/notifications/useDeviceToken.js +97 -0
  159. package/dist/notifications/useLiveActivity.d.ts +39 -0
  160. package/dist/notifications/useLiveActivity.js +104 -0
  161. package/dist/review/ReviewAnalytics.d.ts +34 -0
  162. package/dist/review/ReviewAnalytics.js +73 -0
  163. package/dist/review/ReviewManager.d.ts +83 -0
  164. package/dist/review/ReviewManager.js +339 -0
  165. package/dist/review/ReviewTimingManager.d.ts +82 -0
  166. package/dist/review/ReviewTimingManager.js +224 -0
  167. package/dist/survey-core/types.d.ts +215 -0
  168. package/dist/survey-core/types.js +8 -0
  169. package/dist/types.d.ts +438 -0
  170. package/dist/types.js +158 -0
  171. package/dist/utils/ApiClient.d.ts +65 -0
  172. package/dist/utils/ApiClient.js +132 -0
  173. package/dist/utils/CSSConverter.d.ts +49 -0
  174. package/dist/utils/CSSConverter.js +470 -0
  175. package/dist/utils/animations.d.ts +41 -0
  176. package/dist/utils/animations.js +194 -0
  177. package/dist/utils/calendarIntegration.d.ts +36 -0
  178. package/dist/utils/calendarIntegration.js +89 -0
  179. package/dist/utils/configurationResolver.d.ts +23 -0
  180. package/dist/utils/configurationResolver.js +78 -0
  181. package/dist/utils/deviceDetection.d.ts +38 -0
  182. package/dist/utils/deviceDetection.js +59 -0
  183. package/dist/utils/hapticFeedback.d.ts +17 -0
  184. package/dist/utils/hapticFeedback.js +53 -0
  185. package/dist/utils/iconMapper.d.ts +26 -0
  186. package/dist/utils/iconMapper.js +113 -0
  187. package/dist/utils/notificationPermissions.d.ts +13 -0
  188. package/dist/utils/notificationPermissions.js +51 -0
  189. package/dist/utils/priceFormatting.d.ts +19 -0
  190. package/dist/utils/priceFormatting.js +99 -0
  191. package/dist/utils/shareSheet.d.ts +17 -0
  192. package/dist/utils/shareSheet.js +42 -0
  193. package/dist/utils/subscriptionUpgrade.d.ts +84 -0
  194. package/dist/utils/subscriptionUpgrade.js +100 -0
  195. package/dist/valueUtils.d.ts +48 -0
  196. package/dist/valueUtils.js +129 -0
  197. package/dist/xFlowTags.d.ts +18 -0
  198. package/dist/xFlowTags.js +385 -0
  199. package/ios/BillDogABTest.m +50 -0
  200. package/ios/BillDogABTest.swift +188 -0
  201. package/ios/BillDogAnalytics.m +105 -0
  202. package/ios/BillDogAnalytics.swift +324 -0
  203. package/ios/BillDogBridge.m +222 -0
  204. package/ios/BillDogBridge.swift +715 -0
  205. package/ios/BillDogLiveActivities.m +41 -0
  206. package/ios/BillDogLiveActivities.swift +104 -0
  207. package/ios/BillDogPaywallViewManager.m +39 -0
  208. package/ios/BillDogPaywallViewManager.swift +361 -0
  209. package/ios/BillDogSurvey.m +34 -0
  210. package/ios/BillDogSurvey.swift +257 -0
  211. package/ios/BillDogVirtualCurrencyBridge.m +63 -0
  212. package/ios/BillDogVirtualCurrencyBridge.swift +511 -0
  213. package/junit.xml +25 -0
  214. package/package.json +61 -0
  215. package/react-native.config.js +13 -0
  216. package/src/AdvancedPaywallCache.ts +433 -0
  217. package/src/BillDog.ts +983 -0
  218. package/src/BillDogConfiguration.ts +318 -0
  219. package/src/ComponentRenderer.tsx +1325 -0
  220. package/src/LayoutEngine.ts +459 -0
  221. package/src/LocalizationResolver.ts +311 -0
  222. package/src/NativePaywallView.tsx +132 -0
  223. package/src/PaywallCache.ts +358 -0
  224. package/src/PaywallStateManager.ts +154 -0
  225. package/src/PaywallView.tsx +328 -0
  226. package/src/ProductVariableProvider.ts +282 -0
  227. package/src/VariableResolver.ts +516 -0
  228. package/src/WebViewPaywall.tsx +454 -0
  229. package/src/animations/presets.ts +421 -0
  230. package/src/components/AccoladeCpsComponent.tsx +259 -0
  231. package/src/components/AccordionComponent.tsx +213 -0
  232. package/src/components/AnimatedWrapper.tsx +316 -0
  233. package/src/components/CarouselComponent.tsx +615 -0
  234. package/src/components/ChartCurveComponent.tsx +452 -0
  235. package/src/components/CheckboxComponent.tsx +185 -0
  236. package/src/components/ConfettiComponent.tsx +178 -0
  237. package/src/components/CountdownComponent.tsx +454 -0
  238. package/src/components/DelayedXComponent.tsx +266 -0
  239. package/src/components/DrawerModalComponent.tsx +324 -0
  240. package/src/components/GradientView.tsx +129 -0
  241. package/src/components/HapticFeedbackComponent.tsx +39 -0
  242. package/src/components/HorizontalProductsComponent.tsx +329 -0
  243. package/src/components/MultiChoiceGridComponent.tsx +265 -0
  244. package/src/components/NPSScaleComponent.tsx +294 -0
  245. package/src/components/NavigationComponent.tsx +329 -0
  246. package/src/components/OAuthButtonComponent.tsx +266 -0
  247. package/src/components/ProgressLoaderComponent.tsx +366 -0
  248. package/src/components/ProgressStepperComponent.tsx +250 -0
  249. package/src/components/SegmentedPickerComponent.tsx +245 -0
  250. package/src/components/ShareButtonsComponent.tsx +299 -0
  251. package/src/components/ShareCodeComponent.tsx +303 -0
  252. package/src/components/SingleChoiceGridComponent.tsx +229 -0
  253. package/src/components/SliderComponent.tsx +280 -0
  254. package/src/components/StarRatingInputComponent.tsx +223 -0
  255. package/src/components/StickerCompositeComponent.tsx +168 -0
  256. package/src/components/TabsComponent.tsx +496 -0
  257. package/src/components/TextInputComponent.tsx +258 -0
  258. package/src/components/TimelineComponent.tsx +129 -0
  259. package/src/components/ToggleComponent.tsx +142 -0
  260. package/src/components/VerticalProductsComponent.tsx +357 -0
  261. package/src/dynamicValues.ts +180 -0
  262. package/src/filters/dateFilters.ts +411 -0
  263. package/src/filters/index.ts +281 -0
  264. package/src/hooks/useOfferings.ts +192 -0
  265. package/src/hooks/usePaywall.ts +154 -0
  266. package/src/hooks/usePlacement.ts +143 -0
  267. package/src/hooks/useSubscription.ts +154 -0
  268. package/src/index.ts +245 -0
  269. package/src/models/BillDogError.ts +24 -0
  270. package/src/models/CacheFetchPolicy.ts +13 -0
  271. package/src/models/CustomProduct.ts +33 -0
  272. package/src/models/CustomerInfo.ts +26 -0
  273. package/src/models/Delegate.ts +22 -0
  274. package/src/models/EntitlementInfo.ts +27 -0
  275. package/src/models/Placement.ts +50 -0
  276. package/src/models/PurchaseParams.ts +81 -0
  277. package/src/models/PurchaseResult.ts +32 -0
  278. package/src/models/RestoreResult.ts +27 -0
  279. package/src/models/RestoredItem.ts +25 -0
  280. package/src/modules/ABTest.ts +131 -0
  281. package/src/modules/Analytics.ts +227 -0
  282. package/src/modules/Survey.ts +126 -0
  283. package/src/modules/VirtualCurrency.ts +223 -0
  284. package/src/murmur.ts +102 -0
  285. package/src/notifications/LiveActivitiesManager.ts +140 -0
  286. package/src/notifications/NotificationScheduler.ts +292 -0
  287. package/src/notifications/PurchaseNotificationHandler.ts +67 -0
  288. package/src/notifications/useDeviceToken.ts +116 -0
  289. package/src/notifications/useLiveActivity.ts +125 -0
  290. package/src/review/ReviewAnalytics.ts +89 -0
  291. package/src/review/ReviewManager.ts +355 -0
  292. package/src/review/ReviewTimingManager.ts +265 -0
  293. package/src/survey-core/types.ts +244 -0
  294. package/src/types/ambient.d.ts +9 -0
  295. package/src/types.ts +680 -0
  296. package/src/utils/ApiClient.ts +163 -0
  297. package/src/utils/CSSConverter.ts +552 -0
  298. package/src/utils/animations.ts +232 -0
  299. package/src/utils/calendarIntegration.ts +113 -0
  300. package/src/utils/configurationResolver.ts +106 -0
  301. package/src/utils/deviceDetection.ts +83 -0
  302. package/src/utils/hapticFeedback.ts +55 -0
  303. package/src/utils/iconMapper.ts +102 -0
  304. package/src/utils/notificationPermissions.ts +48 -0
  305. package/src/utils/priceFormatting.ts +119 -0
  306. package/src/utils/shareSheet.ts +55 -0
  307. package/src/utils/subscriptionUpgrade.ts +183 -0
  308. package/src/valueUtils.ts +108 -0
  309. package/src/xFlowTags.ts +463 -0
@@ -0,0 +1,427 @@
1
+ package io.billdog.reactnative
2
+
3
+ import android.app.Activity
4
+ import android.util.Log
5
+ import com.facebook.react.bridge.Arguments
6
+ import com.facebook.react.bridge.Promise
7
+ import com.facebook.react.bridge.ReactApplicationContext
8
+ import com.facebook.react.bridge.ReactContextBaseJavaModule
9
+ import com.facebook.react.bridge.ReactMethod
10
+ import com.facebook.react.bridge.ReadableArray
11
+ import com.facebook.react.bridge.ReadableMap
12
+ import com.facebook.react.bridge.WritableArray
13
+ import com.facebook.react.bridge.WritableMap
14
+ import com.facebook.react.modules.core.DeviceEventManagerModule
15
+ import io.billdog.core.BillDog
16
+ import io.billdog.core.BillDogEventBus
17
+ import io.billdog.survey.SurveyAnswer
18
+ import io.billdog.survey.SurveyChoiceConfig
19
+ import io.billdog.survey.SurveyConfig
20
+ import io.billdog.survey.SurveyLogicRule
21
+ import io.billdog.survey.SurveyMobileDisplayConfig
22
+ import io.billdog.survey.SurveyPageConfig
23
+ import io.billdog.survey.SurveyPresentationHandler
24
+ import io.billdog.survey.SurveyQuestionConfig
25
+ import io.billdog.survey.SurveySubmitResult
26
+ import kotlinx.coroutines.CoroutineScope
27
+ import kotlinx.coroutines.Dispatchers
28
+ import kotlinx.coroutines.SupervisorJob
29
+ import kotlinx.coroutines.cancel
30
+ import kotlinx.coroutines.launch
31
+ import java.util.concurrent.atomic.AtomicBoolean
32
+
33
+ /**
34
+ * BillDogSurvey — React Native native module for Android
35
+ * (`NativeModules.BillDogSurvey`).
36
+ *
37
+ * Thin bridge: `@ReactMethod`s delegate to the core survey facades resolved from
38
+ * `BillDog.getSurveyPresenter()` (billdog-core BillDog.kt:1969) and
39
+ * `BillDog.getSurveyManager()` (BillDog.kt:2022) — the same entry points the
40
+ * Flutter plugin uses. The authoritative JS contract is `src/modules/Survey.ts`;
41
+ * each `BillDogSurvey.<method>(...)` maps to the identically-named method below.
42
+ * When the SDK is not configured these accessors return null → present rejects
43
+ * "NO_ACTIVITY"/no-ops, and the data calls resolve their JS defaults.
44
+ *
45
+ * `onSurveyCompleted` / `onSurveyDismissed` are emitted by subscribing to the
46
+ * SDK EventBus SURVEY_COMPLETED (BillDogEventBus.kt:40) / SURVEY_DISMISSED
47
+ * (:41) signals, which the core SurveyPresenter fires on every present() path.
48
+ *
49
+ * ⚠️ VERIFICATION: this file cannot be compiled in this environment — there is
50
+ * no Android/Gradle toolchain present. It needs a Gradle/Android build to
51
+ * type-check against io.billdog:billdog-core (which `api`-exposes billdog-survey
52
+ * models) + kotlinx-coroutines. Every native symbol below is cited to file:line.
53
+ *
54
+ * ⚠️ SERIALIZATION SCOPE: kotlinx-serialization-json is `implementation`-scoped
55
+ * in billdog-survey/billdog-core, so it is NOT on this bridge's compile
56
+ * classpath. Survey models are therefore hand-serialized via their plain
57
+ * (String/Int/Boolean/List) fields ONLY; the `JsonElement`-typed maps
58
+ * (`SurveyConfig.settings`, `SurveyPageConfig.settings`,
59
+ * `SurveyQuestionConfig.config`/`settings`, logic-rule conditions,
60
+ * `SurveyAnswer.answer_json`) are omitted. Full-fidelity serialization would
61
+ * require declaring kotlinx-serialization-json in android/build.gradle.
62
+ */
63
+ class BillDogSurveyModule(private val reactContext: ReactApplicationContext) :
64
+ ReactContextBaseJavaModule(reactContext) {
65
+
66
+ private val TAG = "BillDogSurvey"
67
+
68
+ /** suspend fetch/submit are launched here; cancelled in invalidate(). */
69
+ private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
70
+
71
+ private var completedSubscription: String? = null
72
+ private var dismissedSubscription: String? = null
73
+
74
+ override fun getName(): String = "BillDogSurvey"
75
+
76
+ init {
77
+ // Bridge the SDK EventBus survey signals → RN events. subscribe() —
78
+ // BillDogEventBus.kt:77. These fire for EVERY present() path (the core
79
+ // SurveyPresenter wrapHandler emits them), so one subscription covers
80
+ // programmatic present, auto-triggered surveys, and intercepts alike.
81
+ completedSubscription = BillDogEventBus.subscribe(
82
+ BillDogEventBus.EventTypes.SURVEY_COMPLETED // BillDogEventBus.kt:40
83
+ ) { event ->
84
+ // Bus event carries { survey_id, respondent_id } only — the full
85
+ // answer set is delivered on the present() promise, not here.
86
+ emit("onSurveyCompleted", toWritableMap(mapOf(
87
+ "survey_id" to (event.properties["survey_id"]?.toString() ?: ""),
88
+ "respondent_id" to (event.properties["respondent_id"]?.toString())
89
+ )))
90
+ }
91
+ dismissedSubscription = BillDogEventBus.subscribe(
92
+ BillDogEventBus.EventTypes.SURVEY_DISMISSED // BillDogEventBus.kt:41
93
+ ) { event ->
94
+ // Bus event carries only { survey_id }; pageIndex is unavailable → 0.
95
+ emit("onSurveyDismissed", toWritableMap(mapOf(
96
+ "surveyId" to (event.properties["survey_id"]?.toString() ?: ""),
97
+ "pageIndex" to 0
98
+ )))
99
+ }
100
+ }
101
+
102
+ // ── Lifecycle ──────────────────────────────────────────────────────────
103
+
104
+ override fun invalidate() {
105
+ completedSubscription?.let { BillDogEventBus.unsubscribe(it) } // BillDogEventBus.kt:84
106
+ dismissedSubscription?.let { BillDogEventBus.unsubscribe(it) }
107
+ scope.cancel()
108
+ super.invalidate()
109
+ }
110
+
111
+ @Deprecated("Deprecated in RN; kept for older RN versions that call it instead of invalidate()")
112
+ override fun onCatalystInstanceDestroy() {
113
+ completedSubscription?.let { BillDogEventBus.unsubscribe(it) }
114
+ dismissedSubscription?.let { BillDogEventBus.unsubscribe(it) }
115
+ scope.cancel()
116
+ @Suppress("DEPRECATION")
117
+ super.onCatalystInstanceDestroy()
118
+ }
119
+
120
+ private fun run(promise: Promise, block: suspend () -> Any?) {
121
+ scope.launch {
122
+ try {
123
+ promise.resolve(block())
124
+ } catch (e: Throwable) {
125
+ promise.reject("BILLDOG_ERROR", e.message, e)
126
+ }
127
+ }
128
+ }
129
+
130
+ // ── Init ────────────────────────────────────────────────────────────────
131
+
132
+ /**
133
+ * BillDogSurvey.initialize() — surveys are configured by the core
134
+ * `BillDog.configure(...)`; no per-module native init. Resolve null (no-op).
135
+ */
136
+ @ReactMethod
137
+ fun initialize(promise: Promise) {
138
+ Log.d(TAG, "initialize() — surveys configured via BillDog.configure(); no-op")
139
+ promise.resolve(null)
140
+ }
141
+
142
+ /**
143
+ * BillDogSurvey.presentSurvey(options) → SurveyPresenter.present(surveyId,
144
+ * activity, handler, customerId, ...) — core SurveyPresenter.present
145
+ * (SurveyPresenter.kt:23), obtained via BillDog.getSurveyPresenter()
146
+ * (BillDog.kt:1969). Requires an Activity → reject "NO_ACTIVITY" when null.
147
+ *
148
+ * `options.context` and `options.isDismissible` have no native present()
149
+ * parameter and are ignored (documented). The promise resolves with the
150
+ * completion SurveyResponse on onComplete, null on onDismiss.
151
+ */
152
+ @ReactMethod
153
+ fun presentSurvey(options: ReadableMap, promise: Promise) {
154
+ val surveyId = if (options.hasKey("surveyIdentifier")) options.getString("surveyIdentifier") else null
155
+ if (surveyId.isNullOrBlank()) {
156
+ promise.reject("INVALID_ARGS", "Missing surveyIdentifier", null)
157
+ return
158
+ }
159
+ val customerId = if (options.hasKey("customerId")) options.getString("customerId") else null
160
+ val activity: Activity = currentActivity
161
+ ?: return promise.reject("NO_ACTIVITY", "No Activity available for presentSurvey", null)
162
+
163
+ val presenter = BillDog.getSurveyPresenter() // BillDog.kt:1969
164
+ if (presenter == null) {
165
+ Log.w(TAG, "presentSurvey($surveyId) — SDK not configured / no survey presenter; resolving null")
166
+ promise.resolve(null)
167
+ return
168
+ }
169
+
170
+ val replied = AtomicBoolean(false)
171
+ val handler = SurveyPresentationHandler(
172
+ onComplete = { id, result ->
173
+ if (replied.compareAndSet(false, true)) {
174
+ promise.resolve(serializeResponse(id, result))
175
+ }
176
+ },
177
+ onDismiss = {
178
+ if (replied.compareAndSet(false, true)) {
179
+ promise.resolve(null)
180
+ }
181
+ },
182
+ onError = { error ->
183
+ if (replied.compareAndSet(false, true)) {
184
+ promise.reject("BILLDOG_ERROR", error.message, error)
185
+ }
186
+ }
187
+ )
188
+
189
+ try {
190
+ // Resolves to the customVariables/interceptConfig-defaulted overload
191
+ // (the showUI overload requires a non-default lambda). — SurveyPresenter.kt:23
192
+ presenter.present(
193
+ surveyId = surveyId,
194
+ activity = activity,
195
+ handler = handler,
196
+ customerId = customerId
197
+ )
198
+ } catch (e: Throwable) {
199
+ if (replied.compareAndSet(false, true)) {
200
+ promise.reject("BILLDOG_ERROR", e.message, e)
201
+ }
202
+ }
203
+ }
204
+
205
+ /**
206
+ * BillDogSurvey.fetchSurvey(surveyIdentifier) → SurveyManager.fetchSurvey(
207
+ * surveyId) — core SurveyManager.fetchSurvey (SurveyManager.kt:32, suspend),
208
+ * obtained via BillDog.getSurveyManager() (BillDog.kt:2022). Resolves the
209
+ * serialized SurveyConfig or null when unconfigured.
210
+ */
211
+ @ReactMethod
212
+ fun fetchSurvey(surveyIdentifier: String, promise: Promise) {
213
+ run(promise) {
214
+ val mgr = BillDog.getSurveyManager() // BillDog.kt:2022
215
+ ?: return@run null
216
+ serializeSurveyConfig(mgr.fetchSurvey(surveyIdentifier)) // SurveyManager.kt:32
217
+ }
218
+ }
219
+
220
+ /**
221
+ * BillDogSurvey.submitResponse(response) → SurveyManager.submitSurvey(
222
+ * surveyId, answers, ...) — core SurveyManager.submitSurvey
223
+ * (SurveyManager.kt:56, suspend). Returns true on success. Resolves false
224
+ * when unconfigured (mirrors the JS default).
225
+ */
226
+ @ReactMethod
227
+ fun submitResponse(response: ReadableMap, promise: Promise) {
228
+ run(promise) {
229
+ val mgr = BillDog.getSurveyManager() // BillDog.kt:2022
230
+ ?: return@run false
231
+ val surveyId = if (response.hasKey("survey_id")) response.getString("survey_id") else null
232
+ if (surveyId.isNullOrBlank()) return@run false
233
+ val answers = parseAnswers(if (response.hasKey("answers")) response.getArray("answers") else null)
234
+ mgr.submitSurvey(surveyId, answers) // SurveyManager.kt:56
235
+ true
236
+ }
237
+ }
238
+
239
+ /**
240
+ * BillDogSurvey.canShowSurvey(surveyIdentifier) — no dedicated native
241
+ * eligibility API is exposed; the closest PUBLIC signal is
242
+ * SurveyPresenter.hasCompletedSurvey (SurveyPresenter.kt:91 → standalone :630).
243
+ * Returns `!hasCompletedSurvey(id)`. NOTE: full display-condition gating
244
+ * (device/feature-flag/URL/event) is private (`passesGating`) and only
245
+ * evaluated at present() time, so this is a completion-based proxy, not the
246
+ * full gating decision. Resolves false when unconfigured (JS default).
247
+ */
248
+ @ReactMethod
249
+ fun canShowSurvey(surveyIdentifier: String, promise: Promise) {
250
+ run(promise) {
251
+ val presenter = BillDog.getSurveyPresenter() ?: return@run false // BillDog.kt:1969
252
+ !presenter.hasCompletedSurvey(surveyIdentifier) // SurveyPresenter.kt:91
253
+ }
254
+ }
255
+
256
+ // ── NativeEventEmitter plumbing (onSurveyCompleted / onSurveyDismissed) ──
257
+
258
+ @ReactMethod
259
+ fun addListener(eventName: String) { /* NativeEventEmitter bookkeeping — no-op */ }
260
+
261
+ @ReactMethod
262
+ fun removeListeners(count: Int) { /* NativeEventEmitter bookkeeping — no-op */ }
263
+
264
+ private fun emit(event: String, params: WritableMap?) {
265
+ reactContext
266
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
267
+ .emit(event, params)
268
+ }
269
+
270
+ // ── Argument parsing ──────────────────────────────────────────────────────
271
+
272
+ /**
273
+ * ReadableArray of JS SurveyAnswer → List<SurveyAnswer>. `answer_json` is
274
+ * skipped — it is a Map<String, JsonElement> and kotlinx-serialization is
275
+ * not on this bridge's compile classpath (see class header).
276
+ */
277
+ private fun parseAnswers(arr: ReadableArray?): List<SurveyAnswer> {
278
+ if (arr == null) return emptyList()
279
+ val out = ArrayList<SurveyAnswer>(arr.size())
280
+ for (i in 0 until arr.size()) {
281
+ val m = arr.getMap(i) ?: continue
282
+ val questionId = if (m.hasKey("question_id")) m.getString("question_id") else null
283
+ if (questionId.isNullOrBlank()) continue
284
+ out.add(
285
+ SurveyAnswer(
286
+ question_id = questionId,
287
+ choice_id = if (m.hasKey("choice_id")) m.getString("choice_id") else null,
288
+ answer_text = if (m.hasKey("answer_text")) m.getString("answer_text") else null,
289
+ answer_number = if (m.hasKey("answer_number") && !m.isNull("answer_number"))
290
+ m.getDouble("answer_number") else null
291
+ )
292
+ )
293
+ }
294
+ return out
295
+ }
296
+
297
+ // ── Serializers (plain-field only; JsonElement maps omitted) ─────────────
298
+
299
+ /** SurveySubmitResult (SurveyModels.kt:207) → JS SurveyResponse. */
300
+ private fun serializeResponse(surveyId: String, result: SurveySubmitResult): WritableMap =
301
+ toWritableMap(mapOf(
302
+ "survey_id" to surveyId,
303
+ "respondent_id" to result.respondent_id,
304
+ "status" to result.status,
305
+ "answers" to (result.answers?.map { serializeAnswer(it) } ?: emptyList<Any?>())
306
+ ))
307
+
308
+ private fun serializeAnswer(a: SurveyAnswer): Map<String, Any?> = mapOf(
309
+ "question_id" to a.question_id,
310
+ "choice_id" to a.choice_id,
311
+ "answer_text" to a.answer_text,
312
+ "answer_number" to a.answer_number
313
+ )
314
+
315
+ /** SurveyConfig (SurveyModels.kt:22) → JS Survey. JsonElement `settings` maps omitted. */
316
+ private fun serializeSurveyConfig(c: SurveyConfig): WritableMap = toWritableMap(mapOf(
317
+ "id" to c.id,
318
+ "name" to c.name,
319
+ "description" to c.description,
320
+ "type" to c.type,
321
+ "pages" to c.pages.map { serializePage(it) },
322
+ "mobile_display" to c.mobile_display?.let { serializeMobileDisplay(it) }
323
+ ))
324
+
325
+ private fun serializePage(p: SurveyPageConfig): Map<String, Any?> = mapOf(
326
+ "id" to p.id,
327
+ "title" to p.title,
328
+ "description" to p.description,
329
+ "page_order" to p.page_order,
330
+ "questions" to p.questions.map { serializeQuestion(it) }
331
+ )
332
+
333
+ private fun serializeQuestion(q: SurveyQuestionConfig): Map<String, Any?> = mapOf(
334
+ "id" to q.id,
335
+ "type" to q.type,
336
+ "text" to q.text,
337
+ "description" to q.description,
338
+ "is_required" to q.is_required,
339
+ "question_order" to q.question_order,
340
+ "choices" to q.choices.map { serializeChoice(it) },
341
+ "logic_rules" to q.logic_rules.map { serializeLogicRule(it) }
342
+ )
343
+
344
+ private fun serializeChoice(ch: SurveyChoiceConfig): Map<String, Any?> = mapOf(
345
+ "id" to ch.id,
346
+ "label" to ch.label,
347
+ "value" to ch.value,
348
+ "is_other" to ch.is_other,
349
+ "choice_order" to ch.choice_order,
350
+ "image_url" to ch.image_url
351
+ )
352
+
353
+ private fun serializeLogicRule(r: SurveyLogicRule): Map<String, Any?> = mapOf(
354
+ "id" to r.id,
355
+ "condition_logic" to r.condition_logic,
356
+ "action_type" to r.action_type,
357
+ "target_id" to r.target_id,
358
+ "rule_order" to r.rule_order
359
+ )
360
+
361
+ private fun serializeMobileDisplay(m: SurveyMobileDisplayConfig): Map<String, Any?> = mapOf(
362
+ "displayStyle" to m.displayStyle,
363
+ "allowScrolling" to m.allowScrolling,
364
+ "interceptBackButton" to m.interceptBackButton,
365
+ "accessControl" to m.accessControl,
366
+ "safeAreaInsets" to m.safeAreaInsets,
367
+ "sheetConfig" to m.sheetConfig?.let {
368
+ mapOf("heightPercent" to it.heightPercent, "cornerRadius" to it.cornerRadius)
369
+ },
370
+ "popupConfig" to m.popupConfig?.let {
371
+ mapOf("widthPercent" to it.widthPercent, "heightPercent" to it.heightPercent, "cornerRadius" to it.cornerRadius)
372
+ },
373
+ "drawerConfig" to m.drawerConfig?.let {
374
+ mapOf("widthPercent" to it.widthPercent, "cornerRadius" to it.cornerRadius)
375
+ },
376
+ "launcherConfig" to m.launcherConfig?.let {
377
+ mapOf("label" to it.label, "position" to it.position)
378
+ }
379
+ )
380
+
381
+ // ── Map<String, Any?> → WritableMap converter (private per-module copy) ───
382
+
383
+ private fun toWritableMap(map: Map<String, Any?>): WritableMap {
384
+ val out = Arguments.createMap()
385
+ for ((key, value) in map) {
386
+ when (value) {
387
+ null -> out.putNull(key)
388
+ is Boolean -> out.putBoolean(key, value)
389
+ is Int -> out.putInt(key, value)
390
+ is Long -> out.putDouble(key, value.toDouble())
391
+ is Float -> out.putDouble(key, value.toDouble())
392
+ is Double -> out.putDouble(key, value)
393
+ is String -> out.putString(key, value)
394
+ is WritableMap -> out.putMap(key, value)
395
+ is WritableArray -> out.putArray(key, value)
396
+ is Map<*, *> -> out.putMap(key, toWritableMap(coerceStringKeys(value)))
397
+ is List<*> -> out.putArray(key, toWritableArray(value))
398
+ else -> out.putString(key, value.toString())
399
+ }
400
+ }
401
+ return out
402
+ }
403
+
404
+ private fun toWritableArray(list: List<*>): WritableArray {
405
+ val out = Arguments.createArray()
406
+ for (value in list) {
407
+ when (value) {
408
+ null -> out.pushNull()
409
+ is Boolean -> out.pushBoolean(value)
410
+ is Int -> out.pushInt(value)
411
+ is Long -> out.pushDouble(value.toDouble())
412
+ is Float -> out.pushDouble(value.toDouble())
413
+ is Double -> out.pushDouble(value)
414
+ is String -> out.pushString(value)
415
+ is WritableMap -> out.pushMap(value)
416
+ is WritableArray -> out.pushArray(value)
417
+ is Map<*, *> -> out.pushMap(toWritableMap(coerceStringKeys(value)))
418
+ is List<*> -> out.pushArray(toWritableArray(value))
419
+ else -> out.pushString(value.toString())
420
+ }
421
+ }
422
+ return out
423
+ }
424
+
425
+ private fun coerceStringKeys(map: Map<*, *>): Map<String, Any?> =
426
+ map.entries.associate { (k, v) -> k.toString() to v }
427
+ }