@oxyhq/services 5.4.4 → 5.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/lib/commonjs/core/index.js +81 -3
  2. package/lib/commonjs/core/index.js.map +1 -1
  3. package/lib/commonjs/index.js +50 -1
  4. package/lib/commonjs/index.js.map +1 -1
  5. package/lib/commonjs/ui/components/FollowButton.js +94 -31
  6. package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
  7. package/lib/commonjs/ui/components/OxySignInButton.js +2 -2
  8. package/lib/commonjs/ui/components/OxySignInButton.js.map +1 -1
  9. package/lib/commonjs/ui/context/OxyContext.js +11 -1
  10. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  11. package/lib/commonjs/ui/hooks/index.js +13 -0
  12. package/lib/commonjs/ui/hooks/index.js.map +1 -0
  13. package/lib/commonjs/ui/hooks/useFollow.js +203 -0
  14. package/lib/commonjs/ui/hooks/useFollow.js.map +1 -0
  15. package/lib/commonjs/ui/index.js +25 -1
  16. package/lib/commonjs/ui/index.js.map +1 -1
  17. package/lib/commonjs/ui/screens/AccountCenterScreen.js +4 -3
  18. package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
  19. package/lib/commonjs/ui/screens/AccountOverviewScreen.js +7 -6
  20. package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
  21. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +3 -2
  22. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  23. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +3 -2
  24. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
  25. package/lib/commonjs/ui/screens/AppInfoScreen.js +25 -45
  26. package/lib/commonjs/ui/screens/AppInfoScreen.js.map +1 -1
  27. package/lib/commonjs/ui/screens/FileManagementScreen.js +9 -27
  28. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  29. package/lib/commonjs/ui/screens/SignInScreen.js +1 -1
  30. package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
  31. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js +5 -4
  32. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
  33. package/lib/commonjs/ui/store/index.js +223 -4
  34. package/lib/commonjs/ui/store/index.js.map +1 -1
  35. package/lib/module/core/index.js +81 -3
  36. package/lib/module/core/index.js.map +1 -1
  37. package/lib/module/index.js +6 -2
  38. package/lib/module/index.js.map +1 -1
  39. package/lib/module/ui/components/FollowButton.js +95 -32
  40. package/lib/module/ui/components/FollowButton.js.map +1 -1
  41. package/lib/module/ui/components/OxySignInButton.js +2 -2
  42. package/lib/module/ui/components/OxySignInButton.js.map +1 -1
  43. package/lib/module/ui/context/OxyContext.js +11 -1
  44. package/lib/module/ui/context/OxyContext.js.map +1 -1
  45. package/lib/module/ui/hooks/index.js +4 -0
  46. package/lib/module/ui/hooks/index.js.map +1 -0
  47. package/lib/module/ui/hooks/useFollow.js +199 -0
  48. package/lib/module/ui/hooks/useFollow.js.map +1 -0
  49. package/lib/module/ui/index.js +9 -0
  50. package/lib/module/ui/index.js.map +1 -1
  51. package/lib/module/ui/screens/AccountCenterScreen.js +4 -3
  52. package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
  53. package/lib/module/ui/screens/AccountOverviewScreen.js +7 -6
  54. package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
  55. package/lib/module/ui/screens/AccountSettingsScreen.js +3 -2
  56. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  57. package/lib/module/ui/screens/AccountSwitcherScreen.js +3 -2
  58. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
  59. package/lib/module/ui/screens/AppInfoScreen.js +25 -45
  60. package/lib/module/ui/screens/AppInfoScreen.js.map +1 -1
  61. package/lib/module/ui/screens/FileManagementScreen.js +9 -27
  62. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  63. package/lib/module/ui/screens/SignInScreen.js +1 -1
  64. package/lib/module/ui/screens/SignInScreen.js.map +1 -1
  65. package/lib/module/ui/screens/karma/KarmaCenterScreen.js +5 -4
  66. package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
  67. package/lib/module/ui/store/index.js +219 -4
  68. package/lib/module/ui/store/index.js.map +1 -1
  69. package/lib/typescript/core/index.d.ts +44 -3
  70. package/lib/typescript/core/index.d.ts.map +1 -1
  71. package/lib/typescript/index.d.ts +4 -2
  72. package/lib/typescript/index.d.ts.map +1 -1
  73. package/lib/typescript/ui/components/FollowButton.d.ts +1 -0
  74. package/lib/typescript/ui/components/FollowButton.d.ts.map +1 -1
  75. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  76. package/lib/typescript/ui/hooks/index.d.ts +2 -0
  77. package/lib/typescript/ui/hooks/index.d.ts.map +1 -0
  78. package/lib/typescript/ui/hooks/useFollow.d.ts +43 -0
  79. package/lib/typescript/ui/hooks/useFollow.d.ts.map +1 -0
  80. package/lib/typescript/ui/index.d.ts +3 -0
  81. package/lib/typescript/ui/index.d.ts.map +1 -1
  82. package/lib/typescript/ui/screens/AccountCenterScreen.d.ts.map +1 -1
  83. package/lib/typescript/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
  84. package/lib/typescript/ui/screens/AppInfoScreen.d.ts.map +1 -1
  85. package/lib/typescript/ui/screens/FileManagementScreen.d.ts.map +1 -1
  86. package/lib/typescript/ui/store/index.d.ts +47 -0
  87. package/lib/typescript/ui/store/index.d.ts.map +1 -1
  88. package/package.json +1 -1
  89. package/src/core/index.ts +88 -3
  90. package/src/index.ts +19 -3
  91. package/src/ui/components/FollowButton.tsx +128 -56
  92. package/src/ui/components/OxySignInButton.tsx +2 -2
  93. package/src/ui/context/OxyContext.tsx +12 -2
  94. package/src/ui/hooks/index.ts +1 -0
  95. package/src/ui/hooks/useFollow.ts +193 -0
  96. package/src/ui/index.ts +9 -0
  97. package/src/ui/screens/AccountCenterScreen.tsx +17 -15
  98. package/src/ui/screens/AccountOverviewScreen.tsx +25 -25
  99. package/src/ui/screens/AccountSettingsScreen.tsx +30 -30
  100. package/src/ui/screens/AccountSwitcherScreen.tsx +34 -33
  101. package/src/ui/screens/AppInfoScreen.tsx +173 -192
  102. package/src/ui/screens/FileManagementScreen.tsx +248 -268
  103. package/src/ui/screens/SignInScreen.tsx +2 -2
  104. package/src/ui/screens/karma/KarmaCenterScreen.tsx +4 -4
  105. package/src/ui/store/index.ts +202 -3
@@ -0,0 +1,193 @@
1
+ import { useDispatch, useSelector } from 'react-redux';
2
+ import { useCallback, useMemo } from 'react';
3
+ import { toggleFollowUser, setFollowingStatus, clearFollowError, fetchFollowStatus } from '../store';
4
+ import type { RootState } from '../store';
5
+ import { useOxy } from '../context/OxyContext';
6
+
7
+ // Memoized selector to prevent unnecessary re-renders
8
+ const createFollowSelector = (userId: string) => (state: RootState) => ({
9
+ isFollowing: state.follow?.followingUsers?.[userId] ?? false,
10
+ isLoading: state.follow?.loadingUsers?.[userId] ?? false,
11
+ error: state.follow?.errors?.[userId] ?? null,
12
+ });
13
+
14
+ // Memoized selector for multiple users
15
+ const createMultipleFollowSelector = (userIds: string[]) => (state: RootState) => {
16
+ const followData: Record<string, { isFollowing: boolean; isLoading: boolean; error: string | null }> = {};
17
+ const followState = state.follow;
18
+
19
+ // Defensive check for follow state
20
+ if (!followState) {
21
+ // Return default values if follow state is not initialized
22
+ for (const userId of userIds) {
23
+ followData[userId] = {
24
+ isFollowing: false,
25
+ isLoading: false,
26
+ error: null,
27
+ };
28
+ }
29
+
30
+ return {
31
+ followData,
32
+ isAnyLoading: false,
33
+ hasAnyError: false,
34
+ allFollowing: false,
35
+ allNotFollowing: true,
36
+ };
37
+ }
38
+
39
+ for (const userId of userIds) {
40
+ followData[userId] = {
41
+ isFollowing: followState.followingUsers?.[userId] ?? false,
42
+ isLoading: followState.loadingUsers?.[userId] ?? false,
43
+ error: followState.errors?.[userId] ?? null,
44
+ };
45
+ }
46
+
47
+ return {
48
+ followData,
49
+ isAnyLoading: userIds.some(uid => followState.loadingUsers?.[uid]),
50
+ hasAnyError: userIds.some(uid => followState.errors?.[uid]),
51
+ allFollowing: userIds.every(uid => followState.followingUsers?.[uid]),
52
+ allNotFollowing: userIds.every(uid => !followState.followingUsers?.[uid]),
53
+ };
54
+ };
55
+
56
+ /**
57
+ * Custom hook for managing follow/unfollow functionality
58
+ * Optimized to prevent unnecessary re-renders
59
+ * Can handle both single user and multiple users
60
+ */
61
+ export const useFollow = (userId?: string | string[]) => {
62
+ const dispatch = useDispatch();
63
+ const { oxyServices } = useOxy();
64
+
65
+ // Memoize user IDs to prevent recreation on every render
66
+ const userIds = useMemo(() => {
67
+ return Array.isArray(userId) ? userId : userId ? [userId] : [];
68
+ }, [userId]);
69
+
70
+ const isSingleUser = typeof userId === 'string';
71
+
72
+ // Memoize selectors to prevent recreation
73
+ const singleUserSelector = useMemo(() => {
74
+ return isSingleUser && userId ? createFollowSelector(userId) : null;
75
+ }, [isSingleUser, userId]);
76
+
77
+ const multipleUserSelector = useMemo(() => {
78
+ return !isSingleUser ? createMultipleFollowSelector(userIds) : null;
79
+ }, [isSingleUser, userIds]);
80
+
81
+ // Use appropriate selector based on mode
82
+ const singleUserData = useSelector(singleUserSelector || (() => ({ isFollowing: false, isLoading: false, error: null })));
83
+ const multipleUserData = useSelector(multipleUserSelector || (() => ({
84
+ followData: {},
85
+ isAnyLoading: false,
86
+ hasAnyError: false,
87
+ allFollowing: false,
88
+ allNotFollowing: true
89
+ })));
90
+
91
+ // Memoized callbacks to prevent recreation on every render
92
+ const toggleFollow = useCallback(async () => {
93
+ if (!isSingleUser || !userId) throw new Error('toggleFollow is only available for single user mode');
94
+
95
+ try {
96
+ const result = await dispatch(toggleFollowUser({
97
+ userId,
98
+ oxyServices,
99
+ isCurrentlyFollowing: singleUserData.isFollowing
100
+ })).unwrap();
101
+ return result;
102
+ } catch (error) {
103
+ throw error;
104
+ }
105
+ }, [dispatch, userId, oxyServices, singleUserData.isFollowing, isSingleUser]);
106
+
107
+ const setFollowStatus = useCallback((following: boolean) => {
108
+ if (!isSingleUser || !userId) throw new Error('setFollowStatus is only available for single user mode');
109
+ dispatch(setFollowingStatus({ userId, isFollowing: following }));
110
+ }, [dispatch, userId, isSingleUser]);
111
+
112
+ const fetchStatus = useCallback(async () => {
113
+ if (!isSingleUser || !userId) throw new Error('fetchStatus is only available for single user mode');
114
+
115
+ try {
116
+ await dispatch(fetchFollowStatus({ userId, oxyServices })).unwrap();
117
+ } catch (error) {
118
+ console.warn(`Failed to fetch follow status for user ${userId}:`, error);
119
+ }
120
+ }, [dispatch, userId, oxyServices, isSingleUser]);
121
+
122
+ const clearError = useCallback(() => {
123
+ if (!isSingleUser || !userId) throw new Error('clearError is only available for single user mode');
124
+ dispatch(clearFollowError(userId));
125
+ }, [dispatch, userId, isSingleUser]);
126
+
127
+ // Multiple user callbacks
128
+ const toggleFollowForUser = useCallback(async (targetUserId: string) => {
129
+ const currentState = multipleUserData.followData[targetUserId]?.isFollowing ?? false;
130
+ try {
131
+ const result = await dispatch(toggleFollowUser({
132
+ userId: targetUserId,
133
+ oxyServices,
134
+ isCurrentlyFollowing: currentState
135
+ })).unwrap();
136
+ return result;
137
+ } catch (error) {
138
+ throw error;
139
+ }
140
+ }, [dispatch, oxyServices, multipleUserData.followData]);
141
+
142
+ const setFollowStatusForUser = useCallback((targetUserId: string, following: boolean) => {
143
+ dispatch(setFollowingStatus({ userId: targetUserId, isFollowing: following }));
144
+ }, [dispatch]);
145
+
146
+ const fetchStatusForUser = useCallback(async (targetUserId: string) => {
147
+ try {
148
+ await dispatch(fetchFollowStatus({ userId: targetUserId, oxyServices })).unwrap();
149
+ } catch (error) {
150
+ console.warn(`Failed to fetch follow status for user ${targetUserId}:`, error);
151
+ }
152
+ }, [dispatch, oxyServices]);
153
+
154
+ const fetchAllStatuses = useCallback(async () => {
155
+ const promises = userIds.map(uid =>
156
+ dispatch(fetchFollowStatus({ userId: uid, oxyServices })).unwrap().catch((error: any) => {
157
+ console.warn(`Failed to fetch follow status for user ${uid}:`, error);
158
+ })
159
+ );
160
+ await Promise.all(promises);
161
+ }, [dispatch, userIds, oxyServices]);
162
+
163
+ const clearErrorForUser = useCallback((targetUserId: string) => {
164
+ dispatch(clearFollowError(targetUserId));
165
+ }, [dispatch]);
166
+
167
+ // Return appropriate interface based on mode
168
+ if (isSingleUser && userId) {
169
+ return {
170
+ isFollowing: singleUserData.isFollowing,
171
+ isLoading: singleUserData.isLoading,
172
+ error: singleUserData.error,
173
+ toggleFollow,
174
+ setFollowStatus,
175
+ fetchStatus,
176
+ clearError,
177
+ };
178
+ }
179
+
180
+ return {
181
+ followData: multipleUserData.followData,
182
+ toggleFollowForUser,
183
+ setFollowStatusForUser,
184
+ fetchStatusForUser,
185
+ fetchAllStatuses,
186
+ clearErrorForUser,
187
+ // Helper methods
188
+ isAnyLoading: multipleUserData.isAnyLoading,
189
+ hasAnyError: multipleUserData.hasAnyError,
190
+ allFollowing: multipleUserData.allFollowing,
191
+ allNotFollowing: multipleUserData.allNotFollowing,
192
+ };
193
+ };
package/src/ui/index.ts CHANGED
@@ -30,3 +30,12 @@ export { fontFamilies, fontStyles } from './styles/fonts';
30
30
 
31
31
  // Export types for navigation (internal use)
32
32
  export * from './navigation/types';
33
+
34
+ // Hooks
35
+ export { useFollow } from './hooks';
36
+
37
+ // Screens
38
+ export { default as ProfileScreen } from './screens/ProfileScreen';
39
+
40
+ // Navigation
41
+ export { default as OxyRouter } from './navigation/OxyRouter';
@@ -15,12 +15,12 @@ import { packageInfo } from '../../constants/version';
15
15
  import { toast } from '../../lib/sonner';
16
16
  import { Ionicons } from '@expo/vector-icons';
17
17
  import { fontFamilies } from '../styles/fonts';
18
- import {
19
- ProfileCard,
20
- Section,
21
- QuickActions,
22
- GroupedSection,
23
- GroupedItem
18
+ import {
19
+ ProfileCard,
20
+ Section,
21
+ QuickActions,
22
+ GroupedSection,
23
+ GroupedItem
24
24
  } from '../components';
25
25
 
26
26
  const AccountCenterScreen: React.FC<BaseScreenProps> = ({
@@ -28,7 +28,7 @@ const AccountCenterScreen: React.FC<BaseScreenProps> = ({
28
28
  theme,
29
29
  navigate,
30
30
  }) => {
31
- const { user, logout, isLoading, sessions } = useOxy();
31
+ const { user, logout, isLoading, sessions, isAuthenticated } = useOxy();
32
32
 
33
33
  const isDarkTheme = theme === 'dark';
34
34
  const textColor = isDarkTheme ? '#FFFFFF' : '#000000';
@@ -69,7 +69,7 @@ const AccountCenterScreen: React.FC<BaseScreenProps> = ({
69
69
  );
70
70
  };
71
71
 
72
- if (!user) {
72
+ if (!isAuthenticated) {
73
73
  return (
74
74
  <View style={[styles.container, { backgroundColor }]}>
75
75
  <Text style={[styles.message, { color: textColor }]}>Not signed in</Text>
@@ -88,13 +88,15 @@ const AccountCenterScreen: React.FC<BaseScreenProps> = ({
88
88
  return (
89
89
  <View style={[styles.container, { backgroundColor }]}>
90
90
  {/* Header with user profile */}
91
- <ProfileCard
92
- user={user}
93
- theme={theme}
94
- onEditPress={() => navigate('AccountSettings', { activeTab: 'profile' })}
95
- onClosePress={onClose}
96
- showCloseButton={!!onClose}
97
- />
91
+ {user && (
92
+ <ProfileCard
93
+ user={user}
94
+ theme={theme}
95
+ onEditPress={() => navigate('AccountSettings', { activeTab: 'profile' })}
96
+ onClosePress={onClose}
97
+ showCloseButton={!!onClose}
98
+ />
99
+ )}
98
100
 
99
101
  <ScrollView style={styles.scrollView} contentContainerStyle={styles.scrollContainer} showsVerticalScrollIndicator={false}>
100
102
  {/* Quick Actions */}
@@ -34,7 +34,7 @@ const AccountOverviewScreen: React.FC<BaseScreenProps> = ({
34
34
  theme,
35
35
  navigate,
36
36
  }) => {
37
- const { user, logout, isLoading, sessions, activeSessionId, oxyServices } = useOxy();
37
+ const { user, logout, isLoading, sessions, activeSessionId, oxyServices, isAuthenticated } = useOxy();
38
38
  const [showMoreAccounts, setShowMoreAccounts] = useState(false);
39
39
  const [additionalAccountsData, setAdditionalAccountsData] = useState<any[]>([]);
40
40
  const [loadingAdditionalAccounts, setLoadingAdditionalAccounts] = useState(false);
@@ -55,8 +55,8 @@ const AccountOverviewScreen: React.FC<BaseScreenProps> = ({
55
55
  }, [theme]);
56
56
 
57
57
  // Memoize additional accounts filtering to prevent recalculation on every render
58
- const additionalAccounts = useMemo(() =>
59
- sessions.filter(session =>
58
+ const additionalAccounts = useMemo(() =>
59
+ sessions.filter(session =>
60
60
  session.sessionId !== activeSessionId && session.userId !== user?.id
61
61
  ), [sessions, activeSessionId, user?.id]
62
62
  );
@@ -170,7 +170,7 @@ const AccountOverviewScreen: React.FC<BaseScreenProps> = ({
170
170
  );
171
171
  }, [handleLogout]);
172
172
 
173
- if (!user) {
173
+ if (!isAuthenticated) {
174
174
  return (
175
175
  <View style={[styles.container, { backgroundColor: themeStyles.backgroundColor }]}>
176
176
  <Text style={[styles.message, { color: themeStyles.textColor }]}>Not signed in</Text>
@@ -202,7 +202,7 @@ const AccountOverviewScreen: React.FC<BaseScreenProps> = ({
202
202
  {/* User Profile Section */}
203
203
  <View style={styles.section}>
204
204
  <Text style={styles.sectionTitle}>Profile</Text>
205
-
205
+
206
206
  <View style={[styles.settingItem, styles.firstSettingItem, styles.lastSettingItem]}>
207
207
  <View style={styles.userIcon}>
208
208
  <Avatar
@@ -215,9 +215,9 @@ const AccountOverviewScreen: React.FC<BaseScreenProps> = ({
215
215
  <View style={styles.settingInfo}>
216
216
  <View>
217
217
  <Text style={styles.settingLabel}>
218
- {typeof user.name === 'string' ? user.name : user.name?.full || user.name?.first || user.username}
218
+ {user ? (typeof user.name === 'string' ? user.name : user.name?.full || user.name?.first || user.username) : 'Loading...'}
219
219
  </Text>
220
- <Text style={styles.settingDescription}>{user.email || user.username}</Text>
220
+ <Text style={styles.settingDescription}>{user ? (user.email || user.username) : 'Loading...'}</Text>
221
221
  </View>
222
222
  </View>
223
223
  <TouchableOpacity
@@ -232,8 +232,8 @@ const AccountOverviewScreen: React.FC<BaseScreenProps> = ({
232
232
  {/* Account Settings */}
233
233
  <View style={styles.section}>
234
234
  <Text style={styles.sectionTitle}>Account Settings</Text>
235
-
236
- <TouchableOpacity
235
+
236
+ <TouchableOpacity
237
237
  style={[styles.settingItem, styles.firstSettingItem]}
238
238
  onPress={() => navigate?.('AccountSettings', { activeTab: 'profile' })}
239
239
  >
@@ -247,7 +247,7 @@ const AccountOverviewScreen: React.FC<BaseScreenProps> = ({
247
247
  <OxyIcon name="chevron-forward" size={16} color="#ccc" />
248
248
  </TouchableOpacity>
249
249
 
250
- <TouchableOpacity
250
+ <TouchableOpacity
251
251
  style={styles.settingItem}
252
252
  onPress={() => navigate?.('AccountSettings', { activeTab: 'password' })}
253
253
  >
@@ -261,7 +261,7 @@ const AccountOverviewScreen: React.FC<BaseScreenProps> = ({
261
261
  <OxyIcon name="chevron-forward" size={16} color="#ccc" />
262
262
  </TouchableOpacity>
263
263
 
264
- <TouchableOpacity
264
+ <TouchableOpacity
265
265
  style={styles.settingItem}
266
266
  onPress={() => navigate?.('AccountSettings', { activeTab: 'notifications' })}
267
267
  >
@@ -275,7 +275,7 @@ const AccountOverviewScreen: React.FC<BaseScreenProps> = ({
275
275
  <OxyIcon name="chevron-forward" size={16} color="#ccc" />
276
276
  </TouchableOpacity>
277
277
 
278
- <TouchableOpacity
278
+ <TouchableOpacity
279
279
  style={[styles.settingItem]}
280
280
  onPress={() => navigate?.('PremiumSubscription')}
281
281
  >
@@ -283,14 +283,14 @@ const AccountOverviewScreen: React.FC<BaseScreenProps> = ({
283
283
  <OxyIcon name="star" size={20} color="#FFD700" style={styles.settingIcon} />
284
284
  <View>
285
285
  <Text style={styles.settingLabel}>Oxy+ Subscriptions</Text>
286
- <Text style={styles.settingDescription}>{user.isPremium ? 'Manage your premium plan' : 'Upgrade to premium features'}</Text>
286
+ <Text style={styles.settingDescription}>{user?.isPremium ? 'Manage your premium plan' : 'Upgrade to premium features'}</Text>
287
287
  </View>
288
288
  </View>
289
289
  <OxyIcon name="chevron-forward" size={16} color="#ccc" />
290
290
  </TouchableOpacity>
291
291
 
292
- {user.isPremium && (
293
- <TouchableOpacity
292
+ {user?.isPremium && (
293
+ <TouchableOpacity
294
294
  style={[styles.settingItem, styles.lastSettingItem]}
295
295
  onPress={() => navigate?.('BillingManagement')}
296
296
  >
@@ -310,7 +310,7 @@ const AccountOverviewScreen: React.FC<BaseScreenProps> = ({
310
310
  {showMoreAccounts && (
311
311
  <View style={styles.section}>
312
312
  <Text style={styles.sectionTitle}>Additional Accounts{additionalAccountsData.length > 0 ? ` (${additionalAccountsData.length})` : ''}</Text>
313
-
313
+
314
314
  {loadingAdditionalAccounts ? (
315
315
  <View style={[styles.settingItem, styles.firstSettingItem, styles.lastSettingItem]}>
316
316
  <View style={styles.loadingContainer}>
@@ -324,7 +324,7 @@ const AccountOverviewScreen: React.FC<BaseScreenProps> = ({
324
324
  <TouchableOpacity
325
325
  key={account.id}
326
326
  style={[
327
- styles.settingItem,
327
+ styles.settingItem,
328
328
  index === 0 && styles.firstSettingItem,
329
329
  index === additionalAccountsData.length - 1 && styles.lastSettingItem
330
330
  ]}
@@ -348,7 +348,7 @@ const AccountOverviewScreen: React.FC<BaseScreenProps> = ({
348
348
  <View style={styles.settingInfo}>
349
349
  <View>
350
350
  <Text style={styles.settingLabel}>
351
- {typeof account.name === 'object'
351
+ {typeof account.name === 'object'
352
352
  ? account.name?.full || account.name?.first || account.username
353
353
  : account.name || account.username
354
354
  }
@@ -378,7 +378,7 @@ const AccountOverviewScreen: React.FC<BaseScreenProps> = ({
378
378
  {showMoreAccounts && (
379
379
  <View style={styles.section}>
380
380
  <Text style={styles.sectionTitle}>Account Management</Text>
381
-
381
+
382
382
  <TouchableOpacity
383
383
  style={[styles.settingItem, styles.firstSettingItem]}
384
384
  onPress={handleAddAccount}
@@ -412,7 +412,7 @@ const AccountOverviewScreen: React.FC<BaseScreenProps> = ({
412
412
  {/* Quick Actions */}
413
413
  <View style={styles.section}>
414
414
  <Text style={styles.sectionTitle}>Quick Actions</Text>
415
-
415
+
416
416
  <TouchableOpacity
417
417
  style={[styles.settingItem, styles.firstSettingItem]}
418
418
  onPress={() => setShowMoreAccounts(!showMoreAccounts)}
@@ -424,9 +424,9 @@ const AccountOverviewScreen: React.FC<BaseScreenProps> = ({
424
424
  {showMoreAccounts ? 'Hide' : 'Show'} Account Switcher
425
425
  </Text>
426
426
  <Text style={styles.settingDescription}>
427
- {showMoreAccounts
428
- ? 'Hide account switcher'
429
- : additionalAccountsData.length > 0
427
+ {showMoreAccounts
428
+ ? 'Hide account switcher'
429
+ : additionalAccountsData.length > 0
430
430
  ? `Switch between ${additionalAccountsData.length + 1} accounts`
431
431
  : loadingAdditionalAccounts
432
432
  ? 'Loading additional accounts...'
@@ -470,7 +470,7 @@ const AccountOverviewScreen: React.FC<BaseScreenProps> = ({
470
470
  {/* Support & Settings */}
471
471
  <View style={styles.section}>
472
472
  <Text style={styles.sectionTitle}>Support & Settings</Text>
473
-
473
+
474
474
  <TouchableOpacity
475
475
  style={[styles.settingItem, styles.firstSettingItem]}
476
476
  onPress={() => toast.info('Account preferences coming soon!')}
@@ -544,7 +544,7 @@ const AccountOverviewScreen: React.FC<BaseScreenProps> = ({
544
544
 
545
545
  {/* Sign Out */}
546
546
  <View style={styles.section}>
547
- <TouchableOpacity
547
+ <TouchableOpacity
548
548
  style={[styles.settingItem, styles.firstSettingItem, styles.lastSettingItem, styles.signOutButton]}
549
549
  onPress={confirmLogout}
550
550
  >
@@ -24,7 +24,7 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
24
24
  goBack,
25
25
  navigate,
26
26
  }) => {
27
- const { user, oxyServices, isLoading: authLoading } = useOxy();
27
+ const { user, oxyServices, isLoading: authLoading, isAuthenticated } = useOxy();
28
28
  const [isLoading, setIsLoading] = useState(false);
29
29
  const [isSaving, setIsSaving] = useState(false);
30
30
 
@@ -74,10 +74,10 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
74
74
  // Load user data
75
75
  useEffect(() => {
76
76
  if (user) {
77
- const userDisplayName = typeof user.name === 'string'
78
- ? user.name
77
+ const userDisplayName = typeof user.name === 'string'
78
+ ? user.name
79
79
  : user.name?.full || user.name?.first || '';
80
-
80
+
81
81
  setDisplayName(userDisplayName);
82
82
  setUsername(user.username || '');
83
83
  setEmail(user.email || '');
@@ -115,9 +115,9 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
115
115
 
116
116
  await oxyServices.updateProfile(updates);
117
117
  toast.success('Profile updated successfully');
118
-
118
+
119
119
  animateSaveButton(1); // Scale back to normal
120
-
120
+
121
121
  if (onClose) {
122
122
  onClose();
123
123
  } else if (goBack) {
@@ -182,7 +182,7 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
182
182
 
183
183
  const saveField = (type: string) => {
184
184
  animateSaveButton(0.95); // Scale down slightly for animation
185
-
185
+
186
186
  switch (type) {
187
187
  case 'displayName':
188
188
  setDisplayName(tempDisplayName);
@@ -203,7 +203,7 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
203
203
  setWebsite(tempWebsite);
204
204
  break;
205
205
  }
206
-
206
+
207
207
  // Brief delay for animation, then reset and close editing
208
208
  setTimeout(() => {
209
209
  animateSaveButton(1);
@@ -263,7 +263,7 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
263
263
  default: return '';
264
264
  }
265
265
  })();
266
-
266
+
267
267
  const setTempValue = (text: string) => {
268
268
  switch (type) {
269
269
  case 'displayName': setTempDisplayName(text); break;
@@ -285,7 +285,7 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
285
285
  <TextInput
286
286
  style={[
287
287
  config.multiline ? styles.editingFieldTextArea : styles.editingFieldInput,
288
- {
288
+ {
289
289
  backgroundColor: themeStyles.isDarkTheme ? '#333' : '#fff',
290
290
  color: themeStyles.isDarkTheme ? '#fff' : '#000',
291
291
  borderColor: themeStyles.primaryColor
@@ -326,7 +326,7 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
326
326
  ];
327
327
 
328
328
  return (
329
- <TouchableOpacity
329
+ <TouchableOpacity
330
330
  style={itemStyles}
331
331
  onPress={() => startEditing(type, value)}
332
332
  >
@@ -344,7 +344,7 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
344
344
  );
345
345
  };
346
346
 
347
- if (authLoading || !user) {
347
+ if (authLoading || !isAuthenticated) {
348
348
  return (
349
349
  <View style={[styles.container, { backgroundColor: themeStyles.backgroundColor, justifyContent: 'center' }]}>
350
350
  <ActivityIndicator size="large" color={themeStyles.primaryColor} />
@@ -363,14 +363,14 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
363
363
  <Ionicons name="close" size={24} color="#666" />
364
364
  </TouchableOpacity>
365
365
  <Animated.View style={{ transform: [{ scale: saveButtonScale }] }}>
366
- <TouchableOpacity
366
+ <TouchableOpacity
367
367
  style={[
368
- styles.saveHeaderButton,
369
- {
368
+ styles.saveHeaderButton,
369
+ {
370
370
  opacity: isSaving ? 0.7 : 1,
371
371
  backgroundColor: editingField ? getFieldIcon(editingField).color : '#007AFF'
372
372
  }
373
- ]}
373
+ ]}
374
374
  onPress={() => saveField(editingField)}
375
375
  disabled={isSaving}
376
376
  >
@@ -384,11 +384,11 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
384
384
  </View>
385
385
  <View style={styles.editingHeaderBottom}>
386
386
  <View style={styles.headerTitleWithIcon}>
387
- <OxyIcon
388
- name={getFieldIcon(editingField).name}
389
- size={50}
390
- color={getFieldIcon(editingField).color}
391
- style={styles.headerIcon}
387
+ <OxyIcon
388
+ name={getFieldIcon(editingField).name}
389
+ size={50}
390
+ color={getFieldIcon(editingField).color}
391
+ style={styles.headerIcon}
392
392
  />
393
393
  <Text style={styles.headerTitleLarge}>{getFieldLabel(editingField)}</Text>
394
394
  </View>
@@ -401,8 +401,8 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
401
401
  </TouchableOpacity>
402
402
  <Text style={styles.headerTitle}>Account Settings</Text>
403
403
  <Animated.View style={{ transform: [{ scale: saveButtonScale }] }}>
404
- <TouchableOpacity
405
- style={[styles.saveIconButton, { opacity: isSaving ? 0.7 : 1 }]}
404
+ <TouchableOpacity
405
+ style={[styles.saveIconButton, { opacity: isSaving ? 0.7 : 1 }]}
406
406
  onPress={handleSave}
407
407
  disabled={isSaving}
408
408
  >
@@ -429,8 +429,8 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
429
429
  {/* Profile Picture Section */}
430
430
  <View style={styles.section}>
431
431
  <Text style={styles.sectionTitle}>Profile Picture</Text>
432
-
433
- <TouchableOpacity
432
+
433
+ <TouchableOpacity
434
434
  style={[styles.settingItem, styles.firstSettingItem, styles.lastSettingItem]}
435
435
  onPress={handleAvatarUpdate}
436
436
  >
@@ -457,7 +457,7 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
457
457
  {/* Basic Information */}
458
458
  <View style={styles.section}>
459
459
  <Text style={styles.sectionTitle}>Basic Information</Text>
460
-
460
+
461
461
  {renderField(
462
462
  'displayName',
463
463
  'Display Name',
@@ -501,7 +501,7 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
501
501
  {/* About You */}
502
502
  <View style={styles.section}>
503
503
  <Text style={styles.sectionTitle}>About You</Text>
504
-
504
+
505
505
  {renderField(
506
506
  'bio',
507
507
  'Bio',
@@ -545,8 +545,8 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
545
545
  {/* Quick Actions */}
546
546
  <View style={styles.section}>
547
547
  <Text style={styles.sectionTitle}>Quick Actions</Text>
548
-
549
- <TouchableOpacity
548
+
549
+ <TouchableOpacity
550
550
  style={[styles.settingItem, styles.firstSettingItem]}
551
551
  onPress={() => toast.info('Privacy settings coming soon!')}
552
552
  >
@@ -560,7 +560,7 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
560
560
  <OxyIcon name="chevron-forward" size={16} color="#ccc" />
561
561
  </TouchableOpacity>
562
562
 
563
- <TouchableOpacity
563
+ <TouchableOpacity
564
564
  style={[styles.settingItem, styles.lastSettingItem]}
565
565
  onPress={() => toast.info('Account verification coming soon!')}
566
566
  >