11import { useState , useEffect , useRef , useCallback } from 'react' ;
22import Vapi from '@vapi-ai/web' ;
3-
4- interface StoredCallData {
5- webCallUrl : string ;
6- id ?: string ;
7- artifactPlan ?: {
8- videoRecordingEnabled ?: boolean ;
9- } ;
10- assistant ?: {
11- voice ?: {
12- provider ?: string ;
13- } ;
14- } ;
15- timestamp : number ;
16- }
3+ import * as vapiCallStorage from '../utils/vapiCallStorage' ;
174
185export interface VapiCallState {
196 isCallActive : boolean ;
@@ -37,7 +24,7 @@ export interface UseVapiCallOptions {
3724 callOptions : any ;
3825 apiUrl ?: string ;
3926 enabled ?: boolean ;
40- roomDeleteOnUserLeaveEnabled ?: boolean ;
27+ voiceAutoReconnect ?: boolean ;
4128 reconnectStorageKey ?: string ;
4229 onCallStart ?: ( ) => void ;
4330 onCallEnd ?: ( ) => void ;
@@ -55,7 +42,7 @@ export const useVapiCall = ({
5542 callOptions,
5643 apiUrl,
5744 enabled = true ,
58- roomDeleteOnUserLeaveEnabled = false ,
45+ voiceAutoReconnect = false ,
5946 reconnectStorageKey = 'vapi_widget_web_call' ,
6047 onCallStart,
6148 onCallEnd,
@@ -83,54 +70,6 @@ export const useVapiCall = ({
8370 onTranscript,
8471 } ) ;
8572
86- // localStorage utilities
87- const storeCallData = useCallback (
88- ( call : any ) => {
89- if ( ! roomDeleteOnUserLeaveEnabled ) {
90- // Extract webCallUrl from the call object
91- // The webCallUrl can be in call.webCallUrl or call.transport.callUrl
92- const webCallUrl =
93- ( call as any ) . webCallUrl || ( call . transport as any ) ?. callUrl ;
94-
95- if ( webCallUrl ) {
96- const webCallToStore = {
97- webCallUrl,
98- id : call . id ,
99- artifactPlan : call . artifactPlan ,
100- assistant : call . assistant ,
101- timestamp : Date . now ( ) ,
102- } ;
103- localStorage . setItem (
104- reconnectStorageKey ,
105- JSON . stringify ( webCallToStore )
106- ) ;
107- console . log ( 'Stored call data for reconnection:' , webCallToStore ) ;
108- } else {
109- console . warn (
110- 'No webCallUrl found in call object, cannot store for reconnection'
111- ) ;
112- }
113- }
114- } ,
115- [ roomDeleteOnUserLeaveEnabled , reconnectStorageKey ]
116- ) ;
117-
118- const getStoredCallData = useCallback ( ( ) : StoredCallData | null => {
119- try {
120- const stored = localStorage . getItem ( reconnectStorageKey ) ;
121- if ( ! stored ) return null ;
122-
123- return JSON . parse ( stored ) ;
124- } catch {
125- localStorage . removeItem ( reconnectStorageKey ) ;
126- return null ;
127- }
128- } , [ reconnectStorageKey ] ) ;
129-
130- const clearStoredCall = useCallback ( ( ) => {
131- localStorage . removeItem ( reconnectStorageKey ) ;
132- } , [ reconnectStorageKey ] ) ;
133-
13473 useEffect ( ( ) => {
13574 callbacksRef . current = {
13675 onCallStart,
@@ -159,7 +98,7 @@ export const useVapiCall = ({
15998 setIsSpeaking ( false ) ;
16099 setIsMuted ( false ) ;
161100 // Clear stored call data on successful call end
162- clearStoredCall ( ) ;
101+ vapiCallStorage . clearStoredCall ( reconnectStorageKey ) ;
163102 callbacksRef . current . onCallEnd ?.( ) ;
164103 } ;
165104
@@ -214,7 +153,7 @@ export const useVapiCall = ({
214153 vapi . removeListener ( 'message' , handleMessage ) ;
215154 vapi . removeListener ( 'error' , handleError ) ;
216155 } ;
217- } , [ vapi , clearStoredCall ] ) ;
156+ } , [ vapi , reconnectStorageKey ] ) ;
218157
219158 useEffect ( ( ) => {
220159 return ( ) => {
@@ -233,7 +172,7 @@ export const useVapiCall = ({
233172 try {
234173 console . log ( 'Starting call with configuration:' , callOptions ) ;
235174 console . log ( 'Starting call with options:' , {
236- roomDeleteOnUserLeaveEnabled ,
175+ voiceAutoReconnect ,
237176 } ) ;
238177 setConnectionStatus ( 'connecting' ) ;
239178 const call = await vapi . start (
@@ -249,20 +188,20 @@ export const useVapiCall = ({
249188 undefined ,
250189 // options
251190 {
252- roomDeleteOnUserLeaveEnabled,
191+ roomDeleteOnUserLeaveEnabled : ! voiceAutoReconnect ,
253192 }
254193 ) ;
255194
256195 // Store call data for reconnection if call was successful and auto-reconnect is enabled
257- if ( call && ! roomDeleteOnUserLeaveEnabled ) {
258- storeCallData ( call ) ;
196+ if ( call && voiceAutoReconnect ) {
197+ vapiCallStorage . storeCallData ( reconnectStorageKey , call , callOptions ) ;
259198 }
260199 } catch ( error ) {
261200 console . error ( 'Error starting call:' , error ) ;
262201 setConnectionStatus ( 'disconnected' ) ;
263202 callbacksRef . current . onError ?.( error as Error ) ;
264203 }
265- } , [ vapi , callOptions , enabled , roomDeleteOnUserLeaveEnabled , storeCallData ] ) ;
204+ } , [ vapi , callOptions , enabled , voiceAutoReconnect , reconnectStorageKey ] ) ;
266205
267206 const endCall = useCallback (
268207 async ( { force = false } : { force ?: boolean } = { } ) => {
@@ -311,13 +250,26 @@ export const useVapiCall = ({
311250 return ;
312251 }
313252
314- const storedData = getStoredCallData ( ) ;
253+ const storedData = vapiCallStorage . getStoredCallData ( reconnectStorageKey ) ;
254+
315255 if ( ! storedData ) {
316256 console . warn ( 'No stored call data found for reconnection' ) ;
317257 return ;
318258 }
319259
260+ // Check if callOptions match before reconnecting
261+ if (
262+ ! vapiCallStorage . areCallOptionsEqual ( storedData . callOptions , callOptions )
263+ ) {
264+ console . warn (
265+ 'CallOptions have changed since last call, clearing stored data and skipping reconnection'
266+ ) ;
267+ vapiCallStorage . clearStoredCall ( reconnectStorageKey ) ;
268+ return ;
269+ }
270+
320271 setConnectionStatus ( 'connecting' ) ;
272+
321273 try {
322274 await vapi . reconnect ( {
323275 webCallUrl : storedData . webCallUrl ,
@@ -329,28 +281,21 @@ export const useVapiCall = ({
329281 } catch ( error ) {
330282 setConnectionStatus ( 'disconnected' ) ;
331283 console . error ( 'Reconnection failed:' , error ) ;
332- clearStoredCall ( ) ;
284+ vapiCallStorage . clearStoredCall ( reconnectStorageKey ) ;
333285 callbacksRef . current . onError ?.( error as Error ) ;
334286 }
335- } , [ vapi , enabled , getStoredCallData , clearStoredCall ] ) ;
287+ } , [ vapi , enabled , reconnectStorageKey , callOptions ] ) ;
288+
289+ const clearStoredCall = useCallback ( ( ) => {
290+ vapiCallStorage . clearStoredCall ( reconnectStorageKey ) ;
291+ } , [ reconnectStorageKey ] ) ;
336292
337- // Check for stored call data on initialization and attempt reconnection
338293 useEffect ( ( ) => {
339- if ( ! vapi || ! enabled || roomDeleteOnUserLeaveEnabled ) {
294+ if ( ! vapi || ! enabled || ! voiceAutoReconnect ) {
340295 return ;
341296 }
342-
343- const storedData = getStoredCallData ( ) ;
344- if ( storedData ) {
345- reconnect ( ) ;
346- }
347- } , [
348- vapi ,
349- enabled ,
350- roomDeleteOnUserLeaveEnabled ,
351- getStoredCallData ,
352- reconnect ,
353- ] ) ;
297+ reconnect ( ) ;
298+ } , [ vapi , enabled , voiceAutoReconnect , reconnect , reconnectStorageKey ] ) ;
354299
355300 return {
356301 // State
0 commit comments