398 lines
10 KiB
JavaScript
398 lines
10 KiB
JavaScript
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 (
|
|
<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
|