feat: add worklist with missed calls, follow-ups, and leads sections

This commit is contained in:
2026-03-18 11:26:16 +05:30
parent ffcaa79410
commit bb48d07e61
3 changed files with 634 additions and 6 deletions

115
src/hooks/use-worklist.ts Normal file
View File

@@ -0,0 +1,115 @@
import { useState, useEffect, useCallback } from 'react';
import { apiClient } from '@/lib/api-client';
type MissedCall = {
id: string;
createdAt: string;
callDirection: string | null;
callStatus: string | null;
callerNumber: { number: string; callingCode: string }[] | null;
agentName: string | null;
startedAt: string | null;
endedAt: string | null;
durationSeconds: number | null;
disposition: string | null;
callNotes: string | null;
leadId: string | null;
};
type WorklistFollowUp = {
id: string;
createdAt: string | null;
followUpType: string | null;
followUpStatus: string | null;
scheduledAt: string | null;
completedAt: string | null;
priority: string | null;
assignedAgent: string | null;
patientId: string | null;
callId: string | null;
};
type WorklistLead = {
id: string;
createdAt: string;
contactName: { firstName: string; lastName: string } | null;
contactPhone: { number: string; callingCode: string }[] | null;
contactEmail: { address: string }[] | null;
leadSource: string | null;
leadStatus: string | null;
interestedService: string | null;
assignedAgent: string | null;
campaignId: string | null;
adId: string | null;
contactAttempts: number | null;
spamScore: number | null;
isSpam: boolean | null;
aiSummary: string | null;
aiSuggestedAction: string | null;
};
type WorklistData = {
missedCalls: MissedCall[];
followUps: WorklistFollowUp[];
marketingLeads: WorklistLead[];
totalPending: number;
};
type UseWorklistResult = WorklistData & {
loading: boolean;
error: string | null;
refresh: () => void;
};
const EMPTY_WORKLIST: WorklistData = {
missedCalls: [],
followUps: [],
marketingLeads: [],
totalPending: 0,
};
export const useWorklist = (): UseWorklistResult => {
const [data, setData] = useState<WorklistData>(EMPTY_WORKLIST);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const fetchWorklist = useCallback(async () => {
try {
const token = apiClient.getStoredToken();
if (!token) {
setError('Not authenticated');
setLoading(false);
return;
}
const apiUrl = import.meta.env.VITE_API_URL ?? 'http://localhost:4100';
const response = await fetch(`${apiUrl}/api/worklist`, {
headers: { Authorization: `Bearer ${token}` },
});
if (response.ok) {
const json = await response.json();
setData(json);
setError(null);
} else {
setError(`Worklist API returned ${response.status}`);
}
} catch (err) {
console.warn('Worklist fetch failed:', err);
setError('Sidecar not reachable');
}
setLoading(false);
}, []);
useEffect(() => {
fetchWorklist();
// Refresh every 30 seconds
const interval = setInterval(fetchWorklist, 30000);
return () => clearInterval(interval);
}, [fetchWorklist]);
return { ...data, loading, error, refresh: fetchWorklist };
};