2022-06-14 23:28:32 +00:00
|
|
|
import { useCallback, useEffect } from "react";
|
|
|
|
import type { Call } from "@twilio/voice-sdk";
|
|
|
|
import { atom, useAtom } from "jotai";
|
2022-06-19 15:57:51 +00:00
|
|
|
import { notificationDataAtom } from "~/features/core/hooks/use-notifications";
|
2022-06-14 23:28:32 +00:00
|
|
|
|
|
|
|
export default function useCall() {
|
2022-06-19 15:57:51 +00:00
|
|
|
const [, setNotificationData] = useAtom(notificationDataAtom);
|
2022-06-14 23:28:32 +00:00
|
|
|
const [call, setCall] = useAtom(callAtom);
|
|
|
|
const endCall = useCallback(
|
|
|
|
function endCallFn() {
|
|
|
|
call?.removeListener("cancel", endCall);
|
|
|
|
call?.removeListener("disconnect", endCall);
|
|
|
|
call?.disconnect();
|
|
|
|
setCall(null);
|
2022-06-19 15:57:51 +00:00
|
|
|
setNotificationData(null);
|
2022-06-14 23:28:32 +00:00
|
|
|
},
|
2022-06-19 15:57:51 +00:00
|
|
|
[call, setCall, setNotificationData],
|
2022-06-14 23:28:32 +00:00
|
|
|
);
|
|
|
|
const onError = useCallback(
|
|
|
|
function onErrorFn(error: any) {
|
|
|
|
call?.removeListener("cancel", endCall);
|
|
|
|
call?.removeListener("disconnect", endCall);
|
|
|
|
call?.disconnect();
|
|
|
|
setCall(null);
|
2022-06-19 15:57:51 +00:00
|
|
|
setNotificationData(null);
|
2022-06-14 23:28:32 +00:00
|
|
|
throw error; // TODO: might not get caught by error boundary
|
|
|
|
},
|
2022-06-19 15:57:51 +00:00
|
|
|
[call, setCall, endCall, setNotificationData],
|
2022-06-14 23:28:32 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
const eventHandlers = [
|
|
|
|
["error", onError],
|
|
|
|
["cancel", endCall],
|
|
|
|
["disconnect", endCall],
|
|
|
|
] as const;
|
|
|
|
for (const [eventName, handler] of eventHandlers) {
|
|
|
|
// register call event handlers
|
|
|
|
// one event at a time to only update the handlers that changed
|
|
|
|
// without resetting the other handlers
|
|
|
|
|
|
|
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
|
|
useEffect(() => {
|
|
|
|
if (!call) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if we already have this event handler registered, no need to re-register it
|
|
|
|
const listeners = call.listeners(eventName);
|
|
|
|
if (listeners.length > 0 && listeners.every((fn) => fn.toString() === handler.toString())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
call.on(eventName, handler);
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
call.removeListener(eventName, handler);
|
|
|
|
};
|
|
|
|
}, [call, setCall, eventName, handler]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return [call, setCall] as const;
|
|
|
|
}
|
|
|
|
|
|
|
|
const callAtom = atom<Call | null>(null);
|