diff --git a/src/components/drill/PeekModal.test.tsx b/src/components/drill/PeekModal.test.tsx new file mode 100644 index 0000000..ee38367 --- /dev/null +++ b/src/components/drill/PeekModal.test.tsx @@ -0,0 +1,52 @@ +// @vitest-environment happy-dom +(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; + +import { afterEach, describe, it, expect, vi } from "vitest"; +import { cleanup, render, screen, fireEvent } from "@testing-library/react"; +import { PeekModal } from "@/components/drill/PeekModal"; + +// happy-dom keeps `document.body` between tests; without cleanup, +// `screen.getByRole(...)` finds buttons from earlier renders. +afterEach(() => cleanup()); + +describe("PeekModal", () => { + it("renders title and body when open; close button fires onClose", () => { + const onClose = vi.fn(); + render( + +

1,247 claims

+
, + ); + expect(screen.getByText("Payer")).toBeTruthy(); + expect(screen.getByText("CO Medicaid")).toBeTruthy(); + expect(screen.getByText("1,247 claims")).toBeTruthy(); + fireEvent.click(screen.getByRole("button", { name: /close/i })); + expect(onClose).toHaveBeenCalledOnce(); + }); + + it("renders nothing when closed", () => { + const { container } = render( + {}} title="hidden"> +

should not appear

+
, + ); + // jest-dom's toBeEmptyDOMElement is not installed; assert via raw DOM. + expect(container.firstChild).toBeNull(); + }); + + it("esc key closes", () => { + const onClose = vi.fn(); + render( + +

x

+
, + ); + fireEvent.keyDown(document.body, { key: "Escape" }); + expect(onClose).toHaveBeenCalledOnce(); + }); +}); \ No newline at end of file diff --git a/src/components/drill/PeekModal.tsx b/src/components/drill/PeekModal.tsx new file mode 100644 index 0000000..7881e1c --- /dev/null +++ b/src/components/drill/PeekModal.tsx @@ -0,0 +1,35 @@ +import { Dialog, DialogContent } from "@/components/ui/dialog"; +import type { ReactNode } from "react"; + +interface Props { + open: boolean; + onClose: () => void; + eyebrow?: string; + title: string; + children: ReactNode; +} + +/** + * Centered peek modal — used for cross-reference drills (payer, + * validation rule, etc.). Smaller than the right-side Drawer + * (max-width: 480px); closes on Esc, backdrop click, and the X button. + * No keyboard j/k nav — single record. + */ +export function PeekModal({ open, onClose, eyebrow, title, children }: Props) { + return ( + { if (!o) onClose(); }}> + + {eyebrow ? ( +
+ {eyebrow} +
+ ) : null} +

{title}

+
{children}
+
+
+ ); +} \ No newline at end of file