246 lines
9.6 KiB
TypeScript
246 lines
9.6 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
import { ArrowLeft, Loader2, FileText, MapPin, Calendar, AlertTriangle, CheckCircle, Clock, XCircle } from 'lucide-react';
|
|
import { api } from '@/hooks/useApi';
|
|
import { Avaliacao } from '@/types';
|
|
import DDSModal from '@/components/DDSModal';
|
|
|
|
const statusConfig = {
|
|
pendente: { icon: Clock, color: 'bg-amber-100 text-amber-700', label: 'Pendente' },
|
|
em_analise: { icon: AlertTriangle, color: 'bg-blue-100 text-blue-700', label: 'Em Análise' },
|
|
aprovada: { icon: CheckCircle, color: 'bg-green-100 text-green-700', label: 'Aprovada' },
|
|
reprovada: { icon: XCircle, color: 'bg-red-100 text-red-700', label: 'Reprovada' },
|
|
};
|
|
|
|
const riscoConfig = {
|
|
baixo: { color: 'text-green-600', bg: 'bg-green-100', label: 'Baixo' },
|
|
medio: { color: 'text-amber-600', bg: 'bg-amber-100', label: 'Médio' },
|
|
alto: { color: 'text-orange-600', bg: 'bg-orange-100', label: 'Alto' },
|
|
critico: { color: 'text-red-600', bg: 'bg-red-100', label: 'Crítico' },
|
|
};
|
|
|
|
export default function AvaliacaoDetail() {
|
|
const navigate = useNavigate();
|
|
const { id } = useParams();
|
|
const [avaliacao, setAvaliacao] = useState<Avaliacao | null>(null);
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
const [showDDSModal, setShowDDSModal] = useState(false);
|
|
|
|
useEffect(() => {
|
|
loadAvaliacao();
|
|
}, [id]);
|
|
|
|
const loadAvaliacao = async () => {
|
|
try {
|
|
const response = await api.getAvaliacao(Number(id));
|
|
setAvaliacao(response.data);
|
|
} catch (error) {
|
|
console.error('Erro ao carregar avaliação:', error);
|
|
// Mock
|
|
setAvaliacao({
|
|
id: Number(id),
|
|
propriedade_id: 1,
|
|
data_avaliacao: '2024-02-01',
|
|
status: 'aprovada',
|
|
risco_desmatamento: 'baixo',
|
|
score_risco: 15,
|
|
observacoes: 'Propriedade em conformidade com EUDR. Documentação verificada e validada.',
|
|
dds_gerada: true,
|
|
dds_codigo: 'DDS-2024-00001',
|
|
created_at: '2024-02-01',
|
|
updated_at: '2024-02-01',
|
|
propriedade: {
|
|
id: 1,
|
|
nome: 'Fazenda Santa Maria',
|
|
codigo_car: 'MT-5107909-F4B8E35DB1',
|
|
area_total_ha: 1250.5,
|
|
cidade: 'Sinop',
|
|
estado: 'MT',
|
|
} as any,
|
|
});
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<div className="flex items-center justify-center h-96">
|
|
<Loader2 className="w-8 h-8 text-primary animate-spin" />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (!avaliacao) {
|
|
return (
|
|
<div className="text-center py-12">
|
|
<p className="text-gray-muted">Avaliação não encontrada</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const status = statusConfig[avaliacao.status];
|
|
const StatusIcon = status.icon;
|
|
const risco = riscoConfig[avaliacao.risco_desmatamento];
|
|
|
|
return (
|
|
<div>
|
|
{/* Header */}
|
|
<div className="flex items-center justify-between mb-8">
|
|
<div className="flex items-center gap-4">
|
|
<button
|
|
onClick={() => navigate('/avaliacoes')}
|
|
className="p-2 hover:bg-gray-100 rounded-lg transition"
|
|
>
|
|
<ArrowLeft className="w-5 h-5 text-navy" />
|
|
</button>
|
|
<div>
|
|
<h1 className="text-3xl font-bold text-navy">Avaliação #{avaliacao.id}</h1>
|
|
<p className="text-gray-text text-sm mt-1">
|
|
{avaliacao.propriedade?.nome}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center gap-3">
|
|
<button
|
|
onClick={() => setShowDDSModal(true)}
|
|
disabled={avaliacao.status !== 'aprovada'}
|
|
className="btn-primary flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
>
|
|
<FileText className="w-5 h-5" />
|
|
{avaliacao.dds_gerada ? 'Ver DDS' : 'Gerar DDS'}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid md:grid-cols-3 gap-6">
|
|
{/* Main Info */}
|
|
<div className="md:col-span-2 space-y-6">
|
|
{/* Status Card */}
|
|
<div className="glass-card">
|
|
<h2 className="text-lg font-semibold text-navy mb-4">Status da Avaliação</h2>
|
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
|
<div className="p-4 bg-gray-50 rounded-xl text-center">
|
|
<span className={`inline-flex items-center gap-1.5 text-sm font-medium px-3 py-1.5 rounded-full ${status.color}`}>
|
|
<StatusIcon className="w-4 h-4" />
|
|
{status.label}
|
|
</span>
|
|
<p className="text-xs text-gray-muted mt-2">Status</p>
|
|
</div>
|
|
<div className="p-4 bg-gray-50 rounded-xl text-center">
|
|
<span className={`inline-flex text-sm font-medium px-3 py-1.5 rounded-full ${risco.bg} ${risco.color}`}>
|
|
{risco.label}
|
|
</span>
|
|
<p className="text-xs text-gray-muted mt-2">Risco</p>
|
|
</div>
|
|
<div className="p-4 bg-gray-50 rounded-xl text-center">
|
|
<span className="text-2xl font-bold text-navy">{avaliacao.score_risco}%</span>
|
|
<p className="text-xs text-gray-muted mt-1">Score de Risco</p>
|
|
</div>
|
|
<div className="p-4 bg-gray-50 rounded-xl text-center">
|
|
<span className={`text-sm font-medium ${avaliacao.dds_gerada ? 'text-green-600' : 'text-gray-muted'}`}>
|
|
{avaliacao.dds_gerada ? '✓ Gerada' : 'Pendente'}
|
|
</span>
|
|
<p className="text-xs text-gray-muted mt-2">DDS</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Observações */}
|
|
<div className="glass-card">
|
|
<h2 className="text-lg font-semibold text-navy mb-4">Observações</h2>
|
|
<p className="text-gray-text">
|
|
{avaliacao.observacoes || 'Sem observações registradas.'}
|
|
</p>
|
|
</div>
|
|
|
|
{/* DDS Info */}
|
|
{avaliacao.dds_gerada && avaliacao.dds_codigo && (
|
|
<div className="glass-card bg-green-50 border-green-200">
|
|
<div className="flex items-start gap-4">
|
|
<div className="w-12 h-12 rounded-xl bg-green-100 flex items-center justify-center">
|
|
<FileText className="w-6 h-6 text-green-600" />
|
|
</div>
|
|
<div>
|
|
<h3 className="font-semibold text-green-800">DDS Gerada com Sucesso</h3>
|
|
<p className="text-green-700 text-sm mt-1">
|
|
Código: <span className="font-mono font-semibold">{avaliacao.dds_codigo}</span>
|
|
</p>
|
|
<p className="text-green-600 text-xs mt-2">
|
|
Declaração compatível com TRACES NT
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Sidebar */}
|
|
<div className="space-y-6">
|
|
{/* Propriedade Info */}
|
|
<div className="glass-card">
|
|
<h2 className="text-lg font-semibold text-navy mb-4">Propriedade</h2>
|
|
<div className="space-y-4">
|
|
<div className="flex items-center gap-3">
|
|
<MapPin className="w-5 h-5 text-primary" />
|
|
<div>
|
|
<p className="font-medium text-navy">{avaliacao.propriedade?.nome}</p>
|
|
<p className="text-xs text-gray-muted">
|
|
{avaliacao.propriedade?.cidade}/{avaliacao.propriedade?.estado}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div className="pt-3 border-t border-gray-100">
|
|
<p className="text-xs text-gray-muted mb-1">Código CAR</p>
|
|
<p className="font-mono text-sm text-navy">{avaliacao.propriedade?.codigo_car || '-'}</p>
|
|
</div>
|
|
<div className="pt-3 border-t border-gray-100">
|
|
<p className="text-xs text-gray-muted mb-1">Área Total</p>
|
|
<p className="font-medium text-navy">
|
|
{avaliacao.propriedade?.area_total_ha?.toLocaleString('pt-BR')} ha
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Datas */}
|
|
<div className="glass-card">
|
|
<h2 className="text-lg font-semibold text-navy mb-4">Datas</h2>
|
|
<div className="space-y-3">
|
|
<div className="flex items-center justify-between">
|
|
<span className="text-gray-muted text-sm flex items-center gap-2">
|
|
<Calendar className="w-4 h-4" />
|
|
Avaliação
|
|
</span>
|
|
<span className="text-navy font-medium">
|
|
{new Date(avaliacao.data_avaliacao).toLocaleDateString('pt-BR')}
|
|
</span>
|
|
</div>
|
|
<div className="flex items-center justify-between">
|
|
<span className="text-gray-muted text-sm">Criado em</span>
|
|
<span className="text-navy">
|
|
{new Date(avaliacao.created_at).toLocaleDateString('pt-BR')}
|
|
</span>
|
|
</div>
|
|
<div className="flex items-center justify-between">
|
|
<span className="text-gray-muted text-sm">Atualizado em</span>
|
|
<span className="text-navy">
|
|
{new Date(avaliacao.updated_at).toLocaleDateString('pt-BR')}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* DDS Modal */}
|
|
<DDSModal
|
|
isOpen={showDDSModal}
|
|
onClose={() => setShowDDSModal(false)}
|
|
avaliacao={avaliacao}
|
|
onSuccess={loadAvaliacao}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|