@oxyhq/services 22.6.1 → 22.6.3

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 (72) hide show
  1. package/lib/commonjs/ui/components/fileManagement/FileViewer.js +99 -77
  2. package/lib/commonjs/ui/components/fileManagement/FileViewer.js.map +1 -1
  3. package/lib/commonjs/ui/components/fileManagement/UploadPreview.js +33 -40
  4. package/lib/commonjs/ui/components/fileManagement/UploadPreview.js.map +1 -1
  5. package/lib/commonjs/ui/components/photogrid/JustifiedPhotoGrid.js +92 -88
  6. package/lib/commonjs/ui/components/photogrid/JustifiedPhotoGrid.js.map +1 -1
  7. package/lib/commonjs/ui/screens/FileManagementScreen.js +169 -310
  8. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  9. package/lib/commonjs/ui/screens/fileManagement/FileListSection.js +17 -14
  10. package/lib/commonjs/ui/screens/fileManagement/FileListSection.js.map +1 -1
  11. package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js +16 -20
  12. package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
  13. package/lib/commonjs/ui/screens/fileManagement/UploadBar.js +29 -12
  14. package/lib/commonjs/ui/screens/fileManagement/UploadBar.js.map +1 -1
  15. package/lib/commonjs/ui/server.js +1 -1
  16. package/lib/commonjs/ui/server.js.map +1 -1
  17. package/lib/module/ui/components/fileManagement/FileViewer.js +100 -78
  18. package/lib/module/ui/components/fileManagement/FileViewer.js.map +1 -1
  19. package/lib/module/ui/components/fileManagement/UploadPreview.js +34 -41
  20. package/lib/module/ui/components/fileManagement/UploadPreview.js.map +1 -1
  21. package/lib/module/ui/components/photogrid/JustifiedPhotoGrid.js +94 -90
  22. package/lib/module/ui/components/photogrid/JustifiedPhotoGrid.js.map +1 -1
  23. package/lib/module/ui/screens/FileManagementScreen.js +171 -313
  24. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  25. package/lib/module/ui/screens/fileManagement/FileListSection.js +17 -14
  26. package/lib/module/ui/screens/fileManagement/FileListSection.js.map +1 -1
  27. package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js +17 -21
  28. package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
  29. package/lib/module/ui/screens/fileManagement/UploadBar.js +30 -13
  30. package/lib/module/ui/screens/fileManagement/UploadBar.js.map +1 -1
  31. package/lib/module/ui/server.js +1 -1
  32. package/lib/module/ui/server.js.map +1 -1
  33. package/lib/typescript/commonjs/ui/components/fileManagement/FileViewer.d.ts.map +1 -1
  34. package/lib/typescript/commonjs/ui/components/fileManagement/UploadPreview.d.ts.map +1 -1
  35. package/lib/typescript/commonjs/ui/components/photogrid/JustifiedPhotoGrid.d.ts.map +1 -1
  36. package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts +2 -2
  37. package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  38. package/lib/typescript/commonjs/ui/screens/FileManagementScreen.d.ts.map +1 -1
  39. package/lib/typescript/commonjs/ui/screens/fileManagement/FileListSection.d.ts.map +1 -1
  40. package/lib/typescript/commonjs/ui/screens/fileManagement/PhotoPickerSection.d.ts.map +1 -1
  41. package/lib/typescript/commonjs/ui/screens/fileManagement/UploadBar.d.ts.map +1 -1
  42. package/lib/typescript/commonjs/ui/server.d.ts +1 -1
  43. package/lib/typescript/commonjs/ui/server.d.ts.map +1 -1
  44. package/lib/typescript/module/ui/components/fileManagement/FileViewer.d.ts.map +1 -1
  45. package/lib/typescript/module/ui/components/fileManagement/UploadPreview.d.ts.map +1 -1
  46. package/lib/typescript/module/ui/components/photogrid/JustifiedPhotoGrid.d.ts.map +1 -1
  47. package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts +2 -2
  48. package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  49. package/lib/typescript/module/ui/screens/FileManagementScreen.d.ts.map +1 -1
  50. package/lib/typescript/module/ui/screens/fileManagement/FileListSection.d.ts.map +1 -1
  51. package/lib/typescript/module/ui/screens/fileManagement/PhotoPickerSection.d.ts.map +1 -1
  52. package/lib/typescript/module/ui/screens/fileManagement/UploadBar.d.ts.map +1 -1
  53. package/lib/typescript/module/ui/server.d.ts +1 -1
  54. package/lib/typescript/module/ui/server.d.ts.map +1 -1
  55. package/package.json +1 -1
  56. package/src/ui/components/fileManagement/FileViewer.tsx +82 -68
  57. package/src/ui/components/fileManagement/UploadPreview.tsx +34 -29
  58. package/src/ui/components/photogrid/JustifiedPhotoGrid.tsx +14 -12
  59. package/src/ui/screens/FileManagementScreen.tsx +123 -300
  60. package/src/ui/screens/fileManagement/FileListSection.tsx +10 -10
  61. package/src/ui/screens/fileManagement/PhotoPickerSection.tsx +16 -19
  62. package/src/ui/screens/fileManagement/UploadBar.tsx +29 -14
  63. package/src/ui/server.ts +1 -1
  64. package/lib/commonjs/ui/components/fileManagement/styles.js +0 -832
  65. package/lib/commonjs/ui/components/fileManagement/styles.js.map +0 -1
  66. package/lib/module/ui/components/fileManagement/styles.js +0 -828
  67. package/lib/module/ui/components/fileManagement/styles.js.map +0 -1
  68. package/lib/typescript/commonjs/ui/components/fileManagement/styles.d.ts +0 -825
  69. package/lib/typescript/commonjs/ui/components/fileManagement/styles.d.ts.map +0 -1
  70. package/lib/typescript/module/ui/components/fileManagement/styles.d.ts +0 -825
  71. package/lib/typescript/module/ui/components/fileManagement/styles.d.ts.map +0 -1
  72. package/src/ui/components/fileManagement/styles.ts +0 -823
@@ -12,6 +12,7 @@ import {
12
12
  Animated,
13
13
  Easing,
14
14
  AccessibilityInfo,
15
+ useWindowDimensions,
15
16
  } from 'react-native';
16
17
  import { Image as ExpoImage } from 'expo-image';
17
18
  import type { FileManagementScreenProps } from '../types/fileManagement';
@@ -33,13 +34,29 @@ import { useResolvedFileUrls, fileThumbSource } from '../hooks/useResolvedFileUr
33
34
  import { FileViewer } from '../components/fileManagement/FileViewer';
34
35
  import { FileDetailsModal } from '../components/fileManagement/FileDetailsModal';
35
36
  import { UploadPreview } from '../components/fileManagement/UploadPreview';
36
- import { fileManagementStyles } from '../components/fileManagement/styles';
37
37
  import { getErrorMessage } from './fileManagement/shared';
38
38
  import { useFileUploadState } from './fileManagement/hooks/useFileUploadState';
39
39
  import PhotoPickerView from './fileManagement/PhotoPickerSection';
40
40
  import FileListSection, { type FileListItem } from './fileManagement/FileListSection';
41
41
  import UploadBar from './fileManagement/UploadBar';
42
42
 
43
+ // Genuinely-inline-only styles: `viewModeButton` is spread into an Animated.View
44
+ // style array (interpolated backgroundColor), and the photo tiles are
45
+ // `expo-image` (no className remap). Everything else uses NativeWind classNames.
46
+ const screenStyles = StyleSheet.create({
47
+ viewModeButton: {
48
+ paddingHorizontal: 10,
49
+ paddingVertical: 6,
50
+ borderRadius: 999,
51
+ minWidth: 36,
52
+ alignItems: 'center',
53
+ justifyContent: 'center',
54
+ marginHorizontal: 1,
55
+ },
56
+ photoImage: { width: '100%', height: '100%', borderRadius: 8 },
57
+ justifiedPhotoImage: { width: '100%', height: '100%', borderRadius: 6 },
58
+ });
59
+
43
60
  // Animated button component for smooth transitions
44
61
  const AnimatedButton: React.FC<{
45
62
  isSelected: boolean;
@@ -100,7 +117,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
100
117
  goBack,
101
118
  navigate,
102
119
  userId,
103
- containerWidth = 400, // Fallback for when not provided by the router
120
+ containerWidth,
104
121
  selectMode = false,
105
122
  multiSelect = false,
106
123
  onSelect,
@@ -126,8 +143,13 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
126
143
  const visibilityChangeDialog = useDialogControl();
127
144
  const [pendingDeleteFile, setPendingDeleteFile] = useState<{ id: string; name: string } | null>(null);
128
145
  const files = useFiles();
129
- // Ensure containerWidth is a number (TypeScript guard)
130
- const safeContainerWidth: number = typeof containerWidth === 'number' ? containerWidth : 400;
146
+ const { width: windowWidth } = useWindowDimensions();
147
+ // Prefer an explicit sheet width from the router; fall back to the window
148
+ // so photo grids never size against a hardcoded 400px default.
149
+ const safeContainerWidth: number =
150
+ typeof containerWidth === 'number' && containerWidth > 0
151
+ ? containerWidth
152
+ : windowWidth;
131
153
  const uploading = useUploadingStore();
132
154
  const uploadProgress = useUploadAggregateProgress();
133
155
  const deleting = useDeletingStore();
@@ -782,79 +804,26 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
782
804
  fileDetailsControl.open();
783
805
  };
784
806
 
785
- const renderSimplePhotoItem = useCallback((photo: FileMetadata, index: number) => {
786
- const downloadUrl = thumbSourceFor(photo);
787
-
788
- // Calculate photo item width based on actual container size from bottom sheet
789
- let itemsPerRow = 3; // Default for mobile
790
- if (safeContainerWidth > 768) itemsPerRow = 4; // Desktop/tablet
791
- else if (safeContainerWidth > 480) itemsPerRow = 3; // Large mobile
792
-
793
- // Account for the photoScrollContainer padding (16px on each side = 32px total)
794
- const scrollContainerPadding = 32; // Total horizontal padding from photoScrollContainer
795
- const gaps = (itemsPerRow - 1) * 4; // Gap between items (4px)
796
- const availableWidth = safeContainerWidth - scrollContainerPadding;
797
- const itemWidth = (availableWidth - gaps) / itemsPerRow;
798
-
799
- return (
800
- <TouchableOpacity
801
- key={photo.id}
802
- style={[
803
- fileManagementStyles.simplePhotoItem,
804
- {
805
- width: itemWidth,
806
- height: itemWidth,
807
- marginRight: (index + 1) % itemsPerRow === 0 ? 0 : 4,
808
- ...(selectMode && selectedIds.has(photo.id) ? { borderWidth: 2, borderColor: colors.primary } : {})
809
- }
810
- ]}
811
- onPress={() => handleFileOpen(photo)}
812
- activeOpacity={0.8}
813
- >
814
- <View style={fileManagementStyles.simplePhotoContainer}>
815
- <ExpoImage
816
- source={{ uri: downloadUrl }}
817
- style={fileManagementStyles.simplePhotoImage}
818
- contentFit="cover"
819
- transition={120}
820
- cachePolicy="memory-disk"
821
- onError={() => {
822
- // Photo failed to load, will show placeholder
823
- }}
824
- accessibilityLabel={photo.filename}
825
- />
826
- {selectMode && (
827
- <View style={fileManagementStyles.selectionBadge}>
828
- <Ionicons name={selectedIds.has(photo.id) ? 'checkmark-circle' : 'ellipse-outline'} size={20} color={selectedIds.has(photo.id) ? colors.primary : colors.text} />
829
- </View>
830
- )}
831
- </View>
832
- </TouchableOpacity>
833
- );
834
- }, [thumbSourceFor, safeContainerWidth, selectMode, selectedIds, colors.primary, colors.text]);
835
-
836
807
  const renderJustifiedPhotoItem = useCallback((photo: FileMetadata, width: number, height: number, isLast: boolean) => {
837
808
  const downloadUrl = thumbSourceFor(photo);
838
809
 
839
810
  return (
840
811
  <TouchableOpacity
841
812
  key={photo.id}
842
- style={[
843
- fileManagementStyles.justifiedPhotoItem,
844
- {
845
- width,
846
- height,
847
- ...(selectMode && selectedIds.has(photo.id) ? { borderWidth: 2, borderColor: colors.primary } : {}),
848
- ...(selectMode && multiSelect && selectedIds.size > 0 && !selectedIds.has(photo.id) ? { opacity: 0.4 } : {}),
849
- },
850
- ]}
813
+ className="rounded-[6px] overflow-hidden relative"
814
+ style={{
815
+ width,
816
+ height,
817
+ ...(selectMode && selectedIds.has(photo.id) ? { borderWidth: 2, borderColor: colors.primary } : {}),
818
+ ...(selectMode && multiSelect && selectedIds.size > 0 && !selectedIds.has(photo.id) ? { opacity: 0.4 } : {}),
819
+ }}
851
820
  onPress={() => handleFileOpen(photo)}
852
821
  activeOpacity={0.8}
853
822
  >
854
- <View style={fileManagementStyles.justifiedPhotoContainer}>
823
+ <View className="w-full h-full relative rounded-[6px] overflow-hidden">
855
824
  <ExpoImage
856
825
  source={{ uri: downloadUrl }}
857
- style={fileManagementStyles.justifiedPhotoImage}
826
+ style={screenStyles.justifiedPhotoImage}
858
827
  contentFit="cover"
859
828
  transition={120}
860
829
  cachePolicy="memory-disk"
@@ -864,7 +833,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
864
833
  accessibilityLabel={photo.filename}
865
834
  />
866
835
  {selectMode && (
867
- <View style={fileManagementStyles.selectionBadge}>
836
+ <View className="absolute top-[4px] right-[4px] rounded-[12px] p-[2px]" style={{ backgroundColor: 'rgba(0,0,0,0.4)' }}>
868
837
  <Ionicons name={selectedIds.has(photo.id) ? 'checkmark-circle' : 'ellipse-outline'} size={20} color={selectedIds.has(photo.id) ? colors.primary : colors.text} />
869
838
  </View>
870
839
  )}
@@ -884,147 +853,6 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
884
853
  // eslint-disable-next-line react-hooks/exhaustive-deps
885
854
  }, [targetUserId]);
886
855
 
887
- const renderFileItem = (file: FileMetadata) => {
888
- const isImage = file.contentType.startsWith('image/');
889
- const isPDF = file.contentType.includes('pdf');
890
- const isVideo = file.contentType.startsWith('video/');
891
- const isAudio = file.contentType.startsWith('audio/');
892
- const hasPreview = isImage || isPDF || isVideo;
893
- const borderColor = colors.border;
894
-
895
- return (
896
- <View
897
- key={file.id}
898
- style={[fileManagementStyles.fileItem, { backgroundColor: colors.backgroundSecondary, borderColor }, selectMode && selectedIds.has(file.id) && { borderColor: colors.primary, borderWidth: 2 }]}
899
- >
900
- <TouchableOpacity
901
- style={fileManagementStyles.fileContent}
902
- onPress={() => handleFileOpen(file)}
903
- >
904
- {/* Preview Thumbnail */}
905
- <View style={fileManagementStyles.filePreviewContainer}>
906
- {hasPreview ? (
907
- <View style={fileManagementStyles.filePreview}>
908
- {isImage && (
909
- <ExpoImage
910
- source={{ uri: thumbSourceFor(file) }}
911
- style={fileManagementStyles.previewImage}
912
- contentFit="cover"
913
- transition={120}
914
- cachePolicy="memory-disk"
915
- onError={() => {
916
- // Image preview failed to load
917
- }}
918
- accessibilityLabel={file.filename}
919
- />
920
- )}
921
- {isPDF && (
922
- <View style={fileManagementStyles.pdfPreview}>
923
- <Ionicons name="document" size={32} color={colors.primary} />
924
- <Text style={[fileManagementStyles.pdfLabel, { color: colors.primary }]}>PDF</Text>
925
- </View>
926
- )}
927
- {isVideo && (
928
- <View style={fileManagementStyles.videoPreviewWrapper}>
929
- <ExpoImage
930
- source={{ uri: thumbSourceFor(file) }}
931
- style={fileManagementStyles.videoPosterImage}
932
- contentFit="cover"
933
- transition={120}
934
- cachePolicy="memory-disk"
935
- onError={(_: unknown) => {
936
- // If thumbnail not available, we still show icon overlay
937
- }}
938
- accessibilityLabel={`${file.filename} video thumbnail`}
939
- />
940
- <View style={fileManagementStyles.videoOverlay}>
941
- <Ionicons name="play" size={24} color="#FFFFFF" />
942
- </View>
943
- </View>
944
- )}
945
- {/* Fallback icon (hidden by default for images) */}
946
- <View
947
- style={[fileManagementStyles.fallbackIcon, { display: isImage ? 'none' : 'flex' }]}
948
- >
949
- <Ionicons
950
- name={getFileIcon(file.contentType)}
951
- size={32}
952
- color={colors.primary}
953
- />
954
- </View>
955
-
956
- {selectMode && (
957
- <View style={fileManagementStyles.selectionBadge}>
958
- <Ionicons name={selectedIds.has(file.id) ? 'checkmark-circle' : 'ellipse-outline'} size={22} color={selectedIds.has(file.id) ? colors.primary : colors.text} />
959
- </View>
960
- )}
961
- </View>
962
- ) : (
963
- <View style={fileManagementStyles.fileIconContainer}>
964
- <Ionicons
965
- name={getFileIcon(file.contentType)}
966
- size={32}
967
- color={colors.primary}
968
- />
969
- </View>
970
- )}
971
- </View>
972
-
973
- <View style={fileManagementStyles.fileInfo}>
974
- <Text style={[fileManagementStyles.fileName, { color: colors.text }]} numberOfLines={1}>
975
- {file.filename}
976
- </Text>
977
- <Text style={[fileManagementStyles.fileDetails, { color: colors.textSecondary }]}>
978
- {formatFileSize(file.length)} • {new Date(file.uploadDate).toLocaleDateString()}
979
- </Text>
980
- {file.metadata?.description && (
981
- <Text
982
- style={[fileManagementStyles.fileDescription, { color: colors.textTertiary }]}
983
- numberOfLines={2}
984
- >
985
- {file.metadata.description}
986
- </Text>
987
- )}
988
- </View>
989
- </TouchableOpacity>
990
-
991
- {!selectMode && (
992
- <View style={fileManagementStyles.fileActions}>
993
- {/* Preview button for supported files */}
994
- {hasPreview && (
995
- <TouchableOpacity
996
- style={[fileManagementStyles.actionButton, { backgroundColor: colors.backgroundSecondary }]}
997
- onPress={() => handleFileOpen(file)}
998
- >
999
- <Ionicons name="eye" size={20} color={colors.primary} />
1000
- </TouchableOpacity>
1001
- )}
1002
-
1003
- <TouchableOpacity
1004
- style={[fileManagementStyles.actionButton, { backgroundColor: colors.backgroundSecondary }]}
1005
- onPress={() => handleFileDownload(file.id, file.filename)}
1006
- >
1007
- <Ionicons name="download" size={20} color={colors.primary} />
1008
- </TouchableOpacity>
1009
-
1010
- {/* Always show delete button for debugging */}
1011
- <TouchableOpacity
1012
- style={[fileManagementStyles.actionButton, { backgroundColor: colors.negativeSubtle }]}
1013
- onPress={() => confirmFileDelete(file.id, file.filename)}
1014
- disabled={deleting === file.id}
1015
- >
1016
- {deleting === file.id ? (
1017
- <ActivityIndicator size="small" color={colors.error} />
1018
- ) : (
1019
- <Ionicons name="trash" size={20} color={colors.error} />
1020
- )}
1021
- </TouchableOpacity>
1022
- </View>
1023
- )}
1024
- </View>
1025
- );
1026
- };
1027
-
1028
856
  // SettingsListItem-based file items (for 'all' view)
1029
857
  const groupedFileItems: FileListItem[] = useMemo(() => {
1030
858
  // filteredFiles is already sorted, so just use it directly
@@ -1100,23 +928,26 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1100
928
  },
1101
929
  // Hide action buttons when selecting (in selectMode or bulk operations mode)
1102
930
  rightElement: (!selectMode && selectedIds.size === 0) ? (
1103
- <View style={fileManagementStyles.groupedActions}>
931
+ <View className="flex-row items-center gap-[6px] ml-[12px]">
1104
932
  {(isImage || isVideo || file.contentType.includes('pdf')) && (
1105
933
  <TouchableOpacity
1106
- style={[fileManagementStyles.groupedActionBtn, { backgroundColor: colors.backgroundSecondary }]}
934
+ className="w-[34px] h-[34px] rounded-[8px] items-center justify-center"
935
+ style={{ backgroundColor: colors.backgroundSecondary }}
1107
936
  onPress={() => handleFileOpen(file)}
1108
937
  >
1109
938
  <Ionicons name="eye" size={18} color={colors.primary} />
1110
939
  </TouchableOpacity>
1111
940
  )}
1112
941
  <TouchableOpacity
1113
- style={[fileManagementStyles.groupedActionBtn, { backgroundColor: colors.backgroundSecondary }]}
942
+ className="w-[34px] h-[34px] rounded-[8px] items-center justify-center"
943
+ style={{ backgroundColor: colors.backgroundSecondary }}
1114
944
  onPress={() => handleFileDownload(file.id, file.filename)}
1115
945
  >
1116
946
  <Ionicons name="download" size={18} color={colors.primary} />
1117
947
  </TouchableOpacity>
1118
948
  <TouchableOpacity
1119
- style={[fileManagementStyles.groupedActionBtn, { backgroundColor: colors.negativeSubtle }]}
949
+ className="w-[34px] h-[34px] rounded-[8px] items-center justify-center"
950
+ style={{ backgroundColor: colors.negativeSubtle }}
1120
951
  onPress={() => confirmFileDelete(file.id, file.filename)}
1121
952
  disabled={deleting === file.id}
1122
953
  >
@@ -1235,20 +1066,15 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1235
1066
  return (
1236
1067
  <TouchableOpacity
1237
1068
  key={photo.id}
1238
- style={[
1239
- fileManagementStyles.photoItem,
1240
- {
1241
- width: itemWidth,
1242
- height: itemWidth,
1243
- }
1244
- ]}
1069
+ className="rounded-[8px] overflow-hidden"
1070
+ style={{ width: itemWidth, height: itemWidth }}
1245
1071
  onPress={() => handleFileOpen(photo)}
1246
1072
  activeOpacity={0.8}
1247
1073
  >
1248
- <View style={fileManagementStyles.photoContainer}>
1074
+ <View className="w-full h-full relative rounded-[8px] overflow-hidden">
1249
1075
  <ExpoImage
1250
1076
  source={{ uri: downloadUrl }}
1251
- style={fileManagementStyles.photoImage}
1077
+ style={screenStyles.photoImage}
1252
1078
  contentFit="cover"
1253
1079
  transition={120}
1254
1080
  cachePolicy="memory-disk"
@@ -1267,17 +1093,18 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1267
1093
 
1268
1094
  if (photos.length === 0) {
1269
1095
  return (
1270
- <View style={fileManagementStyles.emptyState}>
1096
+ <View className="items-center py-[40px] px-[24px]">
1271
1097
  <Ionicons name="images-outline" size={64} color={colors.textTertiary} />
1272
- <Text style={[fileManagementStyles.emptyStateTitle, { color: colors.text }]}>{t('fileManagement.emptyPhotos.title')}</Text>
1273
- <Text style={[fileManagementStyles.emptyStateDescription, { color: colors.textSecondary }]}> {
1098
+ <Text className="text-[24px] font-bold mt-[16px] mb-[8px]" style={{ color: colors.text }}>{t('fileManagement.emptyPhotos.title')}</Text>
1099
+ <Text className="text-[16px] text-center leading-[24px] mb-[32px]" style={{ color: colors.textSecondary }}> {
1274
1100
  user?.id === targetUserId
1275
1101
  ? t('fileManagement.emptyPhotos.ownDescription')
1276
1102
  : t('fileManagement.emptyPhotos.otherDescription')
1277
1103
  } </Text>
1278
1104
  {user?.id === targetUserId && (
1279
1105
  <TouchableOpacity
1280
- style={[fileManagementStyles.emptyStateButton, { backgroundColor: colors.primary }]}
1106
+ className="flex-row items-center px-[24px] py-[12px] rounded-[24px] gap-[8px]"
1107
+ style={{ backgroundColor: colors.primary }}
1281
1108
  onPress={handleFileUpload}
1282
1109
  disabled={uploading || isPickingDocument}
1283
1110
  >
@@ -1288,7 +1115,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1288
1115
  ) : (
1289
1116
  <>
1290
1117
  <Ionicons name="cloud-upload" size={20} color="#FFFFFF" />
1291
- <Text style={fileManagementStyles.emptyStateButtonText}>{t('fileManagement.uploadPhotos')}</Text>
1118
+ <Text className="text-white text-[16px] font-semibold">{t('fileManagement.uploadPhotos')}</Text>
1292
1119
  </>
1293
1120
  )}
1294
1121
  </TouchableOpacity>
@@ -1300,8 +1127,8 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1300
1127
  return (
1301
1128
  <ScrollView
1302
1129
  ref={photoScrollViewRef}
1303
- style={fileManagementStyles.scrollView}
1304
- contentContainerStyle={fileManagementStyles.photoScrollContainer}
1130
+ className="flex-1"
1131
+ contentContainerClassName="p-[10px]"
1305
1132
  refreshControl={
1306
1133
  <RefreshControl
1307
1134
  refreshing={refreshing}
@@ -1320,9 +1147,9 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1320
1147
  scrollEventThrottle={250}
1321
1148
  >
1322
1149
  {loadingDimensions && (
1323
- <View style={fileManagementStyles.dimensionsLoadingIndicator}>
1150
+ <View className="flex-row items-center justify-center py-[16px] gap-[8px]">
1324
1151
  <ActivityIndicator size="small" color={colors.primary} />
1325
- <Text style={[fileManagementStyles.dimensionsLoadingText, { color: colors.textSecondary }]}>{t('fileManagement.loadingPhotoLayout')}</Text>
1152
+ <Text className="text-[14px] italic" style={{ color: colors.textSecondary }}>{t('fileManagement.loadingPhotoLayout')}</Text>
1326
1153
  </View>
1327
1154
  )}
1328
1155
 
@@ -1361,10 +1188,10 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1361
1188
 
1362
1189
 
1363
1190
  const renderEmptyState = () => (
1364
- <View style={fileManagementStyles.emptyState}>
1191
+ <View className="items-center py-[40px] px-[24px]">
1365
1192
  <Ionicons name="folder-open-outline" size={64} color={colors.textTertiary} />
1366
- <Text style={[fileManagementStyles.emptyStateTitle, { color: colors.text }]}>{t('fileManagement.emptyFiles.title')}</Text>
1367
- <Text style={[fileManagementStyles.emptyStateDescription, { color: colors.textSecondary }]}>
1193
+ <Text className="text-[24px] font-bold mt-[16px] mb-[8px]" style={{ color: colors.text }}>{t('fileManagement.emptyFiles.title')}</Text>
1194
+ <Text className="text-[16px] text-center leading-[24px] mb-[32px]" style={{ color: colors.textSecondary }}>
1368
1195
  {user?.id === targetUserId
1369
1196
  ? t('fileManagement.emptyFiles.ownDescription')
1370
1197
  : t('fileManagement.emptyFiles.otherDescription')
@@ -1372,7 +1199,8 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1372
1199
  </Text>
1373
1200
  {user?.id === targetUserId && (
1374
1201
  <TouchableOpacity
1375
- style={[fileManagementStyles.emptyStateButton, { backgroundColor: colors.primary }]}
1202
+ className="flex-row items-center px-[24px] py-[12px] rounded-[24px] gap-[8px]"
1203
+ style={{ backgroundColor: colors.primary }}
1376
1204
  onPress={handleFileUpload}
1377
1205
  disabled={uploading || isPickingDocument}
1378
1206
  >
@@ -1383,7 +1211,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1383
1211
  ) : (
1384
1212
  <>
1385
1213
  <Ionicons name="cloud-upload" size={20} color="#FFFFFF" />
1386
- <Text style={fileManagementStyles.emptyStateButtonText}>{t('fileManagement.uploadFiles')}</Text>
1214
+ <Text className="text-white text-[16px] font-semibold">{t('fileManagement.uploadFiles')}</Text>
1387
1215
  </>
1388
1216
  )}
1389
1217
  </TouchableOpacity>
@@ -1511,11 +1339,14 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1511
1339
  );
1512
1340
 
1513
1341
  return (
1514
- <View style={[fileManagementStyles.container, { backgroundColor }]}>
1342
+ <View className="flex-1" style={{ backgroundColor }}>
1515
1343
  {/* Header Skeleton */}
1516
- <View style={[fileManagementStyles.header, { borderBottomColor: colors.border, borderBottomWidth: StyleSheet.hairlineWidth }]}>
1344
+ <View
1345
+ className="flex-row items-center justify-between px-[16px] py-[12px] relative"
1346
+ style={{ borderBottomColor: colors.border, borderBottomWidth: StyleSheet.hairlineWidth }}
1347
+ >
1517
1348
  <SkeletonBox width={44} height={44} borderRadius={12} />
1518
- <View style={[fileManagementStyles.headerTitleContainer, { flex: 1 }]}>
1349
+ <View className="flex-1 items-center justify-center mx-[16px]">
1519
1350
  <SkeletonBox width={140} height={20} style={{ marginBottom: 6 }} />
1520
1351
  <SkeletonBox width={100} height={14} />
1521
1352
  </View>
@@ -1523,24 +1354,26 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1523
1354
  </View>
1524
1355
 
1525
1356
  {/* Controls Bar Skeleton */}
1526
- <View style={fileManagementStyles.controlsBar}>
1357
+ <View className="flex-row items-center justify-between px-[12px] py-[12px] gap-[12px]">
1527
1358
  <SkeletonBox width={100} height={36} borderRadius={18} />
1528
1359
  <SkeletonBox width={44} height={44} borderRadius={22} />
1529
1360
  </View>
1530
1361
 
1531
1362
  {/* Search Bar Skeleton */}
1532
- <View style={[fileManagementStyles.searchContainer, {
1533
- backgroundColor: colors.card,
1534
- }]}>
1363
+ <View
1364
+ className="flex-row items-center px-[14px] py-[10px] mx-[12px] mb-[12px] rounded-full gap-[10px]"
1365
+ style={{ backgroundColor: colors.card }}
1366
+ >
1535
1367
  <SkeletonBox width="100%" height={44} borderRadius={12} />
1536
1368
  </View>
1537
1369
 
1538
1370
  {/* Stats Container Skeleton */}
1539
- <View style={[fileManagementStyles.statsContainer, {
1540
- backgroundColor: colors.card,
1541
- }]}>
1371
+ <View
1372
+ className="flex-row px-[14px] py-[10px] mx-[12px] mb-[12px] rounded-[18px]"
1373
+ style={{ backgroundColor: colors.card }}
1374
+ >
1542
1375
  {[1, 2, 3].map((i) => (
1543
- <View key={i} style={fileManagementStyles.statItem}>
1376
+ <View key={i} className="flex-1 items-center py-[4px]">
1544
1377
  <SkeletonBox width={50} height={20} style={{ marginBottom: 4 }} delay={i * 30} />
1545
1378
  <SkeletonBox width={40} height={14} delay={i * 30 + 15} />
1546
1379
  </View>
@@ -1549,8 +1382,8 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1549
1382
 
1550
1383
  {/* File List Skeleton - Matching SettingsListItem */}
1551
1384
  <ScrollView
1552
- style={fileManagementStyles.scrollView}
1553
- contentContainerStyle={fileManagementStyles.scrollContainer}
1385
+ className="flex-1"
1386
+ contentContainerClassName="px-[12px] pt-0 pb-[12px]"
1554
1387
  showsVerticalScrollIndicator={false}
1555
1388
  >
1556
1389
  <View style={{
@@ -1654,7 +1487,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1654
1487
  // If upload preview is showing, render it inline instead of the file list
1655
1488
  if (showUploadPreview) {
1656
1489
  return (
1657
- <View style={fileManagementStyles.container}>
1490
+ <View className="flex-1">
1658
1491
  <Header
1659
1492
  title={t('fileManagement.reviewFiles')}
1660
1493
  subtitle={t('fileManagement.readyToUpload', { count: pendingFiles.length })}
@@ -1676,7 +1509,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1676
1509
  }
1677
1510
 
1678
1511
  return (
1679
- <View style={fileManagementStyles.container}>
1512
+ <View className="flex-1">
1680
1513
  <Header
1681
1514
  title={selectMode ? (multiSelect ? (maxSelection ? t('fileManagement.selectedWithMax', { count: selectedIds.size, max: maxSelection }) : t('fileManagement.selected', { count: selectedIds.size })) : t('fileManagement.selectFile')) : (viewMode === 'photos' ? t('fileManagement.photos') : t('fileManagement.title'))}
1682
1515
  subtitle={selectMode ? (multiSelect ? t('fileManagement.available', { count: filteredFiles.length }) : t('fileManagement.tapToSelect')) : (filteredFiles.length === 1 ? t('fileManagement.itemCount', { count: filteredFiles.length }) : t('fileManagement.itemCount_plural', { count: filteredFiles.length }))}
@@ -1722,25 +1555,24 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1722
1555
  titleAlignment="left"
1723
1556
  />
1724
1557
 
1725
- <View style={fileManagementStyles.controlsBar}>
1558
+ <View className="flex-row items-center justify-between px-[12px] py-[12px] gap-[12px]">
1726
1559
  <ScrollView
1727
1560
  horizontal
1728
1561
  showsHorizontalScrollIndicator={false}
1729
- style={fileManagementStyles.viewModeScroll}
1562
+ className="flex-1"
1563
+ style={{ maxWidth: '80%' }}
1730
1564
  >
1731
- <View style={[
1732
- fileManagementStyles.viewModeToggle,
1733
- {
1734
- backgroundColor: colors.card,
1735
- }
1736
- ]}>
1565
+ <View
1566
+ className="flex-row rounded-full p-[2px] overflow-hidden"
1567
+ style={{ backgroundColor: colors.card }}
1568
+ >
1737
1569
  <AnimatedButton
1738
1570
  isSelected={viewMode === 'all'}
1739
1571
  onPress={() => setViewMode('all')}
1740
1572
  icon={viewMode === 'all' ? 'folder' : 'folder-outline'}
1741
1573
  primaryColor={colors.primary}
1742
1574
  textColor={colors.text}
1743
- style={fileManagementStyles.viewModeButton}
1575
+ style={screenStyles.viewModeButton}
1744
1576
  accessibilityLabel={t('fileManagement.a11y.viewAll') || 'Show all files'}
1745
1577
  />
1746
1578
  <AnimatedButton
@@ -1749,7 +1581,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1749
1581
  icon={viewMode === 'photos' ? 'image-multiple' : 'image-multiple-outline'}
1750
1582
  primaryColor={colors.primary}
1751
1583
  textColor={colors.text}
1752
- style={fileManagementStyles.viewModeButton}
1584
+ style={screenStyles.viewModeButton}
1753
1585
  accessibilityLabel={t('fileManagement.a11y.viewPhotos') || 'Show photos only'}
1754
1586
  />
1755
1587
  {!isImageOnlyPicker && (
@@ -1760,7 +1592,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1760
1592
  icon={viewMode === 'videos' ? 'video' : 'video-outline'}
1761
1593
  primaryColor={colors.primary}
1762
1594
  textColor={colors.text}
1763
- style={fileManagementStyles.viewModeButton}
1595
+ style={screenStyles.viewModeButton}
1764
1596
  accessibilityLabel={t('fileManagement.a11y.viewVideos') || 'Show videos only'}
1765
1597
  />
1766
1598
  <AnimatedButton
@@ -1769,7 +1601,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1769
1601
  icon={viewMode === 'documents' ? 'file-document' : 'file-document-outline'}
1770
1602
  primaryColor={colors.primary}
1771
1603
  textColor={colors.text}
1772
- style={fileManagementStyles.viewModeButton}
1604
+ style={screenStyles.viewModeButton}
1773
1605
  accessibilityLabel={t('fileManagement.a11y.viewDocuments') || 'Show documents only'}
1774
1606
  />
1775
1607
  <AnimatedButton
@@ -1778,7 +1610,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1778
1610
  icon={viewMode === 'audio' ? 'music-note' : 'music-note-outline'}
1779
1611
  primaryColor={colors.primary}
1780
1612
  textColor={colors.text}
1781
- style={fileManagementStyles.viewModeButton}
1613
+ style={screenStyles.viewModeButton}
1782
1614
  accessibilityLabel={t('fileManagement.a11y.viewAudio') || 'Show audio only'}
1783
1615
  />
1784
1616
  </>
@@ -1786,9 +1618,8 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1786
1618
  </View>
1787
1619
  </ScrollView>
1788
1620
  <TouchableOpacity
1789
- style={[fileManagementStyles.sortButton, {
1790
- backgroundColor: colors.card,
1791
- }]}
1621
+ className="flex-row items-center justify-center px-[10px] py-[6px] rounded-full min-w-[36px] gap-[4px]"
1622
+ style={{ backgroundColor: colors.card }}
1792
1623
  accessibilityRole="button"
1793
1624
  accessibilityLabel={t('fileManagement.a11y.sortBy', {
1794
1625
  field: sortBy,
@@ -1823,11 +1654,8 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1823
1654
  </TouchableOpacity>
1824
1655
  {user?.id === targetUserId && (!selectMode || (selectMode && allowUploadInSelectMode)) && (
1825
1656
  <TouchableOpacity
1826
- style={[
1827
- fileManagementStyles.uploadButton,
1828
- isImageOnlyPicker && fileManagementStyles.uploadButtonExtended,
1829
- { backgroundColor: colors.primary },
1830
- ]}
1657
+ className={`h-[44px] rounded-[22px] items-center justify-center ${isImageOnlyPicker ? 'w-auto min-w-[44px] px-[14px]' : 'w-[44px]'}`}
1658
+ style={{ backgroundColor: colors.primary }}
1831
1659
  onPress={handleFileUpload}
1832
1660
  disabled={uploading || isPickingDocument}
1833
1661
  accessibilityRole="button"
@@ -1839,10 +1667,10 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1839
1667
  accessibilityState={{ busy: uploading || isPickingDocument }}
1840
1668
  >
1841
1669
  {uploading ? (
1842
- <View style={fileManagementStyles.uploadProgress}>
1670
+ <View className="items-center justify-center">
1843
1671
  <ActivityIndicator size="small" color="#FFFFFF" />
1844
1672
  {uploadProgress && (
1845
- <Text style={fileManagementStyles.uploadProgressText}>
1673
+ <Text className="text-white text-[10px] font-semibold mt-[2px]">
1846
1674
  {uploadProgress.current}/{uploadProgress.total}
1847
1675
  </Text>
1848
1676
  )}
@@ -1850,9 +1678,9 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1850
1678
  ) : isPickingDocument ? (
1851
1679
  <ActivityIndicator size="small" color="#FFFFFF" />
1852
1680
  ) : isImageOnlyPicker ? (
1853
- <View style={fileManagementStyles.uploadButtonContent}>
1681
+ <View className="flex-row items-center gap-[6px]">
1854
1682
  <Ionicons name="cloud-upload" size={18} color="#FFFFFF" />
1855
- <Text style={fileManagementStyles.uploadButtonLabel} numberOfLines={1}>
1683
+ <Text className="text-white text-[14px] font-semibold" numberOfLines={1}>
1856
1684
  {t('fileManagement.upload') || 'Upload'}
1857
1685
  </Text>
1858
1686
  </View>
@@ -1865,15 +1693,14 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1865
1693
 
1866
1694
  {/* Search Bar */}
1867
1695
  {files.length > 0 && (viewMode === 'all' || files.some(f => f.contentType.startsWith('image/'))) && (
1868
- <View style={[
1869
- fileManagementStyles.searchContainer,
1870
- {
1871
- backgroundColor: colors.card,
1872
- }
1873
- ]}>
1696
+ <View
1697
+ className="flex-row items-center px-[14px] py-[10px] mx-[12px] mb-[12px] rounded-full gap-[10px]"
1698
+ style={{ backgroundColor: colors.card }}
1699
+ >
1874
1700
  <Ionicons name="search" size={22} color={colors.icon} />
1875
1701
  <TextInput
1876
- style={[fileManagementStyles.searchInput, { color: colors.text }]}
1702
+ className="flex-1 text-[16px] leading-[20px]"
1703
+ style={{ color: colors.text }}
1877
1704
  placeholder={viewMode === 'photos' ? t('fileManagement.searchPhotos') : t('fileManagement.searchFiles')}
1878
1705
  placeholderTextColor={colors.textSecondary}
1879
1706
  value={searchQuery}
@@ -1882,7 +1709,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1882
1709
  {searchQuery.length > 0 && (
1883
1710
  <TouchableOpacity
1884
1711
  onPress={() => setSearchQuery('')}
1885
- style={fileManagementStyles.searchClearButton}
1712
+ className="p-[4px] rounded-[12px] items-center justify-center"
1886
1713
  >
1887
1714
  <Ionicons name="close-circle" size={22} color={colors.icon} />
1888
1715
  </TouchableOpacity>
@@ -1892,30 +1719,28 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1892
1719
 
1893
1720
  {/* File Stats */}
1894
1721
  {files.length > 0 && (
1895
- <View style={[
1896
- fileManagementStyles.statsContainer,
1897
- {
1898
- backgroundColor: colors.card,
1899
- }
1900
- ]}>
1901
- <View style={fileManagementStyles.statItem}>
1902
- <Text style={[fileManagementStyles.statValue, { color: colors.text }]}>{filteredFiles.length}</Text>
1903
- <Text style={[fileManagementStyles.statLabel, { color: colors.textSecondary }]}>
1722
+ <View
1723
+ className="flex-row px-[14px] py-[10px] mx-[12px] mb-[12px] rounded-[18px]"
1724
+ style={{ backgroundColor: colors.card }}
1725
+ >
1726
+ <View className="flex-1 items-center py-[4px]">
1727
+ <Text className="text-[20px] font-extrabold leading-[24px]" style={{ color: colors.text, letterSpacing: -0.5 }}>{filteredFiles.length}</Text>
1728
+ <Text className="text-[12px] font-medium mt-[2px]" style={{ color: colors.textSecondary, letterSpacing: 0.2 }}>
1904
1729
  {searchQuery.length > 0 ? t('fileManagement.found') : (filteredFiles.length === 1 ? (viewMode === 'photos' ? t('fileManagement.photo') : t('fileManagement.file')) : (viewMode === 'photos' ? t('fileManagement.photos_stat') : t('fileManagement.files')))}
1905
1730
  </Text>
1906
1731
  </View>
1907
- <View style={fileManagementStyles.statItem}>
1908
- <Text style={[fileManagementStyles.statValue, { color: colors.text }]}>
1732
+ <View className="flex-1 items-center py-[4px]">
1733
+ <Text className="text-[20px] font-extrabold leading-[24px]" style={{ color: colors.text, letterSpacing: -0.5 }}>
1909
1734
  {formatFileSize(filteredFiles.reduce((total, file) => total + file.length, 0))}
1910
1735
  </Text>
1911
- <Text style={[fileManagementStyles.statLabel, { color: colors.textSecondary }]}>
1736
+ <Text className="text-[12px] font-medium mt-[2px]" style={{ color: colors.textSecondary, letterSpacing: 0.2 }}>
1912
1737
  {searchQuery.length > 0 ? t('fileManagement.size') : t('fileManagement.totalSize')}
1913
1738
  </Text>
1914
1739
  </View>
1915
1740
  {searchQuery.length > 0 && (
1916
- <View style={fileManagementStyles.statItem}>
1917
- <Text style={[fileManagementStyles.statValue, { color: colors.text }]}>{files.length}</Text>
1918
- <Text style={[fileManagementStyles.statLabel, { color: colors.textSecondary }]}>
1741
+ <View className="flex-1 items-center py-[4px]">
1742
+ <Text className="text-[20px] font-extrabold leading-[24px]" style={{ color: colors.text, letterSpacing: -0.5 }}>{files.length}</Text>
1743
+ <Text className="text-[12px] font-medium mt-[2px]" style={{ color: colors.textSecondary, letterSpacing: 0.2 }}>
1919
1744
  {t('fileManagement.total')}
1920
1745
  </Text>
1921
1746
  </View>
@@ -1998,6 +1823,4 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1998
1823
  );
1999
1824
  };
2000
1825
 
2001
- // Styles have been moved to components/fileManagement/styles.ts
2002
-
2003
1826
  export default FileManagementScreen;