Files
cyclone/src/store/index.ts
T
Tyler 65d98cf674 feat(dashboard): Recent activity events route to entity by kind
SP21 Task 2.5 — the Dashboard's 'Recent activity' card now routes clicks
to the matching entity drawer / page by event kind:

  - claim_*       → /claims?claim=<id>  (drawer in Phase 5)
  - provider_added → /providers?provider=<npi>  (ProviderDrawer)
  - remit_received → toast 'coming in a later phase' (RemitDrawer in Phase 4)
  - anything else  → toast (manual_match, unknown kinds)

Implementation:
  - New src/lib/event-routing.ts with the eventKindToUrl() helper,
    plus a unit test covering all 6 + default branches.
  - src/components/ActivityFeed.tsx gains an optional onItemClick
    prop; when set, each row gets role='button', tabIndex=0, the
    drillable hover affordance (chevron + tint), and an Enter/Space
    keybinding. e.stopPropagation() is called before the handler so a
    parent row click can't double-fire (same fix as Task 2.4).
  - src/pages/Dashboard.tsx wires the handler on the 'Recent activity'
    card via eventKindToUrl + sonner toast for unhandled kinds.
  - Backend: CycloneStore.recent_activity() now exposes claimId and
    remittanceId on each row (read from ActivityEvent.claim_id /
    remittance_id) so the routing helper has the entity ids it needs.
  - The frontend Activity interface gains optional claimId /
    remittanceId fields; the in-memory sample data and the
    addClaim store action populate them so the dashboard works in
    both API-configured and sample-data modes.
2026-06-21 16:41:15 -06:00

72 lines
1.9 KiB
TypeScript

import { create } from "zustand";
import {
sampleActivity,
sampleClaims,
sampleProviders,
sampleRemittances,
} from "@/data/sampleData";
import type {
Activity,
Claim,
ParsedBatch,
Provider,
Remittance,
} from "@/types";
interface AppState {
// Legacy in-memory store used by the existing pages.
claims: Claim[];
providers: Provider[];
remittances: Remittance[];
activity: Activity[];
addClaim: (claim: Claim) => void;
addActivity: (entry: Activity) => void;
// Parsed-batch slice — populated by the Upload page when the user uploads
// a real EDI file through the FastAPI backend. Independent of the legacy
// store above so the existing pages keep working with sample data.
parsedBatches: ParsedBatch[];
activeBatchId: string | null;
addParsedBatch: (batch: ParsedBatch) => void;
setActiveBatchId: (id: string | null) => void;
}
export const useAppStore = create<AppState>((set) => ({
claims: sampleClaims,
providers: sampleProviders,
remittances: sampleRemittances,
activity: sampleActivity,
addClaim: (claim) =>
set((s) => ({
claims: [claim, ...s.claims],
activity: [
{
id: `ACT-${claim.id}`,
kind: "claim_submitted",
message: `Submitted ${claim.id} · ${claim.patientName}`,
timestamp: claim.submissionDate,
npi: claim.providerNpi,
amount: claim.billedAmount,
// SP21 Task 2.5: mirror the backend wire shape so the
// Dashboard routing helper finds the claim id.
claimId: claim.id,
remittanceId: null,
},
...s.activity,
],
})),
addActivity: (entry) => set((s) => ({ activity: [entry, ...s.activity] })),
parsedBatches: [],
activeBatchId: null,
addParsedBatch: (batch) =>
set((s) => ({
parsedBatches: [batch, ...s.parsedBatches],
activeBatchId: batch.id,
})),
setActiveBatchId: (id) => set({ activeBatchId: id }),
}));