agfrotapainelweb/src/App.tsx

300 lines
8.5 KiB
TypeScript

import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from '@/views/components/ui/card';
import {
ChartContainer,
ChartLegend,
ChartLegendContent,
ChartTooltip,
ChartTooltipContent,
type ChartConfig,
} from '@/views/components/ui/chart';
import { Progress } from '@/views/components/ui/progress';
import { TrendingUp } from 'lucide-react';
import {
Bar,
BarChart,
CartesianGrid,
Line,
LineChart,
Pie,
PieChart,
XAxis,
} from 'recharts';
import { Header } from './views/components/header';
export const description = 'A stacked bar chart with a legend';
export function App() {
const stats = [
{
title: 'Média de Consumo (R$)',
value: 'R$ 0,00',
description: '',
progress: 44.6,
},
{
title: 'Total de KM Percorridos',
value: '0 KM',
description: '',
progress: 30.6,
},
{
title: 'Viagens Realizadas no Mês',
value: '0',
description: '',
progress: 24.8,
},
];
const evolutionConfig = {
price: {
label: 'Preço',
color: '#0e233d',
},
} satisfies ChartConfig;
const evolutionData = [
{ month: 'Shell', price: 186 },
{ month: 'Ipiranga', price: 305 },
{ month: 'BR', price: 237 },
];
const bestPricesConfig = {
price: {
label: 'Preço',
color: '#0e233d',
},
} satisfies ChartConfig;
const bestPricesData = [
{ station: 'Shell', price: 5.42 },
{ station: 'Ipiranga', price: 5.35 },
{ station: 'BR', price: 5.38 },
{ station: 'Ale', price: 5.3 },
];
const vehicleStatusConfig = {
active: {
label: 'Ativos',
color: '#0e233d',
},
maintenance: {
label: 'Manutenção',
color: '#173b63',
},
inactive: {
label: 'Inativos',
color: '#154677',
},
reserved: {
label: 'Reservados',
color: '#145190',
},
} satisfies ChartConfig;
const vehicleStatusData = [
{ status: 'active', count: 45, fill: '#0e233d' },
{ status: 'maintenance', count: 12, fill: '#173b63' },
{ status: 'inactive', count: 8, fill: '#154677' },
{ status: 'reserved', count: 15, fill: '#145190' },
];
const mileageConfig = {
company: {
label: 'Frota Empresa',
color: '#0e233d',
},
rented: {
label: 'Frota Terceirizada',
color: '#173b63',
},
} satisfies ChartConfig;
const mileageData = [
{ month: 'Jan', company: 1200, rented: 800 },
{ month: 'Fev', company: 1350, rented: 750 },
{ month: 'Mar', company: 1100, rented: 900 },
{ month: 'Abr', company: 1400, rented: 600 },
{ month: 'Mai', company: 1250, rented: 850 },
{ month: 'Jun', company: 1300, rented: 700 },
];
return (
<div className="p-[18px] flex flex-col gap-6">
<Header />
<div className="grid gap-4 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-2 xl:grid-cols-3">
{stats.map((stat) => (
<Card
key={stat.title}
className="hover:shadow-md transition-shadow duration-300"
>
<CardHeader className="pb-2">
<CardTitle className="text-sm font-medium text-muted-foreground">
{stat.title}
</CardTitle>
<div className="text-4xl font-bold">{stat.value}</div>
</CardHeader>
<CardContent>
<p className="text-xs text-muted-foreground mb-4">
{stat.description}
</p>
<Progress value={stat.progress} className="h-2" />
</CardContent>
</Card>
))}
</div>
<div className="grid gap-6 grid-cols-1 md:grid-cols-2">
<Card>
<CardHeader>
<CardTitle>Evolução do Consumo de Combustível</CardTitle>
<CardDescription>
Comparativo de preços entre os principais postos
</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={evolutionConfig}>
<LineChart
accessibilityLayer
data={evolutionData}
margin={{
left: 12,
right: 12,
}}
>
<CartesianGrid vertical={false} />
<XAxis
dataKey="month"
tickLine={false}
axisLine={false}
tickMargin={8}
/>
<ChartTooltip
cursor={false}
content={<ChartTooltipContent hideLabel />}
/>
<Line
dataKey="price"
type="natural"
stroke="var(--color-price)"
strokeWidth={2}
dot={{
fill: 'var(--color-price)',
}}
activeDot={{
r: 6,
}}
/>
</LineChart>
</ChartContainer>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Postos com Melhor Preço</CardTitle>
<CardDescription>
Comparativo de preços entre os principais postos
</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={bestPricesConfig}>
<BarChart accessibilityLayer data={bestPricesData}>
<CartesianGrid vertical={false} />
<XAxis
dataKey="station"
tickLine={false}
tickMargin={10}
axisLine={false}
/>
<ChartTooltip
cursor={false}
content={<ChartTooltipContent hideLabel />}
/>
<Bar dataKey="price" fill="var(--color-price)" radius={8} />
</BarChart>
</ChartContainer>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Quilometragem Percorrida</CardTitle>
<CardDescription>
Total de quilômetros percorridos nos últimos meses
</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={mileageConfig}>
<BarChart accessibilityLayer data={mileageData}>
<CartesianGrid vertical={false} />
<XAxis
dataKey="month"
tickLine={false}
tickMargin={10}
axisLine={false}
/>
<ChartTooltip content={<ChartTooltipContent hideLabel />} />
<ChartLegend content={<ChartLegendContent />} />
<Bar
dataKey="company"
stackId="a"
fill="var(--color-company)"
radius={[0, 0, 4, 4]}
/>
<Bar
dataKey="rented"
stackId="a"
fill="var(--color-rented)"
radius={[4, 4, 0, 0]}
/>
</BarChart>
</ChartContainer>
</CardContent>
</Card>
<Card className="flex flex-col">
<CardHeader className="items-center pb-0">
<CardTitle>Status dos Veículos</CardTitle>
<CardDescription>
Distribuição dos veículos por status de operação
</CardDescription>
</CardHeader>
<CardContent className="flex-1 pb-0">
<ChartContainer
config={vehicleStatusConfig}
className="[&_.recharts-pie-label-text]:fill-foreground mx-auto aspect-square max-h-[320px] pb-0"
>
<PieChart>
<ChartTooltip content={<ChartTooltipContent hideLabel />} />
<Pie
data={vehicleStatusData}
dataKey="count"
label
nameKey="status"
/>
</PieChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 leading-none font-medium">
Frota operando com 85% de disponibilidade{' '}
<TrendingUp className="h-4 w-4" />
</div>
<div className="text-muted-foreground leading-none">
Status atual da frota de veículos
</div>
</CardFooter>
</Card>
</div>
</div>
);
}