import React, { useState, useEffect } from 'react'; import { View, Text, TouchableOpacity, TextInput, Dimensions, ActivityIndicator, Modal } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { useLocalSearchParams, useRouter } from 'expo-router'; import { StatusBar } from 'expo-status-bar'; import { ChevronLeft, ImageIcon, Calendar as CalendarIcon } from 'lucide-react-native'; import { AppDatePicker } from '@/components/AppDatePicker'; import { DateType } from 'react-native-ui-datepicker'; import { formatDate, formatPickerDate } from '@/utils/dateTime'; import { Image } from 'expo-image'; import * as ImagePicker from 'expo-image-picker'; import api from '@/utils/api'; import { uploadDocument } from '@/utils/documentUtils'; import { useAlert } from '@/components/AlertComponent'; import GenericDropdown from '@/components/GenericDropdown'; import ActivityLaborCard from '@/components/ActivityLaborCard'; import RemovablePhotoTile from '@/components/RemovablePhotoTile'; import CameraAddTile from '@/components/CameraAddTile'; import { KeyboardAwareScrollView } from 'react-native-keyboard-controller'; export default function ActivityFormScreen() { const router = useRouter(); const alert = useAlert(); const { id } = useLocalSearchParams(); const isEditing = !!id; // Data lists const [subactivities, setSubactivities] = useState([]); // Form states const [date, setDate] = useState(new Date()); const [showDatePicker, setShowDatePicker] = useState(false); const [selectedSubactivityUuid, setSelectedSubactivityUuid] = useState(null); const [selectedSubactivityId, setSelectedSubactivityId] = useState(null); const [description, setDescription] = useState(''); // Labor states const [operatorLabor, setOperatorLabor] = useState([]); const [subcontractorLabor, setSubcontractorLabor] = useState([]); const [otherOperatorLabor, setOtherOperatorLabor] = useState([]); const [equipmentLabor, setEquipmentLabor] = useState([]); // Photos const [photos, setPhotos] = useState([]); // New photos const [existingPhotos, setExistingPhotos] = useState([]); // Existing (readonly) const [isLoading, setIsLoading] = useState(true); const [isSubmitting, setIsSubmitting] = useState(false); // Initial load useEffect(() => { loadInitialData(); }, []); const loadInitialData = async () => { setIsLoading(true); try { // Load subactivities const subRes = await api.get('/subactivity/get-subactivities'); if (subRes.data?.success) { setSubactivities(subRes.data.subactivities); } // If editing, load activity data if (isEditing) { const actRes = await api.post('/activity/get-activity-data', { params: JSON.stringify({ id: id }) }); if (actRes.data?.success) { const data = actRes.data; const activity = data.activity; setDate(new Date(activity.date)); setDescription(activity.description || ''); if (subRes.data?.success) { const match = subRes.data.subactivities.find((s: any) => s.id === activity.id_subactivity); if (match) { setSelectedSubactivityUuid(match.uuid); setSelectedSubactivityId(match.id); } } setOperatorLabor(data.operator_labor || []); setSubcontractorLabor(data.subcontractor_labor || []); setOtherOperatorLabor(data.other_operator_labor || []); setEquipmentLabor(data.materials || []); setExistingPhotos(data.attachments || []); } else { alert.showAlert('error', 'Errore', 'Impossibile caricare i dati dell\'attività.'); } } } catch (error) { console.error('Error loading data:', error); alert.showAlert('error', 'Errore', 'Si è verificato un errore di connessione.'); } finally { setIsLoading(false); } }; const handleDateChange = (params: any) => { setDate(params.date); setShowDatePicker(false); }; const pickFromGallery = async () => { const permissionResult = await ImagePicker.requestMediaLibraryPermissionsAsync(); if (permissionResult.granted === false) { alert.showAlert('error', 'Permessi Negati', 'È necessario consentire l\'accesso alla galleria.'); return; } const limit = 50 - photos.length; if (limit <= 0) return; try { const result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ['images'], allowsMultipleSelection: true, selectionLimit: limit, quality: 0.8, }); if (!result.canceled && result.assets) { setPhotos(prev => [...prev, ...result.assets]); } } catch (error) { console.error('Errore gallery:', error); } }; const takePhoto = async () => { const permissionResult = await ImagePicker.requestCameraPermissionsAsync(); if (permissionResult.granted === false) { alert.showAlert('error', 'Permessi Negati', 'È necessario consentire l\'accesso alla fotocamera.'); return; } if (photos.length >= 50) return; try { const result = await ImagePicker.launchCameraAsync({ mediaTypes: ['images'], quality: 0.8, }); if (!result.canceled && result.assets && result.assets.length > 0) { setPhotos(prev => [...prev, result.assets[0]]); } } catch (error) { console.error('Errore fotocamera:', error); } }; const removePhoto = (index: number) => { setPhotos(prev => prev.filter((_, i) => i !== index)); }; const handleSave = async () => { if (!selectedSubactivityUuid) { alert.showAlert('error', 'Campi obbligatori', 'Selezionare un Cantiere.'); return; } setIsSubmitting(true); try { // Se in edit mode dobbiamo passare subactivity_id, se in add mode subactivity_uuid. let subactivity_id = selectedSubactivityId; if (!subactivity_id) { const match = subactivities.find(s => s.uuid === selectedSubactivityUuid); if (match) subactivity_id = match.id; } const payload: any = { description: description, date: date ? formatPickerDate(date) : new Date().toISOString().split('T')[0], // YYYY-MM-DD n_files: photos.length, operator_labor: operatorLabor, subcontractor_labor: subcontractorLabor, other_operators_labor: otherOperatorLabor, equipment_labor: equipmentLabor, }; if (isEditing) { payload.id = id; payload.subactivity_id = subactivity_id; } else { payload.subactivity_uuid = selectedSubactivityUuid; } const params = { post: JSON.stringify(payload) }; const endpoint = isEditing ? '/activity/edit' : '/activity/add'; const res = await api.post(endpoint, params); if (res.data?.success) { const savedId = res.data.id; // Upload new photos sequentially if (photos.length > 0) { for (const file of photos) { const fileName = file.fileName || file.uri.split('/').pop() || 'photo.jpg'; const mimeType = file.mimeType || 'image/jpeg'; await uploadDocument({ uri: file.uri, name: fileName, mimeType: mimeType }, { endpoint: '/activity/upload', fileKey: 'files', extraData: { model_classname: 'Activity', model_id: savedId.toString(), method: 'put', name: fileName, type: mimeType } }); } } alert.showAlert('success', 'Salvato', 'Attività salvata con successo.'); if (isEditing) { router.back(); } else { router.push('/(protected)/activity'); } } else { alert.showAlert('error', 'Errore', res.data?.message || 'Impossibile salvare l\'attività.'); } } catch (error) { console.error('Errore salvataggio:', error); alert.showAlert('error', 'Errore di connessione', 'Verifica la connessione e riprova.'); } finally { setIsSubmitting(false); } }; if (isLoading) { return ( ); } const windowWidth = Dimensions.get('window').width; const itemsPerRow = 4; const padding = 20; const gap = 12; const tileWidth = (windowWidth - (padding * 2) - (gap * (itemsPerRow - 1))) / itemsPerRow; return ( {/* Header */} router.back()} className="p-2 -ml-2 rounded-full active:bg-gray-100 w-12 items-center justify-center"> {isEditing ? 'Modifica Attività' : 'Nuova Attività'} {/* General Info Card */} Cantiere * ({ id: s.uuid, label: s.label }))} selectedId={selectedSubactivityUuid} onSelect={(id) => setSelectedSubactivityUuid(id as string)} placeholder="Seleziona il cantiere" searchPlaceholder="Cerca cantiere" /> Data setShowDatePicker(true)} className="bg-gray-50 border border-gray-200 p-3 rounded-2xl flex-row items-center justify-between" > {date ? formatDate(formatPickerDate(date) || undefined) : ''} {showDatePicker && ( setShowDatePicker(false)} className="mt-4 p-3 rounded-xl items-center border border-gray-200 active:bg-gray-50" > Chiudi )} Descrizione {/* Labor Cards */} setOperatorLabor([...operatorLabor, labor])} onRemoveLabor={(idx) => setOperatorLabor(operatorLabor.filter((_, i) => i !== idx))} /> setSubcontractorLabor([...subcontractorLabor, labor])} onRemoveLabor={(idx) => setSubcontractorLabor(subcontractorLabor.filter((_, i) => i !== idx))} /> setOtherOperatorLabor([...otherOperatorLabor, labor])} onRemoveLabor={(idx) => setOtherOperatorLabor(otherOperatorLabor.filter((_, i) => i !== idx))} /> setEquipmentLabor([...equipmentLabor, labor])} onRemoveLabor={(idx) => setEquipmentLabor(equipmentLabor.filter((_, i) => i !== idx))} /> {/* Photos */} Allegati {/* Existing Photos (Read-only) */} {existingPhotos.map((photo, index) => ( ))} {/* New Photos */} {photos.map((photo, index) => ( removePhoto(index)} size={tileWidth} /> ))} {/* Add Buttons */} {(photos.length + existingPhotos.length) < 50 && ( <> )} {/* Submit */} {isSubmitting ? ( ) : ( {isEditing ? 'Salva Modifiche' : 'Salva Attività'} )} ); }