@cometchat/chat-uikit-react-native
Version:
Ready-to-use Chat UI Components for React Native
193 lines • 9.32 kB
JavaScript
import { CometChat } from "@cometchat/chat-sdk-react-native";
import React, { useEffect, useMemo, useRef, useState } from "react";
import { Modal, SafeAreaView, Text, TouchableOpacity, View } from "react-native";
import { MessageCategoryConstants, MessageTypeConstants, } from "../../shared/constants/UIKitConstants";
import { CometChatUIEventHandler } from "../../shared/events/CometChatUIEventHandler/CometChatUIEventHandler";
import { CometChatSoundManager, localize } from "../../shared/resources";
import { CometChatAvatar } from "../../shared/views";
import { CallUIEvents } from "../CallEvents";
import { CallingPackage } from "../CallingPackage";
import { CometChatOngoingCall } from "../CometChatOngoingCall";
import { useTheme } from "../../theme";
import { Icon } from "../../shared/icons/Icon";
import { deepMerge } from "../../shared/helper/helperFunctions";
const listenerId = "callListener_" + new Date().getTime();
const CometChatCalls = CallingPackage.CometChatCalls;
/**
* CometChatOutgoingCall component.
*
* This component handles the UI for an outgoing call by playing sound,
* rendering call details and providing an end call action. It listens to call events
* to update the UI based on the call's state.
*
* @param {CometChatOutgoingCallInterface} props - Component configuration props.
* @returns {JSX.Element} The rendered outgoing call UI.
*/
export const CometChatOutgoingCall = (props) => {
const { call, customSoundForCalls, disableSoundForCalls, onEndCallButtonPressed, callSettingsBuilder, style, TitleView, SubtitleView, AvatarView, EndCallView, onError, } = props;
// State to track whether the call is connected.
const [isCallConnected, setCallConnected] = useState(false);
// Controls visibility of this modal.
const [isModalVisible, setModalVisible] = useState(true);
const ongoingCall = useRef(undefined);
const callSessionId = useRef(undefined);
const callListener = useRef(null);
const callSettings = useRef(null);
const isCallEnded = useRef(undefined);
const theme = useTheme();
// Merge default and custom styles for the outgoing call.
const outgoingCallStyle = useMemo(() => {
return deepMerge(theme.outgoingCallStyle, style ?? {});
}, [theme.outgoingCallStyle, style]);
function checkIfDefaultCall(call) {
return call.getCategory() === MessageCategoryConstants.call;
}
/**
* Ends the call if required by checking if it is a default call.
*/
const endCallIfRequired = () => {
if (call && checkIfDefaultCall(call)) {
CometChat.endCall(call.getSessionId())
.then(() => {
call.setStatus("ended");
if (!isCallEnded.current) {
CometChatUIEventHandler.emitCallEvent(CallUIEvents.ccCallEnded, { call });
}
isCallEnded.current = true;
})
.catch((err) => {
console.log("Error", err);
onError && onError(err);
});
}
};
// Set up listeners, call settings, and sound for the outgoing call.
useEffect(() => {
if (call &&
(call["status"] === "ongoing" ||
(call.getCategory() === CometChat.CATEGORY_CUSTOM &&
call.getType() === MessageTypeConstants.meeting))) {
ongoingCall.current = call;
if (call.getType() == MessageTypeConstants.meeting) {
callSessionId.current = call.getCustomData()?.sessionId;
}
if (call.getCategory() === MessageCategoryConstants.call) {
callSessionId.current = call["sessionId"];
}
setCallConnected(true);
}
if (!disableSoundForCalls && call?.getType() !== MessageTypeConstants.meeting) {
if (customSoundForCalls) {
CometChatSoundManager.play("outgoingCall", customSoundForCalls);
}
else {
CometChatSoundManager.play("outgoingCall");
}
}
// Add call listener to handle outgoing call acceptance and rejection.
CometChat.addCallListener(listenerId, new CometChat.CallListener({
onOutgoingCallAccepted: (acceptedCall) => {
CometChatSoundManager.pause();
ongoingCall.current = acceptedCall;
callSessionId.current = acceptedCall["sessionId"];
setCallConnected(true);
},
onOutgoingCallRejected: () => {
CometChatSoundManager.pause();
ongoingCall.current = undefined;
callSessionId.current = undefined;
setCallConnected(false);
},
}));
// Listen for call failure events.
CometChatUIEventHandler.addCallListener(listenerId, {
ccCallFailed: (error) => {
setCallConnected(false);
onError && onError(error);
},
});
// Create an ongoing call listener to manage call events.
callListener.current = new CometChatCalls.OngoingCallListener({
onCallEnded: () => {
CometChatCalls.endSession();
if (checkIfDefaultCall(call)) {
CometChat.clearActiveCall();
setCallConnected(false);
call.setStatus("ended");
if (!isCallEnded.current) {
CometChatUIEventHandler.emitCallEvent(CallUIEvents.ccCallEnded, { call });
}
isCallEnded.current = true;
}
},
onCallEndButtonPressed: () => {
if (!checkIfDefaultCall(call)) {
setCallConnected(false);
call.setStatus("ended");
if (!isCallEnded.current) {
CometChatUIEventHandler.emitCallEvent(CallUIEvents.ccCallEnded, { call });
}
isCallEnded.current = true;
}
else {
endCallIfRequired();
}
},
onUserJoined: (user) => {
console.log("user joined:", user);
},
onUserLeft: (user) => {
endCallIfRequired();
},
onError: (error) => {
CometChatUIEventHandler.emitCallEvent(CallUIEvents.ccCallFailed, { error });
},
});
// Determine call type (audio or meeting) and initialize call settings.
const callType = call?.getType() === MessageTypeConstants.meeting
? call["customData"]?.["callType"]
: call.getType();
callSettings.current =
callSettingsBuilder?.setCallEventListener(callListener.current) ??
new CometChatCalls.CallSettingsBuilder()
.enableDefaultLayout(true)
.setCallEventListener(callListener.current)
.setIsAudioOnlyCall(callType === "audio");
// Cleanup on unmount.
return () => {
if (!disableSoundForCalls) {
CometChatSoundManager.pause();
}
CometChat.removeCallListener(listenerId);
};
}, []);
/**
* Handles closing the modal (via hardware back button on Android or a custom button).
* This is where you can call onEndCallButtonPressed or do any other cleanup.
*/
const handleModalClose = () => {
if (onEndCallButtonPressed) {
onEndCallButtonPressed(call);
}
// Hide the modal – onDismiss fires after the animation completes
setModalVisible(false);
};
const callReceiverName = call?.getReceiver?.().getName?.() ?? "Unknown";
return (<Modal transparent animationType="fade" visible={isModalVisible} onRequestClose={handleModalClose}>
<SafeAreaView style={{ flex: 1 }}>
{isCallConnected ? (<CometChatOngoingCall sessionID={callSessionId.current} callSettingsBuilder={callSettings.current}/>) : (<View style={outgoingCallStyle.containerStyle}>
{TitleView ? (TitleView(call)) : (<Text style={outgoingCallStyle.titleTextStyle}>{callReceiverName}</Text>)}
{SubtitleView ? (SubtitleView(call)) : (<Text style={outgoingCallStyle.subtitleTextStyle}>{localize("CALLING")}</Text>)}
{AvatarView ? (AvatarView(call)) : (<CometChatAvatar name={callReceiverName} image={{
uri: call?.getReceiverType?.() === "user"
? call?.getReceiver?.()?.getAvatar()
: call?.getReceiver?.()?.getIcon(),
}} style={outgoingCallStyle.avatarStyle}/>)}
{EndCallView ? (EndCallView(call)) : (<TouchableOpacity style={outgoingCallStyle.endCallButtonStyle} onPress={handleModalClose}>
<Icon name="call-end-fill" size={32} height={outgoingCallStyle.endCallIconStyle.height} width={outgoingCallStyle.endCallIconStyle.width} color={outgoingCallStyle.endCallIconStyle.tintColor} imageStyle={outgoingCallStyle.endCallIconStyle}/>
</TouchableOpacity>)}
</View>)}
</SafeAreaView>
</Modal>);
};
//# sourceMappingURL=CometChatOutgoingCall.js.map