testes/src_2/features/fleet-v2/views/DashboardView.jsx

147 lines
6.2 KiB
JavaScript

import React from 'react';
import { useFleetData } from '../hooks/useFleetData';
import {
Truck,
Wrench,
Fuel,
MapPin,
AlertCircle,
ClipboardCheck,
Store,
Navigation,
ArrowUpRight,
TrendingUp
} from 'lucide-react';
import { Badge } from '@/components/ui/badge';
import { Card, CardContent } from '@/components/ui/card';
import { cn } from '@/lib/utils';
import { motion } from 'framer-motion';
import { StatsGrid, DataTable } from '@/components/shared';
import { TableRow, TableCell } from '@/components/ui/table';
const TABLE_COLUMNS = ['Placa', 'Modelo', 'Status', 'Localização / Base', 'Motorista Responsável'];
/**
* StatCard - Componente local para replicar o design de "Icon Box" do mockup
*/
const StatCard = ({ label, value, icon, colorClass, statusDesc }) => (
<Card className="border border-slate-200 shadow-sm bg-white overflow-hidden group hover:border-primary/50 transition-all duration-300">
<CardContent className="p-6 flex items-center justify-between">
<div className="space-y-1">
<h3 className="text-[0.7rem] font-bold text-slate-500 uppercase tracking-wider">{label}</h3>
<p className="text-3xl font-black text-slate-900 tracking-tighter">{value}</p>
{statusDesc && <p className="text-[0.65rem] text-slate-400 font-medium">{statusDesc}</p>}
</div>
<div className={cn(
"w-14 h-14 rounded-2xl flex items-center justify-center text-2xl shadow-lg group-hover:scale-110 transition-transform duration-300",
colorClass
)}>
{React.cloneElement(icon, { size: 28, strokeWidth: 2.5 })}
</div>
</CardContent>
</Card>
);
/**
* Visão Geral (Dashboard) do ambiente Fleet V2.
* Replica o layout de grids e cards do mockup.
*/
export const DashboardView = () => {
const { veiculos, stats } = useFleetData();
const primaryStats = React.useMemo(() => [
{ label: 'Frota Total', value: stats.total, icon: <Truck />, color: 'bg-primary/10 text-primary' },
{ label: 'Em Operação', value: stats.operacao, icon: <Navigation />, color: 'bg-emerald-100 text-emerald-600' },
{ label: 'Em Manutenção', value: stats.manutencao, icon: <Wrench />, color: 'bg-rose-100 text-rose-600' },
{ label: 'Abastecimentos (Mês)', value: stats.abastecimentosMes, icon: <Fuel />, color: 'bg-amber-100 text-amber-600' },
], [stats]);
const secondaryStats = React.useMemo(() => [
{ label: 'Checklists Realizados', value: stats.checklists, icon: <ClipboardCheck />, color: 'bg-teal-100 text-teal-600' },
{ label: 'Alertas Monitoramento', value: stats.alertas, icon: <AlertCircle />, color: 'bg-primary/10 text-primary' },
{ label: 'SLA MÁXIMO', value: '4.8h', icon: <TrendingUp />, color: 'bg-emerald-500 text-white', statusDesc: 'Meta de Performance' },
], [stats]);
const renderVehicleRow = (v) => (
<TableRow key={v.id} className="hover:bg-slate-50/50 transition-colors group">
<TableCell className="px-6 py-4">
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded-lg bg-slate-100 flex items-center justify-center text-slate-600 font-bold text-[0.6rem] border border-slate-200">
{v.uf || 'SP'}
</div>
<span className="font-bold text-slate-700 font-mono tracking-tighter text-sm">{v.placa}</span>
</div>
</TableCell>
<TableCell className="px-6 py-4">
<span className="text-sm font-semibold text-slate-600">{v.modelo}</span>
</TableCell>
<TableCell className="px-6 py-4 text-center">
<Badge variant="outline" className={cn(
"font-bold text-[0.65rem] uppercase tracking-tighter px-2.5 py-0.5 rounded-full border-none",
v.status === 'operacao' ? "bg-emerald-500/10 text-emerald-600" :
v.status === 'manutencao' ? "bg-rose-500/10 text-rose-600" :
"bg-slate-500/10 text-slate-600"
)}>
{v.status === 'operacao' ? 'Em Operação' : v.status === 'manutencao' ? 'Manutenção' : 'Parado'}
</Badge>
</TableCell>
<TableCell className="px-6 py-4">
<div className="flex items-center gap-2 text-slate-500">
<MapPin size={14} className="text-slate-400" />
<span className="text-xs font-semibold">{v.base}</span>
</div>
</TableCell>
<TableCell className="px-6 py-4">
<div className="flex items-center gap-2">
<div className="w-7 h-7 rounded-full bg-primary/10 flex items-center justify-center text-[0.6rem] font-bold text-primary">
{v.motorista.substring(0, 2).toUpperCase()}
</div>
<span className="text-xs font-bold text-slate-700">{v.motorista}</span>
</div>
</TableCell>
</TableRow>
);
return (
<div className="space-y-6 pb-10">
{/* Linha 1: Frota Macro (4 cards) */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{primaryStats.map((stat, i) => (
<StatCard key={i} {...stat} colorClass={stat.color} />
))}
</div>
{/* Linha 2: Monitoramento e Qualidade (3 cards) */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{secondaryStats.map((stat, i) => (
<StatCard key={i} {...stat} colorClass={stat.color} />
))}
</div>
{/* Tabela de Resumo */}
<Card className="border border-slate-200 shadow-sm bg-white overflow-hidden">
<div className="px-6 py-4 border-b border-slate-100 bg-slate-50/50 flex items-center justify-between">
<div>
<h3 className="text-sm font-bold text-slate-900 tracking-tight">Resumo da Frota</h3>
<p className="text-[0.65rem] text-slate-400 font-medium uppercase tracking-wider">Status em Tempo Real</p>
</div>
<button className="text-[0.7rem] font-bold text-primary hover:text-emerald-700 flex items-center gap-1 uppercase tracking-widest transition-colors">
Ver Grid Completo <ArrowUpRight size={14} />
</button>
</div>
<div className="p-6 pt-4">
<DataTable
columns={TABLE_COLUMNS}
data={veiculos.slice(0, 5)}
searchKey="placa"
renderRow={renderVehicleRow}
/>
</div>
</Card>
</div>
);
};
export default DashboardView;