@oxyhq/services 5.3.11 → 5.4.1
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.
- package/README.md +21 -0
- package/lib/commonjs/assets/assets/icons/OxyServices.tsx +67 -0
- package/lib/commonjs/assets/assets/icons/logo_OxyServices.svg +1 -0
- package/lib/commonjs/assets/icons/OxyServices.js +53 -0
- package/lib/commonjs/assets/icons/OxyServices.js.map +1 -0
- package/lib/commonjs/assets/icons/logo_OxyServices.svg +1 -0
- package/lib/commonjs/core/index.js +119 -23
- package/lib/commonjs/core/index.js.map +1 -1
- package/lib/commonjs/index.js +2 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/lib/sonner.js +15 -11
- package/lib/commonjs/lib/sonner.js.map +1 -1
- package/lib/commonjs/node/index.js +2 -0
- package/lib/commonjs/node/index.js.map +1 -1
- package/lib/commonjs/ui/components/GroupedItem.js +109 -0
- package/lib/commonjs/ui/components/GroupedItem.js.map +1 -0
- package/lib/commonjs/ui/components/GroupedSection.js +33 -0
- package/lib/commonjs/ui/components/GroupedSection.js.map +1 -0
- package/lib/commonjs/ui/components/OxyProvider.js +95 -112
- package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
- package/lib/commonjs/ui/components/ProfileCard.js +124 -0
- package/lib/commonjs/ui/components/ProfileCard.js.map +1 -0
- package/lib/commonjs/ui/components/QuickActions.js +87 -0
- package/lib/commonjs/ui/components/QuickActions.js.map +1 -0
- package/lib/commonjs/ui/components/Section.js +36 -0
- package/lib/commonjs/ui/components/Section.js.map +1 -0
- package/lib/commonjs/ui/components/SectionTitle.js +35 -0
- package/lib/commonjs/ui/components/SectionTitle.js.map +1 -0
- package/lib/commonjs/ui/components/bottomSheet/index.js +6 -6
- package/lib/commonjs/ui/components/index.js +97 -0
- package/lib/commonjs/ui/components/index.js.map +1 -0
- package/lib/commonjs/ui/navigation/OxyRouter.js +20 -3
- package/lib/commonjs/ui/navigation/OxyRouter.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountCenterScreen.js +190 -207
- package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountManagementDemo.js +299 -0
- package/lib/commonjs/ui/screens/AccountManagementDemo.js.map +1 -0
- package/lib/commonjs/ui/screens/AccountOverviewScreen.js +669 -401
- package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js +695 -498
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +451 -488
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AppInfoScreen.js +498 -185
- package/lib/commonjs/ui/screens/AppInfoScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/BillingManagementScreen.js +636 -0
- package/lib/commonjs/ui/screens/BillingManagementScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/FileManagementScreen.js +2497 -0
- package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js +1620 -0
- package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/ProfileScreen.js +117 -13
- package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SignInScreen.js +1 -1
- package/lib/commonjs/ui/screens/SignUpScreen.js +1 -1
- package/lib/commonjs/utils/polyfills.js +42 -0
- package/lib/commonjs/utils/polyfills.js.map +1 -0
- package/lib/module/assets/assets/icons/OxyServices.tsx +67 -0
- package/lib/module/assets/assets/icons/logo_OxyServices.svg +1 -0
- package/lib/module/assets/icons/OxyServices.js +46 -0
- package/lib/module/assets/icons/OxyServices.js.map +1 -0
- package/lib/module/assets/icons/logo_OxyServices.svg +1 -0
- package/lib/module/core/index.js +119 -23
- package/lib/module/core/index.js.map +1 -1
- package/lib/module/index.js +3 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/lib/sonner.js +13 -1
- package/lib/module/lib/sonner.js.map +1 -1
- package/lib/module/node/index.js +3 -0
- package/lib/module/node/index.js.map +1 -1
- package/lib/module/ui/components/GroupedItem.js +104 -0
- package/lib/module/ui/components/GroupedItem.js.map +1 -0
- package/lib/module/ui/components/GroupedSection.js +28 -0
- package/lib/module/ui/components/GroupedSection.js.map +1 -0
- package/lib/module/ui/components/OxyProvider.js +97 -114
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/components/ProfileCard.js +119 -0
- package/lib/module/ui/components/ProfileCard.js.map +1 -0
- package/lib/module/ui/components/QuickActions.js +82 -0
- package/lib/module/ui/components/QuickActions.js.map +1 -0
- package/lib/module/ui/components/Section.js +31 -0
- package/lib/module/ui/components/Section.js.map +1 -0
- package/lib/module/ui/components/SectionTitle.js +30 -0
- package/lib/module/ui/components/SectionTitle.js.map +1 -0
- package/lib/module/ui/components/bottomSheet/index.js +2 -5
- package/lib/module/ui/components/bottomSheet/index.js.map +1 -1
- package/lib/module/ui/components/index.js +18 -0
- package/lib/module/ui/components/index.js.map +1 -0
- package/lib/module/ui/navigation/OxyRouter.js +20 -3
- package/lib/module/ui/navigation/OxyRouter.js.map +1 -1
- package/lib/module/ui/screens/AccountCenterScreen.js +191 -208
- package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountManagementDemo.js +296 -0
- package/lib/module/ui/screens/AccountManagementDemo.js.map +1 -0
- package/lib/module/ui/screens/AccountOverviewScreen.js +671 -403
- package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountSettingsScreen.js +698 -501
- package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountSwitcherScreen.js +450 -488
- package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/module/ui/screens/AppInfoScreen.js +498 -186
- package/lib/module/ui/screens/AppInfoScreen.js.map +1 -1
- package/lib/module/ui/screens/BillingManagementScreen.js +631 -0
- package/lib/module/ui/screens/BillingManagementScreen.js.map +1 -0
- package/lib/module/ui/screens/FileManagementScreen.js +2492 -0
- package/lib/module/ui/screens/FileManagementScreen.js.map +1 -0
- package/lib/module/ui/screens/PremiumSubscriptionScreen.js +1615 -0
- package/lib/module/ui/screens/PremiumSubscriptionScreen.js.map +1 -0
- package/lib/module/ui/screens/ProfileScreen.js +118 -14
- package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
- package/lib/module/ui/screens/SignInScreen.js +1 -1
- package/lib/module/ui/screens/SignInScreen.js.map +1 -1
- package/lib/module/ui/screens/SignUpScreen.js +1 -1
- package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
- package/lib/module/utils/polyfills.js +36 -0
- package/lib/module/utils/polyfills.js.map +1 -0
- package/lib/typescript/assets/icons/OxyServices.d.ts +29 -0
- package/lib/typescript/assets/icons/OxyServices.d.ts.map +1 -0
- package/lib/typescript/core/index.d.ts +26 -1
- package/lib/typescript/core/index.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/lib/sonner.d.ts +5 -1
- package/lib/typescript/lib/sonner.d.ts.map +1 -1
- package/lib/typescript/models/interfaces.d.ts +1 -2
- package/lib/typescript/models/interfaces.d.ts.map +1 -1
- package/lib/typescript/node/index.d.ts +1 -0
- package/lib/typescript/node/index.d.ts.map +1 -1
- package/lib/typescript/ui/components/GroupedItem.d.ts +17 -0
- package/lib/typescript/ui/components/GroupedItem.d.ts.map +1 -0
- package/lib/typescript/ui/components/GroupedSection.d.ts +19 -0
- package/lib/typescript/ui/components/GroupedSection.d.ts.map +1 -0
- package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/ui/components/ProfileCard.d.ts +20 -0
- package/lib/typescript/ui/components/ProfileCard.d.ts.map +1 -0
- package/lib/typescript/ui/components/QuickActions.d.ts +15 -0
- package/lib/typescript/ui/components/QuickActions.d.ts.map +1 -0
- package/lib/typescript/ui/components/Section.d.ts +11 -0
- package/lib/typescript/ui/components/Section.d.ts.map +1 -0
- package/lib/typescript/ui/components/SectionTitle.d.ts +9 -0
- package/lib/typescript/ui/components/SectionTitle.d.ts.map +1 -0
- package/lib/typescript/ui/components/bottomSheet/index.d.ts +3 -2
- package/lib/typescript/ui/components/bottomSheet/index.d.ts.map +1 -1
- package/lib/typescript/ui/components/index.d.ts +13 -0
- package/lib/typescript/ui/components/index.d.ts.map +1 -0
- package/lib/typescript/ui/navigation/OxyRouter.d.ts.map +1 -1
- package/lib/typescript/ui/navigation/types.d.ts +8 -0
- package/lib/typescript/ui/navigation/types.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountCenterScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountManagementDemo.d.ts +8 -0
- package/lib/typescript/ui/screens/AccountManagementDemo.d.ts.map +1 -0
- package/lib/typescript/ui/screens/AccountOverviewScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts +1 -4
- package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AppInfoScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/BillingManagementScreen.d.ts +5 -0
- package/lib/typescript/ui/screens/BillingManagementScreen.d.ts.map +1 -0
- package/lib/typescript/ui/screens/FileManagementScreen.d.ts +8 -0
- package/lib/typescript/ui/screens/FileManagementScreen.d.ts.map +1 -0
- package/lib/typescript/ui/screens/PremiumSubscriptionScreen.d.ts +5 -0
- package/lib/typescript/ui/screens/PremiumSubscriptionScreen.d.ts.map +1 -0
- package/lib/typescript/ui/screens/ProfileScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SessionManagementScreen.d.ts.map +1 -1
- package/lib/typescript/utils/polyfills.d.ts +6 -0
- package/lib/typescript/utils/polyfills.d.ts.map +1 -0
- package/package.json +11 -3
- package/src/__tests__/polyfills.test.ts +30 -0
- package/src/__tests__/setup.ts +43 -0
- package/src/__tests__/ui/screens/AccountSettingsScreen.test.tsx +8 -8
- package/src/assets/icons/OxyServices.tsx +67 -0
- package/src/assets/icons/logo_OxyServices.svg +1 -0
- package/src/core/index.ts +127 -19
- package/src/index.ts +3 -0
- package/src/lib/sonner.ts +10 -1
- package/src/models/interfaces.ts +1 -2
- package/src/node/index.ts +3 -0
- package/src/ui/components/GroupedItem.tsx +118 -0
- package/src/ui/components/GroupedSection.tsx +45 -0
- package/src/ui/components/OxyProvider.tsx +95 -120
- package/src/ui/components/ProfileCard.tsx +129 -0
- package/src/ui/components/QuickActions.tsx +90 -0
- package/src/ui/components/Section.tsx +37 -0
- package/src/ui/components/SectionTitle.tsx +31 -0
- package/src/ui/components/bottomSheet/index.tsx +13 -11
- package/src/ui/components/index.ts +15 -0
- package/src/ui/navigation/OxyRouter.tsx +20 -3
- package/src/ui/navigation/types.ts +10 -1
- package/src/ui/screens/AccountCenterScreen.tsx +188 -159
- package/src/ui/screens/AccountManagementDemo.tsx +297 -0
- package/src/ui/screens/AccountOverviewScreen.tsx +474 -310
- package/src/ui/screens/AccountSettingsScreen.tsx +648 -463
- package/src/ui/screens/AccountSwitcherScreen.tsx +385 -449
- package/src/ui/screens/AppInfoScreen.tsx +571 -140
- package/src/ui/screens/BillingManagementScreen.tsx +589 -0
- package/src/ui/screens/FileManagementScreen.tsx +2513 -0
- package/src/ui/screens/PremiumSubscriptionScreen.tsx +1628 -0
- package/src/ui/screens/ProfileScreen.tsx +101 -7
- package/src/ui/screens/SessionManagementScreen.tsx +1 -0
- package/src/ui/screens/SignInScreen.tsx +1 -1
- package/src/ui/screens/SignUpScreen.tsx +1 -1
- package/src/utils/polyfills.ts +34 -0
- package/lib/commonjs/lib/sonner.web.js +0 -17
- package/lib/commonjs/lib/sonner.web.js.map +0 -1
- package/lib/module/lib/sonner.web.js +0 -4
- package/lib/module/lib/sonner.web.js.map +0 -1
- package/lib/typescript/__tests__/ui/screens/AccountSettingsScreen.test.d.ts +0 -2
- package/lib/typescript/__tests__/ui/screens/AccountSettingsScreen.test.d.ts.map +0 -1
- package/lib/typescript/lib/sonner.web.d.ts +0 -2
- package/lib/typescript/lib/sonner.web.d.ts.map +0 -1
- package/src/lib/sonner.web.ts +0 -1
|
@@ -0,0 +1,1628 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
Text,
|
|
5
|
+
TouchableOpacity,
|
|
6
|
+
StyleSheet,
|
|
7
|
+
ScrollView,
|
|
8
|
+
ActivityIndicator,
|
|
9
|
+
Alert,
|
|
10
|
+
Platform,
|
|
11
|
+
Animated,
|
|
12
|
+
Dimensions,
|
|
13
|
+
} from 'react-native';
|
|
14
|
+
import { BaseScreenProps } from '../navigation/types';
|
|
15
|
+
import { useOxy } from '../context/OxyContext';
|
|
16
|
+
import { fontFamilies } from '../styles/fonts';
|
|
17
|
+
import { toast } from '../../lib/sonner';
|
|
18
|
+
import { Ionicons } from '@expo/vector-icons';
|
|
19
|
+
import Avatar from '../components/Avatar';
|
|
20
|
+
|
|
21
|
+
interface SubscriptionPlan {
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
description: string;
|
|
25
|
+
price: number;
|
|
26
|
+
currency: string;
|
|
27
|
+
interval: 'month' | 'year';
|
|
28
|
+
features: string[];
|
|
29
|
+
appScope: 'ecosystem' | 'specific';
|
|
30
|
+
applicableApps: string[]; // ['mention', 'oxy-social', 'oxy-workspace', 'oxy-creator'] etc.
|
|
31
|
+
includedFeatures: string[]; // Feature IDs that are included in this plan
|
|
32
|
+
isPopular?: boolean;
|
|
33
|
+
isCurrentPlan?: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface IndividualFeature {
|
|
37
|
+
id: string;
|
|
38
|
+
name: string;
|
|
39
|
+
description: string;
|
|
40
|
+
price: number;
|
|
41
|
+
currency: string;
|
|
42
|
+
interval: 'month' | 'year';
|
|
43
|
+
category: 'analytics' | 'customization' | 'content' | 'networking' | 'productivity';
|
|
44
|
+
appScope: 'ecosystem' | 'specific';
|
|
45
|
+
applicableApps: string[]; // Apps where this feature is available
|
|
46
|
+
canBePurchasedSeparately: boolean;
|
|
47
|
+
includedInPlans: string[]; // Plan IDs that include this feature
|
|
48
|
+
isSubscribed?: boolean;
|
|
49
|
+
isIncludedInCurrentPlan?: boolean;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface UserSubscription {
|
|
53
|
+
id: string;
|
|
54
|
+
planId: string;
|
|
55
|
+
status: 'active' | 'canceled' | 'past_due' | 'trialing';
|
|
56
|
+
currentPeriodStart: string;
|
|
57
|
+
currentPeriodEnd: string;
|
|
58
|
+
cancelAtPeriodEnd: boolean;
|
|
59
|
+
trialEnd?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const PremiumSubscriptionScreen: React.FC<BaseScreenProps> = ({
|
|
63
|
+
onClose,
|
|
64
|
+
theme,
|
|
65
|
+
navigate,
|
|
66
|
+
goBack,
|
|
67
|
+
}) => {
|
|
68
|
+
const { user, oxyServices } = useOxy();
|
|
69
|
+
const [loading, setLoading] = useState(true);
|
|
70
|
+
const [subscription, setSubscription] = useState<UserSubscription | null>(null);
|
|
71
|
+
const [plans, setPlans] = useState<SubscriptionPlan[]>([]);
|
|
72
|
+
const [individualFeatures, setIndividualFeatures] = useState<IndividualFeature[]>([]);
|
|
73
|
+
const [selectedPlan, setSelectedPlan] = useState<string | null>(null);
|
|
74
|
+
const [processingPayment, setProcessingPayment] = useState(false);
|
|
75
|
+
const [billingInterval, setBillingInterval] = useState<'month' | 'year'>('month');
|
|
76
|
+
const [activeTab, setActiveTab] = useState<'plans' | 'features'>('plans');
|
|
77
|
+
const [currentAppPackage, setCurrentAppPackage] = useState<string>('mention'); // Default to mention for demo
|
|
78
|
+
|
|
79
|
+
const isDarkTheme = theme === 'dark';
|
|
80
|
+
const textColor = isDarkTheme ? '#FFFFFF' : '#000000';
|
|
81
|
+
const backgroundColor = isDarkTheme ? '#121212' : '#FFFFFF';
|
|
82
|
+
const secondaryBackgroundColor = isDarkTheme ? '#222222' : '#F5F5F5';
|
|
83
|
+
const borderColor = isDarkTheme ? '#444444' : '#E0E0E0';
|
|
84
|
+
const primaryColor = '#007AFF';
|
|
85
|
+
const successColor = '#30D158';
|
|
86
|
+
const warningColor = '#FF9500';
|
|
87
|
+
const dangerColor = '#FF3B30';
|
|
88
|
+
|
|
89
|
+
// Oxy+ subscription plans
|
|
90
|
+
const mockPlans: SubscriptionPlan[] = [
|
|
91
|
+
{
|
|
92
|
+
id: 'mention-plus',
|
|
93
|
+
name: 'Mention+',
|
|
94
|
+
description: 'Enhanced features for better social experience',
|
|
95
|
+
price: 4.99,
|
|
96
|
+
currency: 'USD',
|
|
97
|
+
interval: 'month',
|
|
98
|
+
appScope: 'specific',
|
|
99
|
+
applicableApps: ['mention'], // Only available in mention app
|
|
100
|
+
features: [
|
|
101
|
+
'Undo posts option',
|
|
102
|
+
'Improved reading mode',
|
|
103
|
+
'Organize bookmarks into folders',
|
|
104
|
+
'Early access to select features',
|
|
105
|
+
'Edit posts capability',
|
|
106
|
+
'Enhanced customization options'
|
|
107
|
+
],
|
|
108
|
+
includedFeatures: ['reading-mode-plus', 'custom-themes']
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: 'oxy-insider',
|
|
112
|
+
name: 'Oxy+ Insider',
|
|
113
|
+
description: 'Exclusive access to behind-the-scenes content',
|
|
114
|
+
price: 9.99,
|
|
115
|
+
currency: 'USD',
|
|
116
|
+
interval: 'month',
|
|
117
|
+
appScope: 'ecosystem',
|
|
118
|
+
applicableApps: ['mention', 'oxy-social', 'oxy-workspace', 'oxy-creator'],
|
|
119
|
+
features: [
|
|
120
|
+
'Everything in Mention+',
|
|
121
|
+
'Behind-the-scenes updates from creators',
|
|
122
|
+
'Early access to new features',
|
|
123
|
+
'Dedicated support team',
|
|
124
|
+
'Exclusive content access',
|
|
125
|
+
'Beta feature testing'
|
|
126
|
+
],
|
|
127
|
+
includedFeatures: ['reading-mode-plus', 'custom-themes', 'analytics-basic'],
|
|
128
|
+
isPopular: true
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
id: 'oxy-connect',
|
|
132
|
+
name: 'Oxy+ Connect',
|
|
133
|
+
description: 'Advanced networking and community features',
|
|
134
|
+
price: 14.99,
|
|
135
|
+
currency: 'USD',
|
|
136
|
+
interval: 'month',
|
|
137
|
+
appScope: 'ecosystem',
|
|
138
|
+
applicableApps: ['mention', 'oxy-social', 'oxy-workspace', 'oxy-creator'],
|
|
139
|
+
features: [
|
|
140
|
+
'Everything in Oxy+ Insider',
|
|
141
|
+
'Create and join private groups',
|
|
142
|
+
'Advanced search and filtering tools',
|
|
143
|
+
'Customizable profile highlighting',
|
|
144
|
+
'Enhanced connection features',
|
|
145
|
+
'Priority in community events'
|
|
146
|
+
],
|
|
147
|
+
includedFeatures: ['reading-mode-plus', 'custom-themes', 'analytics-basic', 'group-management']
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
id: 'oxy-premium',
|
|
151
|
+
name: 'Oxy+ Premium',
|
|
152
|
+
description: 'Complete premium experience with all perks',
|
|
153
|
+
price: 24.99,
|
|
154
|
+
currency: 'USD',
|
|
155
|
+
interval: 'month',
|
|
156
|
+
appScope: 'ecosystem',
|
|
157
|
+
applicableApps: ['mention', 'oxy-social', 'oxy-workspace', 'oxy-creator', 'oxy-analytics'],
|
|
158
|
+
features: [
|
|
159
|
+
'Everything in Oxy+ Connect',
|
|
160
|
+
'Priority customer support',
|
|
161
|
+
'Access to premium content and events',
|
|
162
|
+
'Advanced analytics dashboard',
|
|
163
|
+
'VIP community status',
|
|
164
|
+
'Exclusive premium events'
|
|
165
|
+
],
|
|
166
|
+
includedFeatures: ['reading-mode-plus', 'custom-themes', 'analytics-basic', 'analytics-advanced', 'group-management']
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
id: 'oxy-creator',
|
|
170
|
+
name: 'Oxy+ Creator',
|
|
171
|
+
description: 'Professional tools for content creators',
|
|
172
|
+
price: 39.99,
|
|
173
|
+
currency: 'USD',
|
|
174
|
+
interval: 'month',
|
|
175
|
+
appScope: 'ecosystem',
|
|
176
|
+
applicableApps: ['mention', 'oxy-social', 'oxy-workspace', 'oxy-creator', 'oxy-analytics', 'oxy-studio'],
|
|
177
|
+
features: [
|
|
178
|
+
'Everything in Oxy+ Premium',
|
|
179
|
+
'Advanced analytics and insights',
|
|
180
|
+
'Promotional tools and resources',
|
|
181
|
+
'Content monetization features',
|
|
182
|
+
'Creator support program',
|
|
183
|
+
'Revenue sharing opportunities'
|
|
184
|
+
],
|
|
185
|
+
includedFeatures: ['reading-mode-plus', 'custom-themes', 'analytics-basic', 'analytics-advanced', 'group-management', 'creator-tools', 'monetization-features']
|
|
186
|
+
}
|
|
187
|
+
];
|
|
188
|
+
|
|
189
|
+
// Individual feature subscriptions
|
|
190
|
+
const mockIndividualFeatures: IndividualFeature[] = [
|
|
191
|
+
{
|
|
192
|
+
id: 'analytics-basic',
|
|
193
|
+
name: 'Basic Analytics',
|
|
194
|
+
description: 'View post performance and engagement metrics',
|
|
195
|
+
price: 2.99,
|
|
196
|
+
currency: 'USD',
|
|
197
|
+
interval: 'month',
|
|
198
|
+
category: 'analytics',
|
|
199
|
+
appScope: 'ecosystem',
|
|
200
|
+
applicableApps: ['mention', 'oxy-social', 'oxy-workspace'],
|
|
201
|
+
canBePurchasedSeparately: true,
|
|
202
|
+
includedInPlans: ['oxy-insider', 'oxy-connect', 'oxy-premium', 'oxy-creator']
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
id: 'analytics-advanced',
|
|
206
|
+
name: 'Advanced Analytics',
|
|
207
|
+
description: 'Detailed insights, trends, and audience demographics',
|
|
208
|
+
price: 7.99,
|
|
209
|
+
currency: 'USD',
|
|
210
|
+
interval: 'month',
|
|
211
|
+
category: 'analytics',
|
|
212
|
+
appScope: 'ecosystem',
|
|
213
|
+
applicableApps: ['mention', 'oxy-social', 'oxy-workspace', 'oxy-creator', 'oxy-analytics'],
|
|
214
|
+
canBePurchasedSeparately: true,
|
|
215
|
+
includedInPlans: ['oxy-premium', 'oxy-creator']
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
id: 'custom-themes',
|
|
219
|
+
name: 'Custom Themes',
|
|
220
|
+
description: 'Personalize your app with custom colors and layouts',
|
|
221
|
+
price: 1.99,
|
|
222
|
+
currency: 'USD',
|
|
223
|
+
interval: 'month',
|
|
224
|
+
category: 'customization',
|
|
225
|
+
appScope: 'ecosystem',
|
|
226
|
+
applicableApps: ['mention', 'oxy-social', 'oxy-workspace', 'oxy-creator'],
|
|
227
|
+
canBePurchasedSeparately: false, // Included in all plans
|
|
228
|
+
includedInPlans: ['mention-plus', 'oxy-insider', 'oxy-connect', 'oxy-premium', 'oxy-creator']
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
id: 'reading-mode-plus',
|
|
232
|
+
name: 'Reading Mode Plus',
|
|
233
|
+
description: 'Enhanced reading experience with focus modes',
|
|
234
|
+
price: 1.99,
|
|
235
|
+
currency: 'USD',
|
|
236
|
+
interval: 'month',
|
|
237
|
+
category: 'content',
|
|
238
|
+
appScope: 'specific',
|
|
239
|
+
applicableApps: ['mention', 'oxy-social'],
|
|
240
|
+
canBePurchasedSeparately: false, // Included in all plans
|
|
241
|
+
includedInPlans: ['mention-plus', 'oxy-insider', 'oxy-connect', 'oxy-premium', 'oxy-creator']
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
id: 'group-management',
|
|
245
|
+
name: 'Group Management',
|
|
246
|
+
description: 'Create and manage private groups and communities',
|
|
247
|
+
price: 4.99,
|
|
248
|
+
currency: 'USD',
|
|
249
|
+
interval: 'month',
|
|
250
|
+
category: 'networking',
|
|
251
|
+
appScope: 'ecosystem',
|
|
252
|
+
applicableApps: ['mention', 'oxy-social', 'oxy-workspace'],
|
|
253
|
+
canBePurchasedSeparately: true,
|
|
254
|
+
includedInPlans: ['oxy-connect', 'oxy-premium', 'oxy-creator']
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
id: 'creator-tools',
|
|
258
|
+
name: 'Creator Tools Suite',
|
|
259
|
+
description: 'Professional content creation and editing tools',
|
|
260
|
+
price: 9.99,
|
|
261
|
+
currency: 'USD',
|
|
262
|
+
interval: 'month',
|
|
263
|
+
category: 'productivity',
|
|
264
|
+
appScope: 'specific',
|
|
265
|
+
applicableApps: ['oxy-creator', 'oxy-studio'],
|
|
266
|
+
canBePurchasedSeparately: true,
|
|
267
|
+
includedInPlans: ['oxy-creator']
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
id: 'monetization-features',
|
|
271
|
+
name: 'Monetization Features',
|
|
272
|
+
description: 'Revenue sharing, sponsorship tools, and creator fund access',
|
|
273
|
+
price: 12.99,
|
|
274
|
+
currency: 'USD',
|
|
275
|
+
interval: 'month',
|
|
276
|
+
category: 'productivity',
|
|
277
|
+
appScope: 'specific',
|
|
278
|
+
applicableApps: ['oxy-creator'],
|
|
279
|
+
canBePurchasedSeparately: true,
|
|
280
|
+
includedInPlans: ['oxy-creator']
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
id: 'workspace-collaboration',
|
|
284
|
+
name: 'Workspace Collaboration',
|
|
285
|
+
description: 'Advanced team features and project management tools',
|
|
286
|
+
price: 6.99,
|
|
287
|
+
currency: 'USD',
|
|
288
|
+
interval: 'month',
|
|
289
|
+
category: 'productivity',
|
|
290
|
+
appScope: 'specific',
|
|
291
|
+
applicableApps: ['oxy-workspace'],
|
|
292
|
+
canBePurchasedSeparately: true,
|
|
293
|
+
includedInPlans: ['oxy-premium', 'oxy-creator']
|
|
294
|
+
}
|
|
295
|
+
];
|
|
296
|
+
|
|
297
|
+
useEffect(() => {
|
|
298
|
+
detectCurrentApp();
|
|
299
|
+
}, []);
|
|
300
|
+
|
|
301
|
+
useEffect(() => {
|
|
302
|
+
if (currentAppPackage) {
|
|
303
|
+
loadSubscriptionData();
|
|
304
|
+
}
|
|
305
|
+
}, [currentAppPackage, user?.isPremium]);
|
|
306
|
+
|
|
307
|
+
const detectCurrentApp = () => {
|
|
308
|
+
// In a real implementation, this would detect the actual app package name
|
|
309
|
+
// For now, we'll use a mock detection based on available methods
|
|
310
|
+
|
|
311
|
+
// Real app detection methods you could use:
|
|
312
|
+
// 1. Check bundle identifier in React Native:
|
|
313
|
+
// import DeviceInfo from 'react-native-device-info';
|
|
314
|
+
// const bundleId = DeviceInfo.getBundleId();
|
|
315
|
+
// Example: com.oxy.mention -> 'mention'
|
|
316
|
+
|
|
317
|
+
// 2. Environment variables or build configuration
|
|
318
|
+
// const appPackage = __DEV__ ? process.env.APP_PACKAGE : 'mention';
|
|
319
|
+
|
|
320
|
+
// 3. Check specific app capabilities or modules
|
|
321
|
+
// if (typeof MentionModule !== 'undefined') return 'mention';
|
|
322
|
+
// if (typeof OxyWorkspaceModule !== 'undefined') return 'oxy-workspace';
|
|
323
|
+
|
|
324
|
+
// 4. Use build-time configuration with Metro or similar
|
|
325
|
+
// const appPackage = require('../config/app.json').packageName;
|
|
326
|
+
|
|
327
|
+
// For demo purposes, we'll simulate different apps
|
|
328
|
+
// You would replace this with actual app detection logic
|
|
329
|
+
|
|
330
|
+
// IMPORTANT: This ensures subscription restrictions work properly:
|
|
331
|
+
// - Mention+ plan can only be subscribed to when app package == 'mention'
|
|
332
|
+
// - Other app-specific plans follow the same pattern
|
|
333
|
+
// - Ecosystem plans work across all apps
|
|
334
|
+
|
|
335
|
+
const detectedApp = 'mention'; // This would be dynamic in real implementation
|
|
336
|
+
|
|
337
|
+
setCurrentAppPackage(detectedApp);
|
|
338
|
+
|
|
339
|
+
// Log for debugging
|
|
340
|
+
console.log('Detected app package:', detectedApp);
|
|
341
|
+
console.log('Available plans for this app will be filtered accordingly');
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
const loadSubscriptionData = async () => {
|
|
345
|
+
try {
|
|
346
|
+
setLoading(true);
|
|
347
|
+
|
|
348
|
+
// Filter plans available for current app
|
|
349
|
+
const availablePlans = mockPlans.filter(plan =>
|
|
350
|
+
plan.applicableApps.includes(currentAppPackage)
|
|
351
|
+
);
|
|
352
|
+
setPlans(availablePlans);
|
|
353
|
+
|
|
354
|
+
// Mock current subscription
|
|
355
|
+
let currentSubscription: UserSubscription | null = null;
|
|
356
|
+
if (user?.isPremium) {
|
|
357
|
+
currentSubscription = {
|
|
358
|
+
id: 'sub_12345',
|
|
359
|
+
planId: 'oxy-insider',
|
|
360
|
+
status: 'active',
|
|
361
|
+
currentPeriodStart: new Date().toISOString(),
|
|
362
|
+
currentPeriodEnd: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(),
|
|
363
|
+
cancelAtPeriodEnd: false
|
|
364
|
+
};
|
|
365
|
+
setSubscription(currentSubscription);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Filter features available for current app and update based on current subscription
|
|
369
|
+
const availableFeatures = mockIndividualFeatures.filter(feature =>
|
|
370
|
+
feature.applicableApps.includes(currentAppPackage)
|
|
371
|
+
);
|
|
372
|
+
|
|
373
|
+
const updatedFeatures = availableFeatures.map(feature => {
|
|
374
|
+
const isIncludedInCurrentPlan = !!(currentSubscription &&
|
|
375
|
+
feature.includedInPlans.includes(currentSubscription.planId));
|
|
376
|
+
|
|
377
|
+
return {
|
|
378
|
+
...feature,
|
|
379
|
+
isIncludedInCurrentPlan,
|
|
380
|
+
isSubscribed: isIncludedInCurrentPlan ? true : false // Mock some individual subscriptions
|
|
381
|
+
};
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
setIndividualFeatures(updatedFeatures);
|
|
385
|
+
|
|
386
|
+
} catch (error) {
|
|
387
|
+
console.error('Failed to load subscription data:', error);
|
|
388
|
+
toast.error('Failed to load subscription information');
|
|
389
|
+
} finally {
|
|
390
|
+
setLoading(false);
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
const handlePlanSelection = (planId: string) => {
|
|
395
|
+
setSelectedPlan(planId);
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
const handleSubscribe = async (planId: string) => {
|
|
399
|
+
try {
|
|
400
|
+
// Check if plan is available for current app
|
|
401
|
+
const selectedPlan = mockPlans.find(plan => plan.id === planId);
|
|
402
|
+
if (!selectedPlan?.applicableApps.includes(currentAppPackage)) {
|
|
403
|
+
console.log(`❌ Subscription blocked: Plan "${selectedPlan?.name}" not available for app "${currentAppPackage}"`);
|
|
404
|
+
toast.error(`This plan is not available for the current app (${currentAppPackage})`);
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Special restriction for Mention+ plan - only available in mention app
|
|
409
|
+
if (planId === 'mention-plus' && currentAppPackage !== 'mention') {
|
|
410
|
+
console.log(`❌ Subscription blocked: Mention+ plan requires app to be "mention", current app is "${currentAppPackage}"`);
|
|
411
|
+
toast.error('Mention+ is only available in the Mention app');
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
console.log(`✅ Subscription allowed: Plan "${selectedPlan.name}" is available for app "${currentAppPackage}"`);
|
|
416
|
+
|
|
417
|
+
setProcessingPayment(true);
|
|
418
|
+
|
|
419
|
+
// Mock payment processing
|
|
420
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
421
|
+
|
|
422
|
+
toast.success('Subscription activated successfully!');
|
|
423
|
+
|
|
424
|
+
// Mock subscription update
|
|
425
|
+
setSubscription({
|
|
426
|
+
id: 'sub_' + Date.now(),
|
|
427
|
+
planId,
|
|
428
|
+
status: 'active',
|
|
429
|
+
currentPeriodStart: new Date().toISOString(),
|
|
430
|
+
currentPeriodEnd: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(),
|
|
431
|
+
cancelAtPeriodEnd: false
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
// Reload data to update feature states
|
|
435
|
+
loadSubscriptionData();
|
|
436
|
+
|
|
437
|
+
} catch (error) {
|
|
438
|
+
console.error('Payment failed:', error);
|
|
439
|
+
toast.error('Payment failed. Please try again.');
|
|
440
|
+
} finally {
|
|
441
|
+
setProcessingPayment(false);
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
const handleCancelSubscription = () => {
|
|
446
|
+
Alert.alert(
|
|
447
|
+
'Cancel Subscription',
|
|
448
|
+
'Are you sure you want to cancel your subscription? You will lose access to premium features at the end of your current billing period.',
|
|
449
|
+
[
|
|
450
|
+
{ text: 'Keep Subscription', style: 'cancel' },
|
|
451
|
+
{
|
|
452
|
+
text: 'Cancel Subscription',
|
|
453
|
+
style: 'destructive',
|
|
454
|
+
onPress: async () => {
|
|
455
|
+
try {
|
|
456
|
+
// Mock cancellation
|
|
457
|
+
setSubscription(prev => prev ? {
|
|
458
|
+
...prev,
|
|
459
|
+
cancelAtPeriodEnd: true
|
|
460
|
+
} : null);
|
|
461
|
+
toast.success('Subscription will be canceled at the end of the billing period');
|
|
462
|
+
} catch (error) {
|
|
463
|
+
toast.error('Failed to cancel subscription');
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
]
|
|
468
|
+
);
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
const handleReactivateSubscription = async () => {
|
|
472
|
+
try {
|
|
473
|
+
setSubscription(prev => prev ? {
|
|
474
|
+
...prev,
|
|
475
|
+
cancelAtPeriodEnd: false
|
|
476
|
+
} : null);
|
|
477
|
+
toast.success('Subscription reactivated successfully');
|
|
478
|
+
} catch (error) {
|
|
479
|
+
toast.error('Failed to reactivate subscription');
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
const formatPrice = (price: number, currency: string, interval: string) => {
|
|
484
|
+
const yearlyPrice = interval === 'year' ? price : price * 12 * 0.8; // 20% discount for yearly
|
|
485
|
+
const displayPrice = billingInterval === 'year' ? yearlyPrice : price;
|
|
486
|
+
|
|
487
|
+
return {
|
|
488
|
+
price: displayPrice,
|
|
489
|
+
formatted: `$${displayPrice.toFixed(2)}`,
|
|
490
|
+
interval: billingInterval === 'year' ? 'year' : 'month'
|
|
491
|
+
};
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
const getCurrentPlan = () => {
|
|
495
|
+
if (!subscription) return null;
|
|
496
|
+
return plans.find(plan => plan.id === subscription.planId);
|
|
497
|
+
};
|
|
498
|
+
|
|
499
|
+
const handleFeatureSubscribe = async (featureId: string) => {
|
|
500
|
+
try {
|
|
501
|
+
// Check if feature is available for current app
|
|
502
|
+
const selectedFeature = mockIndividualFeatures.find(feature => feature.id === featureId);
|
|
503
|
+
if (!selectedFeature?.applicableApps.includes(currentAppPackage)) {
|
|
504
|
+
toast.error(`This feature is not available for the current app (${currentAppPackage})`);
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// Special restrictions for app-specific features
|
|
509
|
+
if (selectedFeature.appScope === 'specific') {
|
|
510
|
+
// For features that are only available in specific apps, enforce strict matching
|
|
511
|
+
const hasExactMatch = selectedFeature.applicableApps.length === 1 &&
|
|
512
|
+
selectedFeature.applicableApps[0] === currentAppPackage;
|
|
513
|
+
if (!hasExactMatch && selectedFeature.applicableApps.length === 1) {
|
|
514
|
+
const requiredApp = selectedFeature.applicableApps[0];
|
|
515
|
+
toast.error(`${selectedFeature.name} is only available in the ${requiredApp} app`);
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
setProcessingPayment(true);
|
|
521
|
+
|
|
522
|
+
// Mock feature subscription
|
|
523
|
+
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
524
|
+
|
|
525
|
+
setIndividualFeatures(prev =>
|
|
526
|
+
prev.map(feature =>
|
|
527
|
+
feature.id === featureId
|
|
528
|
+
? { ...feature, isSubscribed: true }
|
|
529
|
+
: feature
|
|
530
|
+
)
|
|
531
|
+
);
|
|
532
|
+
|
|
533
|
+
const feature = individualFeatures.find(f => f.id === featureId);
|
|
534
|
+
toast.success(`Subscribed to ${feature?.name} successfully!`);
|
|
535
|
+
|
|
536
|
+
} catch (error) {
|
|
537
|
+
console.error('Feature subscription failed:', error);
|
|
538
|
+
toast.error('Feature subscription failed. Please try again.');
|
|
539
|
+
} finally {
|
|
540
|
+
setProcessingPayment(false);
|
|
541
|
+
}
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
const handleFeatureUnsubscribe = async (featureId: string) => {
|
|
545
|
+
const feature = individualFeatures.find(f => f.id === featureId);
|
|
546
|
+
Alert.alert(
|
|
547
|
+
'Unsubscribe Feature',
|
|
548
|
+
`Are you sure you want to unsubscribe from ${feature?.name}?`,
|
|
549
|
+
[
|
|
550
|
+
{ text: 'Keep Feature', style: 'cancel' },
|
|
551
|
+
{
|
|
552
|
+
text: 'Unsubscribe',
|
|
553
|
+
style: 'destructive',
|
|
554
|
+
onPress: async () => {
|
|
555
|
+
try {
|
|
556
|
+
setIndividualFeatures(prev =>
|
|
557
|
+
prev.map(f =>
|
|
558
|
+
f.id === featureId
|
|
559
|
+
? { ...f, isSubscribed: false }
|
|
560
|
+
: f
|
|
561
|
+
)
|
|
562
|
+
);
|
|
563
|
+
toast.success(`Unsubscribed from ${feature?.name}`);
|
|
564
|
+
} catch (error) {
|
|
565
|
+
toast.error('Failed to unsubscribe from feature');
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
]
|
|
570
|
+
);
|
|
571
|
+
};
|
|
572
|
+
|
|
573
|
+
const renderHeader = () => {
|
|
574
|
+
const getAppDisplayName = (packageName: string) => {
|
|
575
|
+
const appNames: Record<string, string> = {
|
|
576
|
+
'mention': 'Mention',
|
|
577
|
+
'oxy-social': 'Oxy Social',
|
|
578
|
+
'oxy-workspace': 'Oxy Workspace',
|
|
579
|
+
'oxy-creator': 'Oxy Creator',
|
|
580
|
+
'oxy-analytics': 'Oxy Analytics',
|
|
581
|
+
'oxy-studio': 'Oxy Studio'
|
|
582
|
+
};
|
|
583
|
+
return appNames[packageName] || packageName;
|
|
584
|
+
};
|
|
585
|
+
|
|
586
|
+
return (
|
|
587
|
+
<View style={[styles.header, { borderBottomColor: borderColor }]}>
|
|
588
|
+
<TouchableOpacity style={styles.backButton} onPress={goBack}>
|
|
589
|
+
<Ionicons name="arrow-back" size={24} color={textColor} />
|
|
590
|
+
</TouchableOpacity>
|
|
591
|
+
<View style={styles.headerTitleContainer}>
|
|
592
|
+
<Text style={[styles.headerTitle, { color: textColor }]}>Oxy+ Subscriptions</Text>
|
|
593
|
+
<Text style={[styles.currentAppText, { color: isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
594
|
+
for {getAppDisplayName(currentAppPackage)}
|
|
595
|
+
</Text>
|
|
596
|
+
</View>
|
|
597
|
+
{onClose && (
|
|
598
|
+
<TouchableOpacity style={styles.closeButton} onPress={onClose}>
|
|
599
|
+
<Ionicons name="close" size={24} color={textColor} />
|
|
600
|
+
</TouchableOpacity>
|
|
601
|
+
)}
|
|
602
|
+
</View>
|
|
603
|
+
);
|
|
604
|
+
};
|
|
605
|
+
|
|
606
|
+
const renderCurrentSubscription = () => {
|
|
607
|
+
if (!subscription) return null;
|
|
608
|
+
|
|
609
|
+
const currentPlan = getCurrentPlan();
|
|
610
|
+
if (!currentPlan) return null;
|
|
611
|
+
|
|
612
|
+
const statusColor =
|
|
613
|
+
subscription.status === 'active' ? successColor :
|
|
614
|
+
subscription.status === 'trialing' ? warningColor :
|
|
615
|
+
dangerColor;
|
|
616
|
+
|
|
617
|
+
return (
|
|
618
|
+
<View style={styles.section}>
|
|
619
|
+
<Text style={[styles.sectionTitle, { color: textColor }]}>Current Subscription</Text>
|
|
620
|
+
|
|
621
|
+
<View style={[styles.currentSubscriptionCard, { backgroundColor: secondaryBackgroundColor, borderColor }]}>
|
|
622
|
+
<View style={styles.subscriptionHeader}>
|
|
623
|
+
<View>
|
|
624
|
+
<Text style={[styles.planName, { color: textColor }]}>{currentPlan.name}</Text>
|
|
625
|
+
<Text style={[styles.planPrice, { color: primaryColor }]}>
|
|
626
|
+
${currentPlan.price}/month
|
|
627
|
+
</Text>
|
|
628
|
+
</View>
|
|
629
|
+
<View style={[styles.statusBadge, { backgroundColor: statusColor }]}>
|
|
630
|
+
<Text style={styles.statusText}>
|
|
631
|
+
{subscription.status.toUpperCase()}
|
|
632
|
+
</Text>
|
|
633
|
+
</View>
|
|
634
|
+
</View>
|
|
635
|
+
|
|
636
|
+
<Text style={[styles.subscriptionDetail, { color: isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
637
|
+
Renews on {new Date(subscription.currentPeriodEnd).toLocaleDateString()}
|
|
638
|
+
</Text>
|
|
639
|
+
|
|
640
|
+
{subscription.cancelAtPeriodEnd && (
|
|
641
|
+
<View style={styles.cancelNotice}>
|
|
642
|
+
<Ionicons name="warning" size={16} color={warningColor} />
|
|
643
|
+
<Text style={[styles.cancelText, { color: warningColor }]}>
|
|
644
|
+
Subscription will cancel on {new Date(subscription.currentPeriodEnd).toLocaleDateString()}
|
|
645
|
+
</Text>
|
|
646
|
+
</View>
|
|
647
|
+
)}
|
|
648
|
+
|
|
649
|
+
<View style={styles.subscriptionActions}>
|
|
650
|
+
{subscription.cancelAtPeriodEnd ? (
|
|
651
|
+
<TouchableOpacity
|
|
652
|
+
style={[styles.actionButton, { backgroundColor: successColor }]}
|
|
653
|
+
onPress={handleReactivateSubscription}
|
|
654
|
+
>
|
|
655
|
+
<Text style={styles.actionButtonText}>Reactivate</Text>
|
|
656
|
+
</TouchableOpacity>
|
|
657
|
+
) : (
|
|
658
|
+
<TouchableOpacity
|
|
659
|
+
style={[styles.actionButton, { backgroundColor: dangerColor }]}
|
|
660
|
+
onPress={handleCancelSubscription}
|
|
661
|
+
>
|
|
662
|
+
<Text style={styles.actionButtonText}>Cancel Subscription</Text>
|
|
663
|
+
</TouchableOpacity>
|
|
664
|
+
)}
|
|
665
|
+
|
|
666
|
+
<TouchableOpacity
|
|
667
|
+
style={[styles.actionButton, styles.secondaryButton, { borderColor }]}
|
|
668
|
+
onPress={() => navigate && navigate('BillingManagement')}
|
|
669
|
+
>
|
|
670
|
+
<Text style={[styles.actionButtonText, { color: textColor }]}>Manage Billing</Text>
|
|
671
|
+
</TouchableOpacity>
|
|
672
|
+
</View>
|
|
673
|
+
</View>
|
|
674
|
+
</View>
|
|
675
|
+
);
|
|
676
|
+
};
|
|
677
|
+
|
|
678
|
+
const renderBillingToggle = () => (
|
|
679
|
+
<View style={styles.section}>
|
|
680
|
+
<View style={styles.billingToggle}>
|
|
681
|
+
<TouchableOpacity
|
|
682
|
+
style={[
|
|
683
|
+
styles.billingOption,
|
|
684
|
+
billingInterval === 'month' && { backgroundColor: primaryColor }
|
|
685
|
+
]}
|
|
686
|
+
onPress={() => setBillingInterval('month')}
|
|
687
|
+
>
|
|
688
|
+
<Text style={[
|
|
689
|
+
styles.billingOptionText,
|
|
690
|
+
{ color: billingInterval === 'month' ? '#FFFFFF' : textColor }
|
|
691
|
+
]}>
|
|
692
|
+
Monthly
|
|
693
|
+
</Text>
|
|
694
|
+
</TouchableOpacity>
|
|
695
|
+
|
|
696
|
+
<TouchableOpacity
|
|
697
|
+
style={[
|
|
698
|
+
styles.billingOption,
|
|
699
|
+
billingInterval === 'year' && { backgroundColor: primaryColor }
|
|
700
|
+
]}
|
|
701
|
+
onPress={() => setBillingInterval('year')}
|
|
702
|
+
>
|
|
703
|
+
<Text style={[
|
|
704
|
+
styles.billingOptionText,
|
|
705
|
+
{ color: billingInterval === 'year' ? '#FFFFFF' : textColor }
|
|
706
|
+
]}>
|
|
707
|
+
Yearly
|
|
708
|
+
</Text>
|
|
709
|
+
</TouchableOpacity>
|
|
710
|
+
</View>
|
|
711
|
+
|
|
712
|
+
{billingInterval === 'year' && (
|
|
713
|
+
<Text style={[styles.savingsText, { color: successColor }]}>
|
|
714
|
+
💰 Save 20% with yearly billing
|
|
715
|
+
</Text>
|
|
716
|
+
)}
|
|
717
|
+
</View>
|
|
718
|
+
);
|
|
719
|
+
|
|
720
|
+
const renderPlanCard = (plan: SubscriptionPlan) => {
|
|
721
|
+
const pricing = formatPrice(plan.price, plan.currency, plan.interval);
|
|
722
|
+
const isSelected = selectedPlan === plan.id;
|
|
723
|
+
const isCurrentPlan = subscription?.planId === plan.id;
|
|
724
|
+
const isAppSpecific = plan.appScope === 'specific' && plan.applicableApps.length === 1;
|
|
725
|
+
const isAvailableForCurrentApp = plan.applicableApps.includes(currentAppPackage);
|
|
726
|
+
|
|
727
|
+
const getAppScopeText = () => {
|
|
728
|
+
if (plan.appScope === 'ecosystem') {
|
|
729
|
+
return 'Works across all Oxy apps';
|
|
730
|
+
} else if (isAppSpecific) {
|
|
731
|
+
const appName = plan.applicableApps[0];
|
|
732
|
+
return `Exclusive to ${appName} app`;
|
|
733
|
+
} else {
|
|
734
|
+
return `Available in: ${plan.applicableApps.join(', ')}`;
|
|
735
|
+
}
|
|
736
|
+
};
|
|
737
|
+
|
|
738
|
+
const getAvailabilityStatus = () => {
|
|
739
|
+
if (isAppSpecific && !isAvailableForCurrentApp) {
|
|
740
|
+
const requiredApp = plan.applicableApps[0];
|
|
741
|
+
return {
|
|
742
|
+
available: false,
|
|
743
|
+
reason: `Only available in ${requiredApp} app`
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
return { available: true, reason: null };
|
|
747
|
+
};
|
|
748
|
+
|
|
749
|
+
const availability = getAvailabilityStatus();
|
|
750
|
+
|
|
751
|
+
return (
|
|
752
|
+
<View
|
|
753
|
+
key={plan.id}
|
|
754
|
+
style={[
|
|
755
|
+
styles.planCard,
|
|
756
|
+
{ backgroundColor: secondaryBackgroundColor, borderColor },
|
|
757
|
+
isSelected && { borderColor: primaryColor, borderWidth: 2 },
|
|
758
|
+
plan.isPopular && styles.popularPlan,
|
|
759
|
+
!availability.available && { opacity: 0.6 }
|
|
760
|
+
]}
|
|
761
|
+
>
|
|
762
|
+
{plan.isPopular && (
|
|
763
|
+
<View style={[styles.popularBadge, { backgroundColor: primaryColor }]}>
|
|
764
|
+
<Text style={styles.popularText}>MOST POPULAR</Text>
|
|
765
|
+
</View>
|
|
766
|
+
)}
|
|
767
|
+
|
|
768
|
+
{isAppSpecific && (
|
|
769
|
+
<View style={[styles.appSpecificBadge, {
|
|
770
|
+
backgroundColor: isAvailableForCurrentApp ? successColor : warningColor
|
|
771
|
+
}]}>
|
|
772
|
+
<Text style={styles.appSpecificText}>
|
|
773
|
+
{isAvailableForCurrentApp ? 'App Exclusive' : 'Not Available'}
|
|
774
|
+
</Text>
|
|
775
|
+
</View>
|
|
776
|
+
)}
|
|
777
|
+
|
|
778
|
+
<View style={styles.planHeader}>
|
|
779
|
+
<Text style={[styles.planName, { color: textColor }]}>{plan.name}</Text>
|
|
780
|
+
<Text style={[styles.planDescription, { color: isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
781
|
+
{plan.description}
|
|
782
|
+
</Text>
|
|
783
|
+
<Text style={[styles.planAppScope, { color: isDarkTheme ? '#888888' : '#999999' }]}>
|
|
784
|
+
{getAppScopeText()}
|
|
785
|
+
</Text>
|
|
786
|
+
{!availability.available && (
|
|
787
|
+
<Text style={[styles.planRestrictionText, { color: dangerColor }]}>
|
|
788
|
+
{availability.reason}
|
|
789
|
+
</Text>
|
|
790
|
+
)}
|
|
791
|
+
</View>
|
|
792
|
+
|
|
793
|
+
<View style={styles.planPricing}>
|
|
794
|
+
<Text style={[styles.planPrice, { color: textColor }]}>
|
|
795
|
+
{pricing.formatted}
|
|
796
|
+
</Text>
|
|
797
|
+
<Text style={[styles.planInterval, { color: isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
798
|
+
per {pricing.interval}
|
|
799
|
+
</Text>
|
|
800
|
+
</View>
|
|
801
|
+
|
|
802
|
+
<View style={styles.planFeatures}>
|
|
803
|
+
{plan.features.map((feature, index) => (
|
|
804
|
+
<View key={index} style={styles.featureItem}>
|
|
805
|
+
<Ionicons name="checkmark" size={16} color={successColor} />
|
|
806
|
+
<Text style={[styles.featureText, { color: textColor }]}>{feature}</Text>
|
|
807
|
+
</View>
|
|
808
|
+
))}
|
|
809
|
+
</View>
|
|
810
|
+
|
|
811
|
+
{isCurrentPlan ? (
|
|
812
|
+
<View style={[styles.currentPlanButton, { backgroundColor: successColor }]}>
|
|
813
|
+
<Text style={styles.currentPlanText}>Current Plan</Text>
|
|
814
|
+
</View>
|
|
815
|
+
) : !availability.available ? (
|
|
816
|
+
<View style={[styles.unavailablePlanButton, { backgroundColor: isDarkTheme ? '#444444' : '#E0E0E0' }]}>
|
|
817
|
+
<Text style={[styles.unavailablePlanText, { color: isDarkTheme ? '#888888' : '#999999' }]}>
|
|
818
|
+
Not Available in Current App
|
|
819
|
+
</Text>
|
|
820
|
+
</View>
|
|
821
|
+
) : (
|
|
822
|
+
<TouchableOpacity
|
|
823
|
+
style={[
|
|
824
|
+
styles.selectPlanButton,
|
|
825
|
+
{ backgroundColor: plan.isPopular ? primaryColor : borderColor }
|
|
826
|
+
]}
|
|
827
|
+
onPress={() => handleSubscribe(plan.id)}
|
|
828
|
+
disabled={processingPayment}
|
|
829
|
+
>
|
|
830
|
+
{processingPayment ? (
|
|
831
|
+
<ActivityIndicator color="#FFFFFF" size="small" />
|
|
832
|
+
) : (
|
|
833
|
+
<Text style={[
|
|
834
|
+
styles.selectPlanText,
|
|
835
|
+
{ color: plan.isPopular ? '#FFFFFF' : textColor }
|
|
836
|
+
]}>
|
|
837
|
+
Subscribe to {plan.name}
|
|
838
|
+
</Text>
|
|
839
|
+
)}
|
|
840
|
+
</TouchableOpacity>
|
|
841
|
+
)}
|
|
842
|
+
</View>
|
|
843
|
+
);
|
|
844
|
+
};
|
|
845
|
+
|
|
846
|
+
const renderTabNavigation = () => (
|
|
847
|
+
<View style={styles.section}>
|
|
848
|
+
<View style={[styles.tabContainer, { borderBottomColor: borderColor }]}>
|
|
849
|
+
<TouchableOpacity
|
|
850
|
+
style={[
|
|
851
|
+
styles.tab,
|
|
852
|
+
activeTab === 'plans' && { borderBottomColor: primaryColor, borderBottomWidth: 2 }
|
|
853
|
+
]}
|
|
854
|
+
onPress={() => setActiveTab('plans')}
|
|
855
|
+
>
|
|
856
|
+
<Text style={[
|
|
857
|
+
styles.tabText,
|
|
858
|
+
{ color: activeTab === 'plans' ? primaryColor : textColor }
|
|
859
|
+
]}>
|
|
860
|
+
Full Plans
|
|
861
|
+
</Text>
|
|
862
|
+
</TouchableOpacity>
|
|
863
|
+
|
|
864
|
+
<TouchableOpacity
|
|
865
|
+
style={[
|
|
866
|
+
styles.tab,
|
|
867
|
+
activeTab === 'features' && { borderBottomColor: primaryColor, borderBottomWidth: 2 }
|
|
868
|
+
]}
|
|
869
|
+
onPress={() => setActiveTab('features')}
|
|
870
|
+
>
|
|
871
|
+
<Text style={[
|
|
872
|
+
styles.tabText,
|
|
873
|
+
{ color: activeTab === 'features' ? primaryColor : textColor }
|
|
874
|
+
]}>
|
|
875
|
+
Individual Features
|
|
876
|
+
</Text>
|
|
877
|
+
</TouchableOpacity>
|
|
878
|
+
</View>
|
|
879
|
+
</View>
|
|
880
|
+
);
|
|
881
|
+
|
|
882
|
+
const renderFeatureCard = (feature: IndividualFeature) => {
|
|
883
|
+
const pricing = formatPrice(feature.price, feature.currency, feature.interval);
|
|
884
|
+
const isSubscribed = feature.isSubscribed;
|
|
885
|
+
const isIncludedInCurrentPlan = feature.isIncludedInCurrentPlan;
|
|
886
|
+
const canPurchase = feature.canBePurchasedSeparately && !isIncludedInCurrentPlan;
|
|
887
|
+
|
|
888
|
+
const getCategoryColor = (category: string) => {
|
|
889
|
+
switch (category) {
|
|
890
|
+
case 'analytics': return '#FF9500';
|
|
891
|
+
case 'customization': return '#5856D6';
|
|
892
|
+
case 'content': return '#30D158';
|
|
893
|
+
case 'networking': return '#007AFF';
|
|
894
|
+
case 'productivity': return '#FF3B30';
|
|
895
|
+
default: return primaryColor;
|
|
896
|
+
}
|
|
897
|
+
};
|
|
898
|
+
|
|
899
|
+
const getCategoryIcon = (category: string) => {
|
|
900
|
+
switch (category) {
|
|
901
|
+
case 'analytics': return 'analytics';
|
|
902
|
+
case 'customization': return 'color-palette';
|
|
903
|
+
case 'content': return 'document-text';
|
|
904
|
+
case 'networking': return 'people';
|
|
905
|
+
case 'productivity': return 'briefcase';
|
|
906
|
+
default: return 'star';
|
|
907
|
+
}
|
|
908
|
+
};
|
|
909
|
+
|
|
910
|
+
const getAppScopeText = () => {
|
|
911
|
+
if (feature.appScope === 'ecosystem') {
|
|
912
|
+
return 'Available across all Oxy apps';
|
|
913
|
+
} else {
|
|
914
|
+
return `Available in: ${feature.applicableApps.join(', ')}`;
|
|
915
|
+
}
|
|
916
|
+
};
|
|
917
|
+
|
|
918
|
+
return (
|
|
919
|
+
<View
|
|
920
|
+
key={feature.id}
|
|
921
|
+
style={[
|
|
922
|
+
styles.featureCard,
|
|
923
|
+
{ backgroundColor: secondaryBackgroundColor, borderColor },
|
|
924
|
+
isSubscribed && { borderColor: successColor, borderWidth: 2 },
|
|
925
|
+
isIncludedInCurrentPlan && { borderColor: primaryColor, borderWidth: 2 }
|
|
926
|
+
]}
|
|
927
|
+
>
|
|
928
|
+
<View style={styles.featureHeader}>
|
|
929
|
+
<View style={styles.featureIconContainer}>
|
|
930
|
+
<Ionicons
|
|
931
|
+
name={getCategoryIcon(feature.category) as any}
|
|
932
|
+
size={24}
|
|
933
|
+
color={getCategoryColor(feature.category)}
|
|
934
|
+
/>
|
|
935
|
+
</View>
|
|
936
|
+
<View style={styles.featureInfo}>
|
|
937
|
+
<View style={styles.featureNameRow}>
|
|
938
|
+
<Text style={[styles.featureName, { color: textColor }]}>{feature.name}</Text>
|
|
939
|
+
{isIncludedInCurrentPlan && (
|
|
940
|
+
<View style={[styles.includedBadge, { backgroundColor: primaryColor }]}>
|
|
941
|
+
<Text style={styles.includedBadgeText}>Included</Text>
|
|
942
|
+
</View>
|
|
943
|
+
)}
|
|
944
|
+
</View>
|
|
945
|
+
<Text style={[styles.featureDescription, { color: isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
946
|
+
{feature.description}
|
|
947
|
+
</Text>
|
|
948
|
+
<Text style={[styles.appScopeText, { color: isDarkTheme ? '#888888' : '#999999' }]}>
|
|
949
|
+
{getAppScopeText()}
|
|
950
|
+
</Text>
|
|
951
|
+
</View>
|
|
952
|
+
</View>
|
|
953
|
+
|
|
954
|
+
{!isIncludedInCurrentPlan && (
|
|
955
|
+
<View style={styles.featurePricing}>
|
|
956
|
+
<Text style={[styles.featurePrice, { color: textColor }]}>
|
|
957
|
+
{pricing.formatted}
|
|
958
|
+
</Text>
|
|
959
|
+
<Text style={[styles.featureInterval, { color: isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
960
|
+
per {pricing.interval}
|
|
961
|
+
</Text>
|
|
962
|
+
</View>
|
|
963
|
+
)}
|
|
964
|
+
|
|
965
|
+
{isIncludedInCurrentPlan ? (
|
|
966
|
+
<View style={[styles.includedInPlanButton, { backgroundColor: primaryColor }]}>
|
|
967
|
+
<Ionicons name="checkmark-circle" size={16} color="#FFFFFF" />
|
|
968
|
+
<Text style={styles.includedInPlanText}>Included in your plan</Text>
|
|
969
|
+
</View>
|
|
970
|
+
) : isSubscribed ? (
|
|
971
|
+
<View style={styles.featureActions}>
|
|
972
|
+
<View style={[styles.subscribedButton, { backgroundColor: successColor }]}>
|
|
973
|
+
<Ionicons name="checkmark" size={16} color="#FFFFFF" />
|
|
974
|
+
<Text style={styles.subscribedText}>Subscribed</Text>
|
|
975
|
+
</View>
|
|
976
|
+
<TouchableOpacity
|
|
977
|
+
style={[styles.unsubscribeButton, { borderColor: dangerColor }]}
|
|
978
|
+
onPress={() => handleFeatureUnsubscribe(feature.id)}
|
|
979
|
+
>
|
|
980
|
+
<Text style={[styles.unsubscribeText, { color: dangerColor }]}>Unsubscribe</Text>
|
|
981
|
+
</TouchableOpacity>
|
|
982
|
+
</View>
|
|
983
|
+
) : canPurchase ? (
|
|
984
|
+
<TouchableOpacity
|
|
985
|
+
style={[styles.subscribeFeatureButton, { backgroundColor: primaryColor }]}
|
|
986
|
+
onPress={() => handleFeatureSubscribe(feature.id)}
|
|
987
|
+
disabled={processingPayment}
|
|
988
|
+
>
|
|
989
|
+
{processingPayment ? (
|
|
990
|
+
<ActivityIndicator color="#FFFFFF" size="small" />
|
|
991
|
+
) : (
|
|
992
|
+
<Text style={styles.subscribeFeatureText}>Subscribe</Text>
|
|
993
|
+
)}
|
|
994
|
+
</TouchableOpacity>
|
|
995
|
+
) : (
|
|
996
|
+
<View style={[styles.unavailableButton, { backgroundColor: isDarkTheme ? '#444444' : '#E0E0E0' }]}>
|
|
997
|
+
<Text style={[styles.unavailableText, { color: isDarkTheme ? '#888888' : '#999999' }]}>
|
|
998
|
+
Only available in subscription plans
|
|
999
|
+
</Text>
|
|
1000
|
+
</View>
|
|
1001
|
+
)}
|
|
1002
|
+
</View>
|
|
1003
|
+
);
|
|
1004
|
+
};
|
|
1005
|
+
|
|
1006
|
+
const renderIndividualFeatures = () => {
|
|
1007
|
+
const categories = ['analytics', 'customization', 'content', 'networking', 'productivity'];
|
|
1008
|
+
|
|
1009
|
+
return (
|
|
1010
|
+
<View style={styles.section}>
|
|
1011
|
+
<Text style={[styles.sectionTitle, { color: textColor }]}>Individual Features</Text>
|
|
1012
|
+
<Text style={[styles.sectionSubtitle, { color: isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
1013
|
+
Subscribe to specific features you need. Some features are included in subscription plans.
|
|
1014
|
+
</Text>
|
|
1015
|
+
|
|
1016
|
+
{categories.map(category => {
|
|
1017
|
+
const categoryFeatures = individualFeatures.filter(f => f.category === category);
|
|
1018
|
+
if (categoryFeatures.length === 0) return null;
|
|
1019
|
+
|
|
1020
|
+
return (
|
|
1021
|
+
<View key={category} style={styles.categorySection}>
|
|
1022
|
+
<Text style={[styles.categoryTitle, { color: textColor }]}>
|
|
1023
|
+
{category.charAt(0).toUpperCase() + category.slice(1)}
|
|
1024
|
+
</Text>
|
|
1025
|
+
{categoryFeatures.map(renderFeatureCard)}
|
|
1026
|
+
</View>
|
|
1027
|
+
);
|
|
1028
|
+
})}
|
|
1029
|
+
</View>
|
|
1030
|
+
);
|
|
1031
|
+
};
|
|
1032
|
+
|
|
1033
|
+
// Add this for testing different app contexts (remove in production)
|
|
1034
|
+
const [showAppSwitcher, setShowAppSwitcher] = useState(__DEV__); // Only show in development
|
|
1035
|
+
|
|
1036
|
+
const renderAppSwitcher = () => {
|
|
1037
|
+
if (!showAppSwitcher) return null;
|
|
1038
|
+
|
|
1039
|
+
const testApps = ['mention', 'oxy-social', 'oxy-workspace', 'oxy-creator'];
|
|
1040
|
+
|
|
1041
|
+
return (
|
|
1042
|
+
<View style={[styles.appSwitcher, { backgroundColor: isDarkTheme ? '#333333' : '#F0F0F0', borderColor }]}>
|
|
1043
|
+
<Text style={[styles.appSwitcherTitle, { color: textColor }]}>
|
|
1044
|
+
🧪 Test App Context (Dev Only)
|
|
1045
|
+
</Text>
|
|
1046
|
+
<ScrollView horizontal showsHorizontalScrollIndicator={false}>
|
|
1047
|
+
<View style={styles.appSwitcherButtons}>
|
|
1048
|
+
{testApps.map(app => (
|
|
1049
|
+
<TouchableOpacity
|
|
1050
|
+
key={app}
|
|
1051
|
+
style={[
|
|
1052
|
+
styles.appSwitcherButton,
|
|
1053
|
+
{
|
|
1054
|
+
backgroundColor: currentAppPackage === app ? primaryColor : 'transparent',
|
|
1055
|
+
borderColor: primaryColor,
|
|
1056
|
+
}
|
|
1057
|
+
]}
|
|
1058
|
+
onPress={() => {
|
|
1059
|
+
setCurrentAppPackage(app);
|
|
1060
|
+
console.log('Switched to app context:', app);
|
|
1061
|
+
}}
|
|
1062
|
+
>
|
|
1063
|
+
<Text style={[
|
|
1064
|
+
styles.appSwitcherButtonText,
|
|
1065
|
+
{ color: currentAppPackage === app ? '#FFFFFF' : textColor }
|
|
1066
|
+
]}>
|
|
1067
|
+
{app}
|
|
1068
|
+
</Text>
|
|
1069
|
+
</TouchableOpacity>
|
|
1070
|
+
))}
|
|
1071
|
+
</View>
|
|
1072
|
+
</ScrollView>
|
|
1073
|
+
</View>
|
|
1074
|
+
);
|
|
1075
|
+
};
|
|
1076
|
+
|
|
1077
|
+
if (loading) {
|
|
1078
|
+
return (
|
|
1079
|
+
<View style={[styles.container, { backgroundColor, justifyContent: 'center' }]}>
|
|
1080
|
+
<ActivityIndicator size="large" color={primaryColor} />
|
|
1081
|
+
<Text style={[styles.loadingText, { color: textColor }]}>Loading subscription plans...</Text>
|
|
1082
|
+
</View>
|
|
1083
|
+
);
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
return (
|
|
1087
|
+
<View style={[styles.container, { backgroundColor }]}>
|
|
1088
|
+
{renderHeader()}
|
|
1089
|
+
{renderAppSwitcher()}
|
|
1090
|
+
|
|
1091
|
+
<ScrollView style={styles.content} showsVerticalScrollIndicator={false}>
|
|
1092
|
+
{subscription && renderCurrentSubscription()}
|
|
1093
|
+
|
|
1094
|
+
{!subscription && (
|
|
1095
|
+
<View style={styles.section}>
|
|
1096
|
+
<Text style={[styles.sectionTitle, { color: textColor }]}>Choose Your Plan</Text>
|
|
1097
|
+
<Text style={[styles.sectionSubtitle, { color: isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
1098
|
+
Unlock premium features and take your experience to the next level
|
|
1099
|
+
</Text>
|
|
1100
|
+
</View>
|
|
1101
|
+
)}
|
|
1102
|
+
|
|
1103
|
+
{!subscription && renderTabNavigation()}
|
|
1104
|
+
|
|
1105
|
+
{!subscription && activeTab === 'plans' && renderBillingToggle()}
|
|
1106
|
+
|
|
1107
|
+
{activeTab === 'plans' ? (
|
|
1108
|
+
<View style={styles.section}>
|
|
1109
|
+
{!subscription && (
|
|
1110
|
+
<Text style={[styles.sectionTitle, { color: textColor }]}>Available Plans</Text>
|
|
1111
|
+
)}
|
|
1112
|
+
|
|
1113
|
+
{plans.map(renderPlanCard)}
|
|
1114
|
+
</View>
|
|
1115
|
+
) : (
|
|
1116
|
+
renderIndividualFeatures()
|
|
1117
|
+
)}
|
|
1118
|
+
|
|
1119
|
+
{/* Features Comparison */}
|
|
1120
|
+
<View style={styles.section}>
|
|
1121
|
+
<Text style={[styles.sectionTitle, { color: textColor }]}>Why Go Premium?</Text>
|
|
1122
|
+
|
|
1123
|
+
<View style={[styles.benefitsCard, { backgroundColor: secondaryBackgroundColor, borderColor }]}>
|
|
1124
|
+
<View style={styles.benefitItem}>
|
|
1125
|
+
<Ionicons name="flash" size={24} color={primaryColor} />
|
|
1126
|
+
<View style={styles.benefitContent}>
|
|
1127
|
+
<Text style={[styles.benefitTitle, { color: textColor }]}>Enhanced Performance</Text>
|
|
1128
|
+
<Text style={[styles.benefitDescription, { color: isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
1129
|
+
Faster processing and priority access to our servers
|
|
1130
|
+
</Text>
|
|
1131
|
+
</View>
|
|
1132
|
+
</View>
|
|
1133
|
+
|
|
1134
|
+
<View style={styles.benefitItem}>
|
|
1135
|
+
<Ionicons name="shield-checkmark" size={24} color={successColor} />
|
|
1136
|
+
<View style={styles.benefitContent}>
|
|
1137
|
+
<Text style={[styles.benefitTitle, { color: textColor }]}>Advanced Security</Text>
|
|
1138
|
+
<Text style={[styles.benefitDescription, { color: isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
1139
|
+
Enhanced encryption and security features
|
|
1140
|
+
</Text>
|
|
1141
|
+
</View>
|
|
1142
|
+
</View>
|
|
1143
|
+
|
|
1144
|
+
<View style={styles.benefitItem}>
|
|
1145
|
+
<Ionicons name="headset" size={24} color={warningColor} />
|
|
1146
|
+
<View style={styles.benefitContent}>
|
|
1147
|
+
<Text style={[styles.benefitTitle, { color: textColor }]}>Priority Support</Text>
|
|
1148
|
+
<Text style={[styles.benefitDescription, { color: isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
1149
|
+
Get help faster with our premium support team
|
|
1150
|
+
</Text>
|
|
1151
|
+
</View>
|
|
1152
|
+
</View>
|
|
1153
|
+
</View>
|
|
1154
|
+
</View>
|
|
1155
|
+
|
|
1156
|
+
<View style={styles.bottomSpacing} />
|
|
1157
|
+
</ScrollView>
|
|
1158
|
+
</View>
|
|
1159
|
+
);
|
|
1160
|
+
};
|
|
1161
|
+
|
|
1162
|
+
const styles = StyleSheet.create({
|
|
1163
|
+
container: {
|
|
1164
|
+
flex: 1,
|
|
1165
|
+
},
|
|
1166
|
+
header: {
|
|
1167
|
+
flexDirection: 'row',
|
|
1168
|
+
alignItems: 'center',
|
|
1169
|
+
justifyContent: 'space-between',
|
|
1170
|
+
paddingHorizontal: 20,
|
|
1171
|
+
paddingTop: 20,
|
|
1172
|
+
paddingBottom: 16,
|
|
1173
|
+
borderBottomWidth: 1,
|
|
1174
|
+
},
|
|
1175
|
+
backButton: {
|
|
1176
|
+
padding: 8,
|
|
1177
|
+
},
|
|
1178
|
+
headerTitle: {
|
|
1179
|
+
fontSize: 20,
|
|
1180
|
+
fontWeight: '600',
|
|
1181
|
+
fontFamily: fontFamilies.phuduSemiBold,
|
|
1182
|
+
},
|
|
1183
|
+
headerTitleContainer: {
|
|
1184
|
+
flex: 1,
|
|
1185
|
+
alignItems: 'center',
|
|
1186
|
+
},
|
|
1187
|
+
currentAppText: {
|
|
1188
|
+
fontSize: 14,
|
|
1189
|
+
marginTop: 2,
|
|
1190
|
+
fontStyle: 'italic',
|
|
1191
|
+
},
|
|
1192
|
+
closeButton: {
|
|
1193
|
+
padding: 8,
|
|
1194
|
+
},
|
|
1195
|
+
content: {
|
|
1196
|
+
flex: 1,
|
|
1197
|
+
},
|
|
1198
|
+
section: {
|
|
1199
|
+
padding: 20,
|
|
1200
|
+
},
|
|
1201
|
+
sectionTitle: {
|
|
1202
|
+
fontSize: 24,
|
|
1203
|
+
fontWeight: 'bold',
|
|
1204
|
+
fontFamily: fontFamilies.phuduBold,
|
|
1205
|
+
marginBottom: 8,
|
|
1206
|
+
},
|
|
1207
|
+
sectionSubtitle: {
|
|
1208
|
+
fontSize: 16,
|
|
1209
|
+
lineHeight: 22,
|
|
1210
|
+
marginBottom: 20,
|
|
1211
|
+
},
|
|
1212
|
+
loadingText: {
|
|
1213
|
+
fontSize: 16,
|
|
1214
|
+
textAlign: 'center',
|
|
1215
|
+
marginTop: 16,
|
|
1216
|
+
},
|
|
1217
|
+
currentSubscriptionCard: {
|
|
1218
|
+
borderRadius: 16,
|
|
1219
|
+
padding: 20,
|
|
1220
|
+
borderWidth: 1,
|
|
1221
|
+
},
|
|
1222
|
+
subscriptionHeader: {
|
|
1223
|
+
flexDirection: 'row',
|
|
1224
|
+
justifyContent: 'space-between',
|
|
1225
|
+
alignItems: 'flex-start',
|
|
1226
|
+
marginBottom: 12,
|
|
1227
|
+
},
|
|
1228
|
+
planName: {
|
|
1229
|
+
fontSize: 20,
|
|
1230
|
+
fontWeight: 'bold',
|
|
1231
|
+
marginBottom: 4,
|
|
1232
|
+
},
|
|
1233
|
+
planPrice: {
|
|
1234
|
+
fontSize: 16,
|
|
1235
|
+
fontWeight: '600',
|
|
1236
|
+
},
|
|
1237
|
+
statusBadge: {
|
|
1238
|
+
paddingHorizontal: 12,
|
|
1239
|
+
paddingVertical: 4,
|
|
1240
|
+
borderRadius: 12,
|
|
1241
|
+
},
|
|
1242
|
+
statusText: {
|
|
1243
|
+
color: '#FFFFFF',
|
|
1244
|
+
fontSize: 12,
|
|
1245
|
+
fontWeight: '600',
|
|
1246
|
+
},
|
|
1247
|
+
subscriptionDetail: {
|
|
1248
|
+
fontSize: 14,
|
|
1249
|
+
marginBottom: 16,
|
|
1250
|
+
},
|
|
1251
|
+
cancelNotice: {
|
|
1252
|
+
flexDirection: 'row',
|
|
1253
|
+
alignItems: 'center',
|
|
1254
|
+
padding: 12,
|
|
1255
|
+
backgroundColor: 'rgba(255, 149, 0, 0.1)',
|
|
1256
|
+
borderRadius: 8,
|
|
1257
|
+
marginBottom: 16,
|
|
1258
|
+
},
|
|
1259
|
+
cancelText: {
|
|
1260
|
+
fontSize: 14,
|
|
1261
|
+
marginLeft: 8,
|
|
1262
|
+
flex: 1,
|
|
1263
|
+
},
|
|
1264
|
+
subscriptionActions: {
|
|
1265
|
+
flexDirection: 'row',
|
|
1266
|
+
gap: 12,
|
|
1267
|
+
},
|
|
1268
|
+
actionButton: {
|
|
1269
|
+
flex: 1,
|
|
1270
|
+
paddingVertical: 12,
|
|
1271
|
+
paddingHorizontal: 16,
|
|
1272
|
+
borderRadius: 8,
|
|
1273
|
+
alignItems: 'center',
|
|
1274
|
+
},
|
|
1275
|
+
secondaryButton: {
|
|
1276
|
+
backgroundColor: 'transparent',
|
|
1277
|
+
borderWidth: 1,
|
|
1278
|
+
},
|
|
1279
|
+
actionButtonText: {
|
|
1280
|
+
color: '#FFFFFF',
|
|
1281
|
+
fontSize: 14,
|
|
1282
|
+
fontWeight: '600',
|
|
1283
|
+
},
|
|
1284
|
+
billingToggle: {
|
|
1285
|
+
flexDirection: 'row',
|
|
1286
|
+
backgroundColor: 'rgba(0, 0, 0, 0.05)',
|
|
1287
|
+
borderRadius: 8,
|
|
1288
|
+
padding: 4,
|
|
1289
|
+
marginBottom: 12,
|
|
1290
|
+
},
|
|
1291
|
+
billingOption: {
|
|
1292
|
+
flex: 1,
|
|
1293
|
+
paddingVertical: 12,
|
|
1294
|
+
borderRadius: 6,
|
|
1295
|
+
alignItems: 'center',
|
|
1296
|
+
},
|
|
1297
|
+
billingOptionText: {
|
|
1298
|
+
fontSize: 16,
|
|
1299
|
+
fontWeight: '600',
|
|
1300
|
+
},
|
|
1301
|
+
savingsText: {
|
|
1302
|
+
fontSize: 14,
|
|
1303
|
+
textAlign: 'center',
|
|
1304
|
+
fontWeight: '600',
|
|
1305
|
+
},
|
|
1306
|
+
planCard: {
|
|
1307
|
+
borderRadius: 16,
|
|
1308
|
+
padding: 20,
|
|
1309
|
+
marginBottom: 16,
|
|
1310
|
+
borderWidth: 1,
|
|
1311
|
+
position: 'relative',
|
|
1312
|
+
},
|
|
1313
|
+
popularPlan: {
|
|
1314
|
+
borderWidth: 2,
|
|
1315
|
+
},
|
|
1316
|
+
popularBadge: {
|
|
1317
|
+
position: 'absolute',
|
|
1318
|
+
top: -1,
|
|
1319
|
+
left: 20,
|
|
1320
|
+
right: 20,
|
|
1321
|
+
paddingVertical: 8,
|
|
1322
|
+
borderTopLeftRadius: 16,
|
|
1323
|
+
borderTopRightRadius: 16,
|
|
1324
|
+
alignItems: 'center',
|
|
1325
|
+
},
|
|
1326
|
+
popularText: {
|
|
1327
|
+
color: '#FFFFFF',
|
|
1328
|
+
fontSize: 12,
|
|
1329
|
+
fontWeight: 'bold',
|
|
1330
|
+
},
|
|
1331
|
+
planHeader: {
|
|
1332
|
+
marginBottom: 16,
|
|
1333
|
+
marginTop: 16,
|
|
1334
|
+
},
|
|
1335
|
+
planDescription: {
|
|
1336
|
+
fontSize: 14,
|
|
1337
|
+
lineHeight: 20,
|
|
1338
|
+
},
|
|
1339
|
+
planAppScope: {
|
|
1340
|
+
fontSize: 12,
|
|
1341
|
+
fontStyle: 'italic',
|
|
1342
|
+
marginTop: 4,
|
|
1343
|
+
},
|
|
1344
|
+
planPricing: {
|
|
1345
|
+
flexDirection: 'row',
|
|
1346
|
+
alignItems: 'baseline',
|
|
1347
|
+
marginBottom: 20,
|
|
1348
|
+
},
|
|
1349
|
+
planInterval: {
|
|
1350
|
+
fontSize: 14,
|
|
1351
|
+
marginLeft: 4,
|
|
1352
|
+
},
|
|
1353
|
+
planFeatures: {
|
|
1354
|
+
marginBottom: 24,
|
|
1355
|
+
},
|
|
1356
|
+
featureItem: {
|
|
1357
|
+
flexDirection: 'row',
|
|
1358
|
+
alignItems: 'center',
|
|
1359
|
+
marginBottom: 8,
|
|
1360
|
+
},
|
|
1361
|
+
featureText: {
|
|
1362
|
+
fontSize: 14,
|
|
1363
|
+
marginLeft: 8,
|
|
1364
|
+
flex: 1,
|
|
1365
|
+
},
|
|
1366
|
+
selectPlanButton: {
|
|
1367
|
+
paddingVertical: 16,
|
|
1368
|
+
borderRadius: 12,
|
|
1369
|
+
alignItems: 'center',
|
|
1370
|
+
},
|
|
1371
|
+
selectPlanText: {
|
|
1372
|
+
fontSize: 16,
|
|
1373
|
+
fontWeight: '600',
|
|
1374
|
+
},
|
|
1375
|
+
currentPlanButton: {
|
|
1376
|
+
paddingVertical: 16,
|
|
1377
|
+
borderRadius: 12,
|
|
1378
|
+
alignItems: 'center',
|
|
1379
|
+
},
|
|
1380
|
+
currentPlanText: {
|
|
1381
|
+
color: '#FFFFFF',
|
|
1382
|
+
fontSize: 16,
|
|
1383
|
+
fontWeight: '600',
|
|
1384
|
+
},
|
|
1385
|
+
benefitsCard: {
|
|
1386
|
+
borderRadius: 16,
|
|
1387
|
+
padding: 20,
|
|
1388
|
+
borderWidth: 1,
|
|
1389
|
+
},
|
|
1390
|
+
benefitItem: {
|
|
1391
|
+
flexDirection: 'row',
|
|
1392
|
+
alignItems: 'flex-start',
|
|
1393
|
+
marginBottom: 20,
|
|
1394
|
+
},
|
|
1395
|
+
benefitContent: {
|
|
1396
|
+
marginLeft: 16,
|
|
1397
|
+
flex: 1,
|
|
1398
|
+
},
|
|
1399
|
+
benefitTitle: {
|
|
1400
|
+
fontSize: 16,
|
|
1401
|
+
fontWeight: '600',
|
|
1402
|
+
marginBottom: 4,
|
|
1403
|
+
},
|
|
1404
|
+
benefitDescription: {
|
|
1405
|
+
fontSize: 14,
|
|
1406
|
+
lineHeight: 20,
|
|
1407
|
+
},
|
|
1408
|
+
bottomSpacing: {
|
|
1409
|
+
height: 40,
|
|
1410
|
+
},
|
|
1411
|
+
// Tab Navigation Styles
|
|
1412
|
+
tabContainer: {
|
|
1413
|
+
flexDirection: 'row',
|
|
1414
|
+
borderBottomWidth: 1,
|
|
1415
|
+
marginBottom: 20,
|
|
1416
|
+
},
|
|
1417
|
+
tab: {
|
|
1418
|
+
flex: 1,
|
|
1419
|
+
paddingVertical: 12,
|
|
1420
|
+
paddingHorizontal: 16,
|
|
1421
|
+
alignItems: 'center',
|
|
1422
|
+
},
|
|
1423
|
+
tabText: {
|
|
1424
|
+
fontSize: 16,
|
|
1425
|
+
fontWeight: '600',
|
|
1426
|
+
},
|
|
1427
|
+
// Individual Feature Styles
|
|
1428
|
+
featureCard: {
|
|
1429
|
+
borderRadius: 12,
|
|
1430
|
+
borderWidth: 1,
|
|
1431
|
+
padding: 16,
|
|
1432
|
+
marginBottom: 12,
|
|
1433
|
+
},
|
|
1434
|
+
featureHeader: {
|
|
1435
|
+
flexDirection: 'row',
|
|
1436
|
+
alignItems: 'flex-start',
|
|
1437
|
+
marginBottom: 12,
|
|
1438
|
+
},
|
|
1439
|
+
featureIconContainer: {
|
|
1440
|
+
width: 40,
|
|
1441
|
+
height: 40,
|
|
1442
|
+
borderRadius: 20,
|
|
1443
|
+
backgroundColor: 'rgba(0, 122, 255, 0.1)',
|
|
1444
|
+
justifyContent: 'center',
|
|
1445
|
+
alignItems: 'center',
|
|
1446
|
+
marginRight: 12,
|
|
1447
|
+
},
|
|
1448
|
+
featureInfo: {
|
|
1449
|
+
flex: 1,
|
|
1450
|
+
},
|
|
1451
|
+
featureName: {
|
|
1452
|
+
fontSize: 16,
|
|
1453
|
+
fontWeight: '600',
|
|
1454
|
+
marginBottom: 4,
|
|
1455
|
+
},
|
|
1456
|
+
featureDescription: {
|
|
1457
|
+
fontSize: 14,
|
|
1458
|
+
lineHeight: 20,
|
|
1459
|
+
},
|
|
1460
|
+
featurePricing: {
|
|
1461
|
+
alignItems: 'center',
|
|
1462
|
+
marginBottom: 16,
|
|
1463
|
+
},
|
|
1464
|
+
featurePrice: {
|
|
1465
|
+
fontSize: 20,
|
|
1466
|
+
fontWeight: 'bold',
|
|
1467
|
+
},
|
|
1468
|
+
featureInterval: {
|
|
1469
|
+
fontSize: 14,
|
|
1470
|
+
marginTop: 2,
|
|
1471
|
+
},
|
|
1472
|
+
featureActions: {
|
|
1473
|
+
flexDirection: 'row',
|
|
1474
|
+
gap: 8,
|
|
1475
|
+
},
|
|
1476
|
+
subscribedButton: {
|
|
1477
|
+
flex: 1,
|
|
1478
|
+
flexDirection: 'row',
|
|
1479
|
+
justifyContent: 'center',
|
|
1480
|
+
alignItems: 'center',
|
|
1481
|
+
paddingVertical: 12,
|
|
1482
|
+
borderRadius: 8,
|
|
1483
|
+
gap: 6,
|
|
1484
|
+
},
|
|
1485
|
+
subscribedText: {
|
|
1486
|
+
color: '#FFFFFF',
|
|
1487
|
+
fontSize: 16,
|
|
1488
|
+
fontWeight: '600',
|
|
1489
|
+
},
|
|
1490
|
+
unsubscribeButton: {
|
|
1491
|
+
flex: 1,
|
|
1492
|
+
justifyContent: 'center',
|
|
1493
|
+
alignItems: 'center',
|
|
1494
|
+
paddingVertical: 12,
|
|
1495
|
+
borderRadius: 8,
|
|
1496
|
+
borderWidth: 1,
|
|
1497
|
+
},
|
|
1498
|
+
unsubscribeText: {
|
|
1499
|
+
fontSize: 16,
|
|
1500
|
+
fontWeight: '600',
|
|
1501
|
+
},
|
|
1502
|
+
subscribeFeatureButton: {
|
|
1503
|
+
justifyContent: 'center',
|
|
1504
|
+
alignItems: 'center',
|
|
1505
|
+
paddingVertical: 12,
|
|
1506
|
+
borderRadius: 8,
|
|
1507
|
+
},
|
|
1508
|
+
subscribeFeatureText: {
|
|
1509
|
+
color: '#FFFFFF',
|
|
1510
|
+
fontSize: 16,
|
|
1511
|
+
fontWeight: '600',
|
|
1512
|
+
},
|
|
1513
|
+
categorySection: {
|
|
1514
|
+
marginBottom: 24,
|
|
1515
|
+
},
|
|
1516
|
+
categoryTitle: {
|
|
1517
|
+
fontSize: 18,
|
|
1518
|
+
fontWeight: '600',
|
|
1519
|
+
marginBottom: 12,
|
|
1520
|
+
},
|
|
1521
|
+
// New styles for enhanced feature cards
|
|
1522
|
+
featureNameRow: {
|
|
1523
|
+
flexDirection: 'row',
|
|
1524
|
+
alignItems: 'center',
|
|
1525
|
+
justifyContent: 'space-between',
|
|
1526
|
+
marginBottom: 4,
|
|
1527
|
+
},
|
|
1528
|
+
includedBadge: {
|
|
1529
|
+
paddingHorizontal: 8,
|
|
1530
|
+
paddingVertical: 2,
|
|
1531
|
+
borderRadius: 12,
|
|
1532
|
+
marginLeft: 8,
|
|
1533
|
+
},
|
|
1534
|
+
includedBadgeText: {
|
|
1535
|
+
color: '#FFFFFF',
|
|
1536
|
+
fontSize: 10,
|
|
1537
|
+
fontWeight: '600',
|
|
1538
|
+
textTransform: 'uppercase',
|
|
1539
|
+
},
|
|
1540
|
+
appScopeText: {
|
|
1541
|
+
fontSize: 12,
|
|
1542
|
+
marginTop: 4,
|
|
1543
|
+
fontStyle: 'italic',
|
|
1544
|
+
},
|
|
1545
|
+
includedInPlanButton: {
|
|
1546
|
+
flexDirection: 'row',
|
|
1547
|
+
justifyContent: 'center',
|
|
1548
|
+
alignItems: 'center',
|
|
1549
|
+
paddingVertical: 12,
|
|
1550
|
+
borderRadius: 8,
|
|
1551
|
+
gap: 6,
|
|
1552
|
+
},
|
|
1553
|
+
includedInPlanText: {
|
|
1554
|
+
color: '#FFFFFF',
|
|
1555
|
+
fontSize: 14,
|
|
1556
|
+
fontWeight: '600',
|
|
1557
|
+
},
|
|
1558
|
+
unavailableButton: {
|
|
1559
|
+
justifyContent: 'center',
|
|
1560
|
+
alignItems: 'center',
|
|
1561
|
+
paddingVertical: 12,
|
|
1562
|
+
borderRadius: 8,
|
|
1563
|
+
},
|
|
1564
|
+
unavailableText: {
|
|
1565
|
+
fontSize: 14,
|
|
1566
|
+
fontWeight: '500',
|
|
1567
|
+
textAlign: 'center',
|
|
1568
|
+
},
|
|
1569
|
+
// App-specific plan styles
|
|
1570
|
+
appSpecificBadge: {
|
|
1571
|
+
position: 'absolute',
|
|
1572
|
+
top: 16,
|
|
1573
|
+
right: 16,
|
|
1574
|
+
paddingHorizontal: 8,
|
|
1575
|
+
paddingVertical: 4,
|
|
1576
|
+
borderRadius: 12,
|
|
1577
|
+
zIndex: 1,
|
|
1578
|
+
},
|
|
1579
|
+
appSpecificText: {
|
|
1580
|
+
color: '#FFFFFF',
|
|
1581
|
+
fontSize: 12,
|
|
1582
|
+
fontWeight: '600',
|
|
1583
|
+
},
|
|
1584
|
+
planRestrictionText: {
|
|
1585
|
+
fontSize: 12,
|
|
1586
|
+
fontWeight: '500',
|
|
1587
|
+
marginTop: 4,
|
|
1588
|
+
fontStyle: 'italic',
|
|
1589
|
+
},
|
|
1590
|
+
unavailablePlanButton: {
|
|
1591
|
+
paddingVertical: 16,
|
|
1592
|
+
borderRadius: 12,
|
|
1593
|
+
alignItems: 'center',
|
|
1594
|
+
},
|
|
1595
|
+
unavailablePlanText: {
|
|
1596
|
+
fontSize: 16,
|
|
1597
|
+
fontWeight: '600',
|
|
1598
|
+
},
|
|
1599
|
+
// App switcher styles (for development/testing)
|
|
1600
|
+
appSwitcher: {
|
|
1601
|
+
padding: 16,
|
|
1602
|
+
borderBottomWidth: 1,
|
|
1603
|
+
margin: 16,
|
|
1604
|
+
borderRadius: 12,
|
|
1605
|
+
borderWidth: 1,
|
|
1606
|
+
},
|
|
1607
|
+
appSwitcherTitle: {
|
|
1608
|
+
fontSize: 14,
|
|
1609
|
+
fontWeight: '600',
|
|
1610
|
+
marginBottom: 12,
|
|
1611
|
+
},
|
|
1612
|
+
appSwitcherButtons: {
|
|
1613
|
+
flexDirection: 'row',
|
|
1614
|
+
gap: 8,
|
|
1615
|
+
},
|
|
1616
|
+
appSwitcherButton: {
|
|
1617
|
+
paddingHorizontal: 12,
|
|
1618
|
+
paddingVertical: 6,
|
|
1619
|
+
borderRadius: 8,
|
|
1620
|
+
borderWidth: 1,
|
|
1621
|
+
},
|
|
1622
|
+
appSwitcherButtonText: {
|
|
1623
|
+
fontSize: 12,
|
|
1624
|
+
fontWeight: '500',
|
|
1625
|
+
},
|
|
1626
|
+
});
|
|
1627
|
+
|
|
1628
|
+
export default PremiumSubscriptionScreen;
|