feat(web): read-only campaigns API + SSE + frontend
API: /api/v1/campaigns (paginated list), /api/v1/campaigns/{uuid}
(soft-merge chain follow), /api/v1/campaigns/{uuid}/identities
(member identities), and /api/v1/campaigns/events (SSE under
campaign.> + JWT-via-?token=, snapshot-on-connect). Mirror of the
identity router; same auth, same shape, same OpenAPI tags pattern.
Frontend: CampaignDetail.tsx page (same visual vocabulary as
IdentityDetail), useCampaignStream hook (mirror of
useIdentityStream), /campaigns/:id route, IdentityDetail's
CAMPAIGN badge becomes clickable and navigates to the campaign.
useIdentityStream now listens for identity.campaign.assigned so
the badge appears live without a manual refresh.
This commit is contained in:
@@ -25,7 +25,8 @@ export type IdentityStreamEventName =
|
||||
| 'formed'
|
||||
| 'observation.linked'
|
||||
| 'merged'
|
||||
| 'unmerged';
|
||||
| 'unmerged'
|
||||
| 'campaign.assigned';
|
||||
|
||||
export interface IdentityStreamEvent {
|
||||
name: IdentityStreamEventName | string;
|
||||
@@ -47,6 +48,7 @@ const NAMED_EVENTS: IdentityStreamEventName[] = [
|
||||
'observation.linked',
|
||||
'merged',
|
||||
'unmerged',
|
||||
'campaign.assigned',
|
||||
];
|
||||
|
||||
export function useIdentityStream({
|
||||
|
||||
Reference in New Issue
Block a user