188 lines
9.0 KiB
TypeScript
188 lines
9.0 KiB
TypeScript
|
|
import React, { useState } from 'react';
|
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Badge } from '@/components/ui/badge';
|
|
import { Edit, Trash2, BarChart3, FileText } from 'lucide-react';
|
|
import { format } from 'date-fns';
|
|
import { ptBR } from 'date-fns/locale';
|
|
import { CronogramaOf } from '@/types/cronograma';
|
|
import { toast } from 'sonner';
|
|
import {
|
|
AlertDialog,
|
|
AlertDialogAction,
|
|
AlertDialogCancel,
|
|
AlertDialogContent,
|
|
AlertDialogDescription,
|
|
AlertDialogFooter,
|
|
AlertDialogHeader,
|
|
AlertDialogTitle,
|
|
AlertDialogTrigger,
|
|
} from "@/components/ui/alert-dialog";
|
|
|
|
interface CronogramaTableProps {
|
|
cronogramas: CronogramaOf[];
|
|
onEdit: (cronograma: CronogramaOf) => void;
|
|
onDelete: (cronogramaId: string) => void;
|
|
onViewChart: (cronograma: CronogramaOf) => void;
|
|
onViewPDF: (cronograma: CronogramaOf) => void;
|
|
canEdit?: boolean;
|
|
canDelete?: boolean;
|
|
}
|
|
|
|
export const CronogramaTable: React.FC<CronogramaTableProps> = ({
|
|
cronogramas,
|
|
onEdit,
|
|
onDelete,
|
|
onViewChart,
|
|
onViewPDF,
|
|
canEdit = true,
|
|
canDelete = true,
|
|
}) => {
|
|
const calcularDiasCorridos = (dataInicio: string, dataFim: string) => {
|
|
const inicio = new Date(dataInicio);
|
|
const fim = new Date(dataFim);
|
|
const diffTime = Math.abs(fim.getTime() - inicio.getTime());
|
|
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) + 1;
|
|
return diffDays;
|
|
};
|
|
|
|
return (
|
|
<div className="overflow-x-auto">
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow className="border-gray-200 dark:border-gray-700">
|
|
<TableHead className="text-gray-900 dark:text-gray-100">OF</TableHead>
|
|
<TableHead className="text-gray-900 dark:text-gray-100">Gestor</TableHead>
|
|
<TableHead className="text-gray-900 dark:text-gray-100">Revisão</TableHead>
|
|
<TableHead className="text-gray-900 dark:text-gray-100">Processos</TableHead>
|
|
<TableHead className="text-gray-900 dark:text-gray-100">Peso Total (kg)</TableHead>
|
|
<TableHead className="text-gray-900 dark:text-gray-100">Período Total</TableHead>
|
|
<TableHead className="text-gray-900 dark:text-gray-100">Dias Corridos</TableHead>
|
|
<TableHead className="text-right text-gray-900 dark:text-gray-100">Ações</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{cronogramas.map((cronograma) => {
|
|
const primeiroProcesso = cronograma.processos[0];
|
|
const ultimoProcesso = cronograma.processos[cronograma.processos.length - 1];
|
|
const dataInicio = primeiroProcesso?.data_inicio;
|
|
const dataFim = ultimoProcesso?.data_fim;
|
|
const diasCorridos = dataInicio && dataFim ? calcularDiasCorridos(dataInicio, dataFim) : 0;
|
|
|
|
return (
|
|
<TableRow key={cronograma.id} className="border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-800/50">
|
|
<TableCell className="font-medium">
|
|
<div>
|
|
<div className="font-semibold text-gray-900 dark:text-gray-100">{cronograma.ordem_fabricacao?.num_of}</div>
|
|
<div className="text-sm text-gray-600 dark:text-gray-400">
|
|
{cronograma.ordem_fabricacao?.descritivo}
|
|
</div>
|
|
</div>
|
|
</TableCell>
|
|
<TableCell>
|
|
<div className="text-sm text-gray-900 dark:text-gray-100">
|
|
{cronograma.gestor_profile?.full_name || 'N/A'}
|
|
</div>
|
|
</TableCell>
|
|
<TableCell>
|
|
<Badge variant="secondary" className="bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-100">Rev. {cronograma.revisao}</Badge>
|
|
</TableCell>
|
|
<TableCell>
|
|
<div className="text-sm text-gray-900 dark:text-gray-100">
|
|
{cronograma.processos.length} processo{cronograma.processos.length !== 1 ? 's' : ''}
|
|
</div>
|
|
</TableCell>
|
|
<TableCell>
|
|
<div className="text-sm text-gray-900 dark:text-gray-100 font-medium">
|
|
{cronograma.peso_total ? `${Number(cronograma.peso_total).toLocaleString('pt-BR')} kg` : 'N/A'}
|
|
</div>
|
|
</TableCell>
|
|
<TableCell>
|
|
{dataInicio && dataFim ? (
|
|
<div className="text-sm">
|
|
<div className="text-gray-900 dark:text-gray-100">{format(new Date(dataInicio + 'T00:00:00'), 'dd/MM/yyyy', { locale: ptBR })}</div>
|
|
<div className="text-gray-600 dark:text-gray-400">até</div>
|
|
<div className="text-gray-900 dark:text-gray-100">{format(new Date(dataFim + 'T00:00:00'), 'dd/MM/yyyy', { locale: ptBR })}</div>
|
|
</div>
|
|
) : (
|
|
<span className="text-gray-500 dark:text-gray-400">-</span>
|
|
)}
|
|
</TableCell>
|
|
<TableCell>
|
|
<Badge variant="outline" className="border-gray-300 dark:border-gray-600 text-gray-900 dark:text-gray-100">{diasCorridos} dias</Badge>
|
|
</TableCell>
|
|
<TableCell>
|
|
<div className="flex items-center justify-end space-x-2">
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
onClick={() => onViewChart(cronograma)}
|
|
title="Ver gráfico Gantt"
|
|
className="border-blue-200 dark:border-blue-600 bg-blue-50 dark:bg-blue-900/20 hover:bg-blue-100 dark:hover:bg-blue-800/30 text-blue-700 dark:text-blue-300"
|
|
>
|
|
<BarChart3 className="w-4 h-4" />
|
|
</Button>
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
onClick={() => onViewPDF(cronograma)}
|
|
title="Gerar PDF"
|
|
className="border-green-200 dark:border-green-600 bg-green-50 dark:bg-green-900/20 hover:bg-green-100 dark:hover:bg-green-800/30 text-green-700 dark:text-green-300"
|
|
>
|
|
<FileText className="w-4 h-4" />
|
|
</Button>
|
|
{canEdit && (
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
onClick={() => onEdit(cronograma)}
|
|
title="Editar cronograma"
|
|
className="border-gray-200 dark:border-gray-600 hover:bg-gray-100 dark:hover:bg-gray-700 text-gray-900 dark:text-gray-100"
|
|
>
|
|
<Edit className="w-4 h-4 text-gray-700 dark:text-gray-300" />
|
|
</Button>
|
|
)}
|
|
{canDelete && (
|
|
<AlertDialog>
|
|
<AlertDialogTrigger asChild>
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
title="Remover cronograma"
|
|
className="border-red-200 dark:border-red-600 bg-red-50 dark:bg-red-900/20 hover:bg-red-100 dark:hover:bg-red-800/30 text-red-700 dark:text-red-300"
|
|
>
|
|
<Trash2 className="w-4 h-4" />
|
|
</Button>
|
|
</AlertDialogTrigger>
|
|
<AlertDialogContent className="bg-white dark:bg-gray-800 border-gray-200 dark:border-gray-700">
|
|
<AlertDialogHeader>
|
|
<AlertDialogTitle className="text-gray-900 dark:text-gray-100">Remover Cronograma</AlertDialogTitle>
|
|
<AlertDialogDescription className="text-gray-600 dark:text-gray-400">
|
|
Tem certeza que deseja remover o cronograma da OF {cronograma.ordem_fabricacao?.num_of}?
|
|
Esta ação não pode ser desfeita.
|
|
</AlertDialogDescription>
|
|
</AlertDialogHeader>
|
|
<AlertDialogFooter>
|
|
<AlertDialogCancel className="border-gray-200 dark:border-gray-600 text-gray-900 dark:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-700">Cancelar</AlertDialogCancel>
|
|
<AlertDialogAction
|
|
onClick={() => cronograma.id && onDelete(cronograma.id)}
|
|
className="bg-red-600 hover:bg-red-700 text-white"
|
|
>
|
|
Remover
|
|
</AlertDialogAction>
|
|
</AlertDialogFooter>
|
|
</AlertDialogContent>
|
|
</AlertDialog>
|
|
)}
|
|
</div>
|
|
</TableCell>
|
|
</TableRow>
|
|
);
|
|
})}
|
|
</TableBody>
|
|
</Table>
|
|
</div>
|
|
);
|
|
};
|