diff --git a/backend/src/Modules/Chats/Infrastructure/Persistence/MessageRepository.cs b/backend/src/Modules/Chats/Infrastructure/Persistence/MessageRepository.cs index 06b9890..ffd0125 100644 --- a/backend/src/Modules/Chats/Infrastructure/Persistence/MessageRepository.cs +++ b/backend/src/Modules/Chats/Infrastructure/Persistence/MessageRepository.cs @@ -105,21 +105,35 @@ public sealed class MessageRepository : IMessageRepository public async Task AddReadReceiptsAsync(Guid userId, List messageIds, CancellationToken cancellationToken) { var filter = Builders.Filter.In(m => m.Id, messageIds); - var messages = await _messages.Find(filter).ToListAsync(cancellationToken); + if (!messages.Any()) return; + + var chatId = messages.First().ChatId; + var maxDate = messages.Max(m => m.CreatedAt); + + var notReadFilter = Builders.Filter.Not( + Builders.Filter.ElemMatch( + "ReadBy", + Builders.Filter.Eq(r => r.UserId, userId) + ) + ); + + var finalFilter = Builders.Filter.And( + Builders.Filter.Eq(m => m.ChatId, chatId), + Builders.Filter.Ne(m => m.SenderId, userId), + Builders.Filter.Lte(m => m.CreatedAt, maxDate), + notReadFilter + ); + + var unreadMessagesToMark = await _messages.Find(finalFilter).ToListAsync(cancellationToken); var writes = new List>(); - foreach (var msg in messages) + foreach (var msg in unreadMessagesToMark) { - if (!msg.ReadBy.Any(r => r.UserId == userId)) - { - var receipt = new ReadReceipt(msg.Id, userId); - - var pushUpdate = Builders.Update.Push("ReadBy", receipt); - - var updateModel = new UpdateOneModel(Builders.Filter.Eq(m => m.Id, msg.Id), pushUpdate); - writes.Add(updateModel); - } + var receipt = new ReadReceipt(msg.Id, userId); + var pushUpdate = Builders.Update.Push("ReadBy", receipt); + var updateModel = new UpdateOneModel(Builders.Filter.Eq(m => m.Id, msg.Id), pushUpdate); + writes.Add(updateModel); } if (writes.Any()) @@ -180,8 +194,10 @@ public sealed class MessageRepository : IMessageRepository public async Task GetUnreadCountAsync(Guid chatId, Guid userId, CancellationToken cancellationToken) { var notReadFilter = Builders.Filter.Not( - Builders.Filter.ElemMatch("ReadBy", - Builders.Filter.Eq("UserId", userId)) + Builders.Filter.ElemMatch( + "ReadBy", + Builders.Filter.Eq(r => r.UserId, userId) + ) ); var finalFilter = Builders.Filter.And( diff --git a/client-web/src/modules/chats/presentation/components/ChatView.tsx b/client-web/src/modules/chats/presentation/components/ChatView.tsx index daba39a..e0d29f0 100644 --- a/client-web/src/modules/chats/presentation/components/ChatView.tsx +++ b/client-web/src/modules/chats/presentation/components/ChatView.tsx @@ -200,9 +200,21 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal container.scrollTop = targetEl.offsetTop - 60; } else { container.scrollTop = container.scrollHeight; + requestAnimationFrame(() => { + if (container) container.scrollTop = container.scrollHeight; + }); + setTimeout(() => { + if (container) container.scrollTop = container.scrollHeight; + }, 100); } } else { container.scrollTop = container.scrollHeight; + requestAnimationFrame(() => { + if (container) container.scrollTop = container.scrollHeight; + }); + setTimeout(() => { + if (container) container.scrollTop = container.scrollHeight; + }, 100); } setScrollReady(true); } diff --git a/client-web/src/modules/chats/presentation/components/MessageBubble.tsx b/client-web/src/modules/chats/presentation/components/MessageBubble.tsx index 93c70a6..6d935ca 100644 --- a/client-web/src/modules/chats/presentation/components/MessageBubble.tsx +++ b/client-web/src/modules/chats/presentation/components/MessageBubble.tsx @@ -407,13 +407,18 @@ function MessageBubble({ )} + {(() => { + const hasReactions = Object.keys(reactionGroups).length > 0; + const needsFrame = !!message.content || !!message.forwardedFrom || !!message.replyTo || hasReactions; + + return (
= 3 @@ -827,6 +832,8 @@ function MessageBubble({
)}
+ ); + })()} {isMine && (