178 lines
5.3 KiB
TypeScript
178 lines
5.3 KiB
TypeScript
import { useState, useCallback } from "react";
|
|
import { CustomFile, FileMeta, fileMetadata } from "@/types/webrtc";
|
|
import { Messages } from "@/types/messages";
|
|
import JSZip from "jszip";
|
|
import { downloadAs } from "@/lib/fileUtils";
|
|
|
|
interface UseFileTransferHandlerProps {
|
|
messages: Messages | null;
|
|
putMessageInMs: (
|
|
message: string,
|
|
isShareEnd?: boolean,
|
|
displayTimeMs?: number
|
|
) => void;
|
|
}
|
|
|
|
export function useFileTransferHandler({
|
|
messages,
|
|
putMessageInMs,
|
|
}: UseFileTransferHandlerProps) {
|
|
const [shareContent, setShareContent] = useState("");
|
|
const [sendFiles, setSendFiles] = useState<CustomFile[]>([]);
|
|
const [retrievedContent, setRetrievedContent] = useState("");
|
|
const [retrievedFiles, setRetrievedFiles] = useState<CustomFile[]>([]);
|
|
const [retrievedFileMetas, setRetrievedFileMetas] = useState<FileMeta[]>([]);
|
|
|
|
const updateShareContent = useCallback((content: string) => {
|
|
setShareContent(content);
|
|
}, []);
|
|
|
|
const addFilesToSend = useCallback(
|
|
(pickedFiles: CustomFile[]) => {
|
|
setSendFiles((prevFiles) => {
|
|
const newFiles = pickedFiles.filter(
|
|
(pf) =>
|
|
!prevFiles.some((ef) => ef.name === pf.name && ef.size === pf.size)
|
|
);
|
|
if (newFiles.length < pickedFiles.length && messages) {
|
|
putMessageInMs(
|
|
// messages.text.ClipboardApp.fileExistMsg ||
|
|
"Some files were already added.",
|
|
true
|
|
);
|
|
}
|
|
return [...prevFiles, ...newFiles];
|
|
});
|
|
},
|
|
[messages, putMessageInMs]
|
|
);
|
|
|
|
const removeFileToSend = useCallback((metaToRemove: FileMeta) => {
|
|
setSendFiles((prevFiles) => {
|
|
if (metaToRemove.folderName && metaToRemove.folderName !== "") {
|
|
return prevFiles.filter(
|
|
(file) => file.folderName !== metaToRemove.folderName
|
|
);
|
|
} else {
|
|
return prevFiles.filter((file) => file.name !== metaToRemove.name);
|
|
}
|
|
});
|
|
}, []);
|
|
|
|
const clearSentItems = useCallback(() => {
|
|
setShareContent("");
|
|
setSendFiles([]);
|
|
}, []);
|
|
|
|
const clearRetrievedItems = useCallback(() => {
|
|
setRetrievedContent("");
|
|
setRetrievedFiles([]);
|
|
setRetrievedFileMetas([]);
|
|
}, []);
|
|
|
|
// Callbacks for useWebRTCConnection
|
|
const onStringDataReceived = useCallback((data: string, peerId: string) => {
|
|
// console.log(`FileTransferHandler received string from ${peerId}`);
|
|
setRetrievedContent(data);
|
|
}, []);
|
|
|
|
const onFileMetadataReceived = useCallback(
|
|
(meta: fileMetadata, peerId: string) => {
|
|
// console.log(`FileTransferHandler received file meta from ${peerId}: ${meta.name}`);
|
|
const { type, ...metaWithoutType } = meta; // Assuming 'type' is not part of FileMeta
|
|
setRetrievedFileMetas((prev) => {
|
|
const DPrev = prev.filter(
|
|
(existingFile) => existingFile.fileId !== metaWithoutType.fileId
|
|
);
|
|
return [...DPrev, metaWithoutType];
|
|
});
|
|
},
|
|
[]
|
|
);
|
|
|
|
const onFileFullyReceived = async (file: CustomFile, peerId: string) => {
|
|
// console.log(`FileTransferHandler received file from ${peerId}: ${file.name}`);
|
|
setRetrievedFiles((prev) => {
|
|
const isDuplicate = prev.some(
|
|
(existingFile) =>
|
|
existingFile.fullName === file.fullName &&
|
|
existingFile.size === file.size
|
|
);
|
|
if (isDuplicate) return prev;
|
|
return [...prev, file];
|
|
});
|
|
};
|
|
|
|
const handleDownloadFile = useCallback(
|
|
async (meta: FileMeta) => {
|
|
if (!messages) return;
|
|
|
|
if (meta.folderName && meta.folderName !== "") {
|
|
const filesToZip = retrievedFiles.filter(
|
|
(file) => file.folderName === meta.folderName
|
|
);
|
|
if (filesToZip.length === 0) {
|
|
putMessageInMs(
|
|
// messages.text.ClipboardApp.noFilesForFolderMsg ||
|
|
"No files found for folder '{folderName}'.".replace(
|
|
"{folderName}",
|
|
meta.folderName
|
|
),
|
|
false
|
|
);
|
|
return;
|
|
}
|
|
const zip = new JSZip();
|
|
for (let file of filesToZip) {
|
|
zip.file(file.fullName, file);
|
|
}
|
|
try {
|
|
const content = await zip.generateAsync({ type: "blob" });
|
|
downloadAs(content, `${meta.folderName}.zip`);
|
|
} catch (error) {
|
|
console.error("Error creating zip file:", error);
|
|
putMessageInMs(
|
|
// messages.text.ClipboardApp.zipError ||
|
|
"Error creating ZIP.",
|
|
false
|
|
);
|
|
}
|
|
} else {
|
|
const fileToDownload = retrievedFiles.find((f) => f.name === meta.name);
|
|
if (fileToDownload) {
|
|
downloadAs(fileToDownload, fileToDownload.name);
|
|
} else {
|
|
putMessageInMs(
|
|
// messages.text.ClipboardApp.fileNotFoundMsg ||
|
|
"File '{fileName}' not found for download.".replace(
|
|
"{fileName}",
|
|
meta.name
|
|
),
|
|
false
|
|
);
|
|
}
|
|
}
|
|
},
|
|
[retrievedFiles, messages, putMessageInMs]
|
|
);
|
|
|
|
return {
|
|
shareContent,
|
|
sendFiles,
|
|
retrievedContent,
|
|
retrievedFiles,
|
|
retrievedFileMetas,
|
|
updateShareContent,
|
|
addFilesToSend,
|
|
removeFileToSend,
|
|
clearSentItems,
|
|
clearRetrievedItems,
|
|
// Callbacks to provide to useWebRTCConnection
|
|
onStringDataReceived,
|
|
onFileMetadataReceived,
|
|
onFileFullyReceived,
|
|
// Download function
|
|
handleDownloadFile,
|
|
};
|
|
}
|