UNPKG

@oxyhq/services

Version:

Reusable OxyHQ module to handle authentication, user management, karma system, device-based session management and more 🚀

1,404 lines (1,380 loc) 54.4 kB
"use strict"; import { useState, useEffect } from 'react'; import { View, Text, TouchableOpacity, StyleSheet, ScrollView, ActivityIndicator } from 'react-native'; import { useOxy } from '../context/OxyContext'; import { fontFamilies } from '../styles/fonts'; import { toast } from '../../lib/sonner'; import { confirmAction } from '../utils/confirmAction'; import { Ionicons } from '@expo/vector-icons'; import { useI18n } from '../hooks/useI18n'; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; const PremiumSubscriptionScreen = ({ onClose, theme, navigate, goBack }) => { const { user, oxyServices } = useOxy(); const [loading, setLoading] = useState(true); const [subscription, setSubscription] = useState(null); const [plans, setPlans] = useState([]); const [individualFeatures, setIndividualFeatures] = useState([]); const [selectedPlan, setSelectedPlan] = useState(null); const [processingPayment, setProcessingPayment] = useState(false); const [billingInterval, setBillingInterval] = useState('month'); const [activeTab, setActiveTab] = useState('plans'); const [currentAppPackage, setCurrentAppPackage] = useState('mention'); // Default to mention for demo const isDarkTheme = theme === 'dark'; const { t } = useI18n(); const textColor = isDarkTheme ? '#FFFFFF' : '#000000'; const backgroundColor = isDarkTheme ? '#121212' : '#FFFFFF'; const secondaryBackgroundColor = isDarkTheme ? '#222222' : '#F5F5F5'; const borderColor = isDarkTheme ? '#444444' : '#E0E0E0'; const primaryColor = '#007AFF'; const successColor = '#30D158'; const warningColor = '#FF9500'; const dangerColor = '#FF3B30'; // Oxy+ subscription plans const mockPlans = [{ id: 'mention-plus', name: 'Mention+', description: 'Enhanced features for better social experience', price: 4.99, currency: 'USD', interval: 'month', appScope: 'specific', applicableApps: ['mention'], // Only available in mention app features: ['Undo posts option', 'Improved reading mode', 'Organize bookmarks into folders', 'Early access to select features', 'Edit posts capability', 'Enhanced customization options'], includedFeatures: ['reading-mode-plus', 'custom-themes'] }, { id: 'oxy-insider', name: 'Oxy+ Insider', description: 'Exclusive access to behind-the-scenes content', price: 9.99, currency: 'USD', interval: 'month', appScope: 'ecosystem', applicableApps: ['mention', 'oxy-social', 'oxy-workspace', 'oxy-creator'], features: ['Everything in Mention+', 'Behind-the-scenes updates from creators', 'Early access to new features', 'Dedicated support team', 'Exclusive content access', 'Beta feature testing'], includedFeatures: ['reading-mode-plus', 'custom-themes', 'analytics-basic'], isPopular: true }, { id: 'oxy-connect', name: 'Oxy+ Connect', description: 'Advanced networking and community features', price: 14.99, currency: 'USD', interval: 'month', appScope: 'ecosystem', applicableApps: ['mention', 'oxy-social', 'oxy-workspace', 'oxy-creator'], features: ['Everything in Oxy+ Insider', 'Create and join private groups', 'Advanced search and filtering tools', 'Customizable profile highlighting', 'Enhanced connection features', 'Priority in community events'], includedFeatures: ['reading-mode-plus', 'custom-themes', 'analytics-basic', 'group-management'] }, { id: 'oxy-premium', name: 'Oxy+ Premium', description: 'Complete premium experience with all perks', price: 24.99, currency: 'USD', interval: 'month', appScope: 'ecosystem', applicableApps: ['mention', 'oxy-social', 'oxy-workspace', 'oxy-creator', 'oxy-analytics'], features: ['Everything in Oxy+ Connect', 'Priority customer support', 'Access to premium content and events', 'Advanced analytics dashboard', 'VIP community status', 'Exclusive premium events'], includedFeatures: ['reading-mode-plus', 'custom-themes', 'analytics-basic', 'analytics-advanced', 'group-management'] }, { id: 'oxy-creator', name: 'Oxy+ Creator', description: 'Professional tools for content creators', price: 39.99, currency: 'USD', interval: 'month', appScope: 'ecosystem', applicableApps: ['mention', 'oxy-social', 'oxy-workspace', 'oxy-creator', 'oxy-analytics', 'oxy-studio'], features: ['Everything in Oxy+ Premium', 'Advanced analytics and insights', 'Promotional tools and resources', 'Content monetization features', 'Creator support program', 'Revenue sharing opportunities'], includedFeatures: ['reading-mode-plus', 'custom-themes', 'analytics-basic', 'analytics-advanced', 'group-management', 'creator-tools', 'monetization-features'] }]; // Individual feature subscriptions const mockIndividualFeatures = [{ id: 'analytics-basic', name: 'Basic Analytics', description: 'View post performance and engagement metrics', price: 2.99, currency: 'USD', interval: 'month', category: 'analytics', appScope: 'ecosystem', applicableApps: ['mention', 'oxy-social', 'oxy-workspace'], canBePurchasedSeparately: true, includedInPlans: ['oxy-insider', 'oxy-connect', 'oxy-premium', 'oxy-creator'] }, { id: 'analytics-advanced', name: 'Advanced Analytics', description: 'Detailed insights, trends, and audience demographics', price: 7.99, currency: 'USD', interval: 'month', category: 'analytics', appScope: 'ecosystem', applicableApps: ['mention', 'oxy-social', 'oxy-workspace', 'oxy-creator', 'oxy-analytics'], canBePurchasedSeparately: true, includedInPlans: ['oxy-premium', 'oxy-creator'] }, { id: 'custom-themes', name: 'Custom Themes', description: 'Personalize your app with custom colors and layouts', price: 1.99, currency: 'USD', interval: 'month', category: 'customization', appScope: 'ecosystem', applicableApps: ['mention', 'oxy-social', 'oxy-workspace', 'oxy-creator'], canBePurchasedSeparately: false, // Included in all plans includedInPlans: ['mention-plus', 'oxy-insider', 'oxy-connect', 'oxy-premium', 'oxy-creator'] }, { id: 'reading-mode-plus', name: 'Reading Mode Plus', description: 'Enhanced reading experience with focus modes', price: 1.99, currency: 'USD', interval: 'month', category: 'content', appScope: 'specific', applicableApps: ['mention', 'oxy-social'], canBePurchasedSeparately: false, // Included in all plans includedInPlans: ['mention-plus', 'oxy-insider', 'oxy-connect', 'oxy-premium', 'oxy-creator'] }, { id: 'group-management', name: 'Group Management', description: 'Create and manage private groups and communities', price: 4.99, currency: 'USD', interval: 'month', category: 'networking', appScope: 'ecosystem', applicableApps: ['mention', 'oxy-social', 'oxy-workspace'], canBePurchasedSeparately: true, includedInPlans: ['oxy-connect', 'oxy-premium', 'oxy-creator'] }, { id: 'creator-tools', name: 'Creator Tools Suite', description: 'Professional content creation and editing tools', price: 9.99, currency: 'USD', interval: 'month', category: 'productivity', appScope: 'specific', applicableApps: ['oxy-creator', 'oxy-studio'], canBePurchasedSeparately: true, includedInPlans: ['oxy-creator'] }, { id: 'monetization-features', name: 'Monetization Features', description: 'Revenue sharing, sponsorship tools, and creator fund access', price: 12.99, currency: 'USD', interval: 'month', category: 'productivity', appScope: 'specific', applicableApps: ['oxy-creator'], canBePurchasedSeparately: true, includedInPlans: ['oxy-creator'] }, { id: 'workspace-collaboration', name: 'Workspace Collaboration', description: 'Advanced team features and project management tools', price: 6.99, currency: 'USD', interval: 'month', category: 'productivity', appScope: 'specific', applicableApps: ['oxy-workspace'], canBePurchasedSeparately: true, includedInPlans: ['oxy-premium', 'oxy-creator'] }]; useEffect(() => { detectCurrentApp(); }, []); useEffect(() => { if (currentAppPackage) { loadSubscriptionData(); } }, [currentAppPackage, user?.isPremium]); const detectCurrentApp = () => { // In a real implementation, this would detect the actual app package name // For now, we'll use a mock detection based on available methods // Real app detection methods you could use: // 1. Check bundle identifier in React Native: // import DeviceInfo from 'react-native-device-info'; // const bundleId = DeviceInfo.getBundleId(); // Example: com.oxy.mention -> 'mention' // 2. Environment variables or build configuration // const appPackage = __DEV__ ? process.env.APP_PACKAGE : 'mention'; // 3. Check specific app capabilities or modules // if (typeof MentionModule !== 'undefined') return 'mention'; // if (typeof OxyWorkspaceModule !== 'undefined') return 'oxy-workspace'; // 4. Use build-time configuration with Metro or similar // const appPackage = require('../config/app.json').packageName; // For demo purposes, we'll simulate different apps // You would replace this with actual app detection logic // IMPORTANT: This ensures subscription restrictions work properly: // - Mention+ plan can only be subscribed to when app package == 'mention' // - Other app-specific plans follow the same pattern // - Ecosystem plans work across all apps const detectedApp = 'mention'; // This would be dynamic in real implementation setCurrentAppPackage(detectedApp); // Log for debugging console.log('Detected app package:', detectedApp); console.log('Available plans for this app will be filtered accordingly'); }; const loadSubscriptionData = async () => { try { setLoading(true); // Filter plans available for current app const availablePlans = mockPlans.filter(plan => plan.applicableApps.includes(currentAppPackage)); setPlans(availablePlans); // Mock current subscription let currentSubscription = null; if (user?.isPremium) { currentSubscription = { id: 'sub_12345', planId: 'oxy-insider', status: 'active', currentPeriodStart: new Date().toISOString(), currentPeriodEnd: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(), cancelAtPeriodEnd: false }; setSubscription(currentSubscription); } // Filter features available for current app and update based on current subscription const availableFeatures = mockIndividualFeatures.filter(feature => feature.applicableApps.includes(currentAppPackage)); const updatedFeatures = availableFeatures.map(feature => { const isIncludedInCurrentPlan = !!(currentSubscription && feature.includedInPlans.includes(currentSubscription.planId)); return { ...feature, isIncludedInCurrentPlan, isSubscribed: isIncludedInCurrentPlan ? true : false // Mock some individual subscriptions }; }); setIndividualFeatures(updatedFeatures); } catch (error) { console.error('Failed to load subscription data:', error); toast.error('Failed to load subscription information'); } finally { setLoading(false); } }; const handlePlanSelection = planId => { setSelectedPlan(planId); }; const handleSubscribe = async planId => { try { // Check if plan is available for current app const selectedPlan = mockPlans.find(plan => plan.id === planId); if (!selectedPlan?.applicableApps.includes(currentAppPackage)) { console.log(`❌ Subscription blocked: Plan "${selectedPlan?.name}" not available for app "${currentAppPackage}"`); toast.error(t('premium.toasts.planUnavailable', { app: currentAppPackage }) || `This plan is not available for the current app (${currentAppPackage})`); return; } // Special restriction for Mention+ plan - only available in mention app if (planId === 'mention-plus' && currentAppPackage !== 'mention') { console.log(`❌ Subscription blocked: Mention+ plan requires app to be "mention", current app is "${currentAppPackage}"`); toast.error(t('premium.toasts.mentionOnly') || 'Mention+ is only available in the Mention app'); return; } console.log(`✅ Subscription allowed: Plan "${selectedPlan.name}" is available for app "${currentAppPackage}"`); setProcessingPayment(true); // Mock payment processing await new Promise(resolve => setTimeout(resolve, 2000)); toast.success(t('premium.toasts.activated') || 'Subscription activated successfully!'); // Mock subscription update setSubscription({ id: 'sub_' + Date.now(), planId, status: 'active', currentPeriodStart: new Date().toISOString(), currentPeriodEnd: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(), cancelAtPeriodEnd: false }); // Reload data to update feature states loadSubscriptionData(); } catch (error) { console.error('Payment failed:', error); toast.error(t('premium.toasts.paymentFailed') || 'Payment failed. Please try again.'); } finally { setProcessingPayment(false); } }; const handleCancelSubscription = () => { confirmAction(t('premium.confirms.cancelSub') || 'Are you sure you want to cancel your subscription? You will lose access to premium features at the end of your current billing period.', async () => { try { // Mock cancellation setSubscription(prev => prev ? { ...prev, cancelAtPeriodEnd: true } : null); toast.success(t('premium.toasts.willCancel') || 'Subscription will be canceled at the end of the billing period'); } catch (error) { toast.error(t('premium.toasts.cancelFailed') || 'Failed to cancel subscription'); } }); }; const handleReactivateSubscription = async () => { try { setSubscription(prev => prev ? { ...prev, cancelAtPeriodEnd: false } : null); toast.success(t('premium.toasts.reactivated') || 'Subscription reactivated successfully'); } catch (error) { toast.error(t('premium.toasts.reactivateFailed') || 'Failed to reactivate subscription'); } }; const formatPrice = (price, currency, interval) => { const yearlyPrice = interval === 'year' ? price : price * 12 * 0.8; // 20% discount for yearly const displayPrice = billingInterval === 'year' ? yearlyPrice : price; return { price: displayPrice, formatted: `$${displayPrice.toFixed(2)}`, interval: billingInterval === 'year' ? 'year' : 'month' }; }; const getCurrentPlan = () => { if (!subscription) return null; return plans.find(plan => plan.id === subscription.planId); }; const handleFeatureSubscribe = async featureId => { try { // Check if feature is available for current app const selectedFeature = mockIndividualFeatures.find(feature => feature.id === featureId); if (!selectedFeature?.applicableApps.includes(currentAppPackage)) { toast.error(`This feature is not available for the current app (${currentAppPackage})`); return; } // Special restrictions for app-specific features if (selectedFeature.appScope === 'specific') { // For features that are only available in specific apps, enforce strict matching const hasExactMatch = selectedFeature.applicableApps.length === 1 && selectedFeature.applicableApps[0] === currentAppPackage; if (!hasExactMatch && selectedFeature.applicableApps.length === 1) { const requiredApp = selectedFeature.applicableApps[0]; toast.error(`${selectedFeature.name} is only available in the ${requiredApp} app`); return; } } setProcessingPayment(true); // Mock feature subscription await new Promise(resolve => setTimeout(resolve, 1500)); setIndividualFeatures(prev => prev.map(feature => feature.id === featureId ? { ...feature, isSubscribed: true } : feature)); const feature = individualFeatures.find(f => f.id === featureId); toast.success(t('premium.toasts.featureSubscribed', { name: feature?.name ?? '' }) ?? `Subscribed to ${feature?.name} successfully!`); } catch (error) { console.error('Feature subscription failed:', error); toast.error(t('premium.toasts.featureSubscribeFailed') || 'Feature subscription failed. Please try again.'); } finally { setProcessingPayment(false); } }; const handleFeatureUnsubscribe = async featureId => { const feature = individualFeatures.find(f => f.id === featureId); confirmAction(t('premium.confirms.unsubscribeFeature', { name: feature?.name ?? '' }) ?? `Are you sure you want to unsubscribe from ${feature?.name}?`, async () => { try { setIndividualFeatures(prev => prev.map(f => f.id === featureId ? { ...f, isSubscribed: false } : f)); toast.success(t('premium.toasts.featureUnsubscribed', { name: feature?.name ?? '' }) ?? `Unsubscribed from ${feature?.name}`); } catch (error) { toast.error(t('premium.toasts.featureUnsubscribeFailed') || 'Failed to unsubscribe from feature'); } }); }; const renderHeader = () => { const getAppDisplayName = packageName => { const appNames = { 'mention': 'Mention', 'oxy-social': 'Oxy Social', 'oxy-workspace': 'Oxy Workspace', 'oxy-creator': 'Oxy Creator', 'oxy-analytics': 'Oxy Analytics', 'oxy-studio': 'Oxy Studio' }; return appNames[packageName] || packageName; }; return /*#__PURE__*/_jsxs(View, { style: [styles.header, { borderBottomColor: borderColor }], children: [/*#__PURE__*/_jsx(TouchableOpacity, { style: styles.backButton, onPress: goBack, children: /*#__PURE__*/_jsx(Ionicons, { name: "arrow-back", size: 24, color: textColor }) }), /*#__PURE__*/_jsxs(View, { style: styles.headerTitleContainer, children: [/*#__PURE__*/_jsx(Text, { style: [styles.headerTitle, { color: textColor }], children: t('premium.title') || 'Oxy+ Subscriptions' }), /*#__PURE__*/_jsx(Text, { style: [styles.currentAppText, { color: isDarkTheme ? '#BBBBBB' : '#666666' }], children: t('premium.forApp', { app: getAppDisplayName(currentAppPackage) }) || `for ${getAppDisplayName(currentAppPackage)}` })] }), onClose && /*#__PURE__*/_jsx(TouchableOpacity, { style: styles.closeButton, onPress: onClose, children: /*#__PURE__*/_jsx(Ionicons, { name: "close", size: 24, color: textColor }) })] }); }; const renderCurrentSubscription = () => { if (!subscription) return null; const currentPlan = getCurrentPlan(); if (!currentPlan) return null; const statusColor = subscription.status === 'active' ? successColor : subscription.status === 'trialing' ? warningColor : dangerColor; return /*#__PURE__*/_jsxs(View, { style: styles.section, children: [/*#__PURE__*/_jsx(Text, { style: [styles.sectionTitle, { color: textColor }], children: t('premium.current.title') || 'Current Subscription' }), /*#__PURE__*/_jsxs(View, { style: [styles.currentSubscriptionCard, { backgroundColor: secondaryBackgroundColor, borderColor }], children: [/*#__PURE__*/_jsxs(View, { style: styles.subscriptionHeader, children: [/*#__PURE__*/_jsxs(View, { children: [/*#__PURE__*/_jsx(Text, { style: [styles.planName, { color: textColor }], children: currentPlan.name }), /*#__PURE__*/_jsxs(Text, { style: [styles.planPrice, { color: primaryColor }], children: ["$", currentPlan.price, "/month"] })] }), /*#__PURE__*/_jsx(View, { style: [styles.statusBadge, { backgroundColor: statusColor }], children: /*#__PURE__*/_jsx(Text, { style: styles.statusText, children: subscription.status.toUpperCase() }) })] }), /*#__PURE__*/_jsx(Text, { style: [styles.subscriptionDetail, { color: isDarkTheme ? '#BBBBBB' : '#666666' }], children: t('premium.current.renewsOn', { date: new Date(subscription.currentPeriodEnd).toLocaleDateString() }) || `Renews on ${new Date(subscription.currentPeriodEnd).toLocaleDateString()}` }), subscription.cancelAtPeriodEnd && /*#__PURE__*/_jsxs(View, { style: styles.cancelNotice, children: [/*#__PURE__*/_jsx(Ionicons, { name: "warning", size: 16, color: warningColor }), /*#__PURE__*/_jsx(Text, { style: [styles.cancelText, { color: warningColor }], children: t('premium.current.willCancelOn', { date: new Date(subscription.currentPeriodEnd).toLocaleDateString() }) || `Subscription will cancel on ${new Date(subscription.currentPeriodEnd).toLocaleDateString()}` })] }), /*#__PURE__*/_jsxs(View, { style: styles.subscriptionActions, children: [subscription.cancelAtPeriodEnd ? /*#__PURE__*/_jsx(TouchableOpacity, { style: [styles.actionButton, { backgroundColor: successColor }], onPress: handleReactivateSubscription, children: /*#__PURE__*/_jsx(Text, { style: styles.actionButtonText, children: t('premium.actions.reactivate') || 'Reactivate' }) }) : /*#__PURE__*/_jsx(TouchableOpacity, { style: [styles.actionButton, { backgroundColor: dangerColor }], onPress: handleCancelSubscription, children: /*#__PURE__*/_jsx(Text, { style: styles.actionButtonText, children: t('premium.actions.cancelSubBtn') || 'Cancel Subscription' }) }), /*#__PURE__*/_jsx(TouchableOpacity, { style: [styles.actionButton, styles.secondaryButton, { borderColor }], children: /*#__PURE__*/_jsx(Text, { style: [styles.actionButtonText, { color: textColor }], children: t('premium.actions.manageBilling') || 'Manage Billing' }) })] })] })] }); }; const renderBillingToggle = () => /*#__PURE__*/_jsxs(View, { style: styles.section, children: [/*#__PURE__*/_jsxs(View, { style: styles.billingToggle, children: [/*#__PURE__*/_jsx(TouchableOpacity, { style: [styles.billingOption, billingInterval === 'month' && { backgroundColor: primaryColor }], onPress: () => setBillingInterval('month'), children: /*#__PURE__*/_jsx(Text, { style: [styles.billingOptionText, { color: billingInterval === 'month' ? '#FFFFFF' : textColor }], children: t('premium.billing.monthly') || 'Monthly' }) }), /*#__PURE__*/_jsx(TouchableOpacity, { style: [styles.billingOption, billingInterval === 'year' && { backgroundColor: primaryColor }], onPress: () => setBillingInterval('year'), children: /*#__PURE__*/_jsx(Text, { style: [styles.billingOptionText, { color: billingInterval === 'year' ? '#FFFFFF' : textColor }], children: t('premium.billing.yearly') || 'Yearly' }) })] }), billingInterval === 'year' && /*#__PURE__*/_jsx(Text, { style: [styles.savingsText, { color: successColor }], children: t('premium.billing.saveYearly') || '💰 Save 20% with yearly billing' })] }); const renderPlanCard = plan => { const pricing = formatPrice(plan.price, plan.currency, plan.interval); const isSelected = selectedPlan === plan.id; const isCurrentPlan = subscription?.planId === plan.id; const isAppSpecific = plan.appScope === 'specific' && plan.applicableApps.length === 1; const isAvailableForCurrentApp = plan.applicableApps.includes(currentAppPackage); const getAppScopeText = () => { if (plan.appScope === 'ecosystem') { return t('premium.plan.scope.allApps') || 'Works across all Oxy apps'; } else if (isAppSpecific) { const appName = plan.applicableApps[0]; return t('premium.plan.scope.exclusive', { app: appName }) || `Exclusive to ${appName} app`; } else { return t('premium.plan.scope.availableIn', { apps: plan.applicableApps.join(', ') }) || `Available in: ${plan.applicableApps.join(', ')}`; } }; const getAvailabilityStatus = () => { if (isAppSpecific && !isAvailableForCurrentApp) { const requiredApp = plan.applicableApps[0]; return { available: false, reason: t('premium.plan.scope.exclusive', { app: requiredApp }) || `Only available in ${requiredApp} app` }; } return { available: true, reason: null }; }; const availability = getAvailabilityStatus(); return /*#__PURE__*/_jsxs(View, { style: [styles.planCard, { backgroundColor: secondaryBackgroundColor, borderColor }, isSelected && { borderColor: primaryColor, borderWidth: 2 }, plan.isPopular && styles.popularPlan, !availability.available && { opacity: 0.6 }], children: [plan.isPopular && /*#__PURE__*/_jsx(View, { style: [styles.popularBadge, { backgroundColor: primaryColor }], children: /*#__PURE__*/_jsx(Text, { style: styles.popularText, children: "MOST POPULAR" }) }), isAppSpecific && /*#__PURE__*/_jsx(View, { style: [styles.appSpecificBadge, { backgroundColor: isAvailableForCurrentApp ? successColor : warningColor }], children: /*#__PURE__*/_jsx(Text, { style: styles.appSpecificText, children: isAvailableForCurrentApp ? t('premium.plan.badge.appExclusive') || 'App Exclusive' : t('premium.plan.badge.notAvailable') || 'Not Available' }) }), /*#__PURE__*/_jsxs(View, { style: styles.planHeader, children: [/*#__PURE__*/_jsx(Text, { style: [styles.planName, { color: textColor }], children: plan.name }), /*#__PURE__*/_jsx(Text, { style: [styles.planDescription, { color: isDarkTheme ? '#BBBBBB' : '#666666' }], children: plan.description }), /*#__PURE__*/_jsx(Text, { style: [styles.planAppScope, { color: isDarkTheme ? '#888888' : '#999999' }], children: getAppScopeText() }), !availability.available && /*#__PURE__*/_jsx(Text, { style: [styles.planRestrictionText, { color: dangerColor }], children: availability.reason })] }), /*#__PURE__*/_jsxs(View, { style: styles.planPricing, children: [/*#__PURE__*/_jsx(Text, { style: [styles.planPrice, { color: textColor }], children: pricing.formatted }), /*#__PURE__*/_jsx(Text, { style: [styles.planInterval, { color: isDarkTheme ? '#BBBBBB' : '#666666' }], children: t('premium.plan.perInterval', { interval: pricing.interval }) || `per ${pricing.interval}` })] }), /*#__PURE__*/_jsx(View, { style: styles.planFeatures, children: plan.features.map((feature, index) => /*#__PURE__*/_jsxs(View, { style: styles.featureItem, children: [/*#__PURE__*/_jsx(Ionicons, { name: "checkmark", size: 16, color: successColor }), /*#__PURE__*/_jsx(Text, { style: [styles.featureText, { color: textColor }], children: feature })] }, index)) }), isCurrentPlan ? /*#__PURE__*/_jsx(View, { style: [styles.currentPlanButton, { backgroundColor: successColor }], children: /*#__PURE__*/_jsx(Text, { style: styles.currentPlanText, children: t('premium.plan.current') || 'Current Plan' }) }) : !availability.available ? /*#__PURE__*/_jsx(View, { style: [styles.unavailablePlanButton, { backgroundColor: isDarkTheme ? '#444444' : '#E0E0E0' }], children: /*#__PURE__*/_jsx(Text, { style: [styles.unavailablePlanText, { color: isDarkTheme ? '#888888' : '#999999' }], children: t('premium.plan.notAvailableInApp') || 'Not Available in Current App' }) }) : /*#__PURE__*/_jsx(TouchableOpacity, { style: [styles.selectPlanButton, { backgroundColor: plan.isPopular ? primaryColor : borderColor }], onPress: () => handleSubscribe(plan.id), disabled: processingPayment, children: processingPayment ? /*#__PURE__*/_jsx(ActivityIndicator, { color: "#FFFFFF", size: "small" }) : /*#__PURE__*/_jsx(Text, { style: [styles.selectPlanText, { color: plan.isPopular ? '#FFFFFF' : textColor }], children: t('premium.actions.subscribeTo', { name: plan.name }) || `Subscribe to ${plan.name}` }) })] }, plan.id); }; const renderTabNavigation = () => /*#__PURE__*/_jsx(View, { style: styles.section, children: /*#__PURE__*/_jsxs(View, { style: [styles.tabContainer, { borderBottomColor: borderColor }], children: [/*#__PURE__*/_jsx(TouchableOpacity, { style: [styles.tab, activeTab === 'plans' && { borderBottomColor: primaryColor, borderBottomWidth: 2 }], onPress: () => setActiveTab('plans'), children: /*#__PURE__*/_jsx(Text, { style: [styles.tabText, { color: activeTab === 'plans' ? primaryColor : textColor }], children: t('premium.tabs.plans') || 'Full Plans' }) }), /*#__PURE__*/_jsx(TouchableOpacity, { style: [styles.tab, activeTab === 'features' && { borderBottomColor: primaryColor, borderBottomWidth: 2 }], onPress: () => setActiveTab('features'), children: /*#__PURE__*/_jsx(Text, { style: [styles.tabText, { color: activeTab === 'features' ? primaryColor : textColor }], children: t('premium.tabs.features') || 'Individual Features' }) })] }) }); const renderFeatureCard = feature => { const pricing = formatPrice(feature.price, feature.currency, feature.interval); const isSubscribed = feature.isSubscribed; const isIncludedInCurrentPlan = feature.isIncludedInCurrentPlan; const canPurchase = feature.canBePurchasedSeparately && !isIncludedInCurrentPlan; const getCategoryColor = category => { switch (category) { case 'analytics': return '#FF9500'; case 'customization': return '#5856D6'; case 'content': return '#30D158'; case 'networking': return '#007AFF'; case 'productivity': return '#FF3B30'; default: return primaryColor; } }; const getCategoryIcon = category => { switch (category) { case 'analytics': return 'analytics'; case 'customization': return 'color-palette'; case 'content': return 'document-text'; case 'networking': return 'people'; case 'productivity': return 'briefcase'; default: return 'star'; } }; const getAppScopeText = () => { if (feature.appScope === 'ecosystem') { return t('premium.feature.scope.allApps'); } else { return t('premium.feature.scope.availableIn', { apps: feature.applicableApps.join(', ') }) || `Available in: ${feature.applicableApps.join(', ')}`; } }; return /*#__PURE__*/_jsxs(View, { style: [styles.featureCard, { backgroundColor: secondaryBackgroundColor, borderColor }, isSubscribed && { borderColor: successColor, borderWidth: 2 }, isIncludedInCurrentPlan && { borderColor: primaryColor, borderWidth: 2 }], children: [/*#__PURE__*/_jsxs(View, { style: styles.featureHeader, children: [/*#__PURE__*/_jsx(View, { style: styles.featureIconContainer, children: /*#__PURE__*/_jsx(Ionicons, { name: getCategoryIcon(feature.category), size: 24, color: getCategoryColor(feature.category) }) }), /*#__PURE__*/_jsxs(View, { style: styles.featureInfo, children: [/*#__PURE__*/_jsxs(View, { style: styles.featureNameRow, children: [/*#__PURE__*/_jsx(Text, { style: [styles.featureName, { color: textColor }], children: feature.name }), isIncludedInCurrentPlan && /*#__PURE__*/_jsx(View, { style: [styles.includedBadge, { backgroundColor: primaryColor }], children: /*#__PURE__*/_jsx(Text, { style: styles.includedBadgeText, children: "Included" }) })] }), /*#__PURE__*/_jsx(Text, { style: [styles.featureDescription, { color: isDarkTheme ? '#BBBBBB' : '#666666' }], children: feature.description }), /*#__PURE__*/_jsx(Text, { style: [styles.appScopeText, { color: isDarkTheme ? '#888888' : '#999999' }], children: getAppScopeText() })] })] }), !isIncludedInCurrentPlan && /*#__PURE__*/_jsxs(View, { style: styles.featurePricing, children: [/*#__PURE__*/_jsx(Text, { style: [styles.featurePrice, { color: textColor }], children: pricing.formatted }), /*#__PURE__*/_jsx(Text, { style: [styles.featureInterval, { color: isDarkTheme ? '#BBBBBB' : '#666666' }], children: t('premium.plan.perInterval', { interval: pricing.interval }) || `per ${pricing.interval}` })] }), isIncludedInCurrentPlan ? /*#__PURE__*/_jsxs(View, { style: [styles.includedInPlanButton, { backgroundColor: primaryColor }], children: [/*#__PURE__*/_jsx(Ionicons, { name: "checkmark-circle", size: 16, color: "#FFFFFF" }), /*#__PURE__*/_jsx(Text, { style: styles.includedInPlanText, children: t('premium.feature.includedInPlan') || 'Included in your plan' })] }) : isSubscribed ? /*#__PURE__*/_jsxs(View, { style: styles.featureActions, children: [/*#__PURE__*/_jsxs(View, { style: [styles.subscribedButton, { backgroundColor: successColor }], children: [/*#__PURE__*/_jsx(Ionicons, { name: "checkmark", size: 16, color: "#FFFFFF" }), /*#__PURE__*/_jsx(Text, { style: styles.subscribedText, children: t('premium.feature.subscribed') || 'Subscribed' })] }), /*#__PURE__*/_jsx(TouchableOpacity, { style: [styles.unsubscribeButton, { borderColor: dangerColor }], onPress: () => handleFeatureUnsubscribe(feature.id), children: /*#__PURE__*/_jsx(Text, { style: [styles.unsubscribeText, { color: dangerColor }], children: t('premium.actions.unsubscribe') || 'Unsubscribe' }) })] }) : canPurchase ? /*#__PURE__*/_jsx(TouchableOpacity, { style: [styles.subscribeFeatureButton, { backgroundColor: primaryColor }], onPress: () => handleFeatureSubscribe(feature.id), disabled: processingPayment, children: processingPayment ? /*#__PURE__*/_jsx(ActivityIndicator, { color: "#FFFFFF", size: "small" }) : /*#__PURE__*/_jsx(Text, { style: styles.subscribeFeatureText, children: t('premium.actions.subscribe') || 'Subscribe' }) }) : /*#__PURE__*/_jsx(View, { style: [styles.unavailableButton, { backgroundColor: isDarkTheme ? '#444444' : '#E0E0E0' }], children: /*#__PURE__*/_jsx(Text, { style: [styles.unavailableText, { color: isDarkTheme ? '#888888' : '#999999' }], children: "Only available in subscription plans" }) })] }, feature.id); }; const renderIndividualFeatures = () => { const categories = ['analytics', 'customization', 'content', 'networking', 'productivity']; return /*#__PURE__*/_jsxs(View, { style: styles.section, children: [/*#__PURE__*/_jsx(Text, { style: [styles.sectionTitle, { color: textColor }], children: "Individual Features" }), /*#__PURE__*/_jsx(Text, { style: [styles.sectionSubtitle, { color: isDarkTheme ? '#BBBBBB' : '#666666' }], children: "Subscribe to specific features you need. Some features are included in subscription plans." }), categories.map(category => { const categoryFeatures = individualFeatures.filter(f => f.category === category); if (categoryFeatures.length === 0) return null; return /*#__PURE__*/_jsxs(View, { style: styles.categorySection, children: [/*#__PURE__*/_jsx(Text, { style: [styles.categoryTitle, { color: textColor }], children: category.charAt(0).toUpperCase() + category.slice(1) }), categoryFeatures.map(renderFeatureCard)] }, category); })] }); }; // Add this for testing different app contexts (remove in production) const [showAppSwitcher, setShowAppSwitcher] = useState(__DEV__); // Only show in development const renderAppSwitcher = () => { if (!showAppSwitcher) return null; const testApps = ['mention', 'oxy-social', 'oxy-workspace', 'oxy-creator']; return /*#__PURE__*/_jsxs(View, { style: [styles.appSwitcher, { backgroundColor: isDarkTheme ? '#333333' : '#F0F0F0', borderColor }], children: [/*#__PURE__*/_jsx(Text, { style: [styles.appSwitcherTitle, { color: textColor }], children: "\uD83E\uDDEA Test App Context (Dev Only)" }), /*#__PURE__*/_jsx(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, children: /*#__PURE__*/_jsx(View, { style: styles.appSwitcherButtons, children: testApps.map(app => /*#__PURE__*/_jsx(TouchableOpacity, { style: [styles.appSwitcherButton, { backgroundColor: currentAppPackage === app ? primaryColor : 'transparent', borderColor: primaryColor }], onPress: () => { setCurrentAppPackage(app); }, children: /*#__PURE__*/_jsx(Text, { style: [styles.appSwitcherButtonText, { color: currentAppPackage === app ? '#FFFFFF' : textColor }], children: app }) }, app)) }) })] }); }; if (loading) { return /*#__PURE__*/_jsxs(View, { style: [styles.container, { backgroundColor, justifyContent: 'center' }], children: [/*#__PURE__*/_jsx(ActivityIndicator, { size: "large", color: primaryColor }), /*#__PURE__*/_jsx(Text, { style: [styles.loadingText, { color: textColor }], children: t('premium.loading') || 'Loading subscription plans...' })] }); } return /*#__PURE__*/_jsxs(View, { style: [styles.container, { backgroundColor }], children: [renderHeader(), renderAppSwitcher(), /*#__PURE__*/_jsxs(ScrollView, { style: styles.content, showsVerticalScrollIndicator: false, children: [subscription && renderCurrentSubscription(), !subscription && /*#__PURE__*/_jsxs(View, { style: styles.section, children: [/*#__PURE__*/_jsx(Text, { style: [styles.sectionTitle, { color: textColor }], children: t('premium.choosePlan') || 'Choose Your Plan' }), /*#__PURE__*/_jsx(Text, { style: [styles.sectionSubtitle, { color: isDarkTheme ? '#BBBBBB' : '#666666' }], children: t('premium.choosePlanSubtitle') || 'Unlock premium features and take your experience to the next level' })] }), !subscription && renderTabNavigation(), !subscription && activeTab === 'plans' && renderBillingToggle(), activeTab === 'plans' ? /*#__PURE__*/_jsxs(View, { style: styles.section, children: [!subscription && /*#__PURE__*/_jsx(Text, { style: [styles.sectionTitle, { color: textColor }], children: t('premium.availablePlans') || 'Available Plans' }), plans.map(renderPlanCard)] }) : renderIndividualFeatures(), /*#__PURE__*/_jsxs(View, { style: styles.section, children: [/*#__PURE__*/_jsx(Text, { style: [styles.sectionTitle, { color: textColor }], children: t('premium.why') || 'Why Go Premium?' }), /*#__PURE__*/_jsxs(View, { style: [styles.benefitsCard, { backgroundColor: secondaryBackgroundColor, borderColor }], children: [/*#__PURE__*/_jsxs(View, { style: styles.benefitItem, children: [/*#__PURE__*/_jsx(Ionicons, { name: "flash", size: 24, color: primaryColor }), /*#__PURE__*/_jsxs(View, { style: styles.benefitContent, children: [/*#__PURE__*/_jsx(Text, { style: [styles.benefitTitle, { color: textColor }], children: t('premium.benefits.performance.title') || 'Enhanced Performance' }), /*#__PURE__*/_jsx(Text, { style: [styles.benefitDescription, { color: isDarkTheme ? '#BBBBBB' : '#666666' }], children: t('premium.benefits.performance.desc') || 'Faster processing and priority access to our servers' })] })] }), /*#__PURE__*/_jsxs(View, { style: styles.benefitItem, children: [/*#__PURE__*/_jsx(Ionicons, { name: "shield-checkmark", size: 24, color: successColor }), /*#__PURE__*/_jsxs(View, { style: styles.benefitContent, children: [/*#__PURE__*/_jsx(Text, { style: [styles.benefitTitle, { color: textColor }], children: t('premium.benefits.security.title') || 'Advanced Security' }), /*#__PURE__*/_jsx(Text, { style: [styles.benefitDescription, { color: isDarkTheme ? '#BBBBBB' : '#666666' }], children: t('premium.benefits.security.desc') || 'Enhanced encryption and security features' })] })] }), /*#__PURE__*/_jsxs(View, { style: styles.benefitItem, children: [/*#__PURE__*/_jsx(Ionicons, { name: "headset", size: 24, color: warningColor }), /*#__PURE__*/_jsxs(View, { style: styles.benefitContent, children: [/*#__PURE__*/_jsx(Text, { style: [styles.benefitTitle, { color: textColor }], children: t('premium.benefits.support.title') || 'Priority Support' }), /*#__PURE__*/_jsx(Text, { style: [styles.benefitDescription, { color: isDarkTheme ? '#BBBBBB' : '#666666' }], children: t('premium.benefits.support.desc') || 'Get help faster with our premium support team' })] })] })] })] }), /*#__PURE__*/_jsx(View, { style: styles.bottomSpacing })] })] }); }; const styles = StyleSheet.create({ container: { flex: 1 }, header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingHorizontal: 20, paddingTop: 20, paddingBottom: 16, borderBottomWidth: 1 }, backButton: { padding: 8 }, headerTitle: { fontSize: 20, fontWeight: '600', fontFamily: fontFamilies.phuduSemiBold }, headerTitleContainer: { flex: 1, alignItems: 'center' }, currentAppText: { fontSize: 14, marginTop: 2, fontStyle: 'italic' }, closeButton: { padding: 8 }, content: { flex: 1 }, section: { padding: 20 }, sectionTitle: { fontSize: 24, fontWeight: 'bold', fontFamily: fontFamilies.phuduBold, marginBottom: 8 }, sectionSubtitle: { fontSize: 16, lineHeight: 22, marginBottom: 20 }, loadingText: { fontSize: 16, textAlign: 'center', marginTop: 16 }, currentSubscriptionCard: { borderRadius: 16, padding: 20, borderWidth: 1 }, subscriptionHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 12 }, planName: { fontSize: 20, fontWeight: 'bold', marginBottom: 4 }, planPrice: { fontSize: 16, fontWeight: '600' }, statusBadge: { paddingHorizontal: 12, paddingVertical: 4, borderRadius: 12 }, statusText: { color: '#FFFFFF', fontSize: 12, fontWeight: '600' }, subscriptionDetail: { fontSize: 14, marginBottom: 16 }, cancelNotice: { flexDirection: 'row', alignItems: 'center', padding: 12, backgroundColor: 'rgba(255, 149, 0, 0.1)', borderRadius: 8, marginBottom: 16 }, cancelText: { fontSize: 14, marginLeft: 8, flex: 1 }, subscriptionActions: { flexDirection: 'row', gap: 12 }, actionButton: { flex: 1, paddingVertical: 12, paddingHorizontal: 16, borderRadius: 8, alignItems: 'center' }, secondaryButton: { backgroundColor: 'transparent', borderWidth: 1 }, actionButtonText: { color: '#FFFFFF', fontSize: 14, fontWeight: '600' }, billingToggle: { flexDirection: 'row', backgroundColor: 'rgba(0, 0, 0, 0.05)', borderRadius: 8, padding: 4, marginBottom: 12 }, billingOption: { flex: 1, paddingVertical: 12, borderRadius: 6, alignItems: 'center' }, billingOptionText: { fontSize: 16, fontWeight: '600' }, savingsText: { fontSize: 14, textAlign: 'center', fontWeight: '600' }, planCard: { borderRadius: 16, padding: 20, marginBottom: 16, borderWidth: 1, position: 'relative' }, popularPlan: { borderWidth: 2 }, popularBadge: { position: 'absolute', top: -1, left: 20, right: 20, paddingVertical: 8, borderTopLeftRadius: 16, borderTopRightRadius: 16, alignItems: 'center' }, popularText: { color: '#FFFFFF', fontSize: 12, fontWeight: 'bold' }, planHeader: { marginBottom: 16, marginTop: 16 }, planDescription: { fontSize: 14, lineHeight: 20 }, planAppScope: { fontSize: 12, fontStyle: 'italic', marginTop: 4 }, planPricing: { flexDirection: 'row', alignItems: 'baseline', marginBottom: 20 }, planInterval: { fontSize: 14, marginLeft: 4 }, planFeatures: { marginBottom: 24 }, featureItem: { flexDirection: 'row', alignItems: 'center', marginBottom: 8 }, featureText: { fontSize: 14, marginLeft: 8, flex: 1 }, selectPlanButton: { paddingVertical: 16, borderRadius: 12, alignItems: 'center' }, selectPlanText: { fontSize: 16, fontWeight: '600' }, currentPlanButton: { paddingVertical: 16, borderRadius: 12, alignItems: 'center' }, currentPlanText: { color: '#FFFFFF', fontSize: 16, fontWeight: '600' }, benefitsCard: { borderRadius: 16, padding: 20, borderWidth: 1 }, benefitItem: { flexDirection: 'row', alignItems: 'flex-start', marginBottom: 20 }, benefitContent: { marginLeft: 16, flex: 1 }, benefitTitle: { fontSi