feat(frontend): useReconciliation hook with react-query invalidation cascade

This commit is contained in:
Tyler
2026-06-19 23:58:00 -06:00
parent 23ac7f6fda
commit e8c251f9ca
4 changed files with 303 additions and 0 deletions
+55
View File
@@ -0,0 +1,55 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { api } from "@/lib/api";
import type { MatchResponse, UnmatchedClaim, UnmatchedResponse } from "@/types";
/**
* React Query bindings for the reconciliation surface. Exposes:
* - `unmatched`: polled query for the GET /api/reconciliation/unmatched
* bucket (refreshes every 30s so the page reflects backend auto-matches
* without a manual reload).
* - `match`: mutation that POSTs /api/reconciliation/match. On success it
* invalidates every cache that could be affected by a state change:
* the unmatched bucket, the claims list, the remittances list, and the
* activity feed.
* - `unmatch`: mutation that POSTs /api/reconciliation/unmatch, with the
* same invalidation cascade.
*/
export function useReconciliation() {
const qc = useQueryClient();
const unmatched = useQuery<UnmatchedResponse>({
queryKey: ["reconciliation", "unmatched"],
queryFn: () => api.listUnmatched(),
refetchInterval: 30_000,
});
const match = useMutation<
MatchResponse,
Error,
{ claimId: string; remitId: string }
>({
mutationFn: (args) => api.matchRemit(args.claimId, args.remitId),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["reconciliation"] });
qc.invalidateQueries({ queryKey: ["claims"] });
qc.invalidateQueries({ queryKey: ["remittances"] });
qc.invalidateQueries({ queryKey: ["activity"] });
},
});
const unmatch = useMutation<
{ claim: UnmatchedClaim },
Error,
{ claimId: string }
>({
mutationFn: (args) => api.unmatchClaim(args.claimId),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["reconciliation"] });
qc.invalidateQueries({ queryKey: ["claims"] });
qc.invalidateQueries({ queryKey: ["remittances"] });
qc.invalidateQueries({ queryKey: ["activity"] });
},
});
return { unmatched, match, unmatch };
}