@oxyhq/services 5.13.3 → 5.13.10

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 (156) hide show
  1. package/lib/commonjs/core/HttpClient.js +1 -1
  2. package/lib/commonjs/core/HttpClient.js.map +1 -1
  3. package/lib/commonjs/core/OxyServices.js +82 -8
  4. package/lib/commonjs/core/OxyServices.js.map +1 -1
  5. package/lib/commonjs/i18n/locales/en-US.json +222 -6
  6. package/lib/commonjs/lib/sonner.js.map +1 -1
  7. package/lib/commonjs/ui/components/GroupedItem.js +24 -22
  8. package/lib/commonjs/ui/components/GroupedItem.js.map +1 -1
  9. package/lib/commonjs/ui/components/OxyProvider.js +35 -14
  10. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  11. package/lib/commonjs/ui/navigation/routes.js +36 -1
  12. package/lib/commonjs/ui/navigation/routes.js.map +1 -1
  13. package/lib/commonjs/ui/screens/AccountOverviewScreen.js +150 -5
  14. package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
  15. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +475 -319
  16. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  17. package/lib/commonjs/ui/screens/AccountVerificationScreen.js +217 -0
  18. package/lib/commonjs/ui/screens/AccountVerificationScreen.js.map +1 -0
  19. package/lib/commonjs/ui/screens/FileManagementScreen.js +911 -213
  20. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  21. package/lib/commonjs/ui/screens/HelpSupportScreen.js +131 -0
  22. package/lib/commonjs/ui/screens/HelpSupportScreen.js.map +1 -0
  23. package/lib/commonjs/ui/screens/HistoryViewScreen.js +258 -0
  24. package/lib/commonjs/ui/screens/HistoryViewScreen.js.map +1 -0
  25. package/lib/commonjs/ui/screens/LegalDocumentsScreen.js +211 -0
  26. package/lib/commonjs/ui/screens/LegalDocumentsScreen.js.map +1 -0
  27. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js +0 -1
  28. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  29. package/lib/commonjs/ui/screens/PrivacySettingsScreen.js +307 -0
  30. package/lib/commonjs/ui/screens/PrivacySettingsScreen.js.map +1 -0
  31. package/lib/commonjs/ui/screens/ProfileScreen.js +1 -7
  32. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
  33. package/lib/commonjs/ui/screens/SavesCollectionsScreen.js +205 -0
  34. package/lib/commonjs/ui/screens/SavesCollectionsScreen.js.map +1 -0
  35. package/lib/commonjs/ui/screens/SearchSettingsScreen.js +239 -0
  36. package/lib/commonjs/ui/screens/SearchSettingsScreen.js.map +1 -0
  37. package/lib/commonjs/ui/screens/SignInScreen.js +14 -29
  38. package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
  39. package/lib/commonjs/utils/asyncUtils.js +1 -0
  40. package/lib/commonjs/utils/asyncUtils.js.map +1 -1
  41. package/lib/commonjs/utils/cache.js +4 -4
  42. package/lib/commonjs/utils/cache.js.map +1 -1
  43. package/lib/commonjs/utils/index.js +0 -6
  44. package/lib/commonjs/utils/index.js.map +1 -1
  45. package/lib/module/core/HttpClient.js +1 -1
  46. package/lib/module/core/HttpClient.js.map +1 -1
  47. package/lib/module/core/OxyServices.js +82 -8
  48. package/lib/module/core/OxyServices.js.map +1 -1
  49. package/lib/module/i18n/locales/en-US.json +222 -6
  50. package/lib/module/lib/sonner.js.map +1 -1
  51. package/lib/module/ui/components/GroupedItem.js +24 -22
  52. package/lib/module/ui/components/GroupedItem.js.map +1 -1
  53. package/lib/module/ui/components/OxyProvider.js +40 -17
  54. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  55. package/lib/module/ui/navigation/routes.js +36 -1
  56. package/lib/module/ui/navigation/routes.js.map +1 -1
  57. package/lib/module/ui/screens/AccountOverviewScreen.js +151 -6
  58. package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
  59. package/lib/module/ui/screens/AccountSettingsScreen.js +475 -319
  60. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  61. package/lib/module/ui/screens/AccountVerificationScreen.js +212 -0
  62. package/lib/module/ui/screens/AccountVerificationScreen.js.map +1 -0
  63. package/lib/module/ui/screens/FileManagementScreen.js +913 -212
  64. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  65. package/lib/module/ui/screens/HelpSupportScreen.js +126 -0
  66. package/lib/module/ui/screens/HelpSupportScreen.js.map +1 -0
  67. package/lib/module/ui/screens/HistoryViewScreen.js +253 -0
  68. package/lib/module/ui/screens/HistoryViewScreen.js.map +1 -0
  69. package/lib/module/ui/screens/LegalDocumentsScreen.js +206 -0
  70. package/lib/module/ui/screens/LegalDocumentsScreen.js.map +1 -0
  71. package/lib/module/ui/screens/PremiumSubscriptionScreen.js +0 -1
  72. package/lib/module/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  73. package/lib/module/ui/screens/PrivacySettingsScreen.js +302 -0
  74. package/lib/module/ui/screens/PrivacySettingsScreen.js.map +1 -0
  75. package/lib/module/ui/screens/ProfileScreen.js +1 -7
  76. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  77. package/lib/module/ui/screens/SavesCollectionsScreen.js +200 -0
  78. package/lib/module/ui/screens/SavesCollectionsScreen.js.map +1 -0
  79. package/lib/module/ui/screens/SearchSettingsScreen.js +234 -0
  80. package/lib/module/ui/screens/SearchSettingsScreen.js.map +1 -0
  81. package/lib/module/ui/screens/SignInScreen.js +14 -29
  82. package/lib/module/ui/screens/SignInScreen.js.map +1 -1
  83. package/lib/module/utils/asyncUtils.js +1 -0
  84. package/lib/module/utils/asyncUtils.js.map +1 -1
  85. package/lib/module/utils/cache.js +3 -3
  86. package/lib/module/utils/cache.js.map +1 -1
  87. package/lib/module/utils/index.js +1 -1
  88. package/lib/module/utils/index.js.map +1 -1
  89. package/lib/typescript/core/OxyServices.d.ts +30 -6
  90. package/lib/typescript/core/OxyServices.d.ts.map +1 -1
  91. package/lib/typescript/lib/sonner.d.ts +1 -0
  92. package/lib/typescript/lib/sonner.d.ts.map +1 -1
  93. package/lib/typescript/types/expo-document-picker.d.ts +36 -0
  94. package/lib/typescript/ui/components/GroupedItem.d.ts.map +1 -1
  95. package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
  96. package/lib/typescript/ui/navigation/routes.d.ts +1 -1
  97. package/lib/typescript/ui/navigation/routes.d.ts.map +1 -1
  98. package/lib/typescript/ui/screens/AccountOverviewScreen.d.ts.map +1 -1
  99. package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  100. package/lib/typescript/ui/screens/AccountVerificationScreen.d.ts +5 -0
  101. package/lib/typescript/ui/screens/AccountVerificationScreen.d.ts.map +1 -0
  102. package/lib/typescript/ui/screens/FileManagementScreen.d.ts.map +1 -1
  103. package/lib/typescript/ui/screens/HelpSupportScreen.d.ts +5 -0
  104. package/lib/typescript/ui/screens/HelpSupportScreen.d.ts.map +1 -0
  105. package/lib/typescript/ui/screens/HistoryViewScreen.d.ts +5 -0
  106. package/lib/typescript/ui/screens/HistoryViewScreen.d.ts.map +1 -0
  107. package/lib/typescript/ui/screens/LegalDocumentsScreen.d.ts +5 -0
  108. package/lib/typescript/ui/screens/LegalDocumentsScreen.d.ts.map +1 -0
  109. package/lib/typescript/ui/screens/PremiumSubscriptionScreen.d.ts.map +1 -1
  110. package/lib/typescript/ui/screens/PrivacySettingsScreen.d.ts +5 -0
  111. package/lib/typescript/ui/screens/PrivacySettingsScreen.d.ts.map +1 -0
  112. package/lib/typescript/ui/screens/ProfileScreen.d.ts.map +1 -1
  113. package/lib/typescript/ui/screens/SavesCollectionsScreen.d.ts +5 -0
  114. package/lib/typescript/ui/screens/SavesCollectionsScreen.d.ts.map +1 -0
  115. package/lib/typescript/ui/screens/SearchSettingsScreen.d.ts +5 -0
  116. package/lib/typescript/ui/screens/SearchSettingsScreen.d.ts.map +1 -0
  117. package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
  118. package/lib/typescript/utils/asyncUtils.d.ts.map +1 -1
  119. package/lib/typescript/utils/cache.d.ts +3 -3
  120. package/lib/typescript/utils/cache.d.ts.map +1 -1
  121. package/lib/typescript/utils/index.d.ts +1 -1
  122. package/lib/typescript/utils/index.d.ts.map +1 -1
  123. package/package.json +1 -1
  124. package/src/core/HttpClient.ts +1 -1
  125. package/src/core/OxyServices.ts +80 -8
  126. package/src/i18n/locales/en-US.json +222 -6
  127. package/src/lib/sonner.ts +1 -0
  128. package/src/types/expo-document-picker.d.ts +36 -0
  129. package/src/ui/components/GroupedItem.tsx +23 -21
  130. package/src/ui/components/OxyProvider.tsx +33 -11
  131. package/src/ui/navigation/routes.ts +42 -0
  132. package/src/ui/screens/AccountOverviewScreen.tsx +175 -5
  133. package/src/ui/screens/AccountSettingsScreen.tsx +521 -360
  134. package/src/ui/screens/AccountVerificationScreen.tsx +235 -0
  135. package/src/ui/screens/FileManagementScreen.tsx +934 -208
  136. package/src/ui/screens/HelpSupportScreen.tsx +143 -0
  137. package/src/ui/screens/HistoryViewScreen.tsx +280 -0
  138. package/src/ui/screens/LegalDocumentsScreen.tsx +220 -0
  139. package/src/ui/screens/PremiumSubscriptionScreen.tsx +0 -1
  140. package/src/ui/screens/PrivacySettingsScreen.tsx +332 -0
  141. package/src/ui/screens/ProfileScreen.tsx +1 -8
  142. package/src/ui/screens/SavesCollectionsScreen.tsx +222 -0
  143. package/src/ui/screens/SearchSettingsScreen.tsx +219 -0
  144. package/src/ui/screens/SignInScreen.tsx +19 -35
  145. package/src/utils/asyncUtils.ts +1 -0
  146. package/src/utils/cache.ts +3 -3
  147. package/src/utils/index.ts +1 -1
  148. package/lib/commonjs/ui/components/StepBasedScreen.README.md +0 -337
  149. package/lib/commonjs/ui/components/internal/TextField.md +0 -436
  150. package/lib/commonjs/ui/styles/FONTS.md +0 -126
  151. package/lib/module/ui/components/StepBasedScreen.README.md +0 -337
  152. package/lib/module/ui/components/internal/TextField.md +0 -436
  153. package/lib/module/ui/styles/FONTS.md +0 -126
  154. package/src/ui/components/StepBasedScreen.README.md +0 -337
  155. package/src/ui/components/internal/TextField.md +0 -436
  156. package/src/ui/styles/FONTS.md +0 -126
@@ -0,0 +1,332 @@
1
+ import React, { useState, useCallback, useMemo, useEffect } from 'react';
2
+ import {
3
+ View,
4
+ Text,
5
+ StyleSheet,
6
+ ScrollView,
7
+ Switch,
8
+ ActivityIndicator,
9
+ } from 'react-native';
10
+ import type { BaseScreenProps } from '../navigation/types';
11
+ import { useOxy } from '../context/OxyContext';
12
+ import { toast } from '../../lib/sonner';
13
+ import { Header, Section } from '../components';
14
+ import { useI18n } from '../hooks/useI18n';
15
+
16
+ interface PrivacySettings {
17
+ isPrivateAccount: boolean;
18
+ hideOnlineStatus: boolean;
19
+ hideLastSeen: boolean;
20
+ profileVisibility: boolean;
21
+ twoFactorEnabled: boolean;
22
+ loginAlerts: boolean;
23
+ blockScreenshots: boolean;
24
+ login: boolean;
25
+ biometricLogin: boolean;
26
+ showActivity: boolean;
27
+ allowTagging: boolean;
28
+ allowMentions: boolean;
29
+ hideReadReceipts: boolean;
30
+ allowDirectMessages: boolean;
31
+ dataSharing: boolean;
32
+ locationSharing: boolean;
33
+ analyticsSharing: boolean;
34
+ sensitiveContent: boolean;
35
+ autoFilter: boolean;
36
+ muteKeywords: boolean;
37
+ }
38
+
39
+ const PrivacySettingsScreen: React.FC<BaseScreenProps> = ({
40
+ onClose,
41
+ theme,
42
+ goBack,
43
+ }) => {
44
+ const { oxyServices, user } = useOxy();
45
+ const { t } = useI18n();
46
+ const [settings, setSettings] = useState<PrivacySettings>({
47
+ isPrivateAccount: false,
48
+ hideOnlineStatus: false,
49
+ hideLastSeen: false,
50
+ profileVisibility: true,
51
+ twoFactorEnabled: false,
52
+ loginAlerts: true,
53
+ blockScreenshots: false,
54
+ login: true,
55
+ biometricLogin: false,
56
+ showActivity: true,
57
+ allowTagging: true,
58
+ allowMentions: true,
59
+ hideReadReceipts: false,
60
+ allowDirectMessages: true,
61
+ dataSharing: true,
62
+ locationSharing: false,
63
+ analyticsSharing: true,
64
+ sensitiveContent: false,
65
+ autoFilter: true,
66
+ muteKeywords: false,
67
+ });
68
+ const [isLoading, setIsLoading] = useState(true);
69
+ const [isSaving, setIsSaving] = useState(false);
70
+
71
+ // Load settings
72
+ useEffect(() => {
73
+ const loadSettings = async () => {
74
+ try {
75
+ setIsLoading(true);
76
+ if (user?.id && oxyServices) {
77
+ const privacySettings = await oxyServices.getPrivacySettings(user.id);
78
+ if (privacySettings) {
79
+ setSettings(privacySettings);
80
+ }
81
+ }
82
+ } catch (error) {
83
+ console.error('Failed to load privacy settings:', error);
84
+ toast.error(t('privacySettings.loadError') || 'Failed to load privacy settings');
85
+ } finally {
86
+ setIsLoading(false);
87
+ }
88
+ };
89
+
90
+ loadSettings();
91
+ }, [user?.id, oxyServices, t]);
92
+
93
+ const updateSetting = useCallback(async (key: keyof PrivacySettings, value: boolean) => {
94
+ try {
95
+ setIsSaving(true);
96
+ const newSettings = { ...settings, [key]: value };
97
+ setSettings(newSettings);
98
+
99
+ if (user?.id && oxyServices) {
100
+ await oxyServices.updatePrivacySettings({ [key]: value }, user.id);
101
+ toast.success(t('privacySettings.updated') || 'Privacy settings updated');
102
+ }
103
+ } catch (error) {
104
+ console.error(`Failed to update ${key}:`, error);
105
+ toast.error(t('privacySettings.updateError') || 'Failed to update privacy setting');
106
+ // Revert on error
107
+ setSettings(settings);
108
+ } finally {
109
+ setIsSaving(false);
110
+ }
111
+ }, [settings, user?.id, oxyServices, t]);
112
+
113
+ const themeStyles = useMemo(() => {
114
+ const isDarkTheme = theme === 'dark';
115
+ return {
116
+ textColor: isDarkTheme ? '#FFFFFF' : '#000000',
117
+ backgroundColor: isDarkTheme ? '#121212' : '#FFFFFF',
118
+ secondaryBackgroundColor: isDarkTheme ? '#222222' : '#F5F5F5',
119
+ borderColor: isDarkTheme ? '#444444' : '#E0E0E0',
120
+ mutedTextColor: isDarkTheme ? '#8E8E93' : '#8E8E93',
121
+ };
122
+ }, [theme]);
123
+
124
+ const SettingRow: React.FC<{
125
+ title: string;
126
+ description?: string;
127
+ value: boolean;
128
+ onValueChange: (value: boolean) => void;
129
+ disabled?: boolean;
130
+ }> = ({ title, description, value, onValueChange, disabled }) => (
131
+ <View style={[styles.settingRow, { borderBottomColor: themeStyles.borderColor }]}>
132
+ <View style={styles.settingInfo}>
133
+ <Text style={[styles.settingTitle, { color: themeStyles.textColor }]}>
134
+ {title}
135
+ </Text>
136
+ {description && (
137
+ <Text style={[styles.settingDescription, { color: themeStyles.mutedTextColor }]}>
138
+ {description}
139
+ </Text>
140
+ )}
141
+ </View>
142
+ <Switch
143
+ value={value}
144
+ onValueChange={onValueChange}
145
+ disabled={disabled || isSaving}
146
+ trackColor={{ false: '#767577', true: '#d169e5' }}
147
+ thumbColor={value ? '#fff' : '#f4f3f4'}
148
+ />
149
+ </View>
150
+ );
151
+
152
+ if (isLoading) {
153
+ return (
154
+ <View style={[styles.container, { backgroundColor: themeStyles.backgroundColor }]}>
155
+ <Header
156
+ title={t('privacySettings.title') || 'Privacy Settings'}
157
+ theme={theme}
158
+ onBack={goBack || onClose}
159
+ variant="minimal"
160
+ elevation="subtle"
161
+ />
162
+ <View style={styles.loadingContainer}>
163
+ <ActivityIndicator size="large" color={themeStyles.textColor} />
164
+ </View>
165
+ </View>
166
+ );
167
+ }
168
+
169
+ return (
170
+ <View style={[styles.container, { backgroundColor: themeStyles.backgroundColor }]}>
171
+ <Header
172
+ title={t('privacySettings.title') || 'Privacy Settings'}
173
+ theme={theme}
174
+ onBack={goBack || onClose}
175
+ variant="minimal"
176
+ elevation="subtle"
177
+ />
178
+
179
+ <ScrollView style={styles.content}>
180
+ {/* Account Privacy */}
181
+ <Section title={t('privacySettings.sections.account') || 'ACCOUNT PRIVACY'} theme={theme} isFirst={true}>
182
+ <SettingRow
183
+ title={t('privacySettings.isPrivateAccount') || 'Private Account'}
184
+ description={t('privacySettings.isPrivateAccountDesc') || 'Only approved followers can see your posts'}
185
+ value={settings.isPrivateAccount}
186
+ onValueChange={(value) => updateSetting('isPrivateAccount', value)}
187
+ />
188
+ <SettingRow
189
+ title={t('privacySettings.profileVisibility') || 'Profile Visibility'}
190
+ description={t('privacySettings.profileVisibilityDesc') || 'Control who can view your profile'}
191
+ value={settings.profileVisibility}
192
+ onValueChange={(value) => updateSetting('profileVisibility', value)}
193
+ />
194
+ <SettingRow
195
+ title={t('privacySettings.hideOnlineStatus') || 'Hide Online Status'}
196
+ description={t('privacySettings.hideOnlineStatusDesc') || 'Don\'t show when you\'re online'}
197
+ value={settings.hideOnlineStatus}
198
+ onValueChange={(value) => updateSetting('hideOnlineStatus', value)}
199
+ />
200
+ <SettingRow
201
+ title={t('privacySettings.hideLastSeen') || 'Hide Last Seen'}
202
+ description={t('privacySettings.hideLastSeenDesc') || 'Don\'t show when you were last active'}
203
+ value={settings.hideLastSeen}
204
+ onValueChange={(value) => updateSetting('hideLastSeen', value)}
205
+ />
206
+ </Section>
207
+
208
+ {/* Interactions */}
209
+ <Section title={t('privacySettings.sections.interactions') || 'INTERACTIONS'} theme={theme}>
210
+ <SettingRow
211
+ title={t('privacySettings.allowTagging') || 'Allow Tagging'}
212
+ description={t('privacySettings.allowTaggingDesc') || 'Let others tag you in posts'}
213
+ value={settings.allowTagging}
214
+ onValueChange={(value) => updateSetting('allowTagging', value)}
215
+ />
216
+ <SettingRow
217
+ title={t('privacySettings.allowMentions') || 'Allow Mentions'}
218
+ description={t('privacySettings.allowMentionsDesc') || 'Let others mention you'}
219
+ value={settings.allowMentions}
220
+ onValueChange={(value) => updateSetting('allowMentions', value)}
221
+ />
222
+ <SettingRow
223
+ title={t('privacySettings.allowDirectMessages') || 'Allow Direct Messages'}
224
+ description={t('privacySettings.allowDirectMessagesDesc') || 'Let others send you direct messages'}
225
+ value={settings.allowDirectMessages}
226
+ onValueChange={(value) => updateSetting('allowDirectMessages', value)}
227
+ />
228
+ <SettingRow
229
+ title={t('privacySettings.hideReadReceipts') || 'Hide Read Receipts'}
230
+ description={t('privacySettings.hideReadReceiptsDesc') || 'Don\'t show read receipts in messages'}
231
+ value={settings.hideReadReceipts}
232
+ onValueChange={(value) => updateSetting('hideReadReceipts', value)}
233
+ />
234
+ </Section>
235
+
236
+ {/* Activity & Data */}
237
+ <Section title={t('privacySettings.sections.activity') || 'ACTIVITY & DATA'} theme={theme}>
238
+ <SettingRow
239
+ title={t('privacySettings.showActivity') || 'Show Activity Status'}
240
+ description={t('privacySettings.showActivityDesc') || 'Display your activity on your profile'}
241
+ value={settings.showActivity}
242
+ onValueChange={(value) => updateSetting('showActivity', value)}
243
+ />
244
+ <SettingRow
245
+ title={t('privacySettings.dataSharing') || 'Data Sharing'}
246
+ description={t('privacySettings.dataSharingDesc') || 'Allow sharing data for personalization'}
247
+ value={settings.dataSharing}
248
+ onValueChange={(value) => updateSetting('dataSharing', value)}
249
+ />
250
+ <SettingRow
251
+ title={t('privacySettings.locationSharing') || 'Location Sharing'}
252
+ description={t('privacySettings.locationSharingDesc') || 'Share your location'}
253
+ value={settings.locationSharing}
254
+ onValueChange={(value) => updateSetting('locationSharing', value)}
255
+ />
256
+ <SettingRow
257
+ title={t('privacySettings.analyticsSharing') || 'Analytics Sharing'}
258
+ description={t('privacySettings.analyticsSharingDesc') || 'Allow analytics data collection'}
259
+ value={settings.analyticsSharing}
260
+ onValueChange={(value) => updateSetting('analyticsSharing', value)}
261
+ />
262
+ </Section>
263
+
264
+ {/* Content & Safety */}
265
+ <Section title={t('privacySettings.sections.content') || 'CONTENT & SAFETY'} theme={theme}>
266
+ <SettingRow
267
+ title={t('privacySettings.sensitiveContent') || 'Show Sensitive Content'}
268
+ description={t('privacySettings.sensitiveContentDesc') || 'Allow sensitive or explicit content'}
269
+ value={settings.sensitiveContent}
270
+ onValueChange={(value) => updateSetting('sensitiveContent', value)}
271
+ />
272
+ <SettingRow
273
+ title={t('privacySettings.autoFilter') || 'Auto Filter'}
274
+ description={t('privacySettings.autoFilterDesc') || 'Automatically filter inappropriate content'}
275
+ value={settings.autoFilter}
276
+ onValueChange={(value) => updateSetting('autoFilter', value)}
277
+ />
278
+ <SettingRow
279
+ title={t('privacySettings.muteKeywords') || 'Mute Keywords'}
280
+ description={t('privacySettings.muteKeywordsDesc') || 'Hide posts containing muted keywords'}
281
+ value={settings.muteKeywords}
282
+ onValueChange={(value) => updateSetting('muteKeywords', value)}
283
+ />
284
+ <SettingRow
285
+ title={t('privacySettings.blockScreenshots') || 'Block Screenshots'}
286
+ description={t('privacySettings.blockScreenshotsDesc') || 'Prevent screenshots of your content'}
287
+ value={settings.blockScreenshots}
288
+ onValueChange={(value) => updateSetting('blockScreenshots', value)}
289
+ />
290
+ </Section>
291
+ </ScrollView>
292
+ </View>
293
+ );
294
+ };
295
+
296
+ const styles = StyleSheet.create({
297
+ container: {
298
+ flex: 1,
299
+ },
300
+ content: {
301
+ flex: 1,
302
+ padding: 16,
303
+ },
304
+ loadingContainer: {
305
+ flex: 1,
306
+ alignItems: 'center',
307
+ justifyContent: 'center',
308
+ },
309
+ settingRow: {
310
+ flexDirection: 'row',
311
+ justifyContent: 'space-between',
312
+ alignItems: 'center',
313
+ paddingVertical: 16,
314
+ borderBottomWidth: 1,
315
+ },
316
+ settingInfo: {
317
+ flex: 1,
318
+ marginRight: 16,
319
+ },
320
+ settingTitle: {
321
+ fontSize: 16,
322
+ fontWeight: '500',
323
+ marginBottom: 4,
324
+ },
325
+ settingDescription: {
326
+ fontSize: 14,
327
+ opacity: 0.7,
328
+ },
329
+ });
330
+
331
+ export default React.memo(PrivacySettingsScreen);
332
+
@@ -46,9 +46,6 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
46
46
  const isOwnProfile = currentUser && currentUser.id === userId;
47
47
 
48
48
  useEffect(() => {
49
- console.log('ProfileScreen - userId:', userId);
50
- console.log('ProfileScreen - username:', username);
51
-
52
49
  if (!userId) {
53
50
  setError('No user ID provided');
54
51
  setIsLoading(false);
@@ -61,23 +58,19 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
61
58
  // Load user profile and karma total
62
59
  Promise.all([
63
60
  oxyServices.getUserById(userId).catch((err: any) => {
64
- console.error('getUserById error:', err);
65
61
  // If this is the current user and the API call fails, use current user data as fallback
66
62
  if (currentUser && currentUser.id === userId) {
67
- console.log('API call failed, using current user as fallback:', currentUser);
68
63
  return currentUser;
69
64
  }
70
65
  throw err;
71
66
  }),
72
67
  oxyServices.getUserKarmaTotal ?
73
- oxyServices.getUserKarmaTotal(userId).catch((err: any) => {
74
- console.warn('getUserKarmaTotal error:', err);
68
+ oxyServices.getUserKarmaTotal(userId).catch(() => {
75
69
  return { total: undefined };
76
70
  }) :
77
71
  Promise.resolve({ total: undefined })
78
72
  ])
79
73
  .then(([profileRes, karmaRes]) => {
80
- console.log('Profile loaded:', profileRes);
81
74
  setProfile(profileRes);
82
75
  setKarmaTotal(typeof karmaRes.total === 'number' ? karmaRes.total : null);
83
76
 
@@ -0,0 +1,222 @@
1
+ import React, { useState, useCallback, useMemo, useEffect } from 'react';
2
+ import {
3
+ View,
4
+ Text,
5
+ TouchableOpacity,
6
+ StyleSheet,
7
+ ScrollView,
8
+ ActivityIndicator,
9
+ } from 'react-native';
10
+ import type { BaseScreenProps } from '../navigation/types';
11
+ import { useOxy } from '../context/OxyContext';
12
+ import { toast } from '../../lib/sonner';
13
+ import { Header, Section, GroupedSection } from '../components';
14
+ import { useI18n } from '../hooks/useI18n';
15
+
16
+ interface SavedItem {
17
+ id: string;
18
+ title: string;
19
+ type: 'post' | 'collection';
20
+ savedAt: Date;
21
+ url?: string;
22
+ }
23
+
24
+ const SavesCollectionsScreen: React.FC<BaseScreenProps> = ({
25
+ onClose,
26
+ theme,
27
+ goBack,
28
+ }) => {
29
+ const { oxyServices, user } = useOxy();
30
+ const { t } = useI18n();
31
+ const [savedItems, setSavedItems] = useState<SavedItem[]>([]);
32
+ const [collections, setCollections] = useState<any[]>([]);
33
+ const [isLoading, setIsLoading] = useState(true);
34
+ const [activeTab, setActiveTab] = useState<'saves' | 'collections'>('saves');
35
+
36
+ // Load saved items and collections
37
+ useEffect(() => {
38
+ const loadData = async () => {
39
+ try {
40
+ setIsLoading(true);
41
+ if (user?.id && oxyServices) {
42
+ setSavedItems([]);
43
+ setCollections([]);
44
+ }
45
+ } catch (error) {
46
+ toast.error(t('saves.loadError') || 'Failed to load saved items');
47
+ } finally {
48
+ setIsLoading(false);
49
+ }
50
+ };
51
+
52
+ loadData();
53
+ }, [user?.id, oxyServices, t]);
54
+
55
+ const themeStyles = useMemo(() => {
56
+ const isDarkTheme = theme === 'dark';
57
+ return {
58
+ textColor: isDarkTheme ? '#FFFFFF' : '#000000',
59
+ backgroundColor: isDarkTheme ? '#121212' : '#FFFFFF',
60
+ secondaryBackgroundColor: isDarkTheme ? '#222222' : '#F5F5F5',
61
+ borderColor: isDarkTheme ? '#444444' : '#E0E0E0',
62
+ tabActiveColor: '#007AFF',
63
+ tabInactiveColor: isDarkTheme ? '#888888' : '#666666',
64
+ };
65
+ }, [theme]);
66
+
67
+ const formatDate = (date: Date) => {
68
+ return date.toLocaleDateString();
69
+ };
70
+
71
+ return (
72
+ <View style={[styles.container, { backgroundColor: themeStyles.backgroundColor }]}>
73
+ <Header
74
+ title={t('saves.title') || 'Saves & Collections'}
75
+ theme={theme}
76
+ onBack={goBack || onClose}
77
+ variant="minimal"
78
+ elevation="subtle"
79
+ />
80
+
81
+ {/* Tabs */}
82
+ <View style={[styles.tabs, { borderBottomColor: themeStyles.borderColor }]}>
83
+ <TouchableOpacity
84
+ style={[
85
+ styles.tab,
86
+ activeTab === 'saves' && { borderBottomColor: themeStyles.tabActiveColor },
87
+ ]}
88
+ onPress={() => setActiveTab('saves')}
89
+ >
90
+ <Text
91
+ style={[
92
+ styles.tabText,
93
+ {
94
+ color: activeTab === 'saves' ? themeStyles.tabActiveColor : themeStyles.tabInactiveColor,
95
+ fontWeight: activeTab === 'saves' ? '600' : '400',
96
+ },
97
+ ]}
98
+ >
99
+ {t('saves.tabs.saves') || 'Saves'}
100
+ </Text>
101
+ </TouchableOpacity>
102
+ <TouchableOpacity
103
+ style={[
104
+ styles.tab,
105
+ activeTab === 'collections' && { borderBottomColor: themeStyles.tabActiveColor },
106
+ ]}
107
+ onPress={() => setActiveTab('collections')}
108
+ >
109
+ <Text
110
+ style={[
111
+ styles.tabText,
112
+ {
113
+ color: activeTab === 'collections' ? themeStyles.tabActiveColor : themeStyles.tabInactiveColor,
114
+ fontWeight: activeTab === 'collections' ? '600' : '400',
115
+ },
116
+ ]}
117
+ >
118
+ {t('saves.tabs.collections') || 'Collections'}
119
+ </Text>
120
+ </TouchableOpacity>
121
+ </View>
122
+
123
+ <ScrollView style={styles.content}>
124
+ {isLoading ? (
125
+ <View style={styles.loadingContainer}>
126
+ <ActivityIndicator size="large" color={themeStyles.textColor} />
127
+ <Text style={[styles.loadingText, { color: themeStyles.textColor }]}>
128
+ {t('saves.loading') || 'Loading...'}
129
+ </Text>
130
+ </View>
131
+ ) : activeTab === 'saves' ? (
132
+ savedItems.length === 0 ? (
133
+ <View style={styles.emptyContainer}>
134
+ <Text style={[styles.emptyText, { color: themeStyles.textColor }]}>
135
+ {t('saves.empty') || 'No saved items yet'}
136
+ </Text>
137
+ </View>
138
+ ) : (
139
+ <Section title={t('saves.savedItems') || 'Saved Items'} theme={theme} isFirst={true}>
140
+ <GroupedSection
141
+ items={savedItems.map((item) => ({
142
+ id: item.id,
143
+ icon: item.type === 'post' ? 'document-text' : 'folder',
144
+ iconColor: item.type === 'post' ? '#007AFF' : '#FF9500',
145
+ title: item.title,
146
+ subtitle: formatDate(item.savedAt),
147
+ }))}
148
+ theme={theme}
149
+ />
150
+ </Section>
151
+ )
152
+ ) : (
153
+ collections.length === 0 ? (
154
+ <View style={styles.emptyContainer}>
155
+ <Text style={[styles.emptyText, { color: themeStyles.textColor }]}>
156
+ {t('saves.noCollections') || 'No collections yet'}
157
+ </Text>
158
+ </View>
159
+ ) : (
160
+ <Section title={t('saves.collections') || 'Collections'} theme={theme} isFirst={true}>
161
+ <GroupedSection
162
+ items={collections.map((collection) => ({
163
+ id: collection.id,
164
+ icon: 'folder',
165
+ iconColor: '#FF9500',
166
+ title: collection.name,
167
+ subtitle: `${collection.itemCount || 0} items`,
168
+ }))}
169
+ theme={theme}
170
+ />
171
+ </Section>
172
+ )
173
+ )}
174
+ </ScrollView>
175
+ </View>
176
+ );
177
+ };
178
+
179
+ const styles = StyleSheet.create({
180
+ container: {
181
+ flex: 1,
182
+ },
183
+ tabs: {
184
+ flexDirection: 'row',
185
+ borderBottomWidth: 1,
186
+ },
187
+ tab: {
188
+ flex: 1,
189
+ paddingVertical: 16,
190
+ alignItems: 'center',
191
+ borderBottomWidth: 2,
192
+ borderBottomColor: 'transparent',
193
+ },
194
+ tabText: {
195
+ fontSize: 16,
196
+ },
197
+ content: {
198
+ flex: 1,
199
+ padding: 16,
200
+ },
201
+ loadingContainer: {
202
+ padding: 40,
203
+ alignItems: 'center',
204
+ justifyContent: 'center',
205
+ },
206
+ loadingText: {
207
+ marginTop: 12,
208
+ fontSize: 16,
209
+ },
210
+ emptyContainer: {
211
+ padding: 40,
212
+ alignItems: 'center',
213
+ justifyContent: 'center',
214
+ },
215
+ emptyText: {
216
+ fontSize: 16,
217
+ textAlign: 'center',
218
+ },
219
+ });
220
+
221
+ export default React.memo(SavesCollectionsScreen);
222
+