@oxyhq/services 6.9.3 → 6.9.5
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/ui/client.js +0 -7
- package/lib/commonjs/ui/client.js.map +1 -1
- package/lib/commonjs/ui/components/IconButton/IconButton.js +3 -3
- package/lib/commonjs/ui/components/IconButton/IconButton.js.map +1 -1
- package/lib/commonjs/ui/components/feedback/FormInput.js.map +1 -1
- package/lib/commonjs/ui/components/icon/OxyIcon.js.map +1 -1
- package/lib/commonjs/ui/components/types.js +4 -0
- package/lib/commonjs/ui/screens/AppInfoScreen.js +66 -60
- package/lib/commonjs/ui/screens/AppInfoScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FileManagementScreen.js +139 -79
- package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SessionManagementScreen.js +39 -29
- package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -1
- package/lib/module/ui/client.js +0 -1
- package/lib/module/ui/client.js.map +1 -1
- package/lib/module/ui/components/IconButton/IconButton.js +3 -3
- package/lib/module/ui/components/IconButton/IconButton.js.map +1 -1
- package/lib/module/ui/components/feedback/FormInput.js.map +1 -1
- package/lib/module/ui/components/icon/OxyIcon.js.map +1 -1
- package/lib/module/ui/components/types.js +2 -0
- package/lib/module/ui/screens/AppInfoScreen.js +66 -60
- package/lib/module/ui/screens/AppInfoScreen.js.map +1 -1
- package/lib/module/ui/screens/FileManagementScreen.js +139 -79
- package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/module/ui/screens/SessionManagementScreen.js +39 -29
- package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
- package/lib/typescript/commonjs/ui/client.d.ts +0 -1
- package/lib/typescript/commonjs/ui/client.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/types.d.ts +18 -17
- package/lib/typescript/commonjs/ui/components/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/AppInfoScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/FileManagementScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/SessionManagementScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/client.d.ts +0 -1
- package/lib/typescript/module/ui/client.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/types.d.ts +18 -17
- package/lib/typescript/module/ui/components/types.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/AppInfoScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/FileManagementScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/SessionManagementScreen.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/ui/client.ts +0 -1
- package/src/ui/components/IconButton/IconButton.tsx +2 -2
- package/src/ui/components/feedback/FormInput.tsx +1 -1
- package/src/ui/components/icon/OxyIcon.tsx +1 -1
- package/src/ui/components/types.tsx +19 -17
- package/src/ui/screens/AppInfoScreen.tsx +63 -61
- package/src/ui/screens/FileManagementScreen.tsx +130 -121
- package/src/ui/screens/SessionManagementScreen.tsx +30 -28
- package/lib/commonjs/ui/components/AnimationExample.js +0 -213
- package/lib/commonjs/ui/components/AnimationExample.js.map +0 -1
- package/lib/commonjs/ui/components/ErrorBoundary.js +0 -145
- package/lib/commonjs/ui/components/ErrorBoundary.js.map +0 -1
- package/lib/commonjs/ui/components/WebOxyProvider.js +0 -106
- package/lib/commonjs/ui/components/WebOxyProvider.js.map +0 -1
- package/lib/module/ui/components/AnimationExample.js +0 -209
- package/lib/module/ui/components/AnimationExample.js.map +0 -1
- package/lib/module/ui/components/ErrorBoundary.js +0 -139
- package/lib/module/ui/components/ErrorBoundary.js.map +0 -1
- package/lib/module/ui/components/WebOxyProvider.js +0 -102
- package/lib/module/ui/components/WebOxyProvider.js.map +0 -1
- package/lib/typescript/commonjs/ui/components/AnimationExample.d.ts +0 -4
- package/lib/typescript/commonjs/ui/components/AnimationExample.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/ErrorBoundary.d.ts +0 -31
- package/lib/typescript/commonjs/ui/components/ErrorBoundary.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/WebOxyProvider.d.ts +0 -52
- package/lib/typescript/commonjs/ui/components/WebOxyProvider.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/AnimationExample.d.ts +0 -4
- package/lib/typescript/module/ui/components/AnimationExample.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/ErrorBoundary.d.ts +0 -31
- package/lib/typescript/module/ui/components/ErrorBoundary.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/WebOxyProvider.d.ts +0 -52
- package/lib/typescript/module/ui/components/WebOxyProvider.d.ts.map +0 -1
- package/src/ui/components/AnimationExample.tsx +0 -195
- package/src/ui/components/ErrorBoundary.tsx +0 -154
- package/src/ui/components/WebOxyProvider.tsx +0 -117
|
@@ -27,6 +27,7 @@ import { useThemeStyles } from "../hooks/useThemeStyles.js";
|
|
|
27
27
|
import { useColorScheme } from "../hooks/useColorScheme.js";
|
|
28
28
|
import { normalizeTheme } from "../utils/themeUtils.js";
|
|
29
29
|
import { useOxy } from "../context/OxyContext.js";
|
|
30
|
+
import { useI18n } from "../hooks/useI18n.js";
|
|
30
31
|
import { useUploadFile } from "../hooks/mutations/useAccountMutations.js";
|
|
31
32
|
import { confirmAction, convertDocumentPickerAssetToFile, formatFileSize, getFileIcon, getSafeDownloadUrl } from "../utils/fileManagement.js";
|
|
32
33
|
import { FileViewer } from "../components/fileManagement/FileViewer.js";
|
|
@@ -34,6 +35,9 @@ import { FileDetailsModal } from "../components/fileManagement/FileDetailsModal.
|
|
|
34
35
|
import { UploadPreview } from "../components/fileManagement/UploadPreview.js";
|
|
35
36
|
import { fileManagementStyles } from "../components/fileManagement/styles.js";
|
|
36
37
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
38
|
+
/** Extract error message from unknown error type */
|
|
39
|
+
const getErrorMessage = error => error instanceof Error ? getErrorMessage(error) : typeof error === 'string' ? error : undefined;
|
|
40
|
+
|
|
37
41
|
// Animated button component for smooth transitions
|
|
38
42
|
const AnimatedButton = ({
|
|
39
43
|
isSelected,
|
|
@@ -102,6 +106,9 @@ const FileManagementScreen = ({
|
|
|
102
106
|
user,
|
|
103
107
|
oxyServices
|
|
104
108
|
} = useOxy();
|
|
109
|
+
const {
|
|
110
|
+
t
|
|
111
|
+
} = useI18n();
|
|
105
112
|
const uploadFileMutation = useUploadFile();
|
|
106
113
|
const files = useFiles();
|
|
107
114
|
// Ensure containerWidth is a number (TypeScript guard)
|
|
@@ -190,7 +197,7 @@ const FileManagementScreen = ({
|
|
|
190
197
|
if (disabledMimeTypes.length) {
|
|
191
198
|
const blocked = disabledMimeTypes.some(mt => file.contentType === mt || file.contentType.startsWith(mt.endsWith('/') ? mt : `${mt}/`));
|
|
192
199
|
if (blocked) {
|
|
193
|
-
toast.error('
|
|
200
|
+
toast.error(t('fileManagement.toasts.fileTypeBlocked'));
|
|
194
201
|
return;
|
|
195
202
|
}
|
|
196
203
|
}
|
|
@@ -230,7 +237,9 @@ const FileManagementScreen = ({
|
|
|
230
237
|
const already = next.has(file.id);
|
|
231
238
|
if (!already) {
|
|
232
239
|
if (maxSelection && next.size >= maxSelection) {
|
|
233
|
-
toast.error(
|
|
240
|
+
toast.error(t('fileManagement.toasts.maxSelection', {
|
|
241
|
+
max: maxSelection
|
|
242
|
+
}));
|
|
234
243
|
return prev;
|
|
235
244
|
}
|
|
236
245
|
next.add(file.id);
|
|
@@ -364,7 +373,7 @@ const FileManagementScreen = ({
|
|
|
364
373
|
}));
|
|
365
374
|
}
|
|
366
375
|
} catch (error) {
|
|
367
|
-
toast.error(error
|
|
376
|
+
toast.error(getErrorMessage(error) || t('fileManagement.toasts.loadFailed'));
|
|
368
377
|
} finally {
|
|
369
378
|
setLoading(false);
|
|
370
379
|
setRefreshing(false);
|
|
@@ -466,7 +475,9 @@ const FileManagementScreen = ({
|
|
|
466
475
|
const oversizedFiles = selectedFiles.filter(file => file.size > maxSize);
|
|
467
476
|
if (oversizedFiles.length > 0) {
|
|
468
477
|
const fileList = oversizedFiles.map(f => f.name).join(', ');
|
|
469
|
-
toast.error(
|
|
478
|
+
toast.error(t('fileManagement.toasts.filesTooLarge', {
|
|
479
|
+
files: fileList
|
|
480
|
+
}));
|
|
470
481
|
return [];
|
|
471
482
|
}
|
|
472
483
|
let successCount = 0;
|
|
@@ -555,7 +566,7 @@ const FileManagementScreen = ({
|
|
|
555
566
|
}
|
|
556
567
|
} catch (error) {
|
|
557
568
|
failureCount++;
|
|
558
|
-
const errorMessage = error
|
|
569
|
+
const errorMessage = getErrorMessage(error) || String(error) || 'Upload failed';
|
|
559
570
|
const fullError = `${fileName}: ${errorMessage}`;
|
|
560
571
|
errors.push(fullError);
|
|
561
572
|
if (__DEV__) {
|
|
@@ -564,7 +575,7 @@ const FileManagementScreen = ({
|
|
|
564
575
|
fileSize: raw.size,
|
|
565
576
|
fileType: raw.type,
|
|
566
577
|
error: errorMessage,
|
|
567
|
-
stack: error.stack
|
|
578
|
+
stack: error instanceof Error ? error.stack : undefined
|
|
568
579
|
});
|
|
569
580
|
}
|
|
570
581
|
|
|
@@ -575,24 +586,30 @@ const FileManagementScreen = ({
|
|
|
575
586
|
|
|
576
587
|
// Show success/error messages
|
|
577
588
|
if (successCount > 0) {
|
|
578
|
-
toast.success(
|
|
589
|
+
toast.success(t('fileManagement.toasts.uploadSuccess', {
|
|
590
|
+
count: successCount
|
|
591
|
+
}));
|
|
579
592
|
}
|
|
580
593
|
if (failureCount > 0) {
|
|
581
594
|
// Show detailed error message with first few errors
|
|
582
595
|
const errorDetails = errors.length > 0 ? `\n${errors.slice(0, 3).join('\n')}${errors.length > 3 ? `\n...and ${errors.length - 3} more` : ''}` : '';
|
|
583
|
-
toast.error(`${
|
|
596
|
+
toast.error(`${t('fileManagement.toasts.uploadFailed', {
|
|
597
|
+
count: failureCount
|
|
598
|
+
})}${errorDetails}`);
|
|
584
599
|
}
|
|
585
600
|
// Silent background refresh to ensure metadata/variants updated
|
|
586
601
|
setTimeout(() => {
|
|
587
602
|
loadFiles('silent');
|
|
588
603
|
}, 1200);
|
|
589
604
|
} catch (error) {
|
|
590
|
-
toast.error(error
|
|
605
|
+
toast.error(getErrorMessage(error) || t('fileManagement.toasts.uploadError'));
|
|
591
606
|
} finally {
|
|
592
607
|
storeSetUploadProgress(null);
|
|
593
608
|
}
|
|
594
609
|
return uploadedFiles;
|
|
595
610
|
};
|
|
611
|
+
|
|
612
|
+
// biome-ignore lint/suspicious/noExplicitAny: Files from document picker may have extra properties like uri
|
|
596
613
|
const handleFileSelection = useCallback(async selectedFiles => {
|
|
597
614
|
const MAX_FILE_SIZE = 100 * 1024 * 1024; // 100MB
|
|
598
615
|
const processedFiles = [];
|
|
@@ -602,34 +619,41 @@ const FileManagementScreen = ({
|
|
|
602
619
|
if (__DEV__) {
|
|
603
620
|
console.error('Invalid file: file is null or undefined');
|
|
604
621
|
}
|
|
605
|
-
toast.error('
|
|
622
|
+
toast.error(t('fileManagement.toasts.invalidFileMissing'));
|
|
606
623
|
continue;
|
|
607
624
|
}
|
|
608
625
|
if (!file.name || typeof file.name !== 'string') {
|
|
609
626
|
if (__DEV__) {
|
|
610
627
|
console.error('Invalid file: missing or invalid name property', file);
|
|
611
628
|
}
|
|
612
|
-
toast.error('
|
|
629
|
+
toast.error(t('fileManagement.toasts.invalidFileName'));
|
|
613
630
|
continue;
|
|
614
631
|
}
|
|
615
632
|
if (file.size === undefined || file.size === null || Number.isNaN(file.size)) {
|
|
616
633
|
if (__DEV__) {
|
|
617
634
|
console.error('Invalid file: missing or invalid size property', file);
|
|
618
635
|
}
|
|
619
|
-
toast.error(
|
|
636
|
+
toast.error(t('fileManagement.toasts.invalidFileSize', {
|
|
637
|
+
name: file.name || 'unknown'
|
|
638
|
+
}));
|
|
620
639
|
continue;
|
|
621
640
|
}
|
|
622
641
|
if (file.size <= 0) {
|
|
623
642
|
if (__DEV__) {
|
|
624
643
|
console.error('Invalid file: file size is zero or negative', file);
|
|
625
644
|
}
|
|
626
|
-
toast.error(
|
|
645
|
+
toast.error(t('fileManagement.toasts.fileEmpty', {
|
|
646
|
+
name: file.name
|
|
647
|
+
}));
|
|
627
648
|
continue;
|
|
628
649
|
}
|
|
629
650
|
|
|
630
651
|
// Validate file size
|
|
631
652
|
if (file.size > MAX_FILE_SIZE) {
|
|
632
|
-
toast.error(
|
|
653
|
+
toast.error(t('fileManagement.toasts.fileTooLarge', {
|
|
654
|
+
name: file.name,
|
|
655
|
+
maxSize: formatFileSize(MAX_FILE_SIZE)
|
|
656
|
+
}));
|
|
633
657
|
continue;
|
|
634
658
|
}
|
|
635
659
|
|
|
@@ -666,7 +690,7 @@ const FileManagementScreen = ({
|
|
|
666
690
|
});
|
|
667
691
|
}
|
|
668
692
|
if (processedFiles.length === 0) {
|
|
669
|
-
toast.error('
|
|
693
|
+
toast.error(t('fileManagement.toasts.noValidFiles'));
|
|
670
694
|
return;
|
|
671
695
|
}
|
|
672
696
|
|
|
@@ -721,7 +745,7 @@ const FileManagementScreen = ({
|
|
|
721
745
|
}
|
|
722
746
|
endUpload();
|
|
723
747
|
} catch (error) {
|
|
724
|
-
toast.error(error
|
|
748
|
+
toast.error(getErrorMessage(error) || t('fileManagement.toasts.uploadError'));
|
|
725
749
|
endUpload();
|
|
726
750
|
}
|
|
727
751
|
};
|
|
@@ -754,7 +778,7 @@ const FileManagementScreen = ({
|
|
|
754
778
|
const handleFileUpload = async () => {
|
|
755
779
|
// Prevent concurrent document picker calls
|
|
756
780
|
if (isPickingDocument) {
|
|
757
|
-
toast.error('
|
|
781
|
+
toast.error(t('fileManagement.toasts.waitForSelection'));
|
|
758
782
|
return;
|
|
759
783
|
}
|
|
760
784
|
try {
|
|
@@ -776,7 +800,7 @@ const FileManagementScreen = ({
|
|
|
776
800
|
}
|
|
777
801
|
if (!result.assets || result.assets.length === 0) {
|
|
778
802
|
setIsPickingDocument(false);
|
|
779
|
-
toast.error('
|
|
803
|
+
toast.error(t('fileManagement.toasts.noFilesSelected'));
|
|
780
804
|
return;
|
|
781
805
|
}
|
|
782
806
|
|
|
@@ -803,7 +827,7 @@ const FileManagementScreen = ({
|
|
|
803
827
|
}
|
|
804
828
|
return null;
|
|
805
829
|
}).catch(error => {
|
|
806
|
-
errors.push(`File "${doc.name || 'file'}": ${error
|
|
830
|
+
errors.push(`File "${doc.name || 'file'}": ${getErrorMessage(error) || 'Failed to process'}`);
|
|
807
831
|
return null;
|
|
808
832
|
}));
|
|
809
833
|
const convertedFiles = await Promise.all(conversionPromises);
|
|
@@ -818,7 +842,9 @@ const FileManagementScreen = ({
|
|
|
818
842
|
// Show errors if any
|
|
819
843
|
if (errors.length > 0) {
|
|
820
844
|
const errorMessage = errors.slice(0, 3).join('\n') + (errors.length > 3 ? `\n...and ${errors.length - 3} more` : '');
|
|
821
|
-
toast.error(
|
|
845
|
+
toast.error(t('fileManagement.toasts.loadSomeFailed', {
|
|
846
|
+
errors: errorMessage
|
|
847
|
+
}));
|
|
822
848
|
}
|
|
823
849
|
|
|
824
850
|
// Process successfully converted files
|
|
@@ -826,20 +852,20 @@ const FileManagementScreen = ({
|
|
|
826
852
|
await handleFileSelection(files);
|
|
827
853
|
} else {
|
|
828
854
|
// Files were selected but none could be converted
|
|
829
|
-
toast.error('
|
|
855
|
+
toast.error(t('fileManagement.toasts.noFilesProcessed'));
|
|
830
856
|
}
|
|
831
857
|
} catch (error) {
|
|
832
858
|
if (__DEV__) {
|
|
833
859
|
console.error('File upload error:', error);
|
|
834
860
|
}
|
|
835
|
-
if (error
|
|
836
|
-
if (error
|
|
837
|
-
toast.error('
|
|
861
|
+
if (getErrorMessage(error)?.includes('expo-document-picker') || getErrorMessage(error)?.includes('Different document picking in progress')) {
|
|
862
|
+
if (getErrorMessage(error)?.includes('Different document picking in progress')) {
|
|
863
|
+
toast.error(t('fileManagement.toasts.waitForSelection'));
|
|
838
864
|
} else {
|
|
839
|
-
toast.error('
|
|
865
|
+
toast.error(t('fileManagement.toasts.filePickerNotAvailable'));
|
|
840
866
|
}
|
|
841
867
|
} else {
|
|
842
|
-
toast.error(error
|
|
868
|
+
toast.error(getErrorMessage(error) || t('fileManagement.toasts.selectFilesFailed'));
|
|
843
869
|
}
|
|
844
870
|
} finally {
|
|
845
871
|
// Always reset the picking state, even if there was an error
|
|
@@ -848,14 +874,16 @@ const FileManagementScreen = ({
|
|
|
848
874
|
};
|
|
849
875
|
const handleFileDelete = async (fileId, filename) => {
|
|
850
876
|
// Use platform-aware confirmation dialog
|
|
851
|
-
const confirmed = await confirmAction(
|
|
877
|
+
const confirmed = await confirmAction(t('fileManagement.confirms.deleteFile', {
|
|
878
|
+
filename
|
|
879
|
+
}), t('fileManagement.deleteFile'), t('fileManagement.confirm'), t('common.cancel'));
|
|
852
880
|
if (!confirmed) {
|
|
853
881
|
return;
|
|
854
882
|
}
|
|
855
883
|
try {
|
|
856
884
|
storeSetDeleting(fileId);
|
|
857
885
|
await oxyServices.deleteFile(fileId);
|
|
858
|
-
toast.success('
|
|
886
|
+
toast.success(t('fileManagement.toasts.deleteSuccess'));
|
|
859
887
|
|
|
860
888
|
// Reload files after successful deletion
|
|
861
889
|
// Optimistic remove
|
|
@@ -864,14 +892,14 @@ const FileManagementScreen = ({
|
|
|
864
892
|
setTimeout(() => loadFiles('silent'), 800);
|
|
865
893
|
} catch (error) {
|
|
866
894
|
// Provide specific error messages
|
|
867
|
-
if (error
|
|
868
|
-
toast.error('
|
|
895
|
+
if (getErrorMessage(error)?.includes('File not found') || getErrorMessage(error)?.includes('404')) {
|
|
896
|
+
toast.error(t('fileManagement.toasts.fileNotFound'));
|
|
869
897
|
// Still reload files to refresh the list
|
|
870
898
|
setTimeout(() => loadFiles('silent'), 800);
|
|
871
|
-
} else if (error
|
|
872
|
-
toast.error('
|
|
899
|
+
} else if (getErrorMessage(error)?.includes('permission') || getErrorMessage(error)?.includes('403')) {
|
|
900
|
+
toast.error(t('fileManagement.toasts.noPermission'));
|
|
873
901
|
} else {
|
|
874
|
-
toast.error(error
|
|
902
|
+
toast.error(getErrorMessage(error) || t('fileManagement.toasts.deleteFailed'));
|
|
875
903
|
}
|
|
876
904
|
} finally {
|
|
877
905
|
storeSetDeleting(null);
|
|
@@ -884,7 +912,9 @@ const FileManagementScreen = ({
|
|
|
884
912
|
fileMap[f.id] = f;
|
|
885
913
|
});
|
|
886
914
|
const selectedFiles = Array.from(selectedIds).map(id => fileMap[id]).filter(Boolean);
|
|
887
|
-
const confirmed = await confirmAction(
|
|
915
|
+
const confirmed = await confirmAction(t('fileManagement.confirms.deleteFiles', {
|
|
916
|
+
count: selectedFiles.length
|
|
917
|
+
}), t('fileManagement.deleteFiles'), t('fileManagement.confirm'), t('common.cancel'));
|
|
888
918
|
if (!confirmed) return;
|
|
889
919
|
try {
|
|
890
920
|
const deletePromises = Array.from(selectedIds).map(async fileId => {
|
|
@@ -907,15 +937,19 @@ const FileManagementScreen = ({
|
|
|
907
937
|
const successful = results.filter(r => r.status === 'fulfilled' && r.value.success).length;
|
|
908
938
|
const failed = results.length - successful;
|
|
909
939
|
if (successful > 0) {
|
|
910
|
-
toast.success(
|
|
940
|
+
toast.success(t('fileManagement.toasts.bulkDeleteSuccess', {
|
|
941
|
+
count: successful
|
|
942
|
+
}));
|
|
911
943
|
}
|
|
912
944
|
if (failed > 0) {
|
|
913
|
-
toast.error(
|
|
945
|
+
toast.error(t('fileManagement.toasts.bulkDeleteFailed', {
|
|
946
|
+
count: failed
|
|
947
|
+
}));
|
|
914
948
|
}
|
|
915
949
|
setSelectedIds(new Set());
|
|
916
950
|
setTimeout(() => loadFiles('silent'), 800);
|
|
917
951
|
} catch (error) {
|
|
918
|
-
toast.error(error
|
|
952
|
+
toast.error(getErrorMessage(error) || t('fileManagement.toasts.bulkDeleteError'));
|
|
919
953
|
}
|
|
920
954
|
}, [selectedIds, files, oxyServices, loadFiles]);
|
|
921
955
|
const handleBulkVisibilityChange = useCallback(async visibility => {
|
|
@@ -940,7 +974,10 @@ const FileManagementScreen = ({
|
|
|
940
974
|
const successful = results.filter(r => r.status === 'fulfilled' && r.value.success).length;
|
|
941
975
|
const failed = results.length - successful;
|
|
942
976
|
if (successful > 0) {
|
|
943
|
-
toast.success(
|
|
977
|
+
toast.success(t('fileManagement.toasts.visibilitySuccess', {
|
|
978
|
+
count: successful,
|
|
979
|
+
visibility
|
|
980
|
+
}));
|
|
944
981
|
// Update file metadata in store
|
|
945
982
|
Array.from(selectedIds).forEach(fileId => {
|
|
946
983
|
useFileStore.getState().updateFile(fileId, {
|
|
@@ -952,11 +989,13 @@ const FileManagementScreen = ({
|
|
|
952
989
|
});
|
|
953
990
|
}
|
|
954
991
|
if (failed > 0) {
|
|
955
|
-
toast.error(
|
|
992
|
+
toast.error(t('fileManagement.toasts.visibilityFailed', {
|
|
993
|
+
count: failed
|
|
994
|
+
}));
|
|
956
995
|
}
|
|
957
996
|
setTimeout(() => loadFiles('silent'), 800);
|
|
958
997
|
} catch (error) {
|
|
959
|
-
toast.error(error
|
|
998
|
+
toast.error(getErrorMessage(error) || t('fileManagement.toasts.visibilityError'));
|
|
960
999
|
}
|
|
961
1000
|
}, [selectedIds, oxyServices, files, loadFiles]);
|
|
962
1001
|
|
|
@@ -978,7 +1017,7 @@ const FileManagementScreen = ({
|
|
|
978
1017
|
document.body.appendChild(link);
|
|
979
1018
|
link.click();
|
|
980
1019
|
document.body.removeChild(link);
|
|
981
|
-
toast.success('
|
|
1020
|
+
toast.success(t('fileManagement.toasts.downloadStarted'));
|
|
982
1021
|
} catch (linkError) {
|
|
983
1022
|
// Fallback to authenticated download
|
|
984
1023
|
const blob = await oxyServices.getFileContentAsBlob(fileId);
|
|
@@ -992,16 +1031,16 @@ const FileManagementScreen = ({
|
|
|
992
1031
|
|
|
993
1032
|
// Clean up the blob URL
|
|
994
1033
|
URL.revokeObjectURL(url);
|
|
995
|
-
toast.success('
|
|
1034
|
+
toast.success(t('fileManagement.toasts.downloadSuccess'));
|
|
996
1035
|
}
|
|
997
1036
|
} else {
|
|
998
1037
|
// For mobile, open the URL (user can save from browser)
|
|
999
1038
|
// Note: This is a simplified approach - for full mobile support,
|
|
1000
1039
|
// consider using expo-file-system or react-native-fs
|
|
1001
|
-
toast.info('
|
|
1040
|
+
toast.info(t('fileManagement.toasts.downloadMobile'));
|
|
1002
1041
|
}
|
|
1003
1042
|
} catch (error) {
|
|
1004
|
-
toast.error(error
|
|
1043
|
+
toast.error(getErrorMessage(error) || t('fileManagement.toasts.downloadFailed'));
|
|
1005
1044
|
}
|
|
1006
1045
|
};
|
|
1007
1046
|
const handleFileOpen = async file => {
|
|
@@ -1026,10 +1065,10 @@ const FileManagementScreen = ({
|
|
|
1026
1065
|
setFileContent(content);
|
|
1027
1066
|
}
|
|
1028
1067
|
} catch (error) {
|
|
1029
|
-
if (error
|
|
1030
|
-
toast.error('
|
|
1068
|
+
if (getErrorMessage(error)?.includes('404') || getErrorMessage(error)?.includes('not found')) {
|
|
1069
|
+
toast.error(t('fileManagement.toasts.fileNotFoundContent'));
|
|
1031
1070
|
} else {
|
|
1032
|
-
toast.error('
|
|
1071
|
+
toast.error(t('fileManagement.toasts.loadContentFailed'));
|
|
1033
1072
|
}
|
|
1034
1073
|
setFileContent(null);
|
|
1035
1074
|
}
|
|
@@ -1038,7 +1077,7 @@ const FileManagementScreen = ({
|
|
|
1038
1077
|
setFileContent(null);
|
|
1039
1078
|
}
|
|
1040
1079
|
} catch (error) {
|
|
1041
|
-
toast.error(error
|
|
1080
|
+
toast.error(getErrorMessage(error) || t('fileManagement.toasts.openFailed'));
|
|
1042
1081
|
} finally {
|
|
1043
1082
|
setLoadingFileContent(false);
|
|
1044
1083
|
}
|
|
@@ -1313,6 +1352,7 @@ const FileManagementScreen = ({
|
|
|
1313
1352
|
};
|
|
1314
1353
|
|
|
1315
1354
|
// GroupedSection-based file items (for 'all' view) replacing legacy flat list look
|
|
1355
|
+
// biome-ignore lint/suspicious/noExplicitAny: GroupedSection items have dynamic props
|
|
1316
1356
|
const groupedFileItems = useMemo(() => {
|
|
1317
1357
|
// filteredFiles is already sorted, so just use it directly
|
|
1318
1358
|
const sortedFiles = filteredFiles;
|
|
@@ -1492,6 +1532,7 @@ const FileManagementScreen = ({
|
|
|
1492
1532
|
numberOfLines: 2,
|
|
1493
1533
|
children: file.metadata.description
|
|
1494
1534
|
}) : undefined
|
|
1535
|
+
// biome-ignore lint/suspicious/noExplicitAny: GroupedSectionItem has dynamic properties
|
|
1495
1536
|
};
|
|
1496
1537
|
});
|
|
1497
1538
|
}, [filteredFiles, theme, themeStyles, deleting, handleFileDownload, handleFileDelete, handleFileOpen, getSafeDownloadUrlCallback, selectMode, selectedIds]);
|
|
@@ -1628,12 +1669,12 @@ const FileManagementScreen = ({
|
|
|
1628
1669
|
style: [fileManagementStyles.emptyStateTitle, {
|
|
1629
1670
|
color: themeStyles.textColor
|
|
1630
1671
|
}],
|
|
1631
|
-
children:
|
|
1672
|
+
children: t('fileManagement.emptyPhotos.title')
|
|
1632
1673
|
}), /*#__PURE__*/_jsxs(Text, {
|
|
1633
1674
|
style: [fileManagementStyles.emptyStateDescription, {
|
|
1634
1675
|
color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
|
|
1635
1676
|
}],
|
|
1636
|
-
children: [" ", user?.id === targetUserId ?
|
|
1677
|
+
children: [" ", user?.id === targetUserId ? t('fileManagement.emptyPhotos.ownDescription') : t('fileManagement.emptyPhotos.otherDescription'), " "]
|
|
1637
1678
|
}), user?.id === targetUserId && /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
1638
1679
|
style: [fileManagementStyles.emptyStateButton, {
|
|
1639
1680
|
backgroundColor: themeStyles.primaryColor
|
|
@@ -1653,7 +1694,7 @@ const FileManagementScreen = ({
|
|
|
1653
1694
|
color: "#FFFFFF"
|
|
1654
1695
|
}), /*#__PURE__*/_jsx(Text, {
|
|
1655
1696
|
style: fileManagementStyles.emptyStateButtonText,
|
|
1656
|
-
children:
|
|
1697
|
+
children: t('fileManagement.uploadPhotos')
|
|
1657
1698
|
})]
|
|
1658
1699
|
})
|
|
1659
1700
|
})]
|
|
@@ -1692,7 +1733,7 @@ const FileManagementScreen = ({
|
|
|
1692
1733
|
style: [fileManagementStyles.dimensionsLoadingText, {
|
|
1693
1734
|
color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
|
|
1694
1735
|
}],
|
|
1695
|
-
children:
|
|
1736
|
+
children: t('fileManagement.loadingPhotoLayout')
|
|
1696
1737
|
})]
|
|
1697
1738
|
}), /*#__PURE__*/_jsx(JustifiedPhotoGrid, {
|
|
1698
1739
|
photos: photos,
|
|
@@ -1719,12 +1760,12 @@ const FileManagementScreen = ({
|
|
|
1719
1760
|
style: [fileManagementStyles.emptyStateTitle, {
|
|
1720
1761
|
color: themeStyles.textColor
|
|
1721
1762
|
}],
|
|
1722
|
-
children:
|
|
1763
|
+
children: t('fileManagement.emptyFiles.title')
|
|
1723
1764
|
}), /*#__PURE__*/_jsx(Text, {
|
|
1724
1765
|
style: [fileManagementStyles.emptyStateDescription, {
|
|
1725
1766
|
color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
|
|
1726
1767
|
}],
|
|
1727
|
-
children: user?.id === targetUserId ?
|
|
1768
|
+
children: user?.id === targetUserId ? t('fileManagement.emptyFiles.ownDescription') : t('fileManagement.emptyFiles.otherDescription')
|
|
1728
1769
|
}), user?.id === targetUserId && /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
1729
1770
|
style: [fileManagementStyles.emptyStateButton, {
|
|
1730
1771
|
backgroundColor: themeStyles.primaryColor
|
|
@@ -1744,7 +1785,7 @@ const FileManagementScreen = ({
|
|
|
1744
1785
|
color: "#FFFFFF"
|
|
1745
1786
|
}), /*#__PURE__*/_jsx(Text, {
|
|
1746
1787
|
style: fileManagementStyles.emptyStateButtonText,
|
|
1747
|
-
children:
|
|
1788
|
+
children: t('fileManagement.uploadFiles')
|
|
1748
1789
|
})]
|
|
1749
1790
|
})
|
|
1750
1791
|
})]
|
|
@@ -1990,8 +2031,10 @@ const FileManagementScreen = ({
|
|
|
1990
2031
|
return /*#__PURE__*/_jsxs(View, {
|
|
1991
2032
|
style: fileManagementStyles.container,
|
|
1992
2033
|
children: [/*#__PURE__*/_jsx(Header, {
|
|
1993
|
-
title:
|
|
1994
|
-
subtitle:
|
|
2034
|
+
title: t('fileManagement.reviewFiles'),
|
|
2035
|
+
subtitle: t('fileManagement.readyToUpload', {
|
|
2036
|
+
count: pendingFiles.length
|
|
2037
|
+
}),
|
|
1995
2038
|
onBack: handleCancelUpload,
|
|
1996
2039
|
showBackButton: true,
|
|
1997
2040
|
variant: "minimal",
|
|
@@ -2011,43 +2054,58 @@ const FileManagementScreen = ({
|
|
|
2011
2054
|
return /*#__PURE__*/_jsxs(View, {
|
|
2012
2055
|
style: fileManagementStyles.container,
|
|
2013
2056
|
children: [/*#__PURE__*/_jsx(Header, {
|
|
2014
|
-
title: selectMode ? multiSelect ?
|
|
2015
|
-
|
|
2057
|
+
title: selectMode ? multiSelect ? maxSelection ? t('fileManagement.selectedWithMax', {
|
|
2058
|
+
count: selectedIds.size,
|
|
2059
|
+
max: maxSelection
|
|
2060
|
+
}) : t('fileManagement.selected', {
|
|
2061
|
+
count: selectedIds.size
|
|
2062
|
+
}) : t('fileManagement.selectFile') : viewMode === 'photos' ? t('fileManagement.photos') : t('fileManagement.title'),
|
|
2063
|
+
subtitle: selectMode ? multiSelect ? t('fileManagement.available', {
|
|
2064
|
+
count: filteredFiles.length
|
|
2065
|
+
}) : t('fileManagement.tapToSelect') : filteredFiles.length === 1 ? t('fileManagement.itemCount', {
|
|
2066
|
+
count: filteredFiles.length
|
|
2067
|
+
}) : t('fileManagement.itemCount_plural', {
|
|
2068
|
+
count: filteredFiles.length
|
|
2069
|
+
}),
|
|
2016
2070
|
rightActions: selectMode && multiSelect ? [{
|
|
2017
2071
|
key: 'clear',
|
|
2018
|
-
text: '
|
|
2072
|
+
text: t('fileManagement.clear'),
|
|
2019
2073
|
onPress: () => setSelectedIds(new Set()),
|
|
2020
2074
|
disabled: selectedIds.size === 0
|
|
2021
2075
|
}, {
|
|
2022
2076
|
key: 'confirm',
|
|
2023
|
-
text: '
|
|
2077
|
+
text: t('fileManagement.confirm'),
|
|
2024
2078
|
onPress: confirmMultiSelection,
|
|
2025
2079
|
disabled: selectedIds.size === 0
|
|
2026
2080
|
}] : !selectMode && selectedIds.size > 0 ? [{
|
|
2027
2081
|
key: 'clear',
|
|
2028
|
-
text: '
|
|
2082
|
+
text: t('fileManagement.clear'),
|
|
2029
2083
|
onPress: () => setSelectedIds(new Set())
|
|
2030
2084
|
}, {
|
|
2031
2085
|
key: 'delete',
|
|
2032
|
-
text:
|
|
2086
|
+
text: t('fileManagement.delete', {
|
|
2087
|
+
count: selectedIds.size
|
|
2088
|
+
}),
|
|
2033
2089
|
onPress: handleBulkDelete,
|
|
2034
2090
|
icon: 'delete'
|
|
2035
2091
|
}, {
|
|
2036
2092
|
key: 'visibility',
|
|
2037
|
-
text: '
|
|
2093
|
+
text: t('fileManagement.visibility'),
|
|
2038
2094
|
onPress: () => {
|
|
2039
2095
|
// Show visibility options menu
|
|
2040
|
-
Alert.alert('
|
|
2041
|
-
|
|
2096
|
+
Alert.alert(t('fileManagement.changeVisibility'), t('fileManagement.changeVisibilityConfirm', {
|
|
2097
|
+
count: selectedIds.size
|
|
2098
|
+
}), [{
|
|
2099
|
+
text: t('common.cancel'),
|
|
2042
2100
|
style: 'cancel'
|
|
2043
2101
|
}, {
|
|
2044
|
-
text: '
|
|
2102
|
+
text: t('fileManagement.private'),
|
|
2045
2103
|
onPress: () => handleBulkVisibilityChange('private')
|
|
2046
2104
|
}, {
|
|
2047
|
-
text: '
|
|
2105
|
+
text: t('fileManagement.public'),
|
|
2048
2106
|
onPress: () => handleBulkVisibilityChange('public')
|
|
2049
2107
|
}, {
|
|
2050
|
-
text: '
|
|
2108
|
+
text: t('fileManagement.unlisted'),
|
|
2051
2109
|
onPress: () => handleBulkVisibilityChange('unlisted')
|
|
2052
2110
|
}]);
|
|
2053
2111
|
},
|
|
@@ -2165,7 +2223,7 @@ const FileManagementScreen = ({
|
|
|
2165
2223
|
style: [fileManagementStyles.searchInput, {
|
|
2166
2224
|
color: themeStyles.textColor
|
|
2167
2225
|
}],
|
|
2168
|
-
placeholder: viewMode === 'photos' ? '
|
|
2226
|
+
placeholder: viewMode === 'photos' ? t('fileManagement.searchPhotos') : t('fileManagement.searchFiles'),
|
|
2169
2227
|
placeholderTextColor: themeStyles.colors.secondaryText,
|
|
2170
2228
|
value: searchQuery,
|
|
2171
2229
|
onChangeText: setSearchQuery
|
|
@@ -2193,7 +2251,7 @@ const FileManagementScreen = ({
|
|
|
2193
2251
|
style: [fileManagementStyles.statLabel, {
|
|
2194
2252
|
color: themeStyles.colors.secondaryText
|
|
2195
2253
|
}],
|
|
2196
|
-
children: searchQuery.length > 0 ? '
|
|
2254
|
+
children: 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')
|
|
2197
2255
|
})]
|
|
2198
2256
|
}), /*#__PURE__*/_jsxs(View, {
|
|
2199
2257
|
style: fileManagementStyles.statItem,
|
|
@@ -2206,7 +2264,7 @@ const FileManagementScreen = ({
|
|
|
2206
2264
|
style: [fileManagementStyles.statLabel, {
|
|
2207
2265
|
color: themeStyles.colors.secondaryText
|
|
2208
2266
|
}],
|
|
2209
|
-
children: searchQuery.length > 0 ? '
|
|
2267
|
+
children: searchQuery.length > 0 ? t('fileManagement.size') : t('fileManagement.totalSize')
|
|
2210
2268
|
})]
|
|
2211
2269
|
}), searchQuery.length > 0 && /*#__PURE__*/_jsxs(View, {
|
|
2212
2270
|
style: fileManagementStyles.statItem,
|
|
@@ -2219,7 +2277,7 @@ const FileManagementScreen = ({
|
|
|
2219
2277
|
style: [fileManagementStyles.statLabel, {
|
|
2220
2278
|
color: themeStyles.colors.secondaryText
|
|
2221
2279
|
}],
|
|
2222
|
-
children:
|
|
2280
|
+
children: t('fileManagement.total')
|
|
2223
2281
|
})]
|
|
2224
2282
|
})]
|
|
2225
2283
|
}), viewMode === 'photos' ? renderPhotoGrid() : /*#__PURE__*/_jsx(ScrollView, {
|
|
@@ -2255,12 +2313,14 @@ const FileManagementScreen = ({
|
|
|
2255
2313
|
style: [fileManagementStyles.emptyStateTitle, {
|
|
2256
2314
|
color: themeStyles.textColor
|
|
2257
2315
|
}],
|
|
2258
|
-
children:
|
|
2259
|
-
}), /*#__PURE__*/
|
|
2316
|
+
children: t('fileManagement.noResults.title')
|
|
2317
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
2260
2318
|
style: [fileManagementStyles.emptyStateDescription, {
|
|
2261
2319
|
color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
|
|
2262
2320
|
}],
|
|
2263
|
-
children:
|
|
2321
|
+
children: t('fileManagement.noResults.description', {
|
|
2322
|
+
query: searchQuery
|
|
2323
|
+
})
|
|
2264
2324
|
}), /*#__PURE__*/_jsxs(TouchableOpacity, {
|
|
2265
2325
|
style: [fileManagementStyles.emptyStateButton, {
|
|
2266
2326
|
backgroundColor: themeStyles.primaryColor
|
|
@@ -2272,7 +2332,7 @@ const FileManagementScreen = ({
|
|
|
2272
2332
|
color: "#FFFFFF"
|
|
2273
2333
|
}), /*#__PURE__*/_jsx(Text, {
|
|
2274
2334
|
style: fileManagementStyles.emptyStateButtonText,
|
|
2275
|
-
children:
|
|
2335
|
+
children: t('fileManagement.clearSearch')
|
|
2276
2336
|
})]
|
|
2277
2337
|
})]
|
|
2278
2338
|
}) : filteredFiles.length === 0 ? renderEmptyState() : /*#__PURE__*/_jsxs(_Fragment, {
|
|
@@ -2287,7 +2347,7 @@ const FileManagementScreen = ({
|
|
|
2287
2347
|
style: [fileManagementStyles.loadingMoreText, {
|
|
2288
2348
|
color: themeStyles.textColor
|
|
2289
2349
|
}],
|
|
2290
|
-
children:
|
|
2350
|
+
children: t('fileManagement.loadingMore')
|
|
2291
2351
|
})]
|
|
2292
2352
|
})]
|
|
2293
2353
|
})
|
|
@@ -2318,7 +2378,7 @@ const FileManagementScreen = ({
|
|
|
2318
2378
|
style: [fileManagementStyles.uploadBannerText, {
|
|
2319
2379
|
color: themeStyles.textColor
|
|
2320
2380
|
}],
|
|
2321
|
-
children: [
|
|
2381
|
+
children: [t('fileManagement.uploading'), uploadProgress ? ` ${uploadProgress.current}/${uploadProgress.total}` : '...']
|
|
2322
2382
|
}), uploadProgress && uploadProgress.total > 0 && /*#__PURE__*/_jsx(View, {
|
|
2323
2383
|
style: [fileManagementStyles.uploadProgressBarContainer, {
|
|
2324
2384
|
backgroundColor: themeStyles.isDarkTheme ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.1)'
|