Опросы

This commit is contained in:
Халимов Рустам
2026-04-07 11:11:35 +03:00
parent c45f4db61c
commit 852efa090e
25 changed files with 530 additions and 175 deletions
@@ -79,8 +79,7 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal
const messagesEndRef = useRef<HTMLDivElement>(null);
const scrollContainerRef = useRef<HTMLDivElement>(null);
const handleJumpToMessage = async (msgId: string, cleanup?: () => void, targetCreatedAt?: string) => {
cleanup?.();
const handleJumpToMessage = async (msgId: string, sequenceId?: number) => {
const tryScroll = () => {
const el = document.getElementById(`msg-${msgId}`);
if (el) {
@@ -99,34 +98,26 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal
NotificationStore.useNotificationStore.getState().addNotification('info', (t as any)('searchingHistory') || 'Searching message in history...');
const chatStore = useChatStore.getState();
let found = false;
const targetDate = targetCreatedAt ? new Date(targetCreatedAt).getTime() : 0;
for (let i = 0; i < 100; i++) {
const chatMessages = chatStore.messages[activeChat] || [];
const oldestLoaded = chatMessages.length > 0 ? new Date(chatMessages[0].createdAt).getTime() : Date.now();
if (targetDate && targetDate > oldestLoaded && chatMessages.some(m => m.id === msgId)) {
if (sequenceId !== undefined) {
await chatStore.jumpToMessage(activeChat, sequenceId);
// Wait a bit for React to render
setTimeout(() => {
if (!tryScroll()) {
NotificationStore.useNotificationStore.getState().addNotification('warning', (t as any)('messageNotFound') || 'Message not found');
}
}, 300);
} else {
// Old fallback loop if no sequenceId
let found = false;
for (let i = 0; i < 50; i++) {
await chatStore.loadMessages(activeChat, false, true);
await new Promise(resolve => setTimeout(resolve, 150));
if (tryScroll()) { found = true; break; }
}
if (chatStore.hasMoreMessages[activeChat] === false && oldestLoaded <= targetDate) break;
await chatStore.loadMessages(activeChat, false, true);
await new Promise(resolve => setTimeout(resolve, 150));
if (tryScroll()) {
found = true;
break;
if (!found) {
NotificationStore.useNotificationStore.getState().addNotification('warning', (t as any)('messageNotFound') || 'Message not found');
}
if (targetDate && oldestLoaded < (targetDate - 1000 * 60 * 60)) {
if (i > 10) break;
}
}
if (!found) {
NotificationStore.useNotificationStore.getState().addNotification('warning', (t as any)('messageNotFound') || 'Message not found');
}
};
const searchInputRef = useRef<HTMLInputElement>(null);
@@ -455,17 +446,31 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal
const st = container.scrollTop;
const isScrollingUp = st < lastScrollTopRef.current;
lastScrollTopRef.current = st;
const stChanged = st !== lastScrollTopRef.current;
// Sticky Date Header Logic - Telegram style
if (st > 100 && (isScrollingUp || st !== lastScrollTopRef.current)) {
setShowStickyDate(true);
if (stickyDateTimerRef.current) clearTimeout(stickyDateTimerRef.current);
stickyDateTimerRef.current = setTimeout(() => setShowStickyDate(false), isScrollingUp ? 1500 : 1000);
if (st > 100 && stChanged) {
// Показываем плашку только при прокрутке или если она уже активна
// При прокрутке вверх она должна быть видна всегда
if (isScrollingUp) {
setShowStickyDate(true);
if (stickyDateTimerRef.current) clearTimeout(stickyDateTimerRef.current);
// Таймер на 2 сек запустится только после остановки скролла
stickyDateTimerRef.current = setTimeout(() => setShowStickyDate(false), 2000);
} else {
// При прокрутке вниз плашка обычно скрывается быстрее
if (stickyDateTimerRef.current) {
clearTimeout(stickyDateTimerRef.current);
stickyDateTimerRef.current = setTimeout(() => setShowStickyDate(false), 800);
}
}
} else if (st <= 100) {
setShowStickyDate(false);
if (stickyDateTimerRef.current) clearTimeout(stickyDateTimerRef.current);
}
lastScrollTopRef.current = st;
const containerRect = container.getBoundingClientRect();
const messageElements = container.querySelectorAll('[data-message-id]');
@@ -1172,7 +1177,7 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal
onClick={() => {
const currentPin = chatPinnedMessages[pinnedIndex % chatPinnedMessages.length];
if (!currentPin) return;
handleJumpToMessage(currentPin.id, undefined, currentPin.createdAt);
handleJumpToMessage(currentPin.id, currentPin.sequenceId);
if (chatPinnedMessages.length > 1) {
setPinnedIndex(prev => (prev + 1) % chatPinnedMessages.length);
}
@@ -1353,7 +1358,7 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal
userId={profileUserId}
chatId={activeChat || undefined}
onClose={() => setProfileUserId(null)}
onGoToMessage={(msgId: any, createdAt: string) => handleJumpToMessage(msgId, () => setProfileUserId(null), createdAt)}
onGoToMessage={(msgId: any) => { handleJumpToMessage(msgId); setProfileUserId(null); }}
isSelf={profileUserId === user?.id}
/>
)}
@@ -1364,7 +1369,7 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal
<GroupSettings
chat={chat}
onClose={() => setShowGroupSettings(false)}
onGoToMessage={(msgId) => handleJumpToMessage(msgId, () => setShowGroupSettings(false))}
onGoToMessage={(msgId) => { handleJumpToMessage(msgId); setShowGroupSettings(false); }}
/>
)}
</AnimatePresence>