feat(chats): add per-user pinned chats and pinned sorting

This commit is contained in:
2026-03-08 09:54:43 +03:00
parent fdf973eeab
commit 8cdcd9531d
9 changed files with 139 additions and 4 deletions

View File

@@ -198,6 +198,16 @@ export async function unarchiveChat(chatId: number): Promise<Chat> {
return data;
}
export async function pinChat(chatId: number): Promise<Chat> {
const { data } = await http.post<Chat>(`/chats/${chatId}/pin-chat`);
return data;
}
export async function unpinChat(chatId: number): Promise<Chat> {
const { data } = await http.post<Chat>(`/chats/${chatId}/unpin-chat`);
return data;
}
export async function deleteMessage(messageId: number, forAll = false): Promise<void> {
await http.delete(`/messages/${messageId}`, { params: { for_all: forAll } });
}

View File

@@ -13,6 +13,7 @@ export interface Chat {
is_public?: boolean;
is_saved?: boolean;
archived?: boolean;
pinned?: boolean;
unread_count?: number;
pinned_message_id?: number | null;
members_count?: number | null;

View File

@@ -1,6 +1,6 @@
import { useEffect, useState } from "react";
import { createPortal } from "react-dom";
import { archiveChat, clearChat, createPrivateChat, deleteChat, getChats, joinChat, unarchiveChat } from "../api/chats";
import { archiveChat, clearChat, createPrivateChat, deleteChat, getChats, joinChat, pinChat, unarchiveChat, unpinChat } from "../api/chats";
import { globalSearch } from "../api/search";
import type { DiscoverChat, Message, UserSearchItem } from "../chat/types";
import { updateMyProfile } from "../api/users";
@@ -283,7 +283,7 @@ export function ChatList() {
>
<div className="flex items-start gap-3">
<div className="mt-0.5 flex h-10 w-10 items-center justify-center rounded-full bg-sky-500/30 text-sm font-semibold uppercase text-sky-100">
{(chat.display_title || chat.title || chat.type).slice(0, 1)}
{chat.pinned ? "📌" : (chat.display_title || chat.title || chat.type).slice(0, 1)}
</div>
<div className="min-w-0 flex-1">
<div className="flex items-center justify-between gap-2">
@@ -341,6 +341,29 @@ export function ChatList() {
>
{(chats.find((c) => c.id === ctxChatId) ?? archivedChats.find((c) => c.id === ctxChatId))?.archived ? "Unarchive" : "Archive"}
</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.pinned) {
await unpinChat(target.id);
} else {
await pinChat(target.id);
}
await loadChats();
if (tab === "archived") {
const nextArchived = await getChats(undefined, true);
setArchivedChats(nextArchived);
}
setCtxChatId(null);
setCtxPos(null);
}}
>
{(chats.find((c) => c.id === ctxChatId) ?? archivedChats.find((c) => c.id === ctxChatId))?.pinned ? "Unpin chat" : "Pin chat"}
</button>
</div>,
document.body
)