Files
mariani_mobile/app/(protected)/attendance/index.tsx
leonardo 6e5b9cde68 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.
2025-12-17 18:03:54 +01:00

142 lines
6.6 KiB
TypeScript

import React, { use, useEffect, useState } from 'react';
import { View, Text, TouchableOpacity, ScrollView, Alert, RefreshControl } from 'react-native';
import { QrCode, CheckCircle2 } from 'lucide-react-native';
import { ATTENDANCE_DATA } from '@/data/data';
import QrScanModal from '@/components/QrScanModal';
import LoadingScreen from '@/components/LoadingScreen';
import api from '@/utils/api';
export default function AttendanceScreen() {
const [showScanner, setShowScanner] = useState(false);
const [lastScan, setLastScan] = useState<{ type: string; time: string; site: string } | null>(null);
const [attendances, setAttendances] = useState(ATTENDANCE_DATA);
const [isLoading, setIsLoading] = useState(true);
const [refreshing, setRefreshing] = useState(false);
const fetchAttendances = async () => {
try {
if (!refreshing) setIsLoading(true);
// Fetch today's attendance data from API
const response = await api.get('/attendance/list');
// setAttendances(response.data);
} catch (error) {
console.error('Errore nel recupero delle presenze:', error);
Alert.alert('Errore', 'Impossibile recuperare le presenze. Riprova più tardi.');
} finally {
setIsLoading(false);
setRefreshing(false);
}
};
useEffect(() => {
fetchAttendances();
}, []);
const onRefresh = () => {
setRefreshing(true);
fetchAttendances();
};
const handleQRScan = () => {
setShowScanner(true);
// Simulate scanning process
setTimeout(() => {
setShowScanner(false);
// Add new entry or update existing one
setLastScan({
type: 'Entrata',
time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
site: 'Cantiere Ospedale A.'
});
}, 3000);
};
if (isLoading && !refreshing) {
return <LoadingScreen />;
}
return (
<View className="flex-1 bg-gray-50">
{/* Header */}
<View className="bg-white p-6 pt-16 shadow-sm border-b border-gray-100">
<Text className="text-3xl font-bold text-gray-800 mb-1">Gestione Presenze</Text>
<Text className="text-base text-gray-500">Registra i tuoi movimenti</Text>
</View>
<ScrollView
contentContainerStyle={{ paddingBottom: 40 }}
showsVerticalScrollIndicator={false}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} colors={['#099499']} />
}
>
<View className="flex-1 p-5 items-center">
{/* Feedback Card - OPZIONALE */}
{lastScan ? (
<View className="w-full bg-green-50 border border-green-200 rounded-3xl p-6 mb-8 flex-row items-center gap-5 shadow-sm">
<View className="bg-green-500 rounded-full p-3 shadow-lg shadow-green-500/40">
<CheckCircle2 size={32} color="white" />
</View>
<View>
<Text className="font-bold text-green-800 text-xl">{lastScan.type} Registrata!</Text>
<Text className="text-base text-green-700 font-medium">{lastScan.site} alle {lastScan.time}</Text>
</View>
</View>
) : (
null
)}
{/* Scanner Section */}
<View className="w-full mb-6">
<View className="bg-white rounded-3xl p-8 shadow-sm border border-gray-100">
<Text className="text-2xl font-bold text-gray-800 mb-6 text-center">Scansione QR/NFC</Text>
<TouchableOpacity
onPress={handleQRScan}
className="bg-[#099499] rounded-2xl py-6 flex-row items-center justify-center active:bg-[#077d82] shadow-lg shadow-teal-900/20 active:scale-[0.98]"
>
<QrCode color="white" size={32} />
<Text className="text-white text-xl font-bold ml-3">Scansiona Codice</Text>
</TouchableOpacity>
<Text className="text-gray-500 text-center mt-6 text-base px-2 leading-relaxed">
Posiziona il codice QR davanti alla fotocamera o usa il lettore NFC
</Text>
</View>
</View>
{/* Mini History */}
<View className="w-full mt-4">
<Text className="text-gray-500 font-bold text-base mb-4 uppercase tracking-wider px-2">Ultime Presenze</Text>
<View className="bg-white rounded-3xl shadow-sm overflow-hidden border border-gray-100">
{ATTENDANCE_DATA.map((item, index) => (
<View key={item.id} className={`p-6 flex-row justify-between items-center ${index !== 0 ? 'border-t border-gray-100' : ''}`}>
<View className="flex-row items-center gap-4">
<View className={`w-3 h-3 rounded-full shadow-sm ${item.status === 'complete' ? 'bg-green-500' : 'bg-orange-500'}`} />
<View>
<Text className="font-bold text-gray-800 text-lg mb-0.5">{item.site}</Text>
<Text className="text-base text-gray-400 font-medium">{item.in} - {item.out || 'In corso'}</Text>
</View>
</View>
{item.status === 'complete' && (
<View className="bg-gray-100 px-3 py-1.5 rounded-lg">
<Text className="text-base font-mono text-gray-600 font-bold">8h</Text>
</View>
)}
</View>
))}
</View>
</View>
</View>
</ScrollView>
{/* Scanner Modal */}
<QrScanModal
visible={showScanner}
onClose={() => setShowScanner(false)}
/>
</View>
);
}