import { useState } from "react"; import type { AgendaView, HandoffCard, SignalView, SummaryView } from "../../data"; import type { Matrix, MatrixItem } from "../../matrix"; import { Badge } from "../components/badge"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "../components/table"; import { tenths } from "../format"; import { Empty, Panel, Pending } from "../frame"; import { type Loaded, useLoaded } from "../lib/api"; import { cn } from "../lib/cn"; import { GoalsList, HandoffList, ItemCard, MovesList, ReasonTags } from "../parts"; export const LAYOUTS = [ { value: "matrix", label: "matrix" }, { value: "list", label: "list" }, { value: "briefing", label: "briefing" }, ] as const; export type Layout = (typeof LAYOUTS)[number]["value"]; export function isLayout(value: string | null): value is Layout { return LAYOUTS.some((l) => l.value === value); } const QUADRANTS = [ { id: "now", title: "Do now", note: "matters and cannot wait", lit: true }, { id: "plan", title: "Give it a slot", note: "matters, nothing forcing it", lit: false, }, { id: "noise", title: "Loud, not load-bearing", note: "pressing but serves nothing", lit: false, }, { id: "later", title: "Let it sit", note: "neither", lit: false }, ] as const; const FORTNIGHT_DAYS = 14; function goalsOf(matrix: Matrix): MatrixItem[] { return [...matrix.now, ...matrix.plan, ...matrix.noise, ...matrix.later].filter( (i) => i.kind === "goal" ); } function rankedOf(matrix: Matrix): { item: MatrixItem; quadrant: string }[] { return QUADRANTS.flatMap(({ id, title }) => (matrix[id] as MatrixItem[]).map((item) => ({ item, quadrant: title })) ); } function Quadrant({ title, note, lit, items, onSaved, compact, }: { title: string; note: string; lit: boolean; items: MatrixItem[]; onSaved: () => void; compact?: boolean; }) { return (

{title}

{note}
{items.length === 0 ? ( nothing here ) : ( items.map((item) => ( )) )}
); } function Fortnight() { const view = useLoaded(`/api/summary?days=${FORTNIGHT_DAYS}`); const s = view.state === "ready" ? view.data : null; return (
); } function Figure({ n, label }: { n: string; label: string }) { return (
{n}
{label}
); } function DueBadges() { const signal = useLoaded("/api/signal"); if (signal.state !== "ready") return ; const due = Object.entries(signal.data.due).filter(([, b]) => b.state === "due"); if (due.length === 0) return Nothing is due.; return (
{due.map(([name, badge]) => (
{name} {badge.detail}
))}
); } function Sidebar({ matrix, handoffs }: { matrix: Matrix; handoffs: HandoffCard[] }) { return ( ); } function MatrixLayout({ matrix, handoffs, moves, onSaved, }: { matrix: Matrix; handoffs: HandoffCard[]; moves: AgendaView["moves"]; onSaved: () => void; }) { return (
{moves.map((move, i) => (
{String(i + 1).padStart(2, "0")} {move.move} {move.because}
))}
urgent
not urgent
important
{QUADRANTS.slice(0, 2).map((q) => ( ))}
not important
{QUADRANTS.slice(2).map((q) => ( ))}
); } function ListLayout({ matrix, handoffs, moves, }: { matrix: Matrix; handoffs: HandoffCard[]; moves: AgendaView["moves"]; onSaved: () => void; }) { return (
{["Item", "Placed", "Why", "Next"].map((column) => ( {column} ))} {rankedOf(matrix).map(({ item, quadrant }) => ( {item.label} {quadrant} {item.detail} ))}
); } function BriefingLayout({ matrix, handoffs, moves, onSaved, }: { matrix: Matrix; handoffs: HandoffCard[]; moves: AgendaView["moves"]; onSaved: () => void; }) { return (
If you only do three things
Where you left off
The grid
{QUADRANTS.map((q) => ( ))}
); } function Heading({ agenda, matrix }: { agenda: AgendaView; matrix: Matrix }) { const written = agenda.generatedAt ? `agenda written ${agenda.ageHours ?? 0}h ago at session stop` : "no agenda written yet"; return (

{new Date().toLocaleDateString(undefined, { weekday: "long", day: "numeric", month: "long", })}

{written} ยท {matrix.now.length} items need you
{matrix.unranked > 0 && ( {matrix.unranked} project(s) with no purpose on record )}
); } export function Today({ layout }: { layout: Layout }) { const [nonce, setNonce] = useState(0); const matrix = useLoaded(`/api/matrix?v=${nonce}`); const agenda = useLoaded("/api/agenda"); const handoffs = useLoaded("/api/handoffs"); const reload = () => setNonce((n) => n + 1); const waiting: Loaded[] = [matrix, agenda, handoffs]; const notReady = waiting.find((v) => v.state !== "ready"); if (notReady || matrix.state !== "ready") return ; if (agenda.state !== "ready" || handoffs.state !== "ready") return null; const shared = { matrix: matrix.data, handoffs: handoffs.data, moves: agenda.data.moves, onSaved: reload, }; return (
{layout === "matrix" && } {layout === "list" && } {layout === "briefing" && }
); }