UNPKG

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

287 lines (284 loc) 9.82 kB
import React, { useEffect, useState } from "react"; import { Modal, View, Text, Pressable, StyleSheet, ScrollView, Dimensions, TextInput, } from "react-native"; import { FontAwesome } from "@expo/vector-icons"; import RenderRequestComponent from "./RenderRequestComponent"; import { respondToRequests, } from "../../methods/requestsMethods/respondToRequests"; import { getModalPosition } from "../../methods/utils/getModalPosition"; import { getModalBodyTheme } from "../../components_modern/core/modalBodyTheme"; /** * RequestsModal - Participant request management interface * * RequestsModal is a React Native component that displays pending participant requests * (microphone, video, screenshare) with options to filter, accept, or reject each request. * Host users can review and respond to requests in real-time via Socket.io. * * **Key Features:** * - Scrollable list of participant requests (mic, video, screenshare) * - Accept/reject actions for each request * - Real-time filtering by participant name or request type * - Request counter badge display * - Socket.io synchronization for instant responses * - Custom request item rendering * - Position-configurable modal (5 positions) * * **UI Customization:** * This component can be replaced via `uiOverrides.requestsModal` to * provide a completely custom requests management interface. * * @component * @param {RequestsModalOptions} props - Configuration options * * @returns {JSX.Element} Rendered requests modal * * @example * ```tsx * // Basic usage with request handling * import React, { useState } from 'react'; * import { RequestsModal } from 'mediasfu-reactnative-expo'; * import { io } from 'socket.io-client'; * * const socket = io('https://your-server.com'); * const [showRequests, setShowRequests] = useState(false); * const [filter, setFilter] = useState(''); * * const requests = [ * { id: '1', name: 'John Doe', icon: 'fa-microphone', username: 'john' }, * { id: '2', name: 'Jane Smith', icon: 'fa-video', username: 'jane' }, * { id: '3', name: 'Bob Wilson', icon: 'fa-desktop', username: 'bob' }, * ]; * * return ( * <RequestsModal * isRequestsModalVisible={showRequests} * onRequestClose={() => setShowRequests(false)} * requestCounter={requests.length} * onRequestFilterChange={setFilter} * requestList={requests} * updateRequestList={(newList) => console.log('Updated:', newList)} * roomName="meeting-room-123" * socket={socket} * parameters={{ * getUpdatedAllParams: () => ({ filteredRequestList: requests }), * }} * /> * ); * ``` * * @example * ```tsx * // With custom positioning and request handling * const handleRequestResponse = async (options: RespondToRequestsOptions) => { * await respondToRequests(options); * console.log('Request handled'); * }; * * return ( * <RequestsModal * isRequestsModalVisible={isVisible} * onRequestClose={handleClose} * requestCounter={pendingCount} * onRequestFilterChange={handleFilterChange} * onRequestItemPress={handleRequestResponse} * requestList={pendingRequests} * updateRequestList={setPendingRequests} * roomName={roomId} * socket={socketConnection} * parameters={requestParams} * position="bottomLeft" * backgroundColor="#2c3e50" * /> * ); * ``` * * @example * ```tsx * // Using custom UI via uiOverrides * const config = { * uiOverrides: { * requestsModal: { * component: MyCustomRequestsManager, * injectedProps: { * theme: 'dark', * showAutoApprove: true, * }, * }, * }, * }; * * return <MyMeetingComponent config={config} />; * ``` */ const RequestsModal = ({ isRequestsModalVisible, onRequestClose, requestCounter, onRequestFilterChange, onRequestItemPress = respondToRequests, requestList, updateRequestList, roomName, socket, renderRequestComponent = RenderRequestComponent, backgroundColor = "#83c0e9", isDarkMode, position = "topRight", parameters, style, renderContent, renderContainer, }) => { const [filteredRequestList, setFilteredRequestList] = useState(requestList); const [localRequestCounter, setLocalRequestCounter] = useState(requestCounter); const [filterText, setFilterText] = useState(""); useEffect(() => { if (!isRequestsModalVisible) { return; } const { getUpdatedAllParams } = parameters; const updatedParams = getUpdatedAllParams(); setFilteredRequestList(updatedParams.filteredRequestList); setLocalRequestCounter(updatedParams.filteredRequestList.length); }, [isRequestsModalVisible, requestList, parameters]); if (!isRequestsModalVisible) { return null; } const modalWidth = 0.8 * Dimensions.get("window").width > 350 ? 350 : 0.8 * Dimensions.get("window").width; const dimensions = { width: modalWidth, height: 0 }; const theme = getModalBodyTheme(isDarkMode); const shouldUseModernTheme = typeof isDarkMode === "boolean"; const requestRenderer = renderRequestComponent; const defaultContent = (<> {/* Header */} <View style={styles.modalHeader}> <Text style={[styles.modalTitle, { color: theme.textColor }]}> Requests <Text style={[styles.badge, { backgroundColor: theme.badgeBackgroundColor, color: theme.badgeTextColor }]}>{localRequestCounter}</Text> </Text> <Pressable onPress={onRequestClose} style={styles.closeButton}> <FontAwesome name="times" size={20} color={theme.iconColor}/> </Pressable> </View> <View style={[styles.separator, { backgroundColor: theme.dividerColor }]}/> {/* Filter Input */} <View style={styles.modalBody}> <View style={styles.filterContainer}> <TextInput style={[ styles.input, { backgroundColor: theme.inputBackgroundColor, borderColor: theme.borderColor, color: theme.inputTextColor, }, ]} placeholder="Search ..." placeholderTextColor={theme.placeholderTextColor} value={filterText} onChangeText={(text) => { setFilterText(text); onRequestFilterChange(text); }}/> </View> </View> {/* Request List */} <ScrollView style={styles.scrollView}> <View style={styles.requestList}> {filteredRequestList && filteredRequestList.length > 0 ? (filteredRequestList.map((requestItem, index) => (<View key={index} style={styles.requestItem}> {requestRenderer({ request: requestItem, onRequestItemPress, requestList: filteredRequestList, updateRequestList, roomName, socket, isDarkMode, })} </View>))) : (<Text style={[styles.noRequestsText, { color: theme.mutedTextColor }]}>No requests found.</Text>)} </View> </ScrollView> </>); const content = renderContent ? renderContent({ defaultContent, dimensions }) : defaultContent; const defaultContainer = (<Modal transparent animationType="fade" visible={isRequestsModalVisible} onRequestClose={onRequestClose}> <View style={[styles.modalContainer, getModalPosition({ position }), shouldUseModernTheme ? { borderColor: theme.borderColor } : null]}> <View style={[ styles.modalContent, { backgroundColor, width: modalWidth }, shouldUseModernTheme ? { borderColor: theme.borderColor } : null, style, ]}> {content} </View> </View> </Modal>); return renderContainer ? renderContainer({ defaultContainer, dimensions }) : defaultContainer; }; export default RequestsModal; /** * Stylesheet for the RequestsModal component. */ const styles = StyleSheet.create({ modalContainer: { flex: 1, ...StyleSheet.absoluteFillObject, justifyContent: "flex-end", alignItems: "flex-end", zIndex: 9, elevation: 9, borderWidth: 2, borderColor: "black", }, modalContent: { height: "65%", backgroundColor: "#fff", borderRadius: 0, padding: 20, maxHeight: "65%", maxWidth: "70%", zIndex: 9, elevation: 9, shadowColor: "#000", shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.25, shadowRadius: 4, borderWidth: 2, borderColor: "black", }, modalHeader: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", marginBottom: 15, }, modalTitle: { fontSize: 18, fontWeight: "bold", color: "black", }, badge: { backgroundColor: "#ffffff", color: "#000", borderRadius: 5, paddingHorizontal: 10, paddingVertical: 2, marginLeft: 5, }, closeButton: { padding: 5, }, modalBody: { flex: 1, }, separator: { height: 1, backgroundColor: "#ffffff", marginVertical: 10, }, filterContainer: { marginBottom: 15, }, input: { height: 40, borderColor: "gray", borderWidth: 1, borderRadius: 5, paddingHorizontal: 10, fontSize: 16, }, scrollView: { flex: 1, maxHeight: "100%", maxWidth: "100%", }, requestList: { flexGrow: 1, }, requestItem: { marginBottom: 10, }, noRequestsText: { textAlign: "center", color: "gray", fontSize: 16, }, }); //# sourceMappingURL=RequestsModal.js.map