diff --git a/frontend/src/app/messages/page.tsx b/frontend/src/app/messages/page.tsx index 31bd6032..b6f3de30 100644 --- a/frontend/src/app/messages/page.tsx +++ b/frontend/src/app/messages/page.tsx @@ -5,7 +5,7 @@ import { AppShell } from "../../components/AppShell"; import { apiClient } from "@/lib/api"; import { resolveMediaUrl } from "@/lib/url"; import type { Chat } from "@/types/api"; -import { Search, MessageCircle, Pin, BellOff } from "lucide-react"; +import { Search, MessageCircle, Pin, BellOff, Filter } from "lucide-react"; import Link from "next/link"; import Image from "next/image"; import { useUser } from "@/contexts/UserContext"; @@ -167,6 +167,10 @@ export default function MessagesPage() { ); const [chats, setChats] = useState([]); const [search, setSearch] = useState(""); + const [chatTypeFilter, setChatTypeFilter] = useState("all"); + const [filterUnread, setFilterUnread] = useState<'all' | 'unread' | 'read'>('all'); + const [filterPinned, setFilterPinned] = useState<'all' | 'pinned' | 'unpinned'>('all'); + const [filtersOpen, setFiltersOpen] = useState(false); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); @@ -248,14 +252,62 @@ export default function MessagesPage() { return getChatSortTimestamp(b) - getChatSortTimestamp(a); }); - if (!q) return sorted; - + // Фильтруем по типу и поисковому запросу return sorted.filter((chat: Chat) => { - const title = getChatTitle(chat, currentUserId, currentUserForMatch).toLowerCase(); - const lastMessage = chat.last_message?.content?.toLowerCase() || ""; - return title.includes(q) || lastMessage.includes(q); + // Фильтр по типу чата + if (chatTypeFilter !== "all") { + const chatType = chat.chat_type || chat.type; + if (chatType !== chatTypeFilter) return false; + } + + // Фильтр по прочитанности + if (filterUnread === 'unread' && (chat.unread_count || 0) === 0) return false; + if (filterUnread === 'read' && (chat.unread_count || 0) > 0) return false; + + // Фильтр по закрепленности + if (filterPinned === 'pinned' && !chat.is_pinned) return false; + if (filterPinned === 'unpinned' && chat.is_pinned) return false; + + // Фильтр по поисковому запросу + if (q) { + const title = getChatTitle(chat, currentUserId, currentUserForMatch).toLowerCase(); + const lastMessage = chat.last_message?.content?.toLowerCase() || ""; + if (!title.includes(q) && !lastMessage.includes(q)) return false; + } + + return true; }); - }, [chats, currentUserForMatch, currentUserId, search]); + }, [chats, currentUserForMatch, currentUserId, search, chatTypeFilter, filterUnread, filterPinned]); + + // Подсчет чатов по типам + const chatTypeCounts = useMemo(() => { + const counts: Record = { + all: { total: chats.length, unread: 0 }, + global: { total: 0, unread: 0 }, + channel: { total: 0, unread: 0 }, + private: { total: 0, unread: 0 }, + group: { total: 0, unread: 0 }, + announcement: { total: 0, unread: 0 }, + }; + + chats.forEach((chat: Chat) => { + const chatType = chat.chat_type || chat.type; + const unreadCount = chat.unread_count || 0; + + if (unreadCount > 0) { + counts.all.unread += unreadCount; + } + + if (chatType && counts[chatType] !== undefined) { + counts[chatType].total++; + if (unreadCount > 0) { + counts[chatType].unread += unreadCount; + } + } + }); + + return counts; + }, [chats]); return ( @@ -270,14 +322,240 @@ export default function MessagesPage() { ) : (
-
- - setSearch(e.target.value)} - placeholder="Поиск по чатам" - className="w-full rounded-lg border border-gray-200 bg-gray-50 py-2.5 pl-9 pr-3 text-sm text-gray-800 transition focus:border-sky-500 focus:bg-white focus:outline-none focus:ring-2 focus:ring-sky-100" - /> + {/* Поиск и кнопка фильтров */} +
+
+ + setSearch(e.target.value)} + placeholder="Поиск по чатам" + className="w-full rounded-lg border border-gray-200 bg-gray-50 py-2.5 pl-9 pr-3 text-sm text-gray-800 transition focus:border-sky-500 focus:bg-white focus:outline-none focus:ring-2 focus:ring-sky-100" + /> +
+ +
+ + {/* Панель дополнительных фильтров */} + {filtersOpen && ( +
+ + + + + {(filterUnread !== 'all' || filterPinned !== 'all') && ( + + )} +
+ )} + + {/* Фильтры по типу чата с бэйджами */} +
+ + + {chatTypeCounts.global.total > 0 && ( + + )} + + {chatTypeCounts.channel.total > 0 && ( + + )} + + {chatTypeCounts.private.total > 0 && ( + + )} + + {chatTypeCounts.group.total > 0 && ( + + )} + + {chatTypeCounts.announcement.total > 0 && ( + + )}