import { useActionSheet } from "@expo/react-native-action-sheet"; import * as DocumentPicker from "expo-document-picker"; import * as ImagePicker from "expo-image-picker"; import moment from "moment"; import { Image, Pressable, Text, View } from "react-native"; import Compressor from "react-native-compressor"; import useMinuit from "react-native-minuit/src/hooks/useMinuit"; import React, { useCallback, useEffect, useRef, useState } from "reactn"; import { arrayUnion } from "../config/firebase"; import { icons } from "../assets"; import { Fonts, Palette } from "../styles"; import Style, { gutterConstant, mainBorderRadius } from "../styles/Style"; import { uploadFileToFirebase } from "../helpers/uploadToFirebase"; import useLayoutType from "../hooks/useLayoutType"; const NATIVE_OPTIONS = [ "Importer depuis la galerie", "Ajouter un fichier", "Prendre une photo ou une vidéo", "Annuler", ]; const DocumentDropZone = ({ containerStyle = {}, documentID = null, documentExists = false, collectionRef = null, setFiles = null, customElement = null, shouldReturnObject = false, }) => { const dropRef = useRef(null); const [isDragging, setIsDragging] = useState(false); const { setIsLoading, setTooltip } = useMinuit(); const { isDesktop, isWeb, isNative } = useLayoutType(); const { showActionSheetWithOptions } = useActionSheet(); useEffect(() => { if (isWeb && dropRef.current) { const el = dropRef.current; const handleDragIn = (e) => { e.preventDefault(); e.stopPropagation(); setIsDragging(true); }; const handleDragOut = (e) => { e.preventDefault(); e.stopPropagation(); if (!dropRef.current.contains(e.relatedTarget)) { console.log("drag left"); setIsDragging(false); } }; const handleDrop = (e) => { e.preventDefault(); e.stopPropagation(); setIsDragging(false); let files = [...e.dataTransfer.files]; if (files.length > 0) { for (const file of files) { handleWebFile({ file }); } } }; el.addEventListener("dragenter", handleDragIn); el.addEventListener("dragleave", handleDragOut); el.addEventListener("dragover", (e) => e.preventDefault()); el.addEventListener("drop", handleDrop); return () => { el.removeEventListener("dragenter", handleDragIn); el.removeEventListener("dragleave", handleDragOut); el.removeEventListener("dragover", (e) => e.preventDefault()); el.removeEventListener("drop", handleDrop); }; } }, [dropRef?.current]); const handleWebFile = ({ file }) => { try { const { type = "" } = file; const reader = new FileReader(); reader.onloadend = () => { const base64 = reader.result.split(",")[1]; // Vous pourriez avoir besoin de cette valeur base64 pour un upload direct const uri = reader.result; // URI en base64 du fichier console.log("file", file); onUploadDocument({ files: [{ name: file.name, uri, type }] }); }; reader.onerror = (err) => { console.error("FileReader error", err); }; reader.readAsDataURL(file); // Lire le fichier et déclencher reader.onloadend lorsque c'est fait } catch (error) { console.log(error); setTooltip({ text: error.message, type: "error" }); } }; const onAddFile = async ({} = {}) => { try { if (isNative) { const cancelButtonIndex = NATIVE_OPTIONS.length - 1; showActionSheetWithOptions( { options: NATIVE_OPTIONS, cancelButtonIndex, userInterfaceStyle: "dark", ...Style.actionSheet, }, async (selectedIndex) => { if (selectedIndex !== cancelButtonIndex) { switch (selectedIndex) { case 0: onChooseLibrary(); break; case 1: onChooseDocumentPicker(); break; case 2: onTakePicture(); break; default: break; } } } ); } else { onChooseDocumentPicker(); } } catch (error) { console.log(error); setTooltip({ text: error.message, type: "error" }); } finally { setIsLoading(false); } }; const onChooseLibrary = async ({} = {}) => { const result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ImagePicker.MediaTypeOptions.All, allowsEditing: false, quality: 3, }); if (result?.assets?.[0]?.uri) { const { uri, fileName = "" } = result?.assets?.[0]; onUploadDocument({ files: [ { name: getAssetName({ fileName, uri }), uri, type: "IMAGE", }, ], }); } else { throw new Error("Aucune image sélectionnée"); } }; const onChooseDocumentPicker = async ({} = {}) => { const result = await DocumentPicker.getDocumentAsync({ type: "*/*", copyToCacheDirectory: false, }); if (result?.assets?.length > 0) { const { name = "", uri = null } = result?.assets[0] || {}; if (!uri) { throw new Error("Erreur lors de l'ajout du document"); } onUploadDocument({ files: [ { name: name || getDefaultFileName(), uri, }, ], }); } else { console.log(result); throw new Error("Erreur lors de l'ajout du document"); } }; const onTakePicture = useCallback(async () => { const { status } = await ImagePicker.requestCameraPermissionsAsync(); if (status !== "granted") { throw new Error("Permissions caméra non accordées"); } const result = await ImagePicker.launchCameraAsync({ mediaTypes: ImagePicker.MediaTypeOptions.All, allowsEditing: true, quality: 1, }); if (result?.assets?.[0]?.uri) { const { uri, fileName = "" } = result?.assets?.[0]; onUploadDocument({ files: [ { name: getAssetName({ fileName, uri }), uri, type: "IMAGE", }, ], }); } else { throw new Error("Aucune image sélectionnée"); } }, []); const getDefaultFileName = () => { const randomID = Math.random().toString(36).substring(7); return `${moment().format(`DD_MM_YYYY_HH_mm_ss`)}_${randomID}`; }; const getAssetName = ({ fileName = "", uri = "" }) => { let name = fileName; if (!name && uri?.startsWith("file://")) { const splittedArray = uri?.split("/") || []; name = splittedArray?.[splittedArray?.length - 1] || ""; } if (!name?.length) { let extension = uri?.split(";")?.[0]?.split("/")?.[1] || ""; const defaultFileName = getDefaultFileName(); if (extension?.length) { name = `${defaultFileName}.${extension}`; } else { name = `${defaultFileName}`; } } return name; }; const onUploadDocument = async ({ files = [] } = {}) => { try { setIsLoading(true); const filesToUpdate = []; await Promise.all( files.map(async (file) => { const { name = "", uri = null } = file; console.log(file); if (!uri) { throw new Error("Erreur lors de l'ajout du document"); } const fileName = name || getDefaultFileName(); let type = "FILE"; if (name?.toLowerCase()?.match(/\.(jpeg|jpg|gif|png)$/) != null) { type = "IMAGE"; } if (name?.toLowerCase()?.match(/\.(mp4|mov|avi|mkv)$/) != null) { type = "VIDEO"; } let compressedURI = uri; let thumbnailURI = null; if (isNative) { if (type === "IMAGE") { compressedURI = await Compressor.Image.compress(uri, { compressionMethod: "manual", maxWidth: 1000, quality: 0.8, }); } else if (type === "VIDEO") { compressedURI = await Compressor.Video.compress(uri); } } const { resultURI = null } = await uploadFileToFirebase({ uri: compressedURI, path: `documents/${documentID}/files/${fileName}`, }); if (resultURI) { if (shouldReturnObject) { filesToUpdate.push({ name: fileName, uri: resultURI, type, thumbnailURI, }); } else { filesToUpdate.push(resultURI); } } else { console.log("resultURI is null"); } }) ); if (filesToUpdate.length > 0) { if (documentExists) { await collectionRef.doc(documentID).update({ files: arrayUnion(...filesToUpdate), }); } if (setFiles) { setFiles((prev) => [...prev, ...filesToUpdate]); } } setTooltip({ text: "Document(s) ajouté(s) avec succès" }); } catch (error) { console.log(error); setTooltip({ text: error.message, type: "error" }); } finally { setIsLoading(false); } }; if (!documentID) { return null; } return ( {customElement?.() || ( {isWeb && isDesktop ? `Glissez-déposez ici\nles fichiers, images et vidéos\nà ajouter.` : "Ajouter une image,\nun fichier ou une vidéo."} )} ); }; export default DocumentDropZone;