update
This commit is contained in:
@@ -0,0 +1,405 @@
|
||||
import React, {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
useGlobal,
|
||||
} from "reactn";
|
||||
import { Image, Pressable, Text, View } from "react-native";
|
||||
import * as ImagePicker from "expo-image-picker";
|
||||
import moment from "moment";
|
||||
import { useActionSheet } from "@expo/react-native-action-sheet";
|
||||
import * as DocumentPicker from "expo-document-picker";
|
||||
import Compressor from "react-native-compressor";
|
||||
import useMinuit from "react-native-minuit/src/hooks/useMinuit";
|
||||
|
||||
import { arrayUnion } from "../config/firebase";
|
||||
|
||||
import Style, { gutterConstant, mainBorderRadius } from "../styles/Style";
|
||||
import { Fonts, Palette } from "../styles";
|
||||
import { icons } from "../assets";
|
||||
|
||||
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 (
|
||||
<View ref={dropRef}>
|
||||
<Pressable onPress={onAddFile}>
|
||||
{customElement?.() || (
|
||||
<View
|
||||
style={{
|
||||
...Style.containerCenter,
|
||||
backgroundColor: isDragging
|
||||
? Palette.transparentGreen
|
||||
: Palette.transparentPrimary,
|
||||
borderRadius: mainBorderRadius,
|
||||
borderStyle: "dashed",
|
||||
borderWidth: 2,
|
||||
borderColor: isDragging ? Palette.green : Palette.primary,
|
||||
...containerStyle,
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
source={icons.screenshot}
|
||||
style={{
|
||||
...Style.iconLarge,
|
||||
marginBottom: gutterConstant,
|
||||
}}
|
||||
/>
|
||||
<Text
|
||||
style={{
|
||||
...Fonts({ type: "default" }),
|
||||
textAlign: "center",
|
||||
color: Palette.white,
|
||||
}}
|
||||
>
|
||||
{isWeb && isDesktop
|
||||
? `Glissez-déposez ici\nles fichiers, images et vidéos\nà ajouter.`
|
||||
: "Ajouter une image,\nun fichier ou une vidéo."}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</Pressable>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default DocumentDropZone;
|
||||
Reference in New Issue
Block a user