@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.
- package/BillDogReactNative.podspec +30 -0
- package/LICENSE +21 -0
- package/README.md +330 -0
- package/android/build.gradle +99 -0
- package/android/src/main/AndroidManifest.xml +1 -0
- package/android/src/main/kotlin/io/billdog/reactnative/BillDogABTestModule.kt +317 -0
- package/android/src/main/kotlin/io/billdog/reactnative/BillDogAnalyticsModule.kt +389 -0
- package/android/src/main/kotlin/io/billdog/reactnative/BillDogModule.kt +817 -0
- package/android/src/main/kotlin/io/billdog/reactnative/BillDogPaywallViewManager.kt +383 -0
- package/android/src/main/kotlin/io/billdog/reactnative/BillDogSurveyModule.kt +427 -0
- package/android/src/main/kotlin/io/billdog/reactnative/BillDogVirtualCurrencyModule.kt +407 -0
- package/android/src/main/kotlin/io/billdog/virtualcurrency/BillDogVirtualCurrencyPackage.kt +44 -0
- package/dist/AdvancedPaywallCache.d.ts +70 -0
- package/dist/AdvancedPaywallCache.js +344 -0
- package/dist/BillDog.d.ts +255 -0
- package/dist/BillDog.js +918 -0
- package/dist/BillDogConfiguration.d.ts +145 -0
- package/dist/BillDogConfiguration.js +229 -0
- package/dist/ComponentRenderer.d.ts +17 -0
- package/dist/ComponentRenderer.js +886 -0
- package/dist/LayoutEngine.d.ts +101 -0
- package/dist/LayoutEngine.js +394 -0
- package/dist/LocalizationResolver.d.ts +99 -0
- package/dist/LocalizationResolver.js +266 -0
- package/dist/NativePaywallView.d.ts +36 -0
- package/dist/NativePaywallView.js +59 -0
- package/dist/PaywallCache.d.ts +74 -0
- package/dist/PaywallCache.js +293 -0
- package/dist/PaywallStateManager.d.ts +62 -0
- package/dist/PaywallStateManager.js +147 -0
- package/dist/PaywallView.d.ts +42 -0
- package/dist/PaywallView.js +275 -0
- package/dist/ProductVariableProvider.d.ts +60 -0
- package/dist/ProductVariableProvider.js +239 -0
- package/dist/VariableResolver.d.ts +120 -0
- package/dist/VariableResolver.js +379 -0
- package/dist/WebViewPaywall.d.ts +75 -0
- package/dist/WebViewPaywall.js +360 -0
- package/dist/animations/presets.d.ts +49 -0
- package/dist/animations/presets.js +367 -0
- package/dist/components/AccoladeCpsComponent.d.ts +13 -0
- package/dist/components/AccoladeCpsComponent.js +248 -0
- package/dist/components/AccordionComponent.d.ts +10 -0
- package/dist/components/AccordionComponent.js +187 -0
- package/dist/components/AnimatedWrapper.d.ts +35 -0
- package/dist/components/AnimatedWrapper.js +277 -0
- package/dist/components/CarouselComponent.d.ts +23 -0
- package/dist/components/CarouselComponent.js +484 -0
- package/dist/components/ChartCurveComponent.d.ts +13 -0
- package/dist/components/ChartCurveComponent.js +333 -0
- package/dist/components/CheckboxComponent.d.ts +9 -0
- package/dist/components/CheckboxComponent.js +172 -0
- package/dist/components/ConfettiComponent.d.ts +9 -0
- package/dist/components/ConfettiComponent.js +172 -0
- package/dist/components/CountdownComponent.d.ts +16 -0
- package/dist/components/CountdownComponent.js +414 -0
- package/dist/components/DelayedXComponent.d.ts +12 -0
- package/dist/components/DelayedXComponent.js +240 -0
- package/dist/components/DrawerModalComponent.d.ts +20 -0
- package/dist/components/DrawerModalComponent.js +286 -0
- package/dist/components/GradientView.d.ts +38 -0
- package/dist/components/GradientView.js +126 -0
- package/dist/components/HapticFeedbackComponent.d.ts +16 -0
- package/dist/components/HapticFeedbackComponent.js +64 -0
- package/dist/components/HorizontalProductsComponent.d.ts +17 -0
- package/dist/components/HorizontalProductsComponent.js +284 -0
- package/dist/components/MultiChoiceGridComponent.d.ts +13 -0
- package/dist/components/MultiChoiceGridComponent.js +234 -0
- package/dist/components/NPSScaleComponent.d.ts +16 -0
- package/dist/components/NPSScaleComponent.js +260 -0
- package/dist/components/NavigationComponent.d.ts +26 -0
- package/dist/components/NavigationComponent.js +302 -0
- package/dist/components/OAuthButtonComponent.d.ts +20 -0
- package/dist/components/OAuthButtonComponent.js +237 -0
- package/dist/components/ProgressLoaderComponent.d.ts +13 -0
- package/dist/components/ProgressLoaderComponent.js +308 -0
- package/dist/components/ProgressStepperComponent.d.ts +18 -0
- package/dist/components/ProgressStepperComponent.js +228 -0
- package/dist/components/SegmentedPickerComponent.d.ts +10 -0
- package/dist/components/SegmentedPickerComponent.js +221 -0
- package/dist/components/ShareButtonsComponent.d.ts +21 -0
- package/dist/components/ShareButtonsComponent.js +265 -0
- package/dist/components/ShareCodeComponent.d.ts +16 -0
- package/dist/components/ShareCodeComponent.js +274 -0
- package/dist/components/SingleChoiceGridComponent.d.ts +13 -0
- package/dist/components/SingleChoiceGridComponent.js +210 -0
- package/dist/components/SliderComponent.d.ts +9 -0
- package/dist/components/SliderComponent.js +263 -0
- package/dist/components/StarRatingInputComponent.d.ts +20 -0
- package/dist/components/StarRatingInputComponent.js +198 -0
- package/dist/components/StickerCompositeComponent.d.ts +13 -0
- package/dist/components/StickerCompositeComponent.js +136 -0
- package/dist/components/TabsComponent.d.ts +19 -0
- package/dist/components/TabsComponent.js +431 -0
- package/dist/components/TextInputComponent.d.ts +18 -0
- package/dist/components/TextInputComponent.js +227 -0
- package/dist/components/TimelineComponent.d.ts +19 -0
- package/dist/components/TimelineComponent.js +104 -0
- package/dist/components/ToggleComponent.d.ts +14 -0
- package/dist/components/ToggleComponent.js +132 -0
- package/dist/components/VerticalProductsComponent.d.ts +17 -0
- package/dist/components/VerticalProductsComponent.js +311 -0
- package/dist/dynamicValues.d.ts +36 -0
- package/dist/dynamicValues.js +142 -0
- package/dist/filters/dateFilters.d.ts +50 -0
- package/dist/filters/dateFilters.js +390 -0
- package/dist/filters/index.d.ts +18 -0
- package/dist/filters/index.js +253 -0
- package/dist/hooks/useOfferings.d.ts +76 -0
- package/dist/hooks/useOfferings.js +99 -0
- package/dist/hooks/usePaywall.d.ts +27 -0
- package/dist/hooks/usePaywall.js +114 -0
- package/dist/hooks/usePlacement.d.ts +34 -0
- package/dist/hooks/usePlacement.js +89 -0
- package/dist/hooks/useSubscription.d.ts +40 -0
- package/dist/hooks/useSubscription.js +97 -0
- package/dist/index.d.ts +98 -0
- package/dist/index.js +198 -0
- package/dist/models/BillDogError.d.ts +40 -0
- package/dist/models/BillDogError.js +11 -0
- package/dist/models/CacheFetchPolicy.d.ts +8 -0
- package/dist/models/CacheFetchPolicy.js +4 -0
- package/dist/models/CustomProduct.d.ts +32 -0
- package/dist/models/CustomProduct.js +15 -0
- package/dist/models/CustomerInfo.d.ts +17 -0
- package/dist/models/CustomerInfo.js +11 -0
- package/dist/models/Delegate.d.ts +20 -0
- package/dist/models/Delegate.js +11 -0
- package/dist/models/EntitlementInfo.d.ts +19 -0
- package/dist/models/EntitlementInfo.js +2 -0
- package/dist/models/Placement.d.ts +54 -0
- package/dist/models/Placement.js +15 -0
- package/dist/models/PurchaseParams.d.ts +39 -0
- package/dist/models/PurchaseParams.js +60 -0
- package/dist/models/PurchaseResult.d.ts +30 -0
- package/dist/models/PurchaseResult.js +15 -0
- package/dist/models/RestoreResult.d.ts +30 -0
- package/dist/models/RestoreResult.js +22 -0
- package/dist/models/RestoredItem.d.ts +26 -0
- package/dist/models/RestoredItem.js +13 -0
- package/dist/modules/ABTest.d.ts +65 -0
- package/dist/modules/ABTest.js +113 -0
- package/dist/modules/Analytics.d.ts +91 -0
- package/dist/modules/Analytics.js +182 -0
- package/dist/modules/Survey.d.ts +65 -0
- package/dist/modules/Survey.js +82 -0
- package/dist/modules/VirtualCurrency.d.ts +63 -0
- package/dist/modules/VirtualCurrency.js +147 -0
- package/dist/murmur.d.ts +23 -0
- package/dist/murmur.js +104 -0
- package/dist/notifications/LiveActivitiesManager.d.ts +47 -0
- package/dist/notifications/LiveActivitiesManager.js +106 -0
- package/dist/notifications/NotificationScheduler.d.ts +55 -0
- package/dist/notifications/NotificationScheduler.js +199 -0
- package/dist/notifications/PurchaseNotificationHandler.d.ts +24 -0
- package/dist/notifications/PurchaseNotificationHandler.js +55 -0
- package/dist/notifications/useDeviceToken.d.ts +36 -0
- package/dist/notifications/useDeviceToken.js +97 -0
- package/dist/notifications/useLiveActivity.d.ts +39 -0
- package/dist/notifications/useLiveActivity.js +104 -0
- package/dist/review/ReviewAnalytics.d.ts +34 -0
- package/dist/review/ReviewAnalytics.js +73 -0
- package/dist/review/ReviewManager.d.ts +83 -0
- package/dist/review/ReviewManager.js +339 -0
- package/dist/review/ReviewTimingManager.d.ts +82 -0
- package/dist/review/ReviewTimingManager.js +224 -0
- package/dist/survey-core/types.d.ts +215 -0
- package/dist/survey-core/types.js +8 -0
- package/dist/types.d.ts +438 -0
- package/dist/types.js +158 -0
- package/dist/utils/ApiClient.d.ts +65 -0
- package/dist/utils/ApiClient.js +132 -0
- package/dist/utils/CSSConverter.d.ts +49 -0
- package/dist/utils/CSSConverter.js +470 -0
- package/dist/utils/animations.d.ts +41 -0
- package/dist/utils/animations.js +194 -0
- package/dist/utils/calendarIntegration.d.ts +36 -0
- package/dist/utils/calendarIntegration.js +89 -0
- package/dist/utils/configurationResolver.d.ts +23 -0
- package/dist/utils/configurationResolver.js +78 -0
- package/dist/utils/deviceDetection.d.ts +38 -0
- package/dist/utils/deviceDetection.js +59 -0
- package/dist/utils/hapticFeedback.d.ts +17 -0
- package/dist/utils/hapticFeedback.js +53 -0
- package/dist/utils/iconMapper.d.ts +26 -0
- package/dist/utils/iconMapper.js +113 -0
- package/dist/utils/notificationPermissions.d.ts +13 -0
- package/dist/utils/notificationPermissions.js +51 -0
- package/dist/utils/priceFormatting.d.ts +19 -0
- package/dist/utils/priceFormatting.js +99 -0
- package/dist/utils/shareSheet.d.ts +17 -0
- package/dist/utils/shareSheet.js +42 -0
- package/dist/utils/subscriptionUpgrade.d.ts +84 -0
- package/dist/utils/subscriptionUpgrade.js +100 -0
- package/dist/valueUtils.d.ts +48 -0
- package/dist/valueUtils.js +129 -0
- package/dist/xFlowTags.d.ts +18 -0
- package/dist/xFlowTags.js +385 -0
- package/ios/BillDogABTest.m +50 -0
- package/ios/BillDogABTest.swift +188 -0
- package/ios/BillDogAnalytics.m +105 -0
- package/ios/BillDogAnalytics.swift +324 -0
- package/ios/BillDogBridge.m +222 -0
- package/ios/BillDogBridge.swift +715 -0
- package/ios/BillDogLiveActivities.m +41 -0
- package/ios/BillDogLiveActivities.swift +104 -0
- package/ios/BillDogPaywallViewManager.m +39 -0
- package/ios/BillDogPaywallViewManager.swift +361 -0
- package/ios/BillDogSurvey.m +34 -0
- package/ios/BillDogSurvey.swift +257 -0
- package/ios/BillDogVirtualCurrencyBridge.m +63 -0
- package/ios/BillDogVirtualCurrencyBridge.swift +511 -0
- package/junit.xml +25 -0
- package/package.json +61 -0
- package/react-native.config.js +13 -0
- package/src/AdvancedPaywallCache.ts +433 -0
- package/src/BillDog.ts +983 -0
- package/src/BillDogConfiguration.ts +318 -0
- package/src/ComponentRenderer.tsx +1325 -0
- package/src/LayoutEngine.ts +459 -0
- package/src/LocalizationResolver.ts +311 -0
- package/src/NativePaywallView.tsx +132 -0
- package/src/PaywallCache.ts +358 -0
- package/src/PaywallStateManager.ts +154 -0
- package/src/PaywallView.tsx +328 -0
- package/src/ProductVariableProvider.ts +282 -0
- package/src/VariableResolver.ts +516 -0
- package/src/WebViewPaywall.tsx +454 -0
- package/src/animations/presets.ts +421 -0
- package/src/components/AccoladeCpsComponent.tsx +259 -0
- package/src/components/AccordionComponent.tsx +213 -0
- package/src/components/AnimatedWrapper.tsx +316 -0
- package/src/components/CarouselComponent.tsx +615 -0
- package/src/components/ChartCurveComponent.tsx +452 -0
- package/src/components/CheckboxComponent.tsx +185 -0
- package/src/components/ConfettiComponent.tsx +178 -0
- package/src/components/CountdownComponent.tsx +454 -0
- package/src/components/DelayedXComponent.tsx +266 -0
- package/src/components/DrawerModalComponent.tsx +324 -0
- package/src/components/GradientView.tsx +129 -0
- package/src/components/HapticFeedbackComponent.tsx +39 -0
- package/src/components/HorizontalProductsComponent.tsx +329 -0
- package/src/components/MultiChoiceGridComponent.tsx +265 -0
- package/src/components/NPSScaleComponent.tsx +294 -0
- package/src/components/NavigationComponent.tsx +329 -0
- package/src/components/OAuthButtonComponent.tsx +266 -0
- package/src/components/ProgressLoaderComponent.tsx +366 -0
- package/src/components/ProgressStepperComponent.tsx +250 -0
- package/src/components/SegmentedPickerComponent.tsx +245 -0
- package/src/components/ShareButtonsComponent.tsx +299 -0
- package/src/components/ShareCodeComponent.tsx +303 -0
- package/src/components/SingleChoiceGridComponent.tsx +229 -0
- package/src/components/SliderComponent.tsx +280 -0
- package/src/components/StarRatingInputComponent.tsx +223 -0
- package/src/components/StickerCompositeComponent.tsx +168 -0
- package/src/components/TabsComponent.tsx +496 -0
- package/src/components/TextInputComponent.tsx +258 -0
- package/src/components/TimelineComponent.tsx +129 -0
- package/src/components/ToggleComponent.tsx +142 -0
- package/src/components/VerticalProductsComponent.tsx +357 -0
- package/src/dynamicValues.ts +180 -0
- package/src/filters/dateFilters.ts +411 -0
- package/src/filters/index.ts +281 -0
- package/src/hooks/useOfferings.ts +192 -0
- package/src/hooks/usePaywall.ts +154 -0
- package/src/hooks/usePlacement.ts +143 -0
- package/src/hooks/useSubscription.ts +154 -0
- package/src/index.ts +245 -0
- package/src/models/BillDogError.ts +24 -0
- package/src/models/CacheFetchPolicy.ts +13 -0
- package/src/models/CustomProduct.ts +33 -0
- package/src/models/CustomerInfo.ts +26 -0
- package/src/models/Delegate.ts +22 -0
- package/src/models/EntitlementInfo.ts +27 -0
- package/src/models/Placement.ts +50 -0
- package/src/models/PurchaseParams.ts +81 -0
- package/src/models/PurchaseResult.ts +32 -0
- package/src/models/RestoreResult.ts +27 -0
- package/src/models/RestoredItem.ts +25 -0
- package/src/modules/ABTest.ts +131 -0
- package/src/modules/Analytics.ts +227 -0
- package/src/modules/Survey.ts +126 -0
- package/src/modules/VirtualCurrency.ts +223 -0
- package/src/murmur.ts +102 -0
- package/src/notifications/LiveActivitiesManager.ts +140 -0
- package/src/notifications/NotificationScheduler.ts +292 -0
- package/src/notifications/PurchaseNotificationHandler.ts +67 -0
- package/src/notifications/useDeviceToken.ts +116 -0
- package/src/notifications/useLiveActivity.ts +125 -0
- package/src/review/ReviewAnalytics.ts +89 -0
- package/src/review/ReviewManager.ts +355 -0
- package/src/review/ReviewTimingManager.ts +265 -0
- package/src/survey-core/types.ts +244 -0
- package/src/types/ambient.d.ts +9 -0
- package/src/types.ts +680 -0
- package/src/utils/ApiClient.ts +163 -0
- package/src/utils/CSSConverter.ts +552 -0
- package/src/utils/animations.ts +232 -0
- package/src/utils/calendarIntegration.ts +113 -0
- package/src/utils/configurationResolver.ts +106 -0
- package/src/utils/deviceDetection.ts +83 -0
- package/src/utils/hapticFeedback.ts +55 -0
- package/src/utils/iconMapper.ts +102 -0
- package/src/utils/notificationPermissions.ts +48 -0
- package/src/utils/priceFormatting.ts +119 -0
- package/src/utils/shareSheet.ts +55 -0
- package/src/utils/subscriptionUpgrade.ts +183 -0
- package/src/valueUtils.ts +108 -0
- 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
|
+
}
|