@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,299 @@
1
+ /**
2
+ * ShareButtonsComponent - React Native
3
+ *
4
+ * Social share buttons with Stack Child-Based Hybrid architecture and Layout Assistant.
5
+ * Features:
6
+ * - Hybrid mode: renders children via renderChild when available
7
+ * - Legacy mode: self-renders buttons when no children
8
+ * - Native share sheet
9
+ * - Platform-specific sharing (Twitter, Facebook, etc.)
10
+ * - Copy link functionality
11
+ */
12
+
13
+ import React, { useState, useCallback } from 'react';
14
+ import {
15
+ View,
16
+ Text,
17
+ TouchableOpacity,
18
+ StyleSheet,
19
+ Share,
20
+ Linking,
21
+ Clipboard,
22
+ } from 'react-native';
23
+ import { PaywallComponent } from '../types';
24
+
25
+ interface ShareButtonsComponentProps {
26
+ component: PaywallComponent;
27
+ stateManager?: any;
28
+ isPreviewMode?: boolean;
29
+ renderChild?: (child: PaywallComponent, index: number) => React.ReactNode;
30
+ }
31
+
32
+ // Helper to extract color from fill value
33
+ const getColorFromFill = (fill: any, fallback: string): string => {
34
+ if (!fill) return fallback;
35
+ if (typeof fill === 'string') return fill;
36
+ if (fill.resolvedColor) return fill.resolvedColor;
37
+ if (fill.type === 'color' && fill.color) return fill.color;
38
+ return fallback;
39
+ };
40
+
41
+ // Platform configurations with brand colors
42
+ const PLATFORM_CONFIG: Record<string, { icon: string; label: string; color: string }> = {
43
+ native: { icon: '📤', label: 'Share', color: '#3B82F6' },
44
+ copy: { icon: '🔗', label: 'Copy', color: '#6B7280' },
45
+ twitter: { icon: '🐦', label: 'Twitter', color: '#1DA1F2' },
46
+ facebook: { icon: '📘', label: 'Facebook', color: '#1877F2' },
47
+ linkedin: { icon: '💼', label: 'LinkedIn', color: '#0A66C2' },
48
+ whatsapp: { icon: '💬', label: 'WhatsApp', color: '#25D366' },
49
+ telegram: { icon: '✈️', label: 'Telegram', color: '#0088cc' },
50
+ email: { icon: '✉️', label: 'Email', color: '#6B7280' },
51
+ };
52
+
53
+ export const ShareButtonsComponent: React.FC<ShareButtonsComponentProps> = ({
54
+ component,
55
+ stateManager,
56
+ isPreviewMode = false,
57
+ renderChild,
58
+ }) => {
59
+ const props = component.properties as any;
60
+ // Children arrive fully styled with selectedAppearance for state changes
61
+ const children = component.children || [];
62
+ const visibleChildren = children.filter((c: any) => c.visible !== false);
63
+ const componentId = component.id;
64
+
65
+ // Platform toggles
66
+ const showNativeShare = props.showNativeShare !== false;
67
+ const showCopyLink = props.showCopyLink !== false;
68
+ const showTwitter = props.showTwitter ?? false;
69
+ const showFacebook = props.showFacebook ?? false;
70
+ const showLinkedIn = props.showLinkedIn ?? false;
71
+ const showWhatsApp = props.showWhatsApp ?? false;
72
+ const showTelegram = props.showTelegram ?? false;
73
+ const showEmail = props.showEmail ?? false;
74
+
75
+ // Build enabled platforms array
76
+ const enabledPlatforms: string[] = [];
77
+ if (showNativeShare) enabledPlatforms.push('native');
78
+ if (showCopyLink) enabledPlatforms.push('copy');
79
+ if (showTwitter) enabledPlatforms.push('twitter');
80
+ if (showFacebook) enabledPlatforms.push('facebook');
81
+ if (showLinkedIn) enabledPlatforms.push('linkedin');
82
+ if (showWhatsApp) enabledPlatforms.push('whatsapp');
83
+ if (showTelegram) enabledPlatforms.push('telegram');
84
+ if (showEmail) enabledPlatforms.push('email');
85
+
86
+ // Share Content
87
+ const shareTitle = props.shareTitle ?? 'Check this out!';
88
+ const shareText = props.shareText ?? 'I found this amazing app!';
89
+ const shareUrl = props.shareUrl ?? '';
90
+
91
+ // Layout
92
+ const layout = props.layout ?? 'horizontal';
93
+ const buttonGap = props.buttonGap ?? 8;
94
+ const alignment = props.alignment ?? 'center';
95
+
96
+ // Button Styling - children arrive fully styled
97
+ const componentAppearance = (component as any).appearance || {};
98
+ const buttonStyle = props.buttonStyle ?? 'icon-only';
99
+ const buttonSize = props.buttonSize ?? 44;
100
+ const buttonBorderRadius = componentAppearance.cornerRadius ?? props.buttonBorderRadius ?? 8;
101
+ const useBrandColors = props.useBrandColors !== false;
102
+
103
+ // Custom colors from component appearance
104
+ const customButtonBackground = getColorFromFill(componentAppearance.fill, '#E5E7EB');
105
+ const customIconColor = '#FFFFFF';
106
+
107
+ // Labels
108
+ const copiedLabel = props.copiedLabel ?? 'Copied!';
109
+
110
+ const [copiedState, setCopiedState] = useState(false);
111
+
112
+ // Handle share for each platform
113
+ const handleShare = useCallback(async (platform: string) => {
114
+ const fullContent = shareUrl ? `${shareText} ${shareUrl}` : shareText;
115
+
116
+ switch (platform) {
117
+ case 'native':
118
+ try {
119
+ await Share.share({
120
+ message: fullContent,
121
+ title: shareTitle,
122
+ });
123
+ } catch (err) {
124
+ console.error('Share failed:', err);
125
+ }
126
+ break;
127
+
128
+ case 'copy':
129
+ try {
130
+ Clipboard.setString(shareUrl || shareText);
131
+ setCopiedState(true);
132
+ setTimeout(() => setCopiedState(false), 2000);
133
+ } catch (err) {
134
+ console.error('Copy failed:', err);
135
+ }
136
+ break;
137
+
138
+ case 'twitter':
139
+ Linking.openURL(
140
+ `https://twitter.com/intent/tweet?text=${encodeURIComponent(shareText)}&url=${encodeURIComponent(shareUrl)}`
141
+ );
142
+ break;
143
+
144
+ case 'facebook':
145
+ Linking.openURL(
146
+ `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(shareUrl)}&quote=${encodeURIComponent(shareText)}`
147
+ );
148
+ break;
149
+
150
+ case 'linkedin':
151
+ Linking.openURL(
152
+ `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(shareUrl)}`
153
+ );
154
+ break;
155
+
156
+ case 'whatsapp':
157
+ Linking.openURL(
158
+ `whatsapp://send?text=${encodeURIComponent(fullContent)}`
159
+ );
160
+ break;
161
+
162
+ case 'telegram':
163
+ Linking.openURL(
164
+ `tg://msg?text=${encodeURIComponent(fullContent)}`
165
+ );
166
+ break;
167
+
168
+ case 'email':
169
+ Linking.openURL(
170
+ `mailto:?subject=${encodeURIComponent(shareTitle)}&body=${encodeURIComponent(fullContent)}`
171
+ );
172
+ break;
173
+ }
174
+
175
+ // Track share event
176
+ if (stateManager) {
177
+ stateManager.updateState(`element:${componentId}.lastShared`, platform);
178
+ }
179
+ }, [shareTitle, shareText, shareUrl, componentId, stateManager]);
180
+
181
+ const getLabel = (platform: string): string => {
182
+ if (platform === 'copy') return copiedState ? copiedLabel : PLATFORM_CONFIG[platform]?.label || platform;
183
+ return PLATFORM_CONFIG[platform]?.label || platform;
184
+ };
185
+
186
+ // HYBRID MODE: Render children if available and renderChild is provided
187
+ if (visibleChildren.length > 0 && renderChild) {
188
+ return (
189
+ <View
190
+ style={[
191
+ styles.container,
192
+ {
193
+ flexDirection: layout === 'vertical' ? 'column' : 'row',
194
+ gap: buttonGap,
195
+ justifyContent: alignment === 'start' ? 'flex-start' : alignment === 'end' ? 'flex-end' : 'center',
196
+ },
197
+ ]}
198
+ >
199
+ {visibleChildren.map((child: PaywallComponent, index: number) => {
200
+ const platform = (child.role || '').replace('share-button-', '');
201
+ return (
202
+ <TouchableOpacity
203
+ key={child.id}
204
+ onPress={() => handleShare(platform)}
205
+ activeOpacity={0.7}
206
+ >
207
+ {renderChild(child, index)}
208
+ </TouchableOpacity>
209
+ );
210
+ })}
211
+ </View>
212
+ );
213
+ }
214
+
215
+ // Show message if no platforms enabled
216
+ if (enabledPlatforms.length === 0) {
217
+ return (
218
+ <View style={styles.emptyContainer}>
219
+ <Text style={styles.emptyText}>Enable at least one share platform</Text>
220
+ </View>
221
+ );
222
+ }
223
+
224
+ // LEGACY MODE: Self-render buttons
225
+ return (
226
+ <View
227
+ style={[
228
+ styles.container,
229
+ {
230
+ flexDirection: layout === 'vertical' ? 'column' : 'row',
231
+ gap: buttonGap,
232
+ justifyContent: alignment === 'start' ? 'flex-start' : alignment === 'end' ? 'flex-end' : 'center',
233
+ },
234
+ ]}
235
+ >
236
+ {enabledPlatforms.map((platform) => {
237
+ const config = PLATFORM_CONFIG[platform];
238
+ if (!config) return null;
239
+
240
+ const bgColor = useBrandColors ? config.color : customButtonBackground;
241
+ const textColor = useBrandColors ? '#FFFFFF' : customIconColor;
242
+
243
+ return (
244
+ <TouchableOpacity
245
+ key={platform}
246
+ onPress={() => handleShare(platform)}
247
+ activeOpacity={0.7}
248
+ style={[
249
+ styles.button,
250
+ {
251
+ width: buttonStyle === 'text-only' ? undefined : buttonSize,
252
+ height: buttonSize,
253
+ borderRadius: buttonBorderRadius,
254
+ backgroundColor: bgColor,
255
+ paddingHorizontal: buttonStyle === 'text-only' ? 16 : 0,
256
+ },
257
+ ]}
258
+ >
259
+ {buttonStyle !== 'text-only' && (
260
+ <Text style={{ fontSize: buttonSize * 0.45 }}>
261
+ {platform === 'copy' && copiedState ? '✓' : config.icon}
262
+ </Text>
263
+ )}
264
+ {buttonStyle !== 'icon-only' && (
265
+ <Text style={[styles.buttonText, { color: textColor }]}>
266
+ {getLabel(platform)}
267
+ </Text>
268
+ )}
269
+ </TouchableOpacity>
270
+ );
271
+ })}
272
+ </View>
273
+ );
274
+ };
275
+
276
+ const styles = StyleSheet.create({
277
+ container: {
278
+ flexWrap: 'wrap',
279
+ alignItems: 'center',
280
+ },
281
+ emptyContainer: {
282
+ padding: 16,
283
+ alignItems: 'center',
284
+ },
285
+ emptyText: {
286
+ fontSize: 14,
287
+ color: '#6B7280',
288
+ },
289
+ button: {
290
+ flexDirection: 'row',
291
+ alignItems: 'center',
292
+ justifyContent: 'center',
293
+ gap: 6,
294
+ },
295
+ buttonText: {
296
+ fontSize: 13,
297
+ fontWeight: '500',
298
+ },
299
+ });
@@ -0,0 +1,303 @@
1
+ /**
2
+ * ShareCodeComponent - React Native
3
+ *
4
+ * Hybrid component with child-based architecture.
5
+ * Uses component.properties for styling; children arrive fully styled with selectedAppearance.
6
+ */
7
+
8
+ import React, { useState, useEffect, useCallback } from 'react';
9
+ import {
10
+ View,
11
+ Text,
12
+ TouchableOpacity,
13
+ StyleSheet,
14
+ Share,
15
+ Clipboard,
16
+ Animated,
17
+ } from 'react-native';
18
+ import { PaywallComponent } from '../types';
19
+
20
+ interface ShareCodeComponentProps {
21
+ component: PaywallComponent;
22
+ stateManager?: any;
23
+ isPreviewMode?: boolean;
24
+ renderChild?: (child: PaywallComponent, index: number) => React.ReactNode;
25
+ }
26
+
27
+ // Helper to extract color from fill value
28
+ const getColorFromFill = (fill: any, fallback: string): string => {
29
+ if (!fill) return fallback;
30
+ if (typeof fill === 'string') return fill;
31
+ if (fill.type === 'color' && fill.color) return fill.color;
32
+ if (fill.resolvedColor) return fill.resolvedColor;
33
+ return fallback;
34
+ };
35
+
36
+ export const ShareCodeComponent: React.FC<ShareCodeComponentProps> = ({
37
+ component,
38
+ stateManager,
39
+ isPreviewMode = false,
40
+ renderChild,
41
+ }) => {
42
+ const props = component.properties as any;
43
+ // Children arrive fully styled with selectedAppearance for state changes
44
+ const children = component.children || [];
45
+ const componentId = component.id;
46
+
47
+ // Properties from schema
48
+ const code = props.code ?? 'SAVE20';
49
+ const codeLabel = props.codeLabel ?? '';
50
+ const codeDescription = props.codeDescription ?? '';
51
+ const showCopyButton = props.showCopyButton !== false;
52
+ const showShareButton = props.showShareButton ?? false;
53
+ const showQRCode = props.showQRCode ?? false;
54
+ const layout = props.layout ?? 'vertical';
55
+ const copyButtonText = props.copyButtonText ?? 'Copy Code';
56
+ const copiedFeedback = props.copiedFeedback ?? 'Copied!';
57
+ const shareButtonText = props.shareButtonText ?? 'Share';
58
+ const shareMessage = (props.shareMessage ?? 'Use my code: {{code}} to get a discount!').replace('{{code}}', code);
59
+ const shareUrl = props.shareUrl ?? '';
60
+
61
+ // Styling from component appearance (children arrive fully styled)
62
+ const componentAppearance = (component as any).appearance || {};
63
+ const codeContainerFill = getColorFromFill(componentAppearance.fill, '#F3F4F6');
64
+ const buttonFill = '#3B82F6'; // Default, buttons have their own styling
65
+ const codeTextColor = props.codeTextColor ?? '#1F2937';
66
+ const labelColor = props.labelColor ?? '#6B7280';
67
+ const descriptionColor = props.descriptionColor ?? '#6B7280';
68
+ const buttonTextColor = '#FFFFFF';
69
+ const codeFontSize = props.codeFontSize ?? 24;
70
+ const containerBorderRadius = componentAppearance.cornerRadius ?? 12;
71
+ const containerPadding = props.containerPadding ?? 16;
72
+
73
+ const [copied, setCopied] = useState(false);
74
+ const [copyAnim] = useState(new Animated.Value(1));
75
+
76
+ // Connect to state manager
77
+ useEffect(() => {
78
+ if (stateManager) {
79
+ stateManager.updateState(`element:${componentId}.code`, code);
80
+ stateManager.updateState(`element:${componentId}.copied`, copied);
81
+ }
82
+ }, [code, copied, componentId, stateManager]);
83
+
84
+ // Copy to clipboard
85
+ const handleCopy = useCallback(async () => {
86
+ try {
87
+ Clipboard.setString(code);
88
+ setCopied(true);
89
+
90
+ Animated.sequence([
91
+ Animated.timing(copyAnim, {
92
+ toValue: 0.9,
93
+ duration: 100,
94
+ useNativeDriver: true,
95
+ }),
96
+ Animated.timing(copyAnim, {
97
+ toValue: 1,
98
+ duration: 100,
99
+ useNativeDriver: true,
100
+ }),
101
+ ]).start();
102
+
103
+ if (stateManager) {
104
+ stateManager.updateState(`element:${componentId}.copied`, true);
105
+ }
106
+
107
+ setTimeout(() => {
108
+ setCopied(false);
109
+ if (stateManager) {
110
+ stateManager.updateState(`element:${componentId}.copied`, false);
111
+ }
112
+ }, 2000);
113
+ } catch (err) {
114
+ console.error('Failed to copy:', err);
115
+ }
116
+ }, [code, copyAnim, componentId, stateManager]);
117
+
118
+ // Share functionality
119
+ const handleShare = useCallback(async () => {
120
+ try {
121
+ await Share.share({
122
+ message: shareUrl ? `${shareMessage} ${shareUrl}` : shareMessage,
123
+ title: codeLabel || 'Share Code',
124
+ });
125
+
126
+ if (stateManager) {
127
+ stateManager.updateState(`element:${componentId}.shared`, true);
128
+ }
129
+ } catch (err) {
130
+ console.error('Share failed:', err);
131
+ }
132
+ }, [shareMessage, shareUrl, codeLabel, componentId, stateManager]);
133
+
134
+ const isHorizontal = layout === 'horizontal';
135
+
136
+ // Helper to get visible children
137
+ const visibleChildren = children.filter(
138
+ (child: PaywallComponent) => child.visible !== false
139
+ );
140
+
141
+ // Hybrid mode: render children from Layers panel
142
+ if (visibleChildren.length > 0 && renderChild) {
143
+ return (
144
+ <View
145
+ style={[
146
+ styles.container,
147
+ { flexDirection: isHorizontal ? 'row' : 'column' },
148
+ ]}
149
+ >
150
+ {visibleChildren.map((child: PaywallComponent, index: number) => (
151
+ <React.Fragment key={child.id}>
152
+ {renderChild(child, index)}
153
+ </React.Fragment>
154
+ ))}
155
+ </View>
156
+ );
157
+ }
158
+
159
+ // Legacy mode: self-contained rendering
160
+ return (
161
+ <View
162
+ style={[
163
+ styles.container,
164
+ { flexDirection: isHorizontal ? 'row' : 'column' },
165
+ ]}
166
+ >
167
+ <View
168
+ style={[
169
+ styles.mainContent,
170
+ { alignItems: isHorizontal ? 'flex-start' : 'center' },
171
+ ]}
172
+ >
173
+ {/* Label */}
174
+ {codeLabel ? (
175
+ <Text style={[styles.label, { fontSize: 14, color: labelColor }]}>
176
+ {codeLabel}
177
+ </Text>
178
+ ) : null}
179
+
180
+ {/* Code Display */}
181
+ <View
182
+ style={[
183
+ styles.codeContainer,
184
+ {
185
+ backgroundColor: codeContainerFill,
186
+ borderRadius: containerBorderRadius,
187
+ paddingHorizontal: containerPadding,
188
+ paddingVertical: containerPadding * 0.75,
189
+ },
190
+ ]}
191
+ >
192
+ <Text
193
+ style={[
194
+ styles.codeText,
195
+ {
196
+ fontSize: codeFontSize,
197
+ fontWeight: '700',
198
+ color: codeTextColor,
199
+ },
200
+ ]}
201
+ >
202
+ {code}
203
+ </Text>
204
+
205
+ {showCopyButton && (
206
+ <TouchableOpacity onPress={handleCopy} activeOpacity={0.7}>
207
+ <Animated.View
208
+ style={[
209
+ styles.copyButton,
210
+ {
211
+ backgroundColor: buttonFill,
212
+ borderRadius: 8,
213
+ transform: [{ scale: copyAnim }],
214
+ },
215
+ ]}
216
+ >
217
+ <Text style={[styles.buttonText, { color: copied ? '#22C55E' : buttonTextColor }]}>
218
+ {copied ? copiedFeedback : copyButtonText}
219
+ </Text>
220
+ </Animated.View>
221
+ </TouchableOpacity>
222
+ )}
223
+ </View>
224
+
225
+ {/* Description */}
226
+ {codeDescription ? (
227
+ <Text
228
+ style={[
229
+ styles.description,
230
+ {
231
+ fontSize: 12,
232
+ color: descriptionColor,
233
+ textAlign: isHorizontal ? 'left' : 'center',
234
+ },
235
+ ]}
236
+ >
237
+ {codeDescription}
238
+ </Text>
239
+ ) : null}
240
+
241
+ {/* Share Button */}
242
+ {showShareButton && (
243
+ <TouchableOpacity
244
+ onPress={handleShare}
245
+ style={[
246
+ styles.shareButton,
247
+ {
248
+ backgroundColor: buttonFill,
249
+ borderRadius: 8,
250
+ width: isHorizontal ? 'auto' : '100%',
251
+ },
252
+ ]}
253
+ activeOpacity={0.7}
254
+ >
255
+ <Text style={[styles.buttonText, { color: buttonTextColor }]}>
256
+ 📤 {shareButtonText}
257
+ </Text>
258
+ </TouchableOpacity>
259
+ )}
260
+ </View>
261
+ </View>
262
+ );
263
+ };
264
+
265
+ const styles = StyleSheet.create({
266
+ container: {
267
+ width: '100%',
268
+ gap: 12,
269
+ },
270
+ mainContent: {
271
+ flex: 1,
272
+ gap: 12,
273
+ },
274
+ label: {},
275
+ codeContainer: {
276
+ flexDirection: 'row',
277
+ alignItems: 'center',
278
+ justifyContent: 'center',
279
+ gap: 12,
280
+ width: '100%',
281
+ },
282
+ codeText: {
283
+ fontFamily: 'monospace',
284
+ letterSpacing: 2,
285
+ },
286
+ copyButton: {
287
+ paddingHorizontal: 12,
288
+ paddingVertical: 8,
289
+ },
290
+ buttonText: {
291
+ fontSize: 14,
292
+ fontWeight: '500',
293
+ },
294
+ description: {},
295
+ shareButton: {
296
+ flexDirection: 'row',
297
+ alignItems: 'center',
298
+ justifyContent: 'center',
299
+ gap: 6,
300
+ paddingVertical: 12,
301
+ paddingHorizontal: 16,
302
+ },
303
+ });