diff --git a/MiniSpace.Services.Notifications/src/MiniSpace.Services.Notifications.Application/Events/External/Handlers/FriendInvitedHandler.cs b/MiniSpace.Services.Notifications/src/MiniSpace.Services.Notifications.Application/Events/External/Handlers/FriendInvitedHandler.cs index cf1c44161..8dd3362b6 100644 --- a/MiniSpace.Services.Notifications/src/MiniSpace.Services.Notifications.Application/Events/External/Handlers/FriendInvitedHandler.cs +++ b/MiniSpace.Services.Notifications/src/MiniSpace.Services.Notifications.Application/Events/External/Handlers/FriendInvitedHandler.cs @@ -36,7 +36,7 @@ public async Task HandleAsync(FriendInvited @event, CancellationToken cancellati { var inviter = await _studentsServiceClient.GetAsync(@event.InviterId); var notificationMessage = $"You have been invited by {inviter.FirstName} {inviter.LastName} to be friends."; - var detailsHtml = $"

View {inviter.FirstName} {inviter.LastName}'s profile to respond to the friend invitation.

"; + var detailsHtml = $"

View {inviter.FirstName} {inviter.LastName}'s profile to respond to the friend invitation.

"; var notificationId = Guid.NewGuid(); var notification = new Notification( diff --git a/MiniSpace.Services.Notifications/src/MiniSpace.Services.Notifications.Application/Events/External/Handlers/FriendRequestSentHandler.cs b/MiniSpace.Services.Notifications/src/MiniSpace.Services.Notifications.Application/Events/External/Handlers/FriendRequestSentHandler.cs index 8e0972b7a..29fff237e 100644 --- a/MiniSpace.Services.Notifications/src/MiniSpace.Services.Notifications.Application/Events/External/Handlers/FriendRequestSentHandler.cs +++ b/MiniSpace.Services.Notifications/src/MiniSpace.Services.Notifications.Application/Events/External/Handlers/FriendRequestSentHandler.cs @@ -30,7 +30,7 @@ public async Task HandleAsync(FriendRequestSent @event, CancellationToken cancel { var inviter = await _studentsServiceClient.GetAsync(@event.InviterId); var notificationMessage = $"You have been invited by {inviter.FirstName} {inviter.LastName} to be friends."; - var detailsHtml = $"

View {inviter.FirstName} {inviter.LastName}'s profile to respond to the friend invitation.

"; + var detailsHtml = $"

View {inviter.FirstName} {inviter.LastName}'s profile to respond to the friend invitation.

"; var notification = new Notification( notificationId: Guid.NewGuid(), diff --git a/MiniSpace.Services.Notifications/src/MiniSpace.Services.Notifications.Infrastructure/Mongo/Repositories/StudentNotificationsMongoRepository.cs b/MiniSpace.Services.Notifications/src/MiniSpace.Services.Notifications.Infrastructure/Mongo/Repositories/StudentNotificationsMongoRepository.cs index cdd2c38bb..f4f7f9b58 100644 --- a/MiniSpace.Services.Notifications/src/MiniSpace.Services.Notifications.Infrastructure/Mongo/Repositories/StudentNotificationsMongoRepository.cs +++ b/MiniSpace.Services.Notifications/src/MiniSpace.Services.Notifications.Infrastructure/Mongo/Repositories/StudentNotificationsMongoRepository.cs @@ -41,26 +41,63 @@ public async Task UpdateAsync(StudentNotifications studentNotifications) await _repository.Collection.UpdateOneAsync(filter, update, options); } - public async Task AddOrUpdateAsync(StudentNotifications studentNotifications) + // public async Task AddOrUpdateAsync(StudentNotifications studentNotifications) + // { + // var document = studentNotifications.AsDocument(); + // var filter = Builders.Filter.Eq(doc => doc.StudentId, studentNotifications.StudentId); + // var updates = new List>(); + + // foreach (var notification in studentNotifications.Notifications) + // { + // updates.Add(Builders.Update.Push(doc => doc.Notifications, notification.AsDocument())); + // } + + // var update = Builders.Update + // .SetOnInsert(doc => doc.Id, studentNotifications.StudentId) + // .AddToSetEach(doc => doc.Notifications, studentNotifications.Notifications.Select(n => n.AsDocument())); + + // var options = new UpdateOptions { IsUpsert = true }; + // await _repository.Collection.UpdateOneAsync(filter, update, options); + // } + + public async Task AddOrUpdateAsync(StudentNotifications studentNotifications) { var document = studentNotifications.AsDocument(); var filter = Builders.Filter.Eq(doc => doc.StudentId, studentNotifications.StudentId); - var updates = new List>(); + // Ensure the document is initialized with an empty list if not present + var initializationUpdate = Builders.Update + .SetOnInsert(doc => doc.Notifications, new List()); + + var addToSetUpdates = new List>(); foreach (var notification in studentNotifications.Notifications) { - updates.Add(Builders.Update.Push(doc => doc.Notifications, notification.AsDocument())); - } + var notificationDocument = notification.AsDocument(); + var notificationFilter = Builders.Filter.And( + Builders.Filter.Eq("Notifications.Message", notificationDocument.Message), + Builders.Filter.Eq("Notifications.CreatedAt", notificationDocument.CreatedAt), + Builders.Filter.Eq("Notifications.EventType", notificationDocument.EventType) + ); - var update = Builders.Update - .SetOnInsert(doc => doc.Id, studentNotifications.StudentId) - .AddToSetEach(doc => doc.Notifications, studentNotifications.Notifications.Select(n => n.AsDocument())); + var combinedFilter = Builders.Filter.And(filter, notificationFilter); + var update = Builders.Update.AddToSet(doc => doc.Notifications, notificationDocument); + + addToSetUpdates.Add(update); + } var options = new UpdateOptions { IsUpsert = true }; - await _repository.Collection.UpdateOneAsync(filter, update, options); + // Initialize document if it doesn't exist + await _repository.Collection.UpdateOneAsync(filter, initializationUpdate, options); + + // Apply each AddToSet operation + foreach (var update in addToSetUpdates) + { + await _repository.Collection.UpdateOneAsync(filter, update, options); + } } + public async Task> FindAsync(FilterDefinition filter, FindOptions options) { var documents = await _repository.Collection.Find(filter, options).ToListAsync(); diff --git a/MiniSpace.Web/src/MiniSpace.Web/Pages/_Host.cshtml b/MiniSpace.Web/src/MiniSpace.Web/Pages/_Host.cshtml index 1b61e6407..048d0f5a4 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Pages/_Host.cshtml +++ b/MiniSpace.Web/src/MiniSpace.Web/Pages/_Host.cshtml @@ -7,7 +7,7 @@ - MiniSpace.Web + MiniSpace | Social @@ -56,6 +56,11 @@ return new Date().getTimezoneOffset(); } + function updateTitle(message) { + document.title = message; + setTimeout(() => document.title = "MiniSpace | Social", 8000); + } + diff --git a/MiniSpace.Web/src/MiniSpace.Web/Shared/NotificationComponent.razor b/MiniSpace.Web/src/MiniSpace.Web/Shared/NotificationComponent.razor index ea94eefbd..14aecbcfc 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Shared/NotificationComponent.razor +++ b/MiniSpace.Web/src/MiniSpace.Web/Shared/NotificationComponent.razor @@ -60,9 +60,10 @@ var paginatedResponse = await NotificationsService.GetNotificationsByUserAsync(userId, status: "Unread"); var latestNotifications = paginatedResponse.Results; - if (latestNotifications.Any(n => n.CreatedAt > lastCheckedTime)) + if (latestNotifications.Any(n => n.CreatedAt > lastCheckedTime)) { PlayNotificationSound(); + await JSRuntime.InvokeVoidAsync("updateTitle", "New Notification - MiniSpace | Social"); lastCheckedTime = DateTime.Now; } diff --git a/MiniSpace.Web/src/MiniSpace.Web/wwwroot/favicon.ico b/MiniSpace.Web/src/MiniSpace.Web/wwwroot/favicon.ico index a3a799985..ce8cf6674 100644 Binary files a/MiniSpace.Web/src/MiniSpace.Web/wwwroot/favicon.ico and b/MiniSpace.Web/src/MiniSpace.Web/wwwroot/favicon.ico differ