1)User Login api Integrate
2)Forgot Password api Integrate 3)Change Password api Integrate and ChangePassword UI Create
This commit is contained in:
parent
37e8ebbe30
commit
7aa59ca145
@ -2,7 +2,7 @@ import 'package:cheminova/screens/splash_screen.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
void main() {
|
void main()async{
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12,6 +12,7 @@ class MyApp extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return const GetMaterialApp(
|
return const GetMaterialApp(
|
||||||
|
debugShowCheckedModeBanner: false,
|
||||||
home: SplashScreen(),
|
home: SplashScreen(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
181
lib/screens/authentication/change_password_screen.dart
Normal file
181
lib/screens/authentication/change_password_screen.dart
Normal file
@ -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<ChangePasswordScreen> createState() => _ChangePasswordScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ChangePasswordScreenState extends State<ChangePasswordScreen> {
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ import 'package:cheminova/screens/authentication/controller/auth_service.dart';
|
|||||||
import 'package:cheminova/screens/home_screen.dart';
|
import 'package:cheminova/screens/home_screen.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
class AuthController extends GetxController {
|
class AuthController extends GetxController {
|
||||||
final authService = AuthService();
|
final authService = AuthService();
|
||||||
@ -9,6 +10,10 @@ class AuthController extends GetxController {
|
|||||||
TextEditingController emailController = TextEditingController();
|
TextEditingController emailController = TextEditingController();
|
||||||
TextEditingController passwordController = TextEditingController();
|
TextEditingController passwordController = TextEditingController();
|
||||||
TextEditingController phoneController = TextEditingController();
|
TextEditingController phoneController = TextEditingController();
|
||||||
|
TextEditingController currentpassController = TextEditingController();
|
||||||
|
TextEditingController newpassController = TextEditingController();
|
||||||
|
TextEditingController confirmpassController = TextEditingController();
|
||||||
|
|
||||||
RxBool isLoading = false.obs;
|
RxBool isLoading = false.obs;
|
||||||
|
|
||||||
Future<void> login() async {
|
Future<void> login() async {
|
||||||
@ -23,4 +28,53 @@ class AuthController extends GetxController {
|
|||||||
Get.offAll(() => const HomeScreen());
|
Get.offAll(() => const HomeScreen());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> forgotpass() async{
|
||||||
|
isLoading.value = true;
|
||||||
|
final response = await authService.forgotPassword(
|
||||||
|
{
|
||||||
|
'email': emailController.text,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
isLoading.value = false;
|
||||||
|
update();
|
||||||
|
if(response != null){
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> 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.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ class AuthService {
|
|||||||
Future<Map<String, dynamic>?> login(Map<String, dynamic> data) async {
|
Future<Map<String, dynamic>?> login(Map<String, dynamic> data) async {
|
||||||
try {
|
try {
|
||||||
final response = await commonApiService<Map<String, dynamic>>(
|
final response = await commonApiService<Map<String, dynamic>>(
|
||||||
url: '/api/territorymanager/login',
|
url: '/api/v1/user/login/',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: data,
|
body: data,
|
||||||
fromJson: (json) => json, // Simply return the JSON map as is
|
fromJson: (json) => json, // Simply return the JSON map as is
|
||||||
@ -16,4 +16,41 @@ class AuthService {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Future<Map<String, dynamic>?> forgotPassword(Map<String, dynamic> data) async {
|
||||||
|
try {
|
||||||
|
final response = await commonApiService<Map<String, dynamic>>(
|
||||||
|
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<Map<String, dynamic>?> changePassword(Map<String, dynamic> data, {required String token}) async {
|
||||||
|
try {
|
||||||
|
final response = await commonApiService<Map<String, dynamic>>(
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@ import 'package:flutter_svg/svg.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
|
||||||
|
import 'controller/auth_controller.dart';
|
||||||
|
|
||||||
class ForgetPasswordScreen extends StatefulWidget {
|
class ForgetPasswordScreen extends StatefulWidget {
|
||||||
const ForgetPasswordScreen({super.key});
|
const ForgetPasswordScreen({super.key});
|
||||||
|
|
||||||
@ -15,6 +17,7 @@ class ForgetPasswordScreen extends StatefulWidget {
|
|||||||
class _ForgetPasswordScreenState extends State<ForgetPasswordScreen> {
|
class _ForgetPasswordScreenState extends State<ForgetPasswordScreen> {
|
||||||
final userNameController = TextEditingController();
|
final userNameController = TextEditingController();
|
||||||
final passwordController = TextEditingController();
|
final passwordController = TextEditingController();
|
||||||
|
final authController = Get.put(AuthController());
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
@ -125,7 +128,11 @@ class _ForgetPasswordScreenState extends State<ForgetPasswordScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
CustomButton(text: "Send", onPressed: () {}),
|
CustomButton(text: "Send",
|
||||||
|
|
||||||
|
onPressed: () => authController.forgotpass(),
|
||||||
|
isLoading: authController.isLoading.value,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -11,6 +11,7 @@ Future<BodyType?> commonApiService<BodyType>({
|
|||||||
Map<String, dynamic> body = const {},
|
Map<String, dynamic> body = const {},
|
||||||
File? imageFile,
|
File? imageFile,
|
||||||
bool isformData = true,
|
bool isformData = true,
|
||||||
|
Map<String, String>? additionalHeaders,
|
||||||
required BodyType Function(Map<String, dynamic>) fromJson,
|
required BodyType Function(Map<String, dynamic>) fromJson,
|
||||||
}) async {
|
}) async {
|
||||||
try {
|
try {
|
||||||
@ -31,6 +32,9 @@ Future<BodyType?> commonApiService<BodyType>({
|
|||||||
headers['Authorization'] = 'Bearer $token';
|
headers['Authorization'] = 'Bearer $token';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (additionalHeaders != null) {
|
||||||
|
headers.addAll(additionalHeaders);
|
||||||
|
}
|
||||||
Options options = Options(headers: headers);
|
Options options = Options(headers: headers);
|
||||||
|
|
||||||
FormData formData = FormData.fromMap(body);
|
FormData formData = FormData.fromMap(body);
|
||||||
@ -60,7 +64,7 @@ Future<BodyType?> commonApiService<BodyType>({
|
|||||||
|
|
||||||
print("response of $url : $response");
|
print("response of $url : $response");
|
||||||
|
|
||||||
if (url == "/api/territorymanager/login" &&
|
if (url == "/api/v1/user/login/" &&
|
||||||
response.data['token'] != null) {
|
response.data['token'] != null) {
|
||||||
prefs.setString('token', response.data['token']);
|
prefs.setString('token', response.data['token']);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:cheminova/controller/home_controller.dart';
|
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/authentication/login_screen.dart';
|
||||||
import 'package:cheminova/screens/home_screen.dart';
|
import 'package:cheminova/screens/home_screen.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -64,7 +65,9 @@ class _MyDrawerState extends State<MyDrawer> {
|
|||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.settings),
|
leading: const Icon(Icons.settings),
|
||||||
title: const Text('Change Password'),
|
title: const Text('Change Password'),
|
||||||
onTap: () {},
|
onTap: () {
|
||||||
|
Get.to(ChangePasswordScreen());
|
||||||
|
},
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.exit_to_app),
|
leading: const Icon(Icons.exit_to_app),
|
||||||
|
Loading…
Reference in New Issue
Block a user