@rendermode @(new InteractiveServerRenderMode(prerender: false)) @implements IAsyncDisposable @inject ApiClientService ApiClient @inject AuthenticationStateProvider AuthStateProvider @inject NavigationManager Navigation @inject IJSRuntime JS
@if (IsOpen) {

@AppLocalization.Text("notification.notifications", "Notifications")

@AppLocalization.Number(UnreadCount) @AppLocalization.Text("notification.unread", "unread")

@if (Notifications.Any(item => item.IsRead)) { }
@if (IsLoading) {
@AppLocalization.Text("notification.loading", "Loading notifications...")
} else if (Notifications.Count == 0) {

@AppLocalization.Text("notification.noneYet", "No notifications yet")

@AppLocalization.Text("notification.emptyState", "Your task alerts will show up here.")

} else { @foreach (var item in Notifications) { } }
}
@code { private bool IsOpen; private bool IsLoading; private bool showCleanupConfirmDialog; private int UnreadCount; private List Notifications = new(); protected override async Task OnInitializedAsync() { await RefreshAsync(); } protected override async Task OnAfterRenderAsync(bool firstRender) { await JS.InvokeVoidAsync("initIcons"); } private async Task ToggleOpenAsync() { IsOpen = !IsOpen; if (IsOpen) { await RefreshAsync(); } } private void Close() { IsOpen = false; } private async Task RefreshAsync() { IsLoading = true; try { var authState = await AuthStateProvider.GetAuthenticationStateAsync(); if (authState.User.Identity?.IsAuthenticated != true) { Notifications.Clear(); UnreadCount = 0; return; } var client = ApiClient.CreateClient(authState.User); var unreadTask = client.GetFromJsonAsync("Notification/unread-count"); var itemsTask = client.GetFromJsonAsync>("Notification/mine?take=10"); await Task.WhenAll(unreadTask, itemsTask); UnreadCount = unreadTask.Result; Notifications = (itemsTask.Result ?? new List()) .Select(item => { item.TargetUrl = BuildTargetUrl(item); return item; }) .ToList(); } catch (Exception ex) { Console.WriteLine($"[DEBUG NotificationBell] Failed to refresh: {ex.Message}"); } finally { IsLoading = false; await InvokeAsync(StateHasChanged); } } private void RequestCleanupConfirmation() { showCleanupConfirmDialog = true; } private void CloseCleanupConfirmDialog() { showCleanupConfirmDialog = false; } private async Task ConfirmCleanupAsync() { showCleanupConfirmDialog = false; await ClearReadNotificationsAsync(); } private async Task ClearReadNotificationsAsync() { try { var authState = await AuthStateProvider.GetAuthenticationStateAsync(); if (authState.User.Identity?.IsAuthenticated != true) { return; } var client = ApiClient.CreateClient(authState.User); var response = await client.DeleteAsync("Notification/read"); if (response.IsSuccessStatusCode) { await RefreshAsync(); } } catch (Exception ex) { Console.WriteLine($"[DEBUG NotificationBell] Clear read notifications failed: {ex.Message}"); } } private async Task MarkReadAsync(NotificationDto item) { if (item.IsRead) { Navigation.NavigateTo(GetTargetUrl(item)); return; } try { var authState = await AuthStateProvider.GetAuthenticationStateAsync(); if (authState.User.Identity?.IsAuthenticated != true) { return; } var client = ApiClient.CreateClient(authState.User); var response = await client.PostAsync($"Notification/{item.Id}/read", null); if (response.IsSuccessStatusCode) { item.IsRead = true; if (UnreadCount > 0) { UnreadCount--; } await InvokeAsync(StateHasChanged); Navigation.NavigateTo(GetTargetUrl(item)); } } catch (Exception ex) { Console.WriteLine($"[DEBUG NotificationBell] MarkRead failed: {ex.Message}"); } } private async Task OpenNotificationAsync(NotificationDto item) { await MarkReadAsync(item); IsOpen = false; } private static string GetTargetUrl(NotificationDto item) { if (!string.IsNullOrWhiteSpace(item.TargetUrl)) { return item.TargetUrl; } return BuildTargetUrl(item); } private static string BuildTargetUrl(NotificationDto item) { return NotificationNavigation.BuildTargetUrl(item.SourceType, item.SourceId, item.NotificationType); } private static string FormatSender(string? senderName) { if (string.IsNullOrWhiteSpace(senderName)) { return AppLocalization.Text("notification.system", "System"); } return string.Equals(senderName, "System Admin", StringComparison.OrdinalIgnoreCase) ? AppLocalization.Text("common.systemAdmin", "System Admin") : senderName; } private static string GetNotificationTitle(NotificationDto item) { var title = AppLocalization.IsBurmeseCulture && !string.IsNullOrWhiteSpace(item.TitleMy) ? item.TitleMy : item.Title; return AppLocalization.LocalizeNotificationTitle(title); } private static string GetNotificationBody(NotificationDto item) { var body = AppLocalization.IsBurmeseCulture && !string.IsNullOrWhiteSpace(item.BodyMy) ? item.BodyMy : item.Body; return AppLocalization.LocalizeNotificationBody(body); } private static string FormatTime(DateTime? createdAt) { if (!createdAt.HasValue) { return string.Empty; } var value = createdAt.Value.ToLocalTime(); if (AppLocalization.IsBurmeseCulture) { var formatted = $"{AppLocalization.Number(value.Day)} {AppLocalization.MonthName(value, true)}၊ {AppLocalization.LocalizeDigits(value.ToString("HH:mm"))}"; return AppLocalization.LocalizeDigits(formatted); } return value.ToString("dd MMM, HH:mm"); } public ValueTask DisposeAsync() => ValueTask.CompletedTask; }