From 219a93215f17d56976801173b40a1bb915be4237 Mon Sep 17 00:00:00 2001 From: lizerk Date: Fri, 3 Apr 2026 21:01:10 +0300 Subject: [PATCH] Improve deleted reply preview context --- backend/communications/serialization.py | 4 +--- .../communications/test_communications_api.py | 6 +++--- .../components/messages/ChatMessageItem.tsx | 21 +++++++++++++------ frontend/src/lib/messages/messageUtils.ts | 10 ++++++++- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/backend/communications/serialization.py b/backend/communications/serialization.py index 0dac172a..bc7d8d73 100644 --- a/backend/communications/serialization.py +++ b/backend/communications/serialization.py @@ -91,9 +91,7 @@ def _serialize_reply_preview(reply_msg) -> dict: return { "id": reply_msg.id, - "content": "" - if is_deleted - else (reply_msg.content[:100] if reply_msg.content else ""), + "content": reply_msg.content[:100] if reply_msg.content else "", "author_name": ( reply_msg.author.get_full_name() if reply_msg.author diff --git a/backend/tests/api/v1/communications/test_communications_api.py b/backend/tests/api/v1/communications/test_communications_api.py index 82479d50..8e033ddb 100644 --- a/backend/tests/api/v1/communications/test_communications_api.py +++ b/backend/tests/api/v1/communications/test_communications_api.py @@ -2451,10 +2451,10 @@ class TestDeleteVariousMessageTypes: assert reply2.is_deleted is False assert reply1.reply_to_id == original.id - def test_messages_around_keeps_deleted_reply_preview_non_clickable_contract( + def test_messages_around_keeps_deleted_reply_preview_context_contract( self, auth_client, private_chat, user1 ): - """Ответ на удаленное сообщение сохраняет preview, но помечается как deleted.""" + """Ответ на удаленное сообщение сохраняет контекст preview и помечается как deleted.""" original = Message.objects.create( chat=private_chat, author=user1, content="Original to delete" ) @@ -2477,7 +2477,7 @@ class TestDeleteVariousMessageTypes: assert serialized_reply["reply_to"]["id"] == original.id assert serialized_reply["reply_to"]["is_deleted"] is True - assert serialized_reply["reply_to"]["content"] == "" + assert serialized_reply["reply_to"]["content"] == "Original to delete" assert "author_name" in serialized_reply["reply_to"] def test_bulk_delete_various_types(self, auth_client, private_chat, user1): diff --git a/frontend/src/components/messages/ChatMessageItem.tsx b/frontend/src/components/messages/ChatMessageItem.tsx index 282988be..af52ffed 100644 --- a/frontend/src/components/messages/ChatMessageItem.tsx +++ b/frontend/src/components/messages/ChatMessageItem.tsx @@ -17,6 +17,7 @@ import { resolveMediaUrl } from "@/lib/url"; import { formatFileSize, getReplyPreview, + getReplyPreviewStatusLabel, getReplyPreviewText, getReplyToId, getMessageDate, @@ -133,6 +134,7 @@ export default function ChatMessageItem({ const replyPreviewMessage = getReplyPreview(message, repliedMessage); const replyToId = getReplyToId(message); const canJumpToReply = Boolean(replyToId && !isReplyPreviewDeleted(replyPreviewMessage)); + const replyStatusLabel = getReplyPreviewStatusLabel(replyPreviewMessage); const isMine = Boolean( currentUserId && (message.author_id === currentUserId || message.author?.id === currentUserId || message.sender?.id === currentUserId) @@ -211,18 +213,25 @@ export default function ChatMessageItem({ ) : (
-

- {replyPreviewMessage?.author_name || "Ответ на сообщение"} -

-

+

+

+ {replyPreviewMessage?.author_name || "Ответ на сообщение"} +

+ {replyStatusLabel ? ( + + {replyStatusLabel} + + ) : null} +
+

{replyPreviewMessage ? getReplyPreviewText(replyPreviewMessage) : "Сообщение удалено"}

diff --git a/frontend/src/lib/messages/messageUtils.ts b/frontend/src/lib/messages/messageUtils.ts index d56a886a..b7262649 100644 --- a/frontend/src/lib/messages/messageUtils.ts +++ b/frontend/src/lib/messages/messageUtils.ts @@ -118,15 +118,23 @@ export function isReplyPreviewDeleted(preview: ReplyPreviewSource | null | undef } export function getReplyPreviewText(preview: ReplyPreviewSource): string { - if (preview.is_deleted) return "Сообщение удалено"; if (preview.content?.trim()) return preview.content.trim(); if ("attachments" in preview && Array.isArray(preview.attachments) && preview.attachments.length > 0) { return "[Вложение]"; } if (preview.has_attachments) return "[Вложение]"; + if (preview.is_deleted) return "Сообщение удалено"; return "[Сообщение]"; } +export function getReplyPreviewStatusLabel(preview: ReplyPreviewSource | null | undefined): string | null { + if (!preview?.is_deleted) { + return null; + } + + return "Удалено"; +} + export function getReplyToId(message: Message): number | null { if (typeof message.reply_to_id === "number") return message.reply_to_id; if (typeof message.reply_to === "number") return message.reply_to;