147 lines
6.2 KiB
JavaScript
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;
|