feat: Implement document management features
- Added a new DocumentsScreen for managing user documents with search and date filtering capabilities. - Created AddDocumentModal for uploading documents with file selection and custom title options. - Introduced SiteDocumentsScreen to display documents related to specific construction sites. - Implemented SitesScreen for listing construction sites with search functionality. - Updated ProfileScreen to link to the new DocumentsScreen. - Refactored RangePickerModal for selecting date ranges in document filtering. - Improved date formatting utilities for better timestamp handling. - Added necessary API calls for document and site management. - Updated types to reflect changes in document structure and site information. - Added expo-document-picker dependency for document selection functionality.
This commit is contained in:
161
components/AddDocumentModal.tsx
Normal file
161
components/AddDocumentModal.tsx
Normal file
@ -0,0 +1,161 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Modal, Text, TouchableOpacity, View, TextInput, ActivityIndicator } from 'react-native';
|
||||
import { X, Upload, FileText, Trash2 } from 'lucide-react-native';
|
||||
import * as DocumentPicker from 'expo-document-picker'; // TODO: Testare in ambiente iOS
|
||||
|
||||
interface AddDocumentModalProps {
|
||||
visible: boolean;
|
||||
onClose: () => void;
|
||||
onUpload: (file: DocumentPicker.DocumentPickerAsset, customTitle?: string) => Promise<void>;
|
||||
isUploading?: boolean;
|
||||
}
|
||||
|
||||
export default function AddDocumentModal({ visible, onClose, onUpload, isUploading = false }: AddDocumentModalProps) {
|
||||
const [selectedFile, setSelectedFile] = useState<DocumentPicker.DocumentPickerAsset | null>(null);
|
||||
const [customTitle, setCustomTitle] = useState('');
|
||||
|
||||
// Reset dello stato quando il modale si apre/chiude
|
||||
useEffect(() => {
|
||||
if (!visible) {
|
||||
setSelectedFile(null);
|
||||
setCustomTitle('');
|
||||
}
|
||||
}, [visible]);
|
||||
|
||||
const pickDocument = async () => {
|
||||
try {
|
||||
const result = await DocumentPicker.getDocumentAsync({
|
||||
type: '*/*', // Puoi limitare a 'application/pdf', 'image/*', ecc.
|
||||
copyToCacheDirectory: true,
|
||||
});
|
||||
|
||||
if (result.canceled) return;
|
||||
|
||||
const asset = result.assets[0];
|
||||
setSelectedFile(asset);
|
||||
|
||||
// Pre-compila il titolo con il nome del file (senza estensione se vuoi essere fancy, qui lo lascio intero)
|
||||
setCustomTitle(asset.name);
|
||||
|
||||
} catch (err) {
|
||||
console.error("Errore selezione file:", err);
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpload = () => {
|
||||
if (!selectedFile) return;
|
||||
// Se il titolo custom è vuoto, usiamo il nome originale
|
||||
onUpload(selectedFile, customTitle || selectedFile.name);
|
||||
};
|
||||
|
||||
const removeFile = () => {
|
||||
setSelectedFile(null);
|
||||
setCustomTitle('');
|
||||
};
|
||||
|
||||
// Formatta dimensione file
|
||||
const formatSize = (size?: number) => {
|
||||
if (!size) return '0 B';
|
||||
const k = 1024;
|
||||
const sizes = ['B', 'KB', 'MB', 'GB'];
|
||||
const i = Math.floor(Math.log(size) / Math.log(k));
|
||||
return parseFloat((size / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
animationType="fade"
|
||||
transparent={true}
|
||||
visible={visible}
|
||||
onRequestClose={onClose}
|
||||
>
|
||||
<View className="flex-1 justify-center items-center bg-black/50 px-6">
|
||||
<View className="bg-white w-full rounded-[2rem] p-6 shadow-xl">
|
||||
|
||||
{/* Header */}
|
||||
<View className="flex-row justify-between items-center mb-6">
|
||||
<Text className="text-xl font-bold text-gray-800">Carica Documento</Text>
|
||||
<TouchableOpacity onPress={onClose} className="p-2 bg-gray-50 rounded-full">
|
||||
<X size={20} color="#374151" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Body */}
|
||||
<View className="gap-5">
|
||||
|
||||
{/* Area Selezione File */}
|
||||
{!selectedFile ? (
|
||||
<TouchableOpacity
|
||||
onPress={pickDocument}
|
||||
className="h-64 border-2 border-dashed border-gray-300 rounded-2xl items-center justify-center bg-gray-50 active:bg-gray-100"
|
||||
>
|
||||
<View className="bg-white p-4 rounded-full shadow-sm mb-3">
|
||||
<Upload size={32} color="#099499" />
|
||||
</View>
|
||||
<Text className="text-lg text-gray-600 font-medium">Tocca per selezionare un file</Text>
|
||||
<Text className="text-gray-400 text-sm mt-1">PDF, Immagini, Word</Text>
|
||||
</TouchableOpacity>
|
||||
) : (
|
||||
// Visualizzazione File Selezionato
|
||||
<View className="bg-[#E6F4F4] p-4 rounded-2xl border border-[#099499]/20 flex-row items-center gap-4">
|
||||
<View className="bg-white p-3 rounded-xl">
|
||||
<FileText size={24} color="#099499" />
|
||||
</View>
|
||||
<View className="flex-1">
|
||||
<Text className="text-gray-800 font-bold text-sm" numberOfLines={1}>
|
||||
{selectedFile.name}
|
||||
</Text>
|
||||
<Text className="text-gray-500 text-xs">
|
||||
{formatSize(selectedFile.size)}
|
||||
</Text>
|
||||
</View>
|
||||
<TouchableOpacity onPress={removeFile} className="p-2 bg-white rounded-lg">
|
||||
<Trash2 size={18} color="#ef4444" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* Campo Rinomina (Visibile solo se c'è un file) */}
|
||||
{selectedFile && (
|
||||
<View>
|
||||
<Text className="text-gray-700 font-bold mb-2 ml-1 text-sm">Nome Documento (Opzionale)</Text>
|
||||
<TextInput
|
||||
value={customTitle}
|
||||
onChangeText={setCustomTitle}
|
||||
placeholder="Come vuoi chiamare questo file?"
|
||||
className="w-full p-4 bg-gray-50 rounded-xl border border-gray-200 text-gray-800 text-base"
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* Footer Buttons */}
|
||||
<View className="flex-row gap-3 mt-8">
|
||||
<TouchableOpacity
|
||||
onPress={onClose}
|
||||
className="flex-1 py-4 bg-gray-100 rounded-xl items-center"
|
||||
disabled={isUploading}
|
||||
>
|
||||
<Text className="text-gray-600 font-bold text-base">Annulla</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
onPress={handleUpload}
|
||||
disabled={!selectedFile || isUploading}
|
||||
className={`flex-1 py-4 rounded-xl items-center flex-row justify-center gap-2 ${!selectedFile ? 'bg-gray-300' : 'bg-[#099499]'}`}
|
||||
>
|
||||
{isUploading ? (
|
||||
<ActivityIndicator color="white" />
|
||||
) : (
|
||||
<>
|
||||
<Upload size={20} color="white" />
|
||||
<Text className="text-white font-bold text-base">Carica</Text>
|
||||
</>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user