Yevhen Romanenko
9 months ago
11 changed files with 16284 additions and 16036 deletions
Binary file not shown.
Binary file not shown.
@ -0,0 +1,267 @@
@@ -0,0 +1,267 @@
|
||||
/* eslint-disable react/no-unstable-nested-components */ |
||||
import React, { useCallback } from 'react' |
||||
import { |
||||
$size, |
||||
Avatar, |
||||
IShortUser, |
||||
IconComponent, |
||||
RouteKey, |
||||
ScreenLayout, |
||||
SearchForm, |
||||
Txt, |
||||
appEvents, |
||||
hasImageUrl, |
||||
useNav, |
||||
useTheme, |
||||
} from '@/shared' |
||||
import { useFetchUsersList } from '@/modules/users/hooks' |
||||
import { |
||||
TouchableOpacity, |
||||
StyleSheet, |
||||
FlatList, |
||||
ActivityIndicator, |
||||
Platform, |
||||
View, |
||||
} from 'react-native' |
||||
import { PartialTheme } from '@/shared/themes/interfaces' |
||||
import { chatManager } from '@/managers' |
||||
import { simpleDispatch } from '@/store/store-helpers' |
||||
import { SelectChat } from '@/store/chats' |
||||
import { useSelector } from 'react-redux' |
||||
import { selectAccount } from '@/store/account' |
||||
import _ from 'lodash' |
||||
|
||||
export const CreateConversationScreen = () => { |
||||
const account = useSelector(selectAccount) |
||||
const nav = useNav() |
||||
const { styles, theme, themeTitle } = useTheme(createStyles) |
||||
const { |
||||
items, |
||||
searchString, |
||||
setSearchVal, |
||||
loadMore, |
||||
resetFlatList, |
||||
isLoading, |
||||
isLoadingNext, |
||||
} = useFetchUsersList({ |
||||
type: 'all', |
||||
execludeUserId: [account.id], |
||||
}) |
||||
|
||||
const onPressMessage = async userId => { |
||||
try { |
||||
const chatId = await chatManager.getPersonalChatId({ |
||||
userId, |
||||
}) |
||||
simpleDispatch(new SelectChat({ id: chatId })) |
||||
chatManager.readChat.bind(chatManager)(chatId) |
||||
|
||||
nav.navigate(RouteKey.Conversation) |
||||
} catch (e) { |
||||
appEvents.emit('openInfoModal', { |
||||
title: 'Сталась помилка!', |
||||
message: 'Спробуйте будь-ласка пізніше.', |
||||
onPressOk: () => {}, |
||||
}) |
||||
} |
||||
} |
||||
|
||||
const checkSelectedUsersAndContinue = (selectedUsers: IShortUser[]) => { |
||||
if (_.isEmpty(selectedUsers)) |
||||
appEvents.emit('openInfoModal', { |
||||
title: 'Виберіть учасників.', |
||||
message: 'Хоча б один користувач повинен бути вибраний', |
||||
onPressOk: () => {}, |
||||
}) |
||||
else nav.navigate(RouteKey.CreateGroup) |
||||
} |
||||
|
||||
const onCreateGroupPress = () => { |
||||
nav.navigate(RouteKey.SelectUsersScreen, { |
||||
title: 'Нова група', |
||||
isLoading: false, |
||||
footerBtnTitle: 'Далі', |
||||
onSubmit: checkSelectedUsersAndContinue, |
||||
useChatBtnColors: true, |
||||
excludeIds: [account.id], |
||||
resetOnGoBack: true, |
||||
type: 'all', |
||||
}) |
||||
} |
||||
|
||||
const renderItem = useCallback( |
||||
({ item, index }: { item: IShortUser; index: number }) => { |
||||
return ( |
||||
<TouchableOpacity |
||||
style={[ |
||||
styles.container, |
||||
index === 0 |
||||
? { borderTopColor: theme.$layoutBg } |
||||
: null, |
||||
]} |
||||
onPress={() => onPressMessage(item.id)}> |
||||
<Avatar |
||||
imageUrl={hasImageUrl(item.avatarUrl, item.fullName)} |
||||
maxHeight={$size(35, 32)} |
||||
maxWidth={$size(35, 32)} |
||||
textStyle={styles.avatarLabel} |
||||
/> |
||||
<Txt style={styles.userName}>{item.fullName}</Txt> |
||||
<IconComponent |
||||
name="chatcircledots-1" |
||||
size={24} |
||||
color="#9F2843" |
||||
/> |
||||
</TouchableOpacity> |
||||
) |
||||
}, |
||||
[], |
||||
) |
||||
|
||||
const renderFooter = useCallback(() => { |
||||
if (!isLoading && isLoadingNext) |
||||
return ( |
||||
<ActivityIndicator |
||||
color={theme.$loaderPrimary} |
||||
style={{ marginTop: 20 }} |
||||
/> |
||||
) |
||||
else return null |
||||
}, [isLoading, isLoadingNext, theme]) |
||||
|
||||
const renderEmpty = useCallback(() => { |
||||
if (isLoading || isLoadingNext) { |
||||
return <ActivityIndicator color={theme.$loaderPrimary} /> |
||||
} else { |
||||
return <Txt style={styles.emptyText}>Користувачі відсутні</Txt> |
||||
} |
||||
}, [isLoading, isLoadingNext]) |
||||
|
||||
const renderGroupChatHeader = useCallback(() => { |
||||
return ( |
||||
<TouchableOpacity |
||||
style={styles.conversationContainer} |
||||
onPress={onCreateGroupPress}> |
||||
<View |
||||
style={[ |
||||
styles.conversationIconContainer, |
||||
themeTitle === 'dark' |
||||
? styles.borderedIconContainer |
||||
: null, |
||||
]}> |
||||
<IconComponent |
||||
name="group-conversation" |
||||
color={theme.chats.header.rightIcon.$icon} |
||||
size={$size(18)} |
||||
/> |
||||
</View> |
||||
<Txt style={{ color: theme.$textPrimary }}>{'Нова група'}</Txt> |
||||
</TouchableOpacity> |
||||
) |
||||
}, [theme]) |
||||
|
||||
const keyExtractor = useCallback(item => `${item.id}`, []) |
||||
|
||||
return ( |
||||
<ScreenLayout |
||||
horizontalPadding={0} |
||||
header={{ |
||||
goBack: nav.goBack, |
||||
title: 'Нова бесіда', |
||||
style: { |
||||
marginBottom: $size(20, 18), |
||||
paddingTop: $size(10, 10), |
||||
}, |
||||
}}> |
||||
<> |
||||
<SearchForm |
||||
containerStyle={styles.searchContainer} |
||||
searchValue={searchString} |
||||
placeholder={'Знайдіть контакт'} |
||||
onChange={setSearchVal} |
||||
/> |
||||
<FlatList |
||||
style={{ flex: 1 }} |
||||
data={items} |
||||
renderItem={renderItem} |
||||
contentContainerStyle={{ paddingHorizontal: $size(16) }} |
||||
keyExtractor={keyExtractor} |
||||
initialNumToRender={10} |
||||
onEndReachedThreshold={0.4} |
||||
refreshing={Platform.select({ |
||||
ios: false, |
||||
android: isLoading, |
||||
})} |
||||
onEndReached={loadMore} |
||||
onRefresh={resetFlatList} |
||||
showsVerticalScrollIndicator={false} |
||||
showsHorizontalScrollIndicator={false} |
||||
ListEmptyComponent={renderEmpty} |
||||
ListFooterComponent={renderFooter} |
||||
ListHeaderComponent={renderGroupChatHeader} |
||||
/> |
||||
</> |
||||
</ScreenLayout> |
||||
) |
||||
} |
||||
|
||||
const createStyles = (theme: PartialTheme) => |
||||
StyleSheet.create({ |
||||
container: { |
||||
flexDirection: 'row', |
||||
alignItems: 'center', |
||||
height: $size(65, 60), |
||||
borderTopWidth: 0.3, |
||||
borderTopColor: theme.$border, |
||||
}, |
||||
|
||||
userName: { |
||||
fontSize: $size(16, 14), |
||||
fontWeight: '400', |
||||
marginLeft: $size(20, 16), |
||||
marginRight: 'auto', |
||||
color: theme.$textPrimary, |
||||
}, |
||||
|
||||
checkBox: { |
||||
position: 'absolute', |
||||
right: 0, |
||||
alignItems: 'center', |
||||
justifyContent: 'center', |
||||
}, |
||||
|
||||
searchContainer: { |
||||
borderBottomWidth: 0, |
||||
}, |
||||
|
||||
conversationContainer: { |
||||
flexDirection: 'row', |
||||
justifyContent: 'flex-start', |
||||
alignItems: 'center', |
||||
height: $size(50), |
||||
gap: $size(10), |
||||
borderRadius: $size(10), |
||||
backgroundColor: theme.chats.$elementsBg, |
||||
paddingHorizontal: $size(16), |
||||
marginVertical: $size(5), |
||||
}, |
||||
|
||||
conversationIconContainer: { |
||||
alignItems: 'center', |
||||
justifyContent: 'center', |
||||
backgroundColor: theme.chats.header.rightIcon.$bg, |
||||
width: $size(32), |
||||
height: $size(32), |
||||
borderRadius: $size(16), |
||||
}, |
||||
|
||||
borderedIconContainer: { |
||||
borderWidth: 1, |
||||
borderColor: theme.chats.header.rightIcon.$border, |
||||
}, |
||||
|
||||
avatarLabel: { |
||||
fontSize: $size(20, 18), |
||||
fontWeight: '500', |
||||
}, |
||||
}) |
Loading…
Reference in new issue