123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 |
- import React, { useState, useEffect, useRef, useCallback } from 'react';
- import {
- View,
- Text,
- TouchableOpacity,
- StyleSheet,
- Image,
- Platform,
- TouchableHighlight
- } from 'react-native';
- import { HorizontalTabView, Input, PageWrapper } from 'src/components';
- import { NAVIGATION_PAGES } from 'src/types';
- import { useFocusEffect, useNavigation } from '@react-navigation/native';
- import AddChatIcon from 'assets/icons/messages/chat-plus.svg';
- import { API_HOST } from 'src/constants';
- import { Colors } from 'src/theme';
- import { getFontSize } from 'src/utils';
- import SwipeableRow from './Components/SwipeableRow';
- import { FlashList } from '@shopify/flash-list';
- import ReadIcon from 'assets/icons/messages/check-read.svg';
- import UnreadIcon from 'assets/icons/messages/check-unread.svg';
- import SearchModal from './Components/SearchUsersModal';
- import { SheetManager } from 'react-native-actions-sheet';
- import MoreModal from './Components/MoreModal';
- import SearchIcon from 'assets/icons/search.svg';
- import { storage, StoreType } from 'src/storage';
- import { usePostGetChatsListQuery } from '@api/chat';
- import moment from 'moment';
- import { Chat } from './types';
- import PinIcon from 'assets/icons/messages/pin.svg';
- type Routes = {
- key: 'all' | 'unread' | 'archived';
- title: string;
- };
- const MessagesScreen = () => {
- const navigation = useNavigation();
- const token = storage.get('token', StoreType.STRING) as string;
- const { data: chatsData, refetch } = usePostGetChatsListQuery(token, 0, true);
- const [chats, setChats] = useState<Chat[]>([]);
- const [index, setIndex] = useState(0);
- const [filteredChats, setFilteredChats] = useState<Chat[]>([]);
- const [search, setSearch] = useState('');
- const openRowRef = useRef<any>(null);
- const routes: Routes[] = [
- { key: 'all', title: 'All' },
- { key: 'unread', title: 'Unread' },
- { key: 'archived', title: 'Archived' }
- ];
- const handleRowOpen = (ref: any) => {
- if (openRowRef.current && openRowRef.current !== ref) {
- openRowRef.current.close();
- }
- openRowRef.current = ref;
- };
- useFocusEffect(() => {
- navigation.getParent()?.setOptions({
- tabBarStyle: {
- display: 'flex',
- ...Platform.select({
- android: {
- height: 58
- }
- })
- }
- });
- });
- useEffect(() => {
- if (chatsData && chatsData.conversations) {
- setChats(chatsData.conversations);
- }
- }, [chatsData]);
- useFocusEffect(
- useCallback(() => {
- refetch();
- }, [])
- );
- const filterChatsByTab = () => {
- if (index === 1) {
- setFilteredChats(
- chats
- .filter((chat: Chat) => chat.unread_count > 0)
- .sort((a: Chat, b: Chat) => b.pin - a.pin || b.pin_order - a.pin_order)
- );
- } else if (index === 2) {
- setFilteredChats([]);
- } else {
- setFilteredChats(
- chats.sort((a: Chat, b: Chat) => b.pin - a.pin || b.pin_order - a.pin_order)
- );
- }
- };
- useEffect(() => {
- filterChatsByTab();
- }, [index, chats]);
- const handleDeleteChat = (id: number) => {
- const updatedChats = chats.filter((chat: Chat) => chat.uid !== id);
- setChats(updatedChats);
- };
- const searchFilter = (text: string) => {
- if (text) {
- const newData =
- chats?.filter((item: Chat) => {
- const itemData = item.short ? item.short.toLowerCase() : ''.toLowerCase();
- const textData = text.toLowerCase();
- return itemData.indexOf(textData) > -1;
- }) ?? [];
- setFilteredChats(newData);
- setSearch(text);
- } else {
- filterChatsByTab();
- setSearch(text);
- }
- };
- const formatDate = (dateString: Date) => {
- const inputDate = moment.utc(dateString).local();
- const today = moment().local();
- const yesterday = moment().local().subtract(1, 'days');
- if (inputDate.isSame(today, 'day')) {
- return inputDate.format('HH:mm');
- }
- if (inputDate.isSame(yesterday, 'day')) {
- return 'yesterday';
- }
- if (!inputDate.isSame(today, 'year')) {
- return inputDate.format('DD.MM.YYYY');
- }
- return inputDate.format('DD.MM');
- };
- const renderChatItem = ({ item }: { item: Chat }) => {
- return (
- <SwipeableRow
- chat={{ id: item.uid, name: item.name, avatar: item.avatar, pin: item.pin }}
- onRowOpen={handleRowOpen}
- refetch={refetch}
- >
- <TouchableHighlight
- activeOpacity={0.8}
- onPress={() =>
- navigation.navigate(
- ...([
- NAVIGATION_PAGES.CHAT,
- {
- id: item.uid,
- name: item.name,
- avatar: item.avatar
- }
- ] as never)
- )
- }
- underlayColor={Colors.FILL_LIGHT}
- >
- <View style={styles.chatItem}>
- <Image source={{ uri: API_HOST + item.avatar }} style={styles.avatar} />
- <View style={{ flex: 1, gap: 6 }}>
- <View style={[styles.rowContainer, { alignItems: 'center' }]}>
- <Text style={styles.chatName}>{item.name}</Text>
- <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
- {item.pin === 1 ? <PinIcon height={12} fill={Colors.DARK_BLUE} /> : null}
- {item.sent_by !== item.uid && item.status === 3 ? (
- <ReadIcon fill={Colors.DARK_BLUE} />
- ) : item.sent_by !== item.uid && (item.status === 2 || item.status === 1) ? (
- <UnreadIcon fill={Colors.LIGHT_GRAY} />
- ) : null}
- <Text style={styles.chatTime}>{formatDate(item.updated)}</Text>
- </View>
- </View>
- <View style={[styles.rowContainer, { flex: 1, gap: 6 }]}>
- <Text numberOfLines={2} style={styles.chatMessage}>
- {item.short}
- </Text>
- {item.unread_count > 0 ? (
- <View style={styles.unreadBadge}>
- <Text style={styles.unreadText}>
- {item.unread_count > 99 ? '99+' : item.unread_count}
- </Text>
- </View>
- ) : null}
- </View>
- </View>
- </View>
- </TouchableHighlight>
- </SwipeableRow>
- );
- };
- return (
- <PageWrapper style={{ flex: 1, marginLeft: 0, marginRight: 0, gap: 12 }}>
- <View style={styles.header}>
- <View style={{ width: 30 }} />
- <Text style={styles.title}>Messages</Text>
- <TouchableOpacity
- onPress={() => SheetManager.show('search-modal')}
- style={{ width: 30, alignItems: 'flex-end' }}
- >
- <AddChatIcon />
- </TouchableOpacity>
- </View>
- <View style={[{ paddingHorizontal: '4%' }]}>
- <Input
- inputMode={'search'}
- placeholder={'Search'}
- onChange={(text) => searchFilter(text)}
- value={search}
- icon={<SearchIcon fill={'#C8C8C8'} width={14} height={14} />}
- height={38}
- />
- </View>
- <HorizontalTabView
- index={index}
- setIndex={setIndex}
- routes={routes}
- tabBarStyle={{ paddingHorizontal: '4%' }}
- renderScene={({ route }: { route: any }) => (
- <FlashList
- viewabilityConfig={{
- waitForInteraction: true,
- itemVisiblePercentThreshold: 50,
- minimumViewTime: 1000
- }}
- data={filteredChats}
- renderItem={renderChatItem}
- keyExtractor={(item, index) => `${item.uid}-${index}`}
- estimatedItemSize={78}
- removeClippedSubviews={true}
- />
- )}
- />
- <SearchModal />
- <MoreModal />
- </PageWrapper>
- );
- };
- const styles = StyleSheet.create({
- title: { color: Colors.DARK_BLUE, fontFamily: 'redhat-700', fontSize: getFontSize(14) },
- header: {
- alignItems: 'center',
- paddingVertical: 16,
- flexDirection: 'row',
- justifyContent: 'space-between',
- marginLeft: '5%',
- marginRight: '5%'
- },
- chatItem: {
- flexDirection: 'row',
- paddingVertical: 12,
- backgroundColor: Colors.WHITE,
- borderBottomWidth: 1,
- borderBottomColor: Colors.FILL_LIGHT,
- gap: 8,
- paddingHorizontal: '4%'
- },
- avatar: {
- width: 54,
- height: 54,
- borderRadius: 27,
- borderWidth: 1,
- borderColor: Colors.FILL_LIGHT
- },
- rowContainer: {
- flexDirection: 'row',
- alignItems: 'center',
- justifyContent: 'space-between'
- },
- chatName: {
- flex: 1,
- fontFamily: 'montserrat-700',
- fontSize: getFontSize(14),
- color: Colors.DARK_BLUE
- },
- chatMessage: {
- flex: 1,
- fontSize: getFontSize(12),
- fontWeight: '600',
- color: Colors.DARK_BLUE,
- height: '100%'
- },
- chatTimeContainer: {
- justifyContent: 'center',
- alignItems: 'flex-end'
- },
- chatTime: {
- fontSize: getFontSize(12),
- fontWeight: '600',
- color: Colors.LIGHT_GRAY
- },
- unreadBadge: {
- backgroundColor: Colors.ORANGE,
- borderRadius: 9,
- paddingHorizontal: 6,
- alignItems: 'center',
- justifyContent: 'center',
- height: 18,
- minWidth: 18
- },
- unreadText: {
- color: Colors.WHITE,
- fontSize: getFontSize(11),
- fontFamily: 'montserrat-700'
- },
- swipeActions: {
- flexDirection: 'row',
- alignItems: 'center'
- },
- swipeButton: {
- paddingHorizontal: 20
- }
- });
- export default MessagesScreen;
|