@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,265 @@
1
+ import AsyncStorage from '@react-native-async-storage/async-storage';
2
+
3
+ /**
4
+ * Configuration for review timing logic
5
+ */
6
+ export interface ReviewTimingConfig {
7
+ /** Minimum number of days since app install before requesting review */
8
+ minDaysSinceInstall?: number;
9
+ /** Minimum number of app sessions before requesting review */
10
+ minSessionCount?: number;
11
+ /** Minimum number of significant events (e.g., purchases, completed actions) */
12
+ minSignificantEvents?: number;
13
+ /** Days to wait after a user dismisses a review prompt */
14
+ cooldownAfterDismissal?: number;
15
+ /** Maximum number of review requests to show to a user */
16
+ maxRequestsPerUser?: number;
17
+ /** Enable automatic timing checks */
18
+ enableAutomaticTiming?: boolean;
19
+ }
20
+
21
+ /**
22
+ * Timing data stored locally
23
+ */
24
+ interface ReviewTimingData {
25
+ installDate: string;
26
+ sessionCount: number;
27
+ significantEventCount: number;
28
+ lastRequestDate?: string;
29
+ lastDismissalDate?: string;
30
+ totalRequestCount: number;
31
+ lastReviewCompletedDate?: string;
32
+ }
33
+
34
+ const STORAGE_KEY = '@billdog_review_timing';
35
+
36
+ /**
37
+ * Default timing configuration
38
+ */
39
+ const DEFAULT_CONFIG: Required<ReviewTimingConfig> = {
40
+ minDaysSinceInstall: 7,
41
+ minSessionCount: 5,
42
+ minSignificantEvents: 3,
43
+ cooldownAfterDismissal: 30,
44
+ maxRequestsPerUser: 3,
45
+ enableAutomaticTiming: true,
46
+ };
47
+
48
+ /**
49
+ * Manager for smart review timing logic
50
+ * Determines optimal moments to request reviews based on user behavior
51
+ */
52
+ export class ReviewTimingManager {
53
+ private config: Required<ReviewTimingConfig>;
54
+ private timingData: ReviewTimingData | null = null;
55
+
56
+ constructor(config: ReviewTimingConfig = {}) {
57
+ this.config = { ...DEFAULT_CONFIG, ...config };
58
+ }
59
+
60
+ /**
61
+ * Initialize timing data (call on app launch)
62
+ */
63
+ async initialize(): Promise<void> {
64
+ try {
65
+ const stored = await AsyncStorage.getItem(STORAGE_KEY);
66
+ if (stored) {
67
+ this.timingData = JSON.parse(stored);
68
+ } else {
69
+ // First time - create initial data
70
+ this.timingData = {
71
+ installDate: new Date().toISOString(),
72
+ sessionCount: 0,
73
+ significantEventCount: 0,
74
+ totalRequestCount: 0,
75
+ };
76
+ await this.saveTimingData();
77
+ }
78
+ } catch (error) {
79
+ console.error('Error initializing review timing:', error);
80
+ // Fallback to in-memory only
81
+ this.timingData = {
82
+ installDate: new Date().toISOString(),
83
+ sessionCount: 0,
84
+ significantEventCount: 0,
85
+ totalRequestCount: 0,
86
+ };
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Record a new app session
92
+ */
93
+ async recordSession(): Promise<void> {
94
+ if (!this.timingData) await this.initialize();
95
+ if (this.timingData) {
96
+ this.timingData.sessionCount++;
97
+ await this.saveTimingData();
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Record a significant event (e.g., purchase, completed action)
103
+ */
104
+ async recordSignificantEvent(): Promise<void> {
105
+ if (!this.timingData) await this.initialize();
106
+ if (this.timingData) {
107
+ this.timingData.significantEventCount++;
108
+ await this.saveTimingData();
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Record that a review was requested
114
+ */
115
+ async recordReviewRequested(): Promise<void> {
116
+ if (!this.timingData) await this.initialize();
117
+ if (this.timingData) {
118
+ this.timingData.lastRequestDate = new Date().toISOString();
119
+ this.timingData.totalRequestCount++;
120
+ await this.saveTimingData();
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Record that a review was dismissed by the user
126
+ */
127
+ async recordReviewDismissed(): Promise<void> {
128
+ if (!this.timingData) await this.initialize();
129
+ if (this.timingData) {
130
+ this.timingData.lastDismissalDate = new Date().toISOString();
131
+ await this.saveTimingData();
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Record that a review was completed by the user
137
+ */
138
+ async recordReviewCompleted(): Promise<void> {
139
+ if (!this.timingData) await this.initialize();
140
+ if (this.timingData) {
141
+ this.timingData.lastReviewCompletedDate = new Date().toISOString();
142
+ await this.saveTimingData();
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Check if it's a good time to request a review
148
+ * Returns true if all timing conditions are met
149
+ */
150
+ async shouldRequestReview(): Promise<{
151
+ shouldRequest: boolean;
152
+ reason?: string;
153
+ timingData?: ReviewTimingData;
154
+ }> {
155
+ if (!this.config.enableAutomaticTiming) {
156
+ return { shouldRequest: true, reason: 'Automatic timing disabled' };
157
+ }
158
+
159
+ if (!this.timingData) await this.initialize();
160
+ if (!this.timingData) {
161
+ return { shouldRequest: false, reason: 'Timing data not available' };
162
+ }
163
+
164
+ // Check if user has already completed a review
165
+ if (this.timingData.lastReviewCompletedDate) {
166
+ return {
167
+ shouldRequest: false,
168
+ reason: 'User has already completed a review',
169
+ timingData: this.timingData
170
+ };
171
+ }
172
+
173
+ // Check max requests limit
174
+ if (this.timingData.totalRequestCount >= this.config.maxRequestsPerUser) {
175
+ return {
176
+ shouldRequest: false,
177
+ reason: `Maximum review requests (${this.config.maxRequestsPerUser}) reached`,
178
+ timingData: this.timingData
179
+ };
180
+ }
181
+
182
+ // Check days since install
183
+ const daysSinceInstall = this.getDaysSince(new Date(this.timingData.installDate));
184
+ if (daysSinceInstall < this.config.minDaysSinceInstall) {
185
+ return {
186
+ shouldRequest: false,
187
+ reason: `Only ${daysSinceInstall} days since install (need ${this.config.minDaysSinceInstall})`,
188
+ timingData: this.timingData
189
+ };
190
+ }
191
+
192
+ // Check session count
193
+ if (this.timingData.sessionCount < this.config.minSessionCount) {
194
+ return {
195
+ shouldRequest: false,
196
+ reason: `Only ${this.timingData.sessionCount} sessions (need ${this.config.minSessionCount})`,
197
+ timingData: this.timingData
198
+ };
199
+ }
200
+
201
+ // Check significant events
202
+ if (this.timingData.significantEventCount < this.config.minSignificantEvents) {
203
+ return {
204
+ shouldRequest: false,
205
+ reason: `Only ${this.timingData.significantEventCount} significant events (need ${this.config.minSignificantEvents})`,
206
+ timingData: this.timingData
207
+ };
208
+ }
209
+
210
+ // Check cooldown after dismissal
211
+ if (this.timingData.lastDismissalDate) {
212
+ const daysSinceDismissal = this.getDaysSince(new Date(this.timingData.lastDismissalDate));
213
+ if (daysSinceDismissal < this.config.cooldownAfterDismissal) {
214
+ return {
215
+ shouldRequest: false,
216
+ reason: `Only ${daysSinceDismissal} days since last dismissal (need ${this.config.cooldownAfterDismissal})`,
217
+ timingData: this.timingData
218
+ };
219
+ }
220
+ }
221
+
222
+ // All conditions met!
223
+ return {
224
+ shouldRequest: true,
225
+ reason: 'All timing conditions met',
226
+ timingData: this.timingData
227
+ };
228
+ }
229
+
230
+ /**
231
+ * Get current timing data
232
+ */
233
+ async getTimingData(): Promise<ReviewTimingData | null> {
234
+ if (!this.timingData) await this.initialize();
235
+ return this.timingData;
236
+ }
237
+
238
+ /**
239
+ * Reset timing data (useful for testing)
240
+ */
241
+ async resetTimingData(): Promise<void> {
242
+ this.timingData = {
243
+ installDate: new Date().toISOString(),
244
+ sessionCount: 0,
245
+ significantEventCount: 0,
246
+ totalRequestCount: 0,
247
+ };
248
+ await this.saveTimingData();
249
+ }
250
+
251
+ private async saveTimingData(): Promise<void> {
252
+ if (!this.timingData) return;
253
+ try {
254
+ await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(this.timingData));
255
+ } catch (error) {
256
+ console.error('Error saving review timing data:', error);
257
+ }
258
+ }
259
+
260
+ private getDaysSince(date: Date): number {
261
+ const now = new Date();
262
+ const diffMs = now.getTime() - date.getTime();
263
+ return Math.floor(diffMs / (1000 * 60 * 60 * 24));
264
+ }
265
+ }
@@ -0,0 +1,244 @@
1
+ /**
2
+ * BDSurvey Types — Standalone survey SDK types
3
+ *
4
+ * These types are the canonical definitions for the BDSurvey system.
5
+ * The BillDog SDK re-exports these for backward compatibility.
6
+ */
7
+
8
+ // ============= Survey Configuration (from bdsurvey-fetch) =============
9
+
10
+ export type SurveyQuestionType =
11
+ | 'multiple_choice'
12
+ | 'multi_select'
13
+ | 'text'
14
+ | 'rating'
15
+ | 'nps'
16
+ | 'boolean'
17
+ | 'dropdown'
18
+ | 'matrix'
19
+ | 'ranking'
20
+ | 'slider'
21
+ // PostHog-parity question types (added):
22
+ | 'emoji' // emoji-scale rating; config: { scale?: number; emojis?: string[]; labels?: { low?: string; high?: string } }
23
+ | 'thumbs' // thumbs up/down; answered via answer_number (1 = up, 0 = down) or boolean
24
+ | 'link'; // call-to-action question; config: { url: string; buttonText?: string }
25
+
26
+ export interface SurveyChoice {
27
+ id: string;
28
+ label: string;
29
+ value: string | null;
30
+ is_other: boolean;
31
+ choice_order: number;
32
+ image_url?: string | null;
33
+ metadata: Record<string, unknown>;
34
+ }
35
+
36
+ export type SurveyLogicOperator =
37
+ | 'equals'
38
+ | 'not_equals'
39
+ | 'contains'
40
+ | 'is_any_of'
41
+ | 'greater_than'
42
+ | 'less_than';
43
+
44
+ export interface SurveyLogicCondition {
45
+ operator: SurveyLogicOperator;
46
+ value?: string | number;
47
+ choice_id?: string;
48
+ }
49
+
50
+ export interface SurveyLogicRule {
51
+ id: string;
52
+ /**
53
+ * Single condition (legacy / simple rules). Retained for backward compatibility.
54
+ * When `conditions` is present and non-empty it takes precedence over `condition`.
55
+ */
56
+ condition?: SurveyLogicCondition;
57
+ /**
58
+ * Compound conditions (PostHog-parity, added). Combined per `condition_logic`.
59
+ * Evaluators prefer this over `condition` when present.
60
+ */
61
+ conditions?: SurveyLogicCondition[];
62
+ /** How to combine `conditions`. Defaults to 'and'. */
63
+ condition_logic?: 'and' | 'or';
64
+ action_type: 'skip_to_question' | 'skip_to_page' | 'end_survey';
65
+ target_id?: string;
66
+ rule_order: number;
67
+ }
68
+
69
+ export interface SurveyQuestion {
70
+ id: string;
71
+ type: SurveyQuestionType;
72
+ text: string;
73
+ description: string | null;
74
+ is_required: boolean;
75
+ question_order: number;
76
+ config: Record<string, unknown>;
77
+ settings: Record<string, unknown>;
78
+ choices: SurveyChoice[];
79
+ logic_rules?: SurveyLogicRule[];
80
+ }
81
+
82
+ export interface SurveyPage {
83
+ id: string;
84
+ title: string | null;
85
+ description: string | null;
86
+ page_order: number;
87
+ settings: Record<string, unknown>;
88
+ questions: SurveyQuestion[];
89
+ }
90
+
91
+ export interface SurveyMobileDisplayConfig {
92
+ displayStyle?: 'full_screen' | 'sheet' | 'push_navigation' | 'no_transition' | 'side_drawer' | 'overlay_popup';
93
+ allowScrolling?: boolean;
94
+ interceptBackButton?: boolean;
95
+ accessControl?: 'restricted' | 'unrestricted';
96
+ safeAreaInsets?: boolean;
97
+ sheetConfig?: { heightPercent?: number; cornerRadius?: number };
98
+ popupConfig?: { widthPercent?: number; heightPercent?: number; cornerRadius?: number };
99
+ drawerConfig?: { widthPercent?: number; cornerRadius?: number };
100
+ }
101
+
102
+ export interface SurveyConfiguration {
103
+ id: string;
104
+ name: string;
105
+ description: string | null;
106
+ type: string;
107
+ settings: SurveySettings;
108
+ pages: SurveyPage[];
109
+ mobile_display?: SurveyMobileDisplayConfig;
110
+ version?: number;
111
+ variant_group?: string | null;
112
+ variant_name?: string | null;
113
+ should_show?: boolean;
114
+ presentation_percentage?: number;
115
+ /** Display/targeting conditions (PostHog-parity, added). */
116
+ display_conditions?: SurveyDisplayConditions;
117
+ }
118
+
119
+ /**
120
+ * Display/targeting conditions evaluated client-side before a survey is shown
121
+ * (PostHog-parity, added). All present conditions must pass (logical AND).
122
+ */
123
+ export interface SurveyDisplayConditions {
124
+ /** Restrict to device categories. Empty/undefined = all devices. */
125
+ device_types?: SurveyDeviceType[];
126
+ /** Only show when a feature flag is enabled (optionally a specific variant). */
127
+ feature_flag?: { key: string; variant?: string | null };
128
+ /** Web/screen targeting: match the current URL/route. */
129
+ url_match?: { operator: 'exact' | 'contains' | 'regex' | 'not_contains'; value: string };
130
+ /** Only show after an event fires during the session (optional property filters). */
131
+ event_trigger?: { event_name: string; property_filters?: Record<string, unknown> };
132
+ /** Delay before showing, in milliseconds. */
133
+ delay_ms?: number;
134
+ [key: string]: unknown;
135
+ }
136
+
137
+ export type SurveyDeviceType = 'phone' | 'tablet' | 'desktop' | 'tv' | 'watch';
138
+
139
+ /**
140
+ * Recurrence/repeat policy (PostHog-parity, added).
141
+ * `show_once` is the legacy single-show flag; `recurring` supersedes it when enabled.
142
+ */
143
+ export interface SurveyRecurrence {
144
+ enabled: boolean;
145
+ /** Maximum number of times the survey may be shown to a user. */
146
+ max_repeats?: number;
147
+ /** Minimum days between repeated showings. */
148
+ interval_days?: number;
149
+ /** Re-show every time the trigger event fires (ignores interval_days when true). */
150
+ on_every_trigger?: boolean;
151
+ }
152
+
153
+ export interface SurveySettings {
154
+ show_once?: boolean;
155
+ shuffle_options?: boolean;
156
+ /** Randomize question order (PostHog-parity, added). */
157
+ shuffle_questions?: boolean;
158
+ /** Recurring/repeat policy (PostHog-parity, added). */
159
+ recurring?: SurveyRecurrence;
160
+ /** Global wait period: don't show if the user saw ANY survey in the last N days (added). */
161
+ wait_period_days?: number;
162
+ presentation_percentage?: number;
163
+ locale?: string | null;
164
+ theme?: SurveyTheme;
165
+ thankYouMessage?: { title: string; body?: string | null } | null;
166
+ welcomeScreen?: {
167
+ title: string;
168
+ body?: string | null;
169
+ buttonText?: string | null;
170
+ } | null;
171
+ [key: string]: unknown;
172
+ }
173
+
174
+ export interface SurveyTheme {
175
+ primaryColor?: string;
176
+ backgroundColor?: string;
177
+ textColor?: string;
178
+ borderRadius?: number;
179
+ fontFamily?: string;
180
+ [key: string]: unknown;
181
+ }
182
+
183
+ // ============= Survey Answers (for bdsurvey-submit) =============
184
+
185
+ export interface SurveyAnswer {
186
+ question_id: string;
187
+ choice_id?: string | null;
188
+ answer_text?: string | null;
189
+ answer_number?: number | null;
190
+ answer_json?: Record<string, unknown> | null;
191
+ }
192
+
193
+ export interface SurveyContext {
194
+ customer_id?: string;
195
+ anonymous_id?: string;
196
+ platform?: string;
197
+ session_id?: string;
198
+ device_info?: Record<string, unknown>;
199
+ custom_variables?: Record<string, string>;
200
+ [key: string]: unknown;
201
+ }
202
+
203
+ export interface SurveySubmitResult {
204
+ respondent_id: string;
205
+ survey_id: string;
206
+ status: string;
207
+ /** Submitted answers — included so host apps can implement conditional post-submit flows */
208
+ answers?: SurveyAnswer[];
209
+ }
210
+
211
+ // ============= Presentation Options =============
212
+
213
+ export interface SurveyPresentationOptions {
214
+ customerId?: string;
215
+ anonymousId?: string;
216
+ platform?: string;
217
+ customVariables?: Record<string, string>;
218
+ onPresent?: (surveyId: string) => void;
219
+ onDismiss?: (surveyId: string) => void;
220
+ onComplete?: (surveyId: string, result: SurveySubmitResult) => void;
221
+ onError?: (error: Error) => void;
222
+ onAnswerChanged?: (answer: SurveyAnswer) => void;
223
+ }
224
+
225
+ // ============= Cache Entry =============
226
+
227
+ export interface SurveyCacheEntry {
228
+ config: SurveyConfiguration;
229
+ fetchedAt: number;
230
+ }
231
+
232
+ // ============= Survey List (from bdsurvey-list) =============
233
+
234
+ export interface SurveyListItem {
235
+ id: string;
236
+ name: string;
237
+ description: string | null;
238
+ type: string;
239
+ status: string;
240
+ }
241
+
242
+ export interface SurveyListResult {
243
+ surveys: SurveyListItem[];
244
+ }
@@ -0,0 +1,9 @@
1
+ // Ambient module declarations for OPTIONAL native peer dependencies that are
2
+ // not installed by default in this package. These are runtime-optional deps;
3
+ // consumers who use the notification / icon features are expected to install
4
+ // them. Declaring them as `any` modules is the standard approach for optional
5
+ // peers so the type build does not fail when they are absent.
6
+
7
+ declare module 'react-native-push-notification';
8
+ declare module '@react-native-community/push-notification-ios';
9
+ declare module 'lucide-react-native';