Skip to content
New issue

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

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

Already on GitHub? # to your account

[MBL-1208] Part 4: Continue CTA Section #1980

Merged
merged 3 commits into from
Mar 18, 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 @@ -71,6 +71,11 @@ final class ConfirmDetailsViewController: UIViewController {
PostCampaignPledgeRewardsSummaryViewController.instantiate()
}()

private lazy var continueCTAView: ConfirmDetailsContinueCTAView = {
ConfirmDetailsContinueCTAView(frame: .zero)
|> \.translatesAutoresizingMaskIntoConstraints .~ false
}()

private lazy var keyboardDimissingTapGestureRecognizer: UITapGestureRecognizer = {
UITapGestureRecognizer(
target: self,
Expand Down Expand Up @@ -114,6 +119,12 @@ final class ConfirmDetailsViewController: UIViewController {
_ = self
|> \.title .~ Strings.Back_this_project()

self.continueCTAView.continueButton.addTarget(
self,
action: #selector(self.continueButtonTapped),
for: .touchUpInside
)

self.view.addGestureRecognizer(self.keyboardDimissingTapGestureRecognizer)

self.configureChildViewControllers()
Expand All @@ -128,6 +139,9 @@ final class ConfirmDetailsViewController: UIViewController {
_ = (self.rootScrollView, self.view)
|> ksr_addSubviewToParent()

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

_ = (self.rootStackView, self.rootScrollView)
|> ksr_addSubviewToParent()
|> ksr_constrainViewToEdgesInParent()
Expand Down Expand Up @@ -171,7 +185,10 @@ final class ConfirmDetailsViewController: UIViewController {
self.rootScrollView.topAnchor.constraint(equalTo: self.view.topAnchor),
self.rootScrollView.leftAnchor.constraint(equalTo: self.view.leftAnchor),
self.rootScrollView.rightAnchor.constraint(equalTo: self.view.rightAnchor),
self.rootScrollView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
self.rootScrollView.bottomAnchor.constraint(equalTo: self.continueCTAView.topAnchor),
self.continueCTAView.leftAnchor.constraint(equalTo: self.view.leftAnchor),
self.continueCTAView.rightAnchor.constraint(equalTo: self.view.rightAnchor),
self.continueCTAView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
self.rootStackView.widthAnchor.constraint(equalTo: self.view.widthAnchor),
self.pledgeSummarySectionSeparator.heightAnchor.constraint(equalToConstant: 1)
])
Expand Down Expand Up @@ -243,6 +260,12 @@ final class ConfirmDetailsViewController: UIViewController {
.configureWith(rewardsData: rewardsData, bonusAmount: bonusAmount, pledgeData: pledgeData)
}

self.viewModel.outputs.configureCTAWithPledgeTotal
.observeForUI()
.observeValues { data in
self.continueCTAView.configure(with: data)
}

Keyboard.change
.observeForUI()
.observeValues { [weak self] change in
Expand All @@ -262,10 +285,18 @@ final class ConfirmDetailsViewController: UIViewController {

self.pledgeRewardsSummaryViewController.view.rac.hidden = self.viewModel.outputs
.pledgeRewardsSummaryViewHidden

self.continueCTAView.titleAndAmountStackView.rac.hidden = self.viewModel.outputs
.pledgeSummaryViewHidden.negate()
}

// MARK: - Actions

@objc func continueButtonTapped() {
// TODO: Navigate to Checkout Screen
// self.viewModel.inputs.continueButtonTapped()
}

@objc private func dismissKeyboard() {
self.view.endEditing(true)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import KsApi
import Library
import Prelude
import UIKit

public typealias ConfirmDetailsContinueCTAViewData = (
project: Project,
total: Double
)

private enum Layout {
enum Button {
static let minHeight: CGFloat = 48.0
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this not in our design system somewhere?

}
}

protocol ConfirmDetailsContinueCTAViewDelegate: AnyObject {
func continueButtonTapped()
}

final class ConfirmDetailsContinueCTAView: UIView {
// MARK: - Properties

private lazy var rootStackView: UIStackView = { UIStackView(frame: .zero) }()
private(set) lazy var titleAndAmountStackView: UIStackView = { UIStackView(frame: .zero) }()
private lazy var titleLabel: UILabel = { UILabel(frame: .zero) }()
private lazy var amountLabel: UILabel = { UILabel(frame: .zero) }()

private(set) lazy var continueButton: UIButton = {
UIButton(type: .custom)
|> \.translatesAutoresizingMaskIntoConstraints .~ false
}()

public weak var delegate: ConfirmDetailsContinueCTAViewDelegate?

// MARK: - Lifecycle

override init(frame: CGRect) {
super.init(frame: frame)

self.configureSubviews()
self.setupConstraints()

self.continueButton.addTarget(
self, action: #selector(self.continueButtonTapped),
for: .touchUpInside
)
}

required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

// MARK: - Styles

override func bindStyles() {
super.bindStyles()

_ = self
|> \.layoutMargins .~ .init(all: Styles.grid(3))

_ = self.layer
|> checkoutLayerCardRoundedStyle
|> \.backgroundColor .~ UIColor.ksr_white.cgColor
|> \.shadowColor .~ UIColor.ksr_black.cgColor
|> \.shadowOpacity .~ 0.12
|> \.shadowOffset .~ CGSize(width: 0, height: -1.0)
|> \.shadowRadius .~ CGFloat(1.0)
|> \.maskedCorners .~ [
CACornerMask.layerMaxXMinYCorner,
CACornerMask.layerMinXMinYCorner
]

_ = self.rootStackView
|> verticalStackViewStyle
|> \.spacing .~ Styles.grid(3)

_ = self.titleAndAmountStackView
|> self.titleAndAmountStackViewStyle

_ = self.titleLabel
|> self.titleLabelStyle

_ = self.amountLabel
|> self.amountLabelStyle

_ = self.continueButton
|> greenButtonStyle
|> UIButton.lens.title(for: .normal) %~ { _ in Strings.Continue() }
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit/non-blocking: Mentioned this in an earlier PR but I'd prefer us to move away from Prelude code in bindStyles whenever we can avoid it.

}

// MARK: Functions

private func configureSubviews() {
_ = (self.rootStackView, self)
|> ksr_addSubviewToParent()
|> ksr_constrainViewToMarginsInParent()

_ = ([self.titleAndAmountStackView, self.continueButton], self.rootStackView)
|> ksr_addArrangedSubviewsToStackView()

_ = ([self.titleLabel, self.amountLabel], self.titleAndAmountStackView)
|> ksr_addArrangedSubviewsToStackView()
}

private func setupConstraints() {
NSLayoutConstraint.activate([
self.continueButton.heightAnchor.constraint(greaterThanOrEqualToConstant: Layout.Button.minHeight)
])
}

func configure(with data: ConfirmDetailsContinueCTAViewData) {
if let attributedAmount = attributedCurrency(withProject: data.project, total: data.total) {
self.amountLabel.attributedText = attributedAmount
}
}

private func attributedCurrency(withProject project: Project, total: Double) -> NSAttributedString? {
let defaultAttributes = checkoutCurrencyDefaultAttributes()
.withAllValuesFrom([.foregroundColor: UIColor.ksr_support_700])
let projectCurrencyCountry = projectCountry(forCurrency: project.stats.currency) ?? project.country
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we expect this fall-through to ever have to happen? I wonder if we should just change the type of project.currency to be a forced non-nil value, since it would be pretty odd if we didn't have that information from the server.


return Format.attributedCurrency(
total,
country: projectCurrencyCountry,
omitCurrencyCode: project.stats.omitUSCurrencyCode,
defaultAttributes: defaultAttributes,
superscriptAttributes: checkoutCurrencySuperscriptAttributes()
)
}

// MARK: - Accessors

@objc func continueButtonTapped() {
self.delegate?.continueButtonTapped()
}

// MARK: - Styles

private let titleLabelStyle: LabelStyle = { (label: UILabel) -> UILabel in
_ = label
|> checkoutTitleLabelStyle
|> \.text %~ { _ in Strings.Total_amount() }

return label
}

private let amountLabelStyle: LabelStyle = { (label: UILabel) in
_ = label
|> \.adjustsFontForContentSizeCategory .~ true
|> \.textAlignment .~ NSTextAlignment.right
|> \.isAccessibilityElement .~ true
|> \.minimumScaleFactor .~ 0.75

return label
}

private let titleAndAmountStackViewStyle: StackViewStyle = { (stackView: UIStackView) in
stackView
|> \.backgroundColor .~ .ksr_white
|> \.layoutMargins .~ UIEdgeInsets(leftRight: Styles.gridHalf(4))
}
}
12 changes: 12 additions & 0 deletions Kickstarter.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@
6051C6792B67F36800514202 /* CreatePaymentIntentInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6051C6782B67F36800514202 /* CreatePaymentIntentInput.swift */; };
6051C67C2B67F44500514202 /* CreatePaymentIntentInputTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6051C67A2B67F36C00514202 /* CreatePaymentIntentInputTests.swift */; };
6051C6832B683E6300514202 /* PaymentIntentEnvelope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6051C6822B683E6300514202 /* PaymentIntentEnvelope.swift */; };
606067112BA8717000023E9A /* ConfirmDetailsContinueCTAView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 606067102BA8717000023E9A /* ConfirmDetailsContinueCTAView.swift */; };
606754BD28CF91D60033CD5E /* FacebookCore in Frameworks */ = {isa = PBXBuildFile; productRef = 606754BC28CF91D60033CD5E /* FacebookCore */; };
606754BF28CF91DD0033CD5E /* FacebookLogin in Frameworks */ = {isa = PBXBuildFile; productRef = 606754BE28CF91DD0033CD5E /* FacebookLogin */; };
6067BCE9293E49AC0036ABB1 /* FacebookResetPasswordViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6067BCE7293E48140036ABB1 /* FacebookResetPasswordViewController.swift */; };
Expand Down Expand Up @@ -2080,6 +2081,7 @@
6051C6782B67F36800514202 /* CreatePaymentIntentInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatePaymentIntentInput.swift; sourceTree = "<group>"; };
6051C67A2B67F36C00514202 /* CreatePaymentIntentInputTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatePaymentIntentInputTests.swift; sourceTree = "<group>"; };
6051C6822B683E6300514202 /* PaymentIntentEnvelope.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentIntentEnvelope.swift; sourceTree = "<group>"; };
606067102BA8717000023E9A /* ConfirmDetailsContinueCTAView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmDetailsContinueCTAView.swift; sourceTree = "<group>"; };
6067BCE7293E48140036ABB1 /* FacebookResetPasswordViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FacebookResetPasswordViewController.swift; sourceTree = "<group>"; };
6067BCEA293E49CB0036ABB1 /* FacebookResetPasswordViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FacebookResetPasswordViewModel.swift; sourceTree = "<group>"; };
6067BCEF293FC10E0036ABB1 /* FacebookResetPasswordViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FacebookResetPasswordViewModelTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -5573,6 +5575,7 @@
isa = PBXGroup;
children = (
6021F6682B97BC7400F76031 /* Controllers */,
6060670F2BA8715F00023E9A /* Views */,
);
path = ConfirmDetails;
sourceTree = "<group>";
Expand Down Expand Up @@ -5629,6 +5632,14 @@
path = Colors;
sourceTree = "<group>";
};
6060670F2BA8715F00023E9A /* Views */ = {
isa = PBXGroup;
children = (
606067102BA8717000023E9A /* ConfirmDetailsContinueCTAView.swift */,
);
path = Views;
sourceTree = "<group>";
};
6067BCE5293E47D50036ABB1 /* FacebookResetPasswordViewController */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -8283,6 +8294,7 @@
60AE9F062ABB897900FB3A96 /* ReportProjectInfoListItem.swift in Sources */,
604453242BA08EEA00B8F485 /* PostCampaignPledgeRewardsSummaryViewController.swift in Sources */,
47F4CA63267A7B2300356DBF /* RemoteConfigFeatureFlagToolsViewController.swift in Sources */,
606067112BA8717000023E9A /* ConfirmDetailsContinueCTAView.swift in Sources */,
A7CA8BB71D8F14260086A3E9 /* ProjectPamphletMainCell.swift in Sources */,
A71003E31CDD077200B4F4D7 /* MessageCell.swift in Sources */,
01B3B0301E78890800B8BF46 /* BackerDashboardPagesDataSource.swift in Sources */,
Expand Down
4 changes: 4 additions & 0 deletions Library/ViewModels/ConfirmDetailsViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public protocol ConfirmDetailsViewModelInputs {
}

public protocol ConfirmDetailsViewModelOutputs {
var configureCTAWithPledgeTotal: Signal<(Project, Double), Never> { get }
var configureLocalPickupViewWithData: Signal<PledgeLocalPickupViewData, Never> { get }
var configurePledgeAmountViewWithData: Signal<PledgeAmountViewConfigData, Never> { get }
var configurePledgeRewardsSummaryViewWithData: Signal<
Expand Down Expand Up @@ -310,6 +311,8 @@ public class ConfirmDetailsViewModel: ConfirmDetailsViewModelType, ConfirmDetail
pledgeTotalSummaryData
)
}

self.configureCTAWithPledgeTotal = Signal.combineLatest(project, pledgeTotal)
}

// MARK: - Inputs
Expand Down Expand Up @@ -341,6 +344,7 @@ public class ConfirmDetailsViewModel: ConfirmDetailsViewModelType, ConfirmDetail

// MARK: - Outputs

public let configureCTAWithPledgeTotal: Signal<(Project, Double), Never>
public let configureLocalPickupViewWithData: Signal<PledgeLocalPickupViewData, Never>
public let configurePledgeAmountViewWithData: Signal<PledgeAmountViewConfigData, Never>
public let configurePledgeRewardsSummaryViewWithData: Signal<(
Expand Down