178 lines
8.5 KiB
TypeScript
178 lines
8.5 KiB
TypeScript
import LoadingScreen from '@/components/LoadingScreen';
|
|
import api from '@/utils/api';
|
|
import { useLocalSearchParams, useRouter } from 'expo-router';
|
|
import { StatusBar } from 'expo-status-bar';
|
|
import { Building2, ChevronLeft, Paperclip, AlertCircle, FileText } from 'lucide-react-native';
|
|
import React, { useEffect, useState } from 'react';
|
|
import { ScrollView, Text, TouchableOpacity, View } from 'react-native';
|
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
|
|
const InfoRow = ({
|
|
label,
|
|
value,
|
|
isLast = false,
|
|
isCode = false
|
|
}: {
|
|
label: string;
|
|
value?: string | number | null;
|
|
isLast?: boolean;
|
|
isCode?: boolean
|
|
}) => (
|
|
<View className={`flex-row justify-between items-start ${!isLast ? 'border-b border-slate-100 pb-3' : ''}`}>
|
|
<Text className="text-slate-500 font-medium">{label}</Text>
|
|
<Text
|
|
selectable={true}
|
|
className={`text-primary-dark font-bold text-right flex-1 ${isCode ? 'tracking-widest' : ''}`}
|
|
>
|
|
{value || '-'}
|
|
</Text>
|
|
</View>
|
|
);
|
|
|
|
export default function ConstructionSiteDetailsScreen() {
|
|
const { id } = useLocalSearchParams();
|
|
const router = useRouter();
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
const [siteData, setSiteData] = useState<any>(null);
|
|
|
|
const fetchDetails = async () => {
|
|
try {
|
|
const response = await api.get(`/construction-site/get-info?id=${id}`);
|
|
if (response.data?.success) {
|
|
setSiteData(response.data.result);
|
|
}
|
|
} catch (error) {
|
|
console.error('Errore nel recupero dei dettagli del cantiere:', error);
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (id) {
|
|
fetchDetails();
|
|
}
|
|
}, [id]);
|
|
|
|
if (isLoading) {
|
|
return <LoadingScreen />;
|
|
}
|
|
|
|
if (!siteData) {
|
|
return (
|
|
<View className="flex-1 bg-slate-50 justify-center items-center">
|
|
<AlertCircle size={48} color="#94a3b8" />
|
|
<Text className="text-slate-500 mt-4 font-medium">Impossibile caricare i dettagli.</Text>
|
|
<TouchableOpacity onPress={() => router.back()} className="mt-4 px-6 py-2 bg-primary-dark rounded-full">
|
|
<Text className="text-white font-bold">Indietro</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
const { constructionSite, client, subactivities } = siteData;
|
|
|
|
return (
|
|
<View className="flex-1 bg-primary-dark">
|
|
<StatusBar style="light" />
|
|
<SafeAreaView edges={['top']} className="pt-5">
|
|
{/* Header */}
|
|
<View className="pb-6 px-6 z-10 flex-row items-center justify-between">
|
|
<TouchableOpacity
|
|
onPress={() => router.push(`/`)}
|
|
className="p-2 -ml-2 rounded-full active:bg-white/20 w-12 items-center justify-center"
|
|
>
|
|
<ChevronLeft size={28} color="white" pointerEvents="none" />
|
|
</TouchableOpacity>
|
|
|
|
<View className="flex-1 px-2">
|
|
<Text className="text-white text-xl font-bold text-center leading-tight" numberOfLines={1}>
|
|
{constructionSite?.name || 'Dettaglio Cantiere'}
|
|
</Text>
|
|
</View>
|
|
|
|
<TouchableOpacity
|
|
onPress={() => router.push(`/construction-site/${id}/documents?name=${encodeURIComponent(constructionSite?.name || '')}`)}
|
|
className="p-2 -mr-2 rounded-full active:bg-white/20 w-12 items-center justify-center"
|
|
>
|
|
<Paperclip size={22} color="white" pointerEvents="none" />
|
|
</TouchableOpacity>
|
|
</View>
|
|
</SafeAreaView>
|
|
|
|
{/* Content */}
|
|
<View className="flex-1 bg-slate-50 rounded-t-[2.5rem] overflow-hidden">
|
|
<ScrollView
|
|
className="flex-1 px-6 pt-8"
|
|
contentContainerStyle={{ paddingBottom: 100 }}
|
|
showsVerticalScrollIndicator={false}
|
|
>
|
|
{/* Info Card */}
|
|
<View className="bg-white rounded-3xl p-6 shadow-sm border border-slate-100 mb-6">
|
|
<View className="flex-row items-center mb-6">
|
|
<View className="bg-primary-50 p-3 rounded-xl mr-4">
|
|
<Building2 size={24} color="#1071C2" />
|
|
</View>
|
|
<Text className="text-xl font-bold text-slate-800 flex-1">Informazioni</Text>
|
|
</View>
|
|
|
|
<View className="gap-4">
|
|
<InfoRow label="Cliente" value={client} />
|
|
<InfoRow label="Indirizzo" value={constructionSite?.address} />
|
|
<InfoRow label="CIG" value={constructionSite?.cig} isCode={true} />
|
|
<InfoRow label="CUP" value={constructionSite?.cup} isCode={true} />
|
|
<InfoRow
|
|
label="% Ribasso"
|
|
value={constructionSite?.reduction ? `${constructionSite.reduction} %` : undefined}
|
|
isLast={true}
|
|
/>
|
|
</View>
|
|
</View>
|
|
|
|
{/* Subactivities */}
|
|
{subactivities && subactivities.length > 0 && (
|
|
<View className="mb-6">
|
|
<Text className="text-slate-800 text-xl font-bold mb-4 px-2">Sottocommesse</Text>
|
|
|
|
<View className="gap-3">
|
|
{subactivities.map((sub: any, index: number) => {
|
|
const hasCodes = sub.cig || sub.cup;
|
|
return (
|
|
<View key={index} className="bg-white p-5 rounded-2xl shadow-sm border border-slate-100">
|
|
<View className={`flex-row items-center ${hasCodes ? 'mb-3 border-b border-slate-50 pb-3' : ''}`}>
|
|
<View className="bg-slate-50 p-2 rounded-lg mr-3">
|
|
<FileText size={20} color="#64748b" />
|
|
</View>
|
|
<Text selectable={true} className="text-slate-800 font-bold text-sm uppercase flex-1 leading-tight">
|
|
{sub.code} - {sub.description}
|
|
</Text>
|
|
</View>
|
|
|
|
{hasCodes && (
|
|
<View className="gap-2 px-2">
|
|
{sub.cig && (
|
|
<View className="flex-row justify-between items-center">
|
|
<Text className="text-slate-500 text-xs font-medium">CIG</Text>
|
|
<Text selectable={true} className="text-primary-dark font-bold text-sm tracking-widest">{sub.cig}</Text>
|
|
</View>
|
|
)}
|
|
{sub.cup && (
|
|
<View className="flex-row justify-between items-center">
|
|
<Text className="text-slate-500 text-xs font-medium">CUP</Text>
|
|
<Text selectable={true} className="text-primary-dark font-bold text-sm tracking-widest">{sub.cup}</Text>
|
|
</View>
|
|
)}
|
|
</View>
|
|
)}
|
|
</View>
|
|
);
|
|
})}
|
|
</View>
|
|
</View>
|
|
)}
|
|
</ScrollView>
|
|
</View>
|
|
</View>
|
|
);
|
|
}
|