🚀 Initial commit: Versão atual do TrackSteel APP
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
|
||||
import React from 'react';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Calendar } from '@/components/ui/calendar';
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
|
||||
import { Search, Calendar as CalendarIcon, Filter, RefreshCw } from 'lucide-react';
|
||||
import { format } from 'date-fns';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
interface ApontamentosFiltersProps {
|
||||
searchTerm: string;
|
||||
setSearchTerm: (value: string) => void;
|
||||
filterOF: string;
|
||||
filterFase: string;
|
||||
filterProcesso: string;
|
||||
dataInicio: Date | undefined;
|
||||
dataFim: Date | undefined;
|
||||
setDataInicio: (date: Date | undefined) => void;
|
||||
setDataFim: (date: Date | undefined) => void;
|
||||
uniqueOFs: string[];
|
||||
uniqueFases: string[];
|
||||
uniqueProcessos: string[];
|
||||
handleOFChange: (value: string) => void;
|
||||
handleFaseChange: (value: string) => void;
|
||||
handleProcessoChange: (value: string) => void;
|
||||
clearFilters: () => void;
|
||||
}
|
||||
|
||||
export const ApontamentosFilters: React.FC<ApontamentosFiltersProps> = ({
|
||||
searchTerm,
|
||||
setSearchTerm,
|
||||
filterOF,
|
||||
filterFase,
|
||||
filterProcesso,
|
||||
dataInicio,
|
||||
dataFim,
|
||||
setDataInicio,
|
||||
setDataFim,
|
||||
uniqueOFs,
|
||||
uniqueFases,
|
||||
uniqueProcessos,
|
||||
handleOFChange,
|
||||
handleFaseChange,
|
||||
handleProcessoChange,
|
||||
clearFilters
|
||||
}) => {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-sm flex items-center gap-2">
|
||||
<Filter className="h-4 w-4" />
|
||||
Filtros Inteligentes
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
{/* Primeira linha de filtros - mais compacta */}
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-2">
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-medium">Buscar</label>
|
||||
<div className="relative">
|
||||
<Search className="absolute left-2 top-1/2 transform -translate-y-1/2 h-3 w-3 text-muted-foreground" />
|
||||
<Input
|
||||
placeholder="OF, Marca..."
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
className="pl-7 h-8 text-xs"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-medium">OF</label>
|
||||
<Select value={filterOF || 'all'} onValueChange={handleOFChange}>
|
||||
<SelectTrigger className="h-8 text-xs">
|
||||
<SelectValue placeholder="Selecione" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">Todas as OFs</SelectItem>
|
||||
{uniqueOFs.map((of) => (
|
||||
<SelectItem key={of} value={of}>{of}</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-medium">Fase</label>
|
||||
<Select value={filterFase || 'all'} onValueChange={handleFaseChange}>
|
||||
<SelectTrigger className="h-8 text-xs">
|
||||
<SelectValue placeholder="Selecione" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">Todas as fases</SelectItem>
|
||||
{uniqueFases.map((fase) => (
|
||||
<SelectItem key={fase} value={fase}>{fase}</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-medium">Processo</label>
|
||||
<Select value={filterProcesso || 'all'} onValueChange={handleProcessoChange}>
|
||||
<SelectTrigger className="h-8 text-xs">
|
||||
<SelectValue placeholder="Selecione" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">Todos os processos</SelectItem>
|
||||
{uniqueProcessos.map((processo) => (
|
||||
<SelectItem key={processo} value={processo}>{processo}</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className="flex items-end">
|
||||
<Button variant="outline" onClick={clearFilters} className="h-8 text-xs">
|
||||
<RefreshCw className="h-3 w-3 mr-1" />
|
||||
Limpar
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Segunda linha - filtros de data */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-2">
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-medium">Data Início</label>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
className={cn(
|
||||
"h-8 justify-start text-left font-normal text-xs",
|
||||
!dataInicio && "text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
<CalendarIcon className="mr-1 h-3 w-3" />
|
||||
{dataInicio ? format(dataInicio, "dd/MM/yyyy") : "Selecionar"}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={dataInicio}
|
||||
onSelect={setDataInicio}
|
||||
initialFocus
|
||||
className="pointer-events-auto"
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-medium">Data Fim</label>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
className={cn(
|
||||
"h-8 justify-start text-left font-normal text-xs",
|
||||
!dataFim && "text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
<CalendarIcon className="mr-1 h-3 w-3" />
|
||||
{dataFim ? format(dataFim, "dd/MM/yyyy") : "Selecionar"}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={dataFim}
|
||||
onSelect={setDataFim}
|
||||
initialFocus
|
||||
className="pointer-events-auto"
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between items-center">
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{filterOF || filterFase || filterProcesso || dataInicio || dataFim ?
|
||||
'Filtros aplicados automaticamente baseados no último uso' :
|
||||
'Use os filtros para otimizar a visualização'
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,106 @@
|
||||
|
||||
import React from 'react';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from '@/components/ui/alert-dialog';
|
||||
import { Package, Wrench, Undo2 } from 'lucide-react';
|
||||
import { format } from 'date-fns';
|
||||
import { ptBR } from 'date-fns/locale';
|
||||
import { ApontamentoProducao } from '@/hooks/useApontamentosProducao';
|
||||
|
||||
interface ApontamentosListItemProps {
|
||||
apontamento: ApontamentoProducao;
|
||||
onRevert: (id: string) => void;
|
||||
}
|
||||
|
||||
export const ApontamentosListItem: React.FC<ApontamentosListItemProps> = ({
|
||||
apontamento,
|
||||
onRevert
|
||||
}) => {
|
||||
const formatDate = (dateString: string) => {
|
||||
try {
|
||||
const date = new Date(dateString + 'T00:00:00');
|
||||
return format(date, 'dd/MM/yyyy', { locale: ptBR });
|
||||
} catch (error) {
|
||||
console.error('Erro ao formatar data:', error);
|
||||
return dateString;
|
||||
}
|
||||
};
|
||||
|
||||
const getMarcaItem = (apontamento: ApontamentoProducao) => {
|
||||
if (apontamento.tipo_apontamento === 'componente') {
|
||||
return apontamento.componente?.marca_componente || 'N/A';
|
||||
} else {
|
||||
return apontamento.peca?.marca || 'N/A';
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between p-3 border rounded-lg hover:bg-muted/50 transition-colors">
|
||||
<div className="flex items-center gap-3">
|
||||
{apontamento.tipo_apontamento === 'componente' ? (
|
||||
<Wrench className="h-4 w-4 text-blue-500" />
|
||||
) : (
|
||||
<Package className="h-4 w-4 text-green-500" />
|
||||
)}
|
||||
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-medium">
|
||||
{getMarcaItem(apontamento)}
|
||||
</span>
|
||||
<Badge variant="outline">
|
||||
{apontamento.of_number || 'N/A'}
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
{apontamento.processo?.nome || 'N/A'} • {formatDate(apontamento.data_apontamento)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="text-right">
|
||||
<div className="font-medium">
|
||||
{apontamento.quantidade_produzida || 0} un.
|
||||
</div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{format(new Date(apontamento.created_at), 'HH:mm', { locale: ptBR })}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="text-orange-600 hover:text-orange-700 hover:bg-orange-50"
|
||||
>
|
||||
<Undo2 className="h-3 w-3" />
|
||||
</Button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Reverter Apontamento</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Tem certeza de que deseja reverter este apontamento?
|
||||
Esta ação não pode ser desfeita e irá remover permanentemente o registro de:
|
||||
<br />
|
||||
<strong>{getMarcaItem(apontamento)}</strong> - {apontamento.quantidade_produzida} unidades
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancelar</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
onClick={() => onRevert(apontamento.id)}
|
||||
className="bg-orange-600 hover:bg-orange-700"
|
||||
>
|
||||
Confirmar Reversão
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
|
||||
import React from 'react';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Calendar as CalendarIcon } from 'lucide-react';
|
||||
import { ApontamentosListItem } from './ApontamentosListItem';
|
||||
import { ApontamentoProducao } from '@/hooks/useApontamentosProducao';
|
||||
|
||||
interface ApontamentosResultsListProps {
|
||||
filteredApontamentos: ApontamentoProducao[];
|
||||
onRevert: (id: string) => void;
|
||||
}
|
||||
|
||||
export const ApontamentosResultsList: React.FC<ApontamentosResultsListProps> = ({
|
||||
filteredApontamentos,
|
||||
onRevert
|
||||
}) => {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<CalendarIcon className="h-5 w-5" />
|
||||
Histórico de Apontamentos
|
||||
</div>
|
||||
<Badge variant="secondary">
|
||||
{filteredApontamentos.length} {filteredApontamentos.length === 1 ? 'registro' : 'registros'}
|
||||
</Badge>
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{filteredApontamentos.length === 0 ? (
|
||||
<div className="text-center py-8 text-muted-foreground">
|
||||
<CalendarIcon className="h-12 w-12 mx-auto mb-4 opacity-50" />
|
||||
<p>Nenhum apontamento encontrado</p>
|
||||
<p className="text-sm">
|
||||
Tente ajustar os filtros para ver mais resultados
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-2 max-h-96 overflow-y-auto">
|
||||
{filteredApontamentos.map((apontamento) => (
|
||||
<ApontamentosListItem
|
||||
key={apontamento.id}
|
||||
apontamento={apontamento}
|
||||
onRevert={onRevert}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,273 @@
|
||||
import { useState, useMemo, useEffect } from 'react';
|
||||
import { ApontamentoProducao } from '@/hooks/useApontamentosProducao';
|
||||
|
||||
// Cache para lembrar os últimos filtros utilizados
|
||||
const historicCache = {
|
||||
lastOF: '',
|
||||
lastFase: '',
|
||||
lastProcesso: ''
|
||||
};
|
||||
|
||||
export const useApontamentosFilters = (apontamentos: ApontamentoProducao[]) => {
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [filterOF, setFilterOF] = useState('');
|
||||
const [filterFase, setFilterFase] = useState('');
|
||||
const [filterProcesso, setFilterProcesso] = useState('');
|
||||
const [dataInicio, setDataInicio] = useState<Date | undefined>();
|
||||
const [dataFim, setDataFim] = useState<Date | undefined>();
|
||||
const [initialized, setInitialized] = useState(false);
|
||||
|
||||
// Logs detalhados para debug
|
||||
useEffect(() => {
|
||||
console.log(`🔍 DADOS RECEBIDOS NO FILTRO: ${apontamentos.length} apontamentos`);
|
||||
|
||||
if (apontamentos.length > 0) {
|
||||
// Verificar OF B118 especificamente
|
||||
const b118Records = apontamentos.filter(apt => apt.of_number === 'B118');
|
||||
console.log(`🎯 OF B118 no filtro: ${b118Records.length} registros`);
|
||||
|
||||
// Mostrar alguns exemplos
|
||||
if (b118Records.length > 0) {
|
||||
console.log('🔍 Primeiros 5 registros B118:',
|
||||
b118Records.slice(0, 5).map(apt => ({
|
||||
id: apt.id,
|
||||
of: apt.of_number,
|
||||
peca: apt.peca?.marca,
|
||||
processo: apt.processo?.nome,
|
||||
data: apt.data_apontamento
|
||||
}))
|
||||
);
|
||||
}
|
||||
}
|
||||
}, [apontamentos]);
|
||||
|
||||
// Carregar cache inicial apenas uma vez
|
||||
useEffect(() => {
|
||||
if (!initialized) {
|
||||
console.log(`📊 Inicializando filtros com ${apontamentos.length} apontamentos totais`);
|
||||
|
||||
const savedCache = localStorage.getItem('historico_apontamentos_cache');
|
||||
if (savedCache) {
|
||||
try {
|
||||
const parsed = JSON.parse(savedCache);
|
||||
Object.assign(historicCache, parsed);
|
||||
console.log('📋 Cache carregado:', historicCache);
|
||||
} catch (error) {
|
||||
console.log('⚠️ Erro ao carregar cache do histórico:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// NÃO aplicar filtros do cache automaticamente - deixar limpo por padrão
|
||||
setInitialized(true);
|
||||
}
|
||||
}, [apontamentos, initialized]);
|
||||
|
||||
// Salvar cache quando filtros mudam
|
||||
const updateCache = (updates: Partial<typeof historicCache>) => {
|
||||
Object.assign(historicCache, updates);
|
||||
localStorage.setItem('historico_apontamentos_cache', JSON.stringify(historicCache));
|
||||
};
|
||||
|
||||
// Obter valores únicos para filtros - SEMPRE todos os valores disponíveis
|
||||
const uniqueOFs = useMemo(() => {
|
||||
const ofs = apontamentos
|
||||
.map(apt => apt.of_number)
|
||||
.filter((of): of is string => {
|
||||
return typeof of === 'string' && of.trim() !== '';
|
||||
})
|
||||
.filter((of, index, array) => array.indexOf(of) === index)
|
||||
.sort();
|
||||
|
||||
console.log(`📋 OFs únicas encontradas: ${ofs.length}`, ofs.slice(0, 10), '...');
|
||||
return ofs;
|
||||
}, [apontamentos]);
|
||||
|
||||
const uniqueFases = useMemo(() => {
|
||||
// Se não há OF selecionada, mostrar todas as fases
|
||||
const apontamentosFiltrados = filterOF && filterOF !== ''
|
||||
? apontamentos.filter(apt => apt.of_number === filterOF)
|
||||
: apontamentos;
|
||||
|
||||
const fases = apontamentosFiltrados
|
||||
.map(apt => apt.peca?.etapa_fase)
|
||||
.filter((fase): fase is string => {
|
||||
return typeof fase === 'string' && fase.trim() !== '';
|
||||
})
|
||||
.filter((fase, index, array) => array.indexOf(fase) === index)
|
||||
.sort();
|
||||
|
||||
console.log(`📋 Fases únicas encontradas para OF "${filterOF}": ${fases.length}`, fases);
|
||||
return fases;
|
||||
}, [apontamentos, filterOF]);
|
||||
|
||||
const uniqueProcessos = useMemo(() => {
|
||||
// Aplicar filtros hierárquicos apenas se existirem
|
||||
let apontamentosFiltrados = apontamentos;
|
||||
|
||||
if (filterOF && filterOF !== '') {
|
||||
apontamentosFiltrados = apontamentosFiltrados.filter(apt => apt.of_number === filterOF);
|
||||
}
|
||||
|
||||
if (filterFase && filterFase !== '') {
|
||||
apontamentosFiltrados = apontamentosFiltrados.filter(apt => apt.peca?.etapa_fase === filterFase);
|
||||
}
|
||||
|
||||
const processos = apontamentosFiltrados
|
||||
.map(apt => apt.processo?.nome)
|
||||
.filter((processo): processo is string => {
|
||||
return typeof processo === 'string' && processo.trim() !== '';
|
||||
})
|
||||
.filter((processo, index, array) => array.indexOf(processo) === index)
|
||||
.sort();
|
||||
|
||||
console.log(`📋 Processos únicos encontrados para OF "${filterOF}" e Fase "${filterFase}": ${processos.length}`, processos);
|
||||
return processos;
|
||||
}, [apontamentos, filterOF, filterFase]);
|
||||
|
||||
// Filtrar apontamentos - LÓGICA SIMPLIFICADA E CORRIGIDA
|
||||
const filteredApontamentos = useMemo(() => {
|
||||
if (!initialized) {
|
||||
console.log('⏳ Aguardando inicialização...');
|
||||
return [];
|
||||
}
|
||||
|
||||
console.log(`🔍 INICIANDO FILTRAGEM DE ${apontamentos.length} APONTAMENTOS`);
|
||||
console.log('🔍 Filtros ativos:', {
|
||||
searchTerm: searchTerm || 'VAZIO',
|
||||
filterOF: filterOF || 'VAZIO',
|
||||
filterFase: filterFase || 'VAZIO',
|
||||
filterProcesso: filterProcesso || 'VAZIO',
|
||||
dataInicio: dataInicio ? 'SIM' : 'NÃO',
|
||||
dataFim: dataFim ? 'SIM' : 'NÃO'
|
||||
});
|
||||
|
||||
let resultado = [...apontamentos]; // Começar com TODOS os apontamentos
|
||||
|
||||
// Aplicar filtro de busca textual APENAS se preenchido
|
||||
if (searchTerm && searchTerm.trim() !== '') {
|
||||
const searchLower = searchTerm.toLowerCase();
|
||||
const beforeSearch = resultado.length;
|
||||
|
||||
resultado = resultado.filter(apt =>
|
||||
(apt.of_number && apt.of_number.toLowerCase().includes(searchLower)) ||
|
||||
(apt.peca?.marca && apt.peca.marca.toLowerCase().includes(searchLower)) ||
|
||||
(apt.componente?.marca_componente && apt.componente.marca_componente.toLowerCase().includes(searchLower))
|
||||
);
|
||||
|
||||
console.log(`🔎 Filtro texto "${searchTerm}": ${beforeSearch} → ${resultado.length} registros`);
|
||||
}
|
||||
|
||||
// Aplicar filtro por OF APENAS se selecionado
|
||||
if (filterOF && filterOF !== '' && filterOF !== 'all') {
|
||||
const beforeOF = resultado.length;
|
||||
resultado = resultado.filter(apt => apt.of_number === filterOF);
|
||||
console.log(`🏷️ Filtro OF "${filterOF}": ${beforeOF} → ${resultado.length} registros`);
|
||||
}
|
||||
|
||||
// Aplicar filtro por Fase APENAS se selecionado
|
||||
if (filterFase && filterFase !== '' && filterFase !== 'all') {
|
||||
const beforeFase = resultado.length;
|
||||
resultado = resultado.filter(apt => apt.peca?.etapa_fase === filterFase);
|
||||
console.log(`📋 Filtro Fase "${filterFase}": ${beforeFase} → ${resultado.length} registros`);
|
||||
}
|
||||
|
||||
// Aplicar filtro por Processo APENAS se selecionado
|
||||
if (filterProcesso && filterProcesso !== '' && filterProcesso !== 'all') {
|
||||
const beforeProcesso = resultado.length;
|
||||
resultado = resultado.filter(apt => apt.processo?.nome === filterProcesso);
|
||||
console.log(`⚙️ Filtro Processo "${filterProcesso}": ${beforeProcesso} → ${resultado.length} registros`);
|
||||
}
|
||||
|
||||
// Aplicar filtros de data APENAS se definidos
|
||||
if (dataInicio || dataFim) {
|
||||
const beforeData = resultado.length;
|
||||
|
||||
resultado = resultado.filter(apt => {
|
||||
const apontamentoDate = new Date(apt.data_apontamento);
|
||||
let matchesDataInicio = true;
|
||||
let matchesDataFim = true;
|
||||
|
||||
if (dataInicio) {
|
||||
matchesDataInicio = apontamentoDate >= dataInicio;
|
||||
}
|
||||
if (dataFim) {
|
||||
matchesDataFim = apontamentoDate <= dataFim;
|
||||
}
|
||||
|
||||
return matchesDataInicio && matchesDataFim;
|
||||
});
|
||||
|
||||
console.log(`📅 Filtro Data: ${beforeData} → ${resultado.length} registros`);
|
||||
}
|
||||
|
||||
console.log(`✅ RESULTADO FINAL DA FILTRAGEM: ${resultado.length} de ${apontamentos.length} apontamentos`);
|
||||
|
||||
// Log específico para B118 se estiver sendo filtrado
|
||||
if (filterOF === 'B118') {
|
||||
console.log(`🎯 Resultado B118: ${resultado.length} registros filtrados`);
|
||||
}
|
||||
|
||||
return resultado;
|
||||
}, [apontamentos, searchTerm, filterOF, filterFase, filterProcesso, dataInicio, dataFim, initialized]);
|
||||
|
||||
const clearFilters = () => {
|
||||
console.log('🧹 Limpando todos os filtros');
|
||||
setSearchTerm('');
|
||||
setFilterOF('');
|
||||
setFilterFase('');
|
||||
setFilterProcesso('');
|
||||
setDataInicio(undefined);
|
||||
setDataFim(undefined);
|
||||
|
||||
// Limpar cache
|
||||
Object.assign(historicCache, { lastOF: '', lastFase: '', lastProcesso: '' });
|
||||
localStorage.removeItem('historico_apontamentos_cache');
|
||||
};
|
||||
|
||||
const handleOFChange = (value: string) => {
|
||||
const selectedValue = value === 'all' ? '' : value;
|
||||
console.log('🔄 Mudando OF para:', selectedValue);
|
||||
setFilterOF(selectedValue);
|
||||
// Limpar fase e processo quando OF muda
|
||||
setFilterFase('');
|
||||
setFilterProcesso('');
|
||||
updateCache({ lastOF: selectedValue, lastFase: '', lastProcesso: '' });
|
||||
};
|
||||
|
||||
const handleFaseChange = (value: string) => {
|
||||
const selectedValue = value === 'all' ? '' : value;
|
||||
console.log('🔄 Mudando Fase para:', selectedValue);
|
||||
setFilterFase(selectedValue);
|
||||
// Limpar processo quando fase muda
|
||||
setFilterProcesso('');
|
||||
updateCache({ lastFase: selectedValue, lastProcesso: '' });
|
||||
};
|
||||
|
||||
const handleProcessoChange = (value: string) => {
|
||||
const selectedValue = value === 'all' ? '' : value;
|
||||
console.log('🔄 Mudando Processo para:', selectedValue);
|
||||
setFilterProcesso(selectedValue);
|
||||
updateCache({ lastProcesso: selectedValue });
|
||||
};
|
||||
|
||||
return {
|
||||
searchTerm,
|
||||
setSearchTerm,
|
||||
filterOF,
|
||||
filterFase,
|
||||
filterProcesso,
|
||||
dataInicio,
|
||||
dataFim,
|
||||
setDataInicio,
|
||||
setDataFim,
|
||||
uniqueOFs,
|
||||
uniqueFases,
|
||||
uniqueProcessos,
|
||||
filteredApontamentos,
|
||||
initialized,
|
||||
handleOFChange,
|
||||
handleFaseChange,
|
||||
handleProcessoChange,
|
||||
clearFilters
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user