Skip to content
Closed
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
8 changes: 0 additions & 8 deletions Adyen.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -994,7 +994,6 @@
E9093401228C54CD00C9F04B /* LogoURLProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9093400228C54CD00C9F04B /* LogoURLProvider.swift */; };
E909342822969AFF00C9F04B /* PaymentComponentData.swift in Sources */ = {isa = PBXBuildFile; fileRef = E909342722969AFF00C9F04B /* PaymentComponentData.swift */; };
E90934A72297E7C800C9F04B /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E909346A2297E33B00C9F04B /* Localizable.strings */; };
E9240D6C2265EFE900FB57D0 /* StoredCardAlertManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9240D6B2265EFE900FB57D0 /* StoredCardAlertManager.swift */; };
E95E24C022C2593900973184 /* ApplePayPaymentMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = E95E24BF22C2593900973184 /* ApplePayPaymentMethod.swift */; };
E97B970C2297ED0D00505476 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E97B970A2297ED0D00505476 /* LaunchScreen.storyboard */; };
E97B970D22980C7900505476 /* AdyenCard.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E2C0E05F220982AE008616F6 /* AdyenCard.framework */; };
Expand Down Expand Up @@ -1332,7 +1331,6 @@
F9EDB78923955ABF00CFB3C9 /* AdyenUIHost.strings in Resources */ = {isa = PBXBuildFile; fileRef = F9EDB78823955ABF00CFB3C9 /* AdyenUIHost.strings */; };
F9EDB78B2395608D00CFB3C9 /* SEPADirectDebitComponentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9EDB78A2395608D00CFB3C9 /* SEPADirectDebitComponentTests.swift */; };
F9EDB78D2395643A00CFB3C9 /* CardComponentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9EDB78C2395643A00CFB3C9 /* CardComponentTests.swift */; };
F9EDB78F23964FC000CFB3C9 /* StoredCardAlertManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9EDB78E23964FC000CFB3C9 /* StoredCardAlertManagerTests.swift */; };
F9EDB794239663C200CFB3C9 /* PaymentMethodMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9EDB793239663C200CFB3C9 /* PaymentMethodMock.swift */; };
F9EDB796239663F800CFB3C9 /* PaymentComponentMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9EDB795239663F800CFB3C9 /* PaymentComponentMock.swift */; };
F9EDB7982396643A00CFB3C9 /* CardPaymentMethodMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9EDB7972396643A00CFB3C9 /* CardPaymentMethodMock.swift */; };
Expand Down Expand Up @@ -2678,7 +2676,6 @@
E90934762297E37800C9F04B /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = "<group>"; };
E90934772297E37B00C9F04B /* fr-FR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "fr-FR"; path = "fr-FR.lproj/Localizable.strings"; sourceTree = "<group>"; };
E90934792297E38000C9F04B /* sv-SE */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "sv-SE"; path = "sv-SE.lproj/Localizable.strings"; sourceTree = "<group>"; };
E9240D6B2265EFE900FB57D0 /* StoredCardAlertManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoredCardAlertManager.swift; sourceTree = "<group>"; };
E95E24BF22C2593900973184 /* ApplePayPaymentMethod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplePayPaymentMethod.swift; sourceTree = "<group>"; };
E97B970B2297ED0D00505476 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
E97B9719229D54D600505476 /* ActionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3021,7 +3018,6 @@
F9EDB78823955ABF00CFB3C9 /* AdyenUIHost.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = AdyenUIHost.strings; sourceTree = "<group>"; };
F9EDB78A2395608D00CFB3C9 /* SEPADirectDebitComponentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SEPADirectDebitComponentTests.swift; sourceTree = "<group>"; };
F9EDB78C2395643A00CFB3C9 /* CardComponentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardComponentTests.swift; sourceTree = "<group>"; };
F9EDB78E23964FC000CFB3C9 /* StoredCardAlertManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoredCardAlertManagerTests.swift; sourceTree = "<group>"; };
F9EDB793239663C200CFB3C9 /* PaymentMethodMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentMethodMock.swift; sourceTree = "<group>"; };
F9EDB795239663F800CFB3C9 /* PaymentComponentMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentComponentMock.swift; sourceTree = "<group>"; };
F9EDB7972396643A00CFB3C9 /* CardPaymentMethodMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardPaymentMethodMock.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -6029,7 +6025,6 @@
A0B4B9B02BC027DE00C99926 /* CardComponentEventTests.swift */,
B60FB35B2F33769500F77471 /* CardComponentValidationTests.swift */,
F924C071246BEEF0006DDAB8 /* CardDetailsTests.swift */,
F9EDB78E23964FC000CFB3C9 /* StoredCardAlertManagerTests.swift */,
F919DF9F24EABCC10027976E /* StoredCardComponentTests.swift */,
F9EDB799239664B500CFB3C9 /* StoredPaymentMethodComponentTests.swift */,
81D7EC8F2CD24143005159F6 /* FormViewControllerTests.swift */,
Expand Down Expand Up @@ -6286,7 +6281,6 @@
children = (
211BBD6D2F6C4F9A00EF2172 /* StoredCardInputView */,
F919DF9624E6E2810027976E /* StoredCardComponent.swift */,
E9240D6B2265EFE900FB57D0 /* StoredCardAlertManager.swift */,
E7451A102600EDE0000BDCCF /* StoredCardConfiguration.swift */,
);
path = "Stored Card";
Expand Down Expand Up @@ -8870,7 +8864,6 @@
A05D7212276A28EE0087F3E9 /* DocumentComponentTests.swift in Sources */,
F96AE5052603814C009F82BD /* BasicPersonalInfoFormComponentTests.swift in Sources */,
C9E6C5C72F02C5C50030E6C5 /* ComponentContainerViewModelTests.swift in Sources */,
F9EDB78F23964FC000CFB3C9 /* StoredCardAlertManagerTests.swift in Sources */,
E7F563EA28B7758D00082D4C /* DropInTestInternal.swift in Sources */,
F97BC2CE2668EB4500F1D242 /* VoucherViewDelegateMock.swift in Sources */,
F9AC61C2243751A70062A00D /* ActionComponentDelegateMock.swift in Sources */,
Expand Down Expand Up @@ -8997,7 +8990,6 @@
A0E1B63F2EA90BDF0070B915 /* CardComponentFactory.swift in Sources */,
E7166A5224EAC5BA007CCDEF /* BinLookupRequest.swift in Sources */,
E745175525FB6A59000BDCCF /* CardViewController.swift in Sources */,
E9240D6C2265EFE900FB57D0 /* StoredCardAlertManager.swift in Sources */,
A0F455A12968472B001742C7 /* PartialPaymentMethodDetails.swift in Sources */,
E7B627FD24ED32CC000CEC6E /* BinLookupService.swift in Sources */,
F9B8C49123FC286D00C4D0FB /* FormCardNumberItem.swift in Sources */,
Expand Down
1 change: 1 addition & 0 deletions Adyen/Assets/en-US.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"adyen.card.cvcItem.invalid" = "Invalid CVC / CVV format";
"adyen.card.cvcItem.title" = "Security code";
"adyen.card.cvcItem.placeholder" = "123";
"adyen.card.securityCode.title" = "Enter security code";
"adyen.card.securityCode.description" = "Enter the security code for %@ to complete the payment of %@";
"adyen.card.stored.title" = "Verify your card";
"adyen.card.stored.message" = "Please enter the CVC code for %@";
Expand Down
6 changes: 5 additions & 1 deletion AdyenCard/Components/Card/CardComponent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,11 @@ public class CardComponent: PresentableComponent,
}
// TODO: FIX StoredCard UI
if configuration.stored.showsSecurityCodeField {
let storedComponent = StoredCardComponent(storedCardPaymentMethod: paymentMethod, context: context)
let storedComponent = StoredCardComponent(
storedCardPaymentMethod: paymentMethod,
context: context,
theme: configuration.theme
)
storedComponent.localizationParameters = configuration.localizationParameters
return storedComponent
} else {
Expand Down
134 changes: 0 additions & 134 deletions AdyenCard/Components/Stored Card/StoredCardAlertManager.swift

This file was deleted.

86 changes: 50 additions & 36 deletions AdyenCard/Components/Stored Card/StoredCardComponent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,66 +7,80 @@
@_spi(AdyenInternal) import Adyen
import Foundation
import UIKit
#if canImport(AdyenUI)
@_spi(AdyenInternal) import AdyenUI
#endif

/// A component that provides a form for stored card payments.
@MainActor
package final class StoredCardComponent: StoredPaymentComponent, Localizable {

/// The context object for this component.
package let context: AdyenContext

/// The card payment method.
package var paymentMethod: PaymentMethod {
storedCardPaymentMethod
}

/// The delegate of the component.
package weak var delegate: PaymentComponentDelegate?

package var localizationParameters: LocalizationParameters?

private let storedCardPaymentMethod: StoredCardPaymentMethod

private let theme: CheckoutTheme

package init(
storedCardPaymentMethod: StoredCardPaymentMethod,
context: AdyenContext
context: AdyenContext,
theme: CheckoutTheme
) {
self.storedCardPaymentMethod = storedCardPaymentMethod
self.context = context
self.theme = theme
}

package var viewController: UIViewController {
storedCardAlertManager.alertController
}

internal lazy var storedCardAlertManager: StoredCardAlertManager = {
sendInitialAnalytics()
sendDidLoadEvent()

let manager = StoredCardAlertManager(
paymentMethod: storedCardPaymentMethod,
context: context,
amount: context.amount

package lazy var viewController: UIViewController = {
let viewModel = StoredCardInputViewModel(
theme: theme,
storedCardPaymentMethod: storedCardPaymentMethod,
apiContext: context.apiContext,
publicKey: context.publicKey,
amount: context.amount,
analyticsProvider: context.analyticsProvider,
localizationParameters: localizationParameters
)

manager.localizationParameters = localizationParameters
manager.completionHandler = { [weak self] result in
guard let self else { return }

switch result {
case let .success(details):
self.submit(data: PaymentComponentData(
paymentMethodDetails: details,
amount: self.context.amount,
order: self.order
))
case let .failure(error):
self.delegate?.didFail(with: error, from: self)
}

viewModel.cardDetailsCompletionHandler = { [weak self] in
self?.receivedCardDetailsResultToProcessPayment(result: $0)
}

return manager

viewModel.closeHandler = { [weak self] in
self?.viewController.dismiss(animated: true)
}

// TODO: Robert: This doesn't seem to a right place to trigger initialAnalytics(). As this is a lazy var. Maybe this could be moved elsewhere? - I don't know where as of yet.
self.sendInitialAnalytics()
Comment on lines +63 to +64
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Triggering sendInitialAnalytics() inside a lazy property initializer makes the analytics reporting dependent on when the viewController is first accessed. To ensure consistent tracking, consider moving this call to the initializer or a more deterministic lifecycle event.


let storedCardInputController = StoredCardInputViewController(viewModel: viewModel)

// TODO: Robert: StoredView: I assume here is the right place to wrap it in a navigation. As StoredCardComponent can be used separately by the merchant. If this is not, where else should this be?
return UINavigationController(rootViewController: storedCardInputController)
Comment on lines +68 to +69
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Wrapping the component's view controller in a UINavigationController can lead to nested navigation stacks when used within DropIn or other navigation-based containers. It is generally better to return the content view controller directly and let the consumer decide how to wrap or present it.

Suggested change
// TODO: Robert: StoredView: I assume here is the right place to wrap it in a navigation. As StoredCardComponent can be used separately by the merchant. If this is not, where else should this be?
return UINavigationController(rootViewController: storedCardInputController)
return storedCardInputController

}()

private func receivedCardDetailsResultToProcessPayment(result: Result<CardDetails, Error>) {
switch result {
case let .success(details):
submit(data: PaymentComponentData(
paymentMethodDetails: details,
amount: context.amount,
order: order
))
case let .failure(error):
delegate?.didFail(with: error, from: self)
}
}
}

/// :nodoc:
Expand Down
Loading
Loading