diff --git a/lib/api/user_api_client.dart b/lib/api/user_api_client.dart index 1d644ef..623a883 100644 --- a/lib/api/user_api_client.dart +++ b/lib/api/user_api_client.dart @@ -1,4 +1,10 @@ import 'dart:async'; +import 'package:car_customer_app/classes/app_state.dart'; +import 'package:car_customer_app/models/user/change_email.dart'; +import 'package:car_customer_app/models/user/change_mobile.dart'; +import 'package:car_customer_app/models/user/change_password.dart'; +import 'package:car_customer_app/models/user/confirm_email.dart'; +import 'package:car_customer_app/models/user/confirm_mobile.dart'; import 'package:car_customer_app/models/user/country.dart'; import 'package:http/http.dart'; import 'package:car_customer_app/classes/consts.dart'; @@ -72,10 +78,10 @@ class UserApiClent { return await ApiClient().postJsonForResponse(ApiConsts.ForgetPasswordOTPRequest, postParams); } - Future ForgetPasswordOTPCompare(String userToken, String otp) async { + Future ForgetPasswordOTPCompare(String userToken, String userOTP) async { var postParams = {"userToken": userToken, - "userOTP": otp}; + "userOTP": userOTP}; return await ApiClient().postJsonForResponse(ApiConsts.ForgetPasswordOTPCompare, postParams); } @@ -88,4 +94,53 @@ class UserApiClent { return await ApiClient().postJsonForResponse(ApiConsts.ForgetPassword, postParams); } + + Future ChangePassword(String currentPasswor, String newPassword) async { + var postParams = { + "currentPassword": currentPasswor, + "newPassword": newPassword, + }; + // return await ApiClient().postJsonForResponse(ApiConsts.ChangePassword, postParams); + + String t = AppState().getUser.data!.accessToken ?? ""; + print("tokeen " + t); + return await ApiClient().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.ChangePassword, postParams, token: t); + + } + + Future ChangeMobileNoOTPRequest(countryID, String mobileNo, String password,) async { + var postParams = + { "countryID":1, + "mobileNo": mobileNo, + "password": password}; + String t = AppState().getUser.data!.accessToken ?? ""; + return await ApiClient().postJsonForObject((json) => ChangeMobile.fromJson(json), ApiConsts.ChangeMobileNoOTPRequest, postParams, token: t); + } + + Future ChangeMobileNo(String userToken, String userOTP) async { + var postParams = { + "userToken": userToken, + "userOTP": userOTP, + }; + String t = AppState().getUser.data!.accessToken ?? ""; + return await ApiClient().postJsonForObject((json) => ConfirmMobile.fromJson(json), ApiConsts.ChangeMobileNo, postParams, token: t); + } + + Future ChangeEmailOTPRequest(String email, String password) async { + var postParams = + {"email": email, + "password":password + }; + String t = AppState().getUser.data!.accessToken ?? ""; + return await ApiClient().postJsonForObject((json) => ChanEmail.fromJson(json), ApiConsts.ChangeEmailOTPRequest, postParams, token: t); + } + + Future ChangeEmail(String userToken, String userOTP) async { + var postParams = + {"userToken": userToken, + "userOTP": userOTP + }; + String t = AppState().getUser.data!.accessToken ?? ""; + return await ApiClient().postJsonForObject((json) => ConfirmEmail.fromJson(json), ApiConsts.ChangeEmail, postParams, token: t); + } } diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 09b8ad8..7260769 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -16,6 +16,13 @@ class ApiConsts { static String ForgetPasswordOTPRequest = baseUrlServices + "api/Account/ForgetPasswordOTPRequest"; static String ForgetPasswordOTPCompare = baseUrlServices + "api/Account/ForgetPasswordOTPCompare"; static String ForgetPassword = baseUrlServices + "api/Account/ForgetPassword"; + static String ProfileImage = baseUrlServices + "api/api/ProfileImage"; + static String UpdateProfileImage = baseUrlServices + "api/api/User_UpdateProfileImage"; + static String ChangePassword = baseUrlServices + "api/Account/ChangePassword"; + static String ChangeMobileNoOTPRequest = baseUrlServices + "api/Account/ChangeMobileNoOTPRequest"; + static String ChangeMobileNo = baseUrlServices + "api/Account/ChangeMobileNo"; + static String ChangeEmailOTPRequest = baseUrlServices + "api/Account/ChangeEmailOTPRequest"; + static String ChangeEmail = baseUrlServices + "api/Account/ChangeEmail"; } diff --git a/lib/config/routes.dart b/lib/config/routes.dart index ab9223c..f0cfeb0 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -1,5 +1,8 @@ import 'package:car_customer_app/models/user/register_user.dart'; import 'package:car_customer_app/pages/dashboard/dashboard_page.dart'; +import 'package:car_customer_app/pages/user/change_email_page.dart'; +import 'package:car_customer_app/pages/user/change_mobile_page.dart'; +import 'package:car_customer_app/pages/user/change_password_page.dart'; import 'package:car_customer_app/pages/user/complete_profile_page.dart'; import 'package:car_customer_app/pages/user/forget_password_page.dart'; import 'package:car_customer_app/pages/user/login_method_selection_page.dart'; @@ -11,6 +14,7 @@ import 'package:car_customer_app/pages/user/register_selection_page.dart'; import 'package:car_customer_app/pages/user/splash_page.dart'; import 'package:flutter/material.dart'; import 'package:car_customer_app/pages/user/confirm_new_password.dart'; +import 'package:car_customer_app/pages/user/forget_password_method_page.dart'; class AppRoutes { //User @@ -25,6 +29,10 @@ class AppRoutes { static final String completeProfile = "/completeProfile"; static final String confirmNewPasswordPage = "/confirmNewPasswordPage"; + static final String changePasswordPage = "/changePasswordPage"; + static final String forgetPasswordMethodSPage = "/forgetPasswordMethodPage"; + static final String changeMobilePage = "/changeMobilePage"; + static final String changeEmailPage = "/changeEmailPage"; static final String dashboard = "/dashboard"; @@ -42,6 +50,10 @@ class AppRoutes { loginMethodSelection: (context) => LoginMethodSelectionPage(ModalRoute.of(context)!.settings.arguments as String), completeProfile: (context) => CompleteProfilePage(ModalRoute.of(context)!.settings.arguments as RegisterUser), confirmNewPasswordPage: (context) => ConfirmNewPasswordPage(ModalRoute.of(context)!.settings.arguments as String), + changePasswordPage: (context) => ChangePasswordPage(), + forgetPasswordMethodSPage : (context) => ForgetPasswordMethodPage(ModalRoute.of(context)!.settings.arguments as String), + changeMobilePage: (context) => ChangeMobilePage(), + changeEmailPage : (context) => ChangeEmailPage(), //Home page dashboard: (context) => DashboardPage(), diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index 9b8fc19..dbcde00 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -76,6 +76,10 @@ extension EmailValidator on String { return RegExp(r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$').hasMatch(this); } + bool isNum() { + return RegExp(r'[0-9]').hasMatch(this); + } + String toFormattedDate() { String date = this.split("T")[0]; String time = this.split("T")[1]; diff --git a/lib/models/user/change_email.dart b/lib/models/user/change_email.dart new file mode 100644 index 0000000..5ffba17 --- /dev/null +++ b/lib/models/user/change_email.dart @@ -0,0 +1,50 @@ + +import 'dart:convert'; + +ChanEmail changeEmailFromJson(String str) => ChanEmail.fromJson(json.decode(str)); + +String changeEmailToJson(ChanEmail data) => json.encode(data.toJson()); + +class ChanEmail { + int? messageStatus; + Null? totalItemsCount; + Data? data; + String? message; + + ChanEmail( + {this.messageStatus, this.totalItemsCount, this.data, this.message}); + + ChanEmail.fromJson(Map json) { + messageStatus = json['messageStatus']; + totalItemsCount = json['totalItemsCount']; + data = json['data'] != null ? new Data.fromJson(json['data']) : null; + message = json['message']; + } + + Map toJson() { + final Map data = new Map(); + data['messageStatus'] = this.messageStatus; + data['totalItemsCount'] = this.totalItemsCount; + if (this.data != null) { + data['data'] = this.data!.toJson(); + } + data['message'] = this.message; + return data; + } +} + +class Data { + String? userToken; + + Data({this.userToken}); + + Data.fromJson(Map json) { + userToken = json['userToken']; + } + + Map toJson() { + final Map data = new Map(); + data['userToken'] = this.userToken; + return data; + } +} \ No newline at end of file diff --git a/lib/models/user/change_mobile.dart b/lib/models/user/change_mobile.dart new file mode 100644 index 0000000..be98bc7 --- /dev/null +++ b/lib/models/user/change_mobile.dart @@ -0,0 +1,50 @@ + +import 'dart:convert'; + +ChangeMobile changeMobileFromJson(String str) => ChangeMobile.fromJson(json.decode(str)); + +String changeMobileToJson(ChangeMobile data) => json.encode(data.toJson()); + +class ChangeMobile { + int? messageStatus; + Null? totalItemsCount; + Data? data; + String? message; + + ChangeMobile( + {this.messageStatus, this.totalItemsCount, this.data, this.message}); + + ChangeMobile.fromJson(Map json) { + messageStatus = json['messageStatus']; + totalItemsCount = json['totalItemsCount']; + data = json['data'] != null ? new Data.fromJson(json['data']) : null; + message = json['message']; + } + + Map toJson() { + final Map data = new Map(); + data['messageStatus'] = this.messageStatus; + data['totalItemsCount'] = this.totalItemsCount; + if (this.data != null) { + data['data'] = this.data!.toJson(); + } + data['message'] = this.message; + return data; + } +} + +class Data { + String? userToken; + + Data({this.userToken}); + + Data.fromJson(Map json) { + userToken = json['userToken']; + } + + Map toJson() { + final Map data = new Map(); + data['userToken'] = this.userToken; + return data; + } +} \ No newline at end of file diff --git a/lib/models/user/change_password.dart b/lib/models/user/change_password.dart new file mode 100644 index 0000000..55cff11 --- /dev/null +++ b/lib/models/user/change_password.dart @@ -0,0 +1,30 @@ + +import 'dart:convert'; + +MResponse mResponseFromJson(String str) => MResponse.fromJson(json.decode(str)); + +String mResponseToJson(MResponse data) => json.encode(data.toJson()); + +class MResponse { + MResponse({ + this.totalItemsCount, + this.messageStatus, + this.message, + }); + + int? totalItemsCount; + int? messageStatus; + String? message; + + factory MResponse.fromJson(Map json) => MResponse( + totalItemsCount: json["totalItemsCount"] == null ? null : json["totalItemsCount"], + messageStatus: json["messageStatus"] == null ? null : json["messageStatus"], + message: json["message"] == null ? null : json["message"], + ); + + Map toJson() => { + "totalItemsCount": totalItemsCount == null ? null : totalItemsCount, + "messageStatus": messageStatus == null ? null : messageStatus, + "message": message == null ? null : message, + }; +} diff --git a/lib/models/user/confirm_email.dart b/lib/models/user/confirm_email.dart new file mode 100644 index 0000000..0bdef29 --- /dev/null +++ b/lib/models/user/confirm_email.dart @@ -0,0 +1,50 @@ + +import 'dart:convert'; + +ConfirmEmail confirmEmailFromJson(String str) => ConfirmEmail.fromJson(json.decode(str)); + +String confirmEmailToJson(ConfirmEmail data) => json.encode(data.toJson()); + +class ConfirmEmail { + int? messageStatus; + Null? totalItemsCount; + Data? data; + String? message; + + ConfirmEmail( + {this.messageStatus, this.totalItemsCount, this.data, this.message}); + + ConfirmEmail.fromJson(Map json) { + messageStatus = json['messageStatus']; + totalItemsCount = json['totalItemsCount']; + data = json['data'] != null ? new Data.fromJson(json['data']) : null; + message = json['message']; + } + + Map toJson() { + final Map data = new Map(); + data['messageStatus'] = this.messageStatus; + data['totalItemsCount'] = this.totalItemsCount; + if (this.data != null) { + data['data'] = this.data!.toJson(); + } + data['message'] = this.message; + return data; + } +} + +class Data { + String? userID; + + Data({this.userID}); + + Data.fromJson(Map json) { + userID = json['userID']; + } + + Map toJson() { + final Map data = new Map(); + data['userID'] = this.userID; + return data; + } +} \ No newline at end of file diff --git a/lib/models/user/confirm_mobile.dart b/lib/models/user/confirm_mobile.dart new file mode 100644 index 0000000..9e1784c --- /dev/null +++ b/lib/models/user/confirm_mobile.dart @@ -0,0 +1,51 @@ + +import 'dart:convert'; + +ConfirmMobile confirmMobileFromJson(String str) => ConfirmMobile.fromJson(json.decode(str)); + +String confirmMobileToJson(ConfirmMobile data) => json.encode(data.toJson()); + + +class ConfirmMobile { + int? messageStatus; + Null? totalItemsCount; + Data? data; + String? message; + + ConfirmMobile( + {this.messageStatus, this.totalItemsCount, this.data, this.message}); + + ConfirmMobile.fromJson(Map json) { + messageStatus = json['messageStatus']; + totalItemsCount = json['totalItemsCount']; + data = json['data'] != null ? new Data.fromJson(json['data']) : null; + message = json['message']; + } + + Map toJson() { + final Map data = new Map(); + data['messageStatus'] = this.messageStatus; + data['totalItemsCount'] = this.totalItemsCount; + if (this.data != null) { + data['data'] = this.data!.toJson(); + } + data['message'] = this.message; + return data; + } +} + +class Data { + String? userID; + + Data({this.userID}); + + Data.fromJson(Map json) { + userID = json['userID']; + } + + Map toJson() { + final Map data = new Map(); + data['userID'] = this.userID; + return data; + } +} \ No newline at end of file diff --git a/lib/pages/dashboard/dashboard_page.dart b/lib/pages/dashboard/dashboard_page.dart index 91caad2..b44debd 100644 --- a/lib/pages/dashboard/dashboard_page.dart +++ b/lib/pages/dashboard/dashboard_page.dart @@ -1,4 +1,5 @@ import 'package:car_customer_app/api/shared_prefrence.dart'; +import 'package:car_customer_app/config/routes.dart'; import 'package:car_customer_app/theme/colors.dart'; import 'package:car_customer_app/utils/navigator.dart'; import 'package:car_customer_app/widgets/app_bar.dart'; @@ -7,6 +8,8 @@ import 'package:car_customer_app/extensions/int_extensions.dart'; import 'package:car_customer_app/extensions/string_extensions.dart'; import 'package:car_customer_app/extensions/widget_extensions.dart'; import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; +import 'dart:io'; class DashboardPage extends StatefulWidget { @override @@ -15,6 +18,8 @@ class DashboardPage extends StatefulWidget { class _DashboardPageState extends State { String userName = ""; + File? imagePicked; + final _picker = ImagePicker(); @override void initState() { @@ -48,16 +53,41 @@ class _DashboardPageState extends State { child: Container( child: Column( children: [ - Container( - width: double.infinity, - height: 200, - color: accentColor.withOpacity(0.3), - child: Icon( - Icons.person, - size: 80, + Stack( + children:[ + Container( + width: double.infinity, + height: 200, color: accentColor.withOpacity(0.3), + child: Icon( + Icons.person, + size: 80, + color: accentColor.withOpacity(0.3), + ), ), - ), + Positioned( + top: 10, + right: 10, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: Colors.grey[200], + borderRadius: BorderRadius.circular(30), + ), + child: Icon(Icons.edit, + color: Colors.blue,).onPress(() { + _openImagePicker(); + }), + ), + ], + ), + ) + ] ), Container( width: double.infinity, color: accentColor.withOpacity(0.1), @@ -76,7 +106,9 @@ class _DashboardPageState extends State { ), ShowFillButton( title: "EDIT", - onPressed: () {}, + onPressed: () { + + }, ), ], ), @@ -93,6 +125,27 @@ class _DashboardPageState extends State { leading: Icon(Icons.person), title: "Account".toText12(), ), + ListTile( + leading: Icon(Icons.password), + title: "Change Password".toText12(), + onTap: () { + navigateWithName(context, AppRoutes.changePasswordPage); + }, + ), + ListTile( + leading: Icon(Icons.phone_android_sharp), + title: "Change Mobile".toText12(), + onTap: () { + navigateWithName(context, AppRoutes.changeMobilePage); + }, + ), + ListTile( + leading: Icon(Icons.email_outlined), + title: "Change Email".toText12(), + onTap: () { + navigateWithName(context, AppRoutes.changeEmailPage); + }, + ), ListTile( leading: Icon(Icons.logout), title: "Sign Out".toText12(), @@ -106,4 +159,52 @@ class _DashboardPageState extends State { ), ); } + + void _openImagePicker() { + showDialog( + context: context, + builder: (context) => AlertDialog( + content: Text("Choose image source"), + actions: [ + FlatButton( + child: Text("Camera"), + onPressed: () => + cameraImage() + ), + FlatButton( + child: Text("Gallery"), + onPressed: () => gallaryImage() + ), + ] + ), + // .then((ImageSource source) async { + // if (source != null) { + // final pickedFile = await ImagePicker().getImage(source: source); + // setState(() => imagePicked = File(pickedFile.path)); + // } + // } + ); + } + + void gallaryImage() async { + final picker = ImagePicker(); + final pickedImage = await picker.pickImage( + source: ImageSource.gallery, + ); + final pickedImageFile = File(pickedImage!.path); + setState(() { + imagePicked = pickedImageFile; + }); + } + + void cameraImage() async { + final picker = ImagePicker(); + final pickedImage = await picker.pickImage( + source: ImageSource.camera, + ); + final pickedImageFile = File(pickedImage!.path); + setState(() { + imagePicked = pickedImageFile; + }); + } } diff --git a/lib/pages/user/change_email_page.dart b/lib/pages/user/change_email_page.dart new file mode 100644 index 0000000..923ba05 --- /dev/null +++ b/lib/pages/user/change_email_page.dart @@ -0,0 +1,118 @@ + + + +import 'package:car_customer_app/api/user_api_client.dart'; +import 'package:car_customer_app/classes/utils.dart'; +import 'package:car_customer_app/config/routes.dart'; +import 'package:car_customer_app/extensions/int_extensions.dart'; +import 'package:car_customer_app/extensions/string_extensions.dart'; +import 'package:car_customer_app/models/user/change_email.dart'; +import 'package:car_customer_app/models/user/confirm_email.dart'; +import 'package:car_customer_app/utils/navigator.dart'; +import 'package:car_customer_app/widgets/app_bar.dart'; +import 'package:car_customer_app/widgets/dialog/dialogs.dart'; +import 'package:car_customer_app/widgets/dialog/message_dialog.dart'; +import 'package:car_customer_app/widgets/dialog/otp_dialog.dart'; +import 'package:car_customer_app/widgets/show_fill_button.dart'; +import 'package:flutter/material.dart'; + +import 'dart:convert'; +import 'package:http/http.dart'; + +class ChangeEmailPage extends StatefulWidget { + + @override + State createState() => _ChangeEmailPageState(); +} + +class _ChangeEmailPageState extends State { + String password = ""; + String email = ''; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: appBar(title: "Change Email"), + body: SingleChildScrollView( + child: Container( + // width: double.infinity, + // height: double.infinity, + padding: EdgeInsets.all(40), + child: Column( + children: [ + "Enter Email".toText24(), + 12.height, + TextFormField( + decoration: InputDecoration( + hintText: "Enter New Email", + hintStyle: TextStyle(color: Colors.grey), + border: OutlineInputBorder( + borderRadius: const BorderRadius.all( + const Radius.circular(5.0), + ), + ), + ), + obscureText: false, + onChanged: (v) => email = v, + ), + 12.height, + TextFormField( + decoration: InputDecoration( + hintText: "Enter Current Password", + hintStyle: TextStyle(color: Colors.grey), + border: OutlineInputBorder( + borderRadius: const BorderRadius.all( + const Radius.circular(5.0), + ), + ), + ), + obscureText: true, + onChanged: (v) => password = v, + ), + 40.height, + ShowFillButton( + title: "Confirm", + width: double.infinity, + onPressed: () { + changeEmail(context); + }, + ), + ], + ), + ), + ), + ); + } + + Future changeEmail(BuildContext context) async { + Utils.showLoading(context); + ChanEmail otpRequest = await UserApiClent().ChangeEmailOTPRequest(email, password); + Utils.hideLoading(context); + if (otpRequest.messageStatus == 1) { + showMDialog(context, child: OtpDialog( + onClick: (String code) async { + pop(context); + Utils.showLoading(context); + ConfirmEmail otpCompare = await UserApiClent().ChangeEmail(otpRequest.data!.userToken ?? "", code); + Utils.hideLoading(context); + if (otpCompare.messageStatus == 1) { + showMDialog( + context, + child: MessageDialog( + title: "Email Verified", + onClick: () { + Navigator.of(context).pushNamedAndRemoveUntil(AppRoutes.loginWithPassword, (Route route) => false); + }, + ), + ); + } else { + Utils.showToast(otpCompare.message ?? ""); + } + }, + )); + } else { + Utils.showToast(otpRequest.message ?? ""); + } + } + +} diff --git a/lib/pages/user/change_mobile_page.dart b/lib/pages/user/change_mobile_page.dart new file mode 100644 index 0000000..bbe9f70 --- /dev/null +++ b/lib/pages/user/change_mobile_page.dart @@ -0,0 +1,123 @@ + + + + +import 'package:car_customer_app/api/user_api_client.dart'; +import 'package:car_customer_app/classes/utils.dart'; +import 'package:car_customer_app/config/routes.dart'; +import 'package:car_customer_app/extensions/int_extensions.dart'; +import 'package:car_customer_app/extensions/string_extensions.dart'; +import 'package:car_customer_app/models/user/change_mobile.dart'; +import 'package:car_customer_app/models/user/confirm_mobile.dart'; +import 'package:car_customer_app/models/user/confirm_password.dart'; +import 'package:car_customer_app/utils/navigator.dart'; +import 'package:car_customer_app/widgets/app_bar.dart'; +import 'package:car_customer_app/widgets/dialog/dialogs.dart'; +import 'package:car_customer_app/widgets/dialog/message_dialog.dart'; +import 'package:car_customer_app/widgets/dialog/otp_dialog.dart'; +import 'package:car_customer_app/widgets/show_fill_button.dart'; +import 'package:flutter/material.dart'; + +import 'dart:convert'; +import 'package:http/http.dart'; + +class ChangeMobilePage extends StatefulWidget { + + @override + State createState() => _ChangeMobilePageState(); +} + +class _ChangeMobilePageState extends State { + int countryID=1 ; + String mobileNo = ''; + String password = ''; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: appBar(title: "Change Mobile Number"), + body: SingleChildScrollView( + child: Container( + // width: double.infinity, + // height: double.infinity, + padding: EdgeInsets.all(40), + child: Column( + children: [ + "Enter New Phone Number".toText24(), + 12.height, + TextFormField( + decoration: InputDecoration( + hintText: "Enter New Phone Number", + hintStyle: TextStyle(color: Colors.grey), + border: OutlineInputBorder( + borderRadius: const BorderRadius.all( + const Radius.circular(5.0), + ), + ), + ), + obscureText: false, + onChanged: (v) => mobileNo = v, + ), + 12.height, + TextFormField( + decoration: InputDecoration( + hintText: "Enter Current Password", + hintStyle: TextStyle(color: Colors.grey), + border: OutlineInputBorder( + borderRadius: const BorderRadius.all( + const Radius.circular(5.0), + ), + ), + ), + obscureText: true, + onChanged: (v) => password = v, + ), + 40.height, + ShowFillButton( + title: "Confirm", + width: double.infinity, + onPressed: () { + changeMobile(context); + }, + ), + ], + ), + ), + ), + ); + } + + Future changeMobile(BuildContext context) async { + Utils.showLoading(context); + ChangeMobile otpRequest = await UserApiClent().ChangeMobileNoOTPRequest(countryID, mobileNo, password); + Utils.hideLoading(context); + if (otpRequest.messageStatus == 1) { + showMDialog(context, child: OtpDialog( + onClick: (String code) async { + pop(context); + Utils.showLoading(context); + ConfirmMobile otpCompare = await UserApiClent().ChangeMobileNo(otpRequest.data!.userToken ?? "", code); + Utils.hideLoading(context); + if (otpCompare.messageStatus == 1) { + showMDialog( + context, + child: MessageDialog( + title: "Phone Number Verified", + onClick: () { + Navigator.of(context).pushNamedAndRemoveUntil(AppRoutes.loginWithPassword, (Route route) => false); + }, + ), + ); + } else { + Utils.showToast(otpCompare.message ?? ""); + } + }, + )); + } else { + Utils.showToast(otpRequest.message ?? ""); + } + } + + + +} diff --git a/lib/pages/user/change_password_page.dart b/lib/pages/user/change_password_page.dart new file mode 100644 index 0000000..7e26cf5 --- /dev/null +++ b/lib/pages/user/change_password_page.dart @@ -0,0 +1,106 @@ + + +import 'package:car_customer_app/api/user_api_client.dart'; +import 'package:car_customer_app/classes/utils.dart'; +import 'package:car_customer_app/config/routes.dart'; +import 'package:car_customer_app/extensions/int_extensions.dart'; +import 'package:car_customer_app/extensions/string_extensions.dart'; +import 'package:car_customer_app/models/user/change_password.dart'; +import 'package:car_customer_app/models/user/confirm_password.dart'; +import 'package:car_customer_app/utils/navigator.dart'; +import 'package:car_customer_app/widgets/app_bar.dart'; +import 'package:car_customer_app/widgets/show_fill_button.dart'; +import 'package:flutter/material.dart'; + +import 'dart:convert'; +import 'package:http/http.dart'; + +class ChangePasswordPage extends StatefulWidget { + + @override + State createState() => _ChangePasswordPageState(); +} + +class _ChangePasswordPageState extends State { + String newPassword = ""; + String currentPassword = ''; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: appBar(title: "Change Password"), + body: SingleChildScrollView( + child: Container( + // width: double.infinity, + // height: double.infinity, + padding: EdgeInsets.all(40), + child: Column( + children: [ + "Enter New Password".toText24(), + 12.height, + TextFormField( + decoration: InputDecoration( + hintText: "Enter Old Password", + hintStyle: TextStyle(color: Colors.grey), + border: OutlineInputBorder( + borderRadius: const BorderRadius.all( + const Radius.circular(5.0), + ), + ), + ), + obscureText: true, + onChanged: (v) => currentPassword = v, + ), + 12.height, + TextFormField( + decoration: InputDecoration( + hintText: "Enter New Password", + hintStyle: TextStyle(color: Colors.grey), + border: OutlineInputBorder( + borderRadius: const BorderRadius.all( + const Radius.circular(5.0), + ), + ), + ), + obscureText: true, + onChanged: (v) => newPassword = v, + ), + 40.height, + ShowFillButton( + title: "Confirm", + width: double.infinity, + onPressed: () {changePassword(context); + }, + ), + ], + ), + ), + ), + ); + } + + Future changePassword(BuildContext context) async { + if (validateStructure(newPassword ?? "")) { + Utils.showLoading(context); + MResponse res = await UserApiClent().ChangePassword(currentPassword, newPassword); + Utils.hideLoading(context); + if (res.messageStatus == 1) { + Utils.showToast("Password is Updated"); + // navigateWithName(context, AppRoutes.loginWithPassword); + Navigator.of(context) + .pushNamedAndRemoveUntil(AppRoutes.loginWithPassword, (Route route) => false); + } else { + Utils.showToast(res.message ?? ""); + } + } else { + Utils.showToast("Password Should contains Character, Number, Capital and small letters"); + } + } + + + bool validateStructure(String value){ + String pattern = r'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[!@#\$&*~]).{6,}$'; + RegExp regExp = new RegExp(pattern); + return regExp.hasMatch(value); + } +} diff --git a/lib/pages/user/complete_profile_page.dart b/lib/pages/user/complete_profile_page.dart index aa71f19..9714ade 100644 --- a/lib/pages/user/complete_profile_page.dart +++ b/lib/pages/user/complete_profile_page.dart @@ -109,7 +109,7 @@ class _CompleteProfilePageState extends State { title: "Continue", width: double.infinity, onPressed: () { - performCompleteProfile(); + if(validation()) performCompleteProfile(); }, ), ], @@ -132,36 +132,24 @@ class _CompleteProfilePageState extends State { ); Future performCompleteProfile() async { - if (firstName != "") { - if (lastName != "") { - if (validateStructure(password ?? "")) { - if (password == confirmPassword) { - if (isChecked) { - print(widget.user.data!.userId ?? "userId"); - Utils.showLoading(context); - RegisterUser user = await UserApiClent().basicComplete(widget.user.data?.userId ?? "", firstName!, lastName!, email!, password!); - Utils.hideLoading(context); - if (user.messageStatus == 1) { - Utils.showToast("Successfully Registered, Please login once"); - pop(context); - // navigateReplaceWithName(context, AppRoutes.dashboard,arguments: user); - } else { - Utils.showToast(user.message ?? ""); - } - }else{ - Utils.showToast("Please accept terms"); - } + if (validateStructure(password ?? "")) { + if (password == confirmPassword) { + print(widget.user.data!.userId ?? "userId"); + Utils.showLoading(context); + RegisterUser user = await UserApiClent().basicComplete(widget.user.data?.userId ?? "", firstName!, lastName!, email!, password!); + Utils.hideLoading(context); + if (user.messageStatus == 1) { + Utils.showToast("Successfully Registered, Please login once"); + pop(context); + // navigateReplaceWithName(context, AppRoutes.dashboard,arguments: user); } else { - Utils.showToast("Please enter same password"); + Utils.showToast(user.message ?? ""); } } else { - Utils.showToast("Password Should contains Character, Number, Capital and small letters"); + Utils.showToast("Please enter same password"); } - }else{ - Utils.showToast("Surname is mandatory"); - } - }else{ - Utils.showToast("First name is mandatory"); + } else { + Utils.showToast("Password Should contains Character, Number, Capital and small letters"); } } @@ -170,4 +158,22 @@ class _CompleteProfilePageState extends State { RegExp regExp = new RegExp(pattern); return regExp.hasMatch(value); } + + bool validation() { + bool isValid = true; + if (firstName!.isEmpty) { + Utils.showToast("First name is mandatory"); + isValid = false; + } else if (lastName!.isEmpty) { + Utils.showToast("Surname is mandatory"); + isValid = false; + } else if (password!.isEmpty) { + Utils.showToast("Password is mandatory"); + isValid = false; + }else if (!isChecked) { + Utils.showToast("Please accept terms"); + isValid = false; + } + return isValid; + } } diff --git a/lib/pages/user/forget_password_method_page.dart b/lib/pages/user/forget_password_method_page.dart new file mode 100644 index 0000000..19cd18c --- /dev/null +++ b/lib/pages/user/forget_password_method_page.dart @@ -0,0 +1,103 @@ + + +import 'dart:convert'; + +import 'package:car_customer_app/api/shared_prefrence.dart'; +import 'package:car_customer_app/api/user_api_client.dart'; +import 'package:car_customer_app/classes/app_state.dart'; +import 'package:car_customer_app/classes/utils.dart'; +import 'package:car_customer_app/config/constants.dart'; +import 'package:car_customer_app/config/routes.dart'; +import 'package:car_customer_app/models/user/forget_password_otp_compare.dart'; +import 'package:car_customer_app/models/user/login_password.dart'; +import 'package:car_customer_app/models/user/register_user.dart'; +import 'package:car_customer_app/models/user/user.dart'; +import 'package:car_customer_app/utils/navigator.dart'; +import 'package:car_customer_app/utils/utils.dart'; +import 'package:car_customer_app/widgets/app_bar.dart'; +import 'package:car_customer_app/widgets/button/show_image_button.dart'; +import 'package:car_customer_app/widgets/dialog/dialogs.dart'; +import 'package:car_customer_app/widgets/dialog/message_dialog.dart'; +import 'package:car_customer_app/extensions/int_extensions.dart'; +import 'package:car_customer_app/extensions/string_extensions.dart'; +import 'package:car_customer_app/extensions/widget_extensions.dart'; +import 'package:car_customer_app/widgets/dialog/otp_dialog.dart'; +import 'package:car_customer_app/widgets/txt_field.dart'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart'; + +class ForgetPasswordMethodPage extends StatefulWidget { + String userToken; + + ForgetPasswordMethodPage(this.userToken); + + @override + State createState() => _ForgetPasswordMethodPageState(); +} + +class _ForgetPasswordMethodPageState extends State { + int otpType = 1; + String userOTP = ""; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: appBar(title: "Forget Password"), + body: Container( + width: double.infinity, + height: double.infinity, + padding: EdgeInsets.all(40), + child: Column( + children: [ + "Select Method".toText24(), + 12.height, + Row( + children: [ + Expanded( + child: ShowImageButton( + onClick: () { + otpType = 1; + forgetPasswordOTPMethod(context); + }, + title: 'With SMS', + icon: icons + "ic_sms.png", + ), + ), + 20.width, + Expanded( + child: ShowImageButton( + onClick: () { + otpType = 1; + forgetPasswordOTPMethod(context); + }, + title: 'With Whatsapp', + icon: icons + "ic_whatsapp.png", + ), + ), + ], + ), + mFlex(10), + ], + ), + ), + ); + } + + Future forgetPasswordOTPMethod(BuildContext context) async { + showMDialog(context, child: OtpDialog( + onClick: (String code) async { + pop(context); + Utils.showLoading(context); + Response res = await UserApiClent().ForgetPasswordOTPCompare(widget.userToken?? "", code); + Utils.hideLoading(context); + PasswordOTPCompare otpCompare = PasswordOTPCompare.fromJson(jsonDecode(res.body)); + if (otpCompare.messageStatus == 1) { + var userToken = otpCompare.data!.userToken; + navigateWithName(context, AppRoutes.confirmNewPasswordPage, arguments: userToken); + } else { + Utils.showToast(otpCompare.message ?? ""); + } + }, + )); + } +} diff --git a/lib/pages/user/forget_password_page.dart b/lib/pages/user/forget_password_page.dart index 07f9f55..f3198dd 100644 --- a/lib/pages/user/forget_password_page.dart +++ b/lib/pages/user/forget_password_page.dart @@ -14,15 +14,26 @@ import 'package:car_customer_app/widgets/dialog/dialogs.dart'; import 'package:car_customer_app/widgets/dialog/otp_dialog.dart'; import 'package:car_customer_app/extensions/string_extensions.dart'; import 'package:car_customer_app/extensions/int_extensions.dart'; +import 'package:car_customer_app/widgets/show_fill_button.dart'; import 'package:car_customer_app/widgets/txt_field.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart'; -class ForgetPasswordPage extends StatelessWidget { +class ForgetPasswordPage extends StatefulWidget { + @override + State createState() => _ForgetPasswordPageState(); +} + +class _ForgetPasswordPageState extends State { int otpType = 1; + String userName = ""; + bool _email = true; + bool _mobile = true; + + @override Widget build(BuildContext context) { return Scaffold( @@ -33,43 +44,65 @@ class ForgetPasswordPage extends StatelessWidget { padding: EdgeInsets.all(40), child: Column( children: [ + 20.height, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + RaisedButton( + onPressed: () { + setState(() { + _mobile = true; + _email = false; + }); + },child: + Text("Mobile Number", + style: TextStyle(fontSize: 14, + fontWeight: FontWeight.w600,), + ),color: _mobile ? Colors.blue : Colors.transparent,textColor: _mobile ? Colors.white : Colors.blue, + padding: EdgeInsets.symmetric(horizontal: 18, vertical: 12),), + + RaisedButton(onPressed: () { + setState(() { + _mobile = false; + _email = true; + }); + },child: + Text("Email Address", + style: TextStyle(fontSize: 14, + fontWeight: FontWeight.w600,),),color: _email? Colors.blue : Colors.transparent + ,textColor: _email ? Colors.white : Colors.blue, + padding: EdgeInsets.symmetric(horizontal: 18, vertical: 12),), + ], + ), + 50.height, "Retrieve Password".toText24(), 12.height, - TxtField( - hint: "Phone Number", + _mobile ? TxtField( + hint: "Phone Number" , value: userName, onChanged: (v) { userName = v; }, - ), - // TxtField( - // hint: "Email", - // ), - mFlex(2), - Row( - children: [ - Expanded( - child: ShowImageButton( - onClick: () { - otpType = 1; - forgetPasswordOTP(context); - }, - title: 'With SMS', - icon: icons + "ic_sms.png", - ), - ), - 20.width, - Expanded( - child: ShowImageButton( - onClick: () { - otpType = 1; - forgetPasswordOTP(context); - }, - title: 'With Whatsapp', - icon: icons + "ic_whatsapp.png", - ), - ), - ], + ): + _email ? TxtField( + hint: "Email Address", + value: userName, + onChanged: (v) { + userName = v; + }, + ): Container(), + 50.height, + ShowFillButton( + title: "Continue", + width: double.infinity, + txtColor: Colors.white, + onPressed: () { + if(userName.isNum()) { + forgetPasswordPhoneOTP(context); + }else{ + forgetPasswordEmailOTP(context); + } + }, ), mFlex(10), ], @@ -78,12 +111,26 @@ class ForgetPasswordPage extends StatelessWidget { ); } - Future forgetPasswordOTP(BuildContext context) async { + Future forgetPasswordPhoneOTP(BuildContext context) async { + Utils.showLoading(context); + Response response = await UserApiClent().ForgetPasswordOTPRequest(userName, otpType); + Utils.hideLoading(context); + PasswordOTPRequest otpRequest = PasswordOTPRequest.fromJson(jsonDecode(response.body)); + if (otpRequest.messageStatus == 1) { + var userToken = otpRequest.data!.userToken; + navigateReplaceWithName(context, AppRoutes.forgetPasswordMethodSPage, arguments: userToken); + } else { + Utils.showToast(otpRequest.message ?? ""); + } + } + + Future forgetPasswordEmailOTP(BuildContext context) async { Utils.showLoading(context); Response response = await UserApiClent().ForgetPasswordOTPRequest(userName, otpType); Utils.hideLoading(context); PasswordOTPRequest otpRequest = PasswordOTPRequest.fromJson(jsonDecode(response.body)); if (otpRequest.messageStatus == 1) { + Utils.showToast("Code is sent to email"); showMDialog(context, child: OtpDialog( onClick: (String code) async { pop(context); @@ -93,6 +140,8 @@ class ForgetPasswordPage extends StatelessWidget { PasswordOTPCompare otpCompare = PasswordOTPCompare.fromJson(jsonDecode(res.body)); if (otpCompare.messageStatus == 1) { var userToken = otpCompare.data!.userToken; + print("token is ________"); + print(userToken); navigateWithName(context, AppRoutes.confirmNewPasswordPage, arguments: userToken); } else { Utils.showToast(otpCompare.message ?? ""); diff --git a/lib/pages/user/login_with_password_page.dart b/lib/pages/user/login_with_password_page.dart index e5c9567..c0d036a 100644 --- a/lib/pages/user/login_with_password_page.dart +++ b/lib/pages/user/login_with_password_page.dart @@ -23,10 +23,20 @@ import 'package:car_customer_app/widgets/txt_field.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart'; -class LoginWithPassword extends StatelessWidget { +class LoginWithPassword extends StatefulWidget { + @override + State createState() => _LoginWithPasswordState(); +} + +class _LoginWithPasswordState extends State { int otpType = 1; + String phoneNum = "", password = ""; + bool _email = true; + + bool _mobile = true; + @override Widget build(BuildContext context) { return Scaffold( @@ -37,25 +47,69 @@ class LoginWithPassword extends StatelessWidget { padding: EdgeInsets.all(40), child: Column( children: [ - "Login".toText24(), - mFlex(1), - TxtField( - hint: "966501234567", - value: phoneNum, - onChanged: (v) { - phoneNum = v; - }, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + RaisedButton( + onPressed: () { + setState(() { + _mobile = true; + _email = false; + }); + },child: + Text("Mobile Number", + style: TextStyle(fontSize: 14, + fontWeight: FontWeight.w600,), + ),color: _mobile ? Colors.blue : Colors.transparent,textColor: _mobile ? Colors.white : Colors.blue, + padding: EdgeInsets.symmetric(horizontal: 18, vertical: 12),), + + RaisedButton(onPressed: () { + setState(() { + _mobile = false; + _email = true; + }); + },child: + Text("Email Address", + style: TextStyle(fontSize: 14, + fontWeight: FontWeight.w600,),),color: _email? Colors.blue : Colors.transparent + ,textColor: _email ? Colors.white : Colors.blue, + padding: EdgeInsets.symmetric(horizontal: 18, vertical: 12),), + ], ), - 12.height, + 50.height, + "Enter Mobile or Email".toText24(), + mFlex(1), + _mobile ? Column( + children: [ + TxtField( + hint: "Enter phone number", + value: phoneNum, + onChanged: (v) { + phoneNum = v; + }, + ), + 12.height, + TxtField( + hint: "Enter Password", + value: password, + isPasswordEnabled: true, + maxLines: 1, + onChanged: (v) { + password = v; + }, + ), + ], + ): _email ? TxtField( - hint: "Password", + hint: "Enter Email", value: password, isPasswordEnabled: true, maxLines: 1, onChanged: (v) { password = v; }, - ), + ) + :Container(), 10.height, Row( mainAxisAlignment: MainAxisAlignment.end, @@ -67,7 +121,7 @@ class LoginWithPassword extends StatelessWidget { ), 50.height, ShowFillButton( - title: "Continue", + title: "Log In", width: double.infinity, onPressed: () { performBasicOtp(context); diff --git a/pubspec.lock b/pubspec.lock index 13c55cd..5d94910 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -50,6 +50,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.15.0" + cross_file: + dependency: transitive + description: + name: cross_file + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.2" crypto: dependency: transitive description: @@ -116,6 +123,13 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.5" flutter_svg: dependency: "direct dev" description: @@ -154,6 +168,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.0.0" + image_picker: + dependency: "direct main" + description: + name: image_picker + url: "https://pub.dartlang.org" + source: hosted + version: "0.8.4+11" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.6" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.4.1" injector: dependency: "direct dev" description: diff --git a/pubspec.yaml b/pubspec.yaml index 9390e9e..db15cbb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -34,6 +34,7 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 + image_picker: ^0.8.4+4 dev_dependencies: flutter_test: