@oxyhq/services 5.16.17 → 5.16.18

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 (227) hide show
  1. package/lib/commonjs/core/mixins/OxyServices.security.js +42 -0
  2. package/lib/commonjs/core/mixins/OxyServices.security.js.map +1 -1
  3. package/lib/commonjs/models/interfaces.js +2 -0
  4. package/lib/commonjs/models/interfaces.js.map +1 -1
  5. package/lib/commonjs/ui/components/FollowButton.js +19 -1
  6. package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
  7. package/lib/commonjs/ui/components/GroupedItem.js +1 -27
  8. package/lib/commonjs/ui/components/GroupedItem.js.map +1 -1
  9. package/lib/commonjs/ui/components/Section.js +2 -1
  10. package/lib/commonjs/ui/components/Section.js.map +1 -1
  11. package/lib/commonjs/ui/components/SectionTitle.js +1 -2
  12. package/lib/commonjs/ui/components/SectionTitle.js.map +1 -1
  13. package/lib/commonjs/ui/components/fileManagement/FileViewer.js +3 -3
  14. package/lib/commonjs/ui/components/fileManagement/FileViewer.js.map +1 -1
  15. package/lib/commonjs/ui/context/OxyContext.js +44 -6
  16. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  17. package/lib/commonjs/ui/context/hooks/useAuthOperations.js +9 -2
  18. package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
  19. package/lib/commonjs/ui/context/hooks/useDeviceManagement.js +1 -1
  20. package/lib/commonjs/ui/context/hooks/useLanguageManagement.js +1 -1
  21. package/lib/commonjs/ui/context/hooks/useSessionManagement.js +3 -3
  22. package/lib/commonjs/ui/context/hooks/useStorage.js +2 -2
  23. package/lib/commonjs/ui/hooks/queries/useAccountQueries.js +1 -1
  24. package/lib/commonjs/ui/hooks/queries/useAccountQueries.js.map +1 -1
  25. package/lib/commonjs/ui/hooks/queries/useServicesQueries.js +1 -1
  26. package/lib/commonjs/ui/hooks/useSessionSocket.js +22 -7
  27. package/lib/commonjs/ui/hooks/useSessionSocket.js.map +1 -1
  28. package/lib/commonjs/ui/screens/AccountCenterScreen.js +13 -13
  29. package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
  30. package/lib/commonjs/ui/screens/AccountOverviewScreen.js +17 -17
  31. package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
  32. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +2 -2
  33. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  34. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +10 -9
  35. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
  36. package/lib/commonjs/ui/screens/AppInfoScreen.js +15 -15
  37. package/lib/commonjs/ui/screens/AppInfoScreen.js.map +1 -1
  38. package/lib/commonjs/ui/screens/FeedbackScreen.js +1 -1
  39. package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
  40. package/lib/commonjs/ui/screens/FileManagementScreen.js +1 -1
  41. package/lib/commonjs/ui/screens/HelpSupportScreen.js +3 -3
  42. package/lib/commonjs/ui/screens/HelpSupportScreen.js.map +1 -1
  43. package/lib/commonjs/ui/screens/HistoryViewScreen.js +2 -2
  44. package/lib/commonjs/ui/screens/HistoryViewScreen.js.map +1 -1
  45. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +3 -1
  46. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
  47. package/lib/commonjs/ui/screens/LegalDocumentsScreen.js +4 -4
  48. package/lib/commonjs/ui/screens/LegalDocumentsScreen.js.map +1 -1
  49. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +1 -1
  50. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js.map +1 -1
  51. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js +1 -2
  52. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  53. package/lib/commonjs/ui/screens/ProfileScreen.js +44 -16
  54. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
  55. package/lib/commonjs/ui/screens/SavesCollectionsScreen.js.map +1 -1
  56. package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js +3 -1
  57. package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js.map +1 -1
  58. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js +2 -2
  59. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
  60. package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js +8 -5
  61. package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
  62. package/lib/commonjs/ui/utils/errorHandlers.js +49 -2
  63. package/lib/commonjs/ui/utils/errorHandlers.js.map +1 -1
  64. package/lib/commonjs/ui/utils/sessionHelpers.js +0 -2
  65. package/lib/commonjs/ui/utils/sessionHelpers.js.map +1 -1
  66. package/lib/commonjs/utils/languageUtils.js +11 -11
  67. package/lib/commonjs/utils/languageUtils.js.map +1 -1
  68. package/lib/module/core/mixins/OxyServices.security.js +42 -0
  69. package/lib/module/core/mixins/OxyServices.security.js.map +1 -1
  70. package/lib/module/models/interfaces.js +2 -0
  71. package/lib/module/models/interfaces.js.map +1 -1
  72. package/lib/module/ui/components/FollowButton.js +19 -1
  73. package/lib/module/ui/components/FollowButton.js.map +1 -1
  74. package/lib/module/ui/components/GroupedItem.js +1 -29
  75. package/lib/module/ui/components/GroupedItem.js.map +1 -1
  76. package/lib/module/ui/components/Section.js +2 -1
  77. package/lib/module/ui/components/Section.js.map +1 -1
  78. package/lib/module/ui/components/SectionTitle.js +1 -2
  79. package/lib/module/ui/components/SectionTitle.js.map +1 -1
  80. package/lib/module/ui/components/fileManagement/FileViewer.js +3 -3
  81. package/lib/module/ui/components/fileManagement/FileViewer.js.map +1 -1
  82. package/lib/module/ui/context/OxyContext.js +45 -7
  83. package/lib/module/ui/context/OxyContext.js.map +1 -1
  84. package/lib/module/ui/context/hooks/useAuthOperations.js +9 -2
  85. package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
  86. package/lib/module/ui/context/hooks/useDeviceManagement.js +1 -1
  87. package/lib/module/ui/context/hooks/useDeviceManagement.js.map +1 -1
  88. package/lib/module/ui/context/hooks/useLanguageManagement.js +1 -1
  89. package/lib/module/ui/context/hooks/useLanguageManagement.js.map +1 -1
  90. package/lib/module/ui/context/hooks/useSessionManagement.js +3 -3
  91. package/lib/module/ui/context/hooks/useSessionManagement.js.map +1 -1
  92. package/lib/module/ui/context/hooks/useStorage.js +2 -2
  93. package/lib/module/ui/context/hooks/useStorage.js.map +1 -1
  94. package/lib/module/ui/hooks/queries/useAccountQueries.js +1 -1
  95. package/lib/module/ui/hooks/queries/useAccountQueries.js.map +1 -1
  96. package/lib/module/ui/hooks/queries/useServicesQueries.js +1 -1
  97. package/lib/module/ui/hooks/queries/useServicesQueries.js.map +1 -1
  98. package/lib/module/ui/hooks/useSessionSocket.js +22 -7
  99. package/lib/module/ui/hooks/useSessionSocket.js.map +1 -1
  100. package/lib/module/ui/screens/AccountCenterScreen.js +13 -13
  101. package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
  102. package/lib/module/ui/screens/AccountOverviewScreen.js +17 -17
  103. package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
  104. package/lib/module/ui/screens/AccountSettingsScreen.js +2 -2
  105. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  106. package/lib/module/ui/screens/AccountSwitcherScreen.js +11 -10
  107. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
  108. package/lib/module/ui/screens/AppInfoScreen.js +15 -15
  109. package/lib/module/ui/screens/AppInfoScreen.js.map +1 -1
  110. package/lib/module/ui/screens/FeedbackScreen.js +1 -1
  111. package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
  112. package/lib/module/ui/screens/FileManagementScreen.js +1 -1
  113. package/lib/module/ui/screens/HelpSupportScreen.js +3 -3
  114. package/lib/module/ui/screens/HelpSupportScreen.js.map +1 -1
  115. package/lib/module/ui/screens/HistoryViewScreen.js +2 -2
  116. package/lib/module/ui/screens/HistoryViewScreen.js.map +1 -1
  117. package/lib/module/ui/screens/LanguageSelectorScreen.js +4 -2
  118. package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
  119. package/lib/module/ui/screens/LegalDocumentsScreen.js +4 -4
  120. package/lib/module/ui/screens/LegalDocumentsScreen.js.map +1 -1
  121. package/lib/module/ui/screens/PaymentGatewayScreen.js +1 -1
  122. package/lib/module/ui/screens/PaymentGatewayScreen.js.map +1 -1
  123. package/lib/module/ui/screens/PremiumSubscriptionScreen.js +1 -2
  124. package/lib/module/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  125. package/lib/module/ui/screens/ProfileScreen.js +44 -16
  126. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  127. package/lib/module/ui/screens/SavesCollectionsScreen.js.map +1 -1
  128. package/lib/module/ui/screens/karma/KarmaAboutScreen.js +3 -1
  129. package/lib/module/ui/screens/karma/KarmaAboutScreen.js.map +1 -1
  130. package/lib/module/ui/screens/karma/KarmaCenterScreen.js +3 -3
  131. package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
  132. package/lib/module/ui/screens/karma/KarmaRewardsScreen.js +9 -6
  133. package/lib/module/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
  134. package/lib/module/ui/utils/errorHandlers.js +46 -0
  135. package/lib/module/ui/utils/errorHandlers.js.map +1 -1
  136. package/lib/module/ui/utils/sessionHelpers.js +0 -2
  137. package/lib/module/ui/utils/sessionHelpers.js.map +1 -1
  138. package/lib/module/utils/languageUtils.js +11 -11
  139. package/lib/module/utils/languageUtils.js.map +1 -1
  140. package/lib/typescript/core/mixins/OxyServices.security.d.ts +12 -0
  141. package/lib/typescript/core/mixins/OxyServices.security.d.ts.map +1 -1
  142. package/lib/typescript/core/mixins/index.d.ts +2 -0
  143. package/lib/typescript/core/mixins/index.d.ts.map +1 -1
  144. package/lib/typescript/models/interfaces.d.ts +1 -1
  145. package/lib/typescript/models/interfaces.d.ts.map +1 -1
  146. package/lib/typescript/ui/components/FollowButton.d.ts.map +1 -1
  147. package/lib/typescript/ui/components/GroupedItem.d.ts.map +1 -1
  148. package/lib/typescript/ui/components/Section.d.ts.map +1 -1
  149. package/lib/typescript/ui/components/SectionTitle.d.ts.map +1 -1
  150. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  151. package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts +1 -1
  152. package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  153. package/lib/typescript/ui/context/hooks/useLanguageManagement.d.ts +1 -1
  154. package/lib/typescript/ui/context/hooks/useLanguageManagement.d.ts.map +1 -1
  155. package/lib/typescript/ui/context/hooks/useSessionManagement.d.ts +1 -1
  156. package/lib/typescript/ui/context/hooks/useSessionManagement.d.ts.map +1 -1
  157. package/lib/typescript/ui/context/hooks/useStorage.d.ts +1 -1
  158. package/lib/typescript/ui/context/hooks/useStorage.d.ts.map +1 -1
  159. package/lib/typescript/ui/hooks/useSessionSocket.d.ts.map +1 -1
  160. package/lib/typescript/ui/screens/LanguageSelectorScreen.d.ts.map +1 -1
  161. package/lib/typescript/ui/screens/PremiumSubscriptionScreen.d.ts.map +1 -1
  162. package/lib/typescript/ui/screens/ProfileScreen.d.ts.map +1 -1
  163. package/lib/typescript/ui/screens/SavesCollectionsScreen.d.ts.map +1 -1
  164. package/lib/typescript/ui/screens/karma/KarmaAboutScreen.d.ts.map +1 -1
  165. package/lib/typescript/ui/screens/karma/KarmaRewardsScreen.d.ts.map +1 -1
  166. package/lib/typescript/ui/utils/errorHandlers.d.ts +5 -0
  167. package/lib/typescript/ui/utils/errorHandlers.d.ts.map +1 -1
  168. package/lib/typescript/ui/utils/sessionHelpers.d.ts.map +1 -1
  169. package/package.json +1 -1
  170. package/src/core/mixins/OxyServices.security.ts +44 -0
  171. package/src/models/interfaces.ts +4 -0
  172. package/src/ui/components/FollowButton.tsx +19 -1
  173. package/src/ui/components/GroupedItem.tsx +1 -29
  174. package/src/ui/components/Section.tsx +1 -0
  175. package/src/ui/components/SectionTitle.tsx +0 -1
  176. package/src/ui/components/fileManagement/FileViewer.tsx +3 -3
  177. package/src/ui/context/OxyContext.tsx +30 -9
  178. package/src/ui/context/hooks/useAuthOperations.ts +16 -9
  179. package/src/ui/context/hooks/useDeviceManagement.ts +1 -1
  180. package/src/ui/context/hooks/useLanguageManagement.ts +2 -2
  181. package/src/ui/context/hooks/useSessionManagement.ts +3 -3
  182. package/src/ui/context/hooks/useStorage.ts +2 -2
  183. package/src/ui/hooks/queries/useAccountQueries.ts +1 -1
  184. package/src/ui/hooks/queries/useServicesQueries.ts +1 -1
  185. package/src/ui/hooks/useSessionSocket.ts +8 -7
  186. package/src/ui/screens/AccountCenterScreen.tsx +13 -13
  187. package/src/ui/screens/AccountOverviewScreen.tsx +17 -17
  188. package/src/ui/screens/AccountSettingsScreen.tsx +2 -2
  189. package/src/ui/screens/AccountSwitcherScreen.tsx +8 -8
  190. package/src/ui/screens/AppInfoScreen.tsx +15 -15
  191. package/src/ui/screens/FeedbackScreen.tsx +1 -1
  192. package/src/ui/screens/FileManagementScreen.tsx +1 -1
  193. package/src/ui/screens/HelpSupportScreen.tsx +3 -3
  194. package/src/ui/screens/HistoryViewScreen.tsx +2 -2
  195. package/src/ui/screens/LanguageSelectorScreen.tsx +4 -1
  196. package/src/ui/screens/LegalDocumentsScreen.tsx +4 -4
  197. package/src/ui/screens/PaymentGatewayScreen.tsx +1 -1
  198. package/src/ui/screens/PremiumSubscriptionScreen.tsx +0 -1
  199. package/src/ui/screens/ProfileScreen.tsx +61 -22
  200. package/src/ui/screens/SavesCollectionsScreen.tsx +10 -1
  201. package/src/ui/screens/karma/KarmaAboutScreen.tsx +8 -1
  202. package/src/ui/screens/karma/KarmaCenterScreen.tsx +2 -2
  203. package/src/ui/screens/karma/KarmaRewardsScreen.tsx +9 -6
  204. package/src/ui/utils/errorHandlers.ts +58 -0
  205. package/src/ui/utils/sessionHelpers.ts +0 -2
  206. package/src/utils/languageUtils.ts +11 -11
  207. package/lib/commonjs/ui/context/utils/errorHandlers.js +0 -100
  208. package/lib/commonjs/ui/context/utils/errorHandlers.js.map +0 -1
  209. package/lib/commonjs/ui/context/utils/sessionHelpers.js +0 -103
  210. package/lib/commonjs/ui/context/utils/sessionHelpers.js.map +0 -1
  211. package/lib/commonjs/ui/context/utils/storageHelpers.js +0 -119
  212. package/lib/commonjs/ui/context/utils/storageHelpers.js.map +0 -1
  213. package/lib/module/ui/context/utils/errorHandlers.js +0 -93
  214. package/lib/module/ui/context/utils/errorHandlers.js.map +0 -1
  215. package/lib/module/ui/context/utils/sessionHelpers.js +0 -96
  216. package/lib/module/ui/context/utils/sessionHelpers.js.map +0 -1
  217. package/lib/module/ui/context/utils/storageHelpers.js +0 -111
  218. package/lib/module/ui/context/utils/storageHelpers.js.map +0 -1
  219. package/lib/typescript/ui/context/utils/errorHandlers.d.ts +0 -30
  220. package/lib/typescript/ui/context/utils/errorHandlers.d.ts.map +0 -1
  221. package/lib/typescript/ui/context/utils/sessionHelpers.d.ts +0 -59
  222. package/lib/typescript/ui/context/utils/sessionHelpers.d.ts.map +0 -1
  223. package/lib/typescript/ui/context/utils/storageHelpers.d.ts +0 -31
  224. package/lib/typescript/ui/context/utils/storageHelpers.d.ts.map +0 -1
  225. package/src/ui/context/utils/errorHandlers.ts +0 -146
  226. package/src/ui/context/utils/sessionHelpers.ts +0 -146
  227. package/src/ui/context/utils/storageHelpers.ts +0 -134
@@ -2,23 +2,36 @@ import type React from 'react';
2
2
  import { useEffect, useState } from 'react';
3
3
  import { View, Text, StyleSheet, ActivityIndicator, ScrollView, TouchableOpacity, Image } from 'react-native';
4
4
  import type { BaseScreenProps } from '../types/navigation';
5
- import { useThemeColors } from '../styles';
5
+ import { useThemeColors, type ThemeColors } from '../styles';
6
6
  import Avatar from '../components/Avatar';
7
7
  import { FollowButton } from '../components';
8
8
  import { useFollow } from '../hooks/useFollow';
9
9
  import { Ionicons } from '@expo/vector-icons';
10
10
  import { useI18n } from '../hooks/useI18n';
11
11
  import { useOxy } from '../context/OxyContext';
12
+ import { logger } from '../../utils/loggerUtils';
13
+ import type { User } from '../../models/interfaces';
14
+ import { extractErrorMessage } from '../utils/errorHandlers';
12
15
 
13
16
  interface ProfileScreenProps extends BaseScreenProps {
14
17
  userId: string;
15
18
  username?: string;
16
19
  }
17
20
 
21
+ interface LinkMetadata {
22
+ id?: string;
23
+ url: string;
24
+ title?: string;
25
+ description?: string;
26
+ image?: string;
27
+ }
28
+
29
+ type ProfileLink = string | { link: string } | LinkMetadata;
30
+
18
31
  const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme, goBack, navigate }) => {
19
32
  // Use useOxy() hook for OxyContext values
20
33
  const { oxyServices, user: currentUser } = useOxy();
21
- const [profile, setProfile] = useState<any>(null);
34
+ const [profile, setProfile] = useState<User | null>(null);
22
35
  const [karmaTotal, setKarmaTotal] = useState<number | null>(null);
23
36
  const [postsCount, setPostsCount] = useState<number | null>(null);
24
37
  const [commentsCount, setCommentsCount] = useState<number | null>(null);
@@ -44,7 +57,15 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
44
57
  const { t } = useI18n();
45
58
 
46
59
  // Check if current user is viewing their own profile
47
- const isOwnProfile = currentUser && currentUser.id === userId;
60
+ // Normalize IDs by trimming whitespace to handle format mismatches
61
+ const normalizeId = (id: string | undefined | null): string => {
62
+ if (!id) return '';
63
+ return String(id).trim();
64
+ };
65
+
66
+ const currentUserId = normalizeId(currentUser?.id);
67
+ const targetUserId = normalizeId(userId);
68
+ const isOwnProfile = currentUserId && targetUserId && currentUserId === targetUserId;
48
69
 
49
70
  useEffect(() => {
50
71
  if (!userId) {
@@ -58,9 +79,11 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
58
79
 
59
80
  // Load user profile and karma total
60
81
  Promise.all([
61
- oxyServices.getUserById(userId).catch((err: any) => {
82
+ oxyServices.getUserById(userId).catch((err: unknown) => {
62
83
  // If this is the current user and the API call fails, use current user data as fallback
63
- if (currentUser && currentUser.id === userId) {
84
+ const normalizedCurrentId = normalizeId(currentUser?.id);
85
+ const normalizedTargetId = normalizeId(userId);
86
+ if (normalizedCurrentId && normalizedTargetId && normalizedCurrentId === normalizedTargetId) {
64
87
  return currentUser;
65
88
  }
66
89
  throw err;
@@ -72,18 +95,24 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
72
95
  Promise.resolve({ total: undefined })
73
96
  ])
74
97
  .then(([profileRes, karmaRes]) => {
98
+ if (!profileRes) {
99
+ setError('Profile data is not available');
100
+ setIsLoading(false);
101
+ return;
102
+ }
103
+
75
104
  setProfile(profileRes);
76
105
  setKarmaTotal(typeof karmaRes.total === 'number' ? karmaRes.total : null);
77
106
 
78
107
  // Extract links from profile data
79
108
  if (profileRes.linksMetadata && Array.isArray(profileRes.linksMetadata)) {
80
- const linksWithIds = profileRes.linksMetadata.map((link: any, index: number) => ({
109
+ const linksWithIds = profileRes.linksMetadata.map((link: LinkMetadata, index: number) => ({
81
110
  ...link,
82
111
  id: link.id || `existing-${index}`
83
112
  }));
84
113
  setLinks(linksWithIds);
85
114
  } else if (Array.isArray(profileRes.links)) {
86
- const simpleLinks = profileRes.links.map((l: any) => typeof l === 'string' ? l : l.link).filter(Boolean);
115
+ const simpleLinks = profileRes.links.map((l: ProfileLink) => typeof l === 'string' ? l : (typeof l === 'object' && 'link' in l ? l.link : '')).filter(Boolean);
87
116
  const linksWithMetadata = simpleLinks.map((url: string, index: number) => ({
88
117
  url,
89
118
  title: url.replace(/^https?:\/\//, '').replace(/\/$/, ''),
@@ -110,23 +139,29 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
110
139
  setPostsCount(Math.floor(Math.random() * 50));
111
140
  setCommentsCount(Math.floor(Math.random() * 100));
112
141
  })
113
- .catch((err: any) => {
114
- console.error('Profile loading error:', err);
142
+ .catch((err: unknown) => {
143
+ logger.error('Profile loading error', err instanceof Error ? err : new Error(String(err)), { component: 'ProfileScreen' });
115
144
  // Provide user-friendly error messages based on the error type
116
145
  let errorMessage = 'Failed to load profile';
117
146
 
118
- if (err.status === 404 || err.message?.includes('not found') || err.message?.includes('Resource not found')) {
119
- if (currentUser && currentUser.id === userId) {
147
+ // Type guard for error with status property
148
+ const errorWithStatus = err && typeof err === 'object' && 'status' in err ? err as { status?: number; message?: string } : null;
149
+ const errorMessageText = extractErrorMessage(err, '');
150
+
151
+ if (errorWithStatus?.status === 404 || errorMessageText.includes('not found') || errorMessageText.includes('Resource not found')) {
152
+ const normalizedCurrentId = normalizeId(currentUser?.id);
153
+ const normalizedTargetId = normalizeId(userId);
154
+ if (normalizedCurrentId && normalizedTargetId && normalizedCurrentId === normalizedTargetId) {
120
155
  errorMessage = 'Unable to load your profile from the server. This may be due to a temporary service issue.';
121
156
  } else {
122
157
  errorMessage = 'This user profile could not be found or may have been removed.';
123
158
  }
124
- } else if (err.status === 403) {
159
+ } else if (errorWithStatus?.status === 403) {
125
160
  errorMessage = 'You do not have permission to view this profile.';
126
- } else if (err.status === 500) {
161
+ } else if (errorWithStatus?.status === 500) {
127
162
  errorMessage = 'Server error occurred while loading the profile. Please try again later.';
128
- } else if (err.message) {
129
- errorMessage = err.message;
163
+ } else if (errorMessageText) {
164
+ errorMessage = errorMessageText;
130
165
  }
131
166
 
132
167
  setError(errorMessage);
@@ -196,7 +231,9 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
196
231
 
197
232
  onFollowChange={(isFollowing) => {
198
233
  // The follow button will automatically update counts via Zustand
199
- console.log(`Follow status changed: ${isFollowing}`);
234
+ if (__DEV__) {
235
+ logger.debug(`Follow status changed: ${isFollowing}`, { component: 'ProfileScreen' });
236
+ }
200
237
  }}
201
238
  />
202
239
  )}
@@ -204,7 +241,9 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
204
241
  </View>
205
242
  {/* Profile Info */}
206
243
  <View style={styles.header}>
207
- <Text style={[styles.displayName, { color: colors.text }]}>{profile?.displayName || profile?.username || username || profile?.id}</Text>
244
+ <Text style={[styles.displayName, { color: colors.text }]}>
245
+ {(profile && 'displayName' in profile && typeof profile.displayName === 'string' ? profile.displayName : null) || profile?.username || username || profile?.id || ''}
246
+ </Text>
208
247
  {profile?.username && (
209
248
  <Text style={[styles.subText, { color: colors.secondaryText }]}>@{profile.username}</Text>
210
249
  )}
@@ -233,25 +272,25 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
233
272
  <Text style={[styles.infoGridText, { color: colors.secondaryText }]} numberOfLines={1}>{profile.website}</Text>
234
273
  </View>
235
274
  )}
236
- {profile?.company && (
275
+ {profile && 'company' in profile && typeof profile.company === 'string' && profile.company && (
237
276
  <View style={styles.infoGridItem}>
238
277
  <Ionicons name="business-outline" size={16} color={colors.secondaryText} style={{ marginRight: 6 }} />
239
278
  <Text style={[styles.infoGridText, { color: colors.secondaryText }]} numberOfLines={1}>{profile.company}</Text>
240
279
  </View>
241
280
  )}
242
- {profile?.jobTitle && (
281
+ {profile && 'jobTitle' in profile && typeof profile.jobTitle === 'string' && profile.jobTitle && (
243
282
  <View style={styles.infoGridItem}>
244
283
  <Ionicons name="briefcase-outline" size={16} color={colors.secondaryText} style={{ marginRight: 6 }} />
245
284
  <Text style={[styles.infoGridText, { color: colors.secondaryText }]} numberOfLines={1}>{profile.jobTitle}</Text>
246
285
  </View>
247
286
  )}
248
- {profile?.education && (
287
+ {profile && 'education' in profile && typeof profile.education === 'string' && profile.education && (
249
288
  <View style={styles.infoGridItem}>
250
289
  <Ionicons name="school-outline" size={16} color={colors.secondaryText} style={{ marginRight: 6 }} />
251
290
  <Text style={[styles.infoGridText, { color: colors.secondaryText }]} numberOfLines={1}>{profile.education}</Text>
252
291
  </View>
253
292
  )}
254
- {profile?.birthday && (
293
+ {profile && 'birthday' in profile && typeof profile.birthday === 'string' && profile.birthday && (
255
294
  <View style={styles.infoGridItem}>
256
295
  <Ionicons name="gift-outline" size={16} color={colors.secondaryText} style={{ marginRight: 6 }} />
257
296
  <Text style={[styles.infoGridText, { color: colors.secondaryText }]}>
@@ -307,7 +346,7 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
307
346
  );
308
347
  };
309
348
 
310
- const createStyles = (colors: any) => StyleSheet.create({
349
+ const createStyles = (colors: ThemeColors) => StyleSheet.create({
311
350
  container: { flex: 1 },
312
351
  scrollContainer: { alignItems: 'stretch', paddingBottom: 40 },
313
352
  bannerContainer: { height: 160, backgroundColor: colors.primary + '20', position: 'relative', overflow: 'hidden' },
@@ -22,6 +22,15 @@ interface SavedItem {
22
22
  url?: string;
23
23
  }
24
24
 
25
+ interface Collection {
26
+ id: string;
27
+ name: string;
28
+ description?: string;
29
+ itemCount?: number;
30
+ createdAt?: Date;
31
+ updatedAt?: Date;
32
+ }
33
+
25
34
  const SavesCollectionsScreen: React.FC<BaseScreenProps> = ({
26
35
  onClose,
27
36
  theme,
@@ -31,7 +40,7 @@ const SavesCollectionsScreen: React.FC<BaseScreenProps> = ({
31
40
  const { oxyServices, user } = useOxy();
32
41
  const { t } = useI18n();
33
42
  const [savedItems, setSavedItems] = useState<SavedItem[]>([]);
34
- const [collections, setCollections] = useState<any[]>([]);
43
+ const [collections, setCollections] = useState<Collection[]>([]);
35
44
  const [isLoading, setIsLoading] = useState(true);
36
45
  const [activeTab, setActiveTab] = useState<'saves' | 'collections'>('saves');
37
46
 
@@ -6,6 +6,7 @@ import { useI18n } from '../../hooks/useI18n';
6
6
  import { useThemeStyles } from '../../hooks/useThemeStyles';
7
7
  import { normalizeTheme } from '../../utils/themeUtils';
8
8
  import { useColorScheme } from '../../hooks/use-color-scheme';
9
+ import { fontFamilies } from '../../styles/fonts';
9
10
 
10
11
  const KarmaAboutScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
11
12
  const { t } = useI18n();
@@ -61,7 +62,13 @@ const styles = StyleSheet.create({
61
62
  marginBottom: 24,
62
63
  },
63
64
  contentContainer: { padding: 24, paddingTop: 20 },
64
- section: { fontSize: 18, fontWeight: 'bold', marginTop: 24, marginBottom: 8 },
65
+ section: {
66
+ fontSize: 18,
67
+ fontWeight: Platform.OS === 'web' ? 'bold' : undefined,
68
+ fontFamily: fontFamilies.phuduBold,
69
+ marginTop: 24,
70
+ marginBottom: 8
71
+ },
65
72
  paragraph: { fontSize: 16, marginBottom: 12 },
66
73
  });
67
74
 
@@ -223,8 +223,8 @@ const styles = StyleSheet.create({
223
223
  },
224
224
  sectionTitle: {
225
225
  fontSize: 18,
226
- fontWeight: '600',
227
- marginBottom: 12,
226
+ fontWeight: Platform.OS === 'web' ? '600' : undefined,
227
+ fontFamily: fontFamilies.phuduSemiBold,
228
228
  marginTop: 8,
229
229
  alignSelf: 'flex-start',
230
230
  marginLeft: 24,
@@ -1,6 +1,6 @@
1
1
  import type React from 'react';
2
2
  import { useMemo, useState, useEffect } from 'react';
3
- import { View, Text, StyleSheet, ScrollView, TouchableOpacity } from 'react-native';
3
+ import { View, Text, StyleSheet, ScrollView, TouchableOpacity, Platform } from 'react-native';
4
4
  import type { BaseScreenProps } from '../../types/navigation';
5
5
  import { Header } from '../../components';
6
6
  import { Ionicons } from '@expo/vector-icons';
@@ -11,6 +11,7 @@ import { useColorScheme } from '../../hooks/use-color-scheme';
11
11
  import { Colors } from '../../constants/theme';
12
12
  import { useOxy } from '../../context/OxyContext';
13
13
  import { darkenColor, lightenColor } from '../../utils/colorUtils';
14
+ import { fontFamilies } from '../../styles/fonts';
14
15
 
15
16
  interface Achievement {
16
17
  id: string;
@@ -82,7 +83,7 @@ const KarmaRewardsScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
82
83
  name: t('karma.achievements.contributor') || 'Contributor',
83
84
  description: t('karma.achievements.contributorDesc') || 'Reached 50 karma points',
84
85
  category: 'contribution',
85
- icon: 'people',
86
+ icon: 'account-group',
86
87
  iconColor: '#007AFF',
87
88
  unlocked: karmaTotal >= 50,
88
89
  rarity: 'common',
@@ -456,7 +457,8 @@ const styles = StyleSheet.create({
456
457
  },
457
458
  currentKarma: {
458
459
  fontSize: 36,
459
- fontWeight: 'bold',
460
+ fontWeight: Platform.OS === 'web' ? 'bold' : undefined,
461
+ fontFamily: fontFamilies.phuduBold,
460
462
  marginBottom: 4,
461
463
  },
462
464
  achievementStats: {
@@ -464,7 +466,8 @@ const styles = StyleSheet.create({
464
466
  },
465
467
  achievementCount: {
466
468
  fontSize: 36,
467
- fontWeight: 'bold',
469
+ fontWeight: Platform.OS === 'web' ? 'bold' : undefined,
470
+ fontFamily: fontFamilies.phuduBold,
468
471
  marginBottom: 4,
469
472
  },
470
473
  achievementCountLabel: {
@@ -492,8 +495,8 @@ const styles = StyleSheet.create({
492
495
  },
493
496
  sectionTitle: {
494
497
  fontSize: 20,
495
- fontWeight: '600',
496
- marginBottom: 16,
498
+ fontWeight: Platform.OS === 'web' ? '600' : undefined,
499
+ fontFamily: fontFamilies.phuduSemiBold,
497
500
  marginTop: 8,
498
501
  },
499
502
  achievementsGrid: {
@@ -53,16 +53,74 @@ export const isInvalidSessionError = (error: unknown): boolean => {
53
53
  return false;
54
54
  }
55
55
 
56
+ // Check error.status directly (HttpService sets this)
57
+ if ((error as any).status === 401) {
58
+ return true;
59
+ }
60
+
56
61
  const normalizedMessage = extractErrorMessage(error)?.toLowerCase();
57
62
  if (!normalizedMessage) {
58
63
  return false;
59
64
  }
60
65
 
66
+ // Check for HTTP 401 in message (HttpService creates errors with "HTTP 401:" format)
67
+ if (normalizedMessage.includes('http 401') || normalizedMessage.includes('401')) {
68
+ return true;
69
+ }
70
+
61
71
  return DEFAULT_INVALID_SESSION_MESSAGES.some((msg) =>
62
72
  normalizedMessage.includes(msg.toLowerCase()),
63
73
  );
64
74
  };
65
75
 
76
+ /**
77
+ * Determine whether the error represents a timeout or network error.
78
+ * These are expected when the device is offline or has poor connectivity.
79
+ */
80
+ export const isTimeoutOrNetworkError = (error: unknown): boolean => {
81
+ if (!isObject(error) && !(error instanceof Error)) {
82
+ return false;
83
+ }
84
+
85
+ const message = extractErrorMessage(error, '').toLowerCase();
86
+ const errorCode = (error as any).code;
87
+
88
+ // Check for timeout/cancelled messages
89
+ if (
90
+ message.includes('timeout') ||
91
+ message.includes('cancelled') ||
92
+ message.includes('econnaborted') ||
93
+ message.includes('aborted') ||
94
+ message.includes('request timeout or cancelled')
95
+ ) {
96
+ return true;
97
+ }
98
+
99
+ // Check for timeout/network error codes
100
+ if (errorCode === 'TIMEOUT' || errorCode === 'NETWORK_ERROR' || errorCode === 'ECONNABORTED') {
101
+ return true;
102
+ }
103
+
104
+ // Check for AbortError
105
+ if (error instanceof Error && error.name === 'AbortError') {
106
+ return true;
107
+ }
108
+
109
+ // Check for network-related TypeErrors
110
+ if (error instanceof TypeError) {
111
+ const typeErrorMessage = error.message.toLowerCase();
112
+ if (
113
+ typeErrorMessage.includes('fetch') ||
114
+ typeErrorMessage.includes('network') ||
115
+ typeErrorMessage.includes('failed to fetch')
116
+ ) {
117
+ return true;
118
+ }
119
+ }
120
+
121
+ return false;
122
+ };
123
+
66
124
  /**
67
125
  * Extract a consistent error message from unknown error shapes.
68
126
  *
@@ -82,8 +82,6 @@ export const fetchSessionsWithFallback = async (
82
82
  } catch (error) {
83
83
  if (__DEV__ && logger) {
84
84
  logger('Failed to get device sessions, falling back to user sessions', error);
85
- } else if (__DEV__) {
86
- console.warn('Failed to get device sessions, falling back to user sessions:', error);
87
85
  }
88
86
 
89
87
  const userSessions = await oxyServices.getSessionsBySessionId(sessionId);
@@ -19,7 +19,7 @@ export const SUPPORTED_LANGUAGES: LanguageMetadata[] = [
19
19
  name: 'English',
20
20
  nativeName: 'English',
21
21
  flag: '🇺🇸',
22
- icon: 'language-outline',
22
+ icon: 'translate',
23
23
  color: '#007AFF',
24
24
  },
25
25
  {
@@ -27,7 +27,7 @@ export const SUPPORTED_LANGUAGES: LanguageMetadata[] = [
27
27
  name: 'Spanish',
28
28
  nativeName: 'Español',
29
29
  flag: '🇪🇸',
30
- icon: 'language-outline',
30
+ icon: 'translate',
31
31
  color: '#FF3B30',
32
32
  },
33
33
  {
@@ -35,7 +35,7 @@ export const SUPPORTED_LANGUAGES: LanguageMetadata[] = [
35
35
  name: 'Catalan',
36
36
  nativeName: 'Català',
37
37
  flag: '🇪🇸',
38
- icon: 'language-outline',
38
+ icon: 'translate',
39
39
  color: '#0CA678',
40
40
  },
41
41
  {
@@ -43,7 +43,7 @@ export const SUPPORTED_LANGUAGES: LanguageMetadata[] = [
43
43
  name: 'French',
44
44
  nativeName: 'Français',
45
45
  flag: '🇫🇷',
46
- icon: 'language-outline',
46
+ icon: 'translate',
47
47
  color: '#5856D6',
48
48
  },
49
49
  {
@@ -51,7 +51,7 @@ export const SUPPORTED_LANGUAGES: LanguageMetadata[] = [
51
51
  name: 'German',
52
52
  nativeName: 'Deutsch',
53
53
  flag: '🇩🇪',
54
- icon: 'language-outline',
54
+ icon: 'translate',
55
55
  color: '#FF9500',
56
56
  },
57
57
  {
@@ -59,7 +59,7 @@ export const SUPPORTED_LANGUAGES: LanguageMetadata[] = [
59
59
  name: 'Italian',
60
60
  nativeName: 'Italiano',
61
61
  flag: '🇮🇹',
62
- icon: 'language-outline',
62
+ icon: 'translate',
63
63
  color: '#34C759',
64
64
  },
65
65
  {
@@ -67,7 +67,7 @@ export const SUPPORTED_LANGUAGES: LanguageMetadata[] = [
67
67
  name: 'Portuguese',
68
68
  nativeName: 'Português',
69
69
  flag: '🇵🇹',
70
- icon: 'language-outline',
70
+ icon: 'translate',
71
71
  color: '#AF52DE',
72
72
  },
73
73
  {
@@ -75,7 +75,7 @@ export const SUPPORTED_LANGUAGES: LanguageMetadata[] = [
75
75
  name: 'Japanese',
76
76
  nativeName: '日本語',
77
77
  flag: '🇯🇵',
78
- icon: 'language-outline',
78
+ icon: 'translate',
79
79
  color: '#FF2D92',
80
80
  },
81
81
  {
@@ -83,7 +83,7 @@ export const SUPPORTED_LANGUAGES: LanguageMetadata[] = [
83
83
  name: 'Korean',
84
84
  nativeName: '한국어',
85
85
  flag: '🇰🇷',
86
- icon: 'language-outline',
86
+ icon: 'translate',
87
87
  color: '#32D74B',
88
88
  },
89
89
  {
@@ -91,7 +91,7 @@ export const SUPPORTED_LANGUAGES: LanguageMetadata[] = [
91
91
  name: 'Chinese',
92
92
  nativeName: '中文',
93
93
  flag: '🇨🇳',
94
- icon: 'language-outline',
94
+ icon: 'translate',
95
95
  color: '#FF9F0A',
96
96
  },
97
97
  {
@@ -99,7 +99,7 @@ export const SUPPORTED_LANGUAGES: LanguageMetadata[] = [
99
99
  name: 'Arabic',
100
100
  nativeName: 'العربية',
101
101
  flag: '🇸🇦',
102
- icon: 'language-outline',
102
+ icon: 'translate',
103
103
  color: '#30B0C7',
104
104
  },
105
105
  ];
@@ -1,100 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.isInvalidSessionError = exports.handleAuthError = exports.extractErrorMessage = void 0;
7
- const DEFAULT_INVALID_SESSION_MESSAGES = ['Invalid or expired session', 'Session is invalid', 'Session not found', 'Session expired'];
8
- const isObject = value => typeof value === 'object' && value !== null;
9
- const getResponseStatus = error => {
10
- if (!isObject(error)) return undefined;
11
- const response = error.response;
12
- return response?.status;
13
- };
14
-
15
- /**
16
- * Determine whether the error represents an invalid session condition.
17
- * This centralizes 401 detection across different fetch clients.
18
- */
19
- const isInvalidSessionError = error => {
20
- const status = getResponseStatus(error);
21
- if (status === 401) {
22
- return true;
23
- }
24
- if (!isObject(error)) {
25
- return false;
26
- }
27
-
28
- // Check error.status directly (HttpService sets this)
29
- if (error.status === 401) {
30
- return true;
31
- }
32
- const normalizedMessage = extractErrorMessage(error)?.toLowerCase();
33
- if (!normalizedMessage) {
34
- return false;
35
- }
36
-
37
- // Check for HTTP 401 in message (HttpService creates errors with "HTTP 401:" format)
38
- if (normalizedMessage.includes('http 401') || normalizedMessage.includes('401')) {
39
- return true;
40
- }
41
- return DEFAULT_INVALID_SESSION_MESSAGES.some(msg => normalizedMessage.includes(msg.toLowerCase()));
42
- };
43
-
44
- /**
45
- * Extract a consistent error message from unknown error shapes.
46
- *
47
- * @param error - The unknown error payload
48
- * @param fallbackMessage - Message to return when no concrete message is available
49
- */
50
- exports.isInvalidSessionError = isInvalidSessionError;
51
- const extractErrorMessage = (error, fallbackMessage = 'Unexpected error') => {
52
- if (typeof error === 'string' && error.trim().length > 0) {
53
- return error;
54
- }
55
- if (!isObject(error)) {
56
- return fallbackMessage;
57
- }
58
- const withMessage = error;
59
- if (withMessage.message && withMessage.message.trim().length > 0) {
60
- return withMessage.message;
61
- }
62
- const withResponse = error;
63
- const responseMessage = withResponse.response?.data?.message ?? withResponse.response?.data?.error;
64
- if (typeof responseMessage === 'string' && responseMessage.trim().length > 0) {
65
- return responseMessage;
66
- }
67
- return fallbackMessage;
68
- };
69
-
70
- /**
71
- * Centralized error handler for auth-related operations.
72
- *
73
- * @param error - Unknown error object
74
- * @param options - Error handling configuration
75
- * @returns Resolved error message
76
- */
77
- exports.extractErrorMessage = extractErrorMessage;
78
- const handleAuthError = (error, {
79
- defaultMessage,
80
- code,
81
- status,
82
- onError,
83
- setAuthError,
84
- logger
85
- }) => {
86
- const resolvedStatus = status ?? getResponseStatus(error) ?? (isInvalidSessionError(error) ? 401 : 500);
87
- const message = extractErrorMessage(error, defaultMessage);
88
- if (logger) {
89
- logger(message, error);
90
- }
91
- setAuthError?.(message);
92
- onError?.({
93
- message,
94
- code,
95
- status: resolvedStatus
96
- });
97
- return message;
98
- };
99
- exports.handleAuthError = handleAuthError;
100
- //# sourceMappingURL=errorHandlers.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["DEFAULT_INVALID_SESSION_MESSAGES","isObject","value","getResponseStatus","error","undefined","response","status","isInvalidSessionError","normalizedMessage","extractErrorMessage","toLowerCase","includes","some","msg","exports","fallbackMessage","trim","length","withMessage","message","withResponse","responseMessage","data","handleAuthError","defaultMessage","code","onError","setAuthError","logger","resolvedStatus"],"sourceRoot":"../../../../../src","sources":["ui/context/utils/errorHandlers.ts"],"mappings":"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","ignoreList":[]}