import 'dart:async'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:real_estate_mobile/features/notifications/data/models/notification_model.dart'; import 'package:real_estate_mobile/features/notifications/data/notification_repository.dart'; /// Unread notification count — polled every 30 seconds. final unreadCountProvider = StateNotifierProvider((ref) { return UnreadCountNotifier(NotificationRepository()); }); class UnreadCountNotifier extends StateNotifier { final NotificationRepository _repo; Timer? _timer; UnreadCountNotifier(this._repo) : super(0) { refresh(); _timer = Timer.periodic(const Duration(seconds: 30), (_) => refresh()); } Future refresh() async { try { final count = await _repo.getUnreadCount(); if (mounted) state = count; } catch (_) { // Silently fail — badge just won't update } } @override void dispose() { _timer?.cancel(); super.dispose(); } } /// Notification list state. class NotificationListState { final List notifications; final bool isLoading; final bool isLoadingMore; final String? error; final String filter; // 'all' | 'unread' final int currentPage; final int totalPages; const NotificationListState({ this.notifications = const [], this.isLoading = false, this.isLoadingMore = false, this.error, this.filter = 'all', this.currentPage = 1, this.totalPages = 1, }); NotificationListState copyWith({ List? notifications, bool? isLoading, bool? isLoadingMore, String? error, String? filter, int? currentPage, int? totalPages, }) { return NotificationListState( notifications: notifications ?? this.notifications, isLoading: isLoading ?? this.isLoading, isLoadingMore: isLoadingMore ?? this.isLoadingMore, error: error, filter: filter ?? this.filter, currentPage: currentPage ?? this.currentPage, totalPages: totalPages ?? this.totalPages, ); } } final notificationListProvider = StateNotifierProvider( (ref) { return NotificationListNotifier(NotificationRepository(), ref); }); class NotificationListNotifier extends StateNotifier { final NotificationRepository _repo; final Ref _ref; NotificationListNotifier(this._repo, this._ref) : super(const NotificationListState()); Future loadNotifications({String filter = 'all'}) async { state = state.copyWith(isLoading: true, error: null, filter: filter); try { final response = await _repo.getNotifications(filter: filter, page: 1, limit: 20); state = state.copyWith( notifications: response.notifications, isLoading: false, currentPage: response.currentPage, totalPages: response.totalPages, ); } catch (e) { state = state.copyWith(isLoading: false, error: e.toString()); } } Future loadMore() async { if (state.isLoadingMore || state.currentPage >= state.totalPages) return; state = state.copyWith(isLoadingMore: true); try { final nextPage = state.currentPage + 1; final response = await _repo.getNotifications( filter: state.filter, page: nextPage, limit: 20); state = state.copyWith( notifications: [...state.notifications, ...response.notifications], isLoadingMore: false, currentPage: response.currentPage, totalPages: response.totalPages, ); } catch (_) { state = state.copyWith(isLoadingMore: false); } } Future markAsRead(String notificationId) async { try { await _repo.markAsRead(notificationId); state = state.copyWith( notifications: state.notifications.map((n) { if (n.id == notificationId) return n.copyWith(read: true); return n; }).toList(), ); _ref.read(unreadCountProvider.notifier).refresh(); } catch (_) {} } Future markAllAsRead() async { try { await _repo.markAllAsRead(); state = state.copyWith( notifications: state.notifications.map((n) => n.copyWith(read: true)).toList(), ); _ref.read(unreadCountProvider.notifier).refresh(); } catch (_) {} } }