index.tsx 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. import React, { useEffect, useState } from 'react';
  2. import { View, Text, StyleSheet, TouchableOpacity, ActivityIndicator, Linking, Platform } from 'react-native';
  3. import { AntDesign } from '@expo/vector-icons';
  4. import { useNavigation } from '@react-navigation/native';
  5. import { storage, StoreType } from 'src/storage';
  6. import { fetchPremiumStatus } from '@api/app';
  7. import { Colors } from 'src/theme';
  8. import * as IAP from 'expo-iap';
  9. import { SafeAreaView } from 'react-native-safe-area-context';
  10. import { API_HOST } from 'src/constants';
  11. const ManageSubscriptionScreen = () => {
  12. const navigation = useNavigation();
  13. const [loading, setLoading] = useState(true);
  14. const [validUntil, setValidUntil] = useState<string | null>(null);
  15. const [subSource, setSubSource] = useState<string>('web');
  16. useEffect(() => {
  17. const loadStatus = async () => {
  18. try {
  19. const token = storage.get('token', StoreType.STRING) as string;
  20. if (token) {
  21. const status = await fetchPremiumStatus(token);
  22. if (status?.data) {
  23. setValidUntil(status.data.end_date || status.data.next_payment || null);
  24. setSubSource(status.platform || 'web');
  25. }
  26. }
  27. } catch (err) {
  28. console.warn('Failed to fetch premium status on manage screen:', err);
  29. } finally {
  30. setLoading(false);
  31. }
  32. };
  33. loadStatus();
  34. }, []);
  35. const handleManage = async () => {
  36. if (subSource === 'wp') {
  37. Linking.openURL(API_HOST + '/my-account/subscriptions/').catch(err =>
  38. console.error('Failed to open WP subscription URL:', err)
  39. );
  40. } else if (subSource === 'apple' || subSource === 'google') {
  41. try {
  42. if (IAP.deepLinkToSubscriptions) {
  43. await IAP.deepLinkToSubscriptions();
  44. } else {
  45. if (Platform.OS === 'ios') {
  46. Linking.openURL('https://apps.apple.com/account/subscriptions');
  47. } else {
  48. Linking.openURL('https://play.google.com/store/account/subscriptions');
  49. }
  50. }
  51. } catch (e) {
  52. console.error('Deep link to subscriptions failed', e);
  53. }
  54. } else {
  55. if (Platform.OS === 'ios') {
  56. Linking.openURL('https://apps.apple.com/account/subscriptions');
  57. } else {
  58. Linking.openURL('https://play.google.com/store/account/subscriptions');
  59. }
  60. }
  61. };
  62. return (
  63. <SafeAreaView style={styles.safeArea} edges={['bottom', 'left', 'right']}>
  64. <View style={styles.container}>
  65. <TouchableOpacity style={styles.closeButton} onPress={() => navigation.goBack()}>
  66. <AntDesign name="close" size={20} color={Colors.LIGHT_GRAY} />
  67. </TouchableOpacity>
  68. <Text style={styles.title}>Manage Subscription</Text>
  69. <Text style={styles.subtitle}>Review your subscription details</Text>
  70. <View style={styles.detailsContainer}>
  71. {loading ? (
  72. <ActivityIndicator size="large" color={Colors.DARK_BLUE} />
  73. ) : (
  74. <View>
  75. <Text style={styles.infoLabel}>Status:</Text>
  76. <Text style={styles.infoValue}>Active</Text>
  77. <View style={styles.separator} />
  78. <Text style={styles.infoLabel}>Valid Until / Next Payment:</Text>
  79. <Text style={styles.infoValue}>{validUntil || 'Lifetime / Unknown'}</Text>
  80. <View style={styles.separator} />
  81. <Text style={styles.infoLabel}>Source:</Text>
  82. <Text style={styles.infoValue}>
  83. {subSource === 'wp' ? 'Website' :
  84. subSource === 'apple' ? 'App Store' :
  85. subSource === 'google' ? 'Google Play' : 'Unknown'}
  86. </Text>
  87. </View>
  88. )}
  89. </View>
  90. {!loading && (
  91. <TouchableOpacity style={styles.manageButton} onPress={handleManage}>
  92. <Text style={styles.manageButtonText}>Manage Subscription</Text>
  93. </TouchableOpacity>
  94. )}
  95. </View>
  96. </SafeAreaView>
  97. );
  98. };
  99. const styles = StyleSheet.create({
  100. safeArea: {
  101. flex: 1,
  102. backgroundColor: Colors.WHITE,
  103. },
  104. container: {
  105. flex: 1,
  106. padding: 16,
  107. backgroundColor: Colors.WHITE,
  108. },
  109. closeButton: {
  110. alignSelf: 'flex-start',
  111. padding: 5,
  112. },
  113. title: {
  114. fontSize: 20,
  115. fontFamily: 'montserrat-700',
  116. color: Colors.DARK_BLUE,
  117. marginBottom: 8,
  118. textAlign: 'center',
  119. },
  120. subtitle: {
  121. fontSize: 14,
  122. fontWeight: '600',
  123. color: Colors.DARK_BLUE,
  124. textAlign: 'center',
  125. marginBottom: 20,
  126. },
  127. detailsContainer: {
  128. backgroundColor: Colors.FILL_LIGHT,
  129. borderWidth: 1,
  130. borderColor: Colors.LIGHT_GRAY,
  131. borderRadius: 12,
  132. padding: 16,
  133. marginBottom: 30,
  134. },
  135. infoLabel: {
  136. fontSize: 14,
  137. color: Colors.TEXT_GRAY,
  138. fontFamily: 'montserrat-600',
  139. marginBottom: 4,
  140. },
  141. infoValue: {
  142. fontSize: 16,
  143. fontWeight: 'bold',
  144. color: Colors.DARK_BLUE,
  145. },
  146. separator: {
  147. height: 1,
  148. backgroundColor: Colors.LIGHT_GRAY,
  149. marginVertical: 15,
  150. },
  151. manageButton: {
  152. backgroundColor: Colors.WHITE,
  153. borderWidth: 1,
  154. borderColor: Colors.ORANGE,
  155. padding: 15,
  156. borderRadius: 8,
  157. alignItems: 'center',
  158. },
  159. manageButtonText: {
  160. color: Colors.ORANGE,
  161. fontSize: 16,
  162. fontWeight: 'bold',
  163. },
  164. });
  165. export default ManageSubscriptionScreen;