@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,232 @@
1
+ /**
2
+ * Animation utilities for React Native tap behavior transitions
3
+ */
4
+
5
+ import { Animated, Easing } from 'react-native';
6
+
7
+ export type TransitionType = 'none' | 'shrink' | 'grow' | 'fade' | 'bounce' | 'slide' | 'rotate' | 'pulse';
8
+
9
+ /**
10
+ * Play a transition animation on an Animated.Value
11
+ */
12
+ export async function playTransition(
13
+ scaleValue: Animated.Value,
14
+ opacityValue: Animated.Value,
15
+ type: TransitionType,
16
+ duration: number
17
+ ): Promise<void> {
18
+ if (type === 'none') return;
19
+
20
+ return new Promise((resolve) => {
21
+ const animation = getTransitionAnimation(scaleValue, opacityValue, type, duration);
22
+ animation.start(() => resolve());
23
+ });
24
+ }
25
+
26
+ /**
27
+ * Get the appropriate animation for a transition type
28
+ */
29
+ function getTransitionAnimation(
30
+ scaleValue: Animated.Value,
31
+ opacityValue: Animated.Value,
32
+ type: TransitionType,
33
+ duration: number
34
+ ): Animated.CompositeAnimation {
35
+ const halfDuration = duration / 2;
36
+ const quarterDuration = duration / 4;
37
+
38
+ switch (type) {
39
+ case 'shrink':
40
+ return Animated.sequence([
41
+ Animated.timing(scaleValue, {
42
+ toValue: 0.95,
43
+ duration: halfDuration,
44
+ easing: Easing.out(Easing.ease),
45
+ useNativeDriver: true,
46
+ }),
47
+ Animated.timing(scaleValue, {
48
+ toValue: 1,
49
+ duration: halfDuration,
50
+ easing: Easing.out(Easing.ease),
51
+ useNativeDriver: true,
52
+ }),
53
+ ]);
54
+
55
+ case 'grow':
56
+ return Animated.sequence([
57
+ Animated.timing(scaleValue, {
58
+ toValue: 1.05,
59
+ duration: halfDuration,
60
+ easing: Easing.out(Easing.ease),
61
+ useNativeDriver: true,
62
+ }),
63
+ Animated.timing(scaleValue, {
64
+ toValue: 1,
65
+ duration: halfDuration,
66
+ easing: Easing.out(Easing.ease),
67
+ useNativeDriver: true,
68
+ }),
69
+ ]);
70
+
71
+ case 'fade':
72
+ return Animated.sequence([
73
+ Animated.timing(opacityValue, {
74
+ toValue: 0.5,
75
+ duration: halfDuration,
76
+ easing: Easing.out(Easing.ease),
77
+ useNativeDriver: true,
78
+ }),
79
+ Animated.timing(opacityValue, {
80
+ toValue: 1,
81
+ duration: halfDuration,
82
+ easing: Easing.out(Easing.ease),
83
+ useNativeDriver: true,
84
+ }),
85
+ ]);
86
+
87
+ case 'bounce':
88
+ return Animated.sequence([
89
+ Animated.timing(scaleValue, {
90
+ toValue: 0.9,
91
+ duration: quarterDuration,
92
+ easing: Easing.out(Easing.ease),
93
+ useNativeDriver: true,
94
+ }),
95
+ Animated.spring(scaleValue, {
96
+ toValue: 1,
97
+ friction: 3,
98
+ tension: 100,
99
+ useNativeDriver: true,
100
+ }),
101
+ ]);
102
+
103
+ case 'pulse':
104
+ return Animated.sequence([
105
+ Animated.parallel([
106
+ Animated.timing(scaleValue, {
107
+ toValue: 1.1,
108
+ duration: halfDuration,
109
+ easing: Easing.out(Easing.ease),
110
+ useNativeDriver: true,
111
+ }),
112
+ Animated.timing(opacityValue, {
113
+ toValue: 0.8,
114
+ duration: halfDuration,
115
+ easing: Easing.out(Easing.ease),
116
+ useNativeDriver: true,
117
+ }),
118
+ ]),
119
+ Animated.parallel([
120
+ Animated.timing(scaleValue, {
121
+ toValue: 1,
122
+ duration: halfDuration,
123
+ easing: Easing.out(Easing.ease),
124
+ useNativeDriver: true,
125
+ }),
126
+ Animated.timing(opacityValue, {
127
+ toValue: 1,
128
+ duration: halfDuration,
129
+ easing: Easing.out(Easing.ease),
130
+ useNativeDriver: true,
131
+ }),
132
+ ]),
133
+ ]);
134
+
135
+ case 'slide':
136
+ // For slide, we need a translateX value - this is a simplified version
137
+ return Animated.sequence([
138
+ Animated.timing(scaleValue, {
139
+ toValue: 0.98,
140
+ duration: quarterDuration,
141
+ easing: Easing.out(Easing.ease),
142
+ useNativeDriver: true,
143
+ }),
144
+ Animated.timing(scaleValue, {
145
+ toValue: 1.02,
146
+ duration: quarterDuration,
147
+ easing: Easing.inOut(Easing.ease),
148
+ useNativeDriver: true,
149
+ }),
150
+ Animated.timing(scaleValue, {
151
+ toValue: 1,
152
+ duration: quarterDuration,
153
+ easing: Easing.out(Easing.ease),
154
+ useNativeDriver: true,
155
+ }),
156
+ ]);
157
+
158
+ case 'rotate':
159
+ // Note: Rotation requires a different animated value
160
+ return Animated.sequence([
161
+ Animated.timing(scaleValue, {
162
+ toValue: 0.98,
163
+ duration: quarterDuration,
164
+ easing: Easing.out(Easing.ease),
165
+ useNativeDriver: true,
166
+ }),
167
+ Animated.timing(scaleValue, {
168
+ toValue: 1,
169
+ duration: quarterDuration,
170
+ easing: Easing.out(Easing.ease),
171
+ useNativeDriver: true,
172
+ }),
173
+ ]);
174
+
175
+ default:
176
+ return Animated.timing(scaleValue, {
177
+ toValue: 1,
178
+ duration: 0,
179
+ useNativeDriver: true,
180
+ });
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Create animation values for a button
186
+ */
187
+ export function createAnimationValues(): {
188
+ scale: Animated.Value;
189
+ opacity: Animated.Value;
190
+ translateX: Animated.Value;
191
+ rotate: Animated.Value;
192
+ } {
193
+ return {
194
+ scale: new Animated.Value(1),
195
+ opacity: new Animated.Value(1),
196
+ translateX: new Animated.Value(0),
197
+ rotate: new Animated.Value(0),
198
+ };
199
+ }
200
+
201
+ /**
202
+ * Reset animation values to default
203
+ */
204
+ export function resetAnimationValues(values: {
205
+ scale: Animated.Value;
206
+ opacity: Animated.Value;
207
+ translateX: Animated.Value;
208
+ rotate: Animated.Value;
209
+ }): void {
210
+ values.scale.setValue(1);
211
+ values.opacity.setValue(1);
212
+ values.translateX.setValue(0);
213
+ values.rotate.setValue(0);
214
+ }
215
+
216
+ /**
217
+ * Get animated style from animation values
218
+ */
219
+ export function getAnimatedStyle(values: {
220
+ scale: Animated.Value;
221
+ opacity: Animated.Value;
222
+ translateX: Animated.Value;
223
+ rotate: Animated.Value;
224
+ }): {
225
+ transform: { scale: Animated.Value }[];
226
+ opacity: Animated.Value;
227
+ } {
228
+ return {
229
+ transform: [{ scale: values.scale }],
230
+ opacity: values.opacity,
231
+ };
232
+ }
@@ -0,0 +1,113 @@
1
+ import { Platform, PermissionsAndroid } from 'react-native';
2
+ // Note: Requires 'react-native-calendar-events' package to be installed
3
+
4
+ export interface CalendarEvent {
5
+ title: string;
6
+ description?: string;
7
+ location?: string;
8
+ startDate: Date;
9
+ endDate: Date;
10
+ allDay?: boolean;
11
+ url?: string;
12
+ notes?: string;
13
+ }
14
+
15
+ export interface CalendarPermissionStatus {
16
+ granted: boolean;
17
+ canRequest: boolean;
18
+ }
19
+
20
+ export interface CalendarResult {
21
+ success: boolean;
22
+ eventId?: string;
23
+ error?: string;
24
+ }
25
+
26
+ /**
27
+ * Request calendar permissions
28
+ * Note: Requires react-native-calendar-events package
29
+ */
30
+ export async function requestCalendarPermission(): Promise<CalendarPermissionStatus> {
31
+ try {
32
+ // Dynamic import to avoid errors if package not installed
33
+ const RNCalendarEvents = require('react-native-calendar-events');
34
+
35
+ if (Platform.OS === 'android' && Platform.Version >= 23) {
36
+ const granted = await PermissionsAndroid.request(
37
+ PermissionsAndroid.PERMISSIONS.WRITE_CALENDAR
38
+ );
39
+ return {
40
+ granted: granted === PermissionsAndroid.RESULTS.GRANTED,
41
+ canRequest: granted !== PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN,
42
+ };
43
+ }
44
+
45
+ const status = await RNCalendarEvents.requestPermissions();
46
+ return {
47
+ granted: status === 'authorized',
48
+ canRequest: status === 'undetermined',
49
+ };
50
+ } catch (error) {
51
+ console.warn('react-native-calendar-events not installed');
52
+ return { granted: false, canRequest: false };
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Check current calendar permission status
58
+ */
59
+ export async function checkCalendarPermission(): Promise<CalendarPermissionStatus> {
60
+ try {
61
+ const RNCalendarEvents = require('react-native-calendar-events');
62
+ const status = await RNCalendarEvents.checkPermissions();
63
+ return {
64
+ granted: status === 'authorized',
65
+ canRequest: status === 'undetermined',
66
+ };
67
+ } catch (error) {
68
+ return { granted: false, canRequest: false };
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Add event to calendar
74
+ */
75
+ export async function addCalendarEvent(event: CalendarEvent): Promise<CalendarResult> {
76
+ try {
77
+ const RNCalendarEvents = require('react-native-calendar-events');
78
+
79
+ const permission = await checkCalendarPermission();
80
+ if (!permission.granted) {
81
+ return { success: false, error: 'Calendar permission not granted' };
82
+ }
83
+
84
+ const eventId = await RNCalendarEvents.saveEvent(event.title, {
85
+ startDate: event.startDate.toISOString(),
86
+ endDate: event.endDate.toISOString(),
87
+ description: event.description,
88
+ location: event.location,
89
+ allDay: event.allDay,
90
+ notes: event.notes,
91
+ url: event.url,
92
+ });
93
+
94
+ return { success: true, eventId };
95
+ } catch (error) {
96
+ return {
97
+ success: false,
98
+ error: error instanceof Error ? error.message : 'Failed to add event',
99
+ };
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Check if calendar is supported
105
+ */
106
+ export function isCalendarSupported(): boolean {
107
+ try {
108
+ require('react-native-calendar-events');
109
+ return true;
110
+ } catch {
111
+ return false;
112
+ }
113
+ }
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Configuration resolver for React Native
3
+ * Implements fallback logic for multi-device configurations
4
+ */
5
+
6
+ import { PaywallConfiguration } from '../types';
7
+ import { DeviceCategory } from './deviceDetection';
8
+
9
+ export interface MultiPaywallConfig {
10
+ phone_portrait?: PaywallConfiguration;
11
+ phone_landscape?: PaywallConfiguration;
12
+ xl_phone_portrait?: PaywallConfiguration;
13
+ xl_phone_landscape?: PaywallConfiguration;
14
+ tablet_portrait?: PaywallConfiguration;
15
+ tablet_landscape?: PaywallConfiguration;
16
+ desktop_web?: PaywallConfiguration;
17
+ }
18
+
19
+ const DEVICE_GROUPS = {
20
+ phone_portrait: { group: 'phone', orientation: 'portrait' },
21
+ phone_landscape: { group: 'phone', orientation: 'landscape' },
22
+ xl_phone_portrait: { group: 'xl_phone', orientation: 'portrait' },
23
+ xl_phone_landscape: { group: 'xl_phone', orientation: 'landscape' },
24
+ tablet_portrait: { group: 'tablet', orientation: 'portrait' },
25
+ tablet_landscape: { group: 'tablet', orientation: 'landscape' },
26
+ desktop_web: { group: 'desktop', orientation: 'landscape' },
27
+ };
28
+
29
+ /**
30
+ * Find the nearest existing configuration for fallback
31
+ */
32
+ export function findNearestConfig(
33
+ multiConfig: MultiPaywallConfig,
34
+ targetCategory: DeviceCategory
35
+ ): DeviceCategory | null {
36
+ const targetInfo = DEVICE_GROUPS[targetCategory];
37
+
38
+ // Priority 1: Same device group, same orientation
39
+ const sameGroupSameOrientation = (Object.keys(DEVICE_GROUPS) as DeviceCategory[])
40
+ .find(cat =>
41
+ cat !== targetCategory &&
42
+ DEVICE_GROUPS[cat].group === targetInfo.group &&
43
+ DEVICE_GROUPS[cat].orientation === targetInfo.orientation &&
44
+ multiConfig[cat]
45
+ );
46
+
47
+ if (sameGroupSameOrientation) return sameGroupSameOrientation;
48
+
49
+ // Priority 2: Same device group, different orientation
50
+ const sameGroupDiffOrientation = (Object.keys(DEVICE_GROUPS) as DeviceCategory[])
51
+ .find(cat =>
52
+ cat !== targetCategory &&
53
+ DEVICE_GROUPS[cat].group === targetInfo.group &&
54
+ multiConfig[cat]
55
+ );
56
+
57
+ if (sameGroupDiffOrientation) return sameGroupDiffOrientation;
58
+
59
+ // Priority 3: Fallback to smaller device in same orientation
60
+ if (targetInfo.group === 'xl_phone') {
61
+ const phoneEquivalent = targetInfo.orientation === 'portrait'
62
+ ? 'phone_portrait'
63
+ : 'phone_landscape';
64
+ if (multiConfig[phoneEquivalent]) return phoneEquivalent;
65
+ }
66
+
67
+ if (targetInfo.group === 'tablet') {
68
+ const xlPhoneEquivalent = targetInfo.orientation === 'portrait'
69
+ ? 'xl_phone_portrait'
70
+ : 'xl_phone_landscape';
71
+ if (multiConfig[xlPhoneEquivalent]) return xlPhoneEquivalent;
72
+
73
+ const phoneEquivalent = targetInfo.orientation === 'portrait'
74
+ ? 'phone_portrait'
75
+ : 'phone_landscape';
76
+ if (multiConfig[phoneEquivalent]) return phoneEquivalent;
77
+ }
78
+
79
+ // Priority 4: Phone portrait (base config - ALWAYS exists)
80
+ if (multiConfig.phone_portrait && targetCategory !== 'phone_portrait') {
81
+ return 'phone_portrait';
82
+ }
83
+
84
+ return null;
85
+ }
86
+
87
+ /**
88
+ * Resolve the appropriate configuration with fallback logic
89
+ */
90
+ export function resolveConfiguration(
91
+ multiConfig: MultiPaywallConfig,
92
+ targetCategory: DeviceCategory
93
+ ): PaywallConfiguration | null {
94
+ // Try to get specific configuration
95
+ let config = multiConfig[targetCategory];
96
+
97
+ // If not found, use fallback logic
98
+ if (!config) {
99
+ const nearestCategory = findNearestConfig(multiConfig, targetCategory);
100
+ if (nearestCategory) {
101
+ config = multiConfig[nearestCategory];
102
+ }
103
+ }
104
+
105
+ return config || null;
106
+ }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Device detection utilities for React Native
3
+ */
4
+
5
+ import { Dimensions, Platform } from 'react-native';
6
+
7
+ export type DeviceCategory =
8
+ | 'phone_portrait'
9
+ | 'phone_landscape'
10
+ | 'xl_phone_portrait'
11
+ | 'xl_phone_landscape'
12
+ | 'tablet_portrait'
13
+ | 'tablet_landscape'
14
+ | 'desktop_web';
15
+
16
+ export interface DeviceCategoryInfo {
17
+ category: DeviceCategory;
18
+ label: string;
19
+ dimensions: { width: number; height: number };
20
+ orientation: 'portrait' | 'landscape';
21
+ group: 'phone' | 'xl_phone' | 'tablet' | 'desktop';
22
+ osName: string;
23
+ osVersion: string;
24
+ }
25
+
26
+ /**
27
+ * Detect device category based on current dimensions
28
+ */
29
+ export function detectDeviceCategory(): DeviceCategory {
30
+ const { width, height } = Dimensions.get('window');
31
+ const isLandscape = width > height;
32
+
33
+ // Desktop web (viewport >= 1200px)
34
+ if (width >= 1200) return 'desktop_web';
35
+
36
+ // Tablet range (700-1200px)
37
+ if (width >= 700 && width < 1200) {
38
+ return isLandscape ? 'tablet_landscape' : 'tablet_portrait';
39
+ }
40
+
41
+ // XL Phone range (430-700px width)
42
+ if (width >= 430 && width < 700) {
43
+ return isLandscape ? 'xl_phone_landscape' : 'xl_phone_portrait';
44
+ }
45
+
46
+ // Standard phone (<430px)
47
+ return isLandscape ? 'phone_landscape' : 'phone_portrait';
48
+ }
49
+
50
+ /**
51
+ * Get device info including OS details
52
+ */
53
+ export function getDeviceInfo() {
54
+ const { width, height } = Dimensions.get('window');
55
+ const category = detectDeviceCategory();
56
+
57
+ // Get OS name (capitalize first letter)
58
+ const osName = Platform.OS === 'ios' ? 'iOS' : Platform.OS === 'android' ? 'Android' : 'Web';
59
+
60
+ // Get OS version
61
+ const osVersion = String(Platform.Version || 'Unknown');
62
+
63
+ return {
64
+ width,
65
+ height,
66
+ category,
67
+ platform: Platform.OS,
68
+ osName,
69
+ osVersion,
70
+ isTablet: category.includes('tablet'),
71
+ isPhone: category.includes('phone'),
72
+ orientation: width > height ? 'landscape' : 'portrait',
73
+ };
74
+ }
75
+
76
+ /**
77
+ * Check if device is a tablet
78
+ */
79
+ export function isTablet(): boolean {
80
+ const { width, height } = Dimensions.get('window');
81
+ const minDimension = Math.min(width, height);
82
+ return minDimension >= 700;
83
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Haptic feedback utilities for React Native
3
+ */
4
+
5
+ import { Platform, Vibration } from 'react-native';
6
+
7
+ export type HapticType = 'light' | 'medium' | 'heavy' | 'success' | 'warning' | 'error';
8
+
9
+ /**
10
+ * Trigger haptic feedback
11
+ * Phase 4.5: Integrated with paywall action execution
12
+ */
13
+ export function triggerHaptic(type: HapticType, intensity: number = 1.0): void {
14
+ if (Platform.OS === 'ios') {
15
+ // iOS uses native haptic feedback (requires expo-haptics or react-native-haptic-feedback)
16
+ // For now, use basic vibration
17
+ const duration = getHapticDuration(type, intensity);
18
+ Vibration.vibrate(duration);
19
+ } else if (Platform.OS === 'android') {
20
+ // Android vibration
21
+ const duration = getHapticDuration(type, intensity);
22
+ Vibration.vibrate(duration);
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Trigger haptic from WebView action (Phase 4.5)
28
+ */
29
+ export function triggerHapticFromAction(hapticType?: string): void {
30
+ const type = (hapticType || 'medium') as HapticType;
31
+ triggerHaptic(type);
32
+ }
33
+
34
+ /**
35
+ * Get vibration duration for haptic type
36
+ */
37
+ function getHapticDuration(type: HapticType, intensity: number): number {
38
+ const baseDurations: Record<HapticType, number> = {
39
+ light: 10,
40
+ medium: 20,
41
+ heavy: 40,
42
+ success: 15,
43
+ warning: 25,
44
+ error: 30,
45
+ };
46
+
47
+ return Math.round(baseDurations[type] * intensity);
48
+ }
49
+
50
+ /**
51
+ * Check if haptic feedback is available
52
+ */
53
+ export function isHapticAvailable(): boolean {
54
+ return Platform.OS === 'ios' || Platform.OS === 'android';
55
+ }
@@ -0,0 +1,102 @@
1
+ import * as LucideIcons from 'lucide-react-native';
2
+
3
+ /**
4
+ * React Native uses Lucide directly - no mapping needed
5
+ * This file exists for consistency with other platforms
6
+ * and to provide a unified API
7
+ */
8
+
9
+ export interface IconMapperResult {
10
+ component: React.ComponentType<any> | null;
11
+ fallback: string | null;
12
+ }
13
+
14
+ /**
15
+ * Get Lucide icon component by name
16
+ * React Native renders Lucide icons directly (best cross-platform solution for RN)
17
+ */
18
+ export function getLucideIcon(iconName: string): IconMapperResult {
19
+ const icons = LucideIcons as any;
20
+ const IconComponent = icons[iconName];
21
+
22
+ if (IconComponent && typeof IconComponent === 'function') {
23
+ return {
24
+ component: IconComponent,
25
+ fallback: null,
26
+ };
27
+ }
28
+
29
+ // Return fallback
30
+ return {
31
+ component: null,
32
+ fallback: iconName,
33
+ };
34
+ }
35
+
36
+ /**
37
+ * Check if icon exists in Lucide library
38
+ */
39
+ export function hasLucideIcon(iconName: string): boolean {
40
+ const icons = LucideIcons as any;
41
+ return iconName in icons && typeof icons[iconName] === 'function';
42
+ }
43
+
44
+ /**
45
+ * Get all available Lucide icon names
46
+ */
47
+ export function getAvailableIcons(): string[] {
48
+ const icons = LucideIcons as any;
49
+ return Object.keys(icons).filter(key => typeof icons[key] === 'function');
50
+ }
51
+
52
+ /**
53
+ * Recommended cross-platform icons (guaranteed to look good everywhere)
54
+ */
55
+ export const RECOMMENDED_ICONS = [
56
+ // Core Navigation & Actions
57
+ 'Star', 'Heart', 'Home', 'Settings', 'User', 'Search', 'Menu', 'X', 'Check',
58
+ 'ChevronRight', 'ChevronLeft', 'ChevronDown', 'ChevronUp', 'Plus', 'Minus',
59
+ 'Edit', 'Trash', 'Calendar', 'Clock', 'Mail', 'Phone', 'Camera', 'Image',
60
+ 'Video', 'Music', 'Download', 'Upload', 'Share', 'Info', 'AlertTriangle',
61
+ 'Lock', 'Eye', 'Bell', 'ShoppingCart', 'Gift', 'Globe', 'ArrowRight', 'ArrowLeft',
62
+
63
+ // Forms & Controls (expanded)
64
+ 'CheckSquare', 'Square', 'ToggleRight', 'Bold', 'Italic', 'AlignLeft',
65
+ 'AlignCenter', 'AlignRight', 'List', 'Palette', 'Crop', 'RotateCw',
66
+
67
+ // Arrows & Navigation (expanded)
68
+ 'ArrowUp', 'ArrowDown', 'ArrowUpRight', 'ChevronsRight', 'Repeat', 'Undo',
69
+ 'Redo', 'Navigation', 'Compass', 'Expand', 'Minimize',
70
+
71
+ // E-commerce (expanded)
72
+ 'Store', 'ShoppingBag', 'Wallet', 'CreditCard', 'Package', 'Truck',
73
+ 'Receipt', 'Barcode', 'QrCode', 'Tag', 'Percent',
74
+
75
+ // Communication (expanded)
76
+ 'MessageCircle', 'MessageSquare', 'MailOpen', 'Inbox', 'Send', 'Reply',
77
+ 'Phone', 'Mic', 'Users', 'UserPlus', 'Contact', 'Award',
78
+
79
+ // Files & Documents (expanded)
80
+ 'File', 'FileText', 'Folder', 'FolderOpen', 'Save', 'Copy', 'Clipboard',
81
+ 'Paperclip', 'Link', 'Database',
82
+
83
+ // Media (expanded)
84
+ 'Play', 'Pause', 'SkipForward', 'Volume2', 'Film', 'Radio', 'Tv',
85
+
86
+ // Charts & Data (expanded)
87
+ 'BarChart', 'LineChart', 'PieChart', 'Activity', 'TrendingUp', 'TrendingDown',
88
+ 'Zap', 'Signal', 'Network',
89
+
90
+ // Transportation
91
+ 'Car', 'Bus', 'Train', 'Plane', 'Bike', 'MapPin', 'Map',
92
+
93
+ // Health & Lifestyle
94
+ 'Heart', 'Pill', 'Coffee', 'Pizza', 'Leaf', 'Accessibility',
95
+
96
+ // Weather
97
+ 'Sun', 'Moon', 'Cloud', 'CloudRain', 'CloudSnow', 'Droplet', 'Wind',
98
+
99
+ // System & Miscellaneous
100
+ 'Grid', 'Layers', 'Filter', 'RefreshCw', 'Code', 'Power', 'Battery',
101
+ 'Sparkles', 'Crown', 'Shield', 'Timer', 'Flag', 'Target',
102
+ ];