Files
holacompi/hooks/useVapi.ts
T
Haitham Khalifa b538d84e17 Initial commit
2026-02-16 12:18:06 +01:00

103 lines
2.5 KiB
TypeScript

'use client';
import { useCallback, useEffect, useRef, useState } from 'react';
import { initializeVapi, vapiConfig } from '@/lib/vapi';
export type VapiCallStatus = 'idle' | 'connecting' | 'active' | 'ended' | 'error';
interface CallStats {
durationSeconds: number;
creditsUsed: number;
}
const formatError = (error: unknown) => {
if (error instanceof Error) return error.message;
if (typeof error === 'string') return error;
return 'Something went wrong starting the call.';
};
export const useVapi = () => {
const clientRef = useRef<any>(null);
const timerRef = useRef<NodeJS.Timeout | null>(null);
const [status, setStatus] = useState<VapiCallStatus>('idle');
const [error, setError] = useState<string | null>(null);
const [durationSeconds, setDurationSeconds] = useState(0);
const [callStats, setCallStats] = useState<CallStats | null>(null);
useEffect(() => {
if (status === 'active') {
timerRef.current = setInterval(() => {
setDurationSeconds((prev) => prev + 1);
}, 1000);
} else {
if (timerRef.current) {
clearInterval(timerRef.current);
}
}
return () => {
if (timerRef.current) {
clearInterval(timerRef.current);
}
};
}, [status]);
const startCall = useCallback(async () => {
setError(null);
setCallStats(null);
setDurationSeconds(0);
setStatus('connecting');
try {
if (!clientRef.current) {
clientRef.current = initializeVapi();
}
const assistantId = vapiConfig.assistantId;
if (!assistantId) {
throw new Error('Missing NEXT_PUBLIC_VAPI_ASSISTANT_ID');
}
const client = clientRef.current;
const response =
(await client?.start?.({ assistantId })) ??
(await client?.startCall?.({ assistantId })) ??
(await client?.call?.({ assistantId }));
if (response?.id) {
// Future: store call id for status lookup
}
setStatus('active');
} catch (err) {
setError(formatError(err));
setStatus('error');
}
}, []);
const endCall = useCallback(async () => {
try {
const client = clientRef.current;
await client?.stop?.();
await client?.end?.();
} catch (err) {
setError(formatError(err));
} finally {
setStatus('ended');
setCallStats({
durationSeconds,
creditsUsed: Math.max(1, Math.round(durationSeconds / 60)),
});
}
}, [durationSeconds]);
return {
status,
error,
durationSeconds,
callStats,
startCall,
endCall,
};
};