Recent orders
The eight newest orders from anywhere, with their account, country, status and total; reads recentOrders().
Preview
"use client"
import { SimpleTable, type SimpleTableColumn } from "@/components/ui/simple-table"
import { StatusBadge, type StatusVariant } from "@/components/ui/status-badge"
import { CurrencyCell, DateCell, TruncateCell } from "@/components/ui/table-cells"
import { Widget } from "@/components/ui/widget"
import { type OrderRow } from "../data"
// StatusBadge has no default for "fulfilled" or "refunded"; the other three
// resolve on their own and are named here so the whole vocabulary reads in one
// place.
const STATUS_MAP: Record<string, StatusVariant> = {
fulfilled: "success",
paid: "success",
pending: "warning",
refunded: "danger",
cancelled: "neutral",
}
const COLUMNS: SimpleTableColumn<OrderRow>[] = [
{
key: "number",
header: "Order",
cell: (row) => <span className="font-mono text-xs">{row.number}</span>,
},
{
key: "account",
header: "Account",
cell: (row) => <TruncateCell maxWidth={180}>{row.account}</TruncateCell>,
},
{
key: "country",
header: "Country",
cell: (row) => (
<span className="text-muted-foreground">
{row.country} · {row.region}
</span>
),
},
{
key: "status",
header: "Status",
cell: (row) => <StatusBadge status={row.status} map={STATUS_MAP} />,
},
{
key: "total",
header: "Total",
align: "right",
cell: (row) => <CurrencyCell value={row.total} />,
},
{
key: "placedAt",
header: "Placed",
align: "right",
cell: (row) => <DateCell date={row.placedAt} className="text-muted-foreground" />,
},
]
/** The newest orders, wherever in the world they came from. */
export function RecentOrders({ rows }: { rows: OrderRow[] }) {
return (
<Widget data-widget="widget-saas-global-recent-orders" title="Recent orders" description="The newest eight, from anywhere">
<SimpleTable columns={COLUMNS} rows={rows} rowKey="id" size="sm" hoverable />
</Widget>
)
}Install
$
npx shadcn@latest add @vibra/widget-saas-global-recent-ordersNeeds the @vibra registry in your components.json — set it up once.
Source
"use client"
import { SimpleTable, type SimpleTableColumn } from "@/components/ui/simple-table"
import { StatusBadge, type StatusVariant } from "@/components/ui/status-badge"
import { CurrencyCell, DateCell, TruncateCell } from "@/components/ui/table-cells"
import { Widget } from "@/components/ui/widget"
import { type OrderRow } from "../data"
// StatusBadge has no default for "fulfilled" or "refunded"; the other three
// resolve on their own and are named here so the whole vocabulary reads in one
// place.
const STATUS_MAP: Record<string, StatusVariant> = {
fulfilled: "success",
paid: "success",
pending: "warning",
refunded: "danger",
cancelled: "neutral",
}
const COLUMNS: SimpleTableColumn<OrderRow>[] = [
{
key: "number",
header: "Order",
cell: (row) => <span className="font-mono text-xs">{row.number}</span>,
},
{
key: "account",
header: "Account",
cell: (row) => <TruncateCell maxWidth={180}>{row.account}</TruncateCell>,
},
{
key: "country",
header: "Country",
cell: (row) => (
<span className="text-muted-foreground">
{row.country} · {row.region}
</span>
),
},
{
key: "status",
header: "Status",
cell: (row) => <StatusBadge status={row.status} map={STATUS_MAP} />,
},
{
key: "total",
header: "Total",
align: "right",
cell: (row) => <CurrencyCell value={row.total} />,
},
{
key: "placedAt",
header: "Placed",
align: "right",
cell: (row) => <DateCell date={row.placedAt} className="text-muted-foreground" />,
},
]
/** The newest orders, wherever in the world they came from. */
export function RecentOrders({ rows }: { rows: OrderRow[] }) {
return (
<Widget data-widget="widget-saas-global-recent-orders" title="Recent orders" description="The newest eight, from anywhere">
<SimpleTable columns={COLUMNS} rows={rows} rowKey="id" size="sm" hoverable />
</Widget>
)
}/**
* What /global reads. Traffic is `db.sessions` — one row per country per hour
* over the last day, each carrying where the country is — and money is
* `db.orders`, joined to `db.customers` for the account behind an order. The
* region an order belongs to is not a column on the order: it is the region the
* session rows already record for that country, so the two halves of the page
* agree by construction rather than by a second list written by hand. Nothing
* reads a clock: the window ends at REFERENCE_DATE.
*/
import { getInitials } from "@/lib/format"
import {
db,
REFERENCE_DATE,
type Member,
type Order,
type Session,
} from "@/lib/sample-data"
// The sessions are a read-only day of traffic. The orders and the accounts are
// read per call, never held at module scope: a sale rung up or refunded since
// the server started is in the next render's figures.
const SESSIONS = db.sessions.all()
const orders = (): Order[] => db.orders.all()
/** How many hours of traffic the page covers. */
export const WINDOW_HOURS = 24
const dollars = (cents: number): number => cents / 100
/** An order counts towards revenue once it is paid and until it is refunded. */
const billable = (order: Order): boolean =>
order.status === "paid" || order.status === "fulfilled"
type Place = { country: string; region: Session["region"]; lat: number; lng: number }
// One entry per country, folded out of the hourly rows: every hour of a country
// carries the same place, so the first one seen settles it.
const PLACES = new Map<string, Place>()
for (const row of SESSIONS) {
if (!PLACES.has(row.country)) {
PLACES.set(row.country, { country: row.country, region: row.region, lat: row.lat, lng: row.lng })
}
}
/** The region a country trades in, read off the traffic rather than a second list. */
export function regionOf(country: string): string {
return PLACES.get(country)?.region ?? "Rest of world"
}
export type CountryTraffic = {
country: string
region: string
lat: number
lng: number
sessions: number
/** Sessions weighted p95, in milliseconds. */
p95Ms: number
errorRate: number
}
// Every country's day, rolled up once: sessions summed, and latency and errors
// weighted by the sessions behind them — an hour with 12 sessions cannot pull
// the day's p95 as hard as one with 900.
const BY_COUNTRY: CountryTraffic[] = [...PLACES.values()]
.map((place) => {
const hours = SESSIONS.filter((row) => row.country === place.country)
const sessions = hours.reduce((total, row) => total + row.sessions, 0)
const weighted = (read: (row: Session) => number) =>
sessions === 0
? 0
: hours.reduce((total, row) => total + read(row) * row.sessions, 0) / sessions
return {
country: place.country,
region: place.region,
lat: place.lat,
lng: place.lng,
sessions,
p95Ms: Math.round(weighted((row) => row.p95Ms)),
errorRate: weighted((row) => row.errorRate),
}
})
.sort((a, b) => b.sessions - a.sessions)
/** Every country's day, busiest first. */
export function countryTraffic(): CountryTraffic[] {
return BY_COUNTRY
}
export type MapMarker = { id: string; lat: number; lng: number; value: number; label: string }
/** The same rows as markers, which is all the map needs. */
export function mapMarkers(): MapMarker[] {
return BY_COUNTRY.map((row) => ({
id: row.country,
lat: row.lat,
lng: row.lng,
value: row.sessions,
label: row.country,
}))
}
export type GlobalStat = {
key: string
label: string
value: number
description: string
format: "number" | "currency" | "duration" | "percent"
}
const TOTAL_SESSIONS = BY_COUNTRY.reduce((total, row) => total + row.sessions, 0)
/** The four headline numbers: how much traffic, from how far, how fast, worth how much. */
export function globalStats(): GlobalStat[] {
const p95 =
TOTAL_SESSIONS === 0
? 0
: BY_COUNTRY.reduce((total, row) => total + row.p95Ms * row.sessions, 0) / TOTAL_SESSIONS
const paid = orders().filter(billable)
const revenue = paid.reduce((total, order) => total + order.totalCents, 0)
return [
{
key: "sessions",
label: "Sessions",
value: TOTAL_SESSIONS,
description: `in the last ${WINDOW_HOURS} hours`,
format: "number",
},
{
key: "countries",
label: "Countries",
value: BY_COUNTRY.length,
description: `led by ${BY_COUNTRY[0]?.country ?? "nowhere"}`,
format: "number",
},
{
key: "p95",
label: "p95 response",
value: Math.round(p95),
description: "weighted by where the traffic came from",
format: "duration",
},
{
key: "revenue",
label: "Booked revenue",
value: Math.round(dollars(revenue)),
description: `across ${paid.length} paid orders`,
format: "currency",
},
]
}
export type RegionRevenue = { region: string; revenue: number }
const REGION_ORDER = ["Americas", "EMEA", "APAC", "Rest of world"]
/** Booked value per region, in the order a reader reads a map. */
export function revenueByRegion(): RegionRevenue[] {
const totals = new Map<string, number>()
for (const order of orders()) {
if (!billable(order)) continue
const region = regionOf(order.country)
totals.set(region, (totals.get(region) ?? 0) + order.totalCents)
}
return REGION_ORDER.filter((region) => totals.has(region)).map((region) => ({
region,
revenue: Math.round(dollars(totals.get(region) ?? 0)),
}))
}
export type OrderRow = {
id: string
number: string
account: string
country: string
region: string
status: Order["status"]
total: number
placedAt: Date
}
/** How many of the newest orders the table shows. */
const RECENT = 8
/** The newest orders, wherever they came from. */
export function recentOrders(): OrderRow[] {
const accounts = new Map(db.customers.all().map((customer) => [customer.id, customer]))
return orders()
.sort((a, b) => b.placedAt.getTime() - a.placedAt.getTime())
.slice(0, RECENT)
.map((order) => ({
id: order.id,
number: order.number,
// A sale the till rang up for nobody in particular has no account.
account: accounts.get(order.customerId)?.company ?? (order.customerId || "Walk-in"),
country: order.country,
region: regionOf(order.country),
status: order.status,
total: dollars(order.totalCents),
placedAt: order.placedAt,
}))
}
/** The bell's contents: the newest notifications, unread first in the panel. */
export function shellNotifications() {
return db.notifications
.all()
.sort((a, b) => b.at.getTime() - a.at.getTime())
.slice(0, 6)
.map(({ id, title, description, at, read, href }) => ({ id, title, description, at, read, href }))
}
function ownerRow(): Member {
return db.members.all().find((member) => member.role === "owner") ?? db.members.all()[0]
}
/** The person looking at the page: whoever owns this workspace. */
export function currentUser() {
const owner = ownerRow()
return { name: owner.name, email: owner.email, initials: getInitials(owner.name), avatarUrl: owner.avatarUrl }
}
const STAMP = new Intl.DateTimeFormat("en-US", {
month: "short",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
timeZone: "UTC",
})
/** The window the traffic covers, as a line under the title. */
export function lastUpdated(): string {
return `${WINDOW_HOURS} hours to ${STAMP.format(REFERENCE_DATE)} UTC`
}Its page
On its page the card sits among the rest of the dashboard and shares its range and its data with them.
From the Global analytics dashboard page