UNPKG

mediasfu-reactnative-expo

Version:
362 lines (360 loc) 11.5 kB
import React, { useState, useRef, useEffect } from 'react'; import { View, Text, TextInput, Pressable, ScrollView, StyleSheet, } from 'react-native'; import { FontAwesome5 } from "@expo/vector-icons"; /** * MessagePanel component renders a panel for displaying and sending messages. * * @component * @param {MessagePanelOptions} props - The properties for the MessagePanel component. * @returns {JSX.Element} The rendered MessagePanel component. * * @example * ```tsx * import React from 'react'; * import { MessagePanel } from 'mediasfu-reactnative-expo'; * * function App() { * const messages = [ * { sender: 'Alice', message: 'Hello!', timestamp: '10:00', receivers: [], group: true }, * { sender: 'Bob', message: 'Hi Alice!', timestamp: '10:01', receivers: [], group: true }, * ]; * * const handleSendMessage = async (options) => { * // Logic to handle message sending * console.log('Message sent:', options); * }; * * return ( * <MessagePanel * messages={messages} * messagesLength={messages.length} * type="group" * username="john_doe" * onSendMessagePress={handleSendMessage} * backgroundColor="#f5f5f5" * focusedInput={true} * eventType="conference" * member="john_doe" * islevel="1" * startDirectMessage={false} * updateStartDirectMessage={(start) => console.log('Start Direct Message:', start)} * directMessageDetails={null} * updateDirectMessageDetails={(participant) => console.log('Direct Message Participant:', participant)} * coHostResponsibility={[{ name: 'chat', value: true }]} * coHost="jane_doe" * roomName="MainRoom" * socket={socketInstance} * chatSetting="default" * /> * ); * } * * export default App; * ``` */ const MessagePanel = ({ messages, messagesLength, type, username, onSendMessagePress, backgroundColor = '#f5f5f5', focusedInput, showAlert, eventType, member, islevel, startDirectMessage, updateStartDirectMessage, directMessageDetails, updateDirectMessageDetails, coHostResponsibility, coHost, roomName, socket, chatSetting, }) => { const inputRef = useRef(null); const [replyInfo, setReplyInfo] = useState(null); const [senderId, setSenderId] = useState(null); const [directMessageText, setDirectMessageText] = useState(''); const [groupMessageText, setGroupMessageText] = useState(''); /** * Handles changes in the message input field. * @param {string} text - The text input value. */ const handleTextInputChange = (text) => { if (type === 'direct') { setDirectMessageText(text); } else { setGroupMessageText(text); } }; /** * Opens the reply input field for a specific sender. * @param {string} senderId - The username of the message sender. */ const openReplyInput = (senderId) => { const replyInfoContainer = { text: 'Replying to: ', username: senderId, }; setReplyInfo(replyInfoContainer); setSenderId(senderId); }; /** * Handles the sending of messages. */ const handleSendButton = async () => { const message = type === 'direct' ? directMessageText : groupMessageText; if (!message) { showAlert?.({ message: 'Please enter a message', type: 'danger', duration: 3000, }); return; } if (message.length > 350) { showAlert?.({ message: 'Message is too long', type: 'danger', duration: 3000, }); return; } if (message.trim() === '') { showAlert?.({ message: 'Message is not valid.', type: 'danger', duration: 3000, }); return; } if (type === 'direct' && !senderId && islevel === '2') { showAlert?.({ message: 'Please select a message to reply to', type: 'danger', duration: 3000, }); return; } try { await onSendMessagePress({ message, receivers: type === 'direct' ? [senderId] : [], group: type === 'group', messagesLength, member, sender: username, islevel, showAlert, coHostResponsibility, coHost, roomName, socket, chatSetting, }); if (type === 'direct') { setDirectMessageText(''); } else { setGroupMessageText(''); } if (inputRef.current) { inputRef.current.clear(); } if (replyInfo) { setReplyInfo(null); setSenderId(null); } if (focusedInput) { updateDirectMessageDetails(null); updateStartDirectMessage(false); } } catch { showAlert?.({ message: 'Failed to send message.', type: 'danger', duration: 3000, }); } }; useEffect(() => { if (startDirectMessage && directMessageDetails && focusedInput) { inputRef.current?.focus(); const replyInfoContainer = { text: 'Replying to: ', username: directMessageDetails.name, }; setReplyInfo(replyInfoContainer); setSenderId(directMessageDetails.name); } else { setReplyInfo(null); if (inputRef.current) { inputRef.current.clear(); } } }, [directMessageDetails, focusedInput, startDirectMessage]); return (<View style={[styles.container, { backgroundColor }]}> <ScrollView style={styles.messagesContainer}> {messages.map((message, index) => (<View key={index} style={styles.messageWrapper}> <View style={[ styles.messageContainer, message.sender === username ? styles.selfMessage : styles.otherMessage, ]}> <View style={styles.messageHeader}> {message.sender === username && !message.group && (<Text style={styles.receiverText}> To: {message.receivers.join(', ')} </Text>)} <Text style={styles.senderText}> {message.sender === username ? '' : message.sender} </Text> <Text style={styles.timestampText}>{message.timestamp}</Text> {message.sender !== username && !message.group && (<Pressable style={styles.replyButton} onPress={() => openReplyInput(message.sender)}> <FontAwesome5 name="reply" size={12} color="black"/> </Pressable>)} </View> <View style={[ message.sender === member ? styles.contentSelf : styles.contentOther, ]}> <Text style={styles.messageText}>{message.message}</Text> </View> </View> </View>))} {/* Reply Info */} {replyInfo && (<View style={styles.replyInfoContainer}> <Text style={styles.replyText}>{replyInfo.text}</Text> <Text style={styles.replyUsername}>{replyInfo.username}</Text> </View>)} </ScrollView> {/* Input Area */} <View style={styles.inputContainer}> <TextInput ref={focusedInput && startDirectMessage && directMessageDetails ? inputRef : null} style={styles.input} placeholder={type === 'direct' ? focusedInput && startDirectMessage && directMessageDetails ? `Send a direct message to ${directMessageDetails.name}` : 'Select a message to reply to' : eventType === 'chat' ? 'Send a message' : 'Send a message to everyone'} maxLength={350} multiline onChangeText={handleTextInputChange} value={type === 'direct' ? directMessageText : groupMessageText} placeholderTextColor="gray"/> <Pressable style={styles.sendButton} onPress={handleSendButton}> <FontAwesome5 name="paper-plane" size={16} color="white"/> </Pressable> </View> </View>); }; export default MessagePanel; /** * Stylesheet for the MessagePanel component. */ const styles = StyleSheet.create({ container: { flex: 1, padding: 10, }, messagesContainer: { flex: 1, marginBottom: 10, }, messageWrapper: { marginBottom: 5, }, messageContainer: { maxWidth: 200, padding: 5, borderRadius: 10, }, selfMessage: { flexDirection: 'column', alignSelf: 'flex-end', marginBottom: 5, }, otherMessage: { flexDirection: 'column', alignSelf: 'flex-start', marginBottom: 5, }, messageHeader: { flexDirection: 'row', justifyContent: 'space-between', marginBottom: 3, }, receiverText: { fontWeight: 'bold', color: 'black', fontSize: 8, marginLeft: 6, }, senderText: { fontWeight: 'bold', color: 'black', fontSize: 8, marginRight: 10, }, timestampText: { fontSize: 8, color: '#999999', }, replyButton: { padding: 2, marginLeft: 5, borderRadius: 2, backgroundColor: 'transparent', }, messageContent: { paddingTop: 5, }, messageText: { color: 'black', fontSize: 12, maxWidth: 300, }, replyInfoContainer: { flexDirection: 'row', alignItems: 'center', padding: 2, backgroundColor: '#e6e6e6', borderRadius: 5, marginBottom: 1, }, replyText: { fontWeight: 'bold', marginRight: 2, fontSize: 8, }, replyUsername: { color: 'red', fontSize: 8, }, inputContainer: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginTop: 'auto', borderTopWidth: 1, borderColor: '#cccccc', paddingTop: 2, }, input: { flex: 1, height: '100%', borderColor: 'gray', borderWidth: 1, borderRadius: 20, paddingLeft: 15, paddingRight: 15, backgroundColor: '#ffffff', color: 'black', fontSize: 14, justifyContent: 'center', alignItems: 'center', }, sendButton: { backgroundColor: '#83c0e9', padding: 10, borderRadius: 5, justifyContent: 'center', alignItems: 'center', }, contentSelf: { backgroundColor: '#DCF8C6', alignSelf: 'flex-end', padding: 10, borderRadius: 10, }, contentOther: { backgroundColor: '#1ce5c7', alignSelf: 'flex-start', padding: 10, borderRadius: 10, }, }); //# sourceMappingURL=MessagePanel.js.map