Skip to content

Commit

Permalink
FC Networking: implemented broken account support.
Browse files Browse the repository at this point in the history
  • Loading branch information
kgaidis-stripe committed May 17, 2023
1 parent 077a9e6 commit 8146f51
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ struct FinancialConnectionsPartnerAccount: Decodable {
return nil
}
}
var isBroken: Bool {
return (status != "active")
}
}

struct FinancialConnectionsAuthSessionAccounts: Decodable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ struct FinancialConnectionsSessionManifest: Decodable {
case accountPicker = "account_picker"
case attachLinkedPaymentAccount = "attach_linked_payment_account"
case authOptions = "auth_options"
case bankAuthRepair = "bank_auth_repair"
case consent = "consent"
case institutionPicker = "institution_picker"
case linkAccountPicker = "link_account_picker"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ extension FinancialConnectionsAnalyticsClient {
_ viewController: UIViewController?
) -> FinancialConnectionsSessionManifest.NextPane {
switch viewController {
// TODO(kgaidis): add bank repair
case is ConsentViewController:
return .consent
case is InstitutionPickerViewController:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,10 @@ final class LinkAccountPickerBodyView: UIView {

// list all accounts
accounts.forEach { account in
let isDisabled = (account.status != "active")
let isAccountBroken = account.isBroken
let accountRowView = LinkAccountPickerRowView(
isDisabled: isDisabled,
isDisabled: false,
isBroken: isAccountBroken,
didSelect: { [weak self] in
guard let self = self else { return }
self.delegate?.linkAccountPickerBodyView(
Expand All @@ -61,13 +62,12 @@ final class LinkAccountPickerBodyView: UIView {
)
}
)
// TODO(kgaidis): when we implement repair logic, this will have new text
let rowTitles = AccountPickerHelpers.rowTitles(forAccount: account)
accountRowView.configure(
institutionImageUrl: account.institution?.icon?.default,
leadingTitle: rowTitles.leadingTitle,
trailingTitle: rowTitles.trailingTitle,
subtitle: isDisabled ? STPLocalizedString("Disconnected", "A subtitle on a button that represents a bank account. It explains to the user that this bank account is disconnected and needs to be re-added.") : AccountPickerHelpers.rowSubtitle(forAccount: account),
subtitle: isAccountBroken ? STPLocalizedString("Select to repair and connect", "A subtitle on a button that represents a bank account. It explains to the user that this bank account is disconnected from the bank and needs to be re-connected by going through the bank process.") : AccountPickerHelpers.rowSubtitle(forAccount: account),
isSelected: selectedAccount?.id == account.id
)
verticalStackView.addArrangedSubview(accountRowView)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,6 @@ final class LinkAccountPickerFooterView: UIView {

private lazy var connectAccountButton: Button = {
let connectAccountButton = Button(configuration: .financialConnectionsPrimary)
connectAccountButton.title = STPLocalizedString(
"Connect account",
"A button that allows users to confirm the process of saving their bank accounts for future payments. This button appears in a screen that allows users to select which bank accounts they want to use to pay for something."
)
connectAccountButton.isEnabled = false // disable by default
connectAccountButton.addTarget(self, action: #selector(didSelectLinkAccountsButton), for: .touchUpInside)
connectAccountButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
Expand Down Expand Up @@ -60,6 +55,9 @@ final class LinkAccountPickerFooterView: UIView {
verticalStackView.axis = .vertical
verticalStackView.spacing = 24
addAndPinSubview(verticalStackView)

// setup the button
userSelectedAccount(nil)
}

required init?(coder: NSCoder) {
Expand All @@ -70,7 +68,19 @@ final class LinkAccountPickerFooterView: UIView {
didSelectConnectAccount()
}

func enableButton(_ enableButton: Bool) {
connectAccountButton.isEnabled = enableButton
func userSelectedAccount(_ selectedAccount: FinancialConnectionsPartnerAccount?) {
connectAccountButton.isEnabled = (selectedAccount != nil)

if let selectedAccount = selectedAccount, selectedAccount.isBroken {
connectAccountButton.title = STPLocalizedString(
"Repair and connect account",
"A button that initiates the process of repairing and connecting a users bank account. A bank account that needs to be repaired is one that lost connection to the users bank. This button appears in a screen that allows users to select which bank accounts they want to use to pay for something."
)
} else {
connectAccountButton.title = STPLocalizedString(
"Connect account",
"A button that allows users to confirm the process of saving their bank accounts for future payments. This button appears in a screen that allows users to select which bank accounts they want to use to pay for something."
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ final class LinkAccountPickerRowView: UIView {

init(
isDisabled: Bool,
isBroken: Bool,
didSelect: @escaping () -> Void
) {
self.didSelect = didSelect
Expand All @@ -49,6 +50,17 @@ final class LinkAccountPickerRowView: UIView {
if isDisabled {
horizontalStackView.alpha = 0.25
}
if isBroken {
let warningIconImageView = UIImageView()
warningIconImageView.image = Image.warning_triangle.makeImage()
.withTintColor(.textCritical)
warningIconImageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
warningIconImageView.widthAnchor.constraint(equalToConstant: 15),
warningIconImageView.heightAnchor.constraint(equalToConstant: 15),
])
horizontalStackView.addArrangedSubview(warningIconImageView)
}
addAndPinSubviewToSafeArea(horizontalStackView)

if !isDisabled {
Expand Down Expand Up @@ -118,10 +130,12 @@ private struct LinkAccountPickerRowViewUIViewRepresentable: UIViewRepresentable
let subtitle: String?
let isSelected: Bool
let isDisabled: Bool
let isBroken: Bool

func makeUIView(context: Context) -> LinkAccountPickerRowView {
let view = LinkAccountPickerRowView(
isDisabled: isDisabled,
isBroken: isBroken,
didSelect: {}
)
view.configure(
Expand Down Expand Up @@ -159,23 +173,26 @@ struct LinkAccountPickerRowView_Previews: PreviewProvider {
trailingTitle: "••••6789",
subtitle: "$2,000",
isSelected: true,
isDisabled: false
isDisabled: false,
isBroken: false
).frame(height: 60)
LinkAccountPickerRowViewUIViewRepresentable(
institutionImageUrl: nil,
leadingTitle: "Joint Checking",
trailingTitle: nil,
subtitle: nil,
isSelected: false,
isDisabled: false
isDisabled: false,
isBroken: false
).frame(height: 60)
LinkAccountPickerRowViewUIViewRepresentable(
institutionImageUrl: nil,
leadingTitle: "Joint Checking",
trailingTitle: nil,
subtitle: "Must be US checking account",
isSelected: false,
isDisabled: true
isDisabled: false,
isBroken: true
).frame(height: 60)
}
}.padding()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,21 @@ final class LinkAccountPickerViewController: UIViewController {

switch result {
case .success(let networkedAccountsResponse):
self.displayAccounts(networkedAccountsResponse.data)
self.displayAccounts(networkedAccountsResponse.data.map {
FinancialConnectionsPartnerAccount(
id: $0.id,
name: $0.name,
displayableAccountNumbers: $0.displayableAccountNumbers,
linkedAccountId: $0.linkedAccountId,
balanceAmount: $0.balanceAmount,
currency: $0.currency,
supportedPaymentMethodTypes: $0.supportedPaymentMethodTypes,
allowSelection: $0.allowSelection,
allowSelectionMessage: $0.allowSelectionMessage,
status: Bool.random() ? "inactive" : $0.status,
institution: $0.institution
)
})
case .failure(let error):
self.dataSource
.analyticsClient
Expand Down Expand Up @@ -139,15 +153,22 @@ final class LinkAccountPickerViewController: UIViewController {
}

private func didSelectConectAccount() {
// TODO(kgaidis): implement repair bank account

guard let selectedAccount = dataSource.selectedAccount else {
assertionFailure("user shouldn't be able to press the connect account button without an account")
delegate?.linkAccountPickerViewController(self, didRequestNextPane: .institutionPicker)
return
}

if dataSource.manifest.stepUpAuthenticationRequired == true {
if selectedAccount.isBroken {
// TODO(kgaidis): handle partnerToCoreAuths and setPartnerToCoreAuths
dataSource
.analyticsClient
.log(
eventName: "click.repair_accounts",
pane: .linkAccountPicker
)
delegate?.linkAccountPickerViewController(self, didRequestNextPane: .bankAuthRepair)
} else if dataSource.manifest.stepUpAuthenticationRequired == true {
delegate?.linkAccountPickerViewController(self, requestedStepUpVerificationWithSelectedAccount: selectedAccount)
} else {
let linkingAccountsLoadingView = LinkingAccountsLoadingView(
Expand Down Expand Up @@ -235,6 +256,6 @@ extension LinkAccountPickerViewController: LinkAccountPickerDataSourceDelegate {
didSelectAccount selectedAccount: FinancialConnectionsPartnerAccount?
) {
bodyView?.selectAccount(selectedAccount)
footerView.enableButton(selectedAccount != nil)
footerView.userSelectedAccount(selectedAccount)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -820,6 +820,8 @@ private func CreatePaneViewController(
assertionFailure("Code logic error. Missing parameters for \(pane).")
viewController = nil
}
case .bankAuthRepair:
viewController = nil // TODO(kgaidis): implement
case .consent:
let consentDataSource = ConsentDataSourceImplementation(
manifest: dataManager.manifest,
Expand Down

0 comments on commit 8146f51

Please sign in to comment.