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);
27 if (forFolders && inputRef.current) {
28 // React types don't allow `webkitdirectory` but it exists and works
29 inputRef.current.setAttribute('webkitdirectory', 'true');
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];
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] });
55 filesToUpload.push({ path: path.slice(0, -1), file });
59 text: c('Error').t`Your browser does not support uploading folders`,
63 filesToUpload.push({ path: [], file });
70 const handleClick = () => {
71 if (!shareId || !linkId || !inputRef.current) {
75 inputRef.current.value = '';
76 inputRef.current.click();
79 const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
80 const { files } = e.target;
81 if (!shareId || !linkId || !files) {
85 let filesToUpload = getItemsToUpload(files);
87 // MacOS has bug, where you can select folders when uploading files in some cases.
88 filesToUpload = filesToUpload.filter((item) => !!(item as UploadFileItem).file);
91 uploadFiles(shareId, linkId, filesToUpload, isForPhotos).catch(logError);
94 return { inputRef, handleClick, handleChange };