Cart and checkout
The cart, the summary, paying with bKash or a card.
- 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.
Cart
FreeItems, quantities and the total.
cart-page.tsx
"use client";
import { Camera, Cpu, Lock, Trash2, TrafficCone } from "lucide-react";
import * as React from "react";
import { Button, Input, NumberInput } from "@waveinno/ui";
const START = [
{ id: "arm", name: "Barrier arm, 4 m", line: "Graphite", price: 38500, qty: 2, hue: 230, icon: <TrafficCone /> },
{ id: "cam", name: "Plate camera, night", line: "Graphite", price: 24900, qty: 1, hue: 265, icon: <Camera /> },
{ id: "ctl", name: "Gate controller", line: "4 gates", price: 15500, qty: 1, hue: 285, icon: <Cpu /> },
];
const taka = (n: number) => `৳${n.toLocaleString("en-IN")}`;
export default function CartPage() {
const [items, setItems] = React.useState(START);
const subtotal = items.reduce((s, i) => s + i.price * i.qty, 0);
const vat = Math.round(subtotal * 0.05);
return (
<section className="px-4 py-12 sm:px-6">
<div className="mx-auto max-w-5xl">
<h1 className="disp text-[28px] font-bold leading-9 tracking-[-0.025em] text-text">Your cart</h1>
<div className="mt-8 grid gap-8 lg:grid-cols-[1fr_340px]">
<ul className="divide-y divide-border border-y border-border">
{items.map((it) => (
<li key={it.id} className="flex gap-4 py-5">
<span
className="grid size-24 shrink-0 place-items-center rounded-[16px] border border-border [&_svg]:size-9 [&_svg]:stroke-[1.4]"
style={{ color: `hsl(${it.hue} 50% 40%)`, background: `linear-gradient(160deg, hsl(${it.hue} 60% 96%), hsl(${it.hue + 30} 40% 86%))` }}
>
{it.icon}
</span>
<div className="flex min-w-0 flex-1 flex-col">
<div className="flex justify-between gap-3">
<div>
<h2 className="text-[15px] font-semibold text-text">{it.name}</h2>
<p className="text-[13px] text-muted">{it.line}</p>
</div>
<p className="num text-[15px] font-semibold text-text">{taka(it.price * it.qty)}</p>
</div>
<div className="mt-auto flex items-center justify-between pt-3">
<div className="w-32">
<NumberInput value={it.qty} min={1} max={20} onValueChange={(v) => setItems((all) => all.map((x) => (x.id === it.id ? { ...x, qty: v ?? 1 } : x)))} aria-label={`Quantity of ${it.name}`} />
</div>
<button type="button" onClick={() => setItems((all) => all.filter((x) => x.id !== it.id))} className="inline-flex cursor-pointer items-center gap-1.5 text-[13px] font-medium text-muted hover:text-danger">
<Trash2 className="size-4" /> Remove
</button>
</div>
</div>
</li>
))}
{!items.length ? <li className="py-16 text-center text-[14px] text-muted">Your cart is empty.</li> : null}
</ul>
<aside className="h-fit rounded-[20px] border border-border bg-surface p-6">
<h2 className="text-[16px] font-semibold text-text">Summary</h2>
<dl className="mt-4 space-y-2.5 text-[14px]">
<div className="flex justify-between text-body">
<dt>Subtotal</dt>
<dd className="num">{taka(subtotal)}</dd>
</div>
<div className="flex justify-between text-body">
<dt>VAT (5%)</dt>
<dd className="num">{taka(vat)}</dd>
</div>
<div className="flex justify-between text-body">
<dt>Delivery in Dhaka</dt>
<dd className="font-medium text-success">Free</dd>
</div>
<div className="flex justify-between border-t border-border pt-3 text-[16px] font-semibold text-text">
<dt>Total</dt>
<dd className="num">{taka(subtotal + vat)}</dd>
</div>
</dl>
<div className="mt-5 flex gap-2">
<Input placeholder="Discount code" aria-label="Discount code" />
<Button variant="secondary">Apply</Button>
</div>
<Button variant="primary" size="lg" className="mt-4 w-full" disabled={!items.length}>
<Lock /> Check out
</Button>
</aside>
</div>
</div>
</section>
);
}Order confirmed
FreeThank you, what was bought and what happens next.
order-confirmation.tsx
import { Check, Download, Mail, MapPin, Package, Truck, Wrench } from "lucide-react";
import { Button } from "@waveinno/ui";
const ITEMS = [
["Barrier arm, 4 m", "× 2", "৳77,000"],
["Plate camera, night", "× 1", "৳24,900"],
["Gate controller", "× 1", "৳15,500"],
];
const NEXT = [
{ icon: <Package />, title: "Packed", line: "Today, by 6 pm", done: true },
{ icon: <Truck />, title: "On the way", line: "Tomorrow morning" },
{ icon: <Wrench />, title: "Fitted at your site", line: "Our engineer calls first" },
];
export default function OrderConfirmation() {
return (
<section className="px-4 py-14 sm:px-6">
<div className="mx-auto max-w-2xl">
<div className="text-center">
<span className="mx-auto grid size-14 place-items-center rounded-full bg-success text-white shadow-[0_0_0_8px_var(--success-subtle)]">
<Check className="size-7" strokeWidth={3} />
</span>
<h1 className="disp mt-6 text-[28px] font-bold leading-9 tracking-[-0.025em] text-text">Thank you, Karim</h1>
<p className="mt-2 text-[15px] text-body">
Order <b className="font-mono font-semibold text-text">WV-20418</b> is confirmed. A receipt is on its way to your email.
</p>
</div>
<ol className="mt-10 grid grid-cols-3 gap-3">
{NEXT.map((s, i) => (
<li key={s.title} className="relative text-center">
{i < NEXT.length - 1 ? <span aria-hidden className="absolute left-[calc(50%+24px)] right-[calc(-50%+24px)] top-5 h-px bg-border" /> : null}
<span className={`relative mx-auto grid size-10 place-items-center rounded-full [&_svg]:size-[18px] ${s.done ? "bg-primary text-white" : "bg-hover text-muted"}`}>{s.icon}</span>
<p className="mt-2 text-[13.5px] font-semibold text-text">{s.title}</p>
<p className="text-[12px] text-muted">{s.line}</p>
</li>
))}
</ol>
<div className="mt-10 rounded-[20px] border border-border bg-raised shadow-[var(--lit)]">
<ul className="divide-y divide-border px-5">
{ITEMS.map(([n, q, p]) => (
<li key={n} className="flex items-center justify-between py-3.5 text-[14px]">
<span className="text-text">
{n} <span className="text-muted">{q}</span>
</span>
<span className="num font-medium text-text">{p}</span>
</li>
))}
</ul>
<div className="flex justify-between border-t border-border bg-surface px-5 py-4 text-[15px] font-semibold text-text">
<span>Paid with bKash</span>
<span className="num">৳1,23,270</span>
</div>
</div>
<div className="mt-5 grid gap-3 text-[13.5px] sm:grid-cols-2">
<p className="flex items-start gap-2 text-body">
<MapPin className="mt-0.5 size-4 shrink-0 text-muted" /> House 12, Road 7, Gulshan 1, Dhaka
</p>
<p className="flex items-start gap-2 text-body">
<Mail className="mt-0.5 size-4 shrink-0 text-muted" /> karim@gulshanparking.com
</p>
</div>
<div className="mt-8 flex flex-wrap justify-center gap-3">
<Button variant="primary">Track the order</Button>
<Button variant="secondary">
<Download /> VAT invoice
</Button>
</div>
</div>
</section>
);
}Checkout
ProAddress, delivery and payment beside the order summary.
Cart drawer
ProA slide-over cart with free delivery progress and an add-on.
Order tracking
ProWhere the order is, the route and the courier.