11import UIKit
2+ import protocol Yosemite. StoresManager
23
34/// Coordinates navigation for removing Apple ID access from various entry points (settings and empty stores screens).
4- final class RemoveAppleIDAccessCoordinator {
5+ @ MainActor final class RemoveAppleIDAccessCoordinator {
56 private let sourceViewController : UIViewController
67 private let removeAction : ( ) async -> Result < Void , Error >
78 private let onRemoveSuccess : ( ) -> Void
9+ private let stores : StoresManager
10+ private let analytics : Analytics
811
912 /// - Parameters:
1013 /// - sourceViewController: the view controller that presents the in-progress UI and alerts.
1114 /// - removeAction: called when the remove action is confirmed.
1215 /// - onRemoveSuccess: called when the removal is successful.
1316 init ( sourceViewController: UIViewController ,
1417 removeAction: @escaping ( ) async -> Result < Void , Error > ,
15- onRemoveSuccess: @escaping ( ) -> Void ) {
18+ onRemoveSuccess: @escaping ( ) -> Void ,
19+ stores: StoresManager = ServiceLocator . stores,
20+ analytics: Analytics = ServiceLocator . analytics) {
1621 self . sourceViewController = sourceViewController
1722 self . removeAction = removeAction
1823 self . onRemoveSuccess = onRemoveSuccess
24+ self . stores = stores
25+ self . analytics = analytics
1926 }
2027
2128 func start( ) {
@@ -26,11 +33,15 @@ final class RemoveAppleIDAccessCoordinator {
2633private extension RemoveAppleIDAccessCoordinator {
2734 func presentConfirmationAlert( ) {
2835 // TODO: 7068 - analytics
36+
37+ let username = stores. sessionManager. defaultAccount? . username ?? " "
38+ let message = String . localizedStringWithFormat ( Localization . ConfirmationAlert. alertMessageFormat, username)
2939 let alertController = UIAlertController ( title: Localization . ConfirmationAlert. alertTitle,
30- message: Localization . ConfirmationAlert . alertMessage ,
40+ message: message ,
3141 preferredStyle: . alert)
3242 alertController. addActionWithTitle ( Localization . ConfirmationAlert. cancelButtonTitle, style: . cancel) { _ in }
33- alertController. addActionWithTitle ( Localization . ConfirmationAlert. removeButtonTitle, style: . destructive) { [ weak self] _ in
43+ let closeAccountAction = alertController. addActionWithTitle ( Localization . ConfirmationAlert. removeButtonTitle,
44+ style: . destructive) { [ weak self] _ in
3445 guard let self = self else { return }
3546
3647 // TODO: 7068 - analytics
@@ -44,14 +55,28 @@ private extension RemoveAppleIDAccessCoordinator {
4455 guard let self = self else { return }
4556 switch result {
4657 case . success:
58+ self . analytics. track ( event: . closeAccountSuccess( ) )
4759 self . onRemoveSuccess ( )
4860 case . failure( let error) :
49- DDLogError ( " ⛔️ Cannot remove Apple ID access: \( error) " )
50- self . presentErrorAlert ( )
61+ self . analytics. track ( event: . closeAccountFailed( error: error) )
62+ DDLogError ( " ⛔️ Cannot close account: \( error) " )
63+ self . presentErrorAlert ( error: error)
5164 }
5265 }
5366 }
5467 }
68+
69+ // Enables close account button based on whether the username matches the user input.
70+ closeAccountAction. isEnabled = false
71+
72+ // Username text field.
73+ alertController. addTextField { textField in
74+ textField. clearButtonMode = . always
75+ textField. on ( . editingChanged) { textField in
76+ closeAccountAction. isEnabled = textField. text == username
77+ }
78+ }
79+
5580 sourceViewController. present ( alertController, animated: true )
5681 }
5782
@@ -66,62 +91,102 @@ private extension RemoveAppleIDAccessCoordinator {
6691 sourceViewController. dismiss ( animated: true , completion: completion)
6792 }
6893
69- func presentErrorAlert( ) {
94+ func presentErrorAlert( error : Error ) {
7095 let alertController = UIAlertController ( title: Localization . ErrorAlert. alertTitle,
71- message: Localization . ErrorAlert . alertMessage ,
96+ message: generateLocalizedMessage ( error : error ) ,
7297 preferredStyle: . alert)
98+ alertController. addActionWithTitle ( Localization . ErrorAlert. contactSupportButtonTitle, style: . default) { [ weak self] _ in
99+ guard let self = self else { return }
100+ ZendeskProvider . shared. showNewRequestIfPossible ( from: self . sourceViewController, with: nil )
101+ }
73102 alertController. addActionWithTitle ( Localization . ErrorAlert. dismissButtonTitle, style: . cancel) { _ in }
74103 sourceViewController. present ( alertController, animated: true )
75104 }
105+
106+ func generateLocalizedMessage( error: Error ) -> String {
107+ let errorCode = errorCode ( error: error)
108+
109+ switch errorCode {
110+ case " unauthorized " :
111+ return NSLocalizedString ( " You're not authorized to close the account. " ,
112+ comment: " Error message displayed when unable to close user account due to being unauthorized. " )
113+ case " atomic-site " :
114+ return NSLocalizedString ( " To close this account now, contact our support team. " ,
115+ comment: " Error message displayed when unable to close user account due to having active atomic site. " )
116+ case " chargebacked-site " :
117+ return NSLocalizedString ( " This user account cannot be closed if there are unresolved chargebacks. " ,
118+ comment: " Error message displayed when unable to close user account due to unresolved chargebacks. " )
119+ case " active-subscriptions " :
120+ return NSLocalizedString ( " This user account cannot be closed while it has active subscriptions. " ,
121+ comment: " Error message displayed when unable to close user account due to having active subscriptions. " )
122+ case " active-memberships " :
123+ return NSLocalizedString ( " This user account cannot be closed while it has active purchases. " ,
124+ comment: " Error message displayed when unable to close user account due to having active purchases. " )
125+ default :
126+ return NSLocalizedString ( " An error occured while closing account. " ,
127+ comment: " Default error message displayed when unable to close user account. " )
128+ }
129+ }
130+
131+ func errorCode( error: Error ) -> String ? {
132+ let userInfo = ( error as NSError ) . userInfo
133+ let errorCode = userInfo [ Constants . dotcomAPIErrorCodeKey] as? String
134+ return errorCode
135+ }
76136}
77137
78138private extension RemoveAppleIDAccessCoordinator {
79139 enum Localization {
80140 enum RemoveAppleIDAccessInProgressView {
81141 static let title = NSLocalizedString (
82- " Removing Apple ID Access ..." ,
83- comment: " Title of the Remove Apple ID Access in-progress view. "
142+ " Closing account ..." ,
143+ comment: " Title of the Close Account in-progress view. "
84144 )
85145 }
86146
87147 enum ConfirmationAlert {
88148 static let alertTitle = NSLocalizedString (
89- " Remove Apple ID Access " ,
90- comment: " Remove Apple ID Access confirmation alert title - confirms and revokes Apple ID token ."
149+ " Confirm Close Account " ,
150+ comment: " Close Account confirmation alert title."
91151 )
92- static let alertMessage = NSLocalizedString (
93- " This will log you out and reset your Sign In With Apple access token. " +
94- " You will be asked to re-enter your WordPress.com password if you Sign In With Apple again. " ,
95- comment: " Alert message to confirm a user meant to remove Apple ID access. "
152+ static let alertMessageFormat = NSLocalizedString (
153+ " To confirm, please re-enter your username before closing. \n \n %1$@ " ,
154+ comment: " Close Account confirmation alert message. The %1$@ is the user's WordPress.com username. "
96155 )
97156 static let cancelButtonTitle = NSLocalizedString (
98157 " Cancel " ,
99- comment: " Alert button title - dismisses alert, which cancels the Remove Apple ID Access attempt."
158+ comment: " Close Account button title - dismisses alert, which cancels the Close Account attempt."
100159 )
101160
102161 static let removeButtonTitle = NSLocalizedString (
103- " Remove " ,
104- comment: " Remove Apple ID Access button title - confirms and revokes Apple ID token ."
162+ " Permanently Close Account " ,
163+ comment: " Close Account button title - confirms and closes user's WordPress.com account ."
105164 )
106165 }
107166
108167 enum ErrorAlert {
109168 static let alertTitle = NSLocalizedString (
110- " Error Removing Apple ID Access " ,
111- comment: " Remove Apple ID Access error alert title ."
169+ " Couldn’t close account automatically " ,
170+ comment: " Error title displayed when unable to close user account ."
112171 )
113- static let alertMessage = NSLocalizedString (
114- " Please try again or contact us for support. " ,
115- comment: " Remove Apple ID Access error alert message ."
172+ static let contactSupportButtonTitle = NSLocalizedString (
173+ " Contact Support " ,
174+ comment: " Close Account error alert button title - navigates the user to contact support ."
116175 )
117176 static let dismissButtonTitle = NSLocalizedString (
118- " OK " ,
119- comment: " Alert button title - dismisses Remove Apple ID Access error alert."
177+ " Cancel " ,
178+ comment: " Close Account error alert button title - dismisses error alert."
120179 )
121180 }
122181 }
123182}
124183
184+ private extension RemoveAppleIDAccessCoordinator {
185+ enum Constants {
186+ static let dotcomAPIErrorCodeKey = " WordPressComRestApiErrorCodeKey "
187+ }
188+ }
189+
125190enum RemoveAppleIDAccessError : Error {
126191 case presenterDeallocated
127192}
0 commit comments