From d794945faf690b054c01994ee6feb476f940b636 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Tue, 7 Mar 2023 12:27:35 +0300 Subject: [PATCH] account deletion added. --- lib/api/api_client.dart | 53 ++++++++++++++++++++------ lib/api/user_api_client.dart | 6 +++ lib/app_state/app_state.dart | 2 + lib/ui/common_appbar.dart | 56 ++++++++++++++++++++++++---- lib/ui/dialogs/general_dialog.dart | 60 ++++++++++++++++++++++-------- 5 files changed, 143 insertions(+), 34 deletions(-) diff --git a/lib/api/api_client.dart b/lib/api/api_client.dart index a2d9f7d..6a8a1c6 100644 --- a/lib/api/api_client.dart +++ b/lib/api/api_client.dart @@ -39,7 +39,7 @@ APIException _throwAPIException(Response response) { case 404: APIError apiError; if (response.body != null && response.body.isNotEmpty) { - // var jsonError = jsonDecode(response.body); + // var jsonError = jsonDecode(response.body); apiError = APIError(404, response.body.toString()); } return APIException(APIException.BAD_REQUEST, error: apiError); @@ -68,7 +68,7 @@ class ApiClient { factory ApiClient() => _instance; Future postJsonForObject(FactoryConstructor factoryConstructor, String url, T jsonObject, - {String token, Map queryParameters, Map headers, int retryTimes = 0}) async { + {String token, Map queryParameters, Map headers, int retryTimes = 0, bool isPutRequest = false}) async { var _headers = {'Accept': 'application/json'}; if (headers != null && headers.isNotEmpty) { _headers.addAll(headers); @@ -77,7 +77,11 @@ class ApiClient { print("Url:$url"); print("body:${jsonEncode(jsonObject)}"); } - var response = await postJsonForResponse(url, jsonObject, token: token, queryParameters: queryParameters, headers: _headers, retryTimes: retryTimes); + var response = await postJsonForResponse(url, jsonObject, token: token, + queryParameters: queryParameters, + headers: _headers, + retryTimes: retryTimes, + isPutRequest: isPutRequest); try { var jsonData = jsonDecode(response.body); return factoryConstructor(jsonData); @@ -86,7 +90,8 @@ class ApiClient { } } - Future postJsonForResponse(String url, T jsonObject, {String token, Map queryParameters, Map headers, int retryTimes = 0}) async { + Future postJsonForResponse(String url, T jsonObject, + {String token, Map queryParameters, Map headers, int retryTimes = 0, bool isPutRequest = false}) async { String requestBody; if (jsonObject != null) { requestBody = jsonEncode(jsonObject); @@ -97,10 +102,14 @@ class ApiClient { } } - return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes); + return await _postForResponse(url, requestBody, token: token, + queryParameters: queryParameters, + headers: headers, + retryTimes: retryTimes, + isPutRequest: isPutRequest); } - Future _postForResponse(String url, requestBody, {String token, Map queryParameters, Map headers, int retryTimes = 0}) async { + Future _postForResponse(String url, requestBody, {String token, Map queryParameters, Map headers, int retryTimes = 0, bool isPutRequest = false}) async { try { var _headers = {}; if (token != null) { @@ -115,7 +124,7 @@ class ApiClient { var queryString = new Uri(queryParameters: queryParameters).query; url = url + '?' + queryString; } - var response = await _post(Uri.parse(url), body: requestBody, headers: _headers).timeout(Duration(minutes: 2)); + var response = await _post(Uri.parse(url), body: requestBody, headers: _headers, isPutRequest: isPutRequest).timeout(Duration(minutes: 2)); if (response.statusCode >= 200 && response.statusCode < 300) { return response; @@ -126,7 +135,11 @@ class ApiClient { if (retryTimes > 0) { print('will retry after 3 seconds...'); await Future.delayed(Duration(seconds: 3)); - return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + return await _postForResponse(url, requestBody, token: token, + queryParameters: queryParameters, + headers: headers, + retryTimes: retryTimes - 1, + isPutRequest: isPutRequest); } else { throw APIException(APIException.OTHER, arguments: e); } @@ -134,7 +147,11 @@ class ApiClient { if (retryTimes > 0) { print('will retry after 3 seconds...'); await Future.delayed(Duration(seconds: 3)); - return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + return await _postForResponse(url, requestBody, token: token, + queryParameters: queryParameters, + headers: headers, + retryTimes: retryTimes - 1, + isPutRequest: isPutRequest); } else { throw APIException(APIException.OTHER, arguments: e); } @@ -144,7 +161,11 @@ class ApiClient { if (retryTimes > 0) { print('will retry after 3 seconds...'); await Future.delayed(Duration(seconds: 3)); - return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + return await _postForResponse(url, requestBody, token: token, + queryParameters: queryParameters, + headers: headers, + retryTimes: retryTimes - 1, + isPutRequest: isPutRequest); } else { throw APIException(APIException.OTHER, arguments: e); } @@ -154,7 +175,8 @@ class ApiClient { bool _certificateCheck(X509Certificate cert, String host, int port) => true; Future _withClient(Future Function(Client) fn) async { - var httpClient = HttpClient()..badCertificateCallback = _certificateCheck; + var httpClient = HttpClient() + ..badCertificateCallback = _certificateCheck; var client = IOClient(httpClient); try { return await fn(client); @@ -163,5 +185,12 @@ class ApiClient { } } - Future _post(url, {Map headers, body, Encoding encoding}) => _withClient((client) => client.post(url, headers: headers, body: body, encoding: encoding)); + Future _post(url, {Map headers, body, Encoding encoding, bool isPutRequest = false}) => + _withClient((client) { + if (isPutRequest) { + return client.put(url, headers: headers, body: body, encoding: encoding); + } else { + return client.post(url, headers: headers, body: body, encoding: encoding); + } + }); } diff --git a/lib/api/user_api_client.dart b/lib/api/user_api_client.dart index 4d56b4a..c25615c 100644 --- a/lib/api/user_api_client.dart +++ b/lib/api/user_api_client.dart @@ -46,6 +46,12 @@ class UserApiClient { return await ApiClient().postJsonForObject((json) => GeneralResponseModel.fromJson(json), url, postParams); } + Future deleteAccount(String userId) async { + String url = "${ApiConsts.user}UserRegistration_Delete"; + var postParams = {"userId": userId}; + return await ApiClient().postJsonForObject((json) => GeneralResponseModel.fromJson(json), url, postParams, isPutRequest: true); + } + Future verifyOTP(String _email, int _otp) async { String url = "${ApiConsts.user}OTPVerification"; var postParams = {"email": _email, "opt": _otp}; diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index 8b24e02..7a3c3e4 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -41,6 +41,8 @@ class AppState { String get token => _authenticationUser?.result?.data?.token; + String get userId => _authenticationUser?.result?.data?.userId; + String get userEmail => _authenticationUser?.result?.data?.email; void setAuthenticationModel(AuthenticationUserModel _authenticationUser) { diff --git a/lib/ui/common_appbar.dart b/lib/ui/common_appbar.dart index eff1c4b..5084292 100644 --- a/lib/ui/common_appbar.dart +++ b/lib/ui/common_appbar.dart @@ -102,6 +102,24 @@ class _CommonAppbarState extends State { } } + void deleteUserAccount() async { + Utils.showLoading(context); + try { + await UserApiClient().deleteAccount(AppState().userId); + SharedPreferences prefs = await SharedPreferences.getInstance(); + await prefs.remove(GlobalConsts.userAuthData); + AppState().setAuthenticationModel(null); + Utils.showToast("تم حذف الحساب"); + Navigator.pop(context); + Utils.hideLoading(context); + } catch (ex) { + if (mounted) { + Utils.hideLoading(context); + Utils.handleException(ex, null); + } + } + } + @override void dispose() { super.dispose(); @@ -325,35 +343,59 @@ class _CommonAppbarState extends State { ), ); }); - } else { + } else if (index == 1) { SharedPreferences prefs = await SharedPreferences.getInstance(); await prefs.remove(GlobalConsts.userAuthData); AppState().setAuthenticationModel(null); Utils.showToast("تسجيل خروج المستخدم"); Navigator.pop(context); + } else { + await showDialog( + context: context, + barrierColor: ColorConsts.secondaryWhite.withOpacity(0.8), + builder: (BuildContext context) => GeneralDialog( + message: 'بحذف حسابك ، ستتم إزالة بياناتك ولن تتمكن من استرداد حسابك. \ n انقر فوق "نعم" لحذف حسابك.', + onTap: () { + Navigator.pop(context); + deleteUserAccount(); + }, + showCancelButton: true, + ), + ); } }, icon: SvgPicture.asset("assets/icons/fa_key.svg", height: 25, width: 30, color: ColorConsts.textGrey1), itemBuilder: (_) => >[ PopupMenuItem( value: 0, - padding: EdgeInsets.fromLTRB(0, 0, 0, 0), - height: 24, + padding: EdgeInsets.fromLTRB(4, 0, 4, 0), + height: 36, child: Center( child: Text( 'تغيير كلمة المرور', - style: TextStyle(color: ColorConsts.primaryBlack, fontSize: 14), + style: TextStyle(color: ColorConsts.primaryBlack, fontSize: 16), ), ), ), PopupMenuItem( value: 1, - padding: EdgeInsets.fromLTRB(0, 0, 0, 0), - height: 24, + padding: EdgeInsets.fromLTRB(4, 0, 4, 0), + height: 36, child: Center( child: Text( 'تسجيل خروج', - style: TextStyle(color: ColorConsts.primaryBlack, fontSize: 14), + style: TextStyle(color: ColorConsts.primaryBlack, fontSize: 16), + ), + ), + ), + PopupMenuItem( + value: 2, + padding: EdgeInsets.fromLTRB(4, 0, 4, 0), + height: 36, + child: Center( + child: Text( + 'حذف الحساب', + style: TextStyle(color: ColorConsts.primaryBlack, fontSize: 16), ), ), ), diff --git a/lib/ui/dialogs/general_dialog.dart b/lib/ui/dialogs/general_dialog.dart index 793a372..718ca23 100644 --- a/lib/ui/dialogs/general_dialog.dart +++ b/lib/ui/dialogs/general_dialog.dart @@ -3,7 +3,10 @@ import 'package:tangheem/classes/colors.dart'; class GeneralDialog extends StatelessWidget { final String message; - GeneralDialog({Key key, this.message}) : super(key: key); + final VoidCallback onTap; + final bool showCancelButton; + + GeneralDialog({Key key, this.message, this.onTap, this.showCancelButton = false}) : super(key: key); @override Widget build(BuildContext context) { @@ -30,22 +33,49 @@ class GeneralDialog extends StatelessWidget { style: TextStyle(color: Colors.white), ), SizedBox(height: 32), - SizedBox( - width: double.infinity, - height: 40, - child: TextButton( - onPressed: () => Navigator.pop(context), - style: TextButton.styleFrom( - primary: Colors.white, - padding: EdgeInsets.all(2), - backgroundColor: ColorConsts.secondaryPink, - textStyle: TextStyle(fontSize: 14, fontFamily: "DroidKufi"), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(6.0), + Row( + children: [ + if (showCancelButton) + Expanded( + child: SizedBox( + width: double.infinity, + height: 40, + child: TextButton( + onPressed: () => Navigator.pop(context), + style: TextButton.styleFrom( + primary: Colors.black87, + padding: EdgeInsets.all(2), + backgroundColor: ColorConsts.textHintGrey, + textStyle: TextStyle(fontSize: 14, fontFamily: "DroidKufi"), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0), + ), + ), + child: Text("لا"), + ), + ), + ), + if (showCancelButton) SizedBox(width: 16), + Expanded( + child: SizedBox( + width: double.infinity, + height: 40, + child: TextButton( + onPressed: onTap ?? () => Navigator.pop(context), + style: TextButton.styleFrom( + primary: Colors.white, + padding: EdgeInsets.all(2), + backgroundColor: ColorConsts.secondaryPink, + textStyle: TextStyle(fontSize: 14, fontFamily: "DroidKufi"), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0), + ), + ), + child: Text("نعم"), + ), ), ), - child: Text("نعم"), - ), + ], ), ], ),