import React, { useContext, useEffect, useRef, useState } from 'react'; import { Platform, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { Channel, Group, MessageInput, MessageList, User, UserAdd, useTheme, } from 'stream-chat-react-native'; import { RoundButton } from '../components/RoundButton'; import { ScreenHeader } from '../components/ScreenHeader'; import { SelectedUserTag } from '../components/UserSearch/SelectedUserTag'; import { UserSearchResults } from '../components/UserSearch/UserSearchResults'; import { AppContext } from '../context/AppContext'; import { useUserSearchContext } from '../context/UserSearchContext'; import type { StackNavigationProp } from '@react-navigation/stack'; import type { Channel as StreamChatChannel } from 'stream-chat'; import { NewDirectMessagingSendButton } from '../components/NewDirectMessagingSendButton'; import type { LocalAttachmentType, LocalChannelType, LocalCommandType, LocalEventType, LocalMessageType, LocalReactionType, LocalUserType, StackNavigatorParamList, } from '../types'; const styles = StyleSheet.create({ container: { flex: 1, }, createGroupButtonContainer: { alignItems: 'center', flexDirection: 'row', paddingHorizontal: 8, paddingVertical: 16, }, createGroupButtonText: { fontSize: 14, fontWeight: '700', paddingLeft: 8, }, emptyMessageContainer: { alignItems: 'center', flex: 1, justifyContent: 'center', }, inputBox: { flex: 1, fontSize: 14, includeFontPadding: false, // for android vertical text centering padding: 0, // removal of default text input padding on android paddingRight: 16, paddingTop: 0, // removal of iOS top padding for weird centering textAlignVertical: 'center', // for android vertical text centering }, inputBoxContainer: { flexDirection: 'row', }, noChats: { fontSize: 12 }, searchContainer: { borderBottomWidth: 1, flexDirection: 'row', }, searchContainerLeft: { fontSize: 12, paddingHorizontal: 16, paddingVertical: 20, textAlignVertical: 'center', }, searchContainerMiddle: { flex: 1, justifyContent: 'center', }, searchContainerRight: { justifyContent: 'flex-end', paddingBottom: 16, paddingRight: 16, }, selectedUsersContainer: { flexDirection: 'row', flexWrap: 'wrap', }, }); const EmptyMessagesIndicator = () => { const { theme: { colors: { grey }, }, } = useTheme(); return ( No chats here yet... ); }; export type NewDirectMessagingScreenNavigationProp = StackNavigationProp< StackNavigatorParamList, 'NewDirectMessagingScreen' >; export type NewDirectMessagingScreenProps = { navigation: NewDirectMessagingScreenNavigationProp; }; export const NewDirectMessagingScreen: React.FC = ({ navigation, }) => { const { theme: { colors: { accent_blue, black, border, grey, white }, }, } = useTheme(); const { chatClient } = useContext(AppContext); const { onChangeSearchText, onFocusInput, reset, results, searchText, selectedUserIds, selectedUsers, toggleUser, } = useUserSearchContext(); const messageInputRef = useRef(null); const searchInputRef = useRef(null); const currentChannel = useRef< StreamChatChannel< LocalAttachmentType, LocalChannelType, LocalCommandType, LocalEventType, LocalMessageType, LocalReactionType, LocalUserType > >(); const isDraft = useRef(true); const [focusOnMessageInput, setFocusOnMessageInput] = useState(false); const [focusOnSearchInput, setFocusOnSearchInput] = useState(true); // As we don't use the state value, we can omit it here and separate it with a comma within the array. const [, setMessageInputText] = useState(''); // When selectedUsers are changed, initiate a channel with those users as members, // and set it as a channel on current screen. const selectedUsersLength = selectedUsers.length; useEffect(() => { const initChannel = async () => { if (!chatClient?.user?.id) return; // If there are no selected users, then set dummy channel. if (selectedUsers.length === 0) { setFocusOnMessageInput(false); return; } const members = [chatClient.user.id, ...selectedUserIds]; // Check if the channel already exists. const channels = await chatClient.queryChannels({ distinct: true, members, }); if (channels.length === 1) { // Channel already exist currentChannel.current = channels[0]; isDraft.current = false; } else { // Channel doesn't exist. isDraft.current = true; const channel = chatClient.channel('messaging', { members, }); // Hack to trick channel component into accepting channel without watching it. channel.initialized = true; currentChannel.current = channel; } if (messageInputRef.current) { messageInputRef.current.focus(); } setFocusOnMessageInput(true); }; initChannel(); }, [selectedUsersLength]); const renderUserSearch = ({ inSafeArea }: { inSafeArea: boolean }) => ( { setFocusOnMessageInput(false); setFocusOnSearchInput(true); if (searchInputRef.current) { searchInputRef.current.focus(); } }} style={[ styles.searchContainer, { backgroundColor: white, borderBottomColor: border, }, ]} > TO: {selectedUsers.map((tag, index) => { const tagProps = { disabled: !focusOnSearchInput, index, onPress: () => { toggleUser(tag); }, tag, }; return ; })} {focusOnSearchInput && ( )} {selectedUsers.length === 0 ? : } {focusOnSearchInput && !searchText && selectedUsers.length === 0 && ( { navigation.push('NewGroupChannelAddMemberScreen'); }} style={styles.createGroupButtonContainer} > Create a Group )} {results && focusOnSearchInput && ( { setFocusOnSearchInput(false); toggleUser(user); }} /> )} ); if (!chatClient) return null; if (!currentChannel.current) { return renderUserSearch({ inSafeArea: false }); } return ( additionalTextInputProps={{ onFocus: () => { setFocusOnMessageInput(true); setFocusOnSearchInput(false); if (messageInputRef.current) { messageInputRef.current.focus(); } }, }} channel={currentChannel.current} EmptyStateIndicator={EmptyMessagesIndicator} enforceUniqueReaction keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : -300} onChangeText={setMessageInputText} SendButton={NewDirectMessagingSendButton} setInputRef={(ref) => (messageInputRef.current = ref)} > {renderUserSearch({ inSafeArea: true })} {results && results.length >= 0 && !focusOnSearchInput && focusOnMessageInput && ( )} {selectedUsers.length > 0 && } ); };