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 && }
);
};