diff --git a/lib/main.dart b/lib/main.dart index 25be7cb..8eeccca 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,17 +1,13 @@ import 'package:cheminova/provider/collect_kyc_provider.dart'; -import 'package:cheminova/screens/Attendance_success.dart'; -import 'package:cheminova/screens/forgot_password_screen.dart'; -import 'package:cheminova/screens/login_screen.dart'; -import 'package:cheminova/screens/mark_attendence_screen.dart'; -import 'package:cheminova/screens/on_leave_screen.dart'; +import 'package:cheminova/provider/user_provider.dart'; import 'package:cheminova/screens/splash_screen.dart'; -import 'package:cheminova/services/snackbar_service.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; void main() { runApp(MultiProvider(providers: [ - ChangeNotifierProvider(create: (context) => CollectKycProvider()) + ChangeNotifierProvider(create: (context) => CollectKycProvider()), + ChangeNotifierProvider(create: (_) => UserProvider()), ], child: const MyApp())); } diff --git a/lib/models/user_model.dart b/lib/models/user_model.dart new file mode 100644 index 0000000..d77b39d --- /dev/null +++ b/lib/models/user_model.dart @@ -0,0 +1,26 @@ +class UserModel { + String id; + String name; + String email; + String uniqueId; + bool isVerified; + + UserModel({ + required this.id, + required this.name, + required this.email, + required this.uniqueId, + required this.isVerified, + }); + + factory UserModel.fromJson(Map json) { + return UserModel( + id: json['_id'], + name: json['name'], + email: json['email'], + uniqueId: json['uniqueId'], + isVerified: json['isVerified'], + ); + } +} + diff --git a/lib/provider/login_provider.dart b/lib/provider/login_provider.dart index d6410e0..fa2622a 100644 --- a/lib/provider/login_provider.dart +++ b/lib/provider/login_provider.dart @@ -23,8 +23,10 @@ class LoginProvider extends ChangeNotifier { Future<(bool, String)> login() async { setLoading(true); try { - Response response = await _apiClient.post(ApiUrls.loginUrl, - data: {'email': emailController.text.trim(), 'password': passwordController.text.trim()}); + Response response = await _apiClient.post(ApiUrls.loginUrl, data: { + 'email': emailController.text.trim(), + 'password': passwordController.text.trim() + }); setLoading(false); if (response.statusCode == 200) { await _storageService.write( @@ -33,9 +35,22 @@ class LoginProvider extends ChangeNotifier { } else { return (false, response.data['message'].toString()); } + } on DioException catch (e) { + setLoading(false); + + if (e.response?.data is Map) { + return ( + false, + e.response?.data['message'].toString() ?? 'something went wrong' + ); + } else if (e.response?.data is String) { + return (false, e.response?.data.toString() ?? 'something went wrong'); + } else { + return (false, 'something went wrong'); + } } catch (e) { setLoading(false); - return (false, 'Something want wrong'); + return (false, 'something went wrong'); } } } diff --git a/lib/provider/user_provider.dart b/lib/provider/user_provider.dart new file mode 100644 index 0000000..05592fc --- /dev/null +++ b/lib/provider/user_provider.dart @@ -0,0 +1,48 @@ +import 'package:cheminova/models/user_model.dart'; +import 'package:cheminova/services/api_client.dart'; +import 'package:cheminova/services/api_urls.dart'; +import 'package:cheminova/services/secure__storage_service.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +class UserProvider extends ChangeNotifier { + final _apiClient = ApiClient(); + + UserModel? _user; + bool _isLoading = false; + + UserModel? get user => _user; + bool get isLoading => _isLoading; + + void setLoading(bool loading) { + _isLoading = loading; + notifyListeners(); + } + + Future fetchUserProfile() async { + setLoading(true); + try { + Response response = await _apiClient.get( + ApiUrls.profileUrl, + ); + setLoading(false); + if (response.statusCode == 200) { + final data = response.data['myData']; + await SecureStorageService().write(key: 'user', value: data.toString()); + _user = UserModel.fromJson(data); + + notifyListeners(); + } else { + throw Exception('Failed to load user profile'); + } + } catch (e) { + setLoading(false); + throw Exception('Failed to load user profile: $e'); + } + } + + Future clearUserProfile() async { + _user = null; + notifyListeners(); + } +} diff --git a/lib/screens/change_password_screen.dart b/lib/screens/change_password_screen.dart index c5236ea..f792ca7 100644 --- a/lib/screens/change_password_screen.dart +++ b/lib/screens/change_password_screen.dart @@ -1,12 +1,12 @@ -import 'package:cheminova/provider/login_provider.dart'; import 'package:cheminova/screens/password_change_screen.dart'; +import 'package:cheminova/services/api_client.dart'; +import 'package:cheminova/services/api_urls.dart'; import 'package:cheminova/widgets/common_app_bar.dart'; import 'package:cheminova/widgets/common_background.dart'; import 'package:cheminova/widgets/common_elevated_button.dart'; import 'package:cheminova/widgets/common_text_form_field.dart'; +import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; - import '../widgets/common_drawer.dart'; class ChangePasswordPage extends StatefulWidget { @@ -19,130 +19,174 @@ class ChangePasswordPage extends StatefulWidget { class _ChangePasswordPageState extends State { final _formKey = GlobalKey(); + final _oldPasswordController = TextEditingController(); + final _newPasswordController = TextEditingController(); + final _confirmPasswordController = TextEditingController(); + + bool _isLoading = false; + + Future<(bool, String)> _changePassword() async { + if (_formKey.currentState!.validate()) { + setState(() { + _isLoading = true; + }); + try { + final apiClient = ApiClient(); + + Response response = + await apiClient.put(ApiUrls.changePasswordUrl, data: { + 'oldPassword': _oldPasswordController.text.trim(), + 'newPassword': _newPasswordController.text.trim(), + 'confirmPassword': _confirmPasswordController.text.trim(), + }); + if (response.statusCode == 200) { + setState(() { + _isLoading = false; + }); + return (true, response.data['message'].toString()); + } else { + return (false, response.data['message'].toString()); + } + } on DioException catch (e) { + setState(() { + _isLoading = false; + }); + if (e.response?.data is Map) { + return ( + false, + e.response?.data['message'].toString() ?? 'something went wrong' + ); + } else if (e.response?.data is String) { + return (false, e.response?.data.toString() ?? 'something went wrong'); + } else { + return (false, 'something went wrong'); + } + } catch (e) { + setState(() { + _isLoading = false; + }); + return (false, 'something went wrong'); + } + } else { + return (false, 'something went wrong'); + } + } + @override Widget build(BuildContext context) { - return CommonBackground( - isFullWidth: true, + return CommonBackground( + isFullWidth: true, child: Scaffold( - drawer: const CommonDrawer(), - + drawer: const CommonDrawer(), backgroundColor: Colors.transparent, - appBar: CommonAppBar( - - title: const Text(''), - backgroundColor: Colors.transparent, - elevation: 0, - actions: [ - IconButton( - onPressed: () { - Navigator.pop(context); - }, - icon: Image.asset('assets/Back_attendance.png'), - padding: const EdgeInsets.only(right: 20), - ), - ], - ), - body: SingleChildScrollView( - child: Column( - children: [ - // const SizedBox(height: 50), - // const SizedBox(height: 60), - Container( - padding: - const EdgeInsets.all(20.0).copyWith(top: 15, bottom: 30), - margin: const EdgeInsets.symmetric(horizontal: 30.0), - decoration: BoxDecoration( - border: Border.all(color: Colors.white), - color: const Color(0xffB4D1E5).withOpacity(0.9), - borderRadius: BorderRadius.circular(26.0)), - child: Form( - key: _formKey, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - const SizedBox(height: 20), - const Text('Change Password', - style: TextStyle( - fontSize: 30, - color: Colors.black, - fontWeight: FontWeight.w500, - fontFamily: 'Roboto')), - const SizedBox(height: 20), - CommonTextFormField( - // controller: value.emailController, - validator: (value) { - if (value == null || value.isEmpty) { - return 'Please enter your email id'; - } - if (!RegExp(r'^[^@\s]+@[^@\s]+\.[^@\s]+$') - .hasMatch(value)) { - return 'Please enter a valid email id'; - } - return null; - }, - title: 'Current Password'), - const SizedBox(height: 20), - CommonTextFormField( - // controller: value.passwordController, - validator: (value) { - if (value == null || value.isEmpty) { - return 'Please enter your password'; - } - return null; - }, - title: 'New Password'), const SizedBox(height: 20), - CommonTextFormField( - // controller: value.passwordController, - validator: (value) { - if (value == null || value.isEmpty) { - return 'Please enter your password'; - } - return null; - }, - title: 'Confirm Password'), - const SizedBox(height: 15), - Align( - alignment: Alignment.center, - child: CommonElevatedButton( - backgroundColor: const Color(0xff004791), - borderRadius: 30, - width: double.infinity, - height: kToolbarHeight - 10, - text: 'SIGN IN', - isLoading: false, - onPressed: () { - Navigator.push(context, MaterialPageRoute(builder:(context) => const PasswordChangeScreen())); - }, - // onPressed: value.isLoading - // ? null - // : () async { - // if (_formKey.currentState!.validate()) { - // value.login().then((result) { - // var (status, message) = result; - // ScaffoldMessenger.of(context) - // .showSnackBar(SnackBar( - // content: Text(message))); - // if (status) { - // Navigator.pushReplacement( - // context, - // MaterialPageRoute( - // builder: (context) => - // const HomePage())); - // } - // }); - // } - // }, - )) - ], - ), + title: const Text(''), + backgroundColor: Colors.transparent, + elevation: 0, + actions: [ + IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: Image.asset('assets/Back_attendance.png'), + padding: const EdgeInsets.only(right: 20), + ), + ], + ), + body: SingleChildScrollView( + child: Column( + children: [ + // const SizedBox(height: 50), + // const SizedBox(height: 60), + Container( + padding: + const EdgeInsets.all(20.0).copyWith(top: 15, bottom: 30), + margin: const EdgeInsets.symmetric(horizontal: 30.0), + decoration: BoxDecoration( + border: Border.all(color: Colors.white), + color: const Color(0xffB4D1E5).withOpacity(0.9), + borderRadius: BorderRadius.circular(26.0)), + child: Form( + key: _formKey, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + const SizedBox(height: 20), + const Text('Change Password', + style: TextStyle( + fontSize: 30, + color: Colors.black, + fontWeight: FontWeight.w500, + fontFamily: 'Roboto')), + const SizedBox(height: 20), + CommonTextFormField( + controller: _oldPasswordController, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter your password'; + } + return null; + }, + title: 'Current Password'), + const SizedBox(height: 20), + CommonTextFormField( + controller: _newPasswordController, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter your password'; + } + return null; + }, + title: 'New Password'), + const SizedBox(height: 20), + CommonTextFormField( + controller: _confirmPasswordController, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter your password'; + } + return null; + }, + title: 'Confirm Password'), + const SizedBox(height: 15), + Align( + alignment: Alignment.center, + child: CommonElevatedButton( + backgroundColor: const Color(0xff004791), + borderRadius: 30, + width: double.infinity, + height: kToolbarHeight - 10, + text: 'SIGN IN', + isLoading: _isLoading, + onPressed: () { + _changePassword().then( + (result) { + var (status, message) = result; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(message))); + if (status) { + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => + const PasswordChangeScreen(), + ), + ); + } + }, + ); + }, + ), + ) + ], ), ), - ], - ), - )), + ), + ], + ), + )), ); } } diff --git a/lib/screens/forgot_password_screen.dart b/lib/screens/forgot_password_screen.dart index a857dc9..fc4c68e 100644 --- a/lib/screens/forgot_password_screen.dart +++ b/lib/screens/forgot_password_screen.dart @@ -1,7 +1,9 @@ -import 'package:cheminova/screens/verify_phone_screen.dart'; +import 'package:cheminova/services/api_client.dart'; +import 'package:cheminova/services/api_urls.dart'; import 'package:cheminova/widgets/common_background.dart'; import 'package:cheminova/widgets/common_elevated_button.dart'; import 'package:cheminova/widgets/common_text_form_field.dart'; +import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; class ForgotPasswordScreen extends StatefulWidget { @@ -12,15 +14,87 @@ class ForgotPasswordScreen extends StatefulWidget { } class _ForgotPasswordScreenState extends State { + final _formKey = GlobalKey(); + final _emailController = TextEditingController(); + + bool isLoading = false; + + void _submitEmail() { + if (_formKey.currentState!.validate()) { + // Process the form data + _forgetPassword(); + } + } + + Future _forgetPassword() async { + setState(() { + isLoading = true; + }); + + try { + final apiClient = ApiClient(); + Response response = + await apiClient.post(ApiUrls.forgetPasswordUrl, data: { + 'email': _emailController.text.trim(), + }); + + if (response.statusCode == 200) { + setState(() { + isLoading = false; + }); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(response.data['message'].toString()), + ), + ); + Navigator.pop(context); + } + } on DioException catch (e) { + setState(() { + isLoading = false; + }); + if (e.response?.data is Map) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(e.response?.data['message'].toString() ?? + 'Something went wrong'), + ), + ); + } else if (e.response?.data is String) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: + Text(e.response?.data.toString() ?? 'Something went wrong'), + ), + ); + } else { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Something went wrong'), + ), + ); + } + } + + setState(() { + isLoading = false; + }); + } + @override Widget build(BuildContext context) { return CommonBackground( isFullWidth: false, child: Scaffold( backgroundColor: Colors.transparent, - appBar: AppBar(leading: InkWell(onTap:() { - Navigator.pop(context); - },child: Image.asset('assets/Back_attendance.png')),backgroundColor: Colors.transparent,), + appBar: AppBar( + leading: InkWell( + onTap: () { + Navigator.pop(context); + }, + child: Image.asset('assets/Back_attendance.png')), + backgroundColor: Colors.transparent, + ), body: Center( child: SingleChildScrollView( child: Container( @@ -31,74 +105,86 @@ class _ForgotPasswordScreenState extends State { color: const Color(0xffB4D1E5).withOpacity(0.9), borderRadius: BorderRadius.circular(26.0), ), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Align( + child: Form( + key: _formKey, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Align( alignment: Alignment.topLeft, child: Image.asset( 'assets/lock_logo2.png', height: 50.0, // Adjust the height as needed - width: 50.0, // Adjust the width as needed + width: 50.0, // Adjust the width as needed ), - ), - const Text( - 'Forgot Password', - style: TextStyle( - fontSize: 30, - color: Colors.black, - fontWeight: FontWeight.w500, - fontFamily: 'Anek', ), - ), - const Text( - 'Enter Registered Email ID to generate new password', - style: TextStyle( - fontSize: 14, - color: Colors.black, - fontWeight: FontWeight.w300, - fontFamily: 'Roboto', + const Text( + 'Forgot Password', + style: TextStyle( + fontSize: 30, + color: Colors.black, + fontWeight: FontWeight.w500, + fontFamily: 'Anek', + ), ), - ), - const SizedBox(height: 20), - const CommonTextFormField(title: ' Enter Your Email ID'), - const SizedBox(height: 20), - Align( - alignment: Alignment.center, - child: TextButton( - onPressed: () { - Navigator.pop(context); + const Text( + 'Enter Registered Email ID to generate new password', + style: TextStyle( + fontSize: 14, + color: Colors.black, + fontWeight: FontWeight.w300, + fontFamily: 'Roboto', + ), + ), + const SizedBox(height: 20), + CommonTextFormField( + title: ' Enter Your Email ID', + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter your email id'; + } + if (!RegExp(r'^[^@\s]+@[^@\s]+\.[^@\s]+$') + .hasMatch(value)) { + return 'Please enter a valid email id'; + } + return null; }, - child: const Text('Back to Login', + controller: _emailController, + ), + const SizedBox(height: 20), + Align( + alignment: Alignment.center, + child: TextButton( + onPressed: () { + Navigator.pop(context); + }, + child: const Text( + 'Back to Login', style: TextStyle( fontSize: 20, color: Colors.black, fontWeight: FontWeight.w400, - fontFamily: 'Roboto')), + fontFamily: 'Roboto'), + ), + ), ), - ), - const SizedBox(height: 15), - Align( - alignment: Alignment.center, - child: CommonElevatedButton( - backgroundColor: const Color(0xff004791), - borderRadius: 30, - width: double.infinity, - height: kToolbarHeight - 10, - text: 'SEND', - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const VerifyPhoneScreen(), - ), - ); - }, + const SizedBox(height: 15), + Align( + alignment: Alignment.center, + child: CommonElevatedButton( + backgroundColor: const Color(0xff004791), + borderRadius: 30, + width: double.infinity, + isLoading: isLoading, + height: kToolbarHeight - 10, + text: 'SEND', + onPressed: _submitEmail, + ), ), - ), - ], + ], + ), ), ), ), diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index 3bf3ec0..fc2d474 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -1,3 +1,4 @@ +import 'package:cheminova/provider/user_provider.dart'; import 'package:cheminova/screens/calendar_screen.dart'; import 'package:cheminova/screens/collect_kyc_screen.dart'; import 'package:cheminova/screens/mark_attendence_screen.dart'; @@ -12,38 +13,64 @@ import 'package:cheminova/widgets/common_drawer.dart'; import 'package:flutter/material.dart'; import 'package:cheminova/widgets/common_background.dart'; import 'package:cheminova/screens/daily_tasks_screen.dart'; +import 'package:provider/provider.dart'; -class HomePage extends StatelessWidget { +class HomePage extends StatefulWidget { const HomePage({super.key}); + @override + State createState() => _HomePageState(); +} + +class _HomePageState extends State { + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + Provider.of(context, listen: false).fetchUserProfile(); + }); + } + @override Widget build(BuildContext context) { return CommonBackground( child: Scaffold( backgroundColor: Colors.transparent, - appBar: const CommonAppBar( + appBar: AppBar( title: Row( children: [ // CircleAvatar( // backgroundImage: AssetImage( // 'assets/profile.png'), // Replace with actual user image // ), - SizedBox(width: 10), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('Welcome', - style: TextStyle( + const SizedBox(width: 10), + Consumer( + builder: (context, userProvider, child) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Welcome', + style: TextStyle( + color: Colors.black87, + fontSize: 14, + fontWeight: FontWeight.w400), + ), + Text( + userProvider.user?.name ?? 'User Name', + style: const TextStyle( color: Colors.black87, - fontSize: 14, - fontWeight: FontWeight.w400)), - Text('User Name', - style: TextStyle( - color: Colors.black87, fontSize: 20)), - ], + fontSize: 20, + ), + ), + ], + ); + }, ), ], - ), backgroundColor: Colors.transparent, elevation: 0, + ), + backgroundColor: Colors.transparent, + elevation: 0, ), drawer: const CommonDrawer(), body: SafeArea( @@ -62,7 +89,8 @@ class HomePage extends StatelessWidget { Navigator.push( context, MaterialPageRoute( - builder: (context) => const MarkAttendanceScreen(), + builder: (context) => + const MarkAttendanceScreen(), )); }, ), @@ -79,17 +107,23 @@ class HomePage extends StatelessWidget { const SizedBox( height: 5, ), + _buildCustomCard('Assign Tasks', '', onTap: () {}), + const SizedBox( + height: 5, + ), Row( children: [ Expanded( - child: _buildCustomCard('Display\nSales data', - 'Quickly display Sales', onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const DisplaySalesScreen(), - )); - }), + child: _buildCustomCard( + 'Display\nSales data', 'Quickly display Sales', + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + const DisplaySalesScreen(), + )); + }), ), const SizedBox( width: 12, @@ -97,12 +131,13 @@ class HomePage extends StatelessWidget { Expanded( child: _buildCustomCard('Update Inventory Data', 'Quickly Inventory Data', onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const UpdateInventoryScreen(), - )); - }), + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + const UpdateInventoryScreen(), + )); + }), ), ], ), @@ -112,7 +147,8 @@ class HomePage extends StatelessWidget { Row( children: [ Expanded( - child: _buildCustomCard('Summary', '\n\n', onTap: () { + child: + _buildCustomCard('Summary', '\n\n', onTap: () { Navigator.push( context, MaterialPageRoute( @@ -125,11 +161,13 @@ class HomePage extends StatelessWidget { ), Expanded( child: _buildCustomCard( - 'Product\nSales Data Visibility', '', onTap: () { + 'Product\nSales Data Visibility', '', + onTap: () { Navigator.push( context, MaterialPageRoute( - builder: (context) => const ProductSalesData(), + builder: (context) => + const ProductSalesData(), )); }), ), @@ -143,12 +181,13 @@ class HomePage extends StatelessWidget { Expanded( child: _buildCustomCard('Collect \nKYC Data', 'Scan and upload KYC Documents', onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const CollectKycScreen(), - )); - }), + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + const CollectKycScreen(), + )); + }), ), ], ), @@ -156,23 +195,33 @@ class HomePage extends StatelessWidget { Row( children: [ Expanded( - child: _buildCustomCard('Notifications', - 'Tasks & Alerts\n\n', onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const NotificationScreen(), - )); - }), + child: _buildCustomCard( + 'Notifications', 'Tasks & Alerts\n\n', + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + const NotificationScreen(), + )); + }), ), const SizedBox( width: 15, ), Expanded( - child: _buildCustomCard('Calendar', - ' Upcoming Appointments & Deadlines',onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (context) => const CalendarScreen(),)); - },), + child: _buildCustomCard( + 'Calendar', + ' Upcoming Appointments & Deadlines', + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + const CalendarScreen(), + )); + }, + ), ), ], ), @@ -180,14 +229,16 @@ class HomePage extends StatelessWidget { Row( children: [ Expanded( - child: _buildCustomCard('Products Manual', - 'details of products', onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const ProductsManualScreen(), - )); - }), + child: _buildCustomCard( + 'Products Manual', 'details of products', + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + const ProductsManualScreen(), + )); + }), ), ], ), @@ -202,7 +253,8 @@ class HomePage extends StatelessWidget { ); } - Widget _buildCustomCard(String title, String subtitle, {void Function()? onTap}) { + Widget _buildCustomCard(String title, String subtitle, + {void Function()? onTap}) { return Container( margin: const EdgeInsets.only(bottom: 10), decoration: BoxDecoration( @@ -222,9 +274,9 @@ class HomePage extends StatelessWidget { ), subtitle: subtitle.isNotEmpty ? Text( - subtitle, - style: const TextStyle(color: Colors.white70, fontSize: 13), - ) + subtitle, + style: const TextStyle(color: Colors.white70, fontSize: 13), + ) : null, onTap: onTap, ), diff --git a/lib/screens/login_screen.dart b/lib/screens/login_screen.dart index 6755470..b9d627a 100644 --- a/lib/screens/login_screen.dart +++ b/lib/screens/login_screen.dart @@ -1,5 +1,6 @@ import 'package:cheminova/provider/login_provider.dart'; import 'package:cheminova/screens/forgot_password_screen.dart'; +import 'package:cheminova/screens/home_screen.dart'; import 'package:cheminova/screens/verify_phone_screen.dart'; import 'package:cheminova/widgets/common_background.dart'; import 'package:cheminova/widgets/common_elevated_button.dart'; @@ -44,7 +45,10 @@ class _LoginPageState extends State { const SizedBox(height: 50), Align( alignment: Alignment.center, - child: Container(decoration: BoxDecoration(color: Colors.white,borderRadius: BorderRadius.circular(12)), + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12)), padding: const EdgeInsets.all(8), child: Image.asset('assets/cheminova_logo.png', height: kToolbarHeight - 25), @@ -54,7 +58,8 @@ class _LoginPageState extends State { Container( padding: const EdgeInsets.all(20.0).copyWith(top: 15, bottom: 30), - margin: const EdgeInsets.symmetric(horizontal: 30.0).copyWith(bottom: 50), + margin: const EdgeInsets.symmetric(horizontal: 30.0) + .copyWith(bottom: 50), decoration: BoxDecoration( border: Border.all(color: Colors.white), color: const Color(0xffB4D1E5).withOpacity(0.9), @@ -81,20 +86,21 @@ class _LoginPageState extends State { fontFamily: 'Roboto')), const SizedBox(height: 20), Consumer( - builder: (context, value, child) => - CommonTextFormField( - controller: value.emailController, - validator: (value) { - if (value == null || value.isEmpty) { - return 'Please enter your email id'; - } - if (!RegExp(r'^[^@\s]+@[^@\s]+\.[^@\s]+$') - .hasMatch(value)) { - return 'Please enter a valid email id'; - } - return null; - }, - title: 'Username')), + builder: (context, value, child) => + CommonTextFormField( + controller: value.emailController, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter your email id'; + } + if (!RegExp(r'^[^@\s]+@[^@\s]+\.[^@\s]+$') + .hasMatch(value)) { + return 'Please enter a valid email id'; + } + return null; + }, + title: 'Username'), + ), const SizedBox(height: 20), Consumer( builder: (context, value, child) => @@ -108,7 +114,6 @@ class _LoginPageState extends State { }, title: 'Password')), const SizedBox(height: 15), - Align( alignment: Alignment.center, child: TextButton( @@ -140,7 +145,20 @@ class _LoginPageState extends State { text: 'SIGN IN', isLoading: value.isLoading, onPressed: () { - Navigator.push(context, MaterialPageRoute(builder:(context) => const VerifyPhoneScreen())); + loginProvider.login().then((result) { + var (status, message) = result; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(message))); + if (status) { + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => + const HomePage(), + ), + ); + } + }); }, // onPressed: value.isLoading // ? null diff --git a/lib/screens/splash_screen.dart b/lib/screens/splash_screen.dart index ed7e014..72d9ee6 100644 --- a/lib/screens/splash_screen.dart +++ b/lib/screens/splash_screen.dart @@ -1,5 +1,7 @@ import 'package:cheminova/constants/constant.dart'; +import 'package:cheminova/screens/home_screen.dart'; import 'package:cheminova/screens/login_screen.dart'; +import 'package:cheminova/services/secure__storage_service.dart'; import 'package:flutter/material.dart'; class SplashScreen extends StatefulWidget { @@ -10,12 +12,23 @@ class SplashScreen extends StatefulWidget { } class _SplashScreenState extends State { + void _checkLogin() { + SecureStorageService().read(key: 'user').then((value) { + if (value != null) { + Navigator.pushReplacement( + context, MaterialPageRoute(builder: (context) => const HomePage())); + } else { + Navigator.pushReplacement(context, + MaterialPageRoute(builder: (context) => const LoginPage())); + } + }); + } + @override void initState() { super.initState(); Future.delayed(const Duration(seconds: 3), () { - Navigator.pushReplacement( - context, MaterialPageRoute(builder: (context) => const LoginPage())); + _checkLogin(); }); } diff --git a/lib/services/api_urls.dart b/lib/services/api_urls.dart index 386d2fd..fafec62 100644 --- a/lib/services/api_urls.dart +++ b/lib/services/api_urls.dart @@ -1,7 +1,8 @@ class ApiUrls { - static const String baseUrl = - 'https://cheminova-api-2.onrender.com/api/'; - static const String loginUrl = 'salescoordinator/login'; - static const String profileUrl = 'my-profile'; + static const String baseUrl = 'https://cheminova-api-2.onrender.com/api/'; + static const String loginUrl = 'territorymanager/login'; + static const String profileUrl = 'territorymanager/my-profile'; static const String markAttendanceUrl = 'v1/markattendance/salescoordinator'; -} \ No newline at end of file + static const String forgetPasswordUrl = 'territorymanager/forgot-password'; + static const String changePasswordUrl = 'territorymanager/password/update'; +} diff --git a/lib/widgets/common_drawer.dart b/lib/widgets/common_drawer.dart index b22713a..41b204c 100644 --- a/lib/widgets/common_drawer.dart +++ b/lib/widgets/common_drawer.dart @@ -1,7 +1,9 @@ +import 'package:cheminova/provider/user_provider.dart'; import 'package:cheminova/screens/change_password_screen.dart'; import 'package:cheminova/screens/home_screen.dart'; import 'package:cheminova/screens/login_screen.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class CommonDrawer extends StatelessWidget { const CommonDrawer({super.key}); @@ -12,48 +14,58 @@ class CommonDrawer extends StatelessWidget { child: ListView( padding: EdgeInsets.zero, children: [ - Container( + SizedBox( height: 150, - child: const DrawerHeader( - decoration: BoxDecoration( + child: DrawerHeader( + decoration: const BoxDecoration( color: Colors.black87, ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start,mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - 'Username', - style: TextStyle( - color: Colors.white, - fontSize: 18, - ), - ),Text( - 'Employee ID', - style: TextStyle( - color: Colors.white, - fontSize: 20, - ), - ), - ], + child: Consumer( + builder: (context, userProvider, child) { + if (userProvider.isLoading) { + return const Center(child: CircularProgressIndicator()); + } else if (userProvider.user != null) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + userProvider.user!.name, + style: const TextStyle( + color: Colors.white, + fontSize: 18, + ), + ), + Text( + userProvider.user!.uniqueId, + style: const TextStyle( + color: Colors.white, + fontSize: 20, + ), + ), + ], + ); + } else { + return const Text( + 'No User Data', + style: TextStyle( + color: Colors.white, + fontSize: 18, + ), + ); + } + }, ), ), ), - // const UserAccountsDrawerHeader( - // accountName: Text("Name"), - // accountEmail: Text("Employee ID"), - // // currentAccountPicture: CircleAvatar( - // // backgroundImage: AssetImage( - // // 'assets/profile.png'), // Replace with actual user image - // // ), - // decoration: BoxDecoration( - // color: Colors.black87, - // ), - // ), ListTile( leading: const Icon(Icons.home), title: const Text('Home'), onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (context) => const HomePage(),)); + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const HomePage()), + ); }, ), ListTile( @@ -67,15 +79,25 @@ class CommonDrawer extends StatelessWidget { leading: const Icon(Icons.settings), title: const Text('Change Password'), onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (context) => const ChangePasswordPage(),)); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const ChangePasswordPage()), + ); }, ), ListTile( leading: const Icon(Icons.exit_to_app), title: const Text('Logout'), onTap: () { - Navigator.pushReplacement(context, - MaterialPageRoute(builder: (context) => const LoginPage())); + WidgetsBinding.instance.addPostFrameCallback((_) { + Provider.of(context, listen: false) + .clearUserProfile(); + }); + Navigator.pushReplacement( + context, + MaterialPageRoute(builder: (context) => const LoginPage()), + ); }, ), ], diff --git a/lib/widgets/common_elevated_button.dart b/lib/widgets/common_elevated_button.dart index 054cc4c..7e39473 100644 --- a/lib/widgets/common_elevated_button.dart +++ b/lib/widgets/common_elevated_button.dart @@ -16,7 +16,8 @@ class CommonElevatedButton extends StatelessWidget { this.borderRadius, this.backgroundColor, this.height, - this.width, this.isLoading=false}); + this.width, + this.isLoading = false}); @override Widget build(BuildContext context) { @@ -24,21 +25,22 @@ class CommonElevatedButton extends StatelessWidget { height: height ?? kToolbarHeight - 25, width: width ?? 200, child: ElevatedButton( - onPressed: onPressed, + onPressed: isLoading ? null : onPressed, style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(borderRadius ?? 6)), backgroundColor: backgroundColor ?? const Color(0xff1E1E1E), side: const BorderSide(color: Colors.transparent)), child: Center( - child: isLoading?const CircularProgressIndicator( - backgroundColor: Colors.white, - valueColor: AlwaysStoppedAnimation(Colors.black) - ):Text(text ?? 'Submit', - style: const TextStyle( - fontSize: 15, - color: Colors.white, - fontWeight: FontWeight.w400, - fontFamily: 'Anek'))))); + child: isLoading + ? const CircularProgressIndicator( + backgroundColor: Colors.white, + valueColor: AlwaysStoppedAnimation(Colors.black)) + : Text(text ?? 'Submit', + style: const TextStyle( + fontSize: 15, + color: Colors.white, + fontWeight: FontWeight.w400, + fontFamily: 'Anek'))))); } } diff --git a/lib/widgets/common_text_form_field.dart b/lib/widgets/common_text_form_field.dart index bb457f1..68b370f 100644 --- a/lib/widgets/common_text_form_field.dart +++ b/lib/widgets/common_text_form_field.dart @@ -13,17 +13,19 @@ class CommonTextFormField extends StatelessWidget { final List? inputFormatters; final int? maxLength; -const CommonTextFormField( - {super.key, - required this.title, - this.controller, - this.validator, - this.fillColor, - this.readOnly, - this.maxLines, - this.height, - this.keyboardType, - this.inputFormatters, this.maxLength}); + const CommonTextFormField({ + super.key, + required this.title, + this.controller, + this.validator, + this.fillColor, + this.readOnly, + this.maxLines, + this.height, + this.keyboardType, + this.inputFormatters, + this.maxLength, + }); @override Widget build(BuildContext context) {