mediasfu-reactnative-expo
Version:
mediasfu-reactnative-expo – Expo-managed React Native WebRTC SDK for video conferencing, webinars, live streaming, broadcast, screen sharing, whiteboard, chat, recording, live subtitles, translation, and AI agent rooms on iOS, Android, and web. Prebuilt r
281 lines (275 loc) • 8.94 kB
JavaScript
import React, { useEffect, useState } from 'react';
import { Modal, View, Text, Pressable, StyleSheet, Dimensions, } from 'react-native';
import { FontAwesome5 } from '@expo/vector-icons';
import { confirmExit } from '../../methods/exitMethods/confirmExit';
import { getModalPosition } from '../../methods/utils/getModalPosition';
/**
* ConfirmExitModal - Exit confirmation dialog with "End Event for All" option
*
* ConfirmExitModal is a React Native component that provides a confirmation interface
* when users want to leave a meeting. For host-level users (islevel='2'), it offers
* an additional option to end the event for all participants. Supports ban/kick actions.
*
* **Key Features:**
* - Personal exit confirmation ("Leave Room")
* - "End Event for All" option for hosts (islevel='2')
* - Ban/kick action support
* - Socket.io notification on exit
* - Position-configurable modal (4 corners)
* - Customizable exit confirmation handler
* - Cancel option to close modal
*
* **UI Customization:**
* This component can be replaced via `uiOverrides.confirmExitModal` to
* provide a completely custom exit confirmation interface.
*
* @component
* @param {ConfirmExitModalOptions} props - Configuration options
*
* @returns {JSX.Element} Rendered exit confirmation modal
*
* @example
* ```tsx
* // Basic usage for participant exit
* import React, { useState } from 'react';
* import { ConfirmExitModal } from 'mediasfu-reactnative-expo';
* import { io } from 'socket.io-client';
*
* const socket = io('https://your-server.com');
* const [showExitModal, setShowExitModal] = useState(false);
*
* return (
* <ConfirmExitModal
* isConfirmExitModalVisible={showExitModal}
* onConfirmExitClose={() => setShowExitModal(false)}
* member="John Doe"
* roomName="meeting-room-123"
* socket={socket}
* islevel="0" // Regular participant - only "Leave Room" option
* />
* );
* ```
*
* @example
* ```tsx
* // Host usage with "End Event for All" option
* const handleExitConfirm = (options: ConfirmExitOptions) => {
* confirmExit(options);
* console.log('Exit action completed');
* };
*
* return (
* <ConfirmExitModal
* isConfirmExitModalVisible={showModal}
* onConfirmExitClose={handleClose}
* exitEventOnConfirm={handleExitConfirm}
* member="Host Name"
* roomName={roomId}
* socket={socketConnection}
* islevel="2" // Host - shows "End Event for All" option
* position="bottomRight"
* backgroundColor="#e74c3c"
* />
* );
* ```
*
* @example
* ```tsx
* // Using custom UI via uiOverrides
* const config = {
* uiOverrides: {
* confirmExitModal: {
* component: MyCustomExitConfirmation,
* injectedProps: {
* theme: 'dark',
* confirmationText: 'Are you sure you want to leave?',
* },
* },
* },
* };
*
* return <MyMeetingComponent config={config} />;
* ```
*/
const ConfirmExitModal = ({ isConfirmExitModalVisible, onConfirmExitClose, position = 'topRight', backgroundColor = '#83c0e9', isDarkMode, exitEventOnConfirm = confirmExit, member, ban = false, roomName, socket, islevel, style, renderContent, renderContainer, }) => {
const [modalWidth, setModalWidth] = useState(0.7 * Dimensions.get('window').width);
useEffect(() => {
const updateDimensions = () => {
let width = 0.7 * Dimensions.get('window').width;
if (width > 400) {
width = 400;
}
setModalWidth(width);
};
const subscribe = Dimensions.addEventListener('change', updateDimensions);
// Initial call
updateDimensions();
return () => {
subscribe.remove();
};
}, []);
/**
* Handles the logic when the user confirms exit.
*/
const handleConfirmExit = () => {
exitEventOnConfirm({
socket,
member,
roomName,
ban,
});
onConfirmExitClose();
};
const dimensions = { width: modalWidth, height: 0 };
const themed = typeof isDarkMode === 'boolean';
const textColor = themed ? (isDarkMode ? '#f8fafc' : '#0f172a') : 'black';
const borderColor = themed ? (isDarkMode ? 'rgba(226, 232, 240, 0.18)' : 'rgba(71, 85, 105, 0.22)') : 'black';
const defaultContent = (<>
{/* Header */}
<View style={styles.modalHeader}>
<Text style={[styles.modalTitle, { color: textColor }]}>Confirm Exit</Text>
<Pressable onPress={onConfirmExitClose} style={styles.btnCloseConfirmExit} accessibilityRole="button" accessibilityLabel="Close Confirm Exit Modal">
<FontAwesome5 name="times" style={[styles.icon, { color: textColor }]}/>
</Pressable>
</View>
{/* Divider */}
<View style={[styles.hr, { borderBottomColor: borderColor }]}/>
{/* Body */}
<View style={styles.modalBody}>
<Text style={[styles.confirmExitText, { color: textColor }]}>
{islevel === '2'
? 'This will end the event for all. Confirm exit.'
: 'Are you sure you want to exit?'}
</Text>
</View>
{/* Divider */}
<View style={[styles.hr, { borderBottomColor: borderColor }]}/>
{/* Footer */}
<View style={styles.modalFooter}>
{/* Cancel Button */}
<Pressable onPress={onConfirmExitClose} style={[styles.confirmButton, styles.btnCancel]} accessibilityRole="button" accessibilityLabel="Cancel Exit">
<Text style={[styles.confirmButtonText, styles.btnCancelText]}>Cancel</Text>
</Pressable>
{/* Separator */}
<View style={[styles.doubleBorder, { backgroundColor: borderColor }]}/>
{/* Exit/End Event Button */}
<Pressable onPress={handleConfirmExit} style={[styles.confirmButton, styles.btnExit]} accessibilityRole="button" accessibilityLabel={islevel === '2' ? 'End Event' : 'Exit'}>
<Text style={[styles.confirmButtonText, styles.btnExitText]}>
{islevel === '2' ? 'End Event' : 'Exit'}
</Text>
</Pressable>
</View>
</>);
const content = renderContent
? renderContent({ defaultContent, dimensions })
: defaultContent;
const defaultContainer = (<Modal transparent animationType="fade" visible={isConfirmExitModalVisible} onRequestClose={onConfirmExitClose}>
<View style={[styles.modalContainer, getModalPosition({ position })]}>
{/* Modal Content */}
<View style={[styles.modalContent, { backgroundColor, width: modalWidth }, style]}>
{content}
</View>
</View>
</Modal>);
return renderContainer
? renderContainer({ defaultContainer, dimensions })
: defaultContainer;
};
export default ConfirmExitModal;
/**
* Stylesheet for the ConfirmExitModal component.
*/
const styles = StyleSheet.create({
modalContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
modalContent: {
height: '35%',
backgroundColor: '#83c0e9',
borderRadius: 10,
padding: 20,
maxHeight: '35%',
maxWidth: '70%',
zIndex: 9,
elevation: 9,
borderWidth: 2,
borderColor: 'black',
// Shadow for iOS
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.25,
shadowRadius: 4,
},
modalHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 10,
},
modalTitle: {
fontSize: 18,
fontWeight: 'bold',
color: 'black',
},
btnCloseConfirmExit: {
padding: 5,
},
icon: {
fontSize: 20,
color: 'black',
marginRight: 15,
},
hr: {
borderBottomColor: 'black',
borderBottomWidth: 1,
marginBottom: 15,
},
modalBody: {
padding: 4,
},
confirmExitText: {
color: 'black',
fontSize: 16,
textAlign: 'center',
paddingVertical: 10,
},
modalFooter: {
flexDirection: 'row',
justifyContent: 'space-between',
marginTop: 10,
alignItems: 'center',
},
confirmButton: {
padding: 5,
borderRadius: 5,
alignItems: 'center',
justifyContent: 'center',
},
btnCancel: {
backgroundColor: '#6c757d',
},
btnExit: {
backgroundColor: '#dc3545',
},
doubleBorder: {
height: 25,
width: 1,
backgroundColor: 'black',
marginHorizontal: 5,
},
confirmButtonText: {
color: 'black',
fontSize: 14,
fontWeight: 'bold',
},
btnCancelText: {
fontSize: 14,
color: 'white',
},
btnExitText: {
fontSize: 14,
},
});
//# sourceMappingURL=ConfirmExitModal.js.map