web: add multi-message forward from selection
Some checks failed
CI / test (push) Has been cancelled

This commit is contained in:
Codex
2026-03-09 13:42:58 +03:00
parent e992f1e26d
commit 7cf6be6515

View File

@@ -63,7 +63,7 @@ export function MessageList() {
const showToast = useUiStore((s) => s.showToast); const showToast = useUiStore((s) => s.showToast);
const [ctx, setCtx] = useState<ContextMenuState>(null); const [ctx, setCtx] = useState<ContextMenuState>(null);
const [forwardMessageId, setForwardMessageId] = useState<number | null>(null); const [forwardMessageIds, setForwardMessageIds] = useState<number[]>([]);
const [forwardQuery, setForwardQuery] = useState(""); const [forwardQuery, setForwardQuery] = useState("");
const [forwardError, setForwardError] = useState<string | null>(null); const [forwardError, setForwardError] = useState<string | null>(null);
const [isForwarding, setIsForwarding] = useState(false); const [isForwarding, setIsForwarding] = useState(false);
@@ -169,7 +169,7 @@ export function MessageList() {
return; return;
} }
setCtx(null); setCtx(null);
setForwardMessageId(null); setForwardMessageIds([]);
setForwardSelectedChatIds(new Set()); setForwardSelectedChatIds(new Set());
setDeleteMessageId(null); setDeleteMessageId(null);
setSelectedIds(new Set()); setSelectedIds(new Set());
@@ -184,7 +184,7 @@ export function MessageList() {
setSelectedIds(new Set()); setSelectedIds(new Set());
setCtx(null); setCtx(null);
setDeleteMessageId(null); setDeleteMessageId(null);
setForwardMessageId(null); setForwardMessageIds([]);
setForwardSelectedChatIds(new Set()); setForwardSelectedChatIds(new Set());
setForwardIncludeAuthor(true); setForwardIncludeAuthor(true);
if (activeChatId) { if (activeChatId) {
@@ -337,7 +337,7 @@ export function MessageList() {
} }
async function handleForwardSubmit() { async function handleForwardSubmit() {
if (!forwardMessageId) return; if (!forwardMessageIds.length) return;
const targetChatIds = [...forwardSelectedChatIds]; const targetChatIds = [...forwardSelectedChatIds];
if (!targetChatIds.length) { if (!targetChatIds.length) {
setForwardError("Select at least one chat"); setForwardError("Select at least one chat");
@@ -346,11 +346,14 @@ export function MessageList() {
setIsForwarding(true); setIsForwarding(true);
setForwardError(null); setForwardError(null);
try { try {
await forwardMessageBulk(forwardMessageId, targetChatIds, forwardIncludeAuthor); await Promise.all(
setForwardMessageId(null); forwardMessageIds.map((messageId) => forwardMessageBulk(messageId, targetChatIds, forwardIncludeAuthor))
);
setForwardMessageIds([]);
setForwardSelectedChatIds(new Set()); setForwardSelectedChatIds(new Set());
setForwardIncludeAuthor(true); setForwardIncludeAuthor(true);
setForwardQuery(""); setForwardQuery("");
setSelectedIds(new Set());
} catch { } catch {
setForwardError("Failed to forward message"); setForwardError("Failed to forward message");
} finally { } finally {
@@ -359,6 +362,17 @@ export function MessageList() {
setCtx(null); setCtx(null);
} }
function openForwardDialog(messageIds: number[]) {
if (!messageIds.length) {
return;
}
setForwardMessageIds([...new Set(messageIds)]);
setForwardQuery("");
setForwardError(null);
setForwardSelectedChatIds(new Set());
setForwardIncludeAuthor(true);
}
async function handlePin(messageId: number) { async function handlePin(messageId: number) {
const nextPinned = activeChat?.pinned_message_id === messageId ? null : messageId; const nextPinned = activeChat?.pinned_message_id === messageId ? null : messageId;
const chat = await pinMessage(chatId, nextPinned); const chat = await pinMessage(chatId, nextPinned);
@@ -493,6 +507,12 @@ export function MessageList() {
<div className="flex items-center justify-between border-b border-slate-700/50 bg-slate-900/80 px-3 py-2 text-xs"> <div className="flex items-center justify-between border-b border-slate-700/50 bg-slate-900/80 px-3 py-2 text-xs">
<span className="font-semibold text-slate-200">{selectedIds.size} selected</span> <span className="font-semibold text-slate-200">{selectedIds.size} selected</span>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<button
className="rounded bg-sky-500 px-2 py-1 font-semibold text-slate-950"
onClick={() => openForwardDialog(selectedMessages.map((message) => message.id))}
>
Forward
</button>
{!channelOnlyDeleteForAll ? ( {!channelOnlyDeleteForAll ? (
<button className="rounded bg-red-500 px-2 py-1 font-semibold text-white" onClick={() => void deleteSelectedForMe()}> <button className="rounded bg-red-500 px-2 py-1 font-semibold text-white" onClick={() => void deleteSelectedForMe()}>
Delete for me Delete for me
@@ -763,14 +783,10 @@ export function MessageList() {
Edit Edit
</button> </button>
) : null} ) : null}
<button <button
className="block w-full rounded px-2 py-1.5 text-left text-sm hover:bg-slate-800" className="block w-full rounded px-2 py-1.5 text-left text-sm hover:bg-slate-800"
onClick={() => { onClick={() => {
setForwardMessageId(ctx.messageId); openForwardDialog([ctx.messageId]);
setForwardQuery("");
setForwardError(null);
setForwardSelectedChatIds(new Set());
setForwardIncludeAuthor(true);
setCtx(null); setCtx(null);
}} }}
> >
@@ -874,10 +890,12 @@ export function MessageList() {
) )
: null} : null}
{forwardMessageId ? ( {forwardMessageIds.length > 0 ? (
<div className="absolute inset-0 z-50 flex items-end justify-center bg-slate-950/55 p-3" onClick={() => setForwardMessageId(null)}> <div className="absolute inset-0 z-50 flex items-end justify-center bg-slate-950/55 p-3" onClick={() => setForwardMessageIds([])}>
<div className="w-full rounded-xl border border-slate-700/80 bg-slate-900 p-3" onClick={(event) => event.stopPropagation()}> <div className="w-full rounded-xl border border-slate-700/80 bg-slate-900 p-3" onClick={(event) => event.stopPropagation()}>
<p className="mb-2 text-sm font-semibold">Forward message</p> <p className="mb-2 text-sm font-semibold">
Forward {forwardMessageIds.length > 1 ? `${forwardMessageIds.length} messages` : "message"}
</p>
<input <input
className="mb-2 w-full rounded-lg border border-slate-700/80 bg-slate-800/80 px-3 py-2 text-sm outline-none placeholder:text-slate-400 focus:border-sky-500" className="mb-2 w-full rounded-lg border border-slate-700/80 bg-slate-800/80 px-3 py-2 text-sm outline-none placeholder:text-slate-400 focus:border-sky-500"
placeholder="Search chats" placeholder="Search chats"
@@ -923,7 +941,7 @@ export function MessageList() {
<button className="w-full rounded bg-sky-500 px-3 py-2 text-sm font-semibold text-slate-950" onClick={() => void handleForwardSubmit()}> <button className="w-full rounded bg-sky-500 px-3 py-2 text-sm font-semibold text-slate-950" onClick={() => void handleForwardSubmit()}>
Forward ({forwardSelectedChatIds.size}) Forward ({forwardSelectedChatIds.size})
</button> </button>
<button className="w-full rounded bg-slate-700 px-3 py-2 text-sm" onClick={() => setForwardMessageId(null)}> <button className="w-full rounded bg-slate-700 px-3 py-2 text-sm" onClick={() => setForwardMessageIds([])}>
Cancel Cancel
</button> </button>
</div> </div>