diff --git a/lib/controllers/providers/api/notifications_provider.dart b/lib/controllers/providers/api/notifications_provider.dart index 6da2120d..5ddf1103 100644 --- a/lib/controllers/providers/api/notifications_provider.dart +++ b/lib/controllers/providers/api/notifications_provider.dart @@ -163,7 +163,7 @@ class NotificationsProvider extends ChangeNotifier { /// Returns true if successful, false otherwise Future markOneAsRead({required String notificationId}) async { try { - final response = await ApiManager.instance.get("${URLs.markOneNotificationAsRead}?NotificationId=$notificationId"); + final response = await ApiManager.instance.get("${URLs.markOneNotificationAsRead}?NotificationId=$notificationId", enableToastMessage: false); if (response.statusCode >= 200 && response.statusCode < 300) { // Update the specific notification in the local list to read status @@ -215,4 +215,4 @@ class NotificationsProvider extends ChangeNotifier { return null; } } -} \ No newline at end of file +} diff --git a/lib/models/system_notification_model.dart b/lib/models/system_notification_model.dart index bb64637d..492c3575 100644 --- a/lib/models/system_notification_model.dart +++ b/lib/models/system_notification_model.dart @@ -12,6 +12,7 @@ class SystemNotificationModel { String? createdOn; String? modifiedOn; String? priorityName; + int? priorityValue; String? statusName; int? transactionType; String? moduleName; @@ -38,6 +39,7 @@ class SystemNotificationModel { this.createdOn, this.modifiedOn, this.priorityName, + this.priorityValue, this.transactionType, this.statusName, this.moduleName, @@ -65,6 +67,7 @@ class SystemNotificationModel { createdOn = json['createdDate'] ?? json['createdOn']; modifiedOn = json['modifiedOn']; priorityName = json['priorityName']; + priorityValue = json['priorityValue']; statusName = json['statusName']; transactionType = json['transactionType']; moduleName = json['moduleName']; @@ -94,6 +97,7 @@ class SystemNotificationModel { data['createdOn'] = createdOn; data['modifiedOn'] = modifiedOn; data['priorityName'] = priorityName; + data['priorityValue'] = priorityValue; data['priority'] = priorityName; data['statusName'] = statusName; data['transactionType'] = transactionType; @@ -120,6 +124,7 @@ class SystemNotificationModel { data['createdOn'] = createdOn; data['modifiedOn'] = modifiedOn; data['priorityName'] = priorityName; + data['priorityValue'] = priorityValue; data['statusName'] = statusName; data['transactionType'] = transactionType; data['moduleName'] = moduleName; diff --git a/lib/modules/notification_setting/view/widgets/notification_preference_card.dart b/lib/modules/notification_setting/view/widgets/notification_preference_card.dart index c3dcdcb1..773eff4c 100644 --- a/lib/modules/notification_setting/view/widgets/notification_preference_card.dart +++ b/lib/modules/notification_setting/view/widgets/notification_preference_card.dart @@ -30,14 +30,14 @@ class NotificationPreferenceCard extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, + spacing: 4.toScreenHeight, children: [ if(isMandatory) ...[ 4.height, Text( 'You cannot update this notification as it is mandatory.'.addTranslation, - style: AppTextStyle.body2.copyWith( + style: AppTextStyle.tiny.copyWith( color: AppColor.red30, - fontSize: 10.toScreenWidth, ), ), ], @@ -54,27 +54,23 @@ class NotificationPreferenceCard extends StatelessWidget { _buildCompactToggle(context, isEnabled, isMandatory), ], ), - 4.height, InfoTextWidget( label: context.translation.notificationModule, value: template.moduleName ?? '', ), - 4.height, InfoTextWidget( label: 'Sub Module'.addTranslation, value: template.subModuleName ?? '', ), - 4.height, if (template.templateChannels != null && template.templateChannels!.isNotEmpty) ...[ InfoTextLabelWidget( label: '${context.translation.channelPreference} :', ), - 8.height, _buildChannelChips(context, isMandatory), ], ], - ).toShadowContainer(context,padding: 16); + ).toShadowContainer(context); } Widget _buildCompactToggle(BuildContext context, bool isEnabled, bool isMandatory) { diff --git a/lib/new_views/app_style/app_color.dart b/lib/new_views/app_style/app_color.dart index 9933673e..396caf88 100644 --- a/lib/new_views/app_style/app_color.dart +++ b/lib/new_views/app_style/app_color.dart @@ -418,6 +418,42 @@ class AppColor { } } + //0 critical, 1 high, 2 low, 3 medium, + + static Color getNotificationPriorityStatusTextColor(BuildContext context, int id) { + switch (id) { + //low priority + case 2: + return greenStatusColor; + case 3: + return greenStatusTextColor; + case 0: + return redStatusTextColor; + case 1: + return redStatusTextColor; + default: + return defaultStatusTextColor(context); + } + } + + + static Color getNotificationPriorityStatusColor(BuildContext context, int id) { + switch (id) { + //low priority + case 2: + return greenStatusColor; + case 0: + return redStatusColor; + //high priority + case 1: + return redStatusColor; + case 3: + return greenStatusColor; + default: + return defaultStatusColor(context); + } + } + static Color getPriorityStatusColor(BuildContext context, int id) { switch (id) { //low priority diff --git a/lib/views/pages/user/notifications/notification_filter_page.dart b/lib/views/pages/user/notifications/notification_filter_page.dart index 334f94a6..ef48a331 100644 --- a/lib/views/pages/user/notifications/notification_filter_page.dart +++ b/lib/views/pages/user/notifications/notification_filter_page.dart @@ -98,7 +98,7 @@ class _NotificationFilterPageState extends State { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: AppColor.scaffold2Background(context), + // backgroundColor: AppColor.scaffold2Background(context), appBar: DefaultAppBar( title: context.translation.filter, actions: [ @@ -126,17 +126,16 @@ class _NotificationFilterPageState extends State { body: Column( children: [ SingleChildScrollView( - padding: const EdgeInsets.all(16), + padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - // Filter by Priority InfoHeader16Widget("Priority"), 8.height, SingleItemDropDownMenu( context: context, - showAsBottomSheet: true, - showShadow: false, + showAsFullScreenDialog: true, + showShadow: true, title: "Select Priority", initialValue: selectedPriority, onSelect: (value) { @@ -151,15 +150,15 @@ class _NotificationFilterPageState extends State { }, ), - 16.height, + 12.height, // Filter by Module InfoHeader16Widget("Module"), 8.height, SingleItemDropDownMenu( context: context, - showAsBottomSheet: true, - showShadow: false, + showAsFullScreenDialog: true, + showShadow: true, title: "Select Module", initialValue: selectedModule, onSelect: (value) { @@ -177,15 +176,15 @@ class _NotificationFilterPageState extends State { }, ), - 16.height, + 12.height, // Filter by SubModule - InfoHeader16Widget( "SubModule"), + InfoHeader16Widget("SubModule"), 8.height, SingleItemDropDownMenu( context: context, - showAsBottomSheet: true, - showShadow: false, + showAsFullScreenDialog: true, + showShadow: true, title: "Select SubModule", initialValue: selectedSubModule, enabled: selectedModule?.subModules?.isNotEmpty ?? false, @@ -202,10 +201,10 @@ class _NotificationFilterPageState extends State { }, ), - 16.height, + 12.height, // Date Range Filter - context.translation.pickDate.heading5(context).custom(color: AppColor.textStyleColor(context)), + InfoHeader16Widget(context.translation.pickDate), 8.height, Row( children: [ @@ -239,7 +238,6 @@ class _NotificationFilterPageState extends State { ], ), ).expanded, - 16.height, FooterActionButton.footerContainer( context: context, child: AppFilledButton( diff --git a/lib/views/pages/user/notifications/notifications_list.dart b/lib/views/pages/user/notifications/notifications_list.dart index b6549706..051593f4 100644 --- a/lib/views/pages/user/notifications/notifications_list.dart +++ b/lib/views/pages/user/notifications/notifications_list.dart @@ -5,6 +5,7 @@ import 'package:provider/provider.dart'; import 'package:test_sa/controllers/notification/firebase_notification_manger.dart'; import 'package:test_sa/controllers/providers/api/notifications_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/system_notification_model.dart'; import 'package:test_sa/views/pages/user/notifications/widgets/notification_card_redesigned.dart'; @@ -27,22 +28,17 @@ class NotificationsList extends StatelessWidget { nextPage: nextPage, onLazyLoad: onLazyLoad, child: ListView.separated( - // padding: const EdgeInsets.all(16), itemCount: notifications.length, - separatorBuilder: (context, itemIndex) => const SizedBox(height: 12), + separatorBuilder: (context, itemIndex) => 12.height, itemBuilder: (context, itemIndex) { final notification = notifications[itemIndex]; return NotificationCardRedesigned( notification: notification, onTap: () async { - // Mark notification as read when tapped - log('i am tapped with id ${notification.toJson()}'); if (notification.id != null && !(notification.readed ?? false)) { final provider = Provider.of(context, listen: false); await provider.markOneAsRead(notificationId: notification.id!); } - - // Navigate to notification details FirebaseNotificationManger.handleMessage(context, notification.toNotificationJson()); }, ); diff --git a/lib/views/pages/user/notifications/notifications_page.dart b/lib/views/pages/user/notifications/notifications_page.dart index c1207f19..8e4a68ea 100644 --- a/lib/views/pages/user/notifications/notifications_page.dart +++ b/lib/views/pages/user/notifications/notifications_page.dart @@ -16,7 +16,6 @@ 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 'package:test_sa/views/widgets/loaders/app_loading.dart'; import 'dart:async'; import '../../../widgets/loaders/loading_manager.dart'; @@ -80,7 +79,6 @@ class _NotificationsPageState extends State with TickerProvid ); } - /// Handle search with debounce void _onSearchChanged(String value) { setState(() { _searchQuery = value; @@ -141,7 +139,6 @@ class _NotificationsPageState extends State with TickerProvid _userProvider = Provider.of(context); return Scaffold( - backgroundColor: AppColor.scaffold2Background(context), appBar: DefaultAppBar( title: context.translation.notifications, actions: [ @@ -181,37 +178,26 @@ class _NotificationsPageState extends State with TickerProvid ), body: SafeArea( child: Column( + spacing: 12.toScreenHeight, crossAxisAlignment: CrossAxisAlignment.end, children: [ - // Search Section - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - 8.height, - AppTextFormField( - controller: _searchController, - labelText: context.translation.search, - showShadow: false, - showBorder: true, - prefixIconData: Icons.search, - hintText: 'Search by Title or content'.addTranslation, - hintStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.labelTextStyleColor(context)), - contentPadding: const EdgeInsets.symmetric(vertical: 14, horizontal: 16), - onChange: (value) { - _onSearchChanged(value); - }, - ), - ], + 12.height, + AppTextFormField( + controller: _searchController, + labelText: context.translation.search, + showShadow: false, + showBorder: true, + prefixIconData: Icons.search, + onChange: (value) { + _onSearchChanged(value); + }, ), - - 16.height, - - // Notification Tabs + // 8.height, Row( children: [ Expanded( child: SizedBox( - height: 35.toScreenHeight, + height: 30.toScreenHeight, child: ListView.separated( scrollDirection: Axis.horizontal, itemCount: 3, @@ -238,9 +224,10 @@ class _NotificationsPageState extends State with TickerProvid 8.width, // Sort & Filter Container Container( - height: 35.toScreenHeight, - padding: const EdgeInsets.symmetric(horizontal: 8), + 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)), @@ -287,7 +274,7 @@ class _NotificationsPageState extends State with TickerProvid _loadNotifications(); } }), - // Active Filters Badge + // Active Filters Badge we are not using custom badge widget here as it need more customizations if (_activeFilterCount > 0) Positioned( right: -8, @@ -321,15 +308,12 @@ class _NotificationsPageState extends State with TickerProvid ), ], ), - - 16.height, - + // 8.height, // Notifications List Expanded( child: LoadingManager( isLoading: (_notificationsProvider.isLoading) && _notificationsProvider.notifications.isEmpty, isFailedLoading: false, - // Don't show error state, show no data found instead stateCode: _notificationsProvider.stateCode, onRefresh: () async { _notificationsProvider.reset(); @@ -352,7 +336,7 @@ class _NotificationsPageState extends State with TickerProvid ), ), ], - ).paddingOnly(start: 16, end: 16), + ).paddingOnly(start: 12, end: 12), ), ); } diff --git a/lib/views/pages/user/notifications/widgets/notification_card_redesigned.dart b/lib/views/pages/user/notifications/widgets/notification_card_redesigned.dart index 5ea5790b..36184dc9 100644 --- a/lib/views/pages/user/notifications/widgets/notification_card_redesigned.dart +++ b/lib/views/pages/user/notifications/widgets/notification_card_redesigned.dart @@ -1,11 +1,14 @@ import 'package:flutter/material.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/system_notification_model.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/views/widgets/item_views/info_date_widget.dart'; import 'package:test_sa/views/widgets/item_views/info_header_widget.dart'; import 'package:test_sa/views/widgets/item_views/info_text_widget.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; class NotificationCardRedesigned extends StatelessWidget { final SystemNotificationModel notification; @@ -20,112 +23,55 @@ class NotificationCardRedesigned extends StatelessWidget { @override Widget build(BuildContext context) { final isUnread = !(notification.readed ?? false); - return Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: AppColor.background(context), - borderRadius: BorderRadius.circular(8), - border: Border.all(color: AppColor.borderColor(context)), - ), - child: InkWell( - onTap: onTap, - borderRadius: BorderRadius.circular(8), - child: Column( + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 4.toScreenHeight, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + if (notification.priorityName != null && notification.priorityValue != null) + StatusLabel( + label: notification.priorityName!, + radius: 4, + textColor: AppColor.getNotificationPriorityStatusTextColor(context, notification.priorityValue!), + backgroundColor: AppColor.getNotificationPriorityStatusColor(context, notification.priorityValue!), + ), + if (notification.createdOn?.isNotEmpty ?? false) InfoDateWidget(notification.createdOn ?? ""), + ], + ), + Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - // Priority Badge & Date Row - Row( - children: [ - // Priority Badge - if (notification.priorityName != null && notification.priorityName!.isNotEmpty) - Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: AppColor.getRequestStatusColorByName( - context, - notification.priorityName!, - ), - borderRadius: BorderRadius.circular(4), - ), - child: Text( - notification.priorityName!, - style: AppTextStyles.tinyFont2.copyWith( - color: AppColor.getRequestStatusTextColorByName( - context, - notification.priorityName!, - ), - fontWeight: FontWeight.w600, - ), - ), - ), - const Spacer(), - - // Date & Time - Top Right - if (notification.createdOn?.isNotEmpty ?? false) - InfoDateWidget(notification.createdOn ?? ""), - ], - ), - 8.height, - - // Title with Unread Dot - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Unread indicator (blue dot) - aligned with title - if (isUnread) - Padding( - padding: const EdgeInsets.only(top: 6, right: 8), - child: Container( - width: 8, - height: 8, - decoration: const BoxDecoration( - color: AppColor.primary10, - shape: BoxShape.circle, - ), - ), - ), - - // Title - Expanded( - child: InfoHeader16Widget( - notification.title ?? '', - ), - ), - ], - ), - 8.height, - if (notification.sourceName?.isNotEmpty ?? false) - Container( - padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: AppColor.primary10.withValues(alpha: 0.1), - borderRadius: BorderRadius.circular(4), - ), - child: Text( - notification.sourceName!, - style: AppTextStyles.tinyFont2.copyWith( + if (isUnread) + Padding( + padding: const EdgeInsets.only(top: 6, right: 8), + child: Container( + width: 8, + height: 8, + decoration: const BoxDecoration( color: AppColor.primary10, - fontWeight: FontWeight.w500, + shape: BoxShape.circle, ), ), ), - if (notification.sourceName?.isNotEmpty ?? false) 8.height, - - // Message Preview - if (notification.text?.isNotEmpty ?? false) - InfoTextLabelWidget( - label: notification.text!, - // style: AppTextStyles.bodyText2.copyWith( - // color: AppColor.textColor(context), - // height: 1.4, - // ), - // maxLines: 3, - // overflow: TextOverflow.ellipsis, + Expanded( + child: InfoHeader16Widget( + notification.title ?? '', ), + ), ], ), - ), - ); + if (notification.sourceName?.isNotEmpty ?? false) + InfoTextWidget( + label: 'Source'.addTranslation, + value: notification.sourceName ?? '', + ), + if (notification.text?.isNotEmpty ?? false) + InfoTextLabelWidget( + label: notification.text!, + ), + ], + ).toShadowContainer(context).onPress(onTap); } - -} \ No newline at end of file +} diff --git a/lib/views/pages/user/notifications/widgets/notification_tab_button.dart b/lib/views/pages/user/notifications/widgets/notification_tab_button.dart index 754871af..64ecff9a 100644 --- a/lib/views/pages/user/notifications/widgets/notification_tab_button.dart +++ b/lib/views/pages/user/notifications/widgets/notification_tab_button.dart @@ -22,7 +22,7 @@ class NotificationTabButton extends StatelessWidget { onTap: onTap, child: Container( alignment: Alignment.center, - padding: const EdgeInsets.symmetric(horizontal: 12), + padding: const EdgeInsets.symmetric(horizontal: 6), decoration: ShapeDecoration( color: AppColor.background(context), shape: RoundedRectangleBorder(