205 lines
10 KiB
TypeScript
205 lines
10 KiB
TypeScript
import { useAlert } from '@/components/AlertComponent';
|
|
import LoadingScreen from '@/components/LoadingScreen';
|
|
import api from '@/utils/api';
|
|
import { downloadAndShareDocument } from '@/utils/documentUtils';
|
|
import { useRouter } from 'expo-router';
|
|
import { StatusBar } from 'expo-status-bar';
|
|
import { ChevronDown, ChevronLeft, Download, FileText, X } from 'lucide-react-native';
|
|
import React, { useEffect, useState } from 'react';
|
|
import { Modal, RefreshControl, FlatList, Text, TouchableOpacity, View } from 'react-native';
|
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
|
|
export default function DocumentsScreen() {
|
|
const router = useRouter();
|
|
const alert = useAlert();
|
|
const [documents, setDocuments] = useState<any[]>([]);
|
|
const [categories, setCategories] = useState<any[]>([]);
|
|
const [selectedCategory, setSelectedCategory] = useState<any>(null);
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
const [refreshing, setRefreshing] = useState(false);
|
|
const [showPicker, setShowPicker] = useState(false);
|
|
|
|
// Fetch document categories
|
|
const fetchCategories = async () => {
|
|
try {
|
|
const response = await api.get('/registry/get-categories');
|
|
if (response.data?.success) {
|
|
setCategories([{ label: 'Tutte le tipologie', value: null }, ...response.data.categories]);
|
|
}
|
|
} catch (error) {
|
|
console.error('Errore nel recupero delle categorie:', error);
|
|
}
|
|
};
|
|
|
|
// Fetch user documents based on selected category
|
|
const fetchUserDocuments = async (filterValue: any = null) => {
|
|
try {
|
|
if (!refreshing) setIsLoading(true);
|
|
const params = { filter: filterValue };
|
|
const response = await api.get(`/registry/list`, { params });
|
|
if (response.data?.success) {
|
|
setDocuments(response.data.result || []);
|
|
}
|
|
} catch (error) {
|
|
console.error('Errore nel recupero dei documenti utente:', error);
|
|
alert.showAlert('error', 'Errore', 'Impossibile recuperare i documenti. Riprova più tardi.');
|
|
} finally {
|
|
setIsLoading(false);
|
|
setRefreshing(false);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
const init = async () => {
|
|
setIsLoading(true);
|
|
await fetchCategories();
|
|
await fetchUserDocuments(selectedCategory);
|
|
};
|
|
init();
|
|
}, []);
|
|
|
|
const onRefresh = () => {
|
|
setRefreshing(true);
|
|
fetchUserDocuments(selectedCategory);
|
|
};
|
|
|
|
const handleCategorySelect = (value: any) => {
|
|
setSelectedCategory(value);
|
|
fetchUserDocuments(value);
|
|
setShowPicker(false);
|
|
};
|
|
|
|
if (isLoading && !refreshing) {
|
|
return (
|
|
<LoadingScreen />
|
|
);
|
|
}
|
|
|
|
// Get label for the selected category or default text
|
|
const selectedLabel = selectedCategory
|
|
? categories.find(c => c.value === selectedCategory)?.label
|
|
: 'Filtra per tipologia...';
|
|
|
|
return (
|
|
<View className="flex-1 bg-gray-50">
|
|
<StatusBar style="dark" />
|
|
{/* Header */}
|
|
<View className="bg-white px-4 pb-6 shadow-sm border-b border-gray-100">
|
|
<SafeAreaView edges={['top']} className='pt-5'>
|
|
<View className='flex-row items-center gap-4 mb-4'>
|
|
<TouchableOpacity onPress={() => router.back()} className="p-2 rounded-full active:bg-gray-100">
|
|
<ChevronLeft size={28} color="#4b5563" pointerEvents="none" />
|
|
</TouchableOpacity>
|
|
<View className="flex-1">
|
|
<Text className="text-3xl font-bold text-gray-800">Documenti</Text>
|
|
</View>
|
|
</View>
|
|
|
|
{/* Select / Dropdown Trigger and Reset */}
|
|
<View className="flex-row items-center mx-1 gap-3">
|
|
<TouchableOpacity
|
|
onPress={() => setShowPicker(true)}
|
|
className="flex-1 flex-row items-center justify-between bg-white px-5 py-3 rounded-2xl border border-gray-200 shadow-sm"
|
|
>
|
|
<Text className="text-gray-700 font-medium text-base flex-1 mr-2" numberOfLines={1}>
|
|
{selectedLabel}
|
|
</Text>
|
|
<ChevronDown size={20} color="#6b7280" pointerEvents="none" />
|
|
</TouchableOpacity>
|
|
|
|
{selectedCategory !== null && (
|
|
<TouchableOpacity
|
|
onPress={() => handleCategorySelect(null)}
|
|
className="bg-gray-50 p-3.5 rounded-2xl border border-gray-200 shadow-sm justify-center items-center"
|
|
>
|
|
<X size={22} color="#4b5563" pointerEvents="none" />
|
|
</TouchableOpacity>
|
|
)}
|
|
</View>
|
|
</SafeAreaView>
|
|
</View>
|
|
|
|
<View className="p-5 flex-1 pt-4">
|
|
{/* Documents List */}
|
|
<FlatList
|
|
data={documents}
|
|
keyExtractor={(item, index) => index.toString()}
|
|
contentContainerStyle={{ gap: 16, paddingBottom: 100 }}
|
|
showsVerticalScrollIndicator={false}
|
|
refreshControl={
|
|
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} colors={['#1071C2']} />
|
|
}
|
|
initialNumToRender={10}
|
|
maxToRenderPerBatch={15}
|
|
windowSize={5}
|
|
removeClippedSubviews={true}
|
|
renderItem={({ item: doc }) => (
|
|
<View className="bg-white p-5 rounded-3xl shadow-sm flex-row items-center justify-between border border-gray-100">
|
|
<View className="flex-row items-center gap-5 flex-1">
|
|
<View className="bg-blue-50 p-4 rounded-2xl flex-shrink-0">
|
|
<FileText size={32} color="#1071C2" pointerEvents="none" />
|
|
</View>
|
|
<View className="flex-1 mr-2">
|
|
<Text className="font-bold text-gray-800 text-base leading-tight uppercase" numberOfLines={3}>{doc.filename}</Text>
|
|
<View className="flex-row items-center mt-2">
|
|
<Text className="text-sm text-gray-400 font-bold">{doc.date}</Text>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
<TouchableOpacity
|
|
onPress={() => downloadAndShareDocument(doc.mimetype, doc.filename, doc.url)}
|
|
className="p-4 bg-gray-50 rounded-2xl active:bg-gray-100 flex-shrink-0 border border-gray-100">
|
|
<Download size={24} color="#1071C2" pointerEvents="none" />
|
|
</TouchableOpacity>
|
|
</View>
|
|
)}
|
|
ListEmptyComponent={() => (
|
|
!isLoading ? (
|
|
<View className="bg-white p-8 rounded-3xl border border-gray-100 items-center justify-center border-dashed mt-4">
|
|
<Text className="text-gray-400 font-medium text-center">Nessun documento trovato in questa categoria</Text>
|
|
</View>
|
|
) : null
|
|
)}
|
|
/>
|
|
</View>
|
|
|
|
{/* Modal Picker (Dropdown Custom) */}
|
|
<Modal visible={showPicker} transparent={true} animationType="fade" onRequestClose={() => setShowPicker(false)}>
|
|
<TouchableOpacity
|
|
activeOpacity={1}
|
|
onPress={() => setShowPicker(false)}
|
|
className="flex-1 bg-black/50 justify-end"
|
|
>
|
|
<View className="bg-white rounded-t-3xl p-5 max-h-[70%]" onStartShouldSetResponder={() => true}>
|
|
<View className="flex-row justify-between items-center mb-4 border-b border-gray-100 pb-4">
|
|
<Text className="text-xl font-bold text-gray-800">Filtra per tipologia</Text>
|
|
<TouchableOpacity onPress={() => setShowPicker(false)} className="p-2 bg-gray-100 rounded-full">
|
|
<X size={20} color="#4b5563" pointerEvents="none" />
|
|
</TouchableOpacity>
|
|
</View>
|
|
<FlatList
|
|
showsVerticalScrollIndicator={false}
|
|
contentContainerStyle={{ paddingBottom: 30 }}
|
|
data={categories}
|
|
keyExtractor={(item, index) => index.toString()}
|
|
initialNumToRender={10}
|
|
maxToRenderPerBatch={15}
|
|
windowSize={5}
|
|
removeClippedSubviews={true}
|
|
renderItem={({ item: cat }) => (
|
|
<TouchableOpacity
|
|
className={`py-4 px-4 rounded-xl flex-row justify-between items-center mb-2 ${selectedCategory === cat.value ? 'bg-blue-50' : ''}`}
|
|
onPress={() => handleCategorySelect(cat.value)}
|
|
>
|
|
<Text className={`text-lg ${selectedCategory === cat.value ? 'font-bold text-primary-dark' : 'text-gray-700'}`}>
|
|
{cat.label}
|
|
</Text>
|
|
</TouchableOpacity>
|
|
)}
|
|
/>
|
|
</View>
|
|
</TouchableOpacity>
|
|
</Modal>
|
|
</View>
|
|
);
|
|
} |