From fc0a9b31893410ce12a39e5d117d684c6e20045c Mon Sep 17 00:00:00 2001 From: Apple Date: Sat, 29 Nov 2025 17:14:59 -0800 Subject: [PATCH] fix(web): transform snake_case API response to camelCase for governance/incidents --- apps/web/src/lib/api/governance.ts | 40 ++++++++++++++++++++++-- apps/web/src/lib/api/incidents.ts | 50 +++++++++++++++++++++++++++--- 2 files changed, 83 insertions(+), 7 deletions(-) diff --git a/apps/web/src/lib/api/governance.ts b/apps/web/src/lib/api/governance.ts index 5d549bd9..264815d8 100644 --- a/apps/web/src/lib/api/governance.ts +++ b/apps/web/src/lib/api/governance.ts @@ -132,11 +132,47 @@ export async function checkPermission( // ============================================================================ export async function getCityAgents(): Promise { - return fetchApi('/api/v1/governance/agents/city'); + const raw = await fetchApi>('/api/v1/governance/agents/city'); + + return raw.map((agent) => ({ + id: agent.id, + displayName: agent.display_name, + avatarUrl: agent.avatar_url, + govLevel: (agent.gov_level || 'guest') as AgentGovLevel, + status: (agent.status || 'active') as 'active' | 'suspended' | 'revoked', + })); } export async function getDistrictLeadAgents(): Promise { - return fetchApi('/api/v1/governance/agents/district-leads'); + try { + const raw = await fetchApi>('/api/v1/governance/agents/district-leads'); + + return raw.map((agent) => ({ + id: agent.id, + displayName: agent.display_name, + avatarUrl: agent.avatar_url, + govLevel: (agent.gov_level || 'district_lead') as AgentGovLevel, + status: (agent.status || 'active') as 'active' | 'suspended' | 'revoked', + homeMicrodaoId: agent.home_microdao_id, + homeMicrodaoName: agent.home_microdao_name, + })); + } catch { + return []; + } } export async function getAgentsByLevel(level: AgentGovLevel): Promise { diff --git a/apps/web/src/lib/api/incidents.ts b/apps/web/src/lib/api/incidents.ts index bcfb39ea..bd5a4726 100644 --- a/apps/web/src/lib/api/incidents.ts +++ b/apps/web/src/lib/api/incidents.ts @@ -64,22 +64,62 @@ export interface IncidentsFilter { offset?: number; } +interface RawIncident { + id: string; + title: string; + description?: string; + status: string; + priority: string; + scope_type?: string; + scope_id?: string; + escalation_level?: string; + reporter_id?: string; + reporter_name?: string; + assigned_to?: string; + assignee_name?: string; + created_at?: string; + updated_at?: string; +} + +function transformIncident(raw: RawIncident): Incident { + return { + id: raw.id, + title: raw.title, + description: raw.description, + status: (raw.status || 'open') as IncidentStatus, + priority: (raw.priority || 'medium') as IncidentPriority, + escalationLevel: (raw.escalation_level || 'microdao') as EscalationLevel, + targetScopeType: (raw.scope_type || 'city') as TargetScopeType, + targetScopeId: raw.scope_id, + createdByDaisId: raw.reporter_id, + createdByName: raw.reporter_name, + assignedToDaisId: raw.assigned_to, + assignedToName: raw.assignee_name, + createdAt: raw.created_at, + updatedAt: raw.updated_at, + }; +} + export async function getIncidents(filter?: IncidentsFilter): Promise { const params = new URLSearchParams(); if (filter?.status) params.set('status', filter.status); if (filter?.priority) params.set('priority', filter.priority); - if (filter?.escalationLevel) params.set('escalationLevel', filter.escalationLevel); - if (filter?.targetScopeType) params.set('targetScopeType', filter.targetScopeType); - if (filter?.targetScopeId) params.set('targetScopeId', filter.targetScopeId); - if (filter?.assignedTo) params.set('assignedTo', filter.assignedTo); + if (filter?.escalationLevel) params.set('escalation_level', filter.escalationLevel); + if (filter?.targetScopeType) params.set('scope_type', filter.targetScopeType); + if (filter?.targetScopeId) params.set('scope_id', filter.targetScopeId); if (filter?.limit) params.set('limit', filter.limit.toString()); if (filter?.offset) params.set('offset', filter.offset.toString()); const queryString = params.toString(); const endpoint = queryString ? `/api/v1/incidents?${queryString}` : '/api/v1/incidents'; - return fetchApi(endpoint); + try { + const raw = await fetchApi(endpoint); + return raw.map(transformIncident); + } catch { + return []; + } } export async function getIncidentById(id: string): Promise {