From 7aa59ca14566075cf5d619fbcb7ab4e363186d99 Mon Sep 17 00:00:00 2001 From: saritabirare Date: Tue, 27 Aug 2024 15:57:28 +0530 Subject: [PATCH] 1)User Login api Integrate 2)Forgot Password api Integrate 3)Change Password api Integrate and ChangePassword UI Create --- lib/main.dart | 3 +- .../change_password_screen.dart | 181 ++++++++++++++++++ .../controller/auth_controller.dart | 54 ++++++ .../controller/auth_service.dart | 39 +++- .../forget_password_screen.dart | 9 +- lib/utils/common_api_service.dart | 6 +- lib/widgets/my_drawer.dart | 5 +- 7 files changed, 292 insertions(+), 5 deletions(-) create mode 100644 lib/screens/authentication/change_password_screen.dart diff --git a/lib/main.dart b/lib/main.dart index 92066bc..57040fd 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,7 +2,7 @@ import 'package:cheminova/screens/splash_screen.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -void main() { +void main()async{ runApp(const MyApp()); } @@ -12,6 +12,7 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return const GetMaterialApp( + debugShowCheckedModeBanner: false, home: SplashScreen(), ); } diff --git a/lib/screens/authentication/change_password_screen.dart b/lib/screens/authentication/change_password_screen.dart new file mode 100644 index 0000000..91aa32f --- /dev/null +++ b/lib/screens/authentication/change_password_screen.dart @@ -0,0 +1,181 @@ +import 'package:cheminova/widgets/custom_button.dart'; +import 'package:cheminova/widgets/input_field.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:get/get.dart'; +import 'package:google_fonts/google_fonts.dart'; +import '../../utils/show_snackbar.dart'; +import 'controller/auth_controller.dart'; + + +class ChangePasswordScreen extends StatefulWidget { + const ChangePasswordScreen({super.key}); + + @override + State createState() => _ChangePasswordScreenState(); +} + +class _ChangePasswordScreenState extends State { + final authController = Get.put(AuthController()); + + + void dispose() { + authController.currentpassController.dispose(); + authController.newpassController.dispose(); + authController.confirmpassController.dispose(); + super.dispose(); + } + + void validateAndChangePassword() async { + String oldPassword = authController.currentpassController.text.trim(); + String newPassword = authController.newpassController.text.trim(); + String confirmPassword = authController.confirmpassController.text.trim(); + + if (newPassword.isEmpty || confirmPassword.isEmpty || oldPassword.isEmpty) { + showSnackbar('All fields are required'); + return; + } + + if (newPassword.length < 8) { + showSnackbar('Password must be at least 8 characters long'); + return; + } + + if (!RegExp(r'[!@#$%^&*(),.?":{}|<>]').hasMatch(newPassword)) { + showSnackbar('Password must contain at least one special character'); + return; + } + + + if (newPassword != confirmPassword) { + showSnackbar('New Password and Confirm Password do not match'); + return; + } + + + authController.changePassword(); + } + + + + @override + Widget build(BuildContext context) { + return Scaffold( + extendBodyBehindAppBar: true, + appBar: AppBar( + backgroundColor: Colors.transparent, + + elevation: 0, + leading: GestureDetector( + onTap: () => Get.back(), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: SizedBox( + width: 20, + height: 20, + child: SvgPicture.asset('assets/svg/menu.svg')), + ), + ), + actions: [ + GestureDetector( + onTap: () => Get.back(), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: SvgPicture.asset('assets/svg/back_arrow.svg'), + ), + ), + ], + ), + body: Stack( + alignment: Alignment.topCenter, + children: [ + Container( + decoration: const BoxDecoration( + image: DecorationImage( + fit: BoxFit.cover, + image: AssetImage( + 'assets/images/image_1.png', + ), + ), + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(50.0), + bottomRight: Radius.circular(50.0), + ), + ), + child: SizedBox( + width: Get.width, + height: Get.height * 0.7, + ), + ), + Center( + child: SingleChildScrollView( + child: Card( + margin: const EdgeInsets.symmetric(horizontal: 24), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(19), + side: const BorderSide(color: Color(0xFFFDFDFD)), + ), + color: const Color(0xFFB4D1E5).withOpacity(0.9), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + + Container( + padding: const EdgeInsets.only(bottom: 10), + alignment: Alignment.centerLeft, + child: Text( + 'Change Password', + style: GoogleFonts.getFont( + 'Roboto', + fontWeight: FontWeight.w500, + fontSize: 30, + height: 1.2, + ), + ), + ), + InputField( + hintText: "Current Password", + labelText: "Current Password", + controller: authController.currentpassController, + obscureText: true, + keyboardType: TextInputType.text, + ), + + const SizedBox(height: 15), + InputField( + hintText: "New Password", + labelText: "New Password", + obscureText: true, + controller: authController.newpassController, + keyboardType: TextInputType.text, + ), + const SizedBox(height: 15), + InputField( + hintText: "Confirm Password", + labelText: "Confirm Password", + obscureText: true, + controller: authController.confirmpassController, + keyboardType: TextInputType.text, + ), + const SizedBox(height: 30), + CustomButton( + text: "RESET PASSWORD", + onPressed: () async { + + validateAndChangePassword(); + + }, + isLoading: authController.isLoading.value, + ) + ], + ), + ), + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/screens/authentication/controller/auth_controller.dart b/lib/screens/authentication/controller/auth_controller.dart index 6a3b7fb..252db3d 100644 --- a/lib/screens/authentication/controller/auth_controller.dart +++ b/lib/screens/authentication/controller/auth_controller.dart @@ -2,6 +2,7 @@ import 'package:cheminova/screens/authentication/controller/auth_service.dart'; import 'package:cheminova/screens/home_screen.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:shared_preferences/shared_preferences.dart'; class AuthController extends GetxController { final authService = AuthService(); @@ -9,6 +10,10 @@ class AuthController extends GetxController { TextEditingController emailController = TextEditingController(); TextEditingController passwordController = TextEditingController(); TextEditingController phoneController = TextEditingController(); + TextEditingController currentpassController = TextEditingController(); + TextEditingController newpassController = TextEditingController(); + TextEditingController confirmpassController = TextEditingController(); + RxBool isLoading = false.obs; Future login() async { @@ -23,4 +28,53 @@ class AuthController extends GetxController { Get.offAll(() => const HomeScreen()); } } + + Future forgotpass() async{ + isLoading.value = true; + final response = await authService.forgotPassword( + { + 'email': emailController.text, + } + ); + isLoading.value = false; + update(); + if(response != null){ + + } + } + + Future changePassword() async { + isLoading.value = true; + + SharedPreferences prefs = await SharedPreferences.getInstance(); + String? token = prefs.getString('token'); + + if (token != null) { + final response = await authService.changePassword( + { + 'oldPassword': currentpassController.text, + 'newPassword': newpassController.text, + 'confirmPassword': confirmpassController.text, + }, + token: token, // Pass the token here + ); + print("tokemn ,$token"); + isLoading.value = false; + update(); + + if (response != null) { + + Get.snackbar('Success', 'Password changed successfully'); + } else { + + Get.snackbar('Error', 'Failed to change password'); + } + } else { + isLoading.value = false; + update(); + Get.snackbar('Error', 'Token not found. Please login again.'); + } + } + + } diff --git a/lib/screens/authentication/controller/auth_service.dart b/lib/screens/authentication/controller/auth_service.dart index 49853f0..8d20668 100644 --- a/lib/screens/authentication/controller/auth_service.dart +++ b/lib/screens/authentication/controller/auth_service.dart @@ -5,7 +5,7 @@ class AuthService { Future?> login(Map data) async { try { final response = await commonApiService>( - url: '/api/territorymanager/login', + url: '/api/v1/user/login/', method: 'POST', body: data, fromJson: (json) => json, // Simply return the JSON map as is @@ -16,4 +16,41 @@ class AuthService { } return null; } + + + Future?> forgotPassword(Map data) async { + try { + final response = await commonApiService>( + url: '/api/v1/user/password/forgot', + method: 'POST', + body: data, + fromJson: (json) => json, // Simply return the JSON map as is + ); + return response; + } catch (e) { + showSnackbar(e.toString()); + } + return null; + } + + + Future?> changePassword(Map data, {required String token}) async { + try { + final response = await commonApiService>( + url: '/api/v1/user/password/update', + method: 'PUT', + body: data, + fromJson: (json) => json, // Simply return the JSON map as is + additionalHeaders: { // Pass the token here + 'Authorization': 'Bearer $token', + }, + ); + return response; + } catch (e) { + showSnackbar(e.toString()); + } + return null; + } + + } diff --git a/lib/screens/authentication/forget_password_screen.dart b/lib/screens/authentication/forget_password_screen.dart index f966a20..aa55670 100644 --- a/lib/screens/authentication/forget_password_screen.dart +++ b/lib/screens/authentication/forget_password_screen.dart @@ -5,6 +5,8 @@ import 'package:flutter_svg/svg.dart'; import 'package:get/get.dart'; import 'package:google_fonts/google_fonts.dart'; +import 'controller/auth_controller.dart'; + class ForgetPasswordScreen extends StatefulWidget { const ForgetPasswordScreen({super.key}); @@ -15,6 +17,7 @@ class ForgetPasswordScreen extends StatefulWidget { class _ForgetPasswordScreenState extends State { final userNameController = TextEditingController(); final passwordController = TextEditingController(); + final authController = Get.put(AuthController()); @override Widget build(BuildContext context) { return Scaffold( @@ -125,7 +128,11 @@ class _ForgetPasswordScreenState extends State { ), ), const SizedBox(height: 30), - CustomButton(text: "Send", onPressed: () {}), + CustomButton(text: "Send", + + onPressed: () => authController.forgotpass(), + isLoading: authController.isLoading.value, + ), ], ), ), diff --git a/lib/utils/common_api_service.dart b/lib/utils/common_api_service.dart index 4c9dd07..76f054f 100644 --- a/lib/utils/common_api_service.dart +++ b/lib/utils/common_api_service.dart @@ -11,6 +11,7 @@ Future commonApiService({ Map body = const {}, File? imageFile, bool isformData = true, + Map? additionalHeaders, required BodyType Function(Map) fromJson, }) async { try { @@ -31,6 +32,9 @@ Future commonApiService({ headers['Authorization'] = 'Bearer $token'; } + if (additionalHeaders != null) { + headers.addAll(additionalHeaders); + } Options options = Options(headers: headers); FormData formData = FormData.fromMap(body); @@ -60,7 +64,7 @@ Future commonApiService({ print("response of $url : $response"); - if (url == "/api/territorymanager/login" && + if (url == "/api/v1/user/login/" && response.data['token'] != null) { prefs.setString('token', response.data['token']); } diff --git a/lib/widgets/my_drawer.dart b/lib/widgets/my_drawer.dart index fd5c0ab..830705b 100644 --- a/lib/widgets/my_drawer.dart +++ b/lib/widgets/my_drawer.dart @@ -1,4 +1,5 @@ import 'package:cheminova/controller/home_controller.dart'; +import 'package:cheminova/screens/authentication/change_password_screen.dart'; import 'package:cheminova/screens/authentication/login_screen.dart'; import 'package:cheminova/screens/home_screen.dart'; import 'package:flutter/material.dart'; @@ -64,7 +65,9 @@ class _MyDrawerState extends State { ListTile( leading: const Icon(Icons.settings), title: const Text('Change Password'), - onTap: () {}, + onTap: () { + Get.to(ChangePasswordScreen()); + }, ), ListTile( leading: const Icon(Icons.exit_to_app),