feat: wire frontend to platform data, migrate to Jotai + Vercel AI SDK

- Replace mock DataProvider with real GraphQL queries through sidecar
- Add queries.ts and transforms.ts for platform field name mapping
- Migrate SIP state from React Context to Jotai atoms (React 19 compat)
- Add singleton SIP manager to survive StrictMode remounts
- Remove hardcoded Olivia/Sienna accounts from nav menu
- Add password eye toggle, remember me checkbox, forgot password link
- Fix worklist hook to transform platform field names
- Add seed scripts for clinics, health packages, lab tests
- Update test harness for new doctor→clinic relation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-18 16:44:45 +05:30
parent e01a4d7747
commit 61901eb8fb
14 changed files with 1208 additions and 108 deletions

74
src/lib/queries.ts Normal file
View File

@@ -0,0 +1,74 @@
// GraphQL queries for platform entities
// Platform remaps some SDK field names — queries use platform names
export const LEADS_QUERY = `{ leads(first: 100, orderBy: [{ createdAt: DescNullsLast }]) { edges { node {
id name createdAt updatedAt
contactName { firstName lastName }
contactPhone { primaryPhoneNumber primaryPhoneCallingCode }
contactEmail { primaryEmail }
source status priority interestedService assignedAgent
utmSource utmMedium utmCampaign utmContent utmTerm landingPage referrerUrl
leadScore spamScore isSpam isDuplicate duplicateOfLeadId
firstContacted lastContacted contactAttempts convertedAt
patientId campaignId
aiSummary aiSuggestedAction
} } } }`;
export const CAMPAIGNS_QUERY = `{ campaigns(first: 50, orderBy: [{ createdAt: DescNullsLast }]) { edges { node {
id name createdAt updatedAt
campaignName typeCustom status platform
startDate endDate
budget { amountMicros currencyCode }
amountSpent { amountMicros currencyCode }
impressions clicks targetCount contacted converted leadsGenerated
externalCampaignId platformUrl
} } } }`;
export const ADS_QUERY = `{ ads(first: 100, orderBy: [{ createdAt: DescNullsLast }]) { edges { node {
id name createdAt updatedAt
adName externalAdId adStatus adFormat
headline adDescription destinationUrl previewUrl
impressions clicks conversions
spend { amountMicros currencyCode }
campaignId
} } } }`;
export const FOLLOW_UPS_QUERY = `{ followUps(first: 50, orderBy: [{ scheduledAt: DescNullsLast }]) { edges { node {
id name createdAt
typeCustom status scheduledAt completedAt
priority assignedAgent
patientId callId
} } } }`;
export const LEAD_ACTIVITIES_QUERY = `{ leadActivities(first: 200, orderBy: [{ occurredAt: DescNullsLast }]) { edges { node {
id name createdAt
activityType summary occurredAt performedBy
previousValue newValue
channel durationSeconds outcome
leadId
} } } }`;
export const CALLS_QUERY = `{ calls(first: 100, orderBy: [{ startedAt: DescNullsLast }]) { edges { node {
id name createdAt
direction callStatus callerNumber agentName
startedAt endedAt durationSec
recordingUrl disposition
patientId appointmentId leadId
} } } }`;
export const DOCTORS_QUERY = `{ doctors(first: 20) { edges { node {
id name fullName { firstName lastName }
department specialty qualifications yearsOfExperience
visitingHours
consultationFeeNew { amountMicros currencyCode }
consultationFeeFollowUp { amountMicros currencyCode }
active registrationNumber
clinic { id name clinicName }
} } } }`;
export const PATIENTS_QUERY = `{ patients(first: 50) { edges { node {
id name fullName { firstName lastName }
phones { primaryPhoneNumber }
emails { primaryEmail }
dateOfBirth gender patientType
} } } }`;