Skip to content

Commit

Permalink
Merge branch 'main' into networking-refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
scannillo committed Sep 6, 2023
2 parents 71c80fc + c55371b commit 9c2fc60
Show file tree
Hide file tree
Showing 42 changed files with 906 additions and 115 deletions.
10 changes: 8 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@

# PayPal iOS SDK Release Notes

## unreleased
## 0.0.11 (2023-08-22)
* PayPalNativePayments
* Bump `PayPalCheckout` to `1.1.0`
* CardPayments
* Add `vault` method
* Add `CardVaultRequest` and `CardVaultResult` types for interacting with `vault` method
* Add `CardVaultDelegate` protocol to receive success and failure results
* Add `CardVaultDelegate` property to `CardClient`

* Breaking Changes
* FraudProtection
* Update `PayPalDataCollector` constructor to require a configuration instead of an environment
* Remove `PayPalDataCollectorEnvironment` enum

## 0.0.10 (2023-08-14)
* PayPalNativePayments
* Bump `PayPalCheckout` to `1.0.0`
Expand Down
66 changes: 65 additions & 1 deletion Demo/Demo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,27 @@
objects = {

/* Begin PBXBuildFile section */
3B20273D2A89E3F00007907E /* CreateSetupTokenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B20273C2A89E3F00007907E /* CreateSetupTokenView.swift */; };
3B20273F2A89F24E0007907E /* CardVaultViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B20273E2A89F24E0007907E /* CardVaultViewModel.swift */; };
3B2027412A8A72050007907E /* CardVaultState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B2027402A8A72050007907E /* CardVaultState.swift */; };
3B2027432A8A95EF0007907E /* SetupTokenResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B2027422A8A95EF0007907E /* SetupTokenResultView.swift */; };
3B2027452A8AA78B0007907E /* UpdateSetupTokenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B2027442A8AA78B0007907E /* UpdateSetupTokenView.swift */; };
3B22E8BA2A842D8900962E34 /* PaymentTokenRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B22E8B92A842D8900962E34 /* PaymentTokenRequest.swift */; };
3B22E8BC2A84397600962E34 /* PaymentTokenResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B22E8BB2A84397600962E34 /* PaymentTokenResponse.swift */; };
3B4DD9A02A892A7000F4A716 /* CardVaultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B4DD99F2A892A7000F4A716 /* CardVaultView.swift */; };
3B4DD9A22A8982B000F4A716 /* CardFormView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B4DD9A12A8982B000F4A716 /* CardFormView.swift */; };
3B80D50E2A291C0800D2EAC4 /* ClientIDRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B80D50D2A291C0800D2EAC4 /* ClientIDRequest.swift */; };
3B80D5102A291CB100D2EAC4 /* ClientIDResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B80D50F2A291CB100D2EAC4 /* ClientIDResponse.swift */; };
3B8EF4DB2A932DA300A70D0B /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B8EF4DA2A932DA300A70D0B /* ErrorView.swift */; };
3BB7A9772A5CA6FD00C05140 /* MerchantIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BB7A9762A5CA6FD00C05140 /* MerchantIntegration.swift */; };
3BC622072A97115700251B85 /* RoundedBlueButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BC622062A97115700251B85 /* RoundedBlueButtonStyle.swift */; };
3BC622092A97198500251B85 /* LeadingText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BC622082A97198500251B85 /* LeadingText.swift */; };
3BC6220B2A97204E00251B85 /* CircularProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BC6220A2A97204E00251B85 /* CircularProgressView.swift */; };
3BDB348E2A7CB02C008100D7 /* SetupTokenRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BDB348D2A7CB02C008100D7 /* SetupTokenRequest.swift */; };
3BDB34922A7CB5DE008100D7 /* SetupTokenResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BDB34912A7CB5DE008100D7 /* SetupTokenResponse.swift */; };
3BF999762A8AC093009CBDF2 /* UpdateSetupTokenResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BF999752A8AC093009CBDF2 /* UpdateSetupTokenResultView.swift */; };
3BF999782A8AD072009CBDF2 /* CreatePaymentTokenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BF999772A8AD072009CBDF2 /* CreatePaymentTokenView.swift */; };
3BF9997A2A8AE12C009CBDF2 /* PaymentTokenResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BF999792A8AE12C009CBDF2 /* PaymentTokenResultView.swift */; };
5301468C28918B4D00184F22 /* ApprovalResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5301468B28918B4D00184F22 /* ApprovalResult.swift */; };
536A5CA82898AA2A005C053D /* SwiftUINativeCheckoutDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 536A5CA72898AA2A005C053D /* SwiftUINativeCheckoutDemo.swift */; };
53B9E8EA28C93B4400719239 /* OrderRequestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53B9E8E928C93B4400719239 /* OrderRequestHelpers.swift */; };
Expand Down Expand Up @@ -101,13 +115,27 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
3B20273C2A89E3F00007907E /* CreateSetupTokenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateSetupTokenView.swift; sourceTree = "<group>"; };
3B20273E2A89F24E0007907E /* CardVaultViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardVaultViewModel.swift; sourceTree = "<group>"; };
3B2027402A8A72050007907E /* CardVaultState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardVaultState.swift; sourceTree = "<group>"; };
3B2027422A8A95EF0007907E /* SetupTokenResultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupTokenResultView.swift; sourceTree = "<group>"; };
3B2027442A8AA78B0007907E /* UpdateSetupTokenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateSetupTokenView.swift; sourceTree = "<group>"; };
3B22E8B92A842D8900962E34 /* PaymentTokenRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentTokenRequest.swift; sourceTree = "<group>"; };
3B22E8BB2A84397600962E34 /* PaymentTokenResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentTokenResponse.swift; sourceTree = "<group>"; };
3B4DD99F2A892A7000F4A716 /* CardVaultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardVaultView.swift; sourceTree = "<group>"; };
3B4DD9A12A8982B000F4A716 /* CardFormView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardFormView.swift; sourceTree = "<group>"; };
3B80D50D2A291C0800D2EAC4 /* ClientIDRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientIDRequest.swift; sourceTree = "<group>"; };
3B80D50F2A291CB100D2EAC4 /* ClientIDResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientIDResponse.swift; sourceTree = "<group>"; };
3B8EF4DA2A932DA300A70D0B /* ErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorView.swift; sourceTree = "<group>"; };
3BB7A9762A5CA6FD00C05140 /* MerchantIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MerchantIntegration.swift; sourceTree = "<group>"; };
3BC622062A97115700251B85 /* RoundedBlueButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundedBlueButtonStyle.swift; sourceTree = "<group>"; };
3BC622082A97198500251B85 /* LeadingText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LeadingText.swift; sourceTree = "<group>"; };
3BC6220A2A97204E00251B85 /* CircularProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircularProgressView.swift; sourceTree = "<group>"; };
3BDB348D2A7CB02C008100D7 /* SetupTokenRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupTokenRequest.swift; sourceTree = "<group>"; };
3BDB34912A7CB5DE008100D7 /* SetupTokenResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupTokenResponse.swift; sourceTree = "<group>"; };
3BF999752A8AC093009CBDF2 /* UpdateSetupTokenResultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateSetupTokenResultView.swift; sourceTree = "<group>"; };
3BF999772A8AD072009CBDF2 /* CreatePaymentTokenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatePaymentTokenView.swift; sourceTree = "<group>"; };
3BF999792A8AE12C009CBDF2 /* PaymentTokenResultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentTokenResultView.swift; sourceTree = "<group>"; };
5301468B28918B4D00184F22 /* ApprovalResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApprovalResult.swift; sourceTree = "<group>"; };
536A5CA22898A48C005C053D /* PayPalNativeCheckout.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = PayPalNativeCheckout.framework; sourceTree = BUILT_PRODUCTS_DIR; };
536A5CA72898AA2A005C053D /* SwiftUINativeCheckoutDemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUINativeCheckoutDemo.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -190,6 +218,20 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
3B43290F2A8FD7FD00C5441A /* CardVaultViews */ = {
isa = PBXGroup;
children = (
3B4DD99F2A892A7000F4A716 /* CardVaultView.swift */,
3B20273C2A89E3F00007907E /* CreateSetupTokenView.swift */,
3B2027422A8A95EF0007907E /* SetupTokenResultView.swift */,
3B2027442A8AA78B0007907E /* UpdateSetupTokenView.swift */,
3BF999752A8AC093009CBDF2 /* UpdateSetupTokenResultView.swift */,
3BF999772A8AD072009CBDF2 /* CreatePaymentTokenView.swift */,
3BF999792A8AE12C009CBDF2 /* PaymentTokenResultView.swift */,
);
path = CardVaultViews;
sourceTree = "<group>";
};
53B9E8E828C93B2B00719239 /* Helpers */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -321,6 +363,8 @@
children = (
BE9F36E6275548A600AFC7DA /* BaseViewModel.swift */,
CB34B32228BE3A9A001325B9 /* PayPalViewModel.swift */,
3B20273E2A89F24E0007907E /* CardVaultViewModel.swift */,
3B2027402A8A72050007907E /* CardVaultState.swift */,
);
path = ViewModels;
sourceTree = "<group>";
Expand Down Expand Up @@ -348,12 +392,18 @@
BEDE3047275E998700D275FD /* SwiftUIComponents */ = {
isa = PBXGroup;
children = (
3B4DD9A12A8982B000F4A716 /* CardFormView.swift */,
3B8EF4DA2A932DA300A70D0B /* ErrorView.swift */,
3B43290F2A8FD7FD00C5441A /* CardVaultViews */,
BE9F36DB274578D100AFC7DA /* FeatureBaseViewControllerRepresentable.swift */,
BE9F36D72745490400AFC7DA /* FloatingLabelTextField.swift */,
BE31187D273F02A80021C5A2 /* SwiftUICardDemo.swift */,
BEDE304B275FA4A100D275FD /* SwiftUIPayPalDemo.swift */,
CB9ED44D28411B110081F4DE /* SwiftUIPaymentButtonDemo.swift */,
536A5CA72898AA2A005C053D /* SwiftUINativeCheckoutDemo.swift */,
3BC622062A97115700251B85 /* RoundedBlueButtonStyle.swift */,
3BC622082A97198500251B85 /* LeadingText.swift */,
3BC6220A2A97204E00251B85 /* CircularProgressView.swift */,
);
path = SwiftUIComponents;
sourceTree = "<group>";
Expand Down Expand Up @@ -486,16 +536,23 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
3B2027412A8A72050007907E /* CardVaultState.swift in Sources */,
BECD84A427036E02007CCAE4 /* DemoType.swift in Sources */,
80F33CED26F8E7A9006811B1 /* Order.swift in Sources */,
BE31187E273F02A80021C5A2 /* SwiftUICardDemo.swift in Sources */,
3B4DD9A02A892A7000F4A716 /* CardVaultView.swift in Sources */,
3BC622092A97198500251B85 /* LeadingText.swift in Sources */,
3B80D5102A291CB100D2EAC4 /* ClientIDResponse.swift in Sources */,
CB34B32328BE3A9A001325B9 /* PayPalViewModel.swift in Sources */,
3BC622072A97115700251B85 /* RoundedBlueButtonStyle.swift in Sources */,
3B4DD9A22A8982B000F4A716 /* CardFormView.swift in Sources */,
BED04233271084DF00C80954 /* CardFormatter.swift in Sources */,
CB9ED44E28411B120081F4DE /* SwiftUIPaymentButtonDemo.swift in Sources */,
3B22E8BC2A84397600962E34 /* PaymentTokenResponse.swift in Sources */,
80561B3E26FB72D80023138C /* FeatureBaseViewController.swift in Sources */,
BE9F36DC274578D100AFC7DA /* FeatureBaseViewControllerRepresentable.swift in Sources */,
3B2027432A8A95EF0007907E /* SetupTokenResultView.swift in Sources */,
3BF999762A8AC093009CBDF2 /* UpdateSetupTokenResultView.swift in Sources */,
BECD84A027036DC2007CCAE4 /* Environment.swift in Sources */,
806F1E3D26B85367007A60E6 /* ViewController.swift in Sources */,
80F33CF126F8E7D9006811B1 /* ProcessOrderParams.swift in Sources */,
Expand All @@ -512,17 +569,24 @@
BED041AF270CA0FB00C80954 /* CustomButton.swift in Sources */,
3BB7A9772A5CA6FD00C05140 /* MerchantIntegration.swift in Sources */,
BE1766B326F911A2007EF438 /* URLResponseError.swift in Sources */,
3B2027452A8AA78B0007907E /* UpdateSetupTokenView.swift in Sources */,
3B8EF4DB2A932DA300A70D0B /* ErrorView.swift in Sources */,
3BF9997A2A8AE12C009CBDF2 /* PaymentTokenResultView.swift in Sources */,
3BDB34922A7CB5DE008100D7 /* SetupTokenResponse.swift in Sources */,
CBC16DD929ED90B600307117 /* UpdateOrderParams.swift in Sources */,
BE9F36D82745490400AFC7DA /* FloatingLabelTextField.swift in Sources */,
BE9F36E7275548A600AFC7DA /* BaseViewModel.swift in Sources */,
806F1E3926B85367007A60E6 /* AppDelegate.swift in Sources */,
3B20273D2A89E3F00007907E /* CreateSetupTokenView.swift in Sources */,
3B22E8BA2A842D8900962E34 /* PaymentTokenRequest.swift in Sources */,
536A5CA82898AA2A005C053D /* SwiftUINativeCheckoutDemo.swift in Sources */,
806F1E3B26B85367007A60E6 /* SceneDelegate.swift in Sources */,
3B20273F2A89F24E0007907E /* CardVaultViewModel.swift in Sources */,
BC6460CD2A12A2A0002B974B /* EmptyBodyParams.swift in Sources */,
3BF999782A8AD072009CBDF2 /* CreatePaymentTokenView.swift in Sources */,
BED042312710833F00C80954 /* CardType.swift in Sources */,
5301468C28918B4D00184F22 /* ApprovalResult.swift in Sources */,
3BC6220B2A97204E00251B85 /* CircularProgressView.swift in Sources */,
BEDE304C275FA4A100D275FD /* SwiftUIPayPalDemo.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -795,7 +859,7 @@
repositoryURL = "https://github.com/paypal/paypalcheckout-ios";
requirement = {
kind = exactVersion;
version = 1.0.0;
version = 1.1.0;
};
};
BE1766D526FA7AC3007EF438 /* XCRemoteSwiftPackageReference "InAppSettingsKit" */ = {
Expand Down
3 changes: 3 additions & 0 deletions Demo/Demo/DemoSettings/DemoType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import SwiftUI

enum DemoType: String {
case card
case cardVault
case payPalWebCheckout
case paymentButtonCustomization
case payPalNativeCheckout
Expand All @@ -11,6 +12,8 @@ enum DemoType: String {
switch self {
case .card:
return AnyView(SwiftUICardDemo())
case .cardVault:
return AnyView(CardVaultView())
case .payPalWebCheckout:
return AnyView(SwiftUIPayPalDemo())
case .paymentButtonCustomization:
Expand Down
2 changes: 1 addition & 1 deletion Demo/Demo/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>CFBundleShortVersionString</key>
<string>0.0.10</string>
<string>0.0.11</string>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
Expand Down
4 changes: 2 additions & 2 deletions Demo/Demo/Models/PaymentTokenRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ struct PaymentTokenRequest {
var path: String {
"/payment_tokens/"
}

var method: String {
"POST"
}
Expand All @@ -25,7 +25,7 @@ struct PaymentTokenRequest {
]
]
]

return try? JSONSerialization.data(withJSONObject: requestBody)
}
}
8 changes: 4 additions & 4 deletions Demo/Demo/Models/PaymentTokenResponse.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

struct PaymentTokenResponse: Decodable {
struct PaymentTokenResponse: Decodable, Equatable {

let id: String
let customer: Customer
Expand All @@ -14,17 +14,17 @@ struct PaymentTokenResponse: Decodable {
}
}

struct Customer: Decodable {
struct Customer: Decodable, Equatable {

let id: String
}

struct PaymentSource: Decodable {
struct PaymentSource: Decodable, Equatable {

let card: BasicCard
}

struct BasicCard: Decodable {
struct BasicCard: Decodable, Equatable {

let brand: String?
let lastDigits: String
Expand Down
4 changes: 2 additions & 2 deletions Demo/Demo/Models/SetupTokenRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ struct SetUpTokenRequest {
var path: String {
"/setup_tokens/"
}

var method: String {
"POST"
}
Expand All @@ -29,7 +29,7 @@ struct SetUpTokenRequest {
]
]
]

return try? JSONSerialization.data(withJSONObject: requestBody)
}
}
12 changes: 11 additions & 1 deletion Demo/Demo/Models/SetupTokenResponse.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import Foundation

struct SetUpTokenResponse: Decodable {
struct SetUpTokenResponse: Decodable, Equatable {

static func == (lhs: SetUpTokenResponse, rhs: SetUpTokenResponse) -> Bool {
lhs.id == rhs.id
}

let id, status: String
let customer: Customer?

struct Customer: Decodable {

let id: String
}
}
7 changes: 5 additions & 2 deletions Demo/Demo/Networking/DemoMerchantAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ final class DemoMerchantAPI {

func getSetupToken(customerID: String? = nil, selectedMerchantIntegration: MerchantIntegration) async throws -> SetUpTokenResponse {
do {
// TODO: pass in headers depending on integration type
// Different request struct or integration type property
// in SetUpTokenRequest to conditionally add header
let request = SetUpTokenRequest(customerID: customerID)
let urlRequest = try createSetupTokenUrlRequest(
setupTokenRequest: request,
Expand All @@ -43,8 +46,8 @@ final class DemoMerchantAPI {
paymentTokenRequest: request,
environment: DemoSettings.environment,
selectedMerchantIntegration: selectedMerchantIntegration
)
let data = try await data(for: urlRequest)
)
let data = try await data(for: urlRequest)
return try parse(from: data)
} catch {
print("error with the create payment token request: \(error.localizedDescription)")
Expand Down
2 changes: 2 additions & 0 deletions Demo/Demo/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {

if launchArgs.contains("-DemoTypeCard") {
DemoSettings.demoType = .card
} else if launchArgs.contains("-DemoTypeCardVault") {
DemoSettings.demoType = .cardVault
} else if launchArgs.contains("-DemoTypePayPalWebCheckout") {
DemoSettings.demoType = .payPalWebCheckout
} else if launchArgs.contains("-DemoTypePaymentButtonCustomization") {
Expand Down
42 changes: 42 additions & 0 deletions Demo/Demo/SwiftUIComponents/CardFormView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import SwiftUI

struct CardFormView: View {

@Binding var cardNumberText: String
@Binding var expirationDateText: String
@Binding var cvvText: String

private let cardFormatter = CardFormatter()

var body: some View {
VStack(spacing: 16) {
FloatingLabelTextField(placeholder: "Card Number", text: $cardNumberText)
.onChange(of: cardNumberText) { newValue in
cardNumberText = cardFormatter.formatFieldWith(newValue, field: .cardNumber)
}
FloatingLabelTextField(placeholder: "Expiration Date", text: $expirationDateText)
.onChange(of: expirationDateText) { newValue in
expirationDateText = cardFormatter.formatFieldWith(newValue, field: .expirationDate)
}
FloatingLabelTextField(placeholder: "CVV", text: $cvvText)
.onChange(of: cvvText) { newValue in
cvvText = cardFormatter.formatFieldWith(newValue, field: .cvv)
}
}
}
}

struct CardFormView_Previews: PreviewProvider {

@State static var mockCardNumberText: String = "41111111111111111"
@State static var mockExpirationDateText: String = "01/25"
@State static var mockCvvText: String = "123"

static var previews: some View {
CardFormView(
cardNumberText: $mockCardNumberText,
expirationDateText: $mockExpirationDateText,
cvvText: $mockCvvText
)
}
}
Loading

0 comments on commit 9c2fc60

Please sign in to comment.