feat(sp7): wire LineReconciliationTab into ClaimDrawer

This commit is contained in:
Tyler
2026-06-20 19:51:04 -06:00
parent 2569ff99a0
commit 0b8f253186
4 changed files with 192 additions and 11 deletions
+86 -11
View File
@@ -1,8 +1,9 @@
import { useMemo } from "react";
import { useMemo, useState } from "react";
import { Dialog, DialogContent } from "@/components/ui/dialog";
import { ApiError } from "@/lib/api";
import { useClaimDetail } from "@/hooks/useClaimDetail";
import { useDrawerKeyboard } from "@/hooks/useDrawerKeyboard";
import { useLineReconciliation } from "@/hooks/useLineReconciliation";
import { ClaimDrawerHeader } from "./ClaimDrawerHeader";
import { ValidationPanel } from "./ValidationPanel";
import { ServiceLinesTable } from "./ServiceLinesTable";
@@ -11,6 +12,7 @@ import { PartiesGrid } from "./PartiesGrid";
import { RawSegmentsPanel } from "./RawSegmentsPanel";
import { MatchedRemitCard } from "./MatchedRemitCard";
import { StateHistoryTimeline } from "./StateHistoryTimeline";
import { LineReconciliationTab } from "./LineReconciliationTab";
import { ClaimDrawerSkeleton } from "./ClaimDrawerSkeleton";
import { ClaimDrawerError } from "./ClaimDrawerError";
@@ -71,6 +73,12 @@ export function ClaimDrawer({
onToggleHelp,
}: ClaimDrawerProps) {
const { data, isLoading, isError, error, refetch } = useClaimDetail(claimId);
// SP7: tab state. The Line Reconciliation tab lazy-fetches the
// per-line projection when first activated.
const [activeTab, setActiveTab] = useState<"details" | "line-reconciliation">("details");
const lr = useLineReconciliation(
activeTab === "line-reconciliation" ? claimId : null
);
// j/k navigation: derive next/prev IDs based on the current claim's
// index in the parent list. Wrap around at both ends. If the current
@@ -157,17 +165,84 @@ export function ClaimDrawer({
data-testid="claim-drawer-content"
>
<ClaimDrawerHeader claim={data} onClose={onClose} />
<div className="flex flex-col divide-y divide-[color:var(--m-border-heavy)]/15">
<ValidationPanel validation={data.validation} />
<ServiceLinesTable serviceLines={data.serviceLines} />
<DiagnosesList diagnoses={data.diagnoses} />
<PartiesGrid parties={data.parties} />
{data.matchedRemittance ? (
<MatchedRemitCard matchedRemittance={data.matchedRemittance} />
) : null}
<RawSegmentsPanel rawSegments={data.rawSegments} />
<StateHistoryTimeline history={data.stateHistory} />
<div
className="flex gap-2 px-6 pt-4 border-b"
style={{ borderColor: "var(--tt-bg)" }}
data-testid="claim-drawer-tabs"
>
<button
type="button"
onClick={() => setActiveTab("details")}
className="font-mono text-xs uppercase tracking-wider px-3 py-2"
style={{
color:
activeTab === "details"
? "var(--tt-ink, currentColor)"
: "var(--tt-ink-dim, rgba(255,255,255,0.5))",
borderBottom:
activeTab === "details"
? "2px solid var(--tt-amber)"
: "2px solid transparent",
}}
data-testid="tab-button-details"
data-active={activeTab === "details" ? "true" : "false"}
>
Details
</button>
<button
type="button"
onClick={() => setActiveTab("line-reconciliation")}
className="font-mono text-xs uppercase tracking-wider px-3 py-2"
style={{
color:
activeTab === "line-reconciliation"
? "var(--tt-ink, currentColor)"
: "var(--tt-ink-dim, rgba(255,255,255,0.5))",
borderBottom:
activeTab === "line-reconciliation"
? "2px solid var(--tt-amber)"
: "2px solid transparent",
}}
data-testid="tab-button-line-reconciliation"
data-active={activeTab === "line-reconciliation" ? "true" : "false"}
>
Line Reconciliation
</button>
</div>
{activeTab === "line-reconciliation" ? (
lr.loading ? (
<p
className="px-6 py-4 text-sm text-[color:var(--m-ink-tertiary)]"
data-testid="line-reconciliation-loading"
>
Loading line reconciliation
</p>
) : lr.error ? (
<p
className="px-6 py-4 text-sm text-[color:var(--m-ink-tertiary)]"
data-testid="line-reconciliation-error"
>
Failed to load line reconciliation.
</p>
) : lr.data ? (
<LineReconciliationTab data={lr.data} />
) : null
) : (
<div className="flex flex-col divide-y divide-[color:var(--m-border-heavy)]/15">
<ValidationPanel validation={data.validation} />
<ServiceLinesTable
serviceLines={data.serviceLines}
lineReconciliation={data.lineReconciliation}
/>
<DiagnosesList diagnoses={data.diagnoses} />
<PartiesGrid parties={data.parties} />
{data.matchedRemittance ? (
<MatchedRemitCard matchedRemittance={data.matchedRemittance} />
) : null}
<RawSegmentsPanel rawSegments={data.rawSegments} />
<StateHistoryTimeline history={data.stateHistory} />
</div>
)}
</div>
) : null}
</DialogContent>
+1
View File
@@ -11,3 +11,4 @@ export { MatchedRemitCard } from "./MatchedRemitCard";
export { StateHistoryTimeline } from "./StateHistoryTimeline";
export { ClaimDrawerSkeleton } from "./ClaimDrawerSkeleton";
export { ClaimDrawerError } from "./ClaimDrawerError";
export { LineReconciliationTab } from "./LineReconciliationTab";