Files
Kazier/mobile/components/UploadModal.tsx
T
2026-07-29 19:24:13 +02:00

173 lines
4.4 KiB
TypeScript

import React from 'react';
import { View, Text, StyleSheet, TouchableOpacity, Modal, Alert } from 'react-native';
import { MaterialIcons } from '@expo/vector-icons';
import * as ImagePicker from 'expo-image-picker';
import * as DocumentPicker from 'expo-document-picker';
import { UploadFile } from '../services/uploadQueue';
import { useUploadQueue } from '../hooks/useUploadQueue';
interface UploadModalProps {
visible: boolean;
onClose: () => void;
}
export function UploadModal({ visible, onClose }: UploadModalProps) {
const { enqueue } = useUploadQueue();
const pickImages = async () => {
try {
const { status: perm } = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (perm !== 'granted') {
Alert.alert('Permission requise', "L'accès à la galerie est nécessaire pour sélectionner des photos.");
return;
}
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ['images'],
quality: 1,
allowsMultipleSelection: true,
});
if (result.canceled || result.assets.length === 0) return;
const files = result.assets.map((asset) => ({
uri: asset.uri,
type: asset.mimeType || 'image/jpeg',
name: asset.fileName || 'photo.jpg',
}));
enqueue(files);
onClose();
} catch {
Alert.alert('Erreur', "Impossible d'accéder à la galerie");
}
};
const pickDocuments = async () => {
try {
const result = await DocumentPicker.getDocumentAsync({
multiple: true,
copyToCacheDirectory: true,
});
if (result.canceled || result.assets.length === 0) return;
const files = result.assets.map((asset) => ({
uri: asset.uri,
type: asset.mimeType || 'application/octet-stream',
name: asset.name,
}));
enqueue(files);
onClose();
} catch {
Alert.alert('Erreur', "Impossible de sélectionner des documents");
}
};
return (
<Modal
visible={visible}
transparent
animationType="fade"
onRequestClose={onClose}
>
<TouchableOpacity
style={styles.overlay}
activeOpacity={1}
onPress={onClose}
>
<TouchableOpacity activeOpacity={1} style={styles.container} onPress={() => {}}>
<View style={styles.handle} />
<View style={styles.header}>
<Text style={styles.title}>Ajouter des fichiers</Text>
<TouchableOpacity onPress={onClose} style={styles.closeBtn}>
<MaterialIcons name="close" size={22} color="#999" />
</TouchableOpacity>
</View>
<TouchableOpacity
style={styles.photoButton}
onPress={pickImages}
>
<MaterialIcons name="photo-library" size={20} color="#fff" />
<Text style={styles.buttonText}>Sélectionner des photos</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.docButton}
onPress={pickDocuments}
>
<MaterialIcons name="description" size={20} color="#fff" />
<Text style={styles.buttonText}>Sélectionner des documents</Text>
</TouchableOpacity>
</TouchableOpacity>
</TouchableOpacity>
</Modal>
);
}
const styles = StyleSheet.create({
overlay: {
flex: 1,
backgroundColor: 'rgba(0,0,0,0.4)',
justifyContent: 'center',
alignItems: 'center',
},
container: {
backgroundColor: '#fff',
borderRadius: 16,
paddingHorizontal: 20,
paddingTop: 12,
paddingBottom: 20,
width: '85%',
},
handle: {
width: 36,
height: 4,
borderRadius: 2,
backgroundColor: '#ddd',
alignSelf: 'center',
marginBottom: 16,
},
header: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 16,
},
title: {
fontSize: 18,
fontWeight: '700',
color: '#333',
},
closeBtn: {
padding: 4,
},
photoButton: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#1976D2',
padding: 16,
borderRadius: 8,
marginBottom: 12,
gap: 8,
},
docButton: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#4CAF50',
padding: 16,
borderRadius: 8,
gap: 8,
},
buttonText: {
color: '#fff',
fontSize: 16,
fontWeight: '600',
},
});