Merge branch 'feat/rbf-wording' into 'main'
[ProtonMail-WebClient.git] / packages / drive-store / store / _uploads / useUploadInput.ts
blobf588c7675ad97f18c4e06528db9763e7ffb23460
1 import type { ChangeEvent } from 'react';
2 import { useEffect, useRef } from 'react';
4 import { c } from 'ttag';
6 import { useNotifications } from '@proton/components';
8 import { logError } from '../../utils/errorHandling';
9 import { useUploadProvider } from './UploadProvider';
10 import type { UploadFileItem, UploadFileList } from './interface';
12 export function useFileUploadInput(shareId: string, linkId: string, isForPhotos: boolean = false) {
13     return useUploadInput(shareId, linkId, false, isForPhotos);
16 export function useFolderUploadInput(shareId: string, linkId: string, isForPhotos: boolean = false) {
17     return useUploadInput(shareId, linkId, true, isForPhotos);
20 function useUploadInput(shareId: string, linkId: string, forFolders?: boolean, isForPhotos?: boolean) {
21     const { uploadFiles } = useUploadProvider();
22     const { createNotification } = useNotifications();
24     const inputRef = useRef<HTMLInputElement>(null);
26     useEffect(() => {
27         if (forFolders && inputRef.current) {
28             // React types don't allow `webkitdirectory` but it exists and works
29             inputRef.current.setAttribute('webkitdirectory', 'true');
30         }
31     }, [forFolders]);
33     const getItemsToUpload = (files: FileList): UploadFileList => {
34         const foldersCreated = new Set<string>();
35         const filesToUpload: UploadFileList = [];
37         for (let i = 0; i < files.length; i++) {
38             const file = files[i];
40             if (forFolders) {
41                 // webkitRelativePath might be available only if property
42                 // webkitdirectory is set, or not at all. It is important
43                 // to not use it if its not for folders so at least just
44                 // files without structure can be uploaded.
45                 if ('webkitRelativePath' in file) {
46                     const path = ((file as any).webkitRelativePath as string).split('/');
47                     for (let j = 1; j < path.length; j++) {
48                         const folderPath = path.slice(0, j);
49                         const folderPathStr = folderPath.join('/');
50                         if (!foldersCreated.has(folderPathStr)) {
51                             foldersCreated.add(folderPathStr);
52                             filesToUpload.push({ path: folderPath.slice(0, -1), folder: folderPath.slice(-1)[0] });
53                         }
54                     }
55                     filesToUpload.push({ path: path.slice(0, -1), file });
56                 } else {
57                     createNotification({
58                         type: 'error',
59                         text: c('Error').t`Your browser does not support uploading folders`,
60                     });
61                 }
62             } else {
63                 filesToUpload.push({ path: [], file });
64             }
65         }
67         return filesToUpload;
68     };
70     const handleClick = () => {
71         if (!shareId || !linkId || !inputRef.current) {
72             return;
73         }
75         inputRef.current.value = '';
76         inputRef.current.click();
77     };
79     const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
80         const { files } = e.target;
81         if (!shareId || !linkId || !files) {
82             return;
83         }
85         let filesToUpload = getItemsToUpload(files);
86         if (!forFolders) {
87             // MacOS has bug, where you can select folders when uploading files in some cases.
88             filesToUpload = filesToUpload.filter((item) => !!(item as UploadFileItem).file);
89         }
91         uploadFiles(shareId, linkId, filesToUpload, isForPhotos).catch(logError);
92     };
94     return { inputRef, handleClick, handleChange };