100 lines
3.5 KiB
JavaScript
100 lines
3.5 KiB
JavaScript
import { useEffect, useState, useCallback } from "react";
|
||
import { useNavigate } from "react-router-dom";
|
||
import { useTranslation } from 'react-i18next';
|
||
import { useChats } from "../hooks/useChats";
|
||
import { useAuthContext } from "../context/AuthContext";
|
||
import { useUnread } from "../context/UnreadContext";
|
||
import { getPostForChat } from "../stores/chatPostStore";
|
||
import { useDeleteChat } from "../hooks/useDeleteChat";
|
||
import ChatHeader from "../components/chat/ChatHeader";
|
||
import ChatListItem from "../components/chat/ChatListItem";
|
||
import Toast from "../components/Toast";
|
||
|
||
export default function ChatListPage() {
|
||
const { t } = useTranslation();
|
||
const navigate = useNavigate();
|
||
const { chats, loading, fetchChats } = useChats();
|
||
const { isAuthenticated } = useAuthContext();
|
||
const { unreadMap, totalUnread } = useUnread();
|
||
const { deleteChat } = useDeleteChat();
|
||
const [deleteError, setDeleteError] = useState("");
|
||
|
||
useEffect(() => {
|
||
if (isAuthenticated) {
|
||
fetchChats();
|
||
}
|
||
}, [isAuthenticated, fetchChats]);
|
||
|
||
// При поступлении непрочитанного сообщения (WS) обновляем список, чтобы
|
||
// превью показывало новое сообщение и подсветку, не дожидаясь ручного обновления.
|
||
useEffect(() => {
|
||
if (!isAuthenticated) return;
|
||
const timer = setTimeout(() => fetchChats(), 500);
|
||
return () => clearTimeout(timer);
|
||
// totalUnread — числовое значение, поэтому изменение состава чатов с той же
|
||
// суммой не создаст цикл обновлений.
|
||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||
}, [totalUnread, isAuthenticated, fetchChats]);
|
||
|
||
const handleDeleteChat = useCallback(async (chatId) => {
|
||
if (!window.confirm(t('chat.confirmDeleteChat'))) return;
|
||
const result = await deleteChat(chatId);
|
||
if (result.success) {
|
||
fetchChats();
|
||
} else {
|
||
setDeleteError(result.error);
|
||
}
|
||
}, [t, deleteChat, fetchChats]);
|
||
|
||
const goBack = () => navigate("/feed");
|
||
const openChat = (chatId) => navigate(`/chats/${chatId}`);
|
||
|
||
if (!isAuthenticated) {
|
||
return (
|
||
<div className="f-app">
|
||
<div className="chat-page">
|
||
<ChatHeader title={t('chat.chats')} onBack={goBack} />
|
||
<div className="chat-empty-full">{t('chat.loginToSee')}</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<div className="f-app">
|
||
<div className="chat-page">
|
||
<ChatHeader title={t('chat.chats')} onBack={goBack} />
|
||
|
||
<div className="chat-list">
|
||
{loading && (
|
||
<div className="chat-empty-full">{t('chat.loading')}</div>
|
||
)}
|
||
|
||
{!loading && chats.length === 0 && (
|
||
<div className="chat-empty-full">{t('chat.noChats')}</div>
|
||
)}
|
||
|
||
{!loading && chats.map((chat) => (
|
||
<ChatListItem
|
||
key={chat.id}
|
||
chat={chat}
|
||
post={getPostForChat(chat.id)}
|
||
unreadMap={unreadMap}
|
||
t={t}
|
||
onOpen={openChat}
|
||
onDelete={handleDeleteChat}
|
||
/>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{deleteError && (
|
||
<Toast
|
||
message={deleteError}
|
||
type="error"
|
||
onDismiss={() => setDeleteError("")}
|
||
/>
|
||
)}
|
||
</div>
|
||
);
|
||
} |