import SwiftUI struct NotificationsView: View { @StateObject private var viewModel: NotificationsViewModel @State private var showingRefreshIndicator = false init(viewModel: NotificationsViewModel = NotificationsViewModel()) { self._viewModel = StateObject(wrappedValue: viewModel) } var body: some View { NavigationStack { Group { if viewModel.notifications.isEmpty && !viewModel.isLoading { emptyStateView } else { notificationListView } } .navigationTitle("Notifications") .toolbar { if !viewModel.notifications.isEmpty { ToolbarItem(placement: .navigationBarTrailing) { if viewModel.unreadCount > 0 { Button { Task { await viewModel.markAllAsRead() } } label: { Text("Mark All Read") .font(.caption) } .foregroundColor(.blue) } } } } } .onAppear { Task { await viewModel.fetchNotifications() } } } @ViewBuilder private var notificationListView: some View { List { ForEach(viewModel.notifications) { notification in NotificationRowView(notification: notification) .onTapGesture { Task { if !notification.isRead { await viewModel.markAsRead(id: notification.id) } } } } .onDelete { offsets in Task { for index in offsets { let notification = viewModel.notifications[index] await viewModel.markAsRead(id: notification.id) } viewModel.notifications.remove(atOffsets: offsets) } } } .listStyle(.insetGrouped) .refreshable { await viewModel.refresh() } } private var emptyStateView: some View { VStack(spacing: 16) { Image(systemName: "bell.slash") .font(.system(size: 64)) .foregroundColor(.secondary) Text("No Notifications") .font(.title2) .fontWeight(.semibold) .foregroundColor(.primary) Text("You're all caught up!\nWhen you have notifications, they'll appear here.") .font(.subheadline) .foregroundColor(.secondary) .multilineTextAlignment(.center) .padding(.horizontal, 32) } .padding(.vertical, 60) } } #Preview { NotificationsView() } #Preview("With Data") { let previewView = NotificationsView() // Inject mock data for preview return previewView }