Corp/frontend/src/hooks/useMessagesDirectory.ts

110 lines
3.8 KiB
TypeScript

"use client";
import { useMemo } from "react";
import { useUser } from "@/contexts/UserContext";
import {
type ChatIdentity,
getChatLastMessagePreview,
getChatTitle,
isDepartmentCommentsChat,
} from "@/lib/messages/chatUtils";
import type { Chat } from "@/types/api";
import { useMessagesChatList } from "@/hooks/useMessagesChatList";
import { useMessagesListFilters } from "@/hooks/useMessagesListFilters";
export type MessageChatTypeCounts = Record<string, { total: number; unread: number }>;
function chatTimestamp(chat: Chat): number {
const lastMessage = chat.last_message;
if (typeof lastMessage?.created_ts === "number") return lastMessage.created_ts;
const raw = lastMessage?.created_at || lastMessage?.created || chat.created_at;
const timestamp = new Date(raw).getTime();
return Number.isNaN(timestamp) ? 0 : timestamp;
}
export function useMessagesDirectory() {
const { user } = useUser();
const { search, chatTypeFilter, filterUnread, filterPinned } = useMessagesListFilters(user?.id);
const { chats: allChats, loading, error, refreshChat } = useMessagesChatList(user?.id);
const identity = useMemo<ChatIdentity>(() => ({
first_name: user?.first_name,
last_name: user?.last_name,
patronymic: user?.patronymic,
email: user?.email,
}), [user?.email, user?.first_name, user?.last_name, user?.patronymic]);
const departmentIds = useMemo(
() => new Set((user?.departments || []).map((department) => department.id)),
[user?.departments],
);
const chats = useMemo(
() => allChats.filter((chat) => {
const type = chat.chat_type || chat.type;
if (type !== "comments") return true;
return isDepartmentCommentsChat(chat)
&& typeof chat.context_object_id === "number"
&& departmentIds.has(chat.context_object_id);
}),
[allChats, departmentIds],
);
const visibleChats = useMemo(() => {
const query = search.trim().toLowerCase();
return [...chats]
.sort((a, b) => Number(Boolean(b.is_pinned)) - Number(Boolean(a.is_pinned)) || chatTimestamp(b) - chatTimestamp(a))
.filter((chat) => {
const type = chat.chat_type || chat.type;
const unread = chat.unread_count || 0;
if (chatTypeFilter !== "all" && type !== chatTypeFilter) return false;
if (filterUnread === "unread" && unread === 0) return false;
if (filterUnread === "read" && unread > 0) return false;
if (filterPinned === "pinned" && !chat.is_pinned) return false;
if (filterPinned === "unpinned" && chat.is_pinned) return false;
if (!query) return true;
const title = getChatTitle(chat, user?.id, identity).toLowerCase();
const lastMessagePreview = chat.last_message
? getChatLastMessagePreview(chat).toLowerCase()
: "";
return title.includes(query) || lastMessagePreview.includes(query);
});
}, [chatTypeFilter, chats, filterPinned, filterUnread, identity, search, user?.id]);
const chatTypeCounts = useMemo<MessageChatTypeCounts>(() => {
const counts: MessageChatTypeCounts = {
all: { total: chats.length, unread: 0 },
global: { total: 0, unread: 0 },
channel: { total: 0, unread: 0 },
comments: { total: 0, unread: 0 },
private: { total: 0, unread: 0 },
group: { total: 0, unread: 0 },
announcement: { total: 0, unread: 0 },
};
chats.forEach((chat) => {
const type = chat.chat_type || chat.type;
const unread = chat.unread_count || 0;
if (unread > 0) counts.all.unread += unread;
if (!type || !counts[type]) return;
counts[type].total += 1;
if (unread > 0) counts[type].unread += unread;
});
return counts;
}, [chats]);
return {
user,
identity,
visibleChats,
chatTypeCounts,
loading,
error,
refreshChat,
};
}