From 02a85fc5873e8ab6c1d1b5aad211466b46c1041e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A5=D0=B0=D0=BB=D0=B8=D0=BC=D0=BE=D0=B2=20=D0=A0=D1=83?= =?UTF-8?q?=D1=81=D1=82=D0=B0=D0=BC?= Date: Mon, 6 Apr 2026 23:42:46 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9F=D1=80=D0=BE=D0=BA=D1=80=D1=83=D1=82?= =?UTF-8?q?=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chats/presentation/components/ChatView.tsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/client-web/src/modules/chats/presentation/components/ChatView.tsx b/client-web/src/modules/chats/presentation/components/ChatView.tsx index 07f0610..7b22494 100644 --- a/client-web/src/modules/chats/presentation/components/ChatView.tsx +++ b/client-web/src/modules/chats/presentation/components/ChatView.tsx @@ -90,6 +90,7 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal const pinnedMsg = activeChat ? pinnedMessages[activeChat] : null; const [importStatus, setImportStatus] = useState<{ processed: number, total: number, status: string } | null>(null); + const isAtBottomRef = useRef(false); useEffect(() => { if (!chat?.isImporting || !chat?.importJobId) { @@ -232,7 +233,8 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal // Проверка: сообщения в стейте должны быть от целевого чата if (chatMessages.length > 0 && chatMessages[0].chatId !== chatId) return; - const isAtBottomNow = container.scrollHeight - container.scrollTop - container.clientHeight < 150; + const isAtBottomNow = container.scrollHeight - container.scrollTop - container.clientHeight < 100; + isAtBottomRef.current = isAtBottomNow; if (isAtBottomNow) { localStorage.setItem(`chat_at_bottom_${chatId}`, 'true'); @@ -275,6 +277,7 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal // ПРИОРИТЕТ 1: Если чат внизу (после второго клика или скролла) if (localStorage.getItem(`chat_at_bottom_${activeChat}`) === 'true') { container.scrollTop = container.scrollHeight; + isAtBottomRef.current = true; return true; } @@ -314,6 +317,7 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal } container.scrollTop = container.scrollHeight; + isAtBottomRef.current = true; return true; }, [activeChat, chatMessages, user?.id]); @@ -330,7 +334,7 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal setScrollReady(true); isInitializingRef.current = false; } - } else if (localStorage.getItem(`chat_at_bottom_${activeChat}`) === 'true') { + } else if (isAtBottomRef.current) { // Удержание внизу при росте контента container.scrollTop = container.scrollHeight; } @@ -390,6 +394,10 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal checkScrollPosition(); const container = messagesContainerRef.current; if (container && activeChat) { + // Synchronous "at bottom" check to prevent ResizeObserver from fighting the user + const isAtBottomNow = container.scrollHeight - container.scrollTop - container.clientHeight < 100; + isAtBottomRef.current = isAtBottomNow; + if (scrollTimeoutRef.current) clearTimeout(scrollTimeoutRef.current); scrollTimeoutRef.current = setTimeout(() => saveScrollPosition(), 150);