From 780958d011d814f0b3b15c1a1c43863dfcd91dbf Mon Sep 17 00:00:00 2001 From: Michal Smaga Date: Fri, 3 May 2024 15:55:52 +0200 Subject: [PATCH] Support expired subscription state and subscription repurchase (#2707) Task/Issue URL: https://app.asana.com/0/72649045549333/1206382263248900/f **Description**: Support expired subscription state and subscription repurchase. Repurchase is done on a platform that is matching the app distribution (independent to where it was originally bought). Changes for supporting repurchase flows are/were implemented in BSK in the following PRs: - App Store repurchase: https://github.com/duckduckgo/BrowserServicesKit/pull/788 - Stripe repurchase: https://github.com/duckduckgo/BrowserServicesKit/pull/800 **Steps to test this PR**: 1. Activate expired subscription via email 2. Repurchase expired App Store subscription on Stripe 3. Repurchase expired Stripe subscription on App Store 4. Repurchase expired Stripe subscription on Stripe --- ###### Internal references: [Pull Request Review Checklist](https://app.asana.com/0/1202500774821704/1203764234894239/f) [Software Engineering Expectations](https://app.asana.com/0/59792373528535/199064865822552) [Technical Design Template](https://app.asana.com/0/59792373528535/184709971311943) [Pull Request Documentation](https://app.asana.com/0/1202500774821704/1204012835277482/f) --------- Co-authored-by: Daniel Bernal --- .../SubscriptionPagesUserScript.swift | 17 ++++++++++++----- .../PreferencesSubscriptionView.swift | 8 ++++++-- .../subscription-expired-icon.pdf | Bin 2374 -> 1170 bytes .../Sources/SubscriptionUI/UserText.swift | 7 ++++--- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/DuckDuckGo/Tab/UserScripts/Subscription/SubscriptionPagesUserScript.swift b/DuckDuckGo/Tab/UserScripts/Subscription/SubscriptionPagesUserScript.swift index bee8634adc..4d9b38724b 100644 --- a/DuckDuckGo/Tab/UserScripts/Subscription/SubscriptionPagesUserScript.swift +++ b/DuckDuckGo/Tab/UserScripts/Subscription/SubscriptionPagesUserScript.swift @@ -105,6 +105,7 @@ final class SubscriptionPagesUseSubscriptionFeature: Subfeature { static let subscriptionsUnknownPriceClicked = "subscriptionsUnknownPriceClicked" static let subscriptionsAddEmailSuccess = "subscriptionsAddEmailSuccess" static let subscriptionsWelcomeFaqClicked = "subscriptionsWelcomeFaqClicked" + static let getAccessToken = "getAccessToken" } // swiftlint:disable:next cyclomatic_complexity @@ -124,6 +125,7 @@ final class SubscriptionPagesUseSubscriptionFeature: Subfeature { case Handlers.subscriptionsUnknownPriceClicked: return subscriptionsUnknownPriceClicked case Handlers.subscriptionsAddEmailSuccess: return subscriptionsAddEmailSuccess case Handlers.subscriptionsWelcomeFaqClicked: return subscriptionsWelcomeFaqClicked + case Handlers.getAccessToken: return getAccessToken default: return nil } @@ -142,11 +144,8 @@ final class SubscriptionPagesUseSubscriptionFeature: Subfeature { } func getSubscription(params: Any, original: WKScriptMessage) async throws -> Encodable? { - if let authToken = accountManager.authToken, accountManager.accessToken != nil { - return Subscription(token: authToken) - } else { - return Subscription(token: "") - } + let authToken = accountManager.authToken ?? "" + return Subscription(token: authToken) } func setSubscription(params: Any, original: WKScriptMessage) async throws -> Encodable? { @@ -451,6 +450,14 @@ final class SubscriptionPagesUseSubscriptionFeature: Subfeature { return nil } + func getAccessToken(params: Any, original: WKScriptMessage) async throws -> Encodable? { + if let accessToken = AccountManager(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)).accessToken { + return ["token": accessToken] + } else { + return [String: String]() + } + } + // MARK: Push actions enum SubscribeActionName: String { diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionView.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionView.swift index db764f58e1..a0e31c7d4b 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionView.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionView.swift @@ -185,9 +185,13 @@ public struct PreferencesSubscriptionView: View { TextMenuItemCaption(UserText.preferencesSubscriptionExpiredCaption) } buttons: { // We need to improve re-purchase flow - /* Button(UserText.viewPlansButtonTitle) { model.purchaseAction() } - .buttonStyle(DefaultActionButtonStyle(enabled: true)) */ + Button(UserText.viewPlansExpiredButtonTitle) { model.purchaseAction() } + .buttonStyle(DefaultActionButtonStyle(enabled: true)) Menu { + Button(UserText.addToAnotherDeviceButton) { + model.userEventHandler(.addToAnotherDeviceClick) + showingSheet.toggle() + } Button(UserText.removeFromThisDeviceButton, action: { showingRemoveConfirmationDialog.toggle() }) diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Resources/Subscription.xcassets/Icons/subscription-expired-icon.imageset/subscription-expired-icon.pdf b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Resources/Subscription.xcassets/Icons/subscription-expired-icon.imageset/subscription-expired-icon.pdf index d43daeb9b999065914b2ae55c80a3467fee00e9a..a971e48c07a4f1e34f2f92c519b02d4e8cc650e6 100644 GIT binary patch delta 695 zcmX>mG>LP9c)h-BMTvWGNn%N=f{l%WzN;aaN={TT&@(as0R=ld2;xf3OUX~l;^Hz= zFi-$76u?T|GIL5&ixl+Ta)4&Iq$cO5qylAtK;I`dFTEr~!5FAK2qHpIoua(}m321S<9H$ zuJ=<&TV{T+N2%rZ^vBy*o(nDsD%kpZns-N`vpuZvJsx7%FObC@)+>IcKF=zs&p<1v6(QTvv2z z?2di>tXMEChwCuswX1?kAMbGQnkyS-EwkMw_CRiy`@dU(l35Bp2CcJBn&ob6S&%SK zok{BED^@A%z24;~9@}z0R^8FKOQYUx#)S3zoBC@`p0_{DsM{!MCa3i4p4_Zyl?$88 z&3fPMOj*--AWN`k7L$#S>)ot!w@&TV-b|ur__*U+%QxQ=ZFAwj`&UeOz)~Oq2fU zy5GJ&`QlDKLq~ms`V;2QQx<*AF45CIq4c=c>sD4Qt0DV3gV<#Y4hu}5>`*>8^xHHM zmoto-3%!)&7Ej@L#k%9aS=1Ze3p)a0CiAe%GMSid)?qJZ^fNb6fFzwfE--CiU}j{9 jA!Gtf7$BekS7l*nh9P8WF!?QqKc}UMC6}tItG^on9E=(P literal 2374 zcmbVOOHbS|5Wf3Y%moQ5tz#!~oJa_%ETyX2s&wfM^^j%_Y{e$+CRDV)zGKH88y2aL z9MJ6NnQtB*&v0;YcD|5YGbTa6@Z~E5I6j7x6K49g{mJqa&)%8-X1av}!Ijk-r=4lH zEITtlHl10$K859F`l}n+cP6=TABZ3LO!dFUC*Qn zgqnM!Z2}g&P`a*4kdjwrE{iHgKn4^^$4H+r684XXpu;GAe$fxM98y6DDj$tKDx+8iAApjb^lsq@`o-d7)Eh|yA6hcFMdGUovURSDVY>oZPCl1$Q^MoP_686;zaiicVYxEr{ zD8|$!fjCbBNtEc6Od_$ZFx86A?c@zJE$5}Ib9~$dSGCmm)MOP7$sj_Q2w6llk)Amv z8Z;*E=#DHXC^8_#PH!I`VI=Gy5rONl7jBH&mFM?aSblcT%}Y`0qM)5v5{$btd)fEH zG{V(q+@1JkpMHKbkX^Jl#slxodefc`4{#Ot55*P}j#6M+nQ^$^b!G&+omZZ2IrNk1 z(W70>0la8;hyk{?gOUYqAzJL&+szt71)ISNf}iDZkG66z{t=Oc3D;-BWD^|8VN874 zPVL=r^VsxZXRet5&E~GMf1y&UP=K)iqyQ&DPf&qz+K(XYM7)zHP>F#(f^s37JqVv` z(3*Db=FaSxy}dVQSdPPS*qS3a+^mo0qGYRKn7}6N3Y=YTei@A3{m0YpCYMewRn86$ IUVS+K4Zq#t=Kufz diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/UserText.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/UserText.swift index 3d344a38c9..f917d58b71 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/UserText.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/UserText.swift @@ -55,7 +55,7 @@ enum UserText { } static func preferencesSubscriptionExpiredCaption(formattedDate: String) -> String { - let localized = NSLocalizedString("subscription.preferences.subscription.expired.caption", value: "Your Privacy Pro subscription expired on %@.", comment: "Caption for the subscription preferences pane when the subscription has expired. The parameter is date of expiry.") + let localized = NSLocalizedString("subscription.preferences.subscription.expired.caption", value: "Your Privacy Pro subscription expired on %@", comment: "Caption for the subscription preferences pane when the subscription has expired. The parameter is date of expiry.") return String(format: localized, formattedDate) } @@ -64,8 +64,8 @@ enum UserText { static let addToAnotherDeviceButton = NSLocalizedString("subscription.preferences.add.to.another.device.button", value: "Add to Another Device…", comment: "Button to add subscription to another device") static let manageSubscriptionButton = NSLocalizedString("subscription.preferences.manage.subscription.button", value: "Manage Subscription", comment: "Button to manage subscription") - static let changePlanOrBillingButton = NSLocalizedString("subscription.preferences.change.plan.or.billing.button", value: "Change Plan or Billing...", comment: "Button to add subscription to another device") - static let removeFromThisDeviceButton = NSLocalizedString("subscription.preferences.remove.from.this.device.button", value: "Remove From This Device...", comment: "Button to remove subscription from this device") + static let changePlanOrBillingButton = NSLocalizedString("subscription.preferences.change.plan.or.billing.button", value: "Change Plan or Billing…", comment: "Button to add subscription to another device") + static let removeFromThisDeviceButton = NSLocalizedString("subscription.preferences.remove.from.this.device.button", value: "Remove From This Device…", comment: "Button to remove subscription from this device") // MARK: Preferences when subscription is inactive static let preferencesSubscriptionInactiveHeader = NSLocalizedString("subscription.preferences.subscription.inactive.header", value: "Subscribe to Privacy Pro", comment: "Header for the subscription preferences pane when the subscription is inactive") @@ -81,6 +81,7 @@ enum UserText { // MARK: Preferences when subscription is expired static let preferencesSubscriptionExpiredCaption = NSLocalizedString("subscription.preferences.subscription.expired.caption", value: "Subscribe again to continue using Privacy Pro.", comment: "Caption for the subscription preferences pane when the subscription activation is pending") + static let viewPlansExpiredButtonTitle = NSLocalizedString("subscription.preferences.button.view.plans", value: "View Plans…", comment: "Button for viewing subscription plans on expired subscription") static let manageDevicesButton = NSLocalizedString("subscription.preferences.manage.devices.button", value: "Manage Devices", comment: "Button to manage devices") // MARK: - Change plan or billing dialogs