140 lines
5.7 KiB
JavaScript
140 lines
5.7 KiB
JavaScript
import React from 'react';
|
|
import {
|
|
Truck, AlertCircle, Clock, CheckCircle2,
|
|
TrendingUp, TrendingDown, DollarSign, MapPin
|
|
} from 'lucide-react';
|
|
import { Card, CardContent } from '@/components/ui/card';
|
|
|
|
const StatCard = ({ title, value, subtext, icon: Icon, color, trend }) => (
|
|
<Card className="bg-[#1c1c1c] border-[#2a2a2a] text-slate-200 overflow-hidden relative group hover:border-[#333] transition-all">
|
|
<div className={`absolute top-0 left-0 w-1 h-full ${color}`} />
|
|
<CardContent className="p-6">
|
|
<div className="flex justify-between items-start">
|
|
<div>
|
|
<p className="text-[10px] font-bold uppercase tracking-widest text-slate-500 mb-1">{title}</p>
|
|
<h3 className="text-3xl font-bold text-white tracking-tight">{value}</h3>
|
|
{subtext && <p className="text-xs text-slate-500 mt-1 font-medium">{subtext}</p>}
|
|
</div>
|
|
<div className={`p-3 rounded-xl bg-opacity-10 ${color.replace('bg-', 'bg-').replace('w-1', '')} ${color.replace('bg-', 'text-')}`}>
|
|
<Icon size={24} strokeWidth={2.5} />
|
|
</div>
|
|
</div>
|
|
{trend && (
|
|
<div className="mt-4 flex items-center gap-2">
|
|
<span className={`text-xs font-bold px-1.5 py-0.5 rounded flex items-center gap-1 ${trend > 0 ? 'text-orange-500 bg-orange-500/10' : 'text-red-500 bg-red-500/10'}`}>
|
|
{trend > 0 ? <TrendingUp size={12} /> : <TrendingDown size={12} />}
|
|
{Math.abs(trend)}%
|
|
</span>
|
|
<span className="text-[10px] text-slate-600 uppercase font-bold">vs mês anterior</span>
|
|
</div>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
|
|
export default function DashboardView() {
|
|
return (
|
|
<div className="space-y-8">
|
|
{/* Header */}
|
|
<div>
|
|
<h1 className="text-2xl font-bold text-white tracking-tight">Visão Geral</h1>
|
|
<p className="text-slate-500 text-sm">Monitoramento em tempo real da operação.</p>
|
|
</div>
|
|
|
|
{/* KPI Grid */}
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
|
<StatCard
|
|
title="Frota Total"
|
|
value="1,240"
|
|
subtext="1033 em operação"
|
|
icon={Truck}
|
|
color="bg-blue-600"
|
|
trend={12.5}
|
|
/>
|
|
<StatCard
|
|
title="Manutenção"
|
|
value="28"
|
|
subtext="4 críticos"
|
|
icon={AlertCircle}
|
|
color="bg-red-500"
|
|
trend={-2.4}
|
|
/>
|
|
<StatCard
|
|
title="Disponibilidade"
|
|
value="94.2%"
|
|
subtext="Meta: 95%"
|
|
icon={CheckCircle2}
|
|
color="bg-orange-500"
|
|
trend={1.8}
|
|
/>
|
|
<StatCard
|
|
title="Custo Médio"
|
|
value="R$ 2.4k"
|
|
subtext="Por veículo/mês"
|
|
icon={DollarSign}
|
|
color="bg-yellow-500"
|
|
trend={-0.5}
|
|
/>
|
|
</div>
|
|
|
|
{/* Secondary Row */}
|
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
|
<Card className="bg-[#1c1c1c] border-[#2a2a2a] lg:col-span-2">
|
|
<CardContent className="p-6">
|
|
<div className="flex items-center justify-between mb-6">
|
|
<h3 className="font-bold text-white text-lg">Distribuição por Base</h3>
|
|
<button className="text-xs font-bold text-yellow-500 hover:text-yellow-400">VER RELATÓRIO</button>
|
|
</div>
|
|
|
|
<div className="space-y-4">
|
|
{[
|
|
{ label: 'SP - Capital (SRJ10)', val: 450, tot: 1240, col: 'bg-blue-600' },
|
|
{ label: 'RJ - Rio de Janeiro (GIG)', val: 320, tot: 1240, col: 'bg-orange-500' },
|
|
{ label: 'MG - Belo Horizonte', val: 210, tot: 1240, col: 'bg-yellow-500' },
|
|
{ label: 'Outras Bases', val: 260, tot: 1240, col: 'bg-slate-600' },
|
|
].map((item, i) => (
|
|
<div key={i} className="space-y-1">
|
|
<div className="flex justify-between text-xs font-medium text-slate-400">
|
|
<span>{item.label}</span>
|
|
<span className="text-white">{item.val}</span>
|
|
</div>
|
|
<div className="h-2 bg-[#2a2a2a] rounded-full overflow-hidden">
|
|
<div className={`h-full ${item.col} rounded-full`} style={{ width: `${(item.val / item.tot) * 100}%` }} />
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card className="bg-[#1c1c1c] border-[#2a2a2a]">
|
|
<CardContent className="p-6">
|
|
<h3 className="font-bold text-white text-lg mb-6">Alertas Recentes</h3>
|
|
<div className="space-y-4">
|
|
{[
|
|
{ msg: 'Manutenção Preventiva - ABC-1234', time: 'Há 2h', type: 'warn' },
|
|
{ msg: 'Multa Registrada - XYZ-9876', time: 'Há 4h', type: 'crit' },
|
|
{ msg: 'Novo Veículo Cadastrado', time: 'Há 5h', type: 'info' },
|
|
{ msg: 'Checklist Atrasado - GOL-5544', time: 'Ontem', type: 'warn' },
|
|
].map((alert, i) => (
|
|
<div key={i} className="flex items-start gap-3 pb-3 border-b border-[#2a2a2a] last:border-0 last:pb-0">
|
|
<div className={`w-2 h-2 mt-1.5 rounded-full ${alert.type === 'crit' ? 'bg-red-500' : alert.type === 'warn' ? 'bg-yellow-500' : 'bg-blue-500'}`} />
|
|
<div>
|
|
<p className="text-sm text-slate-300 font-medium">{alert.msg}</p>
|
|
<span className="text-[10px] text-slate-500 uppercase font-bold flex items-center gap-1">
|
|
<Clock size={10} /> {alert.time}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
|
|
|