From 80623176fd934ea620861127b9a6b118484be208 Mon Sep 17 00:00:00 2001 From: Povilas Staskus Date: Mon, 16 Oct 2023 15:44:02 +0300 Subject: [PATCH 1/2] Handle domain_name returned from plan selection by using it in site creation When users select paid domain, they can still opt-in for a free wordpress.com subdomain in plan selection view. When domain is selected, it is returned through "domain_name" parameter. Use this domain when creating siteURLString instead of the one selected in domain selection view. --- .../Site Creation/Plan/PlanStep.swift | 3 +- .../Plan/PlanWizardContent.swift | 6 ++- .../Plan/PlanWizardContentViewModel.swift | 25 ++++++++--- .../Site Creation/Wizard/SiteCreator.swift | 44 +++++++++++++------ .../PlanWizardContentViewModelTests.swift | 14 +++--- 5 files changed, 61 insertions(+), 31 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Site Creation/Plan/PlanStep.swift b/WordPress/Classes/ViewRelated/Site Creation/Plan/PlanStep.swift index c741eb555734..0b9245375c71 100644 --- a/WordPress/Classes/ViewRelated/Site Creation/Plan/PlanStep.swift +++ b/WordPress/Classes/ViewRelated/Site Creation/Plan/PlanStep.swift @@ -5,8 +5,9 @@ final class PlanStep: WizardStep { internal var content: UIViewController { let viewModel = PlanWizardContentViewModel(siteCreator: creator) - return PlanWizardContent(viewModel: viewModel) { [weak self] planId in + return PlanWizardContent(viewModel: viewModel) { [weak self] planId, domainName in self?.creator.planId = planId + self?.creator.addressFromPlanSelection = domainName self?.delegate?.nextStep() } } diff --git a/WordPress/Classes/ViewRelated/Site Creation/Plan/PlanWizardContent.swift b/WordPress/Classes/ViewRelated/Site Creation/Plan/PlanWizardContent.swift index 7002e632116a..ddf7e083ba7d 100644 --- a/WordPress/Classes/ViewRelated/Site Creation/Plan/PlanWizardContent.swift +++ b/WordPress/Classes/ViewRelated/Site Creation/Plan/PlanWizardContent.swift @@ -1,7 +1,9 @@ import UIKit final class PlanWizardContent: WebKitViewController { - typealias PlanSelectionCallback = (Int?) -> Void + typealias PlanId = Int + typealias DomainName = String + typealias PlanSelectionCallback = (PlanId?, DomainName?) -> Void private let viewModel: PlanWizardContentViewModel private let completion: PlanSelectionCallback @@ -29,7 +31,7 @@ final class PlanWizardContent: WebKitViewController { } if viewModel.isPlanSelected(url) { - completion(viewModel.selectedPlanId(from: url)) + completion(viewModel.selectedPlanId(from: url), viewModel.selectedDomainName(from: url)) decisionHandler(.cancel) return } diff --git a/WordPress/Classes/ViewRelated/Site Creation/Plan/PlanWizardContentViewModel.swift b/WordPress/Classes/ViewRelated/Site Creation/Plan/PlanWizardContentViewModel.swift index 7db013c8e709..4151c5e33d9a 100644 --- a/WordPress/Classes/ViewRelated/Site Creation/Plan/PlanWizardContentViewModel.swift +++ b/WordPress/Classes/ViewRelated/Site Creation/Plan/PlanWizardContentViewModel.swift @@ -8,7 +8,7 @@ struct PlanWizardContentViewModel { var queryItems: [URLQueryItem] = [] if let domainSuggestion = siteCreator.address, !domainSuggestion.isFree { - queryItems.append(.init(name: Constants.paidDomainNameParameter, value: domainSuggestion.domainName)) + queryItems.append(.init(name: Constants.InputParameter.paidDomainName, value: domainSuggestion.domainName)) } components.queryItems = queryItems @@ -25,7 +25,7 @@ struct PlanWizardContentViewModel { } func selectedPlanId(from url: URL) -> Int? { - guard let planId = parameterValue(from: url, key: Constants.planIdParameter) else { + guard let planId = parameterValue(from: url, key: Constants.OutputParameter.planId) else { return nil } @@ -33,14 +33,25 @@ struct PlanWizardContentViewModel { } func selectedPlanSlug(from url: URL) -> String? { - return parameterValue(from: url, key: Constants.planSlugParameter) + return parameterValue(from: url, key: Constants.OutputParameter.planSlug) } - enum Constants { + func selectedDomainName(from url: URL) -> String? { + return parameterValue(from: url, key: Constants.OutputParameter.domainName) + } + + struct Constants { static let plansWebAddress = "https://wordpress.com/jetpack-app/plans" - static let planIdParameter = "plan_id" - static let planSlugParameter = "plan_slug" - static let paidDomainNameParameter = "paid_domain_name" + + struct InputParameter { + static let paidDomainName = "paid_domain_name" + } + + struct OutputParameter { + static let planId = "plan_id" + static let planSlug = "plan_slug" + static let domainName = "domain_name" + } } } diff --git a/WordPress/Classes/ViewRelated/Site Creation/Wizard/SiteCreator.swift b/WordPress/Classes/ViewRelated/Site Creation/Wizard/SiteCreator.swift index 28388c637619..5e5c224cf4ae 100644 --- a/WordPress/Classes/ViewRelated/Site Creation/Wizard/SiteCreator.swift +++ b/WordPress/Classes/ViewRelated/Site Creation/Wizard/SiteCreator.swift @@ -2,16 +2,6 @@ import Foundation import WordPressKit -extension DomainSuggestion { - var subdomain: String { - return domainName.components(separatedBy: ".").first ?? "" - } - - var isWordPress: Bool { - return domainName.contains("wordpress.com") - } -} - // MARK: - SiteCreationRequestAssemblyError enum SiteCreationRequestAssemblyError: Error { @@ -31,6 +21,8 @@ final class SiteCreator { var information: SiteInformation? var address: DomainSuggestion? var planId: Int? + /// Users can opt for a free domain name in Plans selection + var addressFromPlanSelection: String? /// Generates the final object that will be posted to the backend /// @@ -66,15 +58,17 @@ final class SiteCreator { domainPurchasingEnabled && planId != nil } - /// Returns the domain suggestion if there's one, + /// Returns domain name selected in plan seletion + /// - otherwise the domain suggestion selected in domain view if there's one, /// - otherwise a site name if there's one, /// - otherwise an empty string. private var siteURLString: String { - - guard let domainSuggestion = address else { + guard let domainName = addressFromPlanSelection ?? address?.domainName else { return information?.title ?? "" } - return domainSuggestion.isWordPress ? domainSuggestion.subdomain : domainSuggestion.domainName + + + return domainName.isWordPress ? domainName.subdomain : domainName } private enum Strings { @@ -82,3 +76,25 @@ final class SiteCreator { static let siteCreationFlowForNoAddress = "with-design-picker" } } + +// MARK: - Helper Extensions + +extension String { + var subdomain: String { + return components(separatedBy: ".").first ?? "" + } + + var isWordPress: Bool { + return contains("wordpress.com") + } +} + +extension DomainSuggestion { + var subdomain: String { + return domainName.subdomain + } + + var isWordPress: Bool { + return domainName.isWordPress + } +} diff --git a/WordPress/WordPressTest/SiteCreation/PlanWizardContentViewModelTests.swift b/WordPress/WordPressTest/SiteCreation/PlanWizardContentViewModelTests.swift index 73db109819b9..6fe7a88a321b 100644 --- a/WordPress/WordPressTest/SiteCreation/PlanWizardContentViewModelTests.swift +++ b/WordPress/WordPressTest/SiteCreation/PlanWizardContentViewModelTests.swift @@ -21,7 +21,7 @@ final class PlanWizardContentViewModelTests: XCTestCase { func testIsPlanSelectedWithPlanSlugParameters() { var components = URLComponents(string: PlanWizardContentViewModel.Constants.plansWebAddress)! - components.queryItems = [.init(name: PlanWizardContentViewModel.Constants.planSlugParameter, value: "free_plan")] + components.queryItems = [.init(name: PlanWizardContentViewModel.Constants.OutputParameter.planSlug, value: "free_plan")] XCTAssertTrue(sut.isPlanSelected(components.url!)) } @@ -29,8 +29,8 @@ final class PlanWizardContentViewModelTests: XCTestCase { func testIsPlanSelectedWithPlanSlugAndPlanIdParameters() { var components = URLComponents(string: PlanWizardContentViewModel.Constants.plansWebAddress)! components.queryItems = [ - .init(name: PlanWizardContentViewModel.Constants.planSlugParameter, value: "paid_plan"), - .init(name: PlanWizardContentViewModel.Constants.planIdParameter, value: "1009") + .init(name: PlanWizardContentViewModel.Constants.OutputParameter.planSlug, value: "paid_plan"), + .init(name: PlanWizardContentViewModel.Constants.OutputParameter.planId, value: "1009") ] XCTAssertTrue(sut.isPlanSelected(components.url!)) @@ -46,7 +46,7 @@ final class PlanWizardContentViewModelTests: XCTestCase { func testSelectedPlanId() { var components = URLComponents(string: PlanWizardContentViewModel.Constants.plansWebAddress)! - components.queryItems = [.init(name: PlanWizardContentViewModel.Constants.planIdParameter, value: "125")] + components.queryItems = [.init(name: PlanWizardContentViewModel.Constants.OutputParameter.planId, value: "125")] XCTAssertEqual(sut.selectedPlanId(from: components.url!), 125) } @@ -55,7 +55,7 @@ final class PlanWizardContentViewModelTests: XCTestCase { var components = URLComponents(string: PlanWizardContentViewModel.Constants.plansWebAddress)! components.queryItems = [ .init(name: "parameter", value: "5"), - .init(name: PlanWizardContentViewModel.Constants.planIdParameter, value: "125"), + .init(name: PlanWizardContentViewModel.Constants.OutputParameter.planId, value: "125"), .init(name: "parameter2", value: "abc") ] @@ -70,7 +70,7 @@ final class PlanWizardContentViewModelTests: XCTestCase { let url = URLComponents(url: sut.url, resolvingAgainstBaseURL: true) - let parameter = url?.queryItems?.first(where: { $0.name == PlanWizardContentViewModel.Constants.paidDomainNameParameter }) + let parameter = url?.queryItems?.first(where: { $0.name == PlanWizardContentViewModel.Constants.InputParameter.paidDomainName }) XCTAssertEqual(parameter?.value, domainName) } @@ -80,7 +80,7 @@ final class PlanWizardContentViewModelTests: XCTestCase { let url = URLComponents(url: sut.url, resolvingAgainstBaseURL: true) - let parameter = url?.queryItems?.first(where: { $0.name == PlanWizardContentViewModel.Constants.paidDomainNameParameter }) + let parameter = url?.queryItems?.first(where: { $0.name == PlanWizardContentViewModel.Constants.InputParameter.paidDomainName }) XCTAssertEqual(parameter, nil) } } From 194b99db635fc4840f14c095d479caa51c01c50e Mon Sep 17 00:00:00 2001 From: Povilas Staskus Date: Mon, 16 Oct 2023 15:45:40 +0300 Subject: [PATCH 2/2] Update release notes --- RELEASE-NOTES.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 1fe457d7fd6b..d238f2d51b98 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -1,3 +1,8 @@ +23.6 +----- + +* [***] [internal][Jetpack-only] [***] Added paid domain selection, plan selection, and checkout screens in site creation flow [#21688] + 23.5 ----- * [*] Fix a crash when the blog's blogging prompt settings contain invalid JSON [#21677] @@ -7,7 +12,6 @@ * [*] (Internal) Remove .nativePhotoPicker feature flag and the disabled code [#21681](https://github.com/wordpress-mobile/WordPress-iOS/pull/21681) * [*] [WordPress-only] fixes an issue where users attempting to create a .com site in the post-sign-up flow are presented with two consecutive overlays. [#21752] * [**] [Jetpack-only] Reader: Improvement of core UI elements, including feed cards, tag and site headers, buttons and recommendation sections. [#21772] -* [***] [internal][Jetpack-only] [***] Added paid domain selection, plan selection, and checkout screens in site creation flow [#21688] 23.4 -----