/** The cross-tab desk — one measure by two dimensions, totals at both edges. */ import { useMemo, useState } from "react"; import { Text } from "@lotics/ui/text"; import { colors } from "@lotics/ui/colors"; import { Avatar } from "@lotics/ui/avatar"; import { Status } from "@lotics/ui/status"; import { Box } from "@lotics/ui/box"; import { Card, CardFooter, CardHeader, CardHeaderTitle } from "@lotics/ui/card"; import { Divider } from "@lotics/ui/divider"; import { Drawer, DrawerScrollArea } from "@lotics/ui/drawer"; import { RegionState } from "@lotics/ui/region_state"; import { MetricStrip } from "@lotics/ui/metric_strip"; import { Chip } from "@lotics/ui/chip"; import { Matrix, MatrixGrid, MatrixHeader, MatrixLegend, MatrixTotals } from "@lotics/ui/matrix"; import { type MatrixCellRef } from "@lotics/ui/matrix_totals"; import { RowFocusEntry } from "@lotics/ui/row_focus_entry"; import { PressableRow } from "@lotics/ui/pressable_row"; import { ScrollArea } from "@lotics/ui/scroll_area"; import { Stack } from "@lotics/ui/stack"; // ───────────────────────────────────────────────────────────────────────────── // Template, Pivot — one dimension crossed against another, then drill. // The Matrix is the hero: warehouse × category, the number IN each cell and a // heat wash behind it so the concentration reads at a glance, row/column/grand // totals down the edges. Pressing a cell is a door — the register below filters // to exactly that intersection; a row there opens the item drawer. The pattern // for "how does X distribute across Y, and what's behind each bucket?". // ───────────────────────────────────────────────────────────────────────────── const WAREHOUSES = [ { key: "chi", label: "Chicago" }, { key: "dal", label: "Dallas" }, { key: "nwk", label: "Newark" }, { key: "reno", label: "Reno" }, { key: "atl", label: "Atlanta" }, ] as const; const CATEGORIES = [ { key: "apparel", label: "Apparel" }, { key: "home", label: "Home" }, { key: "elec", label: "Electronics" }, { key: "outdoor", label: "Outdoor" }, ] as const; type WarehouseKey = (typeof WAREHOUSES)[number]["key"]; type CategoryKey = (typeof CATEGORIES)[number]["key"]; interface Sku { code: string; name: string; warehouse: WarehouseKey; category: CategoryKey; units: number; status: "in_stock" | "low" | "backorder"; } // Deterministic mock catalogue — integer hashing, stable across reloads. function hash(i: number, salt: number): number { let x = (i + 1) * 2654435761 + salt * 40503; x = ((x >>> 16) ^ x) * 0x45d9f3b; x = ((x >>> 16) ^ x) * 0x45d9f3b; return (x >>> 16) % 1000; } const NAMES = ["Cotton tee", "Wool throw", "USB hub", "Trail flask", "Rain shell", "Desk lamp", "Sport sock", "Cast pan", "Earbuds", "Tent peg", "Linen shirt", "Throw pillow"]; const SKUS: Sku[] = (() => { const out: Sku[] = []; // A deliberate concentration in Newark, Electronics so a hot cell has a story. for (let i = 0; i < 64; i++) { const wRoll = hash(i, 1) % 100; const warehouse: WarehouseKey = wRoll < 18 ? "chi" : wRoll < 36 ? "dal" : wRoll < 66 ? "nwk" : wRoll < 84 ? "reno" : "atl"; const cRoll = hash(i, 2) % 100; const category: CategoryKey = warehouse === "nwk" && cRoll < 55 ? "elec" : cRoll < 30 ? "apparel" : cRoll < 55 ? "home" : cRoll < 78 ? "elec" : "outdoor"; const units = hash(i, 3) % 40; out.push({ code: `SKU-${String(1000 + i)}`, name: NAMES[hash(i, 4) % NAMES.length], warehouse, category, units, status: units === 0 ? "backorder" : units < 6 ? "low" : "in_stock", }); } return out; })(); const whOf = (k: WarehouseKey) => WAREHOUSES.find((w) => w.key === k)!; const catOf = (k: CategoryKey) => CATEGORIES.find((c) => c.key === k)!; const STATUS: Record = { in_stock: { label: "In stock", color: "emerald" }, low: { label: "Low", color: "amber" }, backorder: { label: "Backorder", color: "red" }, }; const count = (n: number) => n.toLocaleString("en-US"); function KVRow({ label, children }: { label: string; children: React.ReactNode }) { return ( {label} {children} ); } export function TplPivot() { const [cell, setCell] = useState(null); const [openIdx, setOpenIdx] = useState(null); // Cell value = how many SKUs sit at that warehouse × category. const counts = useMemo(() => { const m = new Map(); for (const s of SKUS) m.set(`${s.warehouse}|${s.category}`, (m.get(`${s.warehouse}|${s.category}`) ?? 0) + 1); return m; }, []); const value = (w: string, c: string) => counts.get(`${w}|${c}`) ?? 0; // The drill register follows the pressed cell; no cell = the whole catalogue. const items = useMemo( () => (cell ? SKUS.filter((s) => s.warehouse === cell.row && s.category === cell.col) : SKUS), [cell], ); const open = openIdx !== null ? items[openIdx] : null; const totalUnits = SKUS.reduce((s, x) => s + x.units, 0); const lowOrOut = SKUS.filter((s) => s.status !== "in_stock").length; return ( Stock distribution Where each category sits across the network — press a cell to list what's behind it 0 ? "warning" : "default", caption: "need attention" }, { label: "Warehouses", value: WAREHOUSES.length, format: "number" }, ]} /> SKUs by warehouse × category ({ key: w.key, label: w.label, leading: , }))} cols={CATEGORIES.map((c) => ({ key: c.key, label: c.label }))} value={value} selected={cell} onSelectCell={(c) => { setCell(c); setOpenIdx(null); }} heatColor="indigo" formatValue={count} > Items {cell ? ( { setCell(null); setOpenIdx(null); }} dismissTooltip="Clear cell"> {`${whOf(cell.row as WarehouseKey).label}, ${catOf(cell.col as CategoryKey).label}`} ) : null} Code Item Units Status {items.length === 0 ? ( ) : ( items.slice(0, 10).map((s, i) => ( {i > 0 ? : null} setOpenIdx(i)} selected={openIdx === i} style={{ minHeight: 44 }}> setOpenIdx(i)} accessibilityLabel={`Open ${s.code}`} /> {s.code} {s.name} {count(s.units)} )) )} {items.length > 10 ? `Showing 10 of ${count(items.length)}` : `${count(items.length)} item${items.length === 1 ? "" : "s"}`} {/* The overlay is RENDERED and its `open` toggles — a `{cond ? : null}` is the one shape an overlay may not take. Only the BODY is conditional. */} !o && setOpenIdx(null)} title={open?.code} width={420} onPrev={openIdx !== null && openIdx > 0 ? () => setOpenIdx(openIdx - 1) : undefined} onNext={openIdx !== null && openIdx < Math.min(items.length, 10) - 1 ? () => setOpenIdx(openIdx + 1) : undefined} position={openIdx !== null ? { index: openIdx + 1, total: Math.min(items.length, 10) } : undefined} > {open !== null ? ( {open.name} {whOf(open.warehouse).label} {catOf(open.category).label} {count(open.units)} ) : null} ); }