@oxyhq/services 5.11.8 → 5.11.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.
- package/lib/commonjs/core/OxyServices.js +104 -10
- package/lib/commonjs/core/OxyServices.js.map +1 -1
- package/lib/commonjs/ui/components/AnimationExample.js +213 -0
- package/lib/commonjs/ui/components/AnimationExample.js.map +1 -0
- package/lib/commonjs/ui/components/FollowButton.js +58 -47
- package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
- package/lib/commonjs/ui/components/GroupedItem.js +2 -1
- package/lib/commonjs/ui/components/GroupedItem.js.map +1 -1
- package/lib/commonjs/ui/components/GroupedSection.js +3 -0
- package/lib/commonjs/ui/components/GroupedSection.js.map +1 -1
- package/lib/commonjs/ui/components/Header.js +25 -11
- package/lib/commonjs/ui/components/Header.js.map +1 -1
- package/lib/commonjs/ui/components/OxyProvider.js +69 -33
- package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
- package/lib/commonjs/ui/components/ProfileCard.js +5 -1
- package/lib/commonjs/ui/components/ProfileCard.js.map +1 -1
- package/lib/commonjs/ui/components/index.js +0 -7
- package/lib/commonjs/ui/components/index.js.map +1 -1
- package/lib/commonjs/ui/components/internal/TextField.js +8 -4
- package/lib/commonjs/ui/components/internal/TextField.js.map +1 -1
- package/lib/commonjs/ui/components/photogrid/JustifiedPhotoGrid.js +161 -0
- package/lib/commonjs/ui/components/photogrid/JustifiedPhotoGrid.js.map +1 -0
- package/lib/commonjs/ui/context/OxyContext.js +97 -38
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/hooks/useFollow.types.js +2 -0
- package/lib/commonjs/ui/hooks/useFollow.types.js.map +1 -0
- package/lib/commonjs/ui/navigation/OxyRouter.js +10 -0
- package/lib/commonjs/ui/navigation/OxyRouter.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountCenterScreen.js +26 -14
- package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountOverviewScreen.js +3 -3
- package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js +64 -15
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +4 -4
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FeedbackScreen.js +72 -75
- package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FileManagementScreen.js +286 -126
- package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +322 -0
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/ProfileScreen.js +1 -1
- package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SessionManagementScreen.js +176 -174
- package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SignInScreen.js +43 -52
- package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SignUpScreen.js +6 -4
- package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +386 -0
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js +25 -15
- package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js.map +1 -1
- package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js +16 -9
- package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
- package/lib/commonjs/ui/styles/authStyles.js +1 -1
- package/lib/commonjs/ui/styles/authStyles.js.map +1 -1
- package/lib/module/core/OxyServices.js +103 -9
- package/lib/module/core/OxyServices.js.map +1 -1
- package/lib/module/ui/components/AnimationExample.js +209 -0
- package/lib/module/ui/components/AnimationExample.js.map +1 -0
- package/lib/module/ui/components/FollowButton.js +58 -47
- package/lib/module/ui/components/FollowButton.js.map +1 -1
- package/lib/module/ui/components/GroupedItem.js +2 -1
- package/lib/module/ui/components/GroupedItem.js.map +1 -1
- package/lib/module/ui/components/GroupedSection.js +3 -0
- package/lib/module/ui/components/GroupedSection.js.map +1 -1
- package/lib/module/ui/components/Header.js +25 -11
- package/lib/module/ui/components/Header.js.map +1 -1
- package/lib/module/ui/components/OxyProvider.js +70 -34
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/components/ProfileCard.js +5 -1
- package/lib/module/ui/components/ProfileCard.js.map +1 -1
- package/lib/module/ui/components/index.js +0 -1
- package/lib/module/ui/components/index.js.map +1 -1
- package/lib/module/ui/components/internal/TextField.js +8 -4
- package/lib/module/ui/components/internal/TextField.js.map +1 -1
- package/lib/module/ui/components/photogrid/JustifiedPhotoGrid.js +156 -0
- package/lib/module/ui/components/photogrid/JustifiedPhotoGrid.js.map +1 -0
- package/lib/module/ui/context/OxyContext.js +97 -39
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/hooks/useFollow.types.js +2 -0
- package/lib/module/ui/hooks/useFollow.types.js.map +1 -0
- package/lib/module/ui/navigation/OxyRouter.js +10 -0
- package/lib/module/ui/navigation/OxyRouter.js.map +1 -1
- package/lib/module/ui/screens/AccountCenterScreen.js +12 -1
- package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountOverviewScreen.js +3 -3
- package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountSettingsScreen.js +64 -15
- package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountSwitcherScreen.js +4 -4
- package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/module/ui/screens/FeedbackScreen.js +72 -75
- package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/module/ui/screens/FileManagementScreen.js +285 -125
- package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/module/ui/screens/LanguageSelectorScreen.js +319 -0
- package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -0
- package/lib/module/ui/screens/ProfileScreen.js +1 -1
- package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/module/ui/screens/SessionManagementScreen.js +177 -175
- package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
- package/lib/module/ui/screens/SignInScreen.js +44 -53
- package/lib/module/ui/screens/SignInScreen.js.map +1 -1
- package/lib/module/ui/screens/SignUpScreen.js +6 -4
- package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
- package/lib/module/ui/screens/WelcomeNewUserScreen.js +382 -0
- package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -0
- package/lib/module/ui/screens/internal/SignInPasswordStep.js +23 -14
- package/lib/module/ui/screens/internal/SignInPasswordStep.js.map +1 -1
- package/lib/module/ui/screens/internal/SignInUsernameStep.js +15 -9
- package/lib/module/ui/screens/internal/SignInUsernameStep.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaCenterScreen.js +1 -1
- package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
- package/lib/module/ui/styles/authStyles.js +1 -1
- package/lib/module/ui/styles/authStyles.js.map +1 -1
- package/lib/typescript/core/OxyServices.d.ts +95 -4
- package/lib/typescript/core/OxyServices.d.ts.map +1 -1
- package/lib/typescript/models/interfaces.d.ts +1 -5
- package/lib/typescript/models/interfaces.d.ts.map +1 -1
- package/lib/typescript/models/session.d.ts +1 -4
- package/lib/typescript/models/session.d.ts.map +1 -1
- package/lib/typescript/ui/components/AnimationExample.d.ts +4 -0
- package/lib/typescript/ui/components/AnimationExample.d.ts.map +1 -0
- package/lib/typescript/ui/components/FollowButton.d.ts.map +1 -1
- package/lib/typescript/ui/components/GroupedItem.d.ts.map +1 -1
- package/lib/typescript/ui/components/Header.d.ts +9 -0
- package/lib/typescript/ui/components/Header.d.ts.map +1 -1
- package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/ui/components/ProfileCard.d.ts +1 -3
- package/lib/typescript/ui/components/ProfileCard.d.ts.map +1 -1
- package/lib/typescript/ui/components/index.d.ts +0 -1
- package/lib/typescript/ui/components/index.d.ts.map +1 -1
- package/lib/typescript/ui/components/internal/TextField.d.ts.map +1 -1
- package/lib/typescript/ui/components/photogrid/JustifiedPhotoGrid.d.ts +27 -0
- package/lib/typescript/ui/components/photogrid/JustifiedPhotoGrid.d.ts.map +1 -0
- package/lib/typescript/ui/context/OxyContext.d.ts +6 -2
- package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/useFollow.types.d.ts +33 -0
- package/lib/typescript/ui/hooks/useFollow.types.d.ts.map +1 -0
- package/lib/typescript/ui/navigation/OxyRouter.d.ts.map +1 -1
- package/lib/typescript/ui/navigation/types.d.ts +5 -0
- package/lib/typescript/ui/navigation/types.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountCenterScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/FeedbackScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/FileManagementScreen.d.ts +18 -1
- package/lib/typescript/ui/screens/FileManagementScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/LanguageSelectorScreen.d.ts +7 -0
- package/lib/typescript/ui/screens/LanguageSelectorScreen.d.ts.map +1 -0
- package/lib/typescript/ui/screens/ProfileScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SessionManagementScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SignUpScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/WelcomeNewUserScreen.d.ts +13 -0
- package/lib/typescript/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -0
- package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts +5 -5
- package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts +4 -4
- package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts.map +1 -1
- package/lib/typescript/ui/styles/authStyles.d.ts +1 -1
- package/package.json +10 -2
- package/src/core/OxyServices.ts +107 -13
- package/src/models/interfaces.ts +2 -5
- package/src/models/session.ts +1 -4
- package/src/ui/components/AnimationExample.tsx +194 -0
- package/src/ui/components/FollowButton.tsx +65 -45
- package/src/ui/components/GroupedItem.tsx +1 -0
- package/src/ui/components/GroupedSection.tsx +1 -1
- package/src/ui/components/Header.tsx +36 -12
- package/src/ui/components/OxyProvider.tsx +66 -32
- package/src/ui/components/ProfileCard.tsx +6 -8
- package/src/ui/components/index.ts +0 -1
- package/src/ui/components/internal/TextField.tsx +12 -6
- package/src/ui/components/photogrid/JustifiedPhotoGrid.tsx +158 -0
- package/src/ui/context/OxyContext.tsx +84 -54
- package/src/ui/hooks/useFollow.types.ts +33 -0
- package/src/ui/navigation/OxyRouter.tsx +10 -0
- package/src/ui/navigation/types.ts +6 -0
- package/src/ui/screens/AccountCenterScreen.tsx +13 -7
- package/src/ui/screens/AccountOverviewScreen.tsx +3 -3
- package/src/ui/screens/AccountSettingsScreen.tsx +65 -13
- package/src/ui/screens/AccountSwitcherScreen.tsx +4 -4
- package/src/ui/screens/FeedbackScreen.tsx +57 -80
- package/src/ui/screens/FileManagementScreen.tsx +278 -175
- package/src/ui/screens/LanguageSelectorScreen.tsx +322 -0
- package/src/ui/screens/ProfileScreen.tsx +6 -1
- package/src/ui/screens/SessionManagementScreen.tsx +148 -151
- package/src/ui/screens/SignInScreen.tsx +43 -62
- package/src/ui/screens/SignUpScreen.tsx +3 -5
- package/src/ui/screens/WelcomeNewUserScreen.tsx +272 -0
- package/src/ui/screens/internal/SignInPasswordStep.tsx +28 -13
- package/src/ui/screens/internal/SignInUsernameStep.tsx +21 -11
- package/src/ui/screens/karma/KarmaCenterScreen.tsx +1 -1
- package/src/ui/styles/authStyles.ts +1 -1
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
import type { BaseScreenProps } from '../navigation/types';
|
|
16
16
|
import { useOxy } from '../context/OxyContext';
|
|
17
17
|
import Avatar from '../components/Avatar';
|
|
18
|
+
import type { FileMetadata } from '../../models/interfaces';
|
|
18
19
|
import OxyIcon from '../components/icon/OxyIcon';
|
|
19
20
|
import { Ionicons } from '@expo/vector-icons';
|
|
20
21
|
import { toast } from '../../lib/sonner';
|
|
@@ -29,7 +30,7 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
|
|
|
29
30
|
goBack,
|
|
30
31
|
navigate,
|
|
31
32
|
}) => {
|
|
32
|
-
const { user, oxyServices, isLoading: authLoading, isAuthenticated } = useOxy();
|
|
33
|
+
const { user, oxyServices, isLoading: authLoading, isAuthenticated, showBottomSheet } = useOxy();
|
|
33
34
|
const updateUser = useAuthStore((state) => state.updateUser);
|
|
34
35
|
const [isLoading, setIsLoading] = useState(false);
|
|
35
36
|
const [isSaving, setIsSaving] = useState(false);
|
|
@@ -45,7 +46,7 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
|
|
|
45
46
|
const [bio, setBio] = useState('');
|
|
46
47
|
const [location, setLocation] = useState('');
|
|
47
48
|
const [links, setLinks] = useState<string[]>([]);
|
|
48
|
-
const [
|
|
49
|
+
const [avatarFileId, setAvatarFileId] = useState('');
|
|
49
50
|
|
|
50
51
|
// Editing states
|
|
51
52
|
const [editingField, setEditingField] = useState<string | null>(null);
|
|
@@ -173,7 +174,7 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
|
|
|
173
174
|
setLinks([]);
|
|
174
175
|
setTempLinksWithMetadata([]);
|
|
175
176
|
}
|
|
176
|
-
|
|
177
|
+
setAvatarFileId(typeof user.avatar === 'string' ? user.avatar : '');
|
|
177
178
|
}
|
|
178
179
|
}, [user]);
|
|
179
180
|
|
|
@@ -203,8 +204,8 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
|
|
|
203
204
|
}
|
|
204
205
|
|
|
205
206
|
// Handle avatar
|
|
206
|
-
if (
|
|
207
|
-
updates.avatar =
|
|
207
|
+
if (avatarFileId !== (typeof user.avatar === 'string' ? user.avatar : '')) {
|
|
208
|
+
updates.avatar = avatarFileId;
|
|
208
209
|
}
|
|
209
210
|
|
|
210
211
|
await updateUser(updates, oxyServices);
|
|
@@ -225,14 +226,55 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
|
|
|
225
226
|
}
|
|
226
227
|
};
|
|
227
228
|
|
|
228
|
-
const
|
|
229
|
-
// Always use confirmAction for both web and native
|
|
229
|
+
const handleAvatarRemove = () => {
|
|
230
230
|
confirmAction('Remove your profile picture?', () => {
|
|
231
|
-
|
|
231
|
+
setAvatarFileId('');
|
|
232
232
|
toast.success('Avatar removed');
|
|
233
233
|
});
|
|
234
234
|
};
|
|
235
235
|
|
|
236
|
+
const openAvatarPicker = useCallback(() => {
|
|
237
|
+
showBottomSheet?.({
|
|
238
|
+
screen: 'FileManagement',
|
|
239
|
+
props: {
|
|
240
|
+
selectMode: true,
|
|
241
|
+
multiSelect: false,
|
|
242
|
+
afterSelect: 'back',
|
|
243
|
+
onSelect: (file: FileMetadata) => {
|
|
244
|
+
if (!file.contentType.startsWith('image/')) {
|
|
245
|
+
toast.error('Please select an image file');
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
// If already selected, do nothing
|
|
249
|
+
if (file.id === avatarFileId) {
|
|
250
|
+
toast.info?.('Avatar unchanged');
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
setAvatarFileId(file.id);
|
|
254
|
+
toast.success('Avatar selected');
|
|
255
|
+
// Auto-save avatar immediately (does not close edit profile screen)
|
|
256
|
+
(async () => {
|
|
257
|
+
try {
|
|
258
|
+
console.log('[AccountSettings] Auto-saving avatar', file.id);
|
|
259
|
+
setIsSaving(true);
|
|
260
|
+
await updateUser({ avatar: file.id }, oxyServices);
|
|
261
|
+
// Force refresh current user cache (updateUser already does a fetch with force=true internally)
|
|
262
|
+
// Extra safeguard: ensure avatarFileId reflects saved id (already set) and trigger any dependent UI.
|
|
263
|
+
toast.success('Avatar updated');
|
|
264
|
+
} catch (e: any) {
|
|
265
|
+
console.error('[AccountSettings] Failed to auto-save avatar', e);
|
|
266
|
+
toast.error(e.message || 'Failed to update avatar');
|
|
267
|
+
} finally {
|
|
268
|
+
setIsSaving(false);
|
|
269
|
+
}
|
|
270
|
+
})();
|
|
271
|
+
},
|
|
272
|
+
// Limit to images client-side by using photos view if later exposed
|
|
273
|
+
disabledMimeTypes: ['video/', 'audio/', 'application/pdf']
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
}, [showBottomSheet, oxyServices, avatarFileId, updateUser]);
|
|
277
|
+
|
|
236
278
|
const startEditing = (type: string, currentValue: string) => {
|
|
237
279
|
switch (type) {
|
|
238
280
|
case 'displayName':
|
|
@@ -871,19 +913,29 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
|
|
|
871
913
|
{/* Profile Picture Section */}
|
|
872
914
|
<View style={styles.section}>
|
|
873
915
|
<Text style={styles.sectionTitle}>Profile Picture</Text>
|
|
874
|
-
|
|
875
916
|
<GroupedSection
|
|
876
917
|
items={[
|
|
877
918
|
{
|
|
878
919
|
id: 'profile-photo',
|
|
879
|
-
icon:
|
|
920
|
+
icon: avatarFileId ? undefined : 'person',
|
|
880
921
|
iconColor: '#007AFF',
|
|
881
|
-
|
|
922
|
+
// Use download URL (includes token + fallback) instead of raw stream for reliability
|
|
923
|
+
image: avatarFileId ? oxyServices.getFileDownloadUrl(avatarFileId, 'thumb') : undefined,
|
|
882
924
|
imageSize: 40,
|
|
883
925
|
title: 'Profile Photo',
|
|
884
|
-
subtitle:
|
|
885
|
-
onPress:
|
|
926
|
+
subtitle: avatarFileId ? 'Tap to change your profile picture' : 'Tap to add a profile picture',
|
|
927
|
+
onPress: openAvatarPicker,
|
|
886
928
|
},
|
|
929
|
+
...(avatarFileId ? [
|
|
930
|
+
{
|
|
931
|
+
id: 'remove-profile-photo',
|
|
932
|
+
icon: 'trash',
|
|
933
|
+
iconColor: '#FF3B30',
|
|
934
|
+
title: 'Remove Photo',
|
|
935
|
+
subtitle: 'Delete current profile picture',
|
|
936
|
+
onPress: handleAvatarRemove,
|
|
937
|
+
}
|
|
938
|
+
] : []),
|
|
887
939
|
]}
|
|
888
940
|
theme={theme}
|
|
889
941
|
/>
|
|
@@ -294,8 +294,8 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
|
|
|
294
294
|
|
|
295
295
|
<View style={[styles.settingItem, styles.firstSettingItem, styles.lastSettingItem, styles.currentAccountCard]}>
|
|
296
296
|
<View style={styles.userIcon}>
|
|
297
|
-
{user.avatar
|
|
298
|
-
<Image source={{ uri: user.avatar
|
|
297
|
+
{typeof user.avatar === 'string' && user.avatar ? (
|
|
298
|
+
<Image source={{ uri: oxyServices.getFileDownloadUrl(user.avatar as string, 'thumb') }} style={styles.accountAvatarImage} />
|
|
299
299
|
) : (
|
|
300
300
|
<View style={styles.accountAvatarFallback}>
|
|
301
301
|
<Text style={styles.accountAvatarText}>
|
|
@@ -356,8 +356,8 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
|
|
|
356
356
|
<View style={styles.accountAvatarFallback}>
|
|
357
357
|
<ActivityIndicator size="small" color="#007AFF" />
|
|
358
358
|
</View>
|
|
359
|
-
) : userProfile?.avatar
|
|
360
|
-
<Image source={{ uri: userProfile.avatar
|
|
359
|
+
) : (typeof userProfile?.avatar === 'string' && userProfile.avatar) ? (
|
|
360
|
+
<Image source={{ uri: oxyServices.getFileDownloadUrl(userProfile.avatar as string, 'thumb') }} style={styles.accountAvatarImage} />
|
|
361
361
|
) : (
|
|
362
362
|
<View style={styles.accountAvatarFallback}>
|
|
363
363
|
<Text style={styles.accountAvatarText}>
|
|
@@ -20,6 +20,7 @@ import { useThemeColors } from '../styles';
|
|
|
20
20
|
import { Ionicons } from '@expo/vector-icons';
|
|
21
21
|
import { toast } from '../../lib/sonner';
|
|
22
22
|
import { packageInfo } from '../../constants/version';
|
|
23
|
+
import { GroupedSection } from '../components';
|
|
23
24
|
|
|
24
25
|
// Types for better type safety
|
|
25
26
|
interface FeedbackData {
|
|
@@ -64,6 +65,10 @@ const createStyles = (colors: any, theme: string) => StyleSheet.create({
|
|
|
64
65
|
container: {
|
|
65
66
|
flex: 1,
|
|
66
67
|
},
|
|
68
|
+
fullBleed: {
|
|
69
|
+
width: '100%',
|
|
70
|
+
alignSelf: 'stretch',
|
|
71
|
+
},
|
|
67
72
|
scrollContent: {
|
|
68
73
|
flexGrow: 1,
|
|
69
74
|
paddingHorizontal: 24,
|
|
@@ -622,6 +627,42 @@ const FeedbackScreen: React.FC<BaseScreenProps> = ({
|
|
|
622
627
|
}, [feedbackData, user, isTypeStepValid, isDetailsStepValid, isContactStepValid, resetForm]);
|
|
623
628
|
|
|
624
629
|
// Step components
|
|
630
|
+
// Memoized grouped section items
|
|
631
|
+
const feedbackTypeItems = useMemo(() => FEEDBACK_TYPES.map(type => ({
|
|
632
|
+
id: type.id,
|
|
633
|
+
icon: type.icon,
|
|
634
|
+
iconColor: type.color,
|
|
635
|
+
title: type.label,
|
|
636
|
+
subtitle: type.description,
|
|
637
|
+
onPress: () => { updateField('type', type.id); updateField('category', ''); },
|
|
638
|
+
selected: feedbackData.type === type.id,
|
|
639
|
+
showChevron: false,
|
|
640
|
+
multiRow: true,
|
|
641
|
+
dense: true,
|
|
642
|
+
})), [feedbackData.type, updateField]);
|
|
643
|
+
|
|
644
|
+
const categoryItems = useMemo(() => (feedbackData.type ? (CATEGORIES[feedbackData.type as keyof typeof CATEGORIES] || []).map(cat => ({
|
|
645
|
+
id: cat,
|
|
646
|
+
icon: feedbackData.category === cat ? 'checkmark-circle' : 'ellipse-outline',
|
|
647
|
+
iconColor: feedbackData.category === cat ? colors.primary : colors.secondaryText,
|
|
648
|
+
title: cat,
|
|
649
|
+
onPress: () => updateField('category', cat),
|
|
650
|
+
selected: feedbackData.category === cat,
|
|
651
|
+
showChevron: false,
|
|
652
|
+
dense: true,
|
|
653
|
+
})) : []), [feedbackData.type, feedbackData.category, colors.primary, colors.secondaryText, updateField]);
|
|
654
|
+
|
|
655
|
+
const priorityItems = useMemo(() => PRIORITY_LEVELS.map(p => ({
|
|
656
|
+
id: p.id,
|
|
657
|
+
icon: p.icon,
|
|
658
|
+
iconColor: p.color,
|
|
659
|
+
title: p.label,
|
|
660
|
+
onPress: () => updateField('priority', p.id),
|
|
661
|
+
selected: feedbackData.priority === p.id,
|
|
662
|
+
showChevron: false,
|
|
663
|
+
dense: true,
|
|
664
|
+
})), [feedbackData.priority, updateField]);
|
|
665
|
+
|
|
625
666
|
const renderTypeStep = useCallback(() => (
|
|
626
667
|
<Animated.View style={[
|
|
627
668
|
styles.stepContainer,
|
|
@@ -635,63 +676,16 @@ const FeedbackScreen: React.FC<BaseScreenProps> = ({
|
|
|
635
676
|
Choose the category that best describes your feedback
|
|
636
677
|
</Text>
|
|
637
678
|
</View>
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
{FEEDBACK_TYPES.map((type) => (
|
|
641
|
-
<TouchableOpacity
|
|
642
|
-
key={type.id}
|
|
643
|
-
style={[
|
|
644
|
-
styles.typeCard,
|
|
645
|
-
{
|
|
646
|
-
borderColor: feedbackData.type === type.id ? type.color : colors.border,
|
|
647
|
-
backgroundColor: feedbackData.type === type.id ? type.color + '10' : colors.inputBackground,
|
|
648
|
-
}
|
|
649
|
-
]}
|
|
650
|
-
onPress={() => {
|
|
651
|
-
updateField('type', type.id);
|
|
652
|
-
updateField('category', '');
|
|
653
|
-
}}
|
|
654
|
-
>
|
|
655
|
-
<View style={[styles.typeIcon, { backgroundColor: type.color + '20', padding: 12, borderRadius: 12 }]}>
|
|
656
|
-
<Ionicons name={type.icon as any} size={24} color={type.color} />
|
|
657
|
-
</View>
|
|
658
|
-
<Text style={[styles.typeLabel, { color: colors.text }]}>
|
|
659
|
-
{type.label}
|
|
660
|
-
</Text>
|
|
661
|
-
<Text style={[styles.typeDescription, { color: colors.secondaryText }]}>
|
|
662
|
-
{type.description}
|
|
663
|
-
</Text>
|
|
664
|
-
</TouchableOpacity>
|
|
665
|
-
))}
|
|
679
|
+
<View style={styles.fullBleed}>
|
|
680
|
+
<GroupedSection items={feedbackTypeItems} theme={theme as 'light' | 'dark'} />
|
|
666
681
|
</View>
|
|
667
682
|
|
|
668
683
|
{feedbackData.type && (
|
|
669
684
|
<View style={styles.categoryContainer}>
|
|
670
|
-
<Text style={[styles.modernLabel, { color: colors.secondaryText, marginBottom:
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
<TouchableOpacity
|
|
675
|
-
key={category}
|
|
676
|
-
style={[
|
|
677
|
-
styles.categoryButton,
|
|
678
|
-
{
|
|
679
|
-
borderColor: feedbackData.category === category ? colors.primary : colors.border,
|
|
680
|
-
backgroundColor: feedbackData.category === category ? colors.primary + '10' : colors.inputBackground,
|
|
681
|
-
}
|
|
682
|
-
]}
|
|
683
|
-
onPress={() => updateField('category', category)}
|
|
684
|
-
>
|
|
685
|
-
<Ionicons
|
|
686
|
-
name={feedbackData.category === category ? 'checkmark-circle' : 'ellipse-outline'}
|
|
687
|
-
size={20}
|
|
688
|
-
color={feedbackData.category === category ? colors.primary : colors.secondaryText}
|
|
689
|
-
/>
|
|
690
|
-
<Text style={[styles.categoryText, { color: colors.text }]}>
|
|
691
|
-
{category}
|
|
692
|
-
</Text>
|
|
693
|
-
</TouchableOpacity>
|
|
694
|
-
))}
|
|
685
|
+
<Text style={[styles.modernLabel, { color: colors.secondaryText, marginBottom: 8 }]}>Category</Text>
|
|
686
|
+
<View style={styles.fullBleed}>
|
|
687
|
+
<GroupedSection items={categoryItems} theme={theme as 'light' | 'dark'} />
|
|
688
|
+
</View>
|
|
695
689
|
</View>
|
|
696
690
|
)}
|
|
697
691
|
|
|
@@ -730,7 +724,7 @@ const FeedbackScreen: React.FC<BaseScreenProps> = ({
|
|
|
730
724
|
</TouchableOpacity>
|
|
731
725
|
</View>
|
|
732
726
|
</Animated.View>
|
|
733
|
-
), [fadeAnim, slideAnim, colors, feedbackData, updateField, goBack, nextStep, isTypeStepValid, styles]);
|
|
727
|
+
), [fadeAnim, slideAnim, colors, feedbackData, feedbackTypeItems, categoryItems, updateField, goBack, nextStep, isTypeStepValid, styles, theme]);
|
|
734
728
|
|
|
735
729
|
const renderDetailsStep = useCallback(() => (
|
|
736
730
|
<Animated.View style={[
|
|
@@ -776,28 +770,11 @@ const FeedbackScreen: React.FC<BaseScreenProps> = ({
|
|
|
776
770
|
styles={styles}
|
|
777
771
|
/>
|
|
778
772
|
|
|
779
|
-
<View style={
|
|
780
|
-
<Text style={[styles.modernLabel, { color: colors.secondaryText, marginBottom:
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
<TouchableOpacity
|
|
785
|
-
key={priority.id}
|
|
786
|
-
style={[
|
|
787
|
-
styles.priorityButton,
|
|
788
|
-
{
|
|
789
|
-
borderColor: feedbackData.priority === priority.id ? priority.color : colors.border,
|
|
790
|
-
backgroundColor: feedbackData.priority === priority.id ? priority.color + '10' : colors.inputBackground,
|
|
791
|
-
}
|
|
792
|
-
]}
|
|
793
|
-
onPress={() => updateField('priority', priority.id)}
|
|
794
|
-
>
|
|
795
|
-
<Ionicons name={priority.icon as any} size={20} color={priority.color} />
|
|
796
|
-
<Text style={[styles.priorityLabel, { color: colors.text }]}>
|
|
797
|
-
{priority.label}
|
|
798
|
-
</Text>
|
|
799
|
-
</TouchableOpacity>
|
|
800
|
-
))}
|
|
773
|
+
<View style={{ marginBottom: 24 }}>
|
|
774
|
+
<Text style={[styles.modernLabel, { color: colors.secondaryText, marginBottom: 8 }]}>Priority Level</Text>
|
|
775
|
+
<View style={styles.fullBleed}>
|
|
776
|
+
<GroupedSection items={priorityItems} theme={theme as 'light' | 'dark'} />
|
|
777
|
+
</View>
|
|
801
778
|
</View>
|
|
802
779
|
|
|
803
780
|
<View style={styles.navigationButtons}>
|
|
@@ -826,7 +803,7 @@ const FeedbackScreen: React.FC<BaseScreenProps> = ({
|
|
|
826
803
|
</TouchableOpacity>
|
|
827
804
|
</View>
|
|
828
805
|
</Animated.View>
|
|
829
|
-
), [fadeAnim, slideAnim, colors, feedbackData, updateField, setErrorMessage, prevStep, nextStep, isDetailsStepValid, styles]);
|
|
806
|
+
), [fadeAnim, slideAnim, colors, feedbackData, updateField, setErrorMessage, prevStep, nextStep, isDetailsStepValid, styles, priorityItems, theme]);
|
|
830
807
|
|
|
831
808
|
const renderContactStep = useCallback(() => (
|
|
832
809
|
<Animated.View style={[
|
|
@@ -1032,16 +1009,16 @@ const FeedbackScreen: React.FC<BaseScreenProps> = ({
|
|
|
1032
1009
|
|
|
1033
1010
|
return (
|
|
1034
1011
|
<KeyboardAvoidingView
|
|
1035
|
-
style={[styles.container, { backgroundColor: colors.background }]}
|
|
1012
|
+
style={[styles.container, { backgroundColor: theme === 'dark' ? colors.background : '#F7F9FC' }]}
|
|
1036
1013
|
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
|
1037
1014
|
>
|
|
1038
1015
|
<StatusBar
|
|
1039
1016
|
barStyle={theme === 'dark' ? 'light-content' : 'dark-content'}
|
|
1040
|
-
backgroundColor={colors.background}
|
|
1017
|
+
backgroundColor={theme === 'dark' ? colors.background : '#F7F9FC'}
|
|
1041
1018
|
/>
|
|
1042
1019
|
|
|
1043
1020
|
<ScrollView
|
|
1044
|
-
contentContainerStyle={styles.scrollContent}
|
|
1021
|
+
contentContainerStyle={[styles.scrollContent, { backgroundColor: 'transparent' }]}
|
|
1045
1022
|
showsVerticalScrollIndicator={false}
|
|
1046
1023
|
keyboardShouldPersistTaps="handled"
|
|
1047
1024
|
>
|