feat: add saved messages, public chat discovery/join, and chat delete options
All checks were successful
CI / test (push) Successful in 19s
All checks were successful
CI / test (push) Successful in 19s
- add Saved Messages system chat with dedicated API - add public group/channel metadata and discover/join endpoints - add chat delete flow with for_all option and channel-wide delete - switch message actions to context menu and improve reply/forward visuals - improve microphone permission handling for voice recording
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { deleteChat } from "../api/chats";
|
||||
import { useAuthStore } from "../store/authStore";
|
||||
import { useChatStore } from "../store/chatStore";
|
||||
import { NewChatPanel } from "./NewChatPanel";
|
||||
@@ -12,6 +13,10 @@ export function ChatList() {
|
||||
const me = useAuthStore((s) => s.me);
|
||||
const [search, setSearch] = useState("");
|
||||
const [tab, setTab] = useState<"all" | "people" | "groups" | "channels">("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);
|
||||
const [deleteForAll, setDeleteForAll] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
@@ -41,7 +46,7 @@ export function ChatList() {
|
||||
];
|
||||
|
||||
return (
|
||||
<aside className="relative flex h-full w-full max-w-xs flex-col bg-slate-900/60">
|
||||
<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">
|
||||
<div className="mb-2 flex items-center gap-2">
|
||||
<button className="rounded-lg bg-slate-700/70 px-2 py-2 text-xs">☰</button>
|
||||
@@ -77,6 +82,11 @@ export function ChatList() {
|
||||
}`}
|
||||
key={chat.id}
|
||||
onClick={() => setActiveChatId(chat.id)}
|
||||
onContextMenu={(e) => {
|
||||
e.preventDefault();
|
||||
setCtxChatId(chat.id);
|
||||
setCtxPos({ x: e.clientX, y: e.clientY });
|
||||
}}
|
||||
>
|
||||
<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">
|
||||
@@ -96,6 +106,52 @@ export function ChatList() {
|
||||
))}
|
||||
</div>
|
||||
<NewChatPanel />
|
||||
|
||||
{ctxChatId && ctxPos ? (
|
||||
<div className="fixed z-50 w-44 rounded-lg border border-slate-700/80 bg-slate-900/95 p-1 shadow-2xl" style={{ left: ctxPos.x, top: ctxPos.y }} onClick={(e) => e.stopPropagation()}>
|
||||
<button
|
||||
className="block w-full rounded px-2 py-1.5 text-left text-sm text-red-300 hover:bg-slate-800"
|
||||
onClick={() => {
|
||||
setDeleteModalChatId(ctxChatId);
|
||||
setCtxChatId(null);
|
||||
setCtxPos(null);
|
||||
setDeleteForAll(false);
|
||||
}}
|
||||
>
|
||||
Delete chat
|
||||
</button>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{deleteModalChatId ? (
|
||||
<div className="absolute inset-0 z-50 flex items-end justify-center bg-slate-950/55 p-3">
|
||||
<div className="w-full rounded-xl border border-slate-700/80 bg-slate-900 p-3">
|
||||
<p className="mb-2 text-sm font-semibold">Delete chat #{deleteModalChatId}</p>
|
||||
<label className="mb-3 flex items-center gap-2 text-sm">
|
||||
<input checked={deleteForAll} onChange={(e) => setDeleteForAll(e.target.checked)} type="checkbox" />
|
||||
Delete for everyone
|
||||
</label>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
className="flex-1 rounded bg-red-500 px-3 py-2 text-sm font-semibold text-white"
|
||||
onClick={async () => {
|
||||
await deleteChat(deleteModalChatId, deleteForAll);
|
||||
await loadChats(search.trim() ? search : undefined);
|
||||
if (activeChatId === deleteModalChatId) {
|
||||
setActiveChatId(null);
|
||||
}
|
||||
setDeleteModalChatId(null);
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
<button className="flex-1 rounded bg-slate-700 px-3 py-2 text-sm" onClick={() => setDeleteModalChatId(null)}>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user