diff --git a/lib/config/loading_overlay.dart b/lib/config/loading_overlay.dart index 6830314b..c5d2b97f 100644 --- a/lib/config/loading_overlay.dart +++ b/lib/config/loading_overlay.dart @@ -22,7 +22,7 @@ class LoadingOverlay { color: Colors.black.withOpacity(0.5), dismissible: false), Center( child: Image.asset( - "assets/images/loading.gif", // Make sure to add the GIF in assets + "assets/FCSC-GIF.gif", // Make sure to add the GIF in assets width: 100, height: 100, ), diff --git a/lib/config/my_router.dart b/lib/config/my_router.dart index 12b4006e..9d3ad5f7 100644 --- a/lib/config/my_router.dart +++ b/lib/config/my_router.dart @@ -364,302 +364,305 @@ final FlutterSecureStorage _secureStorage = const FlutterSecureStorage(); // } final GoRouter router = GoRouter( - initialLocation: '/', - routes: [ - GoRoute( - path: '/', - //builder: (context, state) => MyHomePage(), - builder: (context, state) => SessionCheckScreen(), - ), - // GoRoute( - // path: '/', - // redirect: (context, state) async => await _checkSession(), - // ), - GoRoute( - path: '/internetcheck', - builder: (context, state) => InternetCheck(), - ), - GoRoute( - path: '/login', - builder: (context, state) => LoginRoute(), - //builder: (context, state) => LoginRoute(), - ), - GoRoute( - path: '/myhomepage', - builder: (context, state) => MyHomePage(), - ), - GoRoute( - path: '/register', - builder: (context, state) => RegisterScreen(), - ), - // GoRoute( - // path: '/DemoHome/:dataSets', - // builder: (context, state) { - // final dataSets = state.pathParameters['dataSets']!; - // print('Router $dataSets'); - // return ChartPage(dataSets: dataSets); - // }, - // ), - // GoRoute( - // path: '/Chart/:dataSets', - // builder: (context, state) { - // final dataSets = state.pathParameters['dataSets']!; - // print('Router $dataSets'); - // return ChartScreen(dataSets: dataSets); - // }, - // ), - GoRoute( - path: '/chartScreen/:dataSets', - builder: (context, state) { - // Retrieve path parameter - final dataSets = state.pathParameters['dataSets']!; - // Retrieve query parameter - final bgColor = state.uri.queryParameters['bgColor'] ?? - '0xFFFFFFFF'; // Default white - final mainTopic = state.uri.queryParameters['mainTopic'] ?? ''; - final title = state.uri.queryParameters['title'] ?? ''; - final key = state.uri.queryParameters['key'] ?? ''; - final kpi = state.uri.queryParameters['kpi'] ?? ''; // Get kpi + initialLocation: '/', + routes: [ + GoRoute( + path: '/', + //builder: (context, state) => MyHomePage(), + builder: (context, state) => SessionCheckScreen(), + ), + // GoRoute( + // path: '/', + // redirect: (context, state) async => await _checkSession(), + // ), + GoRoute( + path: '/internetcheck', + builder: (context, state) => InternetCheck(), + ), + GoRoute( + path: '/login', + builder: (context, state) => LoginRoute(), + //builder: (context, state) => LoginRoute(), + ), + GoRoute( + path: '/myhomepage', + builder: (context, state) => MyHomePage(), + ), + GoRoute( + path: '/register', + builder: (context, state) => RegisterScreen(), + ), + // GoRoute( + // path: '/DemoHome/:dataSets', + // builder: (context, state) { + // final dataSets = state.pathParameters['dataSets']!; + // print('Router $dataSets'); + // return ChartPage(dataSets: dataSets); + // }, + // ), + // GoRoute( + // path: '/Chart/:dataSets', + // builder: (context, state) { + // final dataSets = state.pathParameters['dataSets']!; + // print('Router $dataSets'); + // return ChartScreen(dataSets: dataSets); + // }, + // ), + GoRoute( + path: '/chartScreen/:dataSets', + builder: (context, state) { + // Retrieve path parameter + final dataSets = state.pathParameters['dataSets']!; + // Retrieve query parameter + final bgColor = state.uri.queryParameters['bgColor'] ?? + '0xFFFFFFFF'; // Default white + final mainTopic = state.uri.queryParameters['mainTopic'] ?? ''; + final title = state.uri.queryParameters['title'] ?? ''; + final key = state.uri.queryParameters['key'] ?? ''; + final kpi = state.uri.queryParameters['kpi'] ?? ''; // Get kpi - // Parse filter_data as a JSON list - // Parse filter_data as a JSON list - List> filterData = []; + // Parse filter_data as a JSON list + // Parse filter_data as a JSON list + List> filterData = []; - if (state.uri.queryParameters.containsKey('filter_data') && - state.uri.queryParameters['filter_data']!.isNotEmpty) { - try { - filterData = List>.from( - jsonDecode(state.uri.queryParameters['filter_data']!)); - } catch (e) { - print('Error parsing filter_data: $e'); - filterData = []; // Assign an empty list to prevent null issues + if (state.uri.queryParameters.containsKey('filter_data') && + state.uri.queryParameters['filter_data']!.isNotEmpty) { + try { + filterData = List>.from( + jsonDecode(state.uri.queryParameters['filter_data']!)); + } catch (e) { + print('Error parsing filter_data: $e'); + filterData = []; // Assign an empty list to prevent null issues + } + } else { + filterData = []; // Ensure it's a valid list } - } else { - filterData = []; // Ensure it's a valid list - } - print('Router dataSets: $dataSets'); - print('Router bgColor: $bgColor'); - print('Router mainTopic: $mainTopic'); - print('Router title: $title'); - print('Router filter: $filterData'); + print('Router dataSets: $dataSets'); + print('Router bgColor: $bgColor'); + print('Router mainTopic: $mainTopic'); + print('Router title: $title'); + print('Router filter: $filterData'); - // Pass both values to the screen - return ChartScreen1( - dataSets: dataSets, - bgColor: bgColor, - mainTopic: mainTopic, - title: title, - keyParam: key, - kpi: kpi, - filter_data: filterData, - ); - }, - ), - GoRoute( - path: '/mailverification', - builder: (context, state) => EmailVerificationScreen( - email: '', - userId: '', - otp: '', - otpId: '', - sendVerificationCode: (String) {}, + // Pass both values to the screen + return ChartScreen1( + dataSets: dataSets, + bgColor: bgColor, + mainTopic: mainTopic, + title: title, + keyParam: key, + kpi: kpi, + filter_data: filterData, + ); + }, ), - ), - GoRoute( - path: '/changepassword/:userId', - builder: (context, state) { - final userId = state.pathParameters['userId']!; - return Changepassword(userId: userId); - }, - ), - GoRoute( - path: '/createNewPw/:userId/:email', - builder: (context, state) { - final userId = state.pathParameters['userId']!; - final email = state.pathParameters['email']!; - final key = state.uri.queryParameters['key'] ?? ''; - - return CreateNewPw(userId: userId, email: email, keyParam: key); - }, - ), - GoRoute( - path: '/confirmpasswd', - builder: (context, state) => ConfirmPassword( - email: '', - userId: '', + GoRoute( + path: '/mailverification', + builder: (context, state) => EmailVerificationScreen( + email: '', + userId: '', + otp: '', + otpId: '', + sendVerificationCode: (String) {}, + ), + ), + GoRoute( + path: '/changepassword/:userId', + builder: (context, state) { + final userId = state.pathParameters['userId']!; + return Changepassword(userId: userId); + }, + ), + GoRoute( + path: '/createNewPw/:userId/:email', + builder: (context, state) { + final userId = state.pathParameters['userId']!; + final email = state.pathParameters['email']!; + final key = state.uri.queryParameters['key'] ?? ''; + + return CreateNewPw(userId: userId, email: email, keyParam: key); + }, + ), + GoRoute( + path: '/confirmpasswd', + builder: (context, state) => ConfirmPassword( + email: '', + userId: '', + ), + ), + GoRoute( + path: '/terms&conditions', + builder: (context, state) => TermsOfUse(), + //builder: (context, state) => LoginRoute(), + ), + GoRoute( + path: '/privacy_policy', + builder: (context, state) => PrivacyPolicy(), + //builder: (context, state) => LoginRoute(), ), - ), - GoRoute( - path: '/terms&conditions', - builder: (context, state) => TermsOfUse(), - //builder: (context, state) => LoginRoute(), - ), - GoRoute( - path: '/privacy_policy', - builder: (context, state) => PrivacyPolicy(), - //builder: (context, state) => LoginRoute(), - ), // Drawer Routers - GoRoute( - path: '/feedback', - builder: (context, state) => FeedbackForm(), - ), - //Sub route - GoRoute( - path: '/profile/:userId', - builder: (context, state) { - final userId = state.pathParameters['userId']!; - return ProfileScreen(userId: userId); - }, - ), - GoRoute( - path: '/notification', - builder: (context, state) { - // final userId = state.pathParameters['userId']!; - return NotificationPage(); - }, - ), - GoRoute( - path: '/notification_details', - builder: (context, state) { - final Map data = state.extra as Map; - return NotificationDetails( - title: data['title'] ?? '', - message: data['message'] ?? '', - date: data['date'] ?? '', - category: data['category'] ?? '', - ); - }, - ), - GoRoute( - path: '/user-guide', - builder: (context, state) => Userguide(), - routes: [ - GoRoute( - path: '/features', - name: 'features', - builder: (context, state) => UsingFeatures(), - routes: [ - GoRoute( - path: 'whoUseApp', - name: 'whoUseApp', - builder: (context, state) => WhoUseTheApp(), - ), - GoRoute( - path: 'howUseApp', - name: 'howUseApp', - builder: (context, state) => HowUseTheApp(), - ), - GoRoute( - path: 'purpose', - name: 'purpose', - builder: (context, state) => Purpose(), - ), - GoRoute( - path: 'stayUpdated', - name: 'stayUpdated', - builder: (context, state) => StayUpdate(), - ), - GoRoute( - path: 'changeMyPassword', - name: 'changeMyPassword', - builder: (context, state) => ChangeMyPassword(), - ), - GoRoute( - path: 'appFeatures', - name: 'appFeatures', - builder: (context, state) => AppFeatures(), - ), - GoRoute( - path: 'editMyProfile', - name: 'editMyProfile', - builder: (context, state) => EditMyProfile(), - ), - ], - ), - GoRoute( - path: 'aboutApp', - builder: (context, state) => aboutTheApp(), + GoRoute( + path: '/feedback', + builder: (context, state) => FeedbackForm(), + ), + //Sub route + GoRoute( + path: '/profile/:userId', + builder: (context, state) { + final userId = state.pathParameters['userId']!; + return ProfileScreen(userId: userId); + }, + ), + GoRoute( + path: '/notification', + builder: (context, state) { + // final userId = state.pathParameters['userId']!; + return NotificationPage(); + }, + ), + GoRoute( + path: '/notification_details', + builder: (context, state) { + final Map data = state.extra as Map; + return NotificationDetails( + title: data['title'] ?? '', + message: data['message'] ?? '', + date: data['date'] ?? '', + category: data['category'] ?? '', + id: data['id'] ?? '', + backNavigation: data['backNavigation'] ?? '', + ); + }, + ), + GoRoute( + path: '/user-guide', + builder: (context, state) => Userguide(), + routes: [ + GoRoute( + path: '/features', + name: 'features', + builder: (context, state) => UsingFeatures(), routes: [ GoRoute( - path: 'aboutFCSC', - name: 'aboutFCSC', - builder: (context, state) => aboutFCSC(), + path: 'whoUseApp', + name: 'whoUseApp', + builder: (context, state) => WhoUseTheApp(), ), GoRoute( - path: 'getStarted', - name: 'getStarted', - builder: (context, state) => GetStarted(), + path: 'howUseApp', + name: 'howUseApp', + builder: (context, state) => HowUseTheApp(), ), - ]), - GoRoute( - path: '/faq', - name: 'faq', - builder: (context, state) => FAQPage(), - ), - ], - ), - // GoRoute( - // path: '/manageuser', - // builder: (context, state) { - // // Retrieve the title from extra or query params - // final title = state.extra as String? ?? 'Manage users'; - // return ManageUserRouter(title: title); - // }, - // ), - GoRoute( - path: '/editProfile', - builder: (context, state) => EditProfile(), - ), - GoRoute( - path: '/bookmark', - builder: (context, state) => BookMark(), - ), - GoRoute( - path: '/manageuser', - builder: (context, state) => ManageUserRouter(), - ), + GoRoute( + path: 'purpose', + name: 'purpose', + builder: (context, state) => Purpose(), + ), + GoRoute( + path: 'stayUpdated', + name: 'stayUpdated', + builder: (context, state) => StayUpdate(), + ), + GoRoute( + path: 'changeMyPassword', + name: 'changeMyPassword', + builder: (context, state) => ChangeMyPassword(), + ), + GoRoute( + path: 'appFeatures', + name: 'appFeatures', + builder: (context, state) => AppFeatures(), + ), + GoRoute( + path: 'editMyProfile', + name: 'editMyProfile', + builder: (context, state) => EditMyProfile(), + ), + ], + ), + GoRoute( + path: 'aboutApp', + builder: (context, state) => aboutTheApp(), + routes: [ + GoRoute( + path: 'aboutFCSC', + name: 'aboutFCSC', + builder: (context, state) => aboutFCSC(), + ), + GoRoute( + path: 'getStarted', + name: 'getStarted', + builder: (context, state) => GetStarted(), + ), + ]), + GoRoute( + path: '/faq', + name: 'faq', + builder: (context, state) => FAQPage(), + ), + ], + ), + // GoRoute( + // path: '/manageuser', + // builder: (context, state) { + // // Retrieve the title from extra or query params + // final title = state.extra as String? ?? 'Manage users'; + // return ManageUserRouter(title: title); + // }, + // ), + GoRoute( + path: '/editProfile', + builder: (context, state) => EditProfile(), + ), + GoRoute( + path: '/bookmark', + builder: (context, state) => BookMark(), + ), + GoRoute( + path: '/manageuser', + builder: (context, state) => ManageUserRouter(), + ), - // Bottom Navigation Routes - // GoRoute( - // path: '/uaenumbers', - // builder: (context, state) => UaeNumbers(), - // ), - GoRoute(path: '/uaenumbers', builder: (context, state) => UaeNumbers()), + // Bottom Navigation Routes + // GoRoute( + // path: '/uaenumbers', + // builder: (context, state) => UaeNumbers(), + // ), + GoRoute(path: '/uaenumbers', builder: (context, state) => UaeNumbers()), - GoRoute( - path: '/competitiveness', - builder: (context, state) => Competitiveness(), - ), + GoRoute( + path: '/competitiveness', + builder: (context, state) => Competitiveness(), + ), - GoRoute( - path: '/countryprofile', - builder: (context, state) => CountryProfile(), - ), + GoRoute( + path: '/countryprofile', + builder: (context, state) => CountryProfile(), + ), - GoRoute( - path: '/marriages', - builder: (context, state) => Marriages(), - ), + GoRoute( + path: '/marriages', + builder: (context, state) => Marriages(), + ), - GoRoute( - path: '/contact', - builder: (context, state) => Contact(), - ), - ], + GoRoute( + path: '/contact', + builder: (context, state) => Contact(), + ), + ], redirect: (context, state) async { - if (state.uri.path == '/SessionCheckScreen' || state.uri.path == '/login') { + if (state.uri.path == '/SessionCheckScreen' || + state.uri.path == '/login') { return null; } final session = await PAuthRepo().fetchLocallyStored(); if (session == null || session.freshness == SessionFreshness.expired) { - print('Session expired, redirecting to login with intendedPath: ${state.uri.path}'); + print( + 'Session expired, redirecting to login with intendedPath: ${state.uri.path}'); return '/login${state.uri.path != '/' ? '?intendedPath=${state.uri.path}' : ''}'; } return null; - } -); + }); diff --git a/lib/l10n/intl_ar.arb b/lib/l10n/intl_ar.arb index 0d4c6344..9019afdb 100644 --- a/lib/l10n/intl_ar.arb +++ b/lib/l10n/intl_ar.arb @@ -45,6 +45,13 @@ "account_confirmation": "هل لديك حساب؟ سجل الدخول", "login_title": "تسجيل الدخول", + "all_updates": "جميع التحديثات", + "app_updates": "تحديثات التطبيق", + "notificationSocial": "اجتماعي", + "notificationEconomy": "اقتصاد", + "notificationEnvironment": "بيئة", + "notificationFavourites": "المفضلة", + "profile_title": "نموذج الملاحظات", "my_profile": "ملفي الشخصي", "logout": "تسجيل الخروج", diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 1ca84b01..5debfd51 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -1,8 +1,8 @@ { - "all_bookmarks":"All Bookmarks", - "economy_title":"Economy", - "social_title":"Social", - "environment_title":"Environment", + "all_bookmarks": "All Bookmarks", + "economy_title": "Economy", + "social_title": "Social", + "environment_title": "Environment", "bookmarks": "Bookmarks", "feedback_title": "Feedback", @@ -41,7 +41,12 @@ "account_confirmation": "Already have an account?", "login_title": "Login", - + "all_updates": "All updates", + "app_updates": "App updates", + "notificationSocial": "Social", + "notificationEconomy": "Economy", + "notificationEnvironment": "Environment", + "notificationFavourites": "Favourites", "profile_title": "Edit Profile", "my_profile": "My Profile", diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart b/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart index 776231d3..459d9585 100644 --- a/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart @@ -65,7 +65,19 @@ class _EditProfileState extends State { 'India', 'Canada', ]; + final List preferred_language = ['English', 'Arabic']; + final Map languageMap = { + "en": "English", + "ar": "Arabic", + }; + +// Reverse mapping for saving back to API + final Map reverseLanguageMap = { + "English": "en", + "Arabic": "ar", + }; String? _selectedCountry; + String? _selectedLanguage; bool isChecked = false; bool showError = false; final _picker = ImagePicker(); @@ -82,6 +94,7 @@ class _EditProfileState extends State { dynamic role; bool _isHoveringDropdown = false; + bool _isHoveringPreferredLang = false; @override void initState() { @@ -177,10 +190,16 @@ class _EditProfileState extends State { print('userDetails: $userDetailsResponse'); setState(() { + setState(() { + _selectedLanguage = + languageMap[userDetailsResponse.data['language']] ?? + 'English'; // Default to English if not found + }); _usernameController.text = userDetailsResponse.data['uname'] ?? ''; _emailController.text = userDetailsResponse.data['email'] ?? ''; _fullNameController.text = userDetailsResponse.data['full_name'] ?? ''; _selectedCountry = userDetailsResponse.data['country_region'] ?? ''; + // _selectedLanguage = userDetailsResponse.data['language'] ?? ''; _isProfileCompleted = userDetailsResponse.data['is_profile_completed'] ?? false; //_isProfileCompleted = true ; @@ -321,6 +340,13 @@ class _EditProfileState extends State { return null; } + String? _validatePreferredLang(String? value) { + if (value == null || value.isEmpty) { + return context.translate('Required', 'مطلوب'); + } + return null; + } + void _toggleCheckbox(bool? value) { setState(() { isChecked = value ?? false; @@ -335,7 +361,8 @@ class _EditProfileState extends State { // if (result == true) { // Validate only the country field - if (_validateDropdown(_selectedCountry) == null) { + if (_validateDropdown(_selectedCountry) == null && + _validatePreferredLang(_selectedLanguage) == null) { try { String userID = userId; @@ -343,6 +370,7 @@ class _EditProfileState extends State { // Retrieve data from the country/region field String countryRegion = _selectedCountry ?? ''; // Ensure the country is selected + String preferredLang = _selectedLanguage ?? ''; // Create a multipart request final uri = @@ -352,6 +380,7 @@ class _EditProfileState extends State { // Add fields to the request request.fields['country_region'] = countryRegion; // Only update country here + request.fields['language'] = preferredLang == 'English' ? 'en' : 'ar'; // If profile image exists, add it if (_profileImage != null) { @@ -406,6 +435,7 @@ class _EditProfileState extends State { _fullNameController.clear(); _dateController.clear(); _selectedCountry = null; + _selectedLanguage = null; isChecked = false; // Reset profile image @@ -829,6 +859,73 @@ class _EditProfileState extends State { validator: _validateDropdown, ), ), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + AppLocalizations.of(context)! + .preferredLang, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500), + ), + ], + ), + SizedBox(height: 10), + MouseRegion( + onEnter: (_) => setState( + () => _isHoveringPreferredLang = true), + onExit: (_) => setState( + () => _isHoveringPreferredLang = false), + child: DropdownButtonFormField( + style: TextStyle( + fontFamily: 'Roboto', + fontSize: 16, + fontWeight: FontWeight.normal, + color: Color(0xFF544C4C), + ), + value: _selectedLanguage, + decoration: InputDecoration( + enabledBorder: OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: MyTheme.topicColor( + IndicatorTopic.economy) + .shade400, + width: 1), // Enabled border + ), + border: OutlineInputBorder( + borderSide: BorderSide( + color: Color(0xFF7296BE), + ), + borderRadius: + BorderRadius.circular(8), + ), + labelText: 'Select', + ), + icon: Icon( + Icons.keyboard_arrow_down_sharp, + color: _isHoveringPreferredLang + ? Colors.black + : Colors.grey), + items: preferred_language + .map( + (item) => DropdownMenuItem( + value: item, + child: Text(item), + ), + ) + .toList(), + onChanged: (String? newValue) { + setState(() { + _selectedLanguage = newValue; + }); + }, + validator: _validatePreferredLang, + ), + ), + SizedBox(height: 20), if (!_isProfileCompleted) // Conditional rendering Column( diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/notification/notification.dart b/lib/presentation/routes/drawer_routes/Drawer Items/notification/notification.dart index 889200a7..6f8c3470 100644 --- a/lib/presentation/routes/drawer_routes/Drawer Items/notification/notification.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/notification/notification.dart @@ -10,6 +10,7 @@ import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/presentation/components/indicators/locale_provider.dart'; import '../../custom_drawer_routes.dart'; import 'package:http/http.dart' as http; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class NotificationPage extends ConsumerStatefulWidget { @override @@ -66,6 +67,7 @@ class _NotificationPageState extends ConsumerState { setState(() { notifications = List>.from( jsonResponse['data']); // Assign decoded data + print('notifications $notifications'); }); } else { throw Exception('Failed to load data'); @@ -100,13 +102,21 @@ class _NotificationPageState extends ConsumerState { final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null fetchNotifications(localeCode); }); + final List> tabs = [ + {'title': AppLocalizations.of(context)!.all_updates}, + {'title': AppLocalizations.of(context)!.app_updates}, + {'title': AppLocalizations.of(context)!.notificationSocial}, + {'title': AppLocalizations.of(context)!.notificationEconomy}, + {'title': AppLocalizations.of(context)!.notificationEnvironment}, + {'title': AppLocalizations.of(context)!.notificationFavourites}, + ]; + // Filter notifications based on the selected tab List> filteredNotifications = selectedTabIndex == 0 ? notifications : notifications.where((notification) { - print( - "Comparing: '${notification["category"]}' with '${tabs[selectedTabIndex]}'"); - return notification["category"] == tabs[selectedTabIndex]; + // print("Comparing: '${notification["category"]}' with '${tabs[selectedTabIndex]}'"); + return notification["category"] == tabs[selectedTabIndex]['title']; }).toList(); return PopScope( @@ -125,7 +135,7 @@ class _NotificationPageState extends ConsumerState { body: Column( children: [ TabBarHeader( - tabs: tabs, + tabs: tabs.map((tab) => tab['title'] as String).toList(), selectedIndex: selectedTabIndex, onTabSelected: (index) { setState(() { @@ -162,10 +172,12 @@ class _NotificationPageState extends ConsumerState { ), ), child: NotificationTile( - title: notification['title'] ?? 'No Title', - date: formatDate(notification['created'] ?? ''), - category: notification['category'] ?? 'Unknown', - message: notification['message'] ?? ''), + title: notification['title'] ?? 'No Title', + date: formatDate(notification['created'] ?? ''), + category: notification['category'] ?? 'Unknown', + message: notification['message'] ?? '', + id: notification['id'], + ), ); }, ), @@ -240,23 +252,28 @@ class NotificationTile extends StatelessWidget { final String message; final String date; final String category; + final String id; const NotificationTile({ required this.title, required this.message, required this.date, required this.category, + required this.id, }); @override Widget build(BuildContext context) { return GestureDetector( onTap: () { + final encodedKey = Uri.encodeQueryComponent('notification'); context.go('/notification_details', extra: { 'title': title, 'message': message, 'date': date, 'category': category, + 'id': id, + 'backNavigation': encodedKey }); }, child: ListTile( diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/notification/notification_details.dart b/lib/presentation/routes/drawer_routes/Drawer Items/notification/notification_details.dart index 83f5c21c..fa0916d4 100644 --- a/lib/presentation/routes/drawer_routes/Drawer Items/notification/notification_details.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/notification/notification_details.dart @@ -1,14 +1,22 @@ +import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; +import 'package:intl/intl.dart'; +import 'package:pocketbase/pocketbase.dart'; +import 'package:uae_stat/config/api_config.dart'; import 'package:uae_stat/domain/use_cases/language.dart'; -import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; +import 'package:uae_stat/presentation/components/indicators/locale_provider.dart'; +import '../../custom_drawer_routes.dart'; +import 'package:http/http.dart' as http; -class NotificationDetails extends ConsumerWidget { +class NotificationDetails extends ConsumerStatefulWidget { final String title; final String message; final String date; final String category; + final String id; + final String backNavigation; const NotificationDetails({ super.key, @@ -16,10 +24,85 @@ class NotificationDetails extends ConsumerWidget { required this.message, required this.date, required this.category, + required this.id, + required this.backNavigation, }); @override - Widget build(BuildContext context, WidgetRef ref) { + _NotificationDetailsState createState() => _NotificationDetailsState(); +} + +class _NotificationDetailsState extends ConsumerState { + // Example notification data + final _pb = PocketBase(apiUrl); + Map? notification; + + // Current selected tab index + int selectedTabIndex = 0; + late final Locale locale; + dynamic notificationID; + + @override + void initState() { + super.initState(); + print(widget.id); + locale = ref.read(localeProvider) ?? const Locale('en'); + fetchNotifications(locale?.languageCode ?? 'en'); + } + + String formatDate(String dateString) { + try { + DateTime dateTime = + DateTime.parse(dateString); // Convert API date to DateTime + return DateFormat('dd MMM yyyy hh:mm a') + .format(dateTime); // Format DateTime + } catch (e) { + return 'Invalid Date'; // Handle parsing errors + } + } + + Future fetchNotifications(locale) async { + notificationID = widget.id; + final baseUrl = apiUrl + '/api/getNotification'; + try { + final response = await http + .get(Uri.parse('$baseUrl?language=$locale&id=$notificationID')); + + if (response.statusCode == 200) { + final Map jsonResponse = + jsonDecode(response.body); // Decode JSON + + if (jsonResponse['message'] == 'Success') { + setState(() { + final data = jsonResponse['data']; + notification = data; + // if (data is Map) { + // notification = data; + // } else { + // notification = null; // Default to null if data is not valid + // } + + print('notification $notification'); + }); + } else { + throw Exception('Failed to load data'); + } + } else { + throw Exception( + 'Failed to load data with status code ${response.statusCode}'); + } + } catch (e) { + print('Error fetching data: $e'); + } + } + + @override + Widget build(BuildContext context) { + ref.listen(localeProvider, (previous, next) { + final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null + fetchNotifications(localeCode); + }); + return PopScope( canPop: false, onPopInvokedWithResult: (didPop, result) { @@ -34,13 +117,14 @@ class NotificationDetails extends ConsumerWidget { ), ), showBackButton: true, + navBackArrow: Text(widget.backNavigation ?? 'Default Value'), body: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - title, + notification?['title'] ?? '', style: const TextStyle( fontSize: 18, fontWeight: FontWeight.w500, @@ -52,7 +136,7 @@ class NotificationDetails extends ConsumerWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ Image.asset( - category == 'App updates' + notification?['category'] == 'App updates' ? 'assets/backgrounds/Notification/App-Update.png' : 'assets/backgrounds/Notification/Update_notific.png', height: 200, @@ -62,9 +146,8 @@ class NotificationDetails extends ConsumerWidget { ), const SizedBox(height: 20), Text( - message.isNotEmpty - ? message - : "No additional details available.", + notification?['message'] ?? + "No additional details available.", style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w400, @@ -72,11 +155,12 @@ class NotificationDetails extends ConsumerWidget { ), const SizedBox(height: 10), Text( - "Date: $date", + "Date: ${notification != null ? formatDate(notification!['created'] ?? '') : 'N/A'}", style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w400, - color: Color(0xFF8E8E8E)), + fontSize: 12, + fontWeight: FontWeight.w400, + color: Color(0xFF8E8E8E), + ), ), ], ), diff --git a/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart b/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart index a601217e..c557fbb0 100644 --- a/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart +++ b/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart @@ -67,6 +67,7 @@ class _BaseScaffoldState extends ConsumerState { String? userEmail; String? userAvatar; String? role; + String? preferredLanguage; String? userNames; String? userEmails; String? userAvatars; @@ -654,17 +655,23 @@ class _BaseScaffoldState extends ConsumerState { userEmail = userDetailsResponse.data['email'] ?? ''; userAvatar = userDetailsResponse.data['avatar'] ?? ''; role = userDetailsResponse.data['role'] ?? ''; + preferredLanguage = userDetailsResponse.data['language'] ?? ''; String recordId = userId; String collectionId = userDetailsResponse.data['collectionId'] ?? '_pb_users_auth_'; if (userAvatar!.isNotEmpty && recordId.isNotEmpty) { - _avatarUrl = - '$apiUrl/api/files/$collectionId/$recordId/$userAvatar'; + _avatarUrl = '$apiUrl/api/files/$collectionId/$recordId/$userAvatar'; } else { _avatarUrl = ''; // Reset to default or empty } }); + // **Set Default Locale in Provider** + if (preferredLanguage == 'ar') { + ref.read(localeProvider.notifier).setLocale(const Locale('ar')); + } else { + ref.read(localeProvider.notifier).setLocale(const Locale('en')); + } } catch (e) { print('Error fetching user details: $e'); } @@ -706,7 +713,9 @@ class _BaseScaffoldState extends ConsumerState { title: Padding( padding: EdgeInsets.only(top: 10), child: Align( - alignment: (locale?.languageCode == 'ar') ? Alignment.centerRight : Alignment.centerLeft, + alignment: (locale?.languageCode == 'ar') + ? Alignment.centerRight + : Alignment.centerLeft, child: DefaultTextStyle( style: TextStyle( color: widget.colorChange ? Colors.white : Color(0xFF414042), @@ -775,12 +784,12 @@ class _BaseScaffoldState extends ConsumerState { color: widget.colorChange ? Colors.white : Colors.black, icon: const Icon(Icons.arrow_back_ios_new, size: 24), onPressed: () { - // if ((widget.navBackArrow as Text).data == 'home') { - // context.go('/myhomepage'); - // } else { - // context.go('/uaenumbers'); - // } - context.pop(); + if ((widget.navBackArrow as Text).data == + 'notification') { + context.go('/notification'); + } else { + context.pop(); + } }, ), ), @@ -1195,7 +1204,7 @@ void _showLogoutConfirmationDialog(BuildContext context) { ), actions: [ Row( - mainAxisAlignment:MainAxisAlignment.spaceEvenly, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox(