🚀 Auto-deploy: TrackSteelAPP atualizado em 21/08/2026 18:42:14

This commit is contained in:
2026-08-21 18:42:14 +00:00
parent dccb9acdce
commit fa3408c238
@@ -6,8 +6,7 @@ import {
XAxis, XAxis,
YAxis, YAxis,
CartesianGrid, CartesianGrid,
Tooltip, Tooltip
Legend
} from 'recharts'; } from 'recharts';
import { format, parseISO } from 'date-fns'; import { format, parseISO } from 'date-fns';
import { ptBR } from 'date-fns/locale'; import { ptBR } from 'date-fns/locale';
@@ -61,6 +60,66 @@ const CORES_FALLBACK = [
'#06b6d4', '#14b8a6', '#6366f1', '#10b981', '#eab308' '#06b6d4', '#14b8a6', '#6366f1', '#10b981', '#eab308'
]; ];
interface CustomTooltipProps {
active?: boolean;
payload?: Array<{
name: string;
value: number;
color: string;
dataKey: string;
}>;
label?: string;
modoExibicao: 'kg' | 'percent';
selectedProcesso: string | null;
}
// Componente Tooltip declarado fora da renderização principal para evitar recriação no render
const CustomTooltip: React.FC<CustomTooltipProps> = ({
active,
payload,
label,
modoExibicao,
selectedProcesso
}) => {
if (!active || !payload || !payload.length) return null;
return (
<div className="bg-popover/95 backdrop-blur-md border border-border shadow-2xl rounded-xl p-3 text-popover-foreground min-w-[200px] z-50">
<div className="flex items-center justify-between border-b border-border/50 pb-2 mb-2">
<span className="text-xs font-semibold text-muted-foreground">Data</span>
<span className="text-xs font-bold bg-primary/10 text-primary px-2 py-0.5 rounded-md">{label}</span>
</div>
<div className="space-y-1.5">
{payload.map((entry, index) => {
const isHighlight = !selectedProcesso || selectedProcesso === entry.name;
return (
<div
key={`item-${index}`}
className={`flex items-center justify-between text-xs transition-opacity ${
isHighlight ? 'opacity-100 font-medium' : 'opacity-40'
}`}
>
<div className="flex items-center gap-1.5">
<span
className="w-2.5 h-2.5 rounded-full shrink-0 shadow-sm"
style={{ backgroundColor: entry.color }}
/>
<span className="truncate max-w-[130px]">{entry.name}</span>
</div>
<span className="font-mono font-semibold ml-2">
{modoExibicao === 'kg'
? `${entry.value.toLocaleString('pt-BR')} kg`
: `${entry.value.toFixed(1)}%`
}
</span>
</div>
);
})}
</div>
</div>
);
};
export const GraficoMestre: React.FC<GraficoMestreProps> = ({ export const GraficoMestre: React.FC<GraficoMestreProps> = ({
processos, processos,
onProcessoClick, onProcessoClick,
@@ -121,7 +180,7 @@ export const GraficoMestre: React.FC<GraficoMestreProps> = ({
return datasOrdenadas.map(data => { return datasOrdenadas.map(data => {
const dataFormatada = format(parseISO(data), 'dd/MM', { locale: ptBR }); const dataFormatada = format(parseISO(data), 'dd/MM', { locale: ptBR });
const pontoGrafico: any = { const pontoGrafico: Record<string, string | number> = {
data: dataFormatada, data: dataFormatada,
dataCompleta: data dataCompleta: data
}; };
@@ -143,47 +202,6 @@ export const GraficoMestre: React.FC<GraficoMestreProps> = ({
}); });
}, [processosOrdenados, modoExibicao]); }, [processosOrdenados, modoExibicao]);
// Formatação customizada para o Tooltip estilo Glassmorphism
const CustomTooltip = ({ active, payload, label }: any) => {
if (!active || !payload || !payload.length) return null;
return (
<div className="bg-popover/95 backdrop-blur-md border border-border shadow-2xl rounded-xl p-3 text-popover-foreground min-w-[200px] z-50">
<div className="flex items-center justify-between border-b border-border/50 pb-2 mb-2">
<span className="text-xs font-semibold text-muted-foreground">Data</span>
<span className="text-xs font-bold bg-primary/10 text-primary px-2 py-0.5 rounded-md">{label}</span>
</div>
<div className="space-y-1.5">
{payload.map((entry: any, index: number) => {
const isHighlight = !selectedProcesso || selectedProcesso === entry.name;
return (
<div
key={`item-${index}`}
className={`flex items-center justify-between text-xs transition-opacity ${
isHighlight ? 'opacity-100 font-medium' : 'opacity-40'
}`}
>
<div className="flex items-center gap-1.5">
<span
className="w-2.5 h-2.5 rounded-full shrink-0 shadow-sm"
style={{ backgroundColor: entry.color }}
/>
<span className="truncate max-w-[130px]">{entry.name}</span>
</div>
<span className="font-mono font-semibold ml-2">
{modoExibicao === 'kg'
? `${entry.value.toLocaleString('pt-BR')} kg`
: `${entry.value.toFixed(1)}%`
}
</span>
</div>
);
})}
</div>
</div>
);
};
return ( return (
<div className="space-y-4 w-full"> <div className="space-y-4 w-full">
{/* Barra Superior de Controles */} {/* Barra Superior de Controles */}
@@ -286,7 +304,7 @@ export const GraficoMestre: React.FC<GraficoMestreProps> = ({
unit={modoExibicao === 'kg' ? ' kg' : '%'} unit={modoExibicao === 'kg' ? ' kg' : '%'}
tickFormatter={(val) => modoExibicao === 'kg' && val >= 1000 ? `${(val / 1000).toFixed(1)}k` : `${val}`} tickFormatter={(val) => modoExibicao === 'kg' && val >= 1000 ? `${(val / 1000).toFixed(1)}k` : `${val}`}
/> />
<Tooltip content={<CustomTooltip />} /> <Tooltip content={<CustomTooltip modoExibicao={modoExibicao} selectedProcesso={selectedProcesso} />} />
{processosOrdenados.map((processo, idx) => { {processosOrdenados.map((processo, idx) => {
const color = getCorProcesso(processo.nome, idx); const color = getCorProcesso(processo.nome, idx);