@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,452 @@
1
+ /**
2
+ * ChartCurveComponent - Native React Native implementation
3
+ * Supports 6 curve types: ascending, descending, dip, rise, flat-end, s-curve
4
+ */
5
+
6
+ import React, { useEffect, useRef } from 'react';
7
+ import {
8
+ View,
9
+ Text,
10
+ StyleSheet,
11
+ Animated,
12
+ Easing,
13
+ } from 'react-native';
14
+ import Svg, {
15
+ Path,
16
+ Line,
17
+ Circle,
18
+ Rect,
19
+ Text as SvgText,
20
+ Defs,
21
+ LinearGradient,
22
+ Stop,
23
+ ClipPath,
24
+ G,
25
+ } from 'react-native-svg';
26
+ import { PaywallComponent } from '../types';
27
+
28
+ interface ChartCurveComponentProps {
29
+ component: PaywallComponent;
30
+ stateManager?: any;
31
+ isPreviewMode?: boolean;
32
+ }
33
+
34
+ // Curve path definitions (relative to viewBox 0 0 100 100)
35
+ const CURVE_PATHS: Record<string, string> = {
36
+ ascending: 'M 0 80 Q 25 75, 50 50 T 100 10',
37
+ descending: 'M 0 10 Q 25 25, 50 50 T 100 80',
38
+ dip: 'M 0 30 Q 25 70, 50 80 T 100 30',
39
+ rise: 'M 0 70 Q 25 30, 50 20 T 100 70',
40
+ 'flat-end': 'M 0 80 Q 30 40, 60 25 T 100 25',
41
+ 's-curve': 'M 0 80 C 25 80, 35 20, 50 20 S 75 80, 100 20',
42
+ };
43
+
44
+ // Helper to extract color from fill value
45
+ const getColorFromFill = (fill: any, fallback: string): string => {
46
+ if (!fill) return fallback;
47
+ if (typeof fill === 'string') return fill;
48
+
49
+ if (typeof fill === 'object') {
50
+ if (fill.type === 'solid' && fill.color) return fill.color;
51
+ if (fill.type === 'gradient' && fill.stops?.length > 0) {
52
+ return fill.stops[0].color || fallback;
53
+ }
54
+ if (fill.color) return fill.color;
55
+ }
56
+
57
+ return fallback;
58
+ };
59
+
60
+ // Helper to extract gradient stops
61
+ const getGradientStops = (fill: any): Array<{ color: string; offset: number }> | null => {
62
+ if (!fill || typeof fill !== 'object') return null;
63
+ if (fill.type === 'gradient' && fill.stops?.length > 0) {
64
+ return fill.stops.map((stop: any) => ({
65
+ color: stop.color || '#3B82F6',
66
+ offset: (stop.position ?? 0) / 100,
67
+ }));
68
+ }
69
+ return null;
70
+ };
71
+
72
+ // Generate date labels based on date range
73
+ const generateDateLabels = (
74
+ startDate: string | undefined,
75
+ endDate: string | undefined,
76
+ unit: string,
77
+ count: number = 5
78
+ ): string[] => {
79
+ const labels: string[] = [];
80
+
81
+ if (!startDate || !endDate) {
82
+ // Generate placeholder labels
83
+ for (let i = 0; i < count; i++) {
84
+ labels.push(`Day ${i + 1}`);
85
+ }
86
+ return labels;
87
+ }
88
+
89
+ const start = new Date(startDate);
90
+ const end = new Date(endDate);
91
+ const diff = end.getTime() - start.getTime();
92
+
93
+ for (let i = 0; i < count; i++) {
94
+ const date = new Date(start.getTime() + (diff * i) / (count - 1));
95
+
96
+ switch (unit) {
97
+ case 'day':
98
+ labels.push(date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }));
99
+ break;
100
+ case 'week':
101
+ labels.push(`W${Math.ceil(date.getDate() / 7)}`);
102
+ break;
103
+ case 'month':
104
+ labels.push(date.toLocaleDateString('en-US', { month: 'short' }));
105
+ break;
106
+ case 'year':
107
+ labels.push(date.getFullYear().toString());
108
+ break;
109
+ default:
110
+ labels.push(date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }));
111
+ }
112
+ }
113
+
114
+ return labels;
115
+ };
116
+
117
+ export const ChartCurveComponent: React.FC<ChartCurveComponentProps> = ({
118
+ component,
119
+ stateManager,
120
+ isPreviewMode = false,
121
+ }) => {
122
+ const props = component.properties as any;
123
+
124
+ // Curve configuration
125
+ const curveType = props.curveType || 'ascending';
126
+ const curvePath = CURVE_PATHS[curveType] || CURVE_PATHS.ascending;
127
+
128
+ // Badge configuration
129
+ const showLeftBadge = props.showLeftBadge !== false;
130
+ const showRightBadge = props.showRightBadge !== false;
131
+ const leftBadgeText = props.leftBadgeText || 'Start';
132
+ const rightBadgeText = props.rightBadgeText || 'End';
133
+ const badgeFill = getColorFromFill(props.badgeFill, '#EFF6FF');
134
+ const badgeTextFill = getColorFromFill(props.badgeTextFill, '#1E40AF');
135
+ const badgeBorderRadius = props.badgeBorderRadius ?? 4;
136
+ const badgeFontSize = props.badgeFontSize ?? 10;
137
+
138
+ // Line styling
139
+ const lineStroke = getColorFromFill(props.lineStroke, '#3B82F6');
140
+ const lineStrokeGradient = getGradientStops(props.lineStroke);
141
+ const lineWidth = props.lineWidth ?? 2;
142
+
143
+ // Area configuration
144
+ const showArea = props.showArea ?? true;
145
+ const areaFill = getColorFromFill(props.areaFill, '#3B82F6');
146
+ const areaFillGradient = getGradientStops(props.areaFill);
147
+
148
+ // Dots configuration
149
+ const showDots = props.showDots ?? false;
150
+ const dotSize = props.dotSize ?? 4;
151
+ const dotFill = getColorFromFill(props.dotFill, '#3B82F6');
152
+
153
+ // Animation configuration
154
+ const animated = props.animated !== false;
155
+ const animationDuration = props.animationDuration ?? 1000;
156
+
157
+ // Grid/axis configuration
158
+ const showGrid = props.showGrid ?? false;
159
+ const showXAxis = props.showXAxis !== false;
160
+ const gridColor = getColorFromFill(props.gridColor, '#E5E7EB');
161
+ const axisColor = getColorFromFill(props.axisColor, '#9CA3AF');
162
+
163
+ // X-axis label configuration
164
+ const xLabelMode = props.xLabelMode || 'none';
165
+ const dateRange = props.dateRange || {};
166
+ const dateUnit = props.dateUnit || 'day';
167
+ const customLabels = props.customLabels || [];
168
+
169
+ // Get X-axis labels
170
+ const getXLabels = (): string[] => {
171
+ switch (xLabelMode) {
172
+ case 'date-range':
173
+ return generateDateLabels(dateRange.start, dateRange.end, dateUnit);
174
+ case 'custom':
175
+ return customLabels.length > 0 ? customLabels : ['', '', '', '', ''];
176
+ default:
177
+ return [];
178
+ }
179
+ };
180
+
181
+ const xLabels = getXLabels();
182
+
183
+ // Animation
184
+ const animatedProgress = useRef(new Animated.Value(0)).current;
185
+
186
+ useEffect(() => {
187
+ if (animated) {
188
+ animatedProgress.setValue(0);
189
+ Animated.timing(animatedProgress, {
190
+ toValue: 1,
191
+ duration: animationDuration,
192
+ easing: Easing.out(Easing.quad),
193
+ useNativeDriver: false,
194
+ }).start();
195
+ } else {
196
+ animatedProgress.setValue(1);
197
+ }
198
+ }, [animated, animationDuration, animatedProgress]);
199
+
200
+ // Get curve endpoint positions for badges
201
+ const getCurveEndpoints = (curveType: string): { left: { x: number; y: number }; right: { x: number; y: number } } => {
202
+ switch (curveType) {
203
+ case 'ascending':
204
+ return { left: { x: 0, y: 80 }, right: { x: 100, y: 10 } };
205
+ case 'descending':
206
+ return { left: { x: 0, y: 10 }, right: { x: 100, y: 80 } };
207
+ case 'dip':
208
+ return { left: { x: 0, y: 30 }, right: { x: 100, y: 30 } };
209
+ case 'rise':
210
+ return { left: { x: 0, y: 70 }, right: { x: 100, y: 70 } };
211
+ case 'flat-end':
212
+ return { left: { x: 0, y: 80 }, right: { x: 100, y: 25 } };
213
+ case 's-curve':
214
+ return { left: { x: 0, y: 80 }, right: { x: 100, y: 20 } };
215
+ default:
216
+ return { left: { x: 0, y: 80 }, right: { x: 100, y: 10 } };
217
+ }
218
+ };
219
+
220
+ const endpoints = getCurveEndpoints(curveType);
221
+
222
+ // Create area path (curve + bottom closing)
223
+ const getAreaPath = (): string => {
224
+ return `${curvePath} L 100 100 L 0 100 Z`;
225
+ };
226
+
227
+ // Calculate dot positions along the curve
228
+ const getDotPositions = (): Array<{ x: number; y: number }> => {
229
+ // Simplified: place dots at key points
230
+ const positions: Array<{ x: number; y: number }> = [];
231
+ const points = 5;
232
+
233
+ for (let i = 0; i < points; i++) {
234
+ const t = i / (points - 1);
235
+ const x = t * 100;
236
+ // Approximate y based on curve type
237
+ let y: number;
238
+ switch (curveType) {
239
+ case 'ascending':
240
+ y = 80 - (70 * t);
241
+ break;
242
+ case 'descending':
243
+ y = 10 + (70 * t);
244
+ break;
245
+ case 'dip':
246
+ y = 30 + 50 * Math.sin(Math.PI * t);
247
+ break;
248
+ case 'rise':
249
+ y = 70 - 50 * Math.sin(Math.PI * t);
250
+ break;
251
+ case 'flat-end':
252
+ y = 80 - 55 * Math.min(1, t * 1.5);
253
+ break;
254
+ case 's-curve':
255
+ y = t < 0.5 ? 80 - 60 * (2 * t) : 20 + 60 * (2 * t - 1) - 60;
256
+ break;
257
+ default:
258
+ y = 50;
259
+ }
260
+ positions.push({ x, y: Math.max(10, Math.min(90, y)) });
261
+ }
262
+
263
+ return positions;
264
+ };
265
+
266
+ const dotPositions = showDots ? getDotPositions() : [];
267
+
268
+ return (
269
+ <View style={styles.container}>
270
+ <View style={styles.chartContainer}>
271
+ <Svg width="100%" height="100%" viewBox="0 0 100 100" preserveAspectRatio="none">
272
+ <Defs>
273
+ {/* Line gradient */}
274
+ {lineStrokeGradient && (
275
+ <LinearGradient id="lineGradient" x1="0%" y1="0%" x2="100%" y2="0%">
276
+ {lineStrokeGradient.map((stop, index) => (
277
+ <Stop key={index} offset={`${stop.offset * 100}%`} stopColor={stop.color} />
278
+ ))}
279
+ </LinearGradient>
280
+ )}
281
+
282
+ {/* Area gradient */}
283
+ <LinearGradient id="areaGradient" x1="0%" y1="0%" x2="0%" y2="100%">
284
+ {areaFillGradient ? (
285
+ areaFillGradient.map((stop, index) => (
286
+ <Stop key={index} offset={`${stop.offset * 100}%`} stopColor={stop.color} stopOpacity={0.3} />
287
+ ))
288
+ ) : (
289
+ [
290
+ <Stop key="area-start" offset="0%" stopColor={areaFill} stopOpacity={0.3} />,
291
+ <Stop key="area-end" offset="100%" stopColor={areaFill} stopOpacity={0.05} />,
292
+ ]
293
+ )}
294
+ </LinearGradient>
295
+ </Defs>
296
+
297
+ {/* Grid lines */}
298
+ {showGrid && (
299
+ <G>
300
+ {[20, 40, 60, 80].map((y) => (
301
+ <Line
302
+ key={`h-${y}`}
303
+ x1="0"
304
+ y1={y}
305
+ x2="100"
306
+ y2={y}
307
+ stroke={gridColor}
308
+ strokeWidth={0.5}
309
+ strokeDasharray="2,2"
310
+ />
311
+ ))}
312
+ {[20, 40, 60, 80].map((x) => (
313
+ <Line
314
+ key={`v-${x}`}
315
+ x1={x}
316
+ y1="0"
317
+ x2={x}
318
+ y2="100"
319
+ stroke={gridColor}
320
+ strokeWidth={0.5}
321
+ strokeDasharray="2,2"
322
+ />
323
+ ))}
324
+ </G>
325
+ )}
326
+
327
+ {/* Area fill */}
328
+ {showArea && (
329
+ <Path
330
+ d={getAreaPath()}
331
+ fill="url(#areaGradient)"
332
+ />
333
+ )}
334
+
335
+ {/* Curve line */}
336
+ <Path
337
+ d={curvePath}
338
+ stroke={lineStrokeGradient ? 'url(#lineGradient)' : lineStroke}
339
+ strokeWidth={lineWidth}
340
+ fill="none"
341
+ strokeLinecap="round"
342
+ strokeLinejoin="round"
343
+ />
344
+
345
+ {/* Data points */}
346
+ {showDots && dotPositions.map((pos, index) => (
347
+ <Circle
348
+ key={index}
349
+ cx={pos.x}
350
+ cy={pos.y}
351
+ r={dotSize / 2}
352
+ fill={dotFill}
353
+ />
354
+ ))}
355
+
356
+ {/* X-axis line */}
357
+ {showXAxis && (
358
+ <Line
359
+ x1="0"
360
+ y1="100"
361
+ x2="100"
362
+ y2="100"
363
+ stroke={axisColor}
364
+ strokeWidth={1}
365
+ />
366
+ )}
367
+
368
+ {/* Left badge */}
369
+ {showLeftBadge && (
370
+ <G>
371
+ <Rect
372
+ x={endpoints.left.x}
373
+ y={endpoints.left.y - 8}
374
+ width={30}
375
+ height={16}
376
+ rx={badgeBorderRadius}
377
+ fill={badgeFill}
378
+ />
379
+ <SvgText
380
+ x={endpoints.left.x + 15}
381
+ y={endpoints.left.y + 1}
382
+ fontSize={badgeFontSize}
383
+ fill={badgeTextFill}
384
+ textAnchor="middle"
385
+ alignmentBaseline="middle"
386
+ >
387
+ {leftBadgeText}
388
+ </SvgText>
389
+ </G>
390
+ )}
391
+
392
+ {/* Right badge */}
393
+ {showRightBadge && (
394
+ <G>
395
+ <Rect
396
+ x={endpoints.right.x - 30}
397
+ y={endpoints.right.y - 8}
398
+ width={30}
399
+ height={16}
400
+ rx={badgeBorderRadius}
401
+ fill={badgeFill}
402
+ />
403
+ <SvgText
404
+ x={endpoints.right.x - 15}
405
+ y={endpoints.right.y + 1}
406
+ fontSize={badgeFontSize}
407
+ fill={badgeTextFill}
408
+ textAnchor="middle"
409
+ alignmentBaseline="middle"
410
+ >
411
+ {rightBadgeText}
412
+ </SvgText>
413
+ </G>
414
+ )}
415
+ </Svg>
416
+ </View>
417
+
418
+ {/* X-axis labels */}
419
+ {xLabelMode !== 'none' && xLabels.length > 0 && (
420
+ <View style={styles.xAxisLabels}>
421
+ {xLabels.map((label, index) => (
422
+ <Text key={index} style={[styles.xAxisLabel, { color: axisColor }]}>
423
+ {label}
424
+ </Text>
425
+ ))}
426
+ </View>
427
+ )}
428
+ </View>
429
+ );
430
+ };
431
+
432
+ const styles = StyleSheet.create({
433
+ container: {
434
+ width: '100%',
435
+ aspectRatio: 2,
436
+ },
437
+ chartContainer: {
438
+ flex: 1,
439
+ paddingTop: 16,
440
+ paddingBottom: 8,
441
+ },
442
+ xAxisLabels: {
443
+ flexDirection: 'row',
444
+ justifyContent: 'space-between',
445
+ paddingHorizontal: 4,
446
+ marginTop: 4,
447
+ },
448
+ xAxisLabel: {
449
+ fontSize: 10,
450
+ textAlign: 'center',
451
+ },
452
+ });
@@ -0,0 +1,185 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import {
3
+ View,
4
+ Text,
5
+ TouchableOpacity,
6
+ StyleSheet,
7
+ } from 'react-native';
8
+ import { PaywallComponent } from '../types';
9
+
10
+ interface CheckboxComponentProps {
11
+ component: PaywallComponent;
12
+ stateManager?: any;
13
+ isPreviewMode?: boolean;
14
+ }
15
+
16
+ // Size mappings matching web schema
17
+ const SIZE_MAP = {
18
+ sm: 20,
19
+ md: 24,
20
+ lg: 32,
21
+ };
22
+
23
+ // Check icon mappings
24
+ const CHECK_ICONS = {
25
+ check: '✓',
26
+ cross: '✕',
27
+ circle: '●',
28
+ };
29
+
30
+ export const CheckboxComponent: React.FC<CheckboxComponentProps> = ({
31
+ component,
32
+ stateManager,
33
+ isPreviewMode = false,
34
+ }) => {
35
+ const props = component.properties as any;
36
+
37
+ const defaultChecked = props.defaultValue ?? false;
38
+ const disabled = props.disabled ?? false;
39
+ const label = props.label;
40
+ const variant = props.variant ?? 'default';
41
+ const checkIcon = props.checkIcon ?? 'check';
42
+ const labelPosition = props.labelPosition ?? 'right';
43
+
44
+ // Size handling - support both select values (sm/md/lg) and numeric values
45
+ const sizeValue = props.size ?? 'md';
46
+ const size = typeof sizeValue === 'number'
47
+ ? sizeValue
48
+ : (SIZE_MAP[sizeValue as keyof typeof SIZE_MAP] ?? SIZE_MAP.md);
49
+
50
+ const checkColor = props.checkColor ?? '#FFFFFF';
51
+ const uncheckedColor = props.uncheckedColor ?? '#d1d5db';
52
+ const checkedBackgroundColor = props.checkedBackgroundColor ?? '#007AFF';
53
+
54
+ const [isChecked, setIsChecked] = useState(defaultChecked);
55
+
56
+ // Register initial state
57
+ useEffect(() => {
58
+ if (stateManager) {
59
+ stateManager.updateState(`element:${component.id}.isChecked`, isChecked);
60
+ }
61
+ }, []);
62
+
63
+ // Subscribe to external state changes
64
+ useEffect(() => {
65
+ if (stateManager) {
66
+ return stateManager.subscribeToState(
67
+ `element:${component.id}.isChecked`,
68
+ (value: boolean) => {
69
+ if (value !== isChecked) {
70
+ setIsChecked(value);
71
+ }
72
+ }
73
+ );
74
+ }
75
+ }, [component.id, stateManager]);
76
+
77
+ const handleToggle = () => {
78
+ if (!disabled) {
79
+ const newValue = !isChecked;
80
+ setIsChecked(newValue);
81
+ if (stateManager) {
82
+ stateManager.updateState(`element:${component.id}.isChecked`, newValue);
83
+ }
84
+ }
85
+ };
86
+
87
+ // Get variant-specific styling
88
+ const getCheckboxStyle = () => {
89
+ const baseStyle = {
90
+ width: size,
91
+ height: size,
92
+ borderRadius: variant === 'outlined' ? size / 2 : 4,
93
+ };
94
+
95
+ switch (variant) {
96
+ case 'filled':
97
+ return {
98
+ ...baseStyle,
99
+ borderColor: isChecked ? checkedBackgroundColor : uncheckedColor,
100
+ backgroundColor: isChecked ? checkedBackgroundColor : uncheckedColor,
101
+ borderWidth: 0,
102
+ };
103
+ case 'outlined':
104
+ return {
105
+ ...baseStyle,
106
+ borderColor: isChecked ? checkedBackgroundColor : uncheckedColor,
107
+ backgroundColor: isChecked ? checkedBackgroundColor : 'transparent',
108
+ borderWidth: 2,
109
+ };
110
+ default: // 'default'
111
+ return {
112
+ ...baseStyle,
113
+ borderColor: isChecked ? checkedBackgroundColor : uncheckedColor,
114
+ backgroundColor: isChecked ? checkedBackgroundColor : 'transparent',
115
+ borderWidth: 2,
116
+ };
117
+ }
118
+ };
119
+
120
+ const checkIconChar = CHECK_ICONS[checkIcon as keyof typeof CHECK_ICONS] ?? CHECK_ICONS.check;
121
+
122
+ const renderCheckbox = () => (
123
+ <View style={[styles.checkbox, getCheckboxStyle()]}>
124
+ {isChecked && (
125
+ <Text style={[styles.checkmark, { fontSize: size * 0.6, color: checkColor }]}>
126
+ {checkIconChar}
127
+ </Text>
128
+ )}
129
+ </View>
130
+ );
131
+
132
+ const renderLabel = () => (
133
+ label ? (
134
+ <Text style={[
135
+ styles.label,
136
+ disabled && styles.disabledText,
137
+ labelPosition === 'left' ? styles.labelLeft : styles.labelRight
138
+ ]}>
139
+ {label}
140
+ </Text>
141
+ ) : null
142
+ );
143
+
144
+ return (
145
+ <TouchableOpacity
146
+ onPress={handleToggle}
147
+ disabled={disabled}
148
+ activeOpacity={0.7}
149
+ style={[styles.container, disabled && styles.disabled]}
150
+ >
151
+ {labelPosition === 'left' && renderLabel()}
152
+ {renderCheckbox()}
153
+ {labelPosition === 'right' && renderLabel()}
154
+ </TouchableOpacity>
155
+ );
156
+ };
157
+
158
+ const styles = StyleSheet.create({
159
+ container: {
160
+ flexDirection: 'row',
161
+ alignItems: 'center',
162
+ },
163
+ disabled: {
164
+ opacity: 0.5,
165
+ },
166
+ checkbox: {
167
+ alignItems: 'center',
168
+ justifyContent: 'center',
169
+ },
170
+ checkmark: {
171
+ fontWeight: 'bold',
172
+ },
173
+ label: {
174
+ fontSize: 16,
175
+ },
176
+ labelLeft: {
177
+ marginRight: 12,
178
+ },
179
+ labelRight: {
180
+ marginLeft: 12,
181
+ },
182
+ disabledText: {
183
+ color: '#999',
184
+ },
185
+ });