diff --git a/Demo/Demo.xcodeproj/project.pbxproj b/Demo/Demo.xcodeproj/project.pbxproj index 73a9be1e5..215f6a85a 100644 --- a/Demo/Demo.xcodeproj/project.pbxproj +++ b/Demo/Demo.xcodeproj/project.pbxproj @@ -16,9 +16,7 @@ 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 */; }; - 3B6472A32AFAE5E3004745C4 /* PayPalWebOrderCompletionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B6472A22AFAE5E3004745C4 /* PayPalWebOrderCompletionView.swift */; }; - 3B6472A52AFAEB1E004745C4 /* PayPalWebOrderCompletionResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B6472A42AFAEB1E004745C4 /* PayPalWebOrderCompletionResultView.swift */; }; - 3B6472A72AFAEB3A004745C4 /* PayPalOrderActionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B6472A62AFAEB3A004745C4 /* PayPalOrderActionButton.swift */; }; + 3B6472A72AFAEB3A004745C4 /* PayPalWebTransactionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B6472A62AFAEB3A004745C4 /* PayPalWebTransactionView.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 */; }; @@ -33,12 +31,9 @@ 3BA56FF82A9FDB5A0081D14F /* CardPaymentOrderCompletionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BA56FF72A9FDB5A0081D14F /* CardPaymentOrderCompletionView.swift */; }; 3BA56FFA2A9FE4180081D14F /* CardOrderCompletionResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BA56FF92A9FE4180081D14F /* CardOrderCompletionResultView.swift */; }; 3BA56FFC2A9FEFE90081D14F /* PayPalWebViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BA56FFB2A9FEFE90081D14F /* PayPalWebViewModel.swift */; }; - 3BA56FFE2A9FF4DA0081D14F /* PayPalWebState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BA56FFD2A9FF4DA0081D14F /* PayPalWebState.swift */; }; - 3BA570012AA052E80081D14F /* PayPalWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BA570002AA052E80081D14F /* PayPalWebView.swift */; }; - 3BA570032AA053AE0081D14F /* CreateOrderPayPalWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BA570022AA053AE0081D14F /* CreateOrderPayPalWebView.swift */; }; - 3BA570052AA0BBF10081D14F /* OrderCreatePayPalWebResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BA570042AA0BBF10081D14F /* OrderCreatePayPalWebResultView.swift */; }; - 3BA570072AA0DF330081D14F /* PayPalTransactionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BA570062AA0DF330081D14F /* PayPalTransactionView.swift */; }; - 3BA570092AA0E8340081D14F /* PayPalWebApprovalResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BA570082AA0E8340081D14F /* PayPalWebApprovalResultView.swift */; }; + 3BA570012AA052E80081D14F /* PayPalWebPaymentsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BA570002AA052E80081D14F /* PayPalWebPaymentsView.swift */; }; + 3BA570032AA053AE0081D14F /* PayPalWebCreateOrderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BA570022AA053AE0081D14F /* PayPalWebCreateOrderView.swift */; }; + 3BA570072AA0DF330081D14F /* PayPalWebButtonsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BA570062AA0DF330081D14F /* PayPalWebButtonsView.swift */; }; 3BA5700B2AA13C1C0081D14F /* CoreConfigManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BA5700A2AA13C1C0081D14F /* CoreConfigManager.swift */; }; 3BB7A9772A5CA6FD00C05140 /* MerchantIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BB7A9762A5CA6FD00C05140 /* MerchantIntegration.swift */; }; 3BC622072A97115700251B85 /* RoundedBlueButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BC622062A97115700251B85 /* RoundedBlueButtonStyle.swift */; }; @@ -71,6 +66,9 @@ BC9D4D2627C6D1720089E5B1 /* XCUIElement+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC9D4D2527C6D1720089E5B1 /* XCUIElement+Helpers.swift */; }; BE1766B326F911A2007EF438 /* URLResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE1766B226F911A2007EF438 /* URLResponseError.swift */; }; BE1766D926FA7BC8007EF438 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = BE1766D826FA7BC8007EF438 /* Settings.bundle */; }; + BE8117642B07E778009867B9 /* PayPalWebResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE8117632B07E778009867B9 /* PayPalWebResultView.swift */; }; + BE8117662B080202009867B9 /* PayPalWebStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE8117652B080202009867B9 /* PayPalWebStatusView.swift */; }; + BE8117682B080472009867B9 /* CurrentState.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE8117672B080472009867B9 /* CurrentState.swift */; }; BE9F36D82745490400AFC7DA /* FloatingLabelTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE9F36D72745490400AFC7DA /* FloatingLabelTextField.swift */; }; BECD84A027036DC2007CCAE4 /* Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = BECD849F27036DC2007CCAE4 /* Environment.swift */; }; BECD84A227036DDB007CCAE4 /* Intent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BECD84A127036DDB007CCAE4 /* Intent.swift */; }; @@ -137,9 +135,7 @@ 3B22E8BB2A84397600962E34 /* PaymentTokenResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentTokenResponse.swift; sourceTree = ""; }; 3B4DD99F2A892A7000F4A716 /* CardVaultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardVaultView.swift; sourceTree = ""; }; 3B4DD9A12A8982B000F4A716 /* CardFormView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardFormView.swift; sourceTree = ""; }; - 3B6472A22AFAE5E3004745C4 /* PayPalWebOrderCompletionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PayPalWebOrderCompletionView.swift; sourceTree = ""; }; - 3B6472A42AFAEB1E004745C4 /* PayPalWebOrderCompletionResultView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PayPalWebOrderCompletionResultView.swift; sourceTree = ""; }; - 3B6472A62AFAEB3A004745C4 /* PayPalOrderActionButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PayPalOrderActionButton.swift; sourceTree = ""; }; + 3B6472A62AFAEB3A004745C4 /* PayPalWebTransactionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PayPalWebTransactionView.swift; sourceTree = ""; }; 3B80D50D2A291C0800D2EAC4 /* ClientIDRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientIDRequest.swift; sourceTree = ""; }; 3B80D50F2A291CB100D2EAC4 /* ClientIDResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientIDResponse.swift; sourceTree = ""; }; 3B8EF4DA2A932DA300A70D0B /* ErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorView.swift; sourceTree = ""; }; @@ -154,12 +150,9 @@ 3BA56FF72A9FDB5A0081D14F /* CardPaymentOrderCompletionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardPaymentOrderCompletionView.swift; sourceTree = ""; }; 3BA56FF92A9FE4180081D14F /* CardOrderCompletionResultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardOrderCompletionResultView.swift; sourceTree = ""; }; 3BA56FFB2A9FEFE90081D14F /* PayPalWebViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayPalWebViewModel.swift; sourceTree = ""; }; - 3BA56FFD2A9FF4DA0081D14F /* PayPalWebState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayPalWebState.swift; sourceTree = ""; }; - 3BA570002AA052E80081D14F /* PayPalWebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayPalWebView.swift; sourceTree = ""; }; - 3BA570022AA053AE0081D14F /* CreateOrderPayPalWebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateOrderPayPalWebView.swift; sourceTree = ""; }; - 3BA570042AA0BBF10081D14F /* OrderCreatePayPalWebResultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderCreatePayPalWebResultView.swift; sourceTree = ""; }; - 3BA570062AA0DF330081D14F /* PayPalTransactionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayPalTransactionView.swift; sourceTree = ""; }; - 3BA570082AA0E8340081D14F /* PayPalWebApprovalResultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayPalWebApprovalResultView.swift; sourceTree = ""; }; + 3BA570002AA052E80081D14F /* PayPalWebPaymentsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayPalWebPaymentsView.swift; sourceTree = ""; }; + 3BA570022AA053AE0081D14F /* PayPalWebCreateOrderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayPalWebCreateOrderView.swift; sourceTree = ""; }; + 3BA570062AA0DF330081D14F /* PayPalWebButtonsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayPalWebButtonsView.swift; sourceTree = ""; }; 3BA5700A2AA13C1C0081D14F /* CoreConfigManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreConfigManager.swift; sourceTree = ""; }; 3BB7A9762A5CA6FD00C05140 /* MerchantIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MerchantIntegration.swift; sourceTree = ""; }; 3BC622062A97115700251B85 /* RoundedBlueButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundedBlueButtonStyle.swift; sourceTree = ""; }; @@ -199,6 +192,9 @@ BE1766B226F911A2007EF438 /* URLResponseError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLResponseError.swift; sourceTree = ""; }; BE1766D826FA7BC8007EF438 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = ""; }; BE420F3628189A7A00D8D66A /* PayPalUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = PayPalUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + BE8117632B07E778009867B9 /* PayPalWebResultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayPalWebResultView.swift; sourceTree = ""; }; + BE8117652B080202009867B9 /* PayPalWebStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayPalWebStatusView.swift; sourceTree = ""; }; + BE8117672B080472009867B9 /* CurrentState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentState.swift; sourceTree = ""; }; BE9F36D72745490400AFC7DA /* FloatingLabelTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingLabelTextField.swift; sourceTree = ""; }; BECD849F27036DC2007CCAE4 /* Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Environment.swift; sourceTree = ""; }; BECD84A127036DDB007CCAE4 /* Intent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Intent.swift; sourceTree = ""; }; @@ -273,19 +269,18 @@ path = CardPaymentViews; sourceTree = ""; }; - 3BA56FFF2A9FF6630081D14F /* PayPalWebViews */ = { + 3BA56FFF2A9FF6630081D14F /* PayPalWebPayments */ = { isa = PBXGroup; children = ( - 3B6472A62AFAEB3A004745C4 /* PayPalOrderActionButton.swift */, - 3B6472A42AFAEB1E004745C4 /* PayPalWebOrderCompletionResultView.swift */, - 3B6472A22AFAE5E3004745C4 /* PayPalWebOrderCompletionView.swift */, - 3BA570002AA052E80081D14F /* PayPalWebView.swift */, - 3BA570022AA053AE0081D14F /* CreateOrderPayPalWebView.swift */, - 3BA570042AA0BBF10081D14F /* OrderCreatePayPalWebResultView.swift */, - 3BA570062AA0DF330081D14F /* PayPalTransactionView.swift */, - 3BA570082AA0E8340081D14F /* PayPalWebApprovalResultView.swift */, - ); - path = PayPalWebViews; + 3BA570062AA0DF330081D14F /* PayPalWebButtonsView.swift */, + 3BA570022AA053AE0081D14F /* PayPalWebCreateOrderView.swift */, + 3BA570002AA052E80081D14F /* PayPalWebPaymentsView.swift */, + BE8117632B07E778009867B9 /* PayPalWebResultView.swift */, + BE8117652B080202009867B9 /* PayPalWebStatusView.swift */, + 3B6472A62AFAEB3A004745C4 /* PayPalWebTransactionView.swift */, + 3BA56FFB2A9FEFE90081D14F /* PayPalWebViewModel.swift */, + ); + path = PayPalWebPayments; sourceTree = ""; }; 3BCCFE472A9D962E00C5102F /* CommonComponents */ = { @@ -425,8 +420,6 @@ 3B2027402A8A72050007907E /* CardVaultState.swift */, 3BA56FE62A9DC9D70081D14F /* CardPaymentViewModel.swift */, 3BA56FE82A9DCA520081D14F /* CardPaymentState.swift */, - 3BA56FFB2A9FEFE90081D14F /* PayPalWebViewModel.swift */, - 3BA56FFD2A9FF4DA0081D14F /* PayPalWebState.swift */, ); path = ViewModels; sourceTree = ""; @@ -453,13 +446,14 @@ BEDE3047275E998700D275FD /* SwiftUIComponents */ = { isa = PBXGroup; children = ( - 3BA56FFF2A9FF6630081D14F /* PayPalWebViews */, + 3BA56FFF2A9FF6630081D14F /* PayPalWebPayments */, 3BA56FEA2A9DCBB30081D14F /* CardPaymentViews */, 3BCCFE472A9D962E00C5102F /* CommonComponents */, 3B43290F2A8FD7FD00C5441A /* CardVaultViews */, CB9ED44D28411B110081F4DE /* SwiftUIPaymentButtonDemo.swift */, 536A5CA72898AA2A005C053D /* SwiftUINativeCheckoutDemo.swift */, 3BCCFE4A2A9D985F00C5102F /* FeatureSelectionView.swift */, + BE8117672B080472009867B9 /* CurrentState.swift */, ); path = SwiftUIComponents; sourceTree = ""; @@ -591,9 +585,9 @@ files = ( 3BA56FE92A9DCA520081D14F /* CardPaymentState.swift in Sources */, 3B2027412A8A72050007907E /* CardVaultState.swift in Sources */, - 3BA570092AA0E8340081D14F /* PayPalWebApprovalResultView.swift in Sources */, 80F33CED26F8E7A9006811B1 /* Order.swift in Sources */, 3B4DD9A02A892A7000F4A716 /* CardVaultView.swift in Sources */, + BE8117642B07E778009867B9 /* PayPalWebResultView.swift in Sources */, 3BA56FF62A9E9AAB0081D14F /* CardOrderActionButton.swift in Sources */, 3BC622092A97198500251B85 /* LeadingText.swift in Sources */, 3B80D5102A291CB100D2EAC4 /* ClientIDResponse.swift in Sources */, @@ -603,11 +597,10 @@ 3B4DD9A22A8982B000F4A716 /* CardFormView.swift in Sources */, BED04233271084DF00C80954 /* CardFormatter.swift in Sources */, CB9ED44E28411B120081F4DE /* SwiftUIPaymentButtonDemo.swift in Sources */, - 3BA570032AA053AE0081D14F /* CreateOrderPayPalWebView.swift in Sources */, + 3BA570032AA053AE0081D14F /* PayPalWebCreateOrderView.swift in Sources */, 3B22E8BC2A84397600962E34 /* PaymentTokenResponse.swift in Sources */, 3B2027432A8A95EF0007907E /* SetupTokenResultView.swift in Sources */, 3BF999762A8AC093009CBDF2 /* UpdateSetupTokenResultView.swift in Sources */, - 3BA56FFE2A9FF4DA0081D14F /* PayPalWebState.swift in Sources */, BECD84A027036DC2007CCAE4 /* Environment.swift in Sources */, 80F33CF126F8E7D9006811B1 /* ProcessOrderParams.swift in Sources */, 53B9E8EA28C93B4400719239 /* OrderRequestHelpers.swift in Sources */, @@ -616,9 +609,11 @@ BED041B1270CB33900C80954 /* CustomTextField.swift in Sources */, 3B80D50E2A291C0800D2EAC4 /* ClientIDRequest.swift in Sources */, 3BA56FF02A9DCCFD0081D14F /* CardOrderApproveView.swift in Sources */, + BE8117682B080472009867B9 /* CurrentState.swift in Sources */, 3BDB348E2A7CB02C008100D7 /* SetupTokenRequest.swift in Sources */, 80F33CF326F8EA50006811B1 /* DemoSettings.swift in Sources */, 3BA56FE72A9DC9D70081D14F /* CardPaymentViewModel.swift in Sources */, + BE8117662B080202009867B9 /* PayPalWebStatusView.swift in Sources */, 3BA5700B2AA13C1C0081D14F /* CoreConfigManager.swift in Sources */, 80E4300C2AD82C8D003CA748 /* ShippingPreference.swift in Sources */, BEDE304A275EA33500D275FD /* UIViewController+Extension.swift in Sources */, @@ -632,21 +627,18 @@ 3B2027452A8AA78B0007907E /* UpdateSetupTokenView.swift in Sources */, 3BA56FF82A9FDB5A0081D14F /* CardPaymentOrderCompletionView.swift in Sources */, 3B8EF4DB2A932DA300A70D0B /* ErrorView.swift in Sources */, - 3B6472A32AFAE5E3004745C4 /* PayPalWebOrderCompletionView.swift in Sources */, 3BF9997A2A8AE12C009CBDF2 /* PaymentTokenResultView.swift in Sources */, 3BA56FFC2A9FEFE90081D14F /* PayPalWebViewModel.swift in Sources */, 3BDB34922A7CB5DE008100D7 /* SetupTokenResponse.swift in Sources */, 3BA56FF22A9DCD440081D14F /* CardApprovalResultView.swift in Sources */, - 3BA570012AA052E80081D14F /* PayPalWebView.swift in Sources */, + 3BA570012AA052E80081D14F /* PayPalWebPaymentsView.swift in Sources */, CBC16DD929ED90B600307117 /* UpdateOrderParams.swift in Sources */, 3BA56FFA2A9FE4180081D14F /* CardOrderCompletionResultView.swift in Sources */, 3BA56FF42A9DCD790081D14F /* CardPaymentView.swift in Sources */, BE9F36D82745490400AFC7DA /* FloatingLabelTextField.swift in Sources */, 3B20273D2A89E3F00007907E /* CreateSetupTokenView.swift in Sources */, - 3BA570052AA0BBF10081D14F /* OrderCreatePayPalWebResultView.swift in Sources */, 3B22E8BA2A842D8900962E34 /* PaymentTokenRequest.swift in Sources */, - 3B6472A52AFAEB1E004745C4 /* PayPalWebOrderCompletionResultView.swift in Sources */, - 3BA570072AA0DF330081D14F /* PayPalTransactionView.swift in Sources */, + 3BA570072AA0DF330081D14F /* PayPalWebButtonsView.swift in Sources */, 3BCCFE492A9D96CA00C5102F /* DemoApp.swift in Sources */, 3BA56FEC2A9DCBF30081D14F /* CreateOrderCardPaymentView.swift in Sources */, 536A5CA82898AA2A005C053D /* SwiftUINativeCheckoutDemo.swift in Sources */, @@ -654,7 +646,7 @@ BC6460CD2A12A2A0002B974B /* EmptyBodyParams.swift in Sources */, 3BF999782A8AD072009CBDF2 /* CreatePaymentTokenView.swift in Sources */, BED042312710833F00C80954 /* CardType.swift in Sources */, - 3B6472A72AFAEB3A004745C4 /* PayPalOrderActionButton.swift in Sources */, + 3B6472A72AFAEB3A004745C4 /* PayPalWebTransactionView.swift in Sources */, 5301468C28918B4D00184F22 /* ApprovalResult.swift in Sources */, 3BC6220B2A97204E00251B85 /* CircularProgressView.swift in Sources */, ); diff --git a/Demo/Demo/Models/Order.swift b/Demo/Demo/Models/Order.swift index e72afe99a..19c29d96e 100644 --- a/Demo/Demo/Models/Order.swift +++ b/Demo/Demo/Models/Order.swift @@ -2,7 +2,7 @@ struct Order: Codable, Equatable { let id: String let status: String - var paymentSource: PaymentSource? + let paymentSource: PaymentSource? struct PaymentSource: Codable, Equatable { diff --git a/Demo/Demo/Networking/DemoMerchantAPI.swift b/Demo/Demo/Networking/DemoMerchantAPI.swift index 7165d5d56..cc0a9eff9 100644 --- a/Demo/Demo/Networking/DemoMerchantAPI.swift +++ b/Demo/Demo/Networking/DemoMerchantAPI.swift @@ -53,7 +53,21 @@ final class DemoMerchantAPI { throw error } } - + + func completeOrder(intent: Intent, orderID: String) async throws -> Order { + let intent = intent == .authorize ? "authorize" : "capture" + guard let url = buildBaseURL( + with: "/orders/\(orderID)/\(intent)", + selectedMerchantIntegration: DemoSettings.merchantIntegration + ) else { + throw URLResponseError.invalidURL + } + + let urlRequest = buildURLRequest(method: "POST", url: url, body: EmptyBodyParams()) + let data = try await data(for: urlRequest) + return try parse(from: data) + } + func captureOrder(orderID: String, selectedMerchantIntegration: MerchantIntegration) async throws -> Order { guard let url = buildBaseURL(with: "/orders/\(orderID)/capture", selectedMerchantIntegration: selectedMerchantIntegration) else { throw URLResponseError.invalidURL diff --git a/Demo/Demo/SwiftUIComponents/CurrentState.swift b/Demo/Demo/SwiftUIComponents/CurrentState.swift new file mode 100644 index 000000000..818dc1651 --- /dev/null +++ b/Demo/Demo/SwiftUIComponents/CurrentState.swift @@ -0,0 +1,8 @@ +import Foundation + +enum CurrentState: Equatable { + case idle + case loading + case success + case error(message: String) +} diff --git a/Demo/Demo/SwiftUIComponents/FeatureSelectionView.swift b/Demo/Demo/SwiftUIComponents/FeatureSelectionView.swift index 9ee0771f4..76b28afc9 100644 --- a/Demo/Demo/SwiftUIComponents/FeatureSelectionView.swift +++ b/Demo/Demo/SwiftUIComponents/FeatureSelectionView.swift @@ -38,10 +38,10 @@ struct FeatureSelectionView: View { Text("Card Vaulting") } NavigationLink { - PayPalWebView() - .navigationTitle("PayPalWeb Payment") + PayPalWebPaymentsView() + .navigationTitle("PayPal Web") } label: { - Text("PayPalWeb Payment") + Text("PayPal Web") } NavigationLink { SwiftUINativeCheckoutDemo() diff --git a/Demo/Demo/SwiftUIComponents/PayPalWebViews/PayPalTransactionView.swift b/Demo/Demo/SwiftUIComponents/PayPalWebPayments/PayPalWebButtonsView.swift similarity index 53% rename from Demo/Demo/SwiftUIComponents/PayPalWebViews/PayPalTransactionView.swift rename to Demo/Demo/SwiftUIComponents/PayPalWebPayments/PayPalWebButtonsView.swift index 5bf0c212e..e213cb94e 100644 --- a/Demo/Demo/SwiftUIComponents/PayPalWebViews/PayPalTransactionView.swift +++ b/Demo/Demo/SwiftUIComponents/PayPalWebPayments/PayPalWebButtonsView.swift @@ -1,24 +1,23 @@ import SwiftUI import PaymentButtons -struct PayPalTransactionView: View { +struct PayPalWebButtonsView: View { - @ObservedObject var paypalWebViewModel: PayPalWebViewModel - let orderID: String + @ObservedObject var payPalWebViewModel: PayPalWebViewModel var body: some View { VStack { VStack(alignment: .center, spacing: 40) { PayPalButton.Representable(color: .blue, size: .mini) { - paypalWebViewModel.paymentButtonTapped(orderID: orderID, funding: .paypal) + payPalWebViewModel.paymentButtonTapped(funding: .paypal) } .frame(maxWidth: .infinity, maxHeight: 40) PayPalCreditButton.Representable(color: .black, edges: .softEdges, size: .expanded) { - paypalWebViewModel.paymentButtonTapped(orderID: orderID, funding: .paypalCredit) + payPalWebViewModel.paymentButtonTapped(funding: .paypalCredit) } .frame(maxWidth: .infinity, maxHeight: 40) PayPalPayLaterButton.Representable(color: .silver, edges: .rounded, size: .full) { - paypalWebViewModel.paymentButtonTapped(orderID: orderID, funding: .paylater) + payPalWebViewModel.paymentButtonTapped(funding: .paylater) } .frame(maxWidth: .infinity, maxHeight: 40) } @@ -29,15 +28,20 @@ struct PayPalTransactionView: View { .stroke(.gray, lineWidth: 2) .padding(5) ) - PayPalWebApprovalResultView(paypalWebViewModel: paypalWebViewModel) - if paypalWebViewModel.state.checkoutResult != nil { + + if payPalWebViewModel.checkoutResult != nil && payPalWebViewModel.state == .success { + PayPalWebResultView(payPalWebViewModel: payPalWebViewModel, status: .approved) NavigationLink { - PayPalWebOrderCompletionView(orderID: orderID, payPalWebViewModel: paypalWebViewModel) + PayPalWebTransactionView(payPalWebViewModel: payPalWebViewModel) + .navigationTitle("Complete Transaction") } label: { - Text("Complete Order Transaction") + Text("Complete Transaction") } + .navigationViewStyle(StackNavigationViewStyle()) .buttonStyle(RoundedBlueButtonStyle()) .padding() + } else if case .error = payPalWebViewModel.state { + PayPalWebResultView(payPalWebViewModel: payPalWebViewModel, status: .error) } Spacer() } diff --git a/Demo/Demo/SwiftUIComponents/PayPalWebViews/CreateOrderPayPalWebView.swift b/Demo/Demo/SwiftUIComponents/PayPalWebPayments/PayPalWebCreateOrderView.swift similarity index 66% rename from Demo/Demo/SwiftUIComponents/PayPalWebViews/CreateOrderPayPalWebView.swift rename to Demo/Demo/SwiftUIComponents/PayPalWebPayments/PayPalWebCreateOrderView.swift index fa52ea3e7..0af1754d6 100644 --- a/Demo/Demo/SwiftUIComponents/PayPalWebViews/CreateOrderPayPalWebView.swift +++ b/Demo/Demo/SwiftUIComponents/PayPalWebPayments/PayPalWebCreateOrderView.swift @@ -1,14 +1,12 @@ import SwiftUI -struct CreateOrderPayPalWebView: View { +struct PayPalWebCreateOrderView: View { - @ObservedObject var paypalWebViewModel: PayPalWebViewModel + @ObservedObject var payPalWebViewModel: PayPalWebViewModel @State private var selectedIntent: Intent = .authorize @State var shouldVaultSelected = false - let selectedMerchantIntegration: MerchantIntegration - var body: some View { VStack(spacing: 16) { HStack { @@ -31,20 +29,15 @@ struct CreateOrderPayPalWebView: View { Button("Create an Order") { Task { do { - paypalWebViewModel.state.intent = selectedIntent - try await paypalWebViewModel.createOrder( - amount: "10.00", - selectedMerchantIntegration: DemoSettings.merchantIntegration, - intent: selectedIntent.rawValue, - shouldVault: shouldVaultSelected - ) + payPalWebViewModel.intent = selectedIntent + try await payPalWebViewModel.createOrder(shouldVault: shouldVaultSelected) } catch { print("Error in getting setup token. \(error.localizedDescription)") } } } .buttonStyle(RoundedBlueButtonStyle()) - if case .loading = paypalWebViewModel.state.createdOrderResponse { + if payPalWebViewModel.state == .loading { CircularProgressView() } } diff --git a/Demo/Demo/SwiftUIComponents/PayPalWebPayments/PayPalWebPaymentsView.swift b/Demo/Demo/SwiftUIComponents/PayPalWebPayments/PayPalWebPaymentsView.swift new file mode 100644 index 000000000..88a03e406 --- /dev/null +++ b/Demo/Demo/SwiftUIComponents/PayPalWebPayments/PayPalWebPaymentsView.swift @@ -0,0 +1,27 @@ +import SwiftUI + +struct PayPalWebPaymentsView: View { + + @StateObject var payPalWebViewModel = PayPalWebViewModel() + + var body: some View { + ScrollView { + VStack(spacing: 16) { + PayPalWebCreateOrderView(payPalWebViewModel: payPalWebViewModel) + if payPalWebViewModel.createOrderResult != nil && payPalWebViewModel.state == .success { + PayPalWebResultView(payPalWebViewModel: payPalWebViewModel, status: .created) + NavigationLink { + PayPalWebButtonsView(payPalWebViewModel: payPalWebViewModel) + .navigationTitle("Checkout with PayPal") + } label: { + Text("Checkout with PayPal") + } + .buttonStyle(RoundedBlueButtonStyle()) + .padding() + } else if case .error = payPalWebViewModel.state { + PayPalWebResultView(payPalWebViewModel: payPalWebViewModel, status: .error) + } + } + } + } +} diff --git a/Demo/Demo/SwiftUIComponents/PayPalWebPayments/PayPalWebResultView.swift b/Demo/Demo/SwiftUIComponents/PayPalWebPayments/PayPalWebResultView.swift new file mode 100644 index 000000000..85cd823c0 --- /dev/null +++ b/Demo/Demo/SwiftUIComponents/PayPalWebPayments/PayPalWebResultView.swift @@ -0,0 +1,26 @@ +import SwiftUI + +enum OrderStatus { + case created + case approved + case completed + case error +} + +struct PayPalWebResultView: View { + + @ObservedObject var payPalWebViewModel: PayPalWebViewModel + + var status: OrderStatus + + var body: some View { + switch payPalWebViewModel.state { + case .idle, .loading: + EmptyView() + case .success: + PayPalWebStatusView(status: status, payPalWebViewModel: payPalWebViewModel) + case .error(let errorMessage): + ErrorView(errorMessage: errorMessage) + } + } +} diff --git a/Demo/Demo/SwiftUIComponents/PayPalWebPayments/PayPalWebStatusView.swift b/Demo/Demo/SwiftUIComponents/PayPalWebPayments/PayPalWebStatusView.swift new file mode 100644 index 000000000..2ec377e39 --- /dev/null +++ b/Demo/Demo/SwiftUIComponents/PayPalWebPayments/PayPalWebStatusView.swift @@ -0,0 +1,76 @@ +import SwiftUI + +struct PayPalWebStatusView: View { + + var status: OrderStatus + var payPalWebViewModel: PayPalWebViewModel + + var body: some View { + VStack(spacing: 16) { + switch status { + case .created: + HStack { + Text("Order Created") + .font(.system(size: 20)) + Spacer() + } + if let order = payPalWebViewModel.createOrderResult { + LeadingText("Order ID", weight: .bold) + LeadingText("\(order.id)") + LeadingText("Status", weight: .bold) + LeadingText("\(order.status)") + } + case .approved: + HStack { + Text("Order Approved") + .font(.system(size: 20)) + Spacer() + } + if let order = payPalWebViewModel.createOrderResult { + LeadingText("Intent", weight: .bold) + LeadingText("\(payPalWebViewModel.intent)") + LeadingText("Order ID", weight: .bold) + LeadingText("\(order.id)") + LeadingText("Payer ID", weight: .bold) + LeadingText("\(payPalWebViewModel.checkoutResult?.payerID ?? "")") + } + case .completed: + if let order = payPalWebViewModel.transactionResult { + HStack { + Text("Order \(payPalWebViewModel.intent.rawValue.capitalized)d") + .font(.system(size: 20)) + Spacer() + } + LeadingText("Order ID", weight: .bold) + LeadingText("\(order.id)") + LeadingText("Status", weight: .bold) + LeadingText("\(order.status)") + + if let emailAddress = order.paymentSource?.paypal?.emailAddress { + LeadingText("Email", weight: .bold) + LeadingText("\(emailAddress)") + } + + if let vaultID = order.paymentSource?.paypal?.attributes?.vault.id { + LeadingText("Vault ID / Payment Token", weight: .bold) + LeadingText("\(vaultID)") + } + + if let customerID = order.paymentSource?.paypal?.attributes?.vault.customer.id { + LeadingText("Customer ID", weight: .bold) + LeadingText("\(customerID)") + } + } + default: + Text("") + } + } + .frame(maxWidth: .infinity) + .padding() + .background( + RoundedRectangle(cornerRadius: 10) + .stroke(.gray, lineWidth: 2) + .padding(5) + ) + } +} diff --git a/Demo/Demo/SwiftUIComponents/PayPalWebPayments/PayPalWebTransactionView.swift b/Demo/Demo/SwiftUIComponents/PayPalWebPayments/PayPalWebTransactionView.swift new file mode 100644 index 000000000..88b075434 --- /dev/null +++ b/Demo/Demo/SwiftUIComponents/PayPalWebPayments/PayPalWebTransactionView.swift @@ -0,0 +1,46 @@ +import SwiftUI + +struct PayPalWebTransactionView: View { + + @ObservedObject var payPalWebViewModel: PayPalWebViewModel + + var body: some View { + ScrollView { + ScrollViewReader { scrollView in + VStack { + PayPalWebStatusView(status: .approved, payPalWebViewModel: payPalWebViewModel) + ZStack { + Button("\(payPalWebViewModel.intent.rawValue.capitalized) Order") { + Task { + do { + try await payPalWebViewModel.completeTransaction() + } catch { + print("Error capturing order: \(error.localizedDescription)") + } + } + } + .buttonStyle(RoundedBlueButtonStyle()) + .padding() + + if payPalWebViewModel.state == .loading { + CircularProgressView() + } + } + + if payPalWebViewModel.transactionResult != nil && payPalWebViewModel.state == .success { + PayPalWebResultView(payPalWebViewModel: payPalWebViewModel, status: .completed) + .id("bottomView") + } else if case .error = payPalWebViewModel.state { + PayPalWebResultView(payPalWebViewModel: payPalWebViewModel, status: .error) + } + } + .onChange(of: payPalWebViewModel.transactionResult) { _ in + withAnimation { + scrollView.scrollTo("bottomView") + } + } + Spacer() + } + } + } +} diff --git a/Demo/Demo/SwiftUIComponents/PayPalWebPayments/PayPalWebViewModel.swift b/Demo/Demo/SwiftUIComponents/PayPalWebPayments/PayPalWebViewModel.swift new file mode 100644 index 000000000..4b2f4b0be --- /dev/null +++ b/Demo/Demo/SwiftUIComponents/PayPalWebPayments/PayPalWebViewModel.swift @@ -0,0 +1,131 @@ +import Foundation +import CorePayments +import PayPalWebPayments + +class PayPalWebViewModel: ObservableObject, PayPalWebCheckoutDelegate { + + @Published var state: CurrentState = .idle + @Published var intent: Intent = .authorize + @Published var createOrderResult: Order? + @Published var transactionResult: Order? + @Published var checkoutResult: PayPalWebCheckoutResult? + + var payPalWebCheckoutClient: PayPalWebCheckoutClient? + var orderID: String? + + let configManager = CoreConfigManager(domain: "PayPalWeb Payments") + + func createOrder(shouldVault: Bool) async throws { + let amountRequest = Amount(currencyCode: "USD", value: "10.00") + + // TODO: might need to pass in payee as payee object or as auth header + var vaultPayPalPaymentSource: VaultPayPalPaymentSource? + if shouldVault { + let attributes = Attributes(vault: Vault(storeInVault: "ON_SUCCESS", usageType: "MERCHANT", customerType: "CONSUMER")) + // The returnURL is not used in our mobile SDK, but a required field for create order with PayPal payment source. DTPPCPSDK-1492 to track this issue + let paypal = VaultPayPal(attributes: attributes, experienceContext: ExperienceContext(returnURL: "https://example.com/returnUrl", cancelURL: "https://example.com/cancelUrl")) + vaultPayPalPaymentSource = VaultPayPalPaymentSource(paypal: paypal) + } + + var vaultPaymentSource: VaultPaymentSource? + if let vaultPayPalPaymentSource { + vaultPaymentSource = .paypal(vaultPayPalPaymentSource) + } + + let orderRequestParams = CreateOrderParams( + applicationContext: nil, + intent: intent.rawValue, + purchaseUnits: [PurchaseUnit(amount: amountRequest)], + paymentSource: vaultPaymentSource + ) + + do { + updateState(.loading) + let order = try await DemoMerchantAPI.sharedService.createOrder( + orderParams: orderRequestParams, + selectedMerchantIntegration: DemoSettings.merchantIntegration + ) + + self.orderID = order.id + + DispatchQueue.main.async { + self.createOrderResult = order + } + updateState(.success) + print("✅ fetched orderID: \(order.id) with status: \(order.status)") + } catch { + updateState(.error(message: error.localizedDescription)) + print("❌ failed to fetch orderID with error: \(error.localizedDescription)") + } + } + + func paymentButtonTapped(funding: PayPalWebCheckoutFundingSource) { + Task { + do { + payPalWebCheckoutClient = try await getPayPalClient() + payPalWebCheckoutClient?.delegate = self + guard let payPalWebCheckoutClient else { + print("Error initializing PayPalWebCheckoutClient") + return + } + + if let orderID { + let payPalRequest = PayPalWebCheckoutRequest(orderID: orderID, fundingSource: funding) + payPalWebCheckoutClient.start(request: payPalRequest) + } + } catch { + print("Error starting PayPalWebCheckoutClient") + state = .error(message: error.localizedDescription) + } + } + } + + func getPayPalClient() async throws -> PayPalWebCheckoutClient { + do { + let config = try await configManager.getCoreConfig() + let payPalClient = PayPalWebCheckoutClient(config: config) + return payPalClient + } + } + + func completeTransaction() async throws { + do { + updateState(.loading) + + if let orderID { + let order = try await DemoMerchantAPI.sharedService.completeOrder(intent: intent, orderID: orderID) + DispatchQueue.main.async { + self.transactionResult = order + } + updateState(.success) + } + } catch { + updateState(.error(message: error.localizedDescription)) + print("Error with \(intent) order: \(error.localizedDescription)") + } + } + + private func updateState(_ state: CurrentState) { + DispatchQueue.main.async { + self.state = state + } + } + + // MARK: - PayPalWeb Checkout Delegate + + func payPal( + _ payPalClient: PayPalWebCheckoutClient, + didFinishWithResult result: PayPalWebCheckoutResult + ) { + updateState(.success) + checkoutResult = result + } + + func payPal(_ payPalClient: PayPalWebCheckoutClient, didFinishWithError error: CoreSDKError) { + updateState(.error(message: error.localizedDescription)) + } + + func payPalDidCancel(_ payPalClient: PayPalWebCheckoutClient) { + print("PayPal Checkout Canceled") + } +} diff --git a/Demo/Demo/SwiftUIComponents/PayPalWebViews/OrderCreatePayPalWebResultView.swift b/Demo/Demo/SwiftUIComponents/PayPalWebViews/OrderCreatePayPalWebResultView.swift deleted file mode 100644 index 609f7b327..000000000 --- a/Demo/Demo/SwiftUIComponents/PayPalWebViews/OrderCreatePayPalWebResultView.swift +++ /dev/null @@ -1,38 +0,0 @@ -import SwiftUI - -struct OrderCreatePayPalWebResultView: View { - - @ObservedObject var paypalWebViewModel: PayPalWebViewModel - - var body: some View { - switch paypalWebViewModel.state.createdOrderResponse { - case .idle, .loading: - EmptyView() - case .loaded(let createOrderResponse): - getSuccessView(createOrderResponse: createOrderResponse) - case .error(let errorMessage): - ErrorView(errorMessage: errorMessage) - } - } - - func getSuccessView(createOrderResponse: Order) -> some View { - VStack(spacing: 16) { - HStack { - Text("Order") - .font(.system(size: 20)) - Spacer() - } - LeadingText("Order ID", weight: .bold) - LeadingText("\(createOrderResponse.id)") - LeadingText("Status", weight: .bold) - LeadingText("\(createOrderResponse.status)") - } - .frame(maxWidth: .infinity) - .padding() - .background( - RoundedRectangle(cornerRadius: 10) - .stroke(.gray, lineWidth: 2) - .padding(5) - ) - } -} diff --git a/Demo/Demo/SwiftUIComponents/PayPalWebViews/PayPalOrderActionButton.swift b/Demo/Demo/SwiftUIComponents/PayPalWebViews/PayPalOrderActionButton.swift deleted file mode 100644 index 8b27a7e83..000000000 --- a/Demo/Demo/SwiftUIComponents/PayPalWebViews/PayPalOrderActionButton.swift +++ /dev/null @@ -1,39 +0,0 @@ -import SwiftUI - -struct PayPalOrderActionButton: View { - - let intent: Intent - let orderID: String - let selectedMerchantIntegration: MerchantIntegration - - @ObservedObject var paypalWebViewModel: PayPalWebViewModel - - var body: some View { - ZStack { - Button("\(intent.rawValue)") { - completeOrder() - } - .buttonStyle(RoundedBlueButtonStyle()) - .padding() - - if .loading == paypalWebViewModel.state.authorizedOrderResponse || - .loading == paypalWebViewModel.state.capturedOrderResponse { - CircularProgressView() - } - } - } - - private func completeOrder() { - Task { - do { - try await paypalWebViewModel.completeOrder( - with: intent, - orderID: orderID, - selectedMerchantIntegration: selectedMerchantIntegration - ) - } catch { - print("Error capturing order: \(error.localizedDescription)") - } - } - } -} diff --git a/Demo/Demo/SwiftUIComponents/PayPalWebViews/PayPalWebApprovalResultView.swift b/Demo/Demo/SwiftUIComponents/PayPalWebViews/PayPalWebApprovalResultView.swift deleted file mode 100644 index 8f692dbbf..000000000 --- a/Demo/Demo/SwiftUIComponents/PayPalWebViews/PayPalWebApprovalResultView.swift +++ /dev/null @@ -1,40 +0,0 @@ -import SwiftUI - -struct PayPalWebApprovalResultView: View { - - @ObservedObject var paypalWebViewModel: PayPalWebViewModel - - var body: some View { - switch paypalWebViewModel.state.checkoutResultResponse { - case .idle, .loading: - EmptyView() - case .loaded(let checkoutResponse): - getCheckoutSuccessView(checkoutResult: checkoutResponse) - case .error(let errorMessage): - ErrorView(errorMessage: errorMessage) - } - } - - func getCheckoutSuccessView(checkoutResult: PayPalWebState.CheckoutResult) -> some View { - VStack(spacing: 16) { - HStack { - Text("Order Approved") - .font(.system(size: 20)) - Spacer() - } - LeadingText("Intent", weight: .bold) - LeadingText("\(paypalWebViewModel.state.intent)") - LeadingText("Order ID", weight: .bold) - LeadingText("\(checkoutResult.id)") - LeadingText("Payer ID", weight: .bold) - LeadingText("\(checkoutResult.payerID)") - } - .frame(maxWidth: .infinity) - .padding() - .background( - RoundedRectangle(cornerRadius: 10) - .stroke(.gray, lineWidth: 2) - .padding(5) - ) - } -} diff --git a/Demo/Demo/SwiftUIComponents/PayPalWebViews/PayPalWebOrderCompletionResultView.swift b/Demo/Demo/SwiftUIComponents/PayPalWebViews/PayPalWebOrderCompletionResultView.swift deleted file mode 100644 index 5a00ee8ef..000000000 --- a/Demo/Demo/SwiftUIComponents/PayPalWebViews/PayPalWebOrderCompletionResultView.swift +++ /dev/null @@ -1,61 +0,0 @@ -import SwiftUI - -struct PayPalWebOrderCompletionResultView: View { - - @ObservedObject var paypalWebViewModel: PayPalWebViewModel - - var body: some View { - switch paypalWebViewModel.state.authorizedOrderResponse { - case .idle, .loading: - EmptyView() - case .loaded(let authorizedOrderResponse): - getOrderSuccessView(orderResponse: authorizedOrderResponse, intent: "Authorized") - case .error(let errorMessage): - ErrorView(errorMessage: errorMessage) - } - - switch paypalWebViewModel.state.capturedOrderResponse { - case .idle, .loading: - EmptyView() - case .loaded(let capturedOrderResponse): - getOrderSuccessView(orderResponse: capturedOrderResponse, intent: "Captured") - case .error(let errorMessage): - ErrorView(errorMessage: errorMessage) - } - } - - func getOrderSuccessView(orderResponse: Order, intent: String) -> some View { - VStack(spacing: 16) { - HStack { - Text("Order \(intent)") - .font(.system(size: 20)) - Spacer() - } - LeadingText("Order ID", weight: .bold) - LeadingText("\(orderResponse.id)") - LeadingText("Status", weight: .bold) - LeadingText("\(orderResponse.status)") - if let email = orderResponse.paymentSource?.paypal?.emailAddress { - LeadingText("Email", weight: .bold) - LeadingText("\(email)") - } - if let vaultID = orderResponse.paymentSource?.paypal?.attributes?.vault.id { - LeadingText("Vault ID / Payment Token", weight: .bold) - LeadingText("\(vaultID)") - } - if let customerID = orderResponse.paymentSource?.paypal?.attributes?.vault.customer.id { - LeadingText("Customer ID", weight: .bold) - LeadingText("\(customerID)") - } - Text("") - .id("bottomView") - } - .frame(maxWidth: .infinity) - .padding() - .background( - RoundedRectangle(cornerRadius: 10) - .stroke(.gray, lineWidth: 2) - .padding(5) - ) - } -} diff --git a/Demo/Demo/SwiftUIComponents/PayPalWebViews/PayPalWebOrderCompletionView.swift b/Demo/Demo/SwiftUIComponents/PayPalWebViews/PayPalWebOrderCompletionView.swift deleted file mode 100644 index 609d8d856..000000000 --- a/Demo/Demo/SwiftUIComponents/PayPalWebViews/PayPalWebOrderCompletionView.swift +++ /dev/null @@ -1,38 +0,0 @@ -import SwiftUI - -struct PayPalWebOrderCompletionView: View { - - let orderID: String - @ObservedObject var payPalWebViewModel: PayPalWebViewModel - - var body: some View { - let state = payPalWebViewModel.state - ScrollView { - ScrollViewReader { scrollView in - VStack { - PayPalWebApprovalResultView(paypalWebViewModel: payPalWebViewModel) - if state.checkoutResult != nil { - PayPalOrderActionButton( - intent: state.intent, - orderID: orderID, - selectedMerchantIntegration: DemoSettings.merchantIntegration, - paypalWebViewModel: payPalWebViewModel - ) - } - - if state.authorizedOrder != nil || state.capturedOrder != nil { - PayPalWebOrderCompletionResultView(paypalWebViewModel: payPalWebViewModel) - } - Text("") - .id("bottomView") - Spacer() - } - .onChange(of: state) { _ in - withAnimation { - scrollView.scrollTo("bottomView") - } - } - } - } - } -} diff --git a/Demo/Demo/SwiftUIComponents/PayPalWebViews/PayPalWebView.swift b/Demo/Demo/SwiftUIComponents/PayPalWebViews/PayPalWebView.swift deleted file mode 100644 index c1ae6f2fa..000000000 --- a/Demo/Demo/SwiftUIComponents/PayPalWebViews/PayPalWebView.swift +++ /dev/null @@ -1,29 +0,0 @@ -import SwiftUI -import PaymentButtons - -struct PayPalWebView: View { - - @StateObject var paypalWebViewModel = PayPalWebViewModel() - - var body: some View { - ScrollView { - VStack(spacing: 16) { - CreateOrderPayPalWebView( - paypalWebViewModel: paypalWebViewModel, - selectedMerchantIntegration: DemoSettings.merchantIntegration - ) - if let order = paypalWebViewModel.state.createOrder { - OrderCreatePayPalWebResultView(paypalWebViewModel: paypalWebViewModel) - NavigationLink { - PayPalTransactionView(paypalWebViewModel: paypalWebViewModel, orderID: order.id) - .navigationTitle("PayPal Transactions") - } label: { - Text("PayPal Transactions") - } - .buttonStyle(RoundedBlueButtonStyle()) - .padding() - } - } - } - } -} diff --git a/Demo/Demo/ViewModels/PayPalWebState.swift b/Demo/Demo/ViewModels/PayPalWebState.swift deleted file mode 100644 index 04f94d0b6..000000000 --- a/Demo/Demo/ViewModels/PayPalWebState.swift +++ /dev/null @@ -1,49 +0,0 @@ -import Foundation -import PayPalWebPayments - -struct PayPalWebState: Equatable { - - struct CheckoutResult: Decodable, Equatable { - - let id: String - let payerID: String - } - - var createOrder: Order? - var intent: Intent = .authorize - var checkoutResult: CheckoutResult? - var authorizedOrder: Order? - var capturedOrder: Order? - - var createdOrderResponse: LoadingState = .idle { - didSet { - if case .loaded(let value) = createdOrderResponse { - createOrder = value - } - } - } - - var checkoutResultResponse: LoadingState = .idle { - didSet { - if case .loaded(let value) = checkoutResultResponse { - checkoutResult = value - } - } - } - - var capturedOrderResponse: LoadingState = .idle { - didSet { - if case .loaded(let value) = capturedOrderResponse { - capturedOrder = value - } - } - } - - var authorizedOrderResponse: LoadingState = .idle { - didSet { - if case .loaded(let value) = authorizedOrderResponse { - authorizedOrder = value - } - } - } -} diff --git a/Demo/Demo/ViewModels/PayPalWebViewModel.swift b/Demo/Demo/ViewModels/PayPalWebViewModel.swift deleted file mode 100644 index 87ce856c8..000000000 --- a/Demo/Demo/ViewModels/PayPalWebViewModel.swift +++ /dev/null @@ -1,172 +0,0 @@ -import Foundation -import CorePayments -import PayPalWebPayments - -class PayPalWebViewModel: ObservableObject, PayPalWebCheckoutDelegate { - - @Published var state = PayPalWebState() - - var payPalWebCheckoutClient: PayPalWebCheckoutClient? - - let configManager = CoreConfigManager(domain: "PayPalWeb Payments") - - func createOrder( - amount: String, - selectedMerchantIntegration: MerchantIntegration, - intent: String, - shouldVault: Bool - ) async throws { - // might need to pass in payee as payee object or as auth header - - let amountRequest = Amount(currencyCode: "USD", value: amount) - // TODO: might need to pass in payee as payee object or as auth header - - var vaultPayPalPaymentSource: VaultPayPalPaymentSource? - if shouldVault { - let attributes = Attributes(vault: Vault(storeInVault: "ON_SUCCESS", usageType: "MERCHANT", customerType: "CONSUMER")) - // The returnURL is not used in our mobile SDK, but a required field for create order with PayPal payment source. DTPPCPSDK-1492 to track this issue - let paypal = VaultPayPal(attributes: attributes, experienceContext: ExperienceContext(returnURL: "https://example.com/returnUrl", cancelURL: "https://example.com/cancelUrl")) - vaultPayPalPaymentSource = VaultPayPalPaymentSource(paypal: paypal) - } - - var vaultPaymentSource: VaultPaymentSource? - if let vaultPayPalPaymentSource { - vaultPaymentSource = .paypal(vaultPayPalPaymentSource) - } - - let orderRequestParams = CreateOrderParams( - applicationContext: nil, - intent: intent, - purchaseUnits: [PurchaseUnit(amount: amountRequest)], - paymentSource: vaultPaymentSource - ) - - do { - DispatchQueue.main.async { - self.state.createdOrderResponse = .loading - } - let order = try await DemoMerchantAPI.sharedService.createOrder( - orderParams: orderRequestParams, selectedMerchantIntegration: selectedMerchantIntegration - ) - DispatchQueue.main.async { - self.state.createdOrderResponse = .loaded(order) - print("✅ fetched orderID: \(order.id) with status: \(order.status)") - } - } catch { - DispatchQueue.main.async { - self.state.createdOrderResponse = .error(message: error.localizedDescription) - print("❌ failed to fetch orderID: \(error)") - } - } - } - - func paymentButtonTapped(orderID: String, funding: PayPalWebCheckoutFundingSource) { - checkoutWithPayPal(orderID: orderID, funding: funding) - } - - func checkoutWithPayPal(orderID: String, funding: PayPalWebCheckoutFundingSource) { - Task { - do { - payPalWebCheckoutClient = try await getPayPalClient() - payPalWebCheckoutClient?.delegate = self - guard let client = payPalWebCheckoutClient else { - print("Error in initializing paypal webcheckout client") - return - } - let payPalRequest = PayPalWebCheckoutRequest(orderID: orderID, fundingSource: funding) - client.start(request: payPalRequest) - } catch { - print("Error in starting paypal webcheckout client") - state.checkoutResultResponse = .error(message: error.localizedDescription) - } - } - } - - func getPayPalClient() async throws -> PayPalWebCheckoutClient { - do { - let config = try await configManager.getCoreConfig() - let payPalClient = PayPalWebCheckoutClient(config: config) - return payPalClient - } - } - - func paypalWebCheckoutSuccessResult(checkoutResult: PayPalWebState.CheckoutResult) { - DispatchQueue.main.async { - self.state.checkoutResultResponse = .loaded(checkoutResult) - } - } - - func paypalWebCheckoutFailureResult(checkoutError: CorePayments.CoreSDKError) { - DispatchQueue.main.async { - self.state.checkoutResultResponse = .error(message: checkoutError.localizedDescription) - } - } - - func completeOrder(with intent: Intent, orderID: String, selectedMerchantIntegration: MerchantIntegration) async throws { - switch intent { - case .capture: - try await captureOrder(orderID: orderID, selectedMerchantIntegration: selectedMerchantIntegration) - print("Order Captured. ID: \(state.capturedOrder?.id ?? "")") - case .authorize: - try await authorizeOrder(orderID: orderID, selectedMerchantIntegration: selectedMerchantIntegration) - print("Order Authorized. ID: \(state.authorizedOrder?.id ?? "")") - } - } - - func captureOrder(orderID: String, selectedMerchantIntegration: MerchantIntegration) async throws { - do { - DispatchQueue.main.async { - self.state.capturedOrderResponse = .loading - } - let order = try await DemoMerchantAPI.sharedService.captureOrder( - orderID: orderID, - selectedMerchantIntegration: selectedMerchantIntegration - ) - DispatchQueue.main.async { - self.state.capturedOrderResponse = .loaded(order) - } - } catch { - DispatchQueue.main.async { - self.state.capturedOrderResponse = .error(message: error.localizedDescription) - } - print("Error capturing order: \(error.localizedDescription)") - } - } - - func authorizeOrder(orderID: String, selectedMerchantIntegration: MerchantIntegration) async throws { - do { - DispatchQueue.main.async { - self.state.authorizedOrderResponse = .loading - } - let order = try await DemoMerchantAPI.sharedService.authorizeOrder( - orderID: orderID, - selectedMerchantIntegration: selectedMerchantIntegration - ) - DispatchQueue.main.async { - self.state.authorizedOrderResponse = .loaded(order) - } - } catch { - DispatchQueue.main.async { - self.state.authorizedOrderResponse = .error(message: error.localizedDescription) - } - print("Error authorizing order: \(error.localizedDescription)") - } - } - - // MARK: - PayPalWeb Checkout Delegate - - func payPal( - _ payPalClient: PayPalWebPayments.PayPalWebCheckoutClient, - didFinishWithResult result: PayPalWebPayments.PayPalWebCheckoutResult - ) { - paypalWebCheckoutSuccessResult(checkoutResult: PayPalWebState.CheckoutResult(id: result.orderID, payerID: result.payerID)) - } - - func payPal(_ payPalClient: PayPalWebPayments.PayPalWebCheckoutClient, didFinishWithError error: CorePayments.CoreSDKError) { - paypalWebCheckoutFailureResult(checkoutError: error) - } - - func payPalDidCancel(_ payPalClient: PayPalWebPayments.PayPalWebCheckoutClient) { - print("PayPal Checkout Canceled") - } -} diff --git a/Sources/PayPalWebPayments/PayPalWebCheckoutFundingSource.swift b/Sources/PayPalWebPayments/PayPalWebCheckoutFundingSource.swift index 3f0edf218..b64f53e28 100644 --- a/Sources/PayPalWebPayments/PayPalWebCheckoutFundingSource.swift +++ b/Sources/PayPalWebPayments/PayPalWebCheckoutFundingSource.swift @@ -6,6 +6,7 @@ public enum PayPalWebCheckoutFundingSource: String { /// Eligible costumers receive a revolving line of credit that they can use to pay over time. case paypalCredit = "credit" + // NEXT_MAJOR_VERSION: rename to `payLater` /// PayLater will launch the web checkout flow and display Pay Later offers to eligible customers, /// which include short-term, interest-free payments and other special financing options case paylater = "paylater"