feat(frontend): wire KeyboardCheatsheet into Claims page via ? toggle

This commit is contained in:
Tyler
2026-06-20 12:23:06 -06:00
parent d44aa1de3f
commit d03293ed1d
2 changed files with 101 additions and 3 deletions
+94
View File
@@ -326,4 +326,98 @@ describe("Claims page drawer wiring", () => {
await settle(() => !window.location.href.includes("?claim="));
expect(window.location.href).not.toContain("?claim=");
});
it("test_question_mark_toggles_cheatsheet", async () => {
// The cheatsheet keystroke is wired through `useDrawerKeyboard`
// (which lives inside ClaimDrawer and only enables when
// `claimId !== null`). Deep-link with `?claim=CLM-1` so the
// drawer mounts and the keyboard listener is active.
setLocation("http://localhost/claims?claim=CLM-1");
const { unmount } = renderClaims();
// Drawer must be open before we test the toggle.
await settle(
() => document.body.querySelector('[data-testid="claim-drawer"]') !== null
);
expect(
document.body.querySelector('[data-testid="claim-drawer"]')
).not.toBeNull();
// Cheatsheet starts closed.
expect(
document.body.querySelector('[data-testid="keyboard-cheatsheet"]')
).toBeNull();
// First `?` press: useDrawerKeyboard's handler flips `helpOpen`
// true on the page; the cheatsheet portals into document.body.
await act(async () => {
window.dispatchEvent(
new KeyboardEvent("keydown", { key: "?", bubbles: true })
);
});
await settle(
() =>
document.body.querySelector('[data-testid="keyboard-cheatsheet"]') !==
null
);
expect(
document.body.querySelector('[data-testid="keyboard-cheatsheet"]')
).not.toBeNull();
// Second `?` press: same handler flips `helpOpen` back to false;
// the cheatsheet unmounts. (The cheatsheet's own window-level
// listener explicitly returns early on `?` — it never pre-empts
// the parent's toggle, by design.)
await act(async () => {
window.dispatchEvent(
new KeyboardEvent("keydown", { key: "?", bubbles: true })
);
});
await settle(
() =>
document.body.querySelector('[data-testid="keyboard-cheatsheet"]') ===
null
);
expect(
document.body.querySelector('[data-testid="keyboard-cheatsheet"]')
).toBeNull();
// Unmount so the next test (which asserts the drawer is absent)
// doesn't see this test's still-open drawer leaking into
// document.body.
unmount();
});
it("test_question_mark_does_nothing_when_drawer_closed", async () => {
// The `?` keystroke is owned by `useDrawerKeyboard`, which only
// attaches its `window` listener when `claimId !== null`. With no
// `?claim=` in the URL, the drawer is closed and `?` is a no-op
// — the cheatsheet must not appear.
setLocation("http://localhost/claims");
renderClaims();
// Wait for the table to populate (so the page is fully mounted).
await settle(
() => document.body.textContent?.includes("CLM-1") ?? false
);
expect(
document.body.querySelector('[data-testid="claim-drawer"]')
).toBeNull();
await act(async () => {
window.dispatchEvent(
new KeyboardEvent("keydown", { key: "?", bubbles: true })
);
});
// No cheatsheet should be present — and not just "not yet":
// flush a tick to make sure a delayed listener couldn't have
// snuck it in.
await act(async () => {
await new Promise((r) => setTimeout(r, 0));
});
expect(
document.body.querySelector('[data-testid="keyboard-cheatsheet"]')
).toBeNull();
});
});
+7 -3
View File
@@ -19,6 +19,7 @@ import {
import { StatusBadge } from "@/components/StatusBadge";
import { NewClaimDialog } from "@/components/NewClaimDialog";
import { ClaimDrawer } from "@/components/ClaimDrawer";
import { KeyboardCheatsheet } from "@/components/KeyboardCheatsheet";
import { Skeleton } from "@/components/ui/skeleton";
import { EmptyState } from "@/components/ui/empty-state";
import { ErrorState } from "@/components/ui/error-state";
@@ -48,6 +49,7 @@ export function Claims() {
const [npi, setNpi] = useState<string>(ALL);
const [query, setQuery] = useState("");
const [page, setPage] = useState(1);
const [helpOpen, setHelpOpen] = useState(false);
const searchRef = useRef<HTMLInputElement>(null);
// SP4 drawer wiring: the URL is the source of truth for "which claim is
@@ -114,9 +116,11 @@ export function Claims() {
claims={items.map((c) => ({ id: c.id }))}
onClose={close}
onNavigate={setClaimId}
onToggleHelp={() => {
// T22 wires the KeyboardCheatsheet overlay; no-op for now.
}}
onToggleHelp={() => setHelpOpen((v) => !v)}
/>
<KeyboardCheatsheet
open={helpOpen}
onClose={() => setHelpOpen(false)}
/>
<div
data-testid="claims-page-body"