import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/providers/api/notifications_provider.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/notification_filter_model.dart'; import 'package:test_sa/models/system_notification_model.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/views/pages/user/notifications/notification_filter_page.dart'; import 'package:test_sa/views/pages/user/notifications/notifications_list.dart'; import 'package:test_sa/views/pages/user/notifications/widgets/notification_tab_button.dart'; import 'dart:async'; import '../../../widgets/loaders/loading_manager.dart'; class NotificationsPage extends StatefulWidget { static const String id = "/notifications"; const NotificationsPage({Key? key}) : super(key: key); @override _NotificationsPageState createState() => _NotificationsPageState(); } class _NotificationsPageState extends State with TickerProviderStateMixin { late NotificationsProvider _notificationsProvider; late UserProvider _userProvider; final TextEditingController _searchController = TextEditingController(); int _selectedTabIndex = 0; // 0: All, 1: Unread, 2: Read String _searchQuery = ''; bool isAscending = false; NotificationFilterModel? _activeFilters; Timer? _debounceTimer; @override void initState() { super.initState(); // Initialize filter model with default isRead = 0 (All) _activeFilters = NotificationFilterModel(isRead: 0); // Load notifications when page loads WidgetsBinding.instance.addPostFrameCallback((_) { _loadNotifications(); }); } @override void dispose() { _searchController.dispose(); _debounceTimer?.cancel(); super.dispose(); } /// Load notifications from API Future _loadNotifications() async { final notificationsProvider = Provider.of(context, listen: false); final userProvider = Provider.of(context, listen: false); // Update filter model with search, sort, and tab selection _activeFilters ??= NotificationFilterModel(); _activeFilters!.searchText = _searchQuery.isEmpty ? null : _searchQuery; _activeFilters!.isAscending = isAscending; _activeFilters!.isRead = _selectedTabIndex; // 0 = All, 1 = Unread, 2 = Read // Reset and fetch fresh data with filters notificationsProvider.reset(); await notificationsProvider.getSystemNotifications( user: userProvider.user!, resetProvider: true, filters: _activeFilters, ); } void _onSearchChanged(String value) { setState(() { _searchQuery = value; }); // Cancel previous timer _debounceTimer?.cancel(); // Start new timer (500ms debounce) _debounceTimer = Timer(const Duration(milliseconds: 500), () { _loadNotifications(); }); } /// Toggle sort order and reload data void _toggleSort() { setState(() { isAscending = !isAscending; }); _loadNotifications(); } List get _filteredNotifications { // Tab filtering is now handled by API via isRead parameter // No need for local filtering return _notificationsProvider.notifications; } int get _unreadCount { return _notificationsProvider.totalNotificationUnread; } int get _allCount { return _notificationsProvider.totalAllNotifications; } int get _readCount { return _notificationsProvider.totalNotificationRead; } /// Get count of active filters int get _activeFilterCount { if (_activeFilters == null) return 0; int count = 0; if (_activeFilters!.priorityIds?.isNotEmpty ?? false) count++; if (_activeFilters!.moduleIds?.isNotEmpty ?? false) count++; if (_activeFilters!.subModuleIds?.isNotEmpty ?? false) count++; if (_activeFilters!.startDate != null) count++; if (_activeFilters!.endDate != null) count++; return count; } @override Widget build(BuildContext context) { _notificationsProvider = Provider.of(context); _userProvider = Provider.of(context); return Scaffold( appBar: DefaultAppBar( title: context.translation.notifications, actions: [ TextButton.icon( onPressed: _unreadCount > 0 ? () async { showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); final result = await _notificationsProvider.markAllAsRead( userId: _userProvider.user!.userID!, ); if (context.mounted) { Navigator.of(context).pop(); } if (context.mounted && result['message'] != null) { '${result['message']}'.showToast; } } : null, icon: 'Icon_mark_read'.toSvgAsset( width: 12, height: 12, color: AppColor.primary10, ), label: Text( 'Mark All as Read', style: AppTextStyles.bodyText2.copyWith( color: AppColor.primary10, fontWeight: FontWeight.w500, ), ), style: TextButton.styleFrom( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), foregroundColor: _unreadCount > 0 ? AppColor.primary10 : AppColor.neutral30, ), ), ], ), body: SafeArea( child: Column( spacing: 12.toScreenHeight, crossAxisAlignment: CrossAxisAlignment.end, children: [ 12.height, AppTextFormField( controller: _searchController, labelText: context.translation.search, showShadow: false, showBorder: true, prefixIconData: Icons.search, onChange: (value) { _onSearchChanged(value); }, ), // 8.height, Row( children: [ Expanded( child: SizedBox( height: 30.toScreenHeight, child: ListView.separated( scrollDirection: Axis.horizontal, itemCount: 3, separatorBuilder: (context, index) => 8.width, itemBuilder: (context, index) { final labels = ['All Notifications', 'Read', 'Unread']; final counts = [_allCount, _readCount, _unreadCount]; return NotificationTabButton( label: labels[index], count: counts[index], isSelected: _selectedTabIndex == index, onTap: () { setState(() { _selectedTabIndex = index; }); // Reload notifications with new tab filter _loadNotifications(); }, ); }, ), ), ), 8.width, // Sort & Filter Container Container( height: 30.toScreenHeight, padding: const EdgeInsets.symmetric(horizontal: 6), decoration: BoxDecoration( boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 14, offset: const Offset(0, 0), spreadRadius: 0)], color: AppColor.background(context), borderRadius: BorderRadius.circular(6), border: Border.all(color: AppColor.borderColor(context)), ), child: Row( children: [ // Sort Icon Transform.flip( flipY: isAscending, child: 'dashboard/sort_descending' .toSvgAsset( width: 20, height: 20, color: AppColor.iconColor(context), ) .onPress(() { _toggleSort(); }), ), 14.width, // Filter Icon Stack( clipBehavior: Clip.none, children: [ 'filter' .toSvgAsset( width: 20, height: 20, color: AppColor.iconColor(context), ) .onPress(() async { // Open filter page final result = await Navigator.push( context, MaterialPageRoute( builder: (context) => NotificationFilterPage(data: _activeFilters), ), ); if (result != null) { setState(() { _activeFilters = result; }); _loadNotifications(); } }), // Active Filters Badge we are not using custom badge widget here as it need more customizations if (_activeFilterCount > 0) Positioned( right: -8, top: -12, child: Container( padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 2), decoration: BoxDecoration( color: AppColor.red30, borderRadius: BorderRadius.circular(10), border: Border.all(color: AppColor.white10, width: 1.5), ), constraints: const BoxConstraints( minWidth: 16, minHeight: 16, ), child: Text( '$_activeFilterCount', textAlign: TextAlign.center, style: AppTextStyles.tinyFont2.copyWith( color: AppColor.white10, fontWeight: FontWeight.w600, fontSize: 9, ), ), ), ), ], ), ], ), ), ], ), // 8.height, // Notifications List Expanded( child: LoadingManager( isLoading: (_notificationsProvider.isLoading) && _notificationsProvider.notifications.isEmpty, isFailedLoading: false, stateCode: _notificationsProvider.stateCode, onRefresh: () async { _notificationsProvider.reset(); await _notificationsProvider.getSystemNotifications( user: _userProvider.user!, resetProvider: true, filters: _activeFilters, ); }, child: NotificationsList( nextPage: _notificationsProvider.nextPage, onLazyLoad: () async { await _notificationsProvider.getSystemNotifications( user: _userProvider.user!, filters: _activeFilters, ); }, notifications: _filteredNotifications, ), ), ), ], ).paddingOnly(start: 12, end: 12), ), ); } }