Архитектура

This commit is contained in:
Халимов Рустам
2026-03-21 02:19:38 +03:00
parent f3e0941647
commit 5da1a2f45d
44 changed files with 826 additions and 380 deletions
@@ -262,27 +262,36 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal
const observer = new IntersectionObserver(
(entries) => {
let highestSequenceId = -1;
let highestMsgId = '';
const newlyReadIds: string[] = [];
entries.forEach((entry) => {
if (entry.isIntersecting) {
const msgId = entry.target.getAttribute('data-message-id');
if (msgId && !sentReadIdsRef.current.has(msgId)) {
const seqIdAttr = entry.target.getAttribute('data-sequence-id');
if (msgId && seqIdAttr && !sentReadIdsRef.current.has(msgId)) {
newlyReadIds.push(msgId);
sentReadIdsRef.current.add(msgId);
// Stop observing once read
observer.unobserve(entry.target);
const seqId = parseInt(seqIdAttr, 10);
if (seqId > highestSequenceId) {
highestSequenceId = seqId;
highestMsgId = msgId;
}
}
}
});
if (newlyReadIds.length > 0) {
console.log('[IntersectionObserver] Marking as read:', newlyReadIds);
if (newlyReadIds.length > 0 && highestMsgId) {
console.log('[IntersectionObserver] Marking as read up to:', highestSequenceId);
socket.emit('read_messages', {
chatId: activeChat,
messageIds: newlyReadIds,
lastReadMessageId: highestMsgId,
lastReadSequenceId: highestSequenceId,
});
// Update local store immediately for current user
useChatStore.getState().markRead(activeChat, user.id, newlyReadIds);
useChatStore.getState().markRead(activeChat, user.id, highestSequenceId);
}
},
{
@@ -904,6 +913,7 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal
<div
key={msg.id}
data-message-id={msg.id}
data-sequence-id={msg.sequenceId}
className={`transition-colors duration-500 ${msg.senderId !== user?.id && !msg.readBy?.some(r => r.userId === user?.id) ? 'unread-detector' : ''}`}
>
{isFirstUnread && (
@@ -986,45 +996,70 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal
{/* Ввод сообщения */}
{activeChat && <MessageInput chatId={activeChat} />}
{/* Профиль пользователя */}
<AnimatePresence>
{profileUserId && (
<UserProfile
userId={profileUserId}
chatId={activeChat || undefined}
onClose={() => setProfileUserId(null)}
onGoToMessage={(msgId) => {
const el = document.getElementById(`msg-${msgId}`);
if (el) {
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
el.classList.add('highlight-message');
setTimeout(() => el.classList.remove('highlight-message'), 5000);
setProfileUserId(null);
}
}}
isSelf={profileUserId === user?.id}
/>
)}
</AnimatePresence>
{(() => {
const handleJumpToMessage = async (msgId: string, cleanup?: () => void) => {
cleanup?.();
const tryScroll = () => {
const el = document.getElementById(`msg-${msgId}`);
if (el) {
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
el.classList.add('highlight-message');
setTimeout(() => el.classList.remove('highlight-message'), 5000);
return true;
}
return false;
};
{/* Настройки группы */}
<AnimatePresence>
{showGroupSettings && chat && chat.type === 'group' && (
<GroupSettings
chat={chat}
onClose={() => setShowGroupSettings(false)}
onGoToMessage={(msgId) => {
const el = document.getElementById(`msg-${msgId}`);
if (el) {
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
el.classList.add('highlight-message');
setTimeout(() => el.classList.remove('highlight-message'), 5000);
setShowGroupSettings(false);
}
}}
/>
)}
</AnimatePresence>
if (tryScroll()) return;
if (!activeChat) return;
const NotificationStore = await import('../../../../core/application/stores/notificationStore');
NotificationStore.useNotificationStore.getState().addNotification('info', 'Поиск сообщения в истории...');
const chatStore = useChatStore.getState();
let found = false;
for (let i = 0; i < 5; i++) {
if (chatStore.hasMoreMessages[activeChat] === false) 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', 'Сообщение слишком старое');
}
};
return (
<>
{/* Профиль пользователя */}
<AnimatePresence>
{profileUserId && (
<UserProfile
userId={profileUserId}
chatId={activeChat || undefined}
onClose={() => setProfileUserId(null)}
onGoToMessage={(msgId) => handleJumpToMessage(msgId, () => setProfileUserId(null))}
isSelf={profileUserId === user?.id}
/>
)}
</AnimatePresence>
{/* Настройки группы */}
<AnimatePresence>
{showGroupSettings && chat && chat.type === 'group' && (
<GroupSettings
chat={chat}
onClose={() => setShowGroupSettings(false)}
onGoToMessage={(msgId) => handleJumpToMessage(msgId, () => setShowGroupSettings(false))}
/>
)}
</AnimatePresence>
</>
);
})()}
<AnimatePresence>
{showForwardModal && (