feat(acks): row click opens AckDrawer

This commit is contained in:
Tyler
2026-06-21 17:28:22 -06:00
parent 33fa899217
commit 5053a1ea8e
2 changed files with 148 additions and 8 deletions
+22 -1
View File
@@ -12,6 +12,8 @@ import { Skeleton } from "@/components/ui/skeleton";
import { EmptyState } from "@/components/ui/empty-state";
import { ErrorState } from "@/components/ui/error-state";
import { KeyboardCheatsheet } from "@/components/KeyboardCheatsheet";
import { AckDrawer } from "@/components/AckDrawer";
import { useAckDrawerUrlState } from "@/hooks/useAckDrawerUrlState";
import { useAcks } from "@/hooks/useAcks";
import { useRowKeyboard } from "@/hooks/useRowKeyboard";
import { api } from "@/lib/api";
@@ -91,7 +93,14 @@ function DownloadButton({ id, sourceBatchId }: { id: number; sourceBatchId: stri
return (
<button
type="button"
onClick={onClick}
onClick={(e) => {
// The row's onClick drills into AckDrawer; this button is a
// nested control and we want the click to NOT bubble into the
// row's onClick handler (matches the precedent set by
// DrillableCell onClick in `src/components/drill/DrillableCell.tsx:39`).
e.stopPropagation();
onClick();
}}
disabled={busy}
className={cn(
"inline-flex items-center gap-1.5 rounded-sm border px-2 py-1 mono text-[10.5px] uppercase tracking-[0.14em] font-semibold transition-colors",
@@ -113,6 +122,10 @@ function DownloadButton({ id, sourceBatchId }: { id: number; sourceBatchId: stri
export function Acks() {
const { data, isLoading, isError, error, refetch } = useAcks({ limit: 100 });
const items = data?.items ?? [];
// SP21 Phase 5 Task 5.3: drill-down from an acks row into
// AckDrawer. The hook reads `?ack=` off `window.location.search`
// so deep links restore the open ack on reload.
const { ackId, open, close } = useAckDrawerUrlState();
const [selectedIndex, setSelectedIndex] = useState<number | null>(null);
const [helpOpen, setHelpOpen] = useState(false);
@@ -172,6 +185,12 @@ export function Acks() {
open={helpOpen}
onClose={() => setHelpOpen(false)}
/>
{/* SP21 Phase 5 Task 5.3: AckDrawer mount. Row click drills
into the matching ack; the drawer portals into document.body
(Radix Dialog), so the surrounding paper plane stays put
while the drawer is open. Deep links via /acks?ack=ID
restore the open ack on reload. */}
<AckDrawer ackId={ackId} onClose={close} />
<div className="space-y-0">
{/* =================================================================
HERO — DARK EDITORIAL HEADER
@@ -650,7 +669,9 @@ export function Acks() {
data-row-index={idx}
data-state={isSelected ? "selected" : undefined}
aria-selected={isSelected}
onClick={() => open(String(a.id))}
className={cn(
"cursor-pointer",
isSelected && [
"ring-1 ring-inset",
],