Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MBL-1607] Add Estimated Shipping View to Late Pledge Checkout #2133

Merged
merged 15 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ final class NoShippingConfirmDetailsViewController: UIViewController, MessageBan

private var sessionStartedObserver: Any?

private let viewModel: ConfirmDetailsViewModelType = ConfirmDetailsViewModel()
private let viewModel: NoShippingConfirmDetailsViewModelType = NoShippingConfirmDetailsViewModel()

// MARK: - Lifecycle

Expand Down Expand Up @@ -309,20 +309,6 @@ extension NoShippingConfirmDetailsViewController: PledgeAmountViewControllerDele
}
}

// MARK: - PledgeShippingLocationViewControllerDelegate

extension NoShippingConfirmDetailsViewController: PledgeShippingLocationViewControllerDelegate {
func pledgeShippingLocationViewController(
_: PledgeShippingLocationViewController,
didSelect shippingRule: ShippingRule
) {
self.viewModel.inputs.shippingRuleSelected(shippingRule)
}

func pledgeShippingLocationViewControllerLayoutDidUpdate(_: PledgeShippingLocationViewController) {}
func pledgeShippingLocationViewControllerFailedToLoad(_: PledgeShippingLocationViewController) {}
}

// MARK: - ConfirmDetailsContinueCTAViewDelegate

extension NoShippingConfirmDetailsViewController: ConfirmDetailsContinueCTAViewDelegate {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ final class NoShippingPledgeViewController: UIViewController,
|> \.translatesAutoresizingMaskIntoConstraints .~ false
}()

private lazy var estimatedShippingStackView: UIStackView = {
UIStackView(frame: .zero)
|> \.translatesAutoresizingMaskIntoConstraints .~ false
}()
Comment on lines +111 to +114
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ifosli For the correct margins to be applied, the estimated shipping view needs to be added to a new stack view as a subview. This is true for UIKit views as well. I spent time rebuilding the view with UIKit to verify this.


private var sessionStartedObserver: Any?
private let viewModel: NoShippingPledgeViewModelType = NoShippingPledgeViewModel()

Expand Down Expand Up @@ -143,31 +148,27 @@ final class NoShippingPledgeViewController: UIViewController,
// MARK: - Configuration

private func configureChildViewControllers() {
_ = (self.rootScrollView, self.view)
|> ksr_addSubviewToParent()
self.view.addSubview(self.rootScrollView)
self.view.addSubview(self.pledgeCTAContainerView)

_ = (self.rootStackView, self.rootScrollView)
|> ksr_addSubviewToParent()
|> ksr_constrainViewToEdgesInParent()

_ = (self.pledgeCTAContainerView, self.view)
|> ksr_addSubviewToParent()

let childViewControllers = [
self.pledgeRewardsSummaryViewController,
self.paymentMethodsViewController
]

let arrangedInsetSubviews = [
[self.titleLabel],
self.paymentMethodsSectionViews,
self.confirmationSectionViews,
[self.pledgeRewardsSummaryViewController.view]
self.confirmationSectionViews
]
.flatMap { $0 }
.compact()

_ = ([self.titleLabel, self.rootInsetStackView], self.rootStackView)
|> ksr_addArrangedSubviewsToStackView()
self.rootStackView.addArrangedSubview(self.rootInsetStackView)

arrangedInsetSubviews.forEach { view in
self.rootInsetStackView.addArrangedSubview(view)
Expand All @@ -178,26 +179,24 @@ final class NoShippingPledgeViewController: UIViewController,
viewController.didMove(toParent: self)
}

self.rootStackView.addArrangedSubview(self.pledgeRewardsSummaryViewController.view)

self.rootStackView.addArrangedSubview(self.estimatedShippingStackView)

self.titleLabel.setContentCompressionResistancePriority(.required, for: .vertical)
self.titleLabel.setContentHuggingPriority(.required, for: .vertical)
}

private func setupConstraints() {
NSLayoutConstraint.activate([
self.rootScrollView.topAnchor.constraint(
equalTo: self.view.safeAreaLayoutGuide.topAnchor,
constant: Styles.grid(1)
),
self.rootScrollView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor),
self.rootScrollView.leftAnchor.constraint(equalTo: self.view.leftAnchor),
self.rootScrollView.rightAnchor.constraint(equalTo: self.view.rightAnchor),
self.rootScrollView.bottomAnchor.constraint(
equalTo: self.pledgeCTAContainerView.topAnchor,
constant: -Styles.grid(3)
),
self.rootScrollView.bottomAnchor.constraint(equalTo: self.pledgeCTAContainerView.topAnchor),
self.pledgeCTAContainerView.leftAnchor.constraint(equalTo: self.view.leftAnchor),
self.pledgeCTAContainerView.rightAnchor.constraint(equalTo: self.view.rightAnchor),
self.pledgeCTAContainerView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
self.rootStackView.widthAnchor.constraint(equalTo: self.view.widthAnchor)
self.rootStackView.widthAnchor.constraint(equalTo: self.rootScrollView.widthAnchor)
])
}

Expand All @@ -206,26 +205,21 @@ final class NoShippingPledgeViewController: UIViewController,
override func bindStyles() {
super.bindStyles()

_ = self.view
|> checkoutBackgroundStyle
self.view.backgroundColor = UIColor.ksr_support_100

_ = self.titleLabel
|> titleLabelStyle
titleLabelStyle(self.titleLabel)

_ = self.pledgeDisclaimerView
|> pledgeDisclaimerViewStyle
rootScrollViewStyle(self.rootScrollView)

_ = self.rootScrollView
|> rootScrollViewStyle
rootStackViewStyle(self.rootStackView)

_ = self.rootStackView
|> rootStackViewStyle
rootInsetStackViewStyle(self.rootInsetStackView)

_ = self.rootInsetStackView
|> rootInsetStackViewStyle
rootInsetStackViewStyle(self.estimatedShippingStackView)

_ = self.paymentMethodsViewController.view
|> roundedStyle(cornerRadius: Layout.Style.cornerRadius)
roundedStyle(self.paymentMethodsViewController.view, cornerRadius: Layout.Style.cornerRadius)

roundedViewStyle(self.pledgeDisclaimerView, cornerRadius: Layout.Style.cornerRadius)
}

// MARK: - View model
Expand Down Expand Up @@ -282,7 +276,7 @@ final class NoShippingPledgeViewController: UIViewController,
.observeForUI()
.observeValues { [weak self] strings in
let (estimatedShippingText, estimatedConversionText) = strings
self?.configureEstimatedShippingView(with: (estimatedShippingText, estimatedConversionText))
self?.configureEstimatedShippingView(estimatedShippingText, estimatedConversionText)
}

self.viewModel.outputs.estimatedShippingViewHidden
Expand Down Expand Up @@ -440,20 +434,22 @@ final class NoShippingPledgeViewController: UIViewController,
self.pledgeDisclaimerView.configure(with: ("icon-not-a-store", attributedText))
}

private func configureEstimatedShippingView(with strings: (String, String)) {
let (estimatedCost, aboutConversion) = strings
private func configureEstimatedShippingView(_ estimatedCost: String, _ aboutConversion: String) {
let estimatedShippingView = EstimatedShippingCheckoutView(
estimatedCost: estimatedCost,
aboutConversion: aboutConversion
)

self.estimatedShippingViewContainer.rootView = estimatedShippingView
self.estimatedShippingViewContainer.view.translatesAutoresizingMaskIntoConstraints = false
self.estimatedShippingViewContainer.view.clipsToBounds = true
self.estimatedShippingViewContainer.view.layer.masksToBounds = true
self.estimatedShippingViewContainer.view.layer.cornerRadius = Layout.Style.cornerRadius

self.rootInsetStackView.addArrangedSubview(self.estimatedShippingViewContainer.view)
self.rootInsetStackView.layoutIfNeeded()
self.estimatedShippingStackView.addArrangedSubview(self.estimatedShippingViewContainer.view)
self.estimatedShippingViewContainer.didMove(toParent: self)

self.estimatedShippingStackView.layoutIfNeeded()
}

private func goToLoginSignup(with intent: LoginIntent, project: Project, reward: Reward) {
Expand Down Expand Up @@ -598,38 +594,39 @@ extension NoShippingPledgeViewController: PledgeDisclaimerViewDelegate {

// MARK: - Styles

private let pledgeDisclaimerViewStyle: ViewStyle = { view in
view
|> roundedStyle(cornerRadius: Layout.Style.cornerRadius)
private func roundedViewStyle(_ view: UIView, cornerRadius: CGFloat) {
view.clipsToBounds = true
view.layer.masksToBounds = true
view.layer.cornerRadius = cornerRadius
}

private let rootScrollViewStyle: ScrollStyle = { scrollView in
scrollView
|> \.showsVerticalScrollIndicator .~ false
|> \.alwaysBounceVertical .~ true
private func rootScrollViewStyle(_ scrollView: UIScrollView) {
scrollView.showsVerticalScrollIndicator = false
scrollView.alwaysBounceVertical = true
}

private let rootStackViewStyle: StackViewStyle = { stackView in
stackView
|> \.axis .~ NSLayoutConstraint.Axis.vertical
|> \.spacing .~ Styles.grid(4)
|> \.isLayoutMarginsRelativeArrangement .~ true
|> \.layoutMargins .~ UIEdgeInsets(
topBottom: 0,
leftRight: Layout.Margin.leftRight
)
private func rootStackViewStyle(_ stackView: UIStackView) {
stackView.axis = NSLayoutConstraint.Axis.vertical
stackView.spacing = Styles.grid(2)
stackView.isLayoutMarginsRelativeArrangement = true
stackView.layoutMargins = UIEdgeInsets(
topBottom: ConfirmDetailsLayout.Margin.topBottom,
leftRight: 0
)
}

private let rootInsetStackViewStyle: StackViewStyle = { stackView in
stackView
|> \.axis .~ NSLayoutConstraint.Axis.vertical
|> \.spacing .~ Styles.grid(4)
|> \.isLayoutMarginsRelativeArrangement .~ true
private func rootInsetStackViewStyle(_ stackView: UIStackView) {
stackView.axis = NSLayoutConstraint.Axis.vertical
stackView.spacing = Styles.grid(4)
stackView.isLayoutMarginsRelativeArrangement = true
stackView.layoutMargins = UIEdgeInsets(
topBottom: ConfirmDetailsLayout.Margin.topBottom,
leftRight: ConfirmDetailsLayout.Margin.leftRight
)
}

public func titleLabelStyle(_ label: UILabel) {
label.numberOfLines = 1
label.textColor = UIColor.ksr_support_700
label.font = UIFont.ksr_title2().bolded
label.layoutMargins = UIEdgeInsets(topBottom: Layout.Margin.topBottom, leftRight: Styles.grid(3))
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ final class NoShippingPledgeViewControllerTests: TestCase {
RemoteConfigFeature.noShippingAtCheckout.rawValue: true
]

orthogonalCombos(Language.allLanguages, [Device.phone4_7inch, Device.pad], [nil, User.template])
.forEach { language, device, currentUser in
orthogonalCombos(Language.allLanguages, [Device.phone4_7inch, Device.pad])
.forEach { language, device in
withEnvironment(language: language, remoteConfigClient: mockConfigClient) {
let controller = NoShippingPledgeViewController.instantiate()
let data = PledgeViewData(
Expand All @@ -155,16 +155,12 @@ final class NoShippingPledgeViewControllerTests: TestCase {

self.scheduler.advance(by: .seconds(1))

let loggedIn = currentUser != nil
let loggedInString = loggedIn ? "LoggedIn" : "LoggedOut"
if loggedIn { parent.view.frame.size.height = 1_200 }

self.allowLayoutPass()

assertSnapshot(
matching: parent.view,
as: .image(perceptualPrecision: 0.98),
named: "lang_\(language)_device_\(device)_\(loggedInString)"
named: "lang_\(language)_device_\(device)"
)
}
}
Expand Down Expand Up @@ -242,24 +238,20 @@ final class NoShippingPledgeViewControllerTests: TestCase {
RemoteConfigFeature.noShippingAtCheckout.rawValue: true
]

orthogonalCombos(Language.allLanguages, [Device.phone4_7inch, Device.pad], [nil, User.template])
.forEach { language, device, currentUser in
orthogonalCombos(Language.allLanguages, [Device.phone4_7inch, Device.pad])
.forEach { language, device in
withEnvironment(language: language, remoteConfigClient: mockConfigClient) {
let controller = NoShippingPledgeViewController.instantiate()
controller.configure(with: data)
let (parent, _) = traitControllers(device: device, orientation: .portrait, child: controller)
self.scheduler.advance(by: .seconds(1))

let loggedIn = currentUser != nil
let loggedInString = loggedIn ? "LoggedIn" : "LoggedOut"
if loggedIn { parent.view.frame.size.height = 1_200 }

self.allowLayoutPass()

assertSnapshot(
matching: parent.view,
as: .image(perceptualPrecision: 0.98),
named: "lang_\(language)_device_\(device)_\(loggedInString)"
named: "lang_\(language)_device_\(device)"
)
}
}
Expand Down
Loading