@umituz/react-native-subscription 2.12.2 → 2.12.3

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 (46) hide show
  1. package/package.json +1 -1
  2. package/src/domains/index.ts +5 -0
  3. package/src/domains/paywall/components/CreditCard.tsx +117 -0
  4. package/src/domains/paywall/components/FeatureItem.tsx +50 -0
  5. package/src/domains/paywall/components/FeatureList.tsx +34 -0
  6. package/src/domains/paywall/components/PaywallFooter.tsx +98 -0
  7. package/src/{presentation/components/paywall/PaywallHeroHeader.tsx → domains/paywall/components/PaywallHeader.tsx} +15 -44
  8. package/src/domains/paywall/components/PaywallModal.tsx +187 -0
  9. package/src/domains/paywall/components/PaywallTabBar.tsx +102 -0
  10. package/src/domains/paywall/components/PlanCard.tsx +124 -0
  11. package/src/domains/paywall/components/index.ts +14 -0
  12. package/src/domains/paywall/entities/index.ts +5 -0
  13. package/src/domains/paywall/entities/types.ts +48 -0
  14. package/src/domains/paywall/hooks/index.ts +6 -0
  15. package/src/{presentation → domains/paywall}/hooks/usePaywall.ts +1 -1
  16. package/src/domains/paywall/index.ts +13 -0
  17. package/src/index.ts +15 -22
  18. package/src/domain/entities/paywall/CreditsPackage.ts +0 -16
  19. package/src/domain/entities/paywall/PaywallMode.ts +0 -6
  20. package/src/domain/entities/paywall/PaywallTab.ts +0 -11
  21. package/src/domain/entities/paywall/SubscriptionPlan.ts +0 -27
  22. package/src/presentation/components/paywall/BestValueBadge.tsx +0 -59
  23. package/src/presentation/components/paywall/CreditsPackageCard.tsx +0 -161
  24. package/src/presentation/components/paywall/CreditsTabContent.tsx +0 -123
  25. package/src/presentation/components/paywall/PaywallFeatureItem.tsx +0 -79
  26. package/src/presentation/components/paywall/PaywallFeaturesList.tsx +0 -47
  27. package/src/presentation/components/paywall/PaywallHeader.tsx +0 -82
  28. package/src/presentation/components/paywall/PaywallLegalFooter.tsx +0 -145
  29. package/src/presentation/components/paywall/PaywallLegalFooterStyles.ts +0 -53
  30. package/src/presentation/components/paywall/PaywallLegalFooterTypes.ts +0 -19
  31. package/src/presentation/components/paywall/PaywallModal.tsx +0 -162
  32. package/src/presentation/components/paywall/PaywallTabBar.tsx +0 -120
  33. package/src/presentation/components/paywall/SubscriptionFooter.tsx +0 -116
  34. package/src/presentation/components/paywall/SubscriptionModal.tsx +0 -168
  35. package/src/presentation/components/paywall/SubscriptionModalHeader.tsx +0 -78
  36. package/src/presentation/components/paywall/SubscriptionPackageList.tsx +0 -171
  37. package/src/presentation/components/paywall/SubscriptionPlanCard.tsx +0 -213
  38. package/src/presentation/components/paywall/SubscriptionPlanCardStyles.ts +0 -61
  39. package/src/presentation/components/paywall/SubscriptionPlanCardTypes.ts +0 -15
  40. package/src/presentation/components/paywall/SubscriptionTabContent.tsx +0 -139
  41. package/src/presentation/components/paywall/accordion/AccordionPlanCard.tsx +0 -98
  42. package/src/presentation/components/paywall/accordion/AccordionPlanCardTypes.ts +0 -39
  43. package/src/presentation/components/paywall/accordion/PlanCardDetails.tsx +0 -107
  44. package/src/presentation/components/paywall/accordion/PlanCardHeader.tsx +0 -155
  45. package/src/presentation/components/paywall/accordion/index.ts +0 -12
  46. /package/src/{presentation → domains/paywall}/hooks/useSubscriptionModal.ts +0 -0
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Paywall Tab Bar
3
+ * Segmented control for hybrid mode
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, TouchableOpacity, StyleSheet, Animated } from "react-native";
8
+ import { AtomicText, useAppDesignTokens } from "@umituz/react-native-design-system";
9
+ import type { PaywallTabType } from "../entities";
10
+
11
+ interface PaywallTabBarProps {
12
+ activeTab: PaywallTabType;
13
+ onTabChange: (tab: PaywallTabType) => void;
14
+ creditsLabel: string;
15
+ subscriptionLabel: string;
16
+ }
17
+
18
+ export const PaywallTabBar: React.FC<PaywallTabBarProps> = React.memo(
19
+ ({ activeTab, onTabChange, creditsLabel, subscriptionLabel }) => {
20
+ const tokens = useAppDesignTokens();
21
+ const animatedValue = React.useRef(
22
+ new Animated.Value(activeTab === "credits" ? 0 : 1)
23
+ ).current;
24
+
25
+ React.useEffect(() => {
26
+ Animated.spring(animatedValue, {
27
+ toValue: activeTab === "credits" ? 0 : 1,
28
+ useNativeDriver: false,
29
+ tension: 68,
30
+ friction: 12,
31
+ }).start();
32
+ }, [activeTab, animatedValue]);
33
+
34
+ const renderTab = (tab: PaywallTabType, label: string) => {
35
+ const isActive = activeTab === tab;
36
+
37
+ return (
38
+ <TouchableOpacity
39
+ key={tab}
40
+ style={styles.tab}
41
+ onPress={() => onTabChange(tab)}
42
+ activeOpacity={0.7}
43
+ >
44
+ <AtomicText
45
+ type="labelLarge"
46
+ style={[
47
+ styles.tabText,
48
+ { color: isActive ? tokens.colors.primary : tokens.colors.textSecondary },
49
+ ]}
50
+ >
51
+ {label}
52
+ </AtomicText>
53
+ </TouchableOpacity>
54
+ );
55
+ };
56
+
57
+ const indicatorLeft = animatedValue.interpolate({
58
+ inputRange: [0, 1],
59
+ outputRange: ["2%", "50%"],
60
+ });
61
+
62
+ return (
63
+ <View style={[styles.container, { backgroundColor: tokens.colors.surfaceSecondary }]}>
64
+ <Animated.View
65
+ style={[styles.indicator, { backgroundColor: tokens.colors.surface, left: indicatorLeft }]}
66
+ />
67
+ {renderTab("credits", creditsLabel)}
68
+ {renderTab("subscription", subscriptionLabel)}
69
+ </View>
70
+ );
71
+ }
72
+ );
73
+
74
+ PaywallTabBar.displayName = "PaywallTabBar";
75
+
76
+ const styles = StyleSheet.create({
77
+ container: {
78
+ flexDirection: "row",
79
+ borderRadius: 12,
80
+ padding: 4,
81
+ marginHorizontal: 24,
82
+ marginBottom: 16,
83
+ position: "relative",
84
+ height: 44,
85
+ },
86
+ indicator: {
87
+ position: "absolute",
88
+ top: 4,
89
+ bottom: 4,
90
+ width: "46%",
91
+ borderRadius: 8,
92
+ },
93
+ tab: {
94
+ flex: 1,
95
+ alignItems: "center",
96
+ justifyContent: "center",
97
+ zIndex: 1,
98
+ },
99
+ tabText: {
100
+ fontWeight: "600",
101
+ },
102
+ });
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Plan Card
3
+ * Subscription plan selection card
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, TouchableOpacity, StyleSheet } from "react-native";
8
+ import { AtomicText, AtomicIcon, AtomicBadge, useAppDesignTokens } from "@umituz/react-native-design-system";
9
+ import type { PurchasesPackage } from "react-native-purchases";
10
+
11
+ interface PlanCardProps {
12
+ pkg: PurchasesPackage;
13
+ isSelected: boolean;
14
+ onSelect: () => void;
15
+ badge?: string;
16
+ creditAmount?: number;
17
+ creditsLabel?: string;
18
+ }
19
+
20
+ export const PlanCard: React.FC<PlanCardProps> = React.memo(
21
+ ({ pkg, isSelected, onSelect, badge, creditAmount, creditsLabel }) => {
22
+ const tokens = useAppDesignTokens();
23
+ const title = pkg.product.title;
24
+ const price = `${pkg.product.currencyCode} ${pkg.product.price.toFixed(2)}`;
25
+
26
+ return (
27
+ <TouchableOpacity onPress={onSelect} activeOpacity={0.7} style={styles.touchable}>
28
+ <View
29
+ style={[
30
+ styles.container,
31
+ {
32
+ backgroundColor: tokens.colors.surface,
33
+ borderColor: isSelected ? tokens.colors.primary : tokens.colors.border,
34
+ borderWidth: isSelected ? 2 : 1,
35
+ },
36
+ ]}
37
+ >
38
+ {badge && (
39
+ <View style={styles.badgeContainer}>
40
+ <AtomicBadge text={badge} variant="primary" size="sm" />
41
+ </View>
42
+ )}
43
+
44
+ <View style={styles.content}>
45
+ <View style={styles.leftSection}>
46
+ <View
47
+ style={[
48
+ styles.radio,
49
+ {
50
+ borderColor: isSelected ? tokens.colors.primary : tokens.colors.border,
51
+ backgroundColor: isSelected ? tokens.colors.primary : "transparent",
52
+ },
53
+ ]}
54
+ >
55
+ {isSelected && (
56
+ <AtomicIcon name="checkmark" customSize={12} customColor={tokens.colors.onPrimary} />
57
+ )}
58
+ </View>
59
+
60
+ <View style={styles.textSection}>
61
+ <AtomicText type="titleSmall" style={{ color: tokens.colors.textPrimary, fontWeight: "600" }}>
62
+ {title}
63
+ </AtomicText>
64
+ {creditAmount && creditsLabel && (
65
+ <AtomicText type="bodySmall" style={{ color: tokens.colors.textSecondary }}>
66
+ {creditAmount} {creditsLabel}
67
+ </AtomicText>
68
+ )}
69
+ </View>
70
+ </View>
71
+
72
+ <AtomicText
73
+ type="titleMedium"
74
+ style={{ color: isSelected ? tokens.colors.primary : tokens.colors.textPrimary, fontWeight: "700" }}
75
+ >
76
+ {price}
77
+ </AtomicText>
78
+ </View>
79
+ </View>
80
+ </TouchableOpacity>
81
+ );
82
+ }
83
+ );
84
+
85
+ PlanCard.displayName = "PlanCard";
86
+
87
+ const styles = StyleSheet.create({
88
+ touchable: {
89
+ marginBottom: 10,
90
+ marginHorizontal: 24,
91
+ },
92
+ container: {
93
+ borderRadius: 16,
94
+ padding: 16,
95
+ position: "relative",
96
+ },
97
+ badgeContainer: {
98
+ position: "absolute",
99
+ top: -10,
100
+ right: 16,
101
+ },
102
+ content: {
103
+ flexDirection: "row",
104
+ alignItems: "center",
105
+ justifyContent: "space-between",
106
+ },
107
+ leftSection: {
108
+ flexDirection: "row",
109
+ alignItems: "center",
110
+ flex: 1,
111
+ },
112
+ radio: {
113
+ width: 22,
114
+ height: 22,
115
+ borderRadius: 11,
116
+ borderWidth: 2,
117
+ alignItems: "center",
118
+ justifyContent: "center",
119
+ marginRight: 12,
120
+ },
121
+ textSection: {
122
+ flex: 1,
123
+ },
124
+ });
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Paywall Components Index
3
+ */
4
+
5
+ export { PaywallModal } from "./PaywallModal";
6
+ export type { PaywallModalProps } from "./PaywallModal";
7
+
8
+ export { PaywallHeader } from "./PaywallHeader";
9
+ export { PaywallTabBar } from "./PaywallTabBar";
10
+ export { PaywallFooter } from "./PaywallFooter";
11
+ export { FeatureList } from "./FeatureList";
12
+ export { FeatureItem } from "./FeatureItem";
13
+ export { PlanCard } from "./PlanCard";
14
+ export { CreditCard } from "./CreditCard";
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Paywall Entities Index
3
+ */
4
+
5
+ export * from "./types";
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Paywall Types
3
+ * All paywall-related type definitions
4
+ */
5
+
6
+ export type PaywallMode = "subscription" | "credits" | "hybrid";
7
+
8
+ export type PaywallTabType = "credits" | "subscription";
9
+
10
+ export interface PaywallTab {
11
+ id: PaywallTabType;
12
+ label: string;
13
+ }
14
+
15
+ export interface CreditsPackage {
16
+ id: string;
17
+ credits: number;
18
+ price: number;
19
+ currency: string;
20
+ bonus?: number;
21
+ badge?: string;
22
+ description?: string;
23
+ }
24
+
25
+ export interface SubscriptionFeature {
26
+ icon: string;
27
+ text: string;
28
+ }
29
+
30
+ export interface PaywallTranslations {
31
+ title: string;
32
+ subtitle?: string;
33
+ creditsTabLabel?: string;
34
+ subscriptionTabLabel?: string;
35
+ purchaseButtonText: string;
36
+ subscribeButtonText?: string;
37
+ restoreButtonText: string;
38
+ loadingText: string;
39
+ emptyText: string;
40
+ processingText: string;
41
+ privacyText?: string;
42
+ termsOfServiceText?: string;
43
+ }
44
+
45
+ export interface PaywallLegalUrls {
46
+ privacyUrl?: string;
47
+ termsUrl?: string;
48
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Paywall Hooks Index
3
+ */
4
+
5
+ export { usePaywall } from "./usePaywall";
6
+ export { useSubscriptionModal } from "./useSubscriptionModal";
@@ -1,6 +1,6 @@
1
1
  import { useState, useCallback } from "react";
2
2
  import type { PurchasesPackage } from "react-native-purchases";
3
- import type { PaywallTabType } from "../../domain/entities/paywall/PaywallTab";
3
+ import type { PaywallTabType } from "../entities";
4
4
 
5
5
  interface UsePaywallProps {
6
6
  initialTab?: PaywallTabType;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Paywall Domain
3
+ * Complete paywall solution for subscription and credits
4
+ */
5
+
6
+ // Entities
7
+ export * from "./entities";
8
+
9
+ // Components
10
+ export * from "./components";
11
+
12
+ // Hooks
13
+ export * from "./hooks";
package/src/index.ts CHANGED
@@ -60,35 +60,28 @@ export {
60
60
  } from "./presentation/hooks/useUserTierWithRepository";
61
61
 
62
62
  // =============================================================================
63
- // PRESENTATION LAYER - Paywall Components
63
+ // PAYWALL DOMAIN
64
64
  // =============================================================================
65
65
 
66
- export {
67
- SubscriptionModal,
68
- type SubscriptionModalProps,
69
- } from "./presentation/components/paywall/SubscriptionModal";
70
-
71
- export { SubscriptionModalHeader } from "./presentation/components/paywall/SubscriptionModalHeader";
72
-
73
- export { SubscriptionPlanCard } from "./presentation/components/paywall/SubscriptionPlanCard";
74
- export {
75
- AccordionPlanCard,
76
- PlanCardHeader,
77
- PlanCardDetails,
78
- type AccordionPlanCardProps,
79
- type PlanCardHeaderProps,
80
- type PlanCardDetailsProps,
81
- } from "./presentation/components/paywall/accordion";
82
- export { PaywallFeaturesList } from "./presentation/components/paywall/PaywallFeaturesList";
83
- export { PaywallFeatureItem } from "./presentation/components/paywall/PaywallFeatureItem";
84
- export { PaywallLegalFooter } from "./presentation/components/paywall/PaywallLegalFooter";
85
66
  export {
86
67
  PaywallModal,
87
68
  type PaywallModalProps,
69
+ PaywallHeader,
70
+ PaywallTabBar,
71
+ PaywallFooter,
72
+ FeatureList,
73
+ FeatureItem,
74
+ PlanCard,
75
+ CreditCard,
76
+ usePaywall,
77
+ useSubscriptionModal,
78
+ type PaywallMode,
79
+ type PaywallTabType,
80
+ type CreditsPackage,
81
+ type SubscriptionFeature,
88
82
  type PaywallTranslations,
89
83
  type PaywallLegalUrls,
90
- } from "./presentation/components/paywall/PaywallModal";
91
- export type { PaywallMode } from "./domain/entities/paywall/PaywallMode";
84
+ } from "./domains/paywall";
92
85
 
93
86
  // =============================================================================
94
87
  // PRESENTATION LAYER - Premium Details Components
@@ -1,16 +0,0 @@
1
- /**
2
- * Credits Package Entity
3
- * Represents a credit package for purchase
4
- */
5
-
6
- export interface CreditsPackage {
7
- id: string;
8
- credits: number;
9
- price: number;
10
- priceString?: string;
11
- currency: string;
12
- bonus?: number;
13
- popular?: boolean;
14
- badge?: string;
15
- description?: string;
16
- }
@@ -1,6 +0,0 @@
1
- /**
2
- * Paywall Mode Entity
3
- * Defines paywall display modes
4
- */
5
-
6
- export type PaywallMode = "subscription" | "credits" | "hybrid";
@@ -1,11 +0,0 @@
1
- /**
2
- * Paywall Tab Entity
3
- * Represents paywall tab types
4
- */
5
-
6
- export type PaywallTabType = "credits" | "subscription";
7
-
8
- export interface PaywallTab {
9
- id: PaywallTabType;
10
- label: string;
11
- }
@@ -1,27 +0,0 @@
1
- /**
2
- * Subscription Plan Entity
3
- * Represents a subscription plan for purchase
4
- */
5
-
6
- export interface SubscriptionPlan {
7
- /** Plan ID */
8
- id: string;
9
-
10
- /** Plan type */
11
- type: "monthly" | "yearly";
12
-
13
- /** Price */
14
- price: number;
15
-
16
- /** Currency code */
17
- currency: string;
18
-
19
- /** Whether this is the best value option */
20
- isBestValue?: boolean;
21
-
22
- /** Optional discount percentage */
23
- discountPercentage?: number;
24
-
25
- /** Optional features list */
26
- features?: string[];
27
- }
@@ -1,59 +0,0 @@
1
- import React, { useMemo } from "react";
2
- import { View, StyleSheet } from "react-native";
3
- import { AtomicText, useAppDesignTokens, useResponsive } from "@umituz/react-native-design-system";
4
- import { LinearGradient } from "expo-linear-gradient";
5
-
6
- interface BestValueBadgeProps {
7
- text: string;
8
- visible?: boolean;
9
- }
10
-
11
- export const BestValueBadge: React.FC<BestValueBadgeProps> = React.memo(
12
- ({ text, visible = true }) => {
13
- const tokens = useAppDesignTokens();
14
- const { spacingMultiplier, getFontSize } = useResponsive();
15
-
16
- const styles = useMemo(() => createStyles(spacingMultiplier), [spacingMultiplier]);
17
- const fontSize = getFontSize(10);
18
-
19
- if (!visible) return null;
20
-
21
- return (
22
- <View style={styles.badgeContainer}>
23
- <LinearGradient
24
- colors={[tokens.colors.secondary, tokens.colors.primary]}
25
- start={{ x: 0, y: 0 }}
26
- end={{ x: 1, y: 1 }}
27
- style={styles.badge}
28
- >
29
- <AtomicText
30
- type="labelSmall"
31
- style={{ color: tokens.colors.onPrimary, fontWeight: "800", textTransform: "uppercase", fontSize }}
32
- >
33
- {text}
34
- </AtomicText>
35
- </LinearGradient>
36
- </View>
37
- );
38
- }
39
- );
40
-
41
- BestValueBadge.displayName = "BestValueBadge";
42
-
43
- const createStyles = (spacingMult: number) =>
44
- StyleSheet.create({
45
- badgeContainer: {
46
- position: "absolute",
47
- top: -12 * spacingMult,
48
- right: 16 * spacingMult,
49
- zIndex: 1,
50
- alignSelf: "flex-end",
51
- },
52
- badge: {
53
- paddingHorizontal: 16 * spacingMult,
54
- paddingVertical: 6 * spacingMult,
55
- borderRadius: 16 * spacingMult,
56
- alignItems: "center",
57
- justifyContent: "center",
58
- },
59
- });
@@ -1,161 +0,0 @@
1
- /**
2
- * Credits Package Card Component
3
- * Selectable card for credit packages
4
- */
5
-
6
- import React from "react";
7
- import { View, StyleSheet, TouchableOpacity } from "react-native";
8
- import {
9
- AtomicText,
10
- AtomicIcon,
11
- AtomicBadge,
12
- useAppDesignTokens,
13
- } from "@umituz/react-native-design-system";
14
- import type { CreditsPackage } from "../../../domain/entities/paywall/CreditsPackage";
15
-
16
- interface CreditsPackageCardProps {
17
- package: CreditsPackage;
18
- isSelected: boolean;
19
- onSelect: () => void;
20
- }
21
-
22
- export const CreditsPackageCard: React.FC<CreditsPackageCardProps> = React.memo(
23
- ({ package: pkg, isSelected, onSelect }) => {
24
- const tokens = useAppDesignTokens();
25
- const totalCredits = pkg.credits + (pkg.bonus || 0);
26
-
27
- return (
28
- <TouchableOpacity
29
- onPress={onSelect}
30
- activeOpacity={0.7}
31
- style={styles.touchable}
32
- >
33
- <View
34
- style={[
35
- styles.container,
36
- {
37
- backgroundColor: tokens.colors.surface,
38
- borderColor: isSelected ? tokens.colors.primary : tokens.colors.border,
39
- borderWidth: isSelected ? 2 : 1,
40
- },
41
- ]}
42
- >
43
- {pkg.badge && (
44
- <View style={styles.badgeContainer}>
45
- <AtomicBadge text={pkg.badge} variant="warning" size="sm" />
46
- </View>
47
- )}
48
-
49
- <View style={styles.content}>
50
- <View style={styles.leftSection}>
51
- <View style={styles.creditsRow}>
52
- <AtomicIcon
53
- name="flash"
54
- size="md"
55
- color={isSelected ? "primary" : "secondary"}
56
- />
57
- <AtomicText
58
- type="headlineSmall"
59
- style={[
60
- styles.credits,
61
- { color: isSelected ? tokens.colors.primary : tokens.colors.textPrimary },
62
- ]}
63
- >
64
- {totalCredits.toLocaleString()}
65
- </AtomicText>
66
- </View>
67
-
68
- {(pkg.bonus ?? 0) > 0 && (
69
- <View style={styles.bonusContainer}>
70
- <AtomicIcon name="gift-outline" size="sm" color="success" />
71
- <AtomicText
72
- type="bodySmall"
73
- style={[styles.bonus, { color: tokens.colors.success }]}
74
- >
75
- +{pkg.bonus}
76
- </AtomicText>
77
- </View>
78
- )}
79
-
80
- {pkg.description && (
81
- <AtomicText
82
- type="bodySmall"
83
- style={{ color: tokens.colors.textSecondary }}
84
- >
85
- {pkg.description}
86
- </AtomicText>
87
- )}
88
- </View>
89
-
90
- <View style={styles.rightSection}>
91
- <AtomicText
92
- type="titleLarge"
93
- style={[
94
- styles.price,
95
- { color: isSelected ? tokens.colors.primary : tokens.colors.textPrimary },
96
- ]}
97
- >
98
- {pkg.currency}{pkg.price.toFixed(2)}
99
- </AtomicText>
100
- {isSelected && (
101
- <AtomicIcon name="checkmark-circle" size="md" color="primary" />
102
- )}
103
- </View>
104
- </View>
105
- </View>
106
- </TouchableOpacity>
107
- );
108
- }
109
- );
110
-
111
- CreditsPackageCard.displayName = "CreditsPackageCard";
112
-
113
- const styles = StyleSheet.create({
114
- touchable: {
115
- marginBottom: 12,
116
- },
117
- container: {
118
- borderRadius: 16,
119
- padding: 16,
120
- position: "relative",
121
- },
122
- badgeContainer: {
123
- position: "absolute",
124
- top: -10,
125
- right: 16,
126
- },
127
- content: {
128
- flexDirection: "row",
129
- justifyContent: "space-between",
130
- alignItems: "center",
131
- },
132
- leftSection: {
133
- flex: 1,
134
- marginRight: 16,
135
- },
136
- creditsRow: {
137
- flexDirection: "row",
138
- alignItems: "center",
139
- marginBottom: 4,
140
- },
141
- credits: {
142
- fontWeight: "700",
143
- marginLeft: 8,
144
- },
145
- bonusContainer: {
146
- flexDirection: "row",
147
- alignItems: "center",
148
- marginBottom: 4,
149
- },
150
- bonus: {
151
- fontWeight: "600",
152
- marginLeft: 4,
153
- },
154
- rightSection: {
155
- alignItems: "flex-end",
156
- },
157
- price: {
158
- fontWeight: "700",
159
- marginBottom: 4,
160
- },
161
- });