Files
helix-engage/src/providers/data-provider.tsx
saridsa2 61901eb8fb 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>
2026-03-18 16:44:45 +05:30

126 lines
4.0 KiB
TypeScript

import type { ReactNode } from 'react';
import { createContext, useCallback, useContext, useEffect, useState } from 'react';
import { apiClient } from '@/lib/api-client';
import {
LEADS_QUERY,
CAMPAIGNS_QUERY,
ADS_QUERY,
FOLLOW_UPS_QUERY,
LEAD_ACTIVITIES_QUERY,
CALLS_QUERY,
} from '@/lib/queries';
import {
transformLeads,
transformCampaigns,
transformAds,
transformFollowUps,
transformLeadActivities,
transformCalls,
} from '@/lib/transforms';
import type { Lead, Campaign, Ad, LeadActivity, FollowUp, WhatsAppTemplate, Agent, Call, LeadIngestionSource } from '@/types/entities';
type DataContextType = {
leads: Lead[];
campaigns: Campaign[];
ads: Ad[];
followUps: FollowUp[];
leadActivities: LeadActivity[];
templates: WhatsAppTemplate[];
agents: Agent[];
calls: Call[];
ingestionSources: LeadIngestionSource[];
loading: boolean;
error: string | null;
updateLead: (id: string, updates: Partial<Lead>) => void;
addCall: (call: Call) => void;
refresh: () => void;
};
const DataContext = createContext<DataContextType | undefined>(undefined);
export const useData = (): DataContextType => {
const context = useContext(DataContext);
if (context === undefined) {
throw new Error('useData must be used within a DataProvider');
}
return context;
};
interface DataProviderProps {
children: ReactNode;
}
export const DataProvider = ({ children }: DataProviderProps) => {
const [leads, setLeads] = useState<Lead[]>([]);
const [campaigns, setCampaigns] = useState<Campaign[]>([]);
const [ads, setAds] = useState<Ad[]>([]);
const [followUps, setFollowUps] = useState<FollowUp[]>([]);
const [leadActivities, setLeadActivities] = useState<LeadActivity[]>([]);
const [calls, setCalls] = useState<Call[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
// These don't have platform entities yet — empty for now
const [templates] = useState<WhatsAppTemplate[]>([]);
const [agents] = useState<Agent[]>([]);
const [ingestionSources] = useState<LeadIngestionSource[]>([]);
const fetchData = useCallback(async () => {
if (!apiClient.isAuthenticated()) {
setLoading(false);
return;
}
setLoading(true);
setError(null);
try {
const [leadsData, campaignsData, adsData, followUpsData, activitiesData, callsData] = await Promise.all([
apiClient.graphql<any>(LEADS_QUERY),
apiClient.graphql<any>(CAMPAIGNS_QUERY),
apiClient.graphql<any>(ADS_QUERY),
apiClient.graphql<any>(FOLLOW_UPS_QUERY),
apiClient.graphql<any>(LEAD_ACTIVITIES_QUERY),
apiClient.graphql<any>(CALLS_QUERY),
]);
setLeads(transformLeads(leadsData));
setCampaigns(transformCampaigns(campaignsData));
setAds(transformAds(adsData));
setFollowUps(transformFollowUps(followUpsData));
setLeadActivities(transformLeadActivities(activitiesData));
setCalls(transformCalls(callsData));
} catch (err: any) {
console.error('Failed to fetch platform data:', err);
setError(err.message ?? 'Failed to load data');
} finally {
setLoading(false);
}
}, []);
useEffect(() => {
fetchData();
}, [fetchData]);
const updateLead = (id: string, updates: Partial<Lead>) => {
setLeads((prev) => prev.map((lead) => (lead.id === id ? { ...lead, ...updates } : lead)));
};
const addCall = (call: Call) => {
setCalls((prev) => [call, ...prev]);
};
return (
<DataContext.Provider value={{
leads, campaigns, ads, followUps, leadActivities, templates, agents, calls, ingestionSources,
loading, error,
updateLead, addCall, refresh: fetchData,
}}>
{children}
</DataContext.Provider>
);
};