Dashboards
The overview screen: numbers, trends, what needs attention.
- 5 blocks
- 2 free
- 3 Pro
- Light and dark
- Responsive
Unlock 55 Pro blocks and every template
Every preview is open. With Pro you get the code, copy-paste ready, with every update for good.
Stats and recent
FreeFour numbers and the latest payments.
dashboard-stats.tsx
import { CarFront, Timer, Wallet } from "lucide-react";
import { Avatar, Badge, StatCard } from "@waveinno/ui";
const PAYMENTS = [
{ who: "Nusrat Jahan", plate: "DHA-GA 12-3456", how: "bKash", amount: "৳120", when: "2 min ago", ok: true },
{ who: "Rafiq Islam", plate: "DHA-KHA 45-1029", how: "Cash", amount: "৳40", when: "6 min ago", ok: true },
{ who: "Farhana Akter", plate: "CTG-GA 11-8890", how: "Card", amount: "৳280", when: "11 min ago", ok: false },
{ who: "Tanvir Hasan", plate: "DHA-CHA 33-4410", how: "Nagad", amount: "৳60", when: "18 min ago", ok: true },
];
export default function DashboardStats() {
return (
<div className="bg-surface px-4 py-8 sm:px-6">
<div className="mx-auto max-w-6xl">
<h1 className="disp text-[24px] font-bold leading-8 text-text">Today</h1>
<p className="text-[13.5px] text-muted">Gulshan Parking, since 6 am</p>
<div className="mt-6 grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
<StatCard label="Revenue" value="48,250" currency delta={12.4} deltaLabel="vs last Thu" variant="gradient" />
<StatCard label="Cars inside" value="312" delta={6.2} deltaLabel="vs last Thu" icon={<CarFront />} />
<StatCard label="Average stay" value="1h 42m" delta={-4.1} deltaLabel="shorter" icon={<Timer />} />
<StatCard label="Paid digitally" value="61%" delta={9} deltaLabel="of payments" icon={<Wallet />} />
</div>
<div className="mt-6 overflow-hidden rounded-[18px] border border-border bg-raised shadow-[var(--lit)]">
<div className="flex items-center justify-between border-b border-border px-5 py-4">
<h2 className="text-[15px] font-semibold text-text">Latest payments</h2>
<a href="#" className="text-[13px] font-semibold text-primary hover:underline">
See all
</a>
</div>
<ul className="divide-y divide-border">
{PAYMENTS.map((p) => (
<li key={p.plate} className="flex items-center gap-3 px-5 py-3.5">
<Avatar name={p.who} size="sm" />
<div className="min-w-0 flex-1">
<p className="truncate text-[13.5px] font-medium text-text">{p.who}</p>
<p className="font-mono text-[12px] text-muted">{p.plate}</p>
</div>
<span className="hidden text-[12.5px] text-muted sm:block">{p.when}</span>
<Badge tone={p.ok ? "success" : "warning"}>{p.ok ? p.how : "Pending"}</Badge>
<span className="num w-16 text-right text-[14px] font-semibold text-text">{p.amount}</span>
</li>
))}
</ul>
</div>
</div>
</div>
);
}Who is inside now, filterable, with status.
dashboard-sessions.tsx
"use client";
import { Download, Search } from "lucide-react";
import * as React from "react";
import { Badge, Button, Input, Segmented } from "@waveinno/ui";
type Status = "parked" | "paying" | "overstay";
const ROWS: { plate: string; level: string; entered: string; stay: string; fee: number; status: Status }[] = [
{ plate: "DHA-GA 12-3456", level: "B2", entered: "16:32", stay: "2 h 10 m", fee: 120, status: "parked" },
{ plate: "DHA-KHA 45-1029", level: "A1", entered: "17:54", stay: "48 m", fee: 40, status: "paying" },
{ plate: "CTG-GA 11-8890", level: "B1", entered: "13:40", stay: "5 h 02 m", fee: 280, status: "overstay" },
{ plate: "DHA-CHA 33-4410", level: "C3", entered: "18:30", stay: "12 m", fee: 20, status: "parked" },
{ plate: "DHA-GHA 21-7781", level: "A2", entered: "15:05", stay: "3 h 37 m", fee: 200, status: "parked" },
{ plate: "SYL-KA 09-1200", level: "B2", entered: "18:12", stay: "30 m", fee: 20, status: "paying" },
];
const TONE: Record<Status, "info" | "warning" | "danger"> = { parked: "info", paying: "warning", overstay: "danger" };
const LABEL: Record<Status, string> = { parked: "Parked", paying: "Paying", overstay: "Overstay" };
export default function DashboardSessions() {
const [filter, setFilter] = React.useState<"all" | Status>("all");
const [q, setQ] = React.useState("");
const rows = ROWS.filter((r) => (filter === "all" || r.status === filter) && r.plate.toLowerCase().includes(q.trim().toLowerCase()));
return (
<div className="bg-surface px-4 py-8 sm:px-6">
<div className="mx-auto max-w-6xl">
<div className="flex flex-wrap items-end justify-between gap-3">
<div>
<h1 className="disp text-[24px] font-bold leading-8 text-text">Sessions</h1>
<p className="text-[13.5px] text-muted">{ROWS.length} cars inside now</p>
</div>
<Button variant="secondary">
<Download /> Export
</Button>
</div>
<div className="mt-6 overflow-hidden rounded-[18px] border border-border bg-raised shadow-[var(--lit)]">
<div className="flex flex-wrap items-center gap-3 border-b border-border p-3">
<Segmented
ariaLabel="Status"
size="sm"
value={filter}
onChange={setFilter}
options={[
{ value: "all", label: "All" },
{ value: "parked", label: "Parked" },
{ value: "paying", label: "Paying" },
{ value: "overstay", label: "Overstay" },
]}
/>
<div className="ml-auto w-full sm:w-64">
<Input value={q} onChange={(e) => setQ(e.target.value)} placeholder="Find a plate" leading={<Search />} aria-label="Find a plate" />
</div>
</div>
<div className="overflow-x-auto">
<table className="w-full min-w-[620px] text-left text-[13.5px]">
<thead className="bg-surface text-[11.5px] font-semibold uppercase tracking-[0.08em] text-muted">
<tr>
<th className="px-5 py-3 font-semibold">Plate</th>
<th className="px-5 py-3 font-semibold">Level</th>
<th className="px-5 py-3 font-semibold">Entered</th>
<th className="px-5 py-3 font-semibold">Stay</th>
<th className="px-5 py-3 font-semibold">Status</th>
<th className="px-5 py-3 text-right font-semibold">Fee so far</th>
</tr>
</thead>
<tbody className="divide-y divide-border">
{rows.map((r) => (
<tr key={r.plate} className="transition-colors hover:bg-hover/60">
<td className="px-5 py-3.5 font-mono font-semibold text-text">{r.plate}</td>
<td className="px-5 py-3.5 text-body">{r.level}</td>
<td className="num px-5 py-3.5 text-body">{r.entered}</td>
<td className="px-5 py-3.5 text-body">{r.stay}</td>
<td className="px-5 py-3.5">
<Badge tone={TONE[r.status]}>{LABEL[r.status]}</Badge>
</td>
<td className="num px-5 py-3.5 text-right font-semibold text-text">৳{r.fee}</td>
</tr>
))}
{!rows.length ? (
<tr>
<td colSpan={6} className="px-5 py-10 text-center text-muted">
No cars match.
</td>
</tr>
) : null}
</tbody>
</table>
</div>
</div>
</div>
</div>
);
}Stats, a trend, a breakdown and what needs attention.
Analytics
ProRevenue trend, payment mix and the busiest sites.
Live occupancy
ProLevels filling up, gates and a live feed.