diff --git a/lib/main.dart b/lib/main.dart index cdeca31..f95acd1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:cheminova/constants/constant.dart'; import 'package:cheminova/provider/add_sales_provider.dart'; import 'package:cheminova/provider/collect_kyc_provider.dart'; +import 'package:cheminova/provider/notification_provider.dart'; import 'package:cheminova/provider/pd_rd_provider.dart'; import 'package:cheminova/provider/product_manual_provider.dart'; import 'package:cheminova/provider/product_provider.dart'; @@ -109,6 +110,7 @@ Future main() async { ChangeNotifierProvider(create: (_) => TaskProvider()), ChangeNotifierProvider(create: (_) => ProductManualProvider()), ChangeNotifierProvider(create: (_) => AddSalesProvider()), + ChangeNotifierProvider(create: (_) => NotificationProvider()), ], child: const MyApp(), ), diff --git a/lib/models/announcement_model.dart b/lib/models/announcement_model.dart new file mode 100644 index 0000000..c5c94d2 --- /dev/null +++ b/lib/models/announcement_model.dart @@ -0,0 +1,19 @@ +class AnnouncementModel { + String id; + String message; + String date; + + AnnouncementModel({ + required this.id, + required this.message, + required this.date, + }); + + factory AnnouncementModel.fromJson(Map json) { + return AnnouncementModel( + id: json['_id'], + message: json['message'], + date: json['createdAt'], + ); + } +} diff --git a/lib/models/pd_rd_response_model.dart b/lib/models/pd_rd_response_model.dart index 2979b26..f59e2ac 100644 --- a/lib/models/pd_rd_response_model.dart +++ b/lib/models/pd_rd_response_model.dart @@ -65,7 +65,7 @@ class ShippingAddress { postalCode: json['postalCode'] ?? '', country: json['country'] ?? '', panNumber: json['panNumber'] ?? '', - tradeName: json['tradeName'] ?? '', + tradeName: json['tradeName'] ?? 'XYZ', gstNumber: json['gstNumber'] ?? '', isDefault: json['isDefault'] ?? false, ); diff --git a/lib/provider/login_provider.dart b/lib/provider/login_provider.dart index fd032f1..405804a 100644 --- a/lib/provider/login_provider.dart +++ b/lib/provider/login_provider.dart @@ -5,7 +5,6 @@ import 'package:cheminova/services/secure__storage_service.dart'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; - class LoginProvider extends ChangeNotifier { final _storageService = SecureStorageService(); @@ -29,7 +28,8 @@ class LoginProvider extends ChangeNotifier { 'email': emailController.text.trim(), 'password': passwordController.text.trim() }); - setLoading(false); + + // Handle successful response if (response.statusCode == 200) { await _storageService.write( key: 'access_token', value: response.data['token']); @@ -37,12 +37,25 @@ class LoginProvider extends ChangeNotifier { print('fcmToken: $fcmToken'); await _apiClient.post(ApiUrls.fcmUrl, data: {'fcmToken': fcmToken}); return (true, response.data['message'].toString()); - } else { - return (false, response.data['message'].toString()); } - } catch (e) { + + // Handle other status codes + setLoading(false); + return (false, response.data['message'].toString()); + } catch (e) { + // Handle DioError specifically + if (e is DioException) { + setLoading(false); + if (e.response != null && e.response!.statusCode == 400) { + return (false, e.response!.data['message'].toString()); + } + } + + setLoading(false); + // Return a more informative error message if there's an exception + return (false, 'Something went wrong: ${e.toString()}'); + } finally { setLoading(false); - return (false, 'Something want wrong'); } } } diff --git a/lib/provider/notification_provider.dart b/lib/provider/notification_provider.dart index 6dbcdbf..571499c 100644 --- a/lib/provider/notification_provider.dart +++ b/lib/provider/notification_provider.dart @@ -1,3 +1,4 @@ +import 'package:cheminova/models/announcement_model.dart'; import 'package:dio/dio.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -13,10 +14,12 @@ class NotificationProvider extends ChangeNotifier { final _apiClient = ApiClient(); List notificationList = []; + List _announcementList = []; bool _isLoading = false; bool get isLoading => _isLoading; + List get announcementList => _announcementList; void setLoading(bool loading) { _isLoading = loading; @@ -26,15 +29,32 @@ class NotificationProvider extends ChangeNotifier { Future getNotification() async { setLoading(true); try { - Response response = await _apiClient.get(ApiUrls.notificationUrl); - setLoading(false); - if (response.statusCode == 200) { - final data = NotificationListResponse.fromJson(response.data); - notificationList = data.notifications ?? []; - notifyListeners(); - } + Response response = await _apiClient.get(ApiUrls.notificationUrl); + setLoading(false); + if (response.statusCode == 200) { + final data = NotificationListResponse.fromJson(response.data); + notificationList = data.notifications ?? []; + notifyListeners(); + } } catch (e) { setLoading(false); } } + + Future getAnnouncement() async { + setLoading(true); + try { + Response response = await _apiClient.get(ApiUrls.announcements); + if (response.statusCode == 200) { + _announcementList = (response.data as List) + .map((e) => AnnouncementModel.fromJson(e)) + .toList(); + notifyListeners(); + } + setLoading(false); + } catch (e) { + print(e); + setLoading(false); + } + } } diff --git a/lib/screens/announcement_screen.dart b/lib/screens/announcement_screen.dart new file mode 100644 index 0000000..e909af3 --- /dev/null +++ b/lib/screens/announcement_screen.dart @@ -0,0 +1,93 @@ +import 'package:cheminova/provider/notification_provider.dart'; +import 'package:cheminova/utils/string_extension.dart'; +import 'package:cheminova/widgets/common_app_bar.dart'; +import 'package:cheminova/widgets/common_background.dart'; +import 'package:cheminova/widgets/common_drawer.dart'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; + +class AnnouncementScreen extends StatefulWidget { + const AnnouncementScreen({super.key}); + + @override + State createState() => _AnnouncementScreenState(); +} + +class _AnnouncementScreenState extends State { + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + context.read().getAnnouncement(); + }); + } + + @override + Widget build(BuildContext context) { + final notificationProvider = context.watch(); + return CommonBackground( + child: Scaffold( + backgroundColor: Colors.transparent, + appBar: CommonAppBar( + actions: [ + IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: Image.asset('assets/Back_attendance.png'), + padding: const EdgeInsets.only(right: 20), + ), + ], + title: const Text('Announcement', + style: TextStyle( + fontSize: 20, + color: Colors.black, + fontWeight: FontWeight.w400, + fontFamily: 'Anek')), + backgroundColor: Colors.transparent, + elevation: 0, + ), + drawer: const CommonDrawer(), + body: Stack( + children: [ + ListView.builder( + itemCount: notificationProvider.announcementList.length, + itemBuilder: (context, index) { + return Container( + margin: const EdgeInsets.only( + bottom: 10, + left: 10, + right: 10, + ), + decoration: const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(10))), + child: ListTile( + title: const Text('Message:'), + subtitle: Text( + '${notificationProvider.announcementList[index].message.capitalize()}\nDate: ${DateFormat("dd/MM/yyyy").format( + DateTime.parse(notificationProvider + .announcementList[index].date), + )}', + ), + ), + ); + }), + if (notificationProvider.isLoading) + Container( + height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.width, + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.2), + ), + child: const Center( + child: CircularProgressIndicator(), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/screens/assign_tasks_screen.dart b/lib/screens/assign_tasks_screen.dart index bd82f9a..bb242da 100644 --- a/lib/screens/assign_tasks_screen.dart +++ b/lib/screens/assign_tasks_screen.dart @@ -394,15 +394,12 @@ class _AssignTasksScreenState extends State { .map((PdRdResponseModel distributor) { return DropdownMenuItem( value: distributor, - child: Text( - (selectedDistributorType == - 'PrincipalDistributor' - ? distributor - .shippingAddress!.tradeName - .capitalize() - : distributor.kyc!.tradeName - .capitalize()), - ), + child: Text(((selectedDistributorType == + 'PrincipalDistributor') + ? distributor + .shippingAddress!.tradeName + : distributor.kyc!.tradeName) + .capitalize()), ); }).toList(), onChanged: (value) { diff --git a/lib/screens/change_password_screen.dart b/lib/screens/change_password_screen.dart index 574c614..59f426d 100644 --- a/lib/screens/change_password_screen.dart +++ b/lib/screens/change_password_screen.dart @@ -123,6 +123,7 @@ class _ChangePasswordPageState extends State { const SizedBox(height: 20), CommonTextFormField( controller: _oldPasswordController, + textCapitalization: TextCapitalization.none, validator: (value) { if (value == null || value.isEmpty) { return 'Please enter your password'; @@ -133,6 +134,7 @@ class _ChangePasswordPageState extends State { const SizedBox(height: 20), CommonTextFormField( controller: _newPasswordController, + textCapitalization: TextCapitalization.none, validator: (value) { if (value == null || value.isEmpty) { return 'Please enter your password'; @@ -143,6 +145,7 @@ class _ChangePasswordPageState extends State { const SizedBox(height: 20), CommonTextFormField( controller: _confirmPasswordController, + textCapitalization: TextCapitalization.none, validator: (value) { if (value == null || value.isEmpty) { return 'Please enter your password'; diff --git a/lib/screens/forgot_password_screen.dart b/lib/screens/forgot_password_screen.dart index fc4c68e..6077243 100644 --- a/lib/screens/forgot_password_screen.dart +++ b/lib/screens/forgot_password_screen.dart @@ -141,6 +141,8 @@ class _ForgotPasswordScreenState extends State { const SizedBox(height: 20), CommonTextFormField( title: ' Enter Your Email ID', + textCapitalization: TextCapitalization.none, + keyboardType: TextInputType.emailAddress, validator: (value) { if (value == null || value.isEmpty) { return 'Please enter your email id'; diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index 62ca66e..394daf3 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -1,5 +1,6 @@ import 'package:cheminova/notification_service.dart'; import 'package:cheminova/provider/user_provider.dart'; +import 'package:cheminova/screens/announcement_screen.dart'; import 'package:cheminova/screens/visit_rd_pd_screen.dart'; import 'package:cheminova/screens/assign_task_dash_board_screen.dart'; import 'package:cheminova/screens/calendar_screen.dart'; @@ -188,21 +189,24 @@ class _HomePageState extends State { ], ), const SizedBox(height: 5), - Row( - children: [ - Expanded( - child: _buildCustomCard('Rejected Applications', - 'Re-upload Rejected Documents', onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - const RejectedApplicationScreen(), - )); - }), - ), - ], - ), + _buildCustomCard('Rejected Applications', + 'Re-upload Rejected Documents', onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + const RejectedApplicationScreen(), + )); + }), + const SizedBox(height: 5), + _buildCustomCard('Announcements', 'Announcements for you', + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const AnnouncementScreen(), + )); + }), const SizedBox(height: 5), Row( children: [ diff --git a/lib/screens/login_screen.dart b/lib/screens/login_screen.dart index 020fe1b..8bb0a08 100644 --- a/lib/screens/login_screen.dart +++ b/lib/screens/login_screen.dart @@ -87,6 +87,7 @@ class _LoginPageState extends State { Consumer( builder: (context, value, child) => CommonTextFormField( + textCapitalization: TextCapitalization.none, controller: value.emailController, keyboardType: TextInputType.emailAddress, validator: (value) { @@ -99,20 +100,24 @@ class _LoginPageState extends State { } return null; }, - title: 'Username'), + title: 'Email'), ), const SizedBox(height: 20), Consumer( - builder: (context, value, child) => - CommonTextFormField( - controller: value.passwordController, - validator: (value) { - if (value == null || value.isEmpty) { - return 'Please enter your password'; - } - return null; - }, - title: 'Password')), + builder: (context, value, child) => + CommonTextFormField( + textCapitalization: TextCapitalization.none, + obscureText: true, + controller: value.passwordController, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter your password'; + } + return null; + }, + title: 'Password', + ), + ), const SizedBox(height: 15), Align( alignment: Alignment.center, diff --git a/lib/screens/select_distributer_screen.dart b/lib/screens/select_distributer_screen.dart index 13a57e8..0e69df4 100644 --- a/lib/screens/select_distributer_screen.dart +++ b/lib/screens/select_distributer_screen.dart @@ -178,11 +178,11 @@ class _SelectDistributerScreenState extends State { return DropdownMenuItem( value: distributor, child: Text( - selectedDistributorType == - 'PrincipalDistributor' - ? distributor.shippingAddress!.tradeName - .capitalize() - : distributor.kyc!.tradeName.capitalize(), + ((selectedDistributorType == + 'Principal Distributor') + ? distributor.shippingAddress!.tradeName + : distributor.kyc!.tradeName) + .capitalize(), ), ); }).toList(), diff --git a/lib/services/api_urls.dart b/lib/services/api_urls.dart index 9dc6ef3..5cd36c0 100644 --- a/lib/services/api_urls.dart +++ b/lib/services/api_urls.dart @@ -24,4 +24,5 @@ class ApiUrls { static const String postSalesTaskUrl = '${baseUrl}sales/add-TM'; static const String visitRdPd = '$baseUrl/visit'; static const String allTaskByDate = '${baseUrl}task/alltask'; + static const String announcements = '${baseUrl}announcement/TMs'; } diff --git a/lib/utils/string_extension.dart b/lib/utils/string_extension.dart index 5d92948..eb58e2d 100644 --- a/lib/utils/string_extension.dart +++ b/lib/utils/string_extension.dart @@ -1,5 +1,6 @@ extension StringExtension on String { String capitalize() { - return "${this[0].toUpperCase()}${substring(1).toLowerCase()}"; + if (isEmpty) return this; + return "${this[0].toUpperCase()}${substring(1)}"; } } diff --git a/lib/widgets/common_drawer.dart b/lib/widgets/common_drawer.dart index 2115caa..a3273a4 100644 --- a/lib/widgets/common_drawer.dart +++ b/lib/widgets/common_drawer.dart @@ -63,7 +63,7 @@ class CommonDrawer extends StatelessWidget { leading: const Icon(Icons.home), title: const Text('Home'), onTap: () { - Navigator.push( + Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => const HomePage()), ); diff --git a/lib/widgets/common_text_form_field.dart b/lib/widgets/common_text_form_field.dart index 1fad71b..3546486 100644 --- a/lib/widgets/common_text_form_field.dart +++ b/lib/widgets/common_text_form_field.dart @@ -48,8 +48,8 @@ class CommonTextFormField extends StatelessWidget { controller: controller, textCapitalization: textCapitalization, readOnly: readOnly ?? false, - maxLines: maxLines, - maxLength: maxLength, + // maxLines: maxLines, + // maxLength: maxLength, onChanged: onChanged, onTapOutside: (event) => FocusScope.of(context).unfocus(), validator: validator,