Files
edr-platform/apps/edr-freight-web/backoffice/src/components/bookings/BookingStatGrid.tsx

109 lines
3.5 KiB
TypeScript

import type { LucideIcon } from "lucide-react";
import { Card, Group, Stack, Text, Paper } from "@mantine/core";
export interface StatItem {
label: string;
value: number | string;
hint?: string;
icon: LucideIcon;
accent?: "default" | "amber" | "emerald" | "rose";
}
const accentColors = {
default: { bg: "var(--mantine-color-gray-1)", color: "var(--mantine-color-gray-6)" },
amber: { bg: "var(--mantine-color-yellow-1)", color: "var(--mantine-color-yellow-6)" },
emerald: { bg: "var(--freight-brand-muted)", color: "var(--freight-brand)" },
rose: { bg: "var(--mantine-color-red-1)", color: "var(--mantine-color-red-6)" },
};
export function BookingStatGrid({ items }: { items: StatItem[] }) {
return (
<Paper
p="md"
radius="lg"
withBorder
style={{
background: "white",
border: "1px solid var(--mantine-color-gray-2)",
overflowX: "auto",
overflowY: "hidden",
WebkitOverflowScrolling: "touch",
scrollBehavior: "smooth",
}}
>
<Group
gap="lg"
style={{
minWidth: "min-content",
display: "flex",
flexWrap: "nowrap",
}}
>
{items.map((item) => {
const Icon = item.icon;
const accent = item.accent ?? "default";
const accentStyle = accentColors[accent];
return (
<Card
key={item.label}
p="lg"
radius="lg"
withBorder
style={{
background: "white",
border: "1px solid var(--mantine-color-gray-2)",
transition: "all 0.2s ease",
cursor: "pointer",
minWidth: "280px",
width: "280px",
flexShrink: 0,
}}
onMouseEnter={(e) => {
e.currentTarget.style.boxShadow = "0 4px 12px rgba(34, 197, 94, 0.12)";
e.currentTarget.style.borderColor = "var(--freight-brand-border)";
}}
onMouseLeave={(e) => {
e.currentTarget.style.boxShadow = "none";
e.currentTarget.style.borderColor = "var(--mantine-color-gray-2)";
}}
>
<Group justify="space-between" align="flex-start">
<Stack gap="xs" style={{ flex: 1 }}>
<Text size="xs" fw={600} c="dimmed" tt="uppercase">
{item.label}
</Text>
<Text size="32px" fw={700} style={{ lineHeight: 1, letterSpacing: "-0.02em" }}>
{item.value}
</Text>
{item.hint && (
<Text size="xs" c="dimmed">
{item.hint}
</Text>
)}
</Stack>
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
width: "44px",
height: "44px",
borderRadius: "10px",
background: accentStyle.bg,
color: accentStyle.color,
flexShrink: 0,
transition: "transform 0.2s ease",
}}
>
<Icon size={22} strokeWidth={1.75} />
</div>
</Group>
</Card>
);
})}
</Group>
</Paper>
);
}