mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-04-11 18:28:15 +00:00
Dashboard:
- Split into components (kpi-cards, agent-table, missed-queue)
- Add collapsible AI panel on right (same pattern as Call Desk)
- Add tabs: Agent Performance | Missed Queue | Campaigns
- Date range filter in header
Integrations page:
- Ozonetel (connected), WhatsApp, Facebook, Google, Instagram, Website, Email
- Status badges, config details, webhook URL with copy button
Settings page:
- Employee table from workspaceMembers GraphQL query
- Name, email, roles, status, reset password action
Fixes:
- Fix CALLS_QUERY: callerNumber needs { primaryPhoneNumber }, recordingUrl → recording { primaryLinkUrl }
- Remove duplicate AI Assistant header
- Remove Follow-ups from CC agent sidebar (already in worklist tabs)
- Remove global search from TopBar (decorative, unused)
- Slim down TopBar height
- Fix search/table gap in worklist
- Add brand border to active nav item
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
168 lines
5.8 KiB
TypeScript
168 lines
5.8 KiB
TypeScript
// Transform platform GraphQL responses → frontend entity types
|
|
// Platform remaps some field names during sync
|
|
|
|
import type { Lead, Campaign, Ad, FollowUp, LeadActivity, Call, Patient } from '@/types/entities';
|
|
|
|
type PlatformNode = Record<string, any>;
|
|
|
|
function extractEdges(data: any, entityName: string): PlatformNode[] {
|
|
return data?.[entityName]?.edges?.map((e: any) => e.node) ?? [];
|
|
}
|
|
|
|
export function transformLeads(data: any): Lead[] {
|
|
return extractEdges(data, 'leads').map((n) => ({
|
|
id: n.id,
|
|
createdAt: n.createdAt,
|
|
updatedAt: n.updatedAt,
|
|
contactName: n.contactName ?? { firstName: '', lastName: '' },
|
|
contactPhone: n.contactPhone?.primaryPhoneNumber
|
|
? [{ number: n.contactPhone.primaryPhoneNumber, callingCode: n.contactPhone.primaryPhoneCallingCode ?? '+91' }]
|
|
: [],
|
|
contactEmail: n.contactEmail?.primaryEmail
|
|
? [{ address: n.contactEmail.primaryEmail }]
|
|
: [],
|
|
leadSource: n.source,
|
|
leadStatus: n.status,
|
|
priority: n.priority ?? 'NORMAL',
|
|
interestedService: n.interestedService,
|
|
assignedAgent: n.assignedAgent,
|
|
utmSource: n.utmSource,
|
|
utmMedium: n.utmMedium,
|
|
utmCampaign: n.utmCampaign,
|
|
utmContent: n.utmContent,
|
|
utmTerm: n.utmTerm,
|
|
landingPageUrl: n.landingPage,
|
|
referrerUrl: n.referrerUrl,
|
|
leadScore: n.leadScore,
|
|
spamScore: n.spamScore ?? 0,
|
|
isSpam: n.isSpam ?? false,
|
|
isDuplicate: n.isDuplicate ?? false,
|
|
duplicateOfLeadId: n.duplicateOfLeadId,
|
|
firstContactedAt: n.firstContacted,
|
|
lastContactedAt: n.lastContacted,
|
|
contactAttempts: n.contactAttempts ?? 0,
|
|
convertedAt: n.convertedAt,
|
|
patientId: n.patientId,
|
|
campaignId: n.campaignId,
|
|
adId: null,
|
|
aiSummary: n.aiSummary,
|
|
aiSuggestedAction: n.aiSuggestedAction,
|
|
}));
|
|
}
|
|
|
|
export function transformCampaigns(data: any): Campaign[] {
|
|
return extractEdges(data, 'campaigns').map((n) => ({
|
|
id: n.id,
|
|
createdAt: n.createdAt,
|
|
updatedAt: n.updatedAt,
|
|
campaignName: n.campaignName ?? n.name,
|
|
campaignType: n.typeCustom,
|
|
campaignStatus: n.status,
|
|
platform: n.platform,
|
|
startDate: n.startDate,
|
|
endDate: n.endDate,
|
|
budget: n.budget ? { amountMicros: n.budget.amountMicros, currencyCode: n.budget.currencyCode } : null,
|
|
amountSpent: n.amountSpent ? { amountMicros: n.amountSpent.amountMicros, currencyCode: n.amountSpent.currencyCode } : null,
|
|
impressionCount: n.impressions ?? 0,
|
|
clickCount: n.clicks ?? 0,
|
|
targetCount: n.targetCount ?? 0,
|
|
contactedCount: n.contacted ?? 0,
|
|
convertedCount: n.converted ?? 0,
|
|
leadCount: n.leadsGenerated ?? 0,
|
|
externalCampaignId: n.externalCampaignId,
|
|
platformUrl: n.platformUrl?.primaryLinkUrl ?? null,
|
|
}));
|
|
}
|
|
|
|
export function transformAds(data: any): Ad[] {
|
|
return extractEdges(data, 'ads').map((n) => ({
|
|
id: n.id,
|
|
createdAt: n.createdAt,
|
|
updatedAt: n.updatedAt,
|
|
adName: n.adName ?? n.name,
|
|
externalAdId: n.externalAdId,
|
|
adStatus: n.status,
|
|
adFormat: n.adFormat,
|
|
headline: n.headline,
|
|
adDescription: n.adDescription,
|
|
destinationUrl: n.destinationUrl,
|
|
previewUrl: n.previewUrl,
|
|
impressions: n.impressions ?? 0,
|
|
clicks: n.clicks ?? 0,
|
|
conversions: n.conversions ?? 0,
|
|
spend: n.spend ? { amountMicros: n.spend.amountMicros, currencyCode: n.spend.currencyCode } : null,
|
|
campaignId: n.campaignId,
|
|
}));
|
|
}
|
|
|
|
export function transformFollowUps(data: any): FollowUp[] {
|
|
return extractEdges(data, 'followUps').map((n) => ({
|
|
id: n.id,
|
|
createdAt: n.createdAt,
|
|
followUpType: n.typeCustom,
|
|
followUpStatus: n.status,
|
|
scheduledAt: n.scheduledAt,
|
|
completedAt: n.completedAt,
|
|
priority: n.priority ?? 'NORMAL',
|
|
assignedAgent: n.assignedAgent,
|
|
patientId: n.patientId,
|
|
callId: n.callId,
|
|
patientName: undefined,
|
|
patientPhone: undefined,
|
|
description: n.name,
|
|
}));
|
|
}
|
|
|
|
export function transformLeadActivities(data: any): LeadActivity[] {
|
|
return extractEdges(data, 'leadActivities').map((n) => ({
|
|
id: n.id,
|
|
createdAt: n.createdAt,
|
|
activityType: n.activityType,
|
|
summary: n.summary,
|
|
occurredAt: n.occurredAt,
|
|
performedBy: n.performedBy,
|
|
previousValue: n.previousValue,
|
|
newValue: n.newValue,
|
|
channel: n.channel,
|
|
durationSeconds: n.durationSeconds,
|
|
outcome: n.outcome,
|
|
activityNotes: null,
|
|
leadId: n.leadId,
|
|
}));
|
|
}
|
|
|
|
export function transformCalls(data: any): Call[] {
|
|
return extractEdges(data, 'calls').map((n) => ({
|
|
id: n.id,
|
|
createdAt: n.createdAt,
|
|
callDirection: n.direction,
|
|
callStatus: n.callStatus,
|
|
callerNumber: n.callerNumber?.primaryPhoneNumber
|
|
? [{ number: n.callerNumber.primaryPhoneNumber, callingCode: '+91' }]
|
|
: [],
|
|
agentName: n.agentName,
|
|
startedAt: n.startedAt,
|
|
endedAt: n.endedAt,
|
|
durationSeconds: n.durationSec ?? 0,
|
|
recordingUrl: n.recording?.primaryLinkUrl || null,
|
|
disposition: n.disposition,
|
|
callNotes: null,
|
|
patientId: n.patientId,
|
|
appointmentId: n.appointmentId,
|
|
leadId: n.leadId,
|
|
}));
|
|
}
|
|
|
|
export function transformPatients(data: any): Patient[] {
|
|
return extractEdges(data, 'patients').map((n) => ({
|
|
id: n.id,
|
|
createdAt: n.createdAt,
|
|
fullName: n.fullName ?? null,
|
|
phones: n.phones ?? null,
|
|
emails: n.emails ?? null,
|
|
dateOfBirth: n.dateOfBirth ?? null,
|
|
gender: n.gender ?? null,
|
|
patientType: n.patientType ?? null,
|
|
}));
|
|
}
|