feat(chats): add per-user chat archive support
This commit is contained in:
@@ -8,9 +8,12 @@ export interface ChatNotificationSettings {
|
||||
muted: boolean;
|
||||
}
|
||||
|
||||
export async function getChats(query?: string): Promise<Chat[]> {
|
||||
export async function getChats(query?: string, archived = false): Promise<Chat[]> {
|
||||
const { data } = await http.get<Chat[]>("/chats", {
|
||||
params: query?.trim() ? { query: query.trim() } : undefined
|
||||
params: {
|
||||
...(query?.trim() ? { query: query.trim() } : {}),
|
||||
...(archived ? { archived: true } : {})
|
||||
}
|
||||
});
|
||||
return data;
|
||||
}
|
||||
@@ -185,6 +188,16 @@ export async function clearChat(chatId: number): Promise<void> {
|
||||
await http.post(`/chats/${chatId}/clear`);
|
||||
}
|
||||
|
||||
export async function archiveChat(chatId: number): Promise<Chat> {
|
||||
const { data } = await http.post<Chat>(`/chats/${chatId}/archive`);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function unarchiveChat(chatId: number): Promise<Chat> {
|
||||
const { data } = await http.post<Chat>(`/chats/${chatId}/unarchive`);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function deleteMessage(messageId: number, forAll = false): Promise<void> {
|
||||
await http.delete(`/messages/${messageId}`, { params: { for_all: forAll } });
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ export interface Chat {
|
||||
description?: string | null;
|
||||
is_public?: boolean;
|
||||
is_saved?: boolean;
|
||||
archived?: boolean;
|
||||
unread_count?: number;
|
||||
pinned_message_id?: number | null;
|
||||
members_count?: number | null;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import { clearChat, createPrivateChat, deleteChat, getChats, joinChat } from "../api/chats";
|
||||
import { archiveChat, clearChat, createPrivateChat, deleteChat, getChats, joinChat, unarchiveChat } from "../api/chats";
|
||||
import { globalSearch } from "../api/search";
|
||||
import type { DiscoverChat, Message, UserSearchItem } from "../chat/types";
|
||||
import { updateMyProfile } from "../api/users";
|
||||
@@ -20,8 +20,9 @@ export function ChatList() {
|
||||
const [userResults, setUserResults] = useState<UserSearchItem[]>([]);
|
||||
const [discoverResults, setDiscoverResults] = useState<DiscoverChat[]>([]);
|
||||
const [messageResults, setMessageResults] = useState<Message[]>([]);
|
||||
const [archivedChats, setArchivedChats] = useState<typeof chats>([]);
|
||||
const [searchLoading, setSearchLoading] = useState(false);
|
||||
const [tab, setTab] = useState<"all" | "people" | "groups" | "channels">("all");
|
||||
const [tab, setTab] = useState<"all" | "people" | "groups" | "channels" | "archived">("all");
|
||||
const [ctxChatId, setCtxChatId] = useState<number | null>(null);
|
||||
const [ctxPos, setCtxPos] = useState<{ x: number; y: number } | null>(null);
|
||||
const [deleteModalChatId, setDeleteModalChatId] = useState<number | null>(null);
|
||||
@@ -45,6 +46,28 @@ export function ChatList() {
|
||||
void loadChats();
|
||||
}, [loadChats]);
|
||||
|
||||
useEffect(() => {
|
||||
if (tab !== "archived") {
|
||||
return;
|
||||
}
|
||||
let cancelled = false;
|
||||
void (async () => {
|
||||
try {
|
||||
const rows = await getChats(undefined, true);
|
||||
if (!cancelled) {
|
||||
setArchivedChats(rows);
|
||||
}
|
||||
} catch {
|
||||
if (!cancelled) {
|
||||
setArchivedChats([]);
|
||||
}
|
||||
}
|
||||
})();
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [tab]);
|
||||
|
||||
useEffect(() => {
|
||||
const term = search.trim();
|
||||
if (term.replace("@", "").length < 2) {
|
||||
@@ -108,6 +131,9 @@ export function ChatList() {
|
||||
}, [me]);
|
||||
|
||||
const filteredChats = chats.filter((chat) => {
|
||||
if (chat.archived) {
|
||||
return false;
|
||||
}
|
||||
if (tab === "people") {
|
||||
return chat.type === "private";
|
||||
}
|
||||
@@ -120,13 +146,16 @@ export function ChatList() {
|
||||
return true;
|
||||
});
|
||||
|
||||
const tabs: Array<{ id: "all" | "people" | "groups" | "channels"; label: string }> = [
|
||||
const tabs: Array<{ id: "all" | "people" | "groups" | "channels" | "archived"; label: string }> = [
|
||||
{ id: "all", label: "All" },
|
||||
{ id: "people", label: "Люди" },
|
||||
{ id: "groups", label: "Groups" },
|
||||
{ id: "channels", label: "Каналы" }
|
||||
{ id: "channels", label: "Каналы" },
|
||||
{ id: "archived", label: "Архив" }
|
||||
];
|
||||
|
||||
const visibleChats = tab === "archived" ? archivedChats : filteredChats;
|
||||
|
||||
return (
|
||||
<aside className="relative flex h-full w-full max-w-xs flex-col bg-slate-900/60" onClick={() => { setCtxChatId(null); setCtxPos(null); }}>
|
||||
<div className="border-b border-slate-700/50 px-3 py-3">
|
||||
@@ -238,7 +267,7 @@ export function ChatList() {
|
||||
) : null}
|
||||
</div>
|
||||
<div className="tg-scrollbar flex-1 overflow-auto">
|
||||
{filteredChats.map((chat) => (
|
||||
{visibleChats.map((chat) => (
|
||||
<button
|
||||
className={`block w-full border-b border-slate-800/60 px-4 py-3 text-left transition ${
|
||||
activeChatId === chat.id ? "bg-sky-500/20" : "hover:bg-slate-800/65"
|
||||
@@ -291,6 +320,27 @@ export function ChatList() {
|
||||
>
|
||||
{chats.find((c) => c.id === ctxChatId)?.is_saved ? "Clear chat" : "Delete chat"}
|
||||
</button>
|
||||
<button
|
||||
className="block w-full rounded px-2 py-1.5 text-left text-sm hover:bg-slate-800"
|
||||
onClick={async () => {
|
||||
const target = chats.find((c) => c.id === ctxChatId) ?? archivedChats.find((c) => c.id === ctxChatId);
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
if (target.archived) {
|
||||
await unarchiveChat(target.id);
|
||||
} else {
|
||||
await archiveChat(target.id);
|
||||
}
|
||||
await loadChats();
|
||||
const nextArchived = await getChats(undefined, true);
|
||||
setArchivedChats(nextArchived);
|
||||
setCtxChatId(null);
|
||||
setCtxPos(null);
|
||||
}}
|
||||
>
|
||||
{(chats.find((c) => c.id === ctxChatId) ?? archivedChats.find((c) => c.id === ctxChatId))?.archived ? "Unarchive" : "Archive"}
|
||||
</button>
|
||||
</div>,
|
||||
document.body
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user