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.
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import type { Activity } from "@/types";
|
||||
|
||||
/**
|
||||
* The minimum an activity event must carry to be routable. Centralizing
|
||||
* this here means callers can pass an `Activity` (full feed row) or a
|
||||
* narrower shape (e.g. a future "activity event" peek payload) — both
|
||||
* satisfy the kind + entity-id fields the helper inspects.
|
||||
*
|
||||
* - `claimId` / `remittanceId` come from the backend `ActivityEvent`
|
||||
* ORM columns (SP21 Task 2.5). `claimId` is set on `claim_*` events;
|
||||
* `remittanceId` is set on `remit_received`.
|
||||
* - `npi` is the existing `Activity.npi` field. For `provider_added`
|
||||
* events the provider NPI IS the entity id (the URL target).
|
||||
*/
|
||||
export type RoutableEvent = Pick<
|
||||
Activity,
|
||||
"kind" | "claimId" | "remittanceId" | "npi"
|
||||
>;
|
||||
|
||||
/**
|
||||
* Maps an activity event to the URL the operator should land on when
|
||||
* clicking the event. Used by:
|
||||
*
|
||||
* - Dashboard "Recent activity" card (this PR, Task 2.5).
|
||||
* - `/activity` log page (Task 2.5 wired here; full integration is
|
||||
* a later task).
|
||||
*
|
||||
* Returns `null` for kinds that don't have a drill target yet, or
|
||||
* when the entity id field is missing on the event. Callers are
|
||||
* expected to surface a "coming soon" toast in that case so the click
|
||||
* still gives feedback.
|
||||
*/
|
||||
export function eventKindToUrl(event: RoutableEvent): string | null {
|
||||
switch (event.kind) {
|
||||
case "claim_submitted":
|
||||
case "claim_paid":
|
||||
case "claim_denied":
|
||||
case "claim_accepted": {
|
||||
if (!event.claimId) return null;
|
||||
return `/claims?claim=${encodeURIComponent(event.claimId)}`;
|
||||
}
|
||||
case "remit_received":
|
||||
// Phase 4 — the `RemitDrawer` isn't built yet; the helper stays
|
||||
// honest and returns null so the caller's "coming soon" toast
|
||||
// fires. When the drawer lands, the route becomes
|
||||
// `/remittances?remit=${encodeURIComponent(event.remittanceId ?? "")}`.
|
||||
return null;
|
||||
case "provider_added": {
|
||||
if (!event.npi) return null;
|
||||
return `/providers?provider=${encodeURIComponent(event.npi)}`;
|
||||
}
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user