From 5f87126b50a694fa2194fb735530da6b0a3783e3 Mon Sep 17 00:00:00 2001 From: Zeno Foltin Date: Fri, 5 Aug 2022 23:21:49 +0100 Subject: [PATCH] CT-2086 Add Billing Details screen (#148) * fixed unit test * Add billing address related viewModels to JPTransactionViewModel * Billing details input fields added * added validators * Fix tests; Rename invalid JPCardDetailsMode enum values * clang format * Remove unused files (mostly outdated/duplicate test files); Add missing public header - JPNetworkTimeout; Reorganise the project file a bit * Bugfixes and other improvements * Fix unit test imports and a test * Attempt to make Sonar happy * More Sonar fixes * Add JPCardTransactionDetails+Additions.h to SPM * Add missing headers for SPM * Fixes * Remove duplicate NetworkTimeout after merge; rename JPDictionaryConvertible.toDictionary to _jp_toDictionary * Updates 3DS package version * Fixes * Fixes * Package version bump * Fixes unit-tests * Making Sonar happy * Make Sonar happy Co-authored-by: Andrei Movila Co-authored-by: Stefan --- .../project.pbxproj | 8 +- .../NoUICardPay/NoUICardPayViewController.m | 1 - .../IASKAppSettingsViewController+Additions.m | 2 - .../ObjectiveCExampleApp/Models/Settings.h | 1 - .../ObjectiveCExampleApp/Models/Settings.m | 16 +- .../Settings.bundle/Root.plist | 12 +- .../Models/ResultTests.m | 11 +- .../Handlers/After/JPAfterHandlers.m | 6 +- .../ObjectiveCExampleAppUITests.m | 2 +- Examples/ObjectiveCExampleApp/Podfile | 8 +- Examples/ObjectiveCExampleApp/Podfile.lock | 19 +- JudoKit-iOS.podspec | 7 +- JudoKit_iOS.xcodeproj/project.pbxproj | 186 ++- .../JudoKit_iOSTests-Bridging-Header.h | 3 +- .../Models/JPAddress/JPAddressTests.swift | 2 - .../JPClientDetails/JPClientDetailsTest.swift | 2 +- .../JPConsumerDeviceTest.swift | 2 +- .../Models/JPCountry/JPCountryTest.swift | 4 +- .../JPEnhancedPaymentDetailTest.swift | 2 +- .../Requests/JPPaymentRequestTests.swift | 2 - .../Modules/CardStorage/CardStorageTest.swift | 53 - .../PaymentMethods/JPPaymentMethodsTest.swift | 1 + .../Mocks/JPApiServicePBBAStub.swift | 9 - .../JPPaymentMethodsInteractorMock.swift | 3 +- .../JPCardValidationServiceTest.swift | 171 -- ...leConfigurationValidationServiceTest.swift | 96 -- ...JPConfigurationValidationServiceTest.swift | 67 - .../JPPaymentMethodsInteractorTest.swift | 55 - .../JPCanadaPostCodeValidation.swift | 70 - .../JPUKPostCodeValidation.swift | 82 - .../JPUSAPostCodeValidation.swift | 82 - .../JPTransactionServiceTest.swift | 108 -- .../JPTransactionInteractorTest.swift | 108 +- .../Mocks/JPTransactionInteractorMock.swift | 59 +- .../Mocks/JPTransactionViewMock.swift | 7 +- .../JPTransactionPresenterTests.swift | 20 +- .../JPCanadaPostCodeValidation.swift | 14 +- .../JPUKPostCodeValidation.swift | 20 +- .../JPUSAPostCodeValidation.swift | 20 +- Resources/CountriesList.json | 1463 +++++++++++++++++ Resources/en.lproj/Localizable.strings | 11 + Resources/es.lproj/Localizable.strings | 11 + Resources/fr.lproj/Localizable.strings | 11 + .../JPCardTransactionDetails+Additions.m | 5 + .../JPRequest/JPRequest+Additions.m | 1 + .../Extensions/NSBundle/NSBundle+Additions.m | 30 +- .../Extensions/NSString/NSString+Additions.h | 15 + .../Extensions/NSString/NSString+Additions.m | 14 + Source/Extensions/UIImage/UIImage+Additions.h | 8 +- Source/Extensions/UIImage/UIImage+Additions.m | 7 +- .../UITextField/UITextField+Additions.m | 3 + .../UIViewController+Additions.m | 1 + Source/JudoKit.h | 2 +- Source/JudoKit_iOS.h | 2 +- Source/Models/Address/JPAddress.h | 6 - Source/Models/Address/JPAddress.m | 6 - Source/Models/Browser/JPBrowser.m | 2 +- Source/Models/CardNetwork/JPCardNetwork.m | 4 + Source/Models/ClientDetails/JPClientDetails.m | 2 +- Source/Models/Constants/JPConstants.h | 2 +- .../Models/ConsumerDevice/JPConsumerDevice.m | 6 +- Source/Models/Country/JPCountry.h | 57 +- Source/Models/Country/JPCountry.m | 87 +- .../JPDictionaryConvertible.h | 2 +- .../JPEnhancedPaymentDetail.m | 6 +- Source/Models/Receipt/JPReceipt.h | 50 - Source/Models/Receipt/JPReceipt.m | 44 - Source/Models/Request/JPApplePayRequest.m | 8 + Source/Models/SDKInfo/JPSDKInfo.m | 2 +- Source/Models/ThreeDSecure/JPThreeDSecure.m | 4 +- Source/Models/Transaction/JPTransactionType.h | 3 + .../TransactionEnricher/JPRequestEnricher.m | 2 +- .../View/JPCardCustomizationViewController.m | 3 + .../Presenter/JPPaymentMethodsPresenter.m | 2 + .../Builder/JPTransactionBuilder.m | 1 - .../Interactor/JPTransactionInteractor.h | 66 +- .../Interactor/JPTransactionInteractor.m | 78 +- .../Presenter/JPTransactionPresenter.h | 45 +- .../Presenter/JPTransactionPresenter.m | 342 +++- .../Presenter/ViewModels/JPCardDetailsMode.h | 7 +- .../Presenter/ViewModels/JPInputType.h | 15 +- .../ViewModels/JPTransactionViewModel.h | 117 +- .../ViewModels/JPTransactionViewModel.m | 4 - .../View/JPTransactionViewController.h | 14 +- .../View/JPTransactionViewController.m | 106 +- .../JPCardTransactionService.m | 12 +- .../CardValidation/JPCardValidationService.h | 29 +- .../CardValidation/JPCardValidationService.m | 29 +- .../JPBillingInformationInputView.h | 29 - .../JPBillingInformationInputView.m | 29 - Source/View/CardInputView/JPCardInputView.h | 61 +- Source/View/CardInputView/JPCardInputView.m | 368 ++++- Source/View/InputField/JPInputField.h | 11 +- Source/View/InputField/JPInputField.m | 35 +- Source/View/InputField/JPInputFieldDelegate.h | 3 +- .../include/JPCardCustomizationPatternCell.h | 1 + Source/include/JPCardCustomizationTitleCell.h | 1 + Source/include/JPCardCustomizationView.h | 1 + Source/include/JPCardPaymentMethodView.h | 1 + .../JPCardTransactionDetails+Additions.h | 1 + Source/include/JPOtherPaymentMethodView.h | 1 + Source/include/JPPaymentMethodsCardCell.h | 1 + .../JPPaymentMethodsCardListFooterCell.h | 1 + .../JPPaymentMethodsEmptyCardListCell.h | 1 + .../include/JPPaymentMethodsIDEALBankCell.h | 1 + Source/include/JPPaymentMethodsView.h | 1 + .../include/JPSliderPresentationController.h | 1 + Source/include/create_symlinks.sh | 164 +- 108 files changed, 3098 insertions(+), 1702 deletions(-) delete mode 100644 JudoKit_iOSTests/Modules/CardStorage/CardStorageTest.swift delete mode 100644 JudoKit_iOSTests/Modules/PaymentMethods/Mocks/JPApiServicePBBAStub.swift delete mode 100644 JudoKit_iOSTests/Modules/Sevices/CardInputValidator/JPCardValidationServiceTest.swift delete mode 100644 JudoKit_iOSTests/Modules/Sevices/ConfigurationValidator/JPAppleConfigurationValidationServiceTest.swift delete mode 100644 JudoKit_iOSTests/Modules/Sevices/ConfigurationValidator/JPConfigurationValidationServiceTest.swift delete mode 100644 JudoKit_iOSTests/Modules/Sevices/PaymentMethod/JPPaymentMethodsInteractorTest.swift delete mode 100644 JudoKit_iOSTests/Modules/Sevices/PostCodesValidation/JPCanadaPostCodeValidation.swift delete mode 100644 JudoKit_iOSTests/Modules/Sevices/PostCodesValidation/JPUKPostCodeValidation.swift delete mode 100644 JudoKit_iOSTests/Modules/Sevices/PostCodesValidation/JPUSAPostCodeValidation.swift delete mode 100644 JudoKit_iOSTests/Modules/Sevices/TransactionService/JPTransactionServiceTest.swift create mode 100644 Resources/CountriesList.json delete mode 100644 Source/Models/Receipt/JPReceipt.h delete mode 100644 Source/Models/Receipt/JPReceipt.m delete mode 100644 Source/View/BillingInformationInputView/JPBillingInformationInputView.h delete mode 100644 Source/View/BillingInformationInputView/JPBillingInformationInputView.m create mode 120000 Source/include/JPCardCustomizationPatternCell.h create mode 120000 Source/include/JPCardCustomizationTitleCell.h create mode 120000 Source/include/JPCardCustomizationView.h create mode 120000 Source/include/JPCardPaymentMethodView.h create mode 120000 Source/include/JPCardTransactionDetails+Additions.h create mode 120000 Source/include/JPOtherPaymentMethodView.h create mode 120000 Source/include/JPPaymentMethodsCardCell.h create mode 120000 Source/include/JPPaymentMethodsCardListFooterCell.h create mode 120000 Source/include/JPPaymentMethodsEmptyCardListCell.h create mode 120000 Source/include/JPPaymentMethodsIDEALBankCell.h create mode 120000 Source/include/JPPaymentMethodsView.h create mode 120000 Source/include/JPSliderPresentationController.h diff --git a/Examples/ObjectiveCExampleApp/ObjectiveCExampleApp.xcodeproj/project.pbxproj b/Examples/ObjectiveCExampleApp/ObjectiveCExampleApp.xcodeproj/project.pbxproj index 63893546b..aaa9a3db6 100644 --- a/Examples/ObjectiveCExampleApp/ObjectiveCExampleApp.xcodeproj/project.pbxproj +++ b/Examples/ObjectiveCExampleApp/ObjectiveCExampleApp.xcodeproj/project.pbxproj @@ -1084,14 +1084,14 @@ CODE_SIGN_ENTITLEMENTS = ObjectiveCExampleApp/ObjectiveCExampleApp.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 95V535S6TQ; INFOPLIST_FILE = ObjectiveCExampleApp/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 3.0.3; + MARKETING_VERSION = 3.1.0; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.judo.JudoPayDemoObjC; PRODUCT_NAME = "Judopay demo"; @@ -1109,14 +1109,14 @@ CODE_SIGN_ENTITLEMENTS = ObjectiveCExampleApp/ObjectiveCExampleApp.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 95V535S6TQ; INFOPLIST_FILE = ObjectiveCExampleApp/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 3.0.3; + MARKETING_VERSION = 3.1.0; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.judo.JudoPayDemoObjC; PRODUCT_NAME = "Judopay demo"; diff --git a/Examples/ObjectiveCExampleApp/ObjectiveCExampleApp/Controllers/NoUICardPay/NoUICardPayViewController.m b/Examples/ObjectiveCExampleApp/ObjectiveCExampleApp/Controllers/NoUICardPay/NoUICardPayViewController.m index 96f56a8db..cfca0a39f 100644 --- a/Examples/ObjectiveCExampleApp/ObjectiveCExampleApp/Controllers/NoUICardPay/NoUICardPayViewController.m +++ b/Examples/ObjectiveCExampleApp/ObjectiveCExampleApp/Controllers/NoUICardPay/NoUICardPayViewController.m @@ -82,7 +82,6 @@ - (JPCardTransactionDetails *)cardTransactionDetails { address2:nil address3:nil town:@"London" - billingCountry:nil postCode:@"se151qa" countryCode:@826]; diff --git a/Examples/ObjectiveCExampleApp/ObjectiveCExampleApp/Extensions/IASKAppSettingsViewController+Additions.m b/Examples/ObjectiveCExampleApp/ObjectiveCExampleApp/Extensions/IASKAppSettingsViewController+Additions.m index 6cd02bc36..74e5af90a 100644 --- a/Examples/ObjectiveCExampleApp/ObjectiveCExampleApp/Extensions/IASKAppSettingsViewController+Additions.m +++ b/Examples/ObjectiveCExampleApp/ObjectiveCExampleApp/Extensions/IASKAppSettingsViewController+Additions.m @@ -43,7 +43,6 @@ - (NSSet *)computeHiddenKeysWithPriority:(NSArray *)keys { kAddressLine3Key, kAddressTownKey, kAddressPostCodeKey, - kAddressBillingCountryKey, kAddressCountryCodeKey, kAddressPhoneCountryCodeKey, kAddressMobileNumberKey, @@ -72,7 +71,6 @@ - (NSSet *)computeHiddenKeysWithPriority:(NSArray *)keys { kAddressLine3Key, kAddressTownKey, kAddressPostCodeKey, - kAddressBillingCountryKey, kAddressCountryCodeKey, kAddressPhoneCountryCodeKey, kAddressMobileNumberKey, diff --git a/Examples/ObjectiveCExampleApp/ObjectiveCExampleApp/Models/Settings.h b/Examples/ObjectiveCExampleApp/ObjectiveCExampleApp/Models/Settings.h index 666ad7833..23e116d2e 100644 --- a/Examples/ObjectiveCExampleApp/ObjectiveCExampleApp/Models/Settings.h +++ b/Examples/ObjectiveCExampleApp/ObjectiveCExampleApp/Models/Settings.h @@ -27,7 +27,6 @@ static NSString *const kAddressLine2Key = @"address_line_2"; static NSString *const kAddressLine3Key = @"address_line_3"; static NSString *const kAddressTownKey = @"address_town"; static NSString *const kAddressPostCodeKey = @"address_post_code"; -static NSString *const kAddressBillingCountryKey = @"address_billing_country"; static NSString *const kAddressCountryCodeKey = @"address_country_code"; static NSString *const kAddressPhoneCountryCodeKey = @"address_phone_country_code"; static NSString *const kAddressMobileNumberKey = @"address_mobile_number"; diff --git a/Examples/ObjectiveCExampleApp/ObjectiveCExampleApp/Models/Settings.m b/Examples/ObjectiveCExampleApp/ObjectiveCExampleApp/Models/Settings.m index 746a1ca6c..68054c2fe 100644 --- a/Examples/ObjectiveCExampleApp/ObjectiveCExampleApp/Models/Settings.m +++ b/Examples/ObjectiveCExampleApp/ObjectiveCExampleApp/Models/Settings.m @@ -214,7 +214,6 @@ - (JPAddress *)address { address2:[self.defaults stringForKey:kAddressLine2Key] address3:[self.defaults stringForKey:kAddressLine3Key] town:[self.defaults stringForKey:kAddressTownKey] - billingCountry:[self.defaults stringForKey:kAddressBillingCountryKey] postCode:[self.defaults stringForKey:kAddressPostCodeKey] countryCode:addressCountryCode]; } @@ -234,15 +233,24 @@ - (JPPrimaryAccountDetails *)primaryAccountDetails { } - (NSString *)emailAddress { - return [self.defaults stringForKey:kAddressEmailAddressKey]; + if (Settings.defaultSettings.isAddressOn) { + return [self.defaults stringForKey:kAddressEmailAddressKey]; + } + return nil; } - (NSString *)mobileNumber { - return [self.defaults stringForKey:kAddressMobileNumberKey]; + if (Settings.defaultSettings.isAddressOn) { + return [self.defaults stringForKey:kAddressMobileNumberKey]; + } + return nil; } - (NSString *)phoneCountryCode { - return [self.defaults stringForKey:kAddressPhoneCountryCodeKey]; + if (Settings.defaultSettings.isAddressOn) { + return [self.defaults stringForKey:kAddressPhoneCountryCodeKey]; + } + return nil; } #pragma mark - 3DS v2.0 diff --git a/Examples/ObjectiveCExampleApp/ObjectiveCExampleApp/Settings.bundle/Root.plist b/Examples/ObjectiveCExampleApp/ObjectiveCExampleApp/Settings.bundle/Root.plist index 4f71e3cb1..61b461172 100644 --- a/Examples/ObjectiveCExampleApp/ObjectiveCExampleApp/Settings.bundle/Root.plist +++ b/Examples/ObjectiveCExampleApp/ObjectiveCExampleApp/Settings.bundle/Root.plist @@ -102,7 +102,7 @@ Title is_3ds2_enabled_title Key - is_billing_info_screen_enabled + should_ask_for_billing_information DefaultValue @@ -421,16 +421,6 @@ DefaultValue TR14 8PA - - Type - PSTextFieldSpecifier - Title - address_billing_country_title - Key - address_billing_country - DefaultValue - 826 - Type PSTextFieldSpecifier diff --git a/Examples/ObjectiveCExampleApp/ObjectiveCExampleAppTests/Models/ResultTests.m b/Examples/ObjectiveCExampleApp/ObjectiveCExampleAppTests/Models/ResultTests.m index 4dc3f4826..3071fe3bb 100644 --- a/Examples/ObjectiveCExampleApp/ObjectiveCExampleAppTests/Models/ResultTests.m +++ b/Examples/ObjectiveCExampleApp/ObjectiveCExampleAppTests/Models/ResultTests.m @@ -38,17 +38,14 @@ - (void)test_GivenValidJPResponse_ParseObjectCorrectly { Result *result = [Result resultFromObject:mockedResponse]; XCTAssertTrue([result.title isEqualToString:@"JPResponse"]); + NSMutableArray *titles = [NSMutableArray new]; for (ResultItem *item in result.items) { - // Judo ID should resolve to NSString and should not have subresults if ([item.title isEqualToString:@"judoId"]) { XCTAssertTrue([item.value isEqualToString:@"123456"]); XCTAssertNil(item.subResult); - } else { - XCTFail(@"Judo ID must be a part of the Result object"); } - // Consumer should resolve to a JPConsumer and should have subresults if ([item.title isEqualToString:@"consumer"]) { XCTAssertTrue([item.value isEqualToString:@"JPConsumer"]); @@ -56,10 +53,12 @@ - (void)test_GivenValidJPResponse_ParseObjectCorrectly { XCTAssertTrue([item.subResult.title isEqualToString:@"JPConsumer"]); XCTAssertEqual(item.subResult.items.count, 2); - } else { - XCTFail(@"Consumer must be part of the Result object"); } + [titles addObject:item.title]; } + + XCTAssertTrue([titles containsObject:@"judoId"],@"Judo ID must be a part of the Result object"); + XCTAssertTrue([titles containsObject:@"consumer"],@"Consumer must be part of the Result object"); } - (JPResponse *)mockedResponse { diff --git a/Examples/ObjectiveCExampleApp/ObjectiveCExampleAppUITests/Handlers/After/JPAfterHandlers.m b/Examples/ObjectiveCExampleApp/ObjectiveCExampleAppUITests/Handlers/After/JPAfterHandlers.m index 1fcdadca4..b44b282ad 100644 --- a/Examples/ObjectiveCExampleApp/ObjectiveCExampleAppUITests/Handlers/After/JPAfterHandlers.m +++ b/Examples/ObjectiveCExampleApp/ObjectiveCExampleAppUITests/Handlers/After/JPAfterHandlers.m @@ -30,7 +30,7 @@ #import "XCUIElement+Additions.h" #import "JPHelpers.h" -void returnToMainScreen() { +void returnToMainScreen(void) { XCUIApplication *application = [XCUIApplication new]; XCUIElement *mainScreen = application.otherElements[@"Main View"]; XCUIElement *cancelButton = application.buttons[@"CANCEL"]; @@ -54,7 +54,7 @@ void swipeAndDeleteCardCell(XCUIElement *cardCell) { [[XCUIApplication new].alerts.buttons[@"Delete"] tap]; } -void resetStoredCards() { +void resetStoredCards(void) { [JPMainElements.settingsButton tap]; [JPSettingsElements.cardPaymentMethodSwitch switchOn]; [JPGenericElements.backButton tap]; @@ -88,7 +88,7 @@ void resetStoredCards() { } } -void resetSettings() { +void resetSettings(void) { [JPMainElements.settingsButton tap]; NSArray *switches = @[ diff --git a/Examples/ObjectiveCExampleApp/ObjectiveCExampleAppUITests/ObjectiveCExampleAppUITests.m b/Examples/ObjectiveCExampleApp/ObjectiveCExampleAppUITests/ObjectiveCExampleAppUITests.m index bcbcca006..340ebe6b6 100644 --- a/Examples/ObjectiveCExampleApp/ObjectiveCExampleAppUITests/ObjectiveCExampleAppUITests.m +++ b/Examples/ObjectiveCExampleApp/ObjectiveCExampleAppUITests/ObjectiveCExampleAppUITests.m @@ -31,7 +31,7 @@ __attribute__((constructor)) -void CucumberishInit() { +void CucumberishInit(void) { NSBundle *bundle = [NSBundle bundleForClass:[JPUITestSetup class]]; diff --git a/Examples/ObjectiveCExampleApp/Podfile b/Examples/ObjectiveCExampleApp/Podfile index c08ffa538..864967a39 100644 --- a/Examples/ObjectiveCExampleApp/Podfile +++ b/Examples/ObjectiveCExampleApp/Podfile @@ -4,11 +4,11 @@ use_frameworks! inhibit_all_warnings! target 'ObjectiveCExampleApp' do - pod 'Judo3DS2_iOS', '1.0.1' - pod 'JudoKit-iOS', '3.0.2' - # pod 'Judo3DS2_iOS', :path => '../../../Judo3DS2-iOS-Source' - # pod 'JudoKit-iOS', :path => '../../' + pod 'Judo3DS2_iOS', '1.1.0' + + pod 'JudoKit-iOS', :path => '../../' + # pod 'JudoKit-iOS', '3.1.0' pod 'MaterialComponents/Snackbar' pod 'InAppSettingsKit', '3.3.6' diff --git a/Examples/ObjectiveCExampleApp/Podfile.lock b/Examples/ObjectiveCExampleApp/Podfile.lock index a5a3469d0..a462137da 100644 --- a/Examples/ObjectiveCExampleApp/Podfile.lock +++ b/Examples/ObjectiveCExampleApp/Podfile.lock @@ -4,10 +4,10 @@ PODS: - DeviceDNA (2.0.0): - OpenSSL-Universal (~> 1.1.180) - InAppSettingsKit (3.3.6) - - Judo3DS2_iOS (1.0.1) - - JudoKit-iOS (3.0.2): + - Judo3DS2_iOS (1.1.0) + - JudoKit-iOS (3.0.3): - DeviceDNA (~> 2.0.0) - - Judo3DS2_iOS (~> 1.0.1) + - Judo3DS2_iOS (~> 1.1.0) - TrustKit - ZappMerchantLib - MaterialComponents/AnimationTiming (124.2.0) @@ -87,8 +87,8 @@ DEPENDENCIES: - CocoaDebug (= 1.7.2) - Cucumberish (from `https://github.com/mpetrenco/Cucumberish.git`) - InAppSettingsKit (= 3.3.6) - - Judo3DS2_iOS (= 1.0.1) - - JudoKit-iOS (= 3.0.2) + - Judo3DS2_iOS (= 1.1.0) + - JudoKit-iOS (from `../../`) - MaterialComponents/Snackbar SPEC REPOS: @@ -97,7 +97,6 @@ SPEC REPOS: - DeviceDNA - InAppSettingsKit - Judo3DS2_iOS - - JudoKit-iOS - MaterialComponents - MDFInternationalization - MDFTextAccessibility @@ -108,6 +107,8 @@ SPEC REPOS: EXTERNAL SOURCES: Cucumberish: :git: https://github.com/mpetrenco/Cucumberish.git + JudoKit-iOS: + :path: "../../" CHECKOUT OPTIONS: Cucumberish: @@ -119,8 +120,8 @@ SPEC CHECKSUMS: Cucumberish: 6cbd0c1f50306b369acebfe7d9f514c9c287d26c DeviceDNA: 9ff289d1fb983937754b324fa0adade2081210c4 InAppSettingsKit: 37df0b44132380d4c7db6fc7cded92997e29873a - Judo3DS2_iOS: c1ccf49ecacddb4559a73fb7eae6e680e2355b21 - JudoKit-iOS: 4a96c63d4cfb45bb1a68a1891b2ebaeaa8a46be1 + Judo3DS2_iOS: 88276544805c5db040e90c0e597d84da302480af + JudoKit-iOS: eb123ac21dde4e14e92d497e4a98f1aff7e23f60 MaterialComponents: 1a9b2d9d45b1601ae544de85089adc4c464306d4 MDFInternationalization: d697c55307816222a55685c4ccb1044ffb030c12 MDFTextAccessibility: f4bb4cc2194286651b59a215fdeaa0e05dc90ba5 @@ -128,6 +129,6 @@ SPEC CHECKSUMS: TrustKit: 610b8c71c07914756dd74c380040a3408a747798 ZappMerchantLib: b14bc5814840426d351190309250347ca9b0983d -PODFILE CHECKSUM: 19338ddb7cdb0fea4f3595c840eb51d5d5e71db9 +PODFILE CHECKSUM: a15c5b473dbfa7199cb2fbc9de48e3a6a4302ca9 COCOAPODS: 1.11.3 diff --git a/JudoKit-iOS.podspec b/JudoKit-iOS.podspec index beb66e98a..780468e57 100755 --- a/JudoKit-iOS.podspec +++ b/JudoKit-iOS.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'JudoKit-iOS' - s.version = '3.0.3' + s.version = '3.1.0' s.summary = 'Judo Pay Full iOS Client Kit' s.homepage = 'https://www.judopay.com/' s.license = 'MIT' @@ -12,13 +12,14 @@ Pod::Spec.new do |s| s.ios.deployment_target = '11.0' s.requires_arc = true s.source_files = 'Source/**/*.{m,h}' + s.exclude_files = 'Source/include/' s.dependency 'DeviceDNA', '~> 2.0.0' s.dependency 'TrustKit' s.dependency 'ZappMerchantLib' - s.dependency 'Judo3DS2_iOS', '~> 1.0.1' + s.dependency 'Judo3DS2_iOS', '~> 1.1.0' s.frameworks = 'CoreLocation', 'Security', 'CoreTelephony', 'Vision' s.resource_bundles = { "JudoKit_iOS" => ["Resources/*.lproj/*.strings"] } - s.resources = ['Resources/icons.bundle', 'Resources/resources.bundle'] + s.resources = ['Resources/icons.bundle', 'Resources/resources.bundle', 'Resources/CountriesList.json'] end diff --git a/JudoKit_iOS.xcodeproj/project.pbxproj b/JudoKit_iOS.xcodeproj/project.pbxproj index 22e47df4a..3bd70b523 100644 --- a/JudoKit_iOS.xcodeproj/project.pbxproj +++ b/JudoKit_iOS.xcodeproj/project.pbxproj @@ -16,7 +16,6 @@ 0777B9E8247BC9BB00867B9F /* JPIDEALServiceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0777B98B247BC9BB00867B9F /* JPIDEALServiceTest.swift */; }; 0777B9EA247BC9BB00867B9F /* JPConfigurationValidationServiceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0777B98F247BC9BB00867B9F /* JPConfigurationValidationServiceTest.swift */; }; 0777B9EB247BC9BB00867B9F /* JPAppleConfigurationValidationServiceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0777B990247BC9BB00867B9F /* JPAppleConfigurationValidationServiceTest.swift */; }; - 0777B9EC247BC9BB00867B9F /* JPApplePayServiceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0777B992247BC9BB00867B9F /* JPApplePayServiceTest.swift */; }; 0777B9ED247BC9BB00867B9F /* CardDetails.json in Resources */ = {isa = PBXBuildFile; fileRef = 0777B995247BC9BB00867B9F /* CardDetails.json */; }; 0777B9EE247BC9BB00867B9F /* PendingResponse.json in Resources */ = {isa = PBXBuildFile; fileRef = 0777B996247BC9BB00867B9F /* PendingResponse.json */; }; 0777B9EF247BC9BB00867B9F /* SuccessResponse.json in Resources */ = {isa = PBXBuildFile; fileRef = 0777B997247BC9BB00867B9F /* SuccessResponse.json */; }; @@ -40,7 +39,6 @@ 0777BA03247BC9BB00867B9F /* JPErrorAdditionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0777B9BF247BC9BB00867B9F /* JPErrorAdditionsTests.swift */; }; 0777BA04247BC9BB00867B9F /* JPTransactionInteractorMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0777B9C3247BC9BB00867B9F /* JPTransactionInteractorMock.swift */; }; 0777BA05247BC9BB00867B9F /* JPTransactionViewMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0777B9C4247BC9BB00867B9F /* JPTransactionViewMock.swift */; }; - 0777BA06247BC9BB00867B9F /* JPTransactionRouterMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0777B9C5247BC9BB00867B9F /* JPTransactionRouterMock.swift */; }; 0777BA07247BC9BB00867B9F /* JPTransactionPresenterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0777B9C7247BC9BB00867B9F /* JPTransactionPresenterTests.swift */; }; 0777BA08247BC9BB00867B9F /* JPTransactionInteractorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0777B9C9247BC9BB00867B9F /* JPTransactionInteractorTest.swift */; }; 0777BA09247BC9BB00867B9F /* JPCardCustomizationRouterMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0777B9CC247BC9BB00867B9F /* JPCardCustomizationRouterMock.swift */; }; @@ -58,7 +56,6 @@ 0777BA15247BC9BB00867B9F /* JPPaymentMethodsRouterTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0777B9DF247BC9BB00867B9F /* JPPaymentMethodsRouterTest.swift */; }; 0777BA16247BC9BB00867B9F /* JPFormattersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0777B9E1247BC9BB00867B9F /* JPFormattersTests.swift */; }; 0777BA17247BC9BB00867B9F /* FunctionsHelpersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0777B9E2247BC9BB00867B9F /* FunctionsHelpersTest.swift */; }; - 0777BA1B247BCA3C00867B9F /* JPPBBAServiceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0777BA1A247BCA3B00867B9F /* JPPBBAServiceTest.swift */; }; 0779B1732490EC05000844AF /* JPCardInputView.m in Sources */ = {isa = PBXBuildFile; fileRef = 0779B16A2490EC05000844AF /* JPCardInputView.m */; }; 0779B1742490EC05000844AF /* JPCardInputField.h in Headers */ = {isa = PBXBuildFile; fileRef = 0779B16C2490EC05000844AF /* JPCardInputField.h */; }; 0779B1752490EC05000844AF /* JPCardNumberField.h in Headers */ = {isa = PBXBuildFile; fileRef = 0779B16D2490EC05000844AF /* JPCardNumberField.h */; }; @@ -323,8 +320,6 @@ 4492117A246A044D00DF6D14 /* JPTransactionViewDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 44921179246A044D00DF6D14 /* JPTransactionViewDelegate.h */; }; 4492117C246A04C500DF6D14 /* JPPaymentMethodsCardListHeaderCellDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4492117B246A04C500DF6D14 /* JPPaymentMethodsCardListHeaderCellDelegate.h */; }; 4492117E246A052300DF6D14 /* JPSectionViewDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4492117D246A052300DF6D14 /* JPSectionViewDelegate.h */; }; - 44A60A24288AB0F800B360E1 /* JPNetworkTimeout.m in Sources */ = {isa = PBXBuildFile; fileRef = 44A60A22288AB0F800B360E1 /* JPNetworkTimeout.m */; }; - 44A60A25288AB0F800B360E1 /* JPNetworkTimeout.h in Headers */ = {isa = PBXBuildFile; fileRef = 44A60A23288AB0F800B360E1 /* JPNetworkTimeout.h */; settings = {ATTRIBUTES = (Public, ); }; }; 525FF3D8252C41CF001F030E /* JPCardScanControllerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 525FF3D0252C41CF001F030E /* JPCardScanControllerDelegate.h */; }; 525FF3D9252C41CF001F030E /* JPCardScanController.h in Headers */ = {isa = PBXBuildFile; fileRef = 525FF3D1252C41CF001F030E /* JPCardScanController.h */; }; 525FF3DA252C41CF001F030E /* JPCardScanController.m in Sources */ = {isa = PBXBuildFile; fileRef = 525FF3D2252C41CF001F030E /* JPCardScanController.m */; }; @@ -407,6 +402,13 @@ AD0F05A8286B67D600470534 /* JPComplete3DS2Request.h in Headers */ = {isa = PBXBuildFile; fileRef = AD0F05A6286B67D600470534 /* JPComplete3DS2Request.h */; settings = {ATTRIBUTES = (Public, ); }; }; AD0F05B0286B69B800470534 /* JPCardTransactionDetails.h in Headers */ = {isa = PBXBuildFile; fileRef = AD0F05AE286B69B800470534 /* JPCardTransactionDetails.h */; settings = {ATTRIBUTES = (Public, ); }; }; AD0F05B1286B69B800470534 /* JPCardTransactionDetails.m in Sources */ = {isa = PBXBuildFile; fileRef = AD0F05AF286B69B800470534 /* JPCardTransactionDetails.m */; }; + AD13DC0828831297002B82CD /* JPNetworkTimeout.m in Sources */ = {isa = PBXBuildFile; fileRef = AD13DC0628831297002B82CD /* JPNetworkTimeout.m */; }; + AD13DC0928831297002B82CD /* JPNetworkTimeout.h in Headers */ = {isa = PBXBuildFile; fileRef = AD13DC0728831297002B82CD /* JPNetworkTimeout.h */; settings = {ATTRIBUTES = (Public, ); }; }; + AD13DC1828831C07002B82CD /* JPPaymentMethodsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD13DC1728831C07002B82CD /* JPPaymentMethodsTest.swift */; }; + AD3C03992885CE8C00063947 /* CountriesList.json in Resources */ = {isa = PBXBuildFile; fileRef = AD3C03982885CE7200063947 /* CountriesList.json */; }; + AD4B368B2882E18600289CB7 /* JPTransactionRouterMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0777B9C5247BC9BB00867B9F /* JPTransactionRouterMock.swift */; }; + AD4B368C2882E19A00289CB7 /* JPApplePayServiceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0777B992247BC9BB00867B9F /* JPApplePayServiceTest.swift */; }; + AD4B368D2882E1AE00289CB7 /* JPPBBAServiceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0777BA1A247BCA3B00867B9F /* JPPBBAServiceTest.swift */; }; AD7404D0284A085A001F11CD /* OHHTTPStubs.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = ADA50D6D282C1C7B00846943 /* OHHTTPStubs.xcframework */; platformFilter = ios; }; ADA50D70282C1C7B00846943 /* ZappMerchantLib.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = ADA50D6C282C1C7B00846943 /* ZappMerchantLib.xcframework */; }; ADA50D74282C1C7B00846943 /* DeviceDNA.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = ADA50D6E282C1C7B00846943 /* DeviceDNA.xcframework */; }; @@ -755,8 +757,6 @@ 44921179246A044D00DF6D14 /* JPTransactionViewDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JPTransactionViewDelegate.h; sourceTree = ""; }; 4492117B246A04C500DF6D14 /* JPPaymentMethodsCardListHeaderCellDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JPPaymentMethodsCardListHeaderCellDelegate.h; sourceTree = ""; }; 4492117D246A052300DF6D14 /* JPSectionViewDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JPSectionViewDelegate.h; sourceTree = ""; }; - 44A60A22288AB0F800B360E1 /* JPNetworkTimeout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPNetworkTimeout.m; sourceTree = ""; }; - 44A60A23288AB0F800B360E1 /* JPNetworkTimeout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPNetworkTimeout.h; sourceTree = ""; }; 525FF3D0252C41CF001F030E /* JPCardScanControllerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCardScanControllerDelegate.h; sourceTree = ""; }; 525FF3D1252C41CF001F030E /* JPCardScanController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCardScanController.h; sourceTree = ""; }; 525FF3D2252C41CF001F030E /* JPCardScanController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCardScanController.m; sourceTree = ""; }; @@ -840,6 +840,10 @@ AD0F05A6286B67D600470534 /* JPComplete3DS2Request.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPComplete3DS2Request.h; sourceTree = ""; }; AD0F05AE286B69B800470534 /* JPCardTransactionDetails.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCardTransactionDetails.h; sourceTree = ""; }; AD0F05AF286B69B800470534 /* JPCardTransactionDetails.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCardTransactionDetails.m; sourceTree = ""; }; + AD13DC0628831297002B82CD /* JPNetworkTimeout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPNetworkTimeout.m; sourceTree = ""; }; + AD13DC0728831297002B82CD /* JPNetworkTimeout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPNetworkTimeout.h; sourceTree = ""; }; + AD13DC1728831C07002B82CD /* JPPaymentMethodsTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JPPaymentMethodsTest.swift; sourceTree = ""; }; + AD3C03982885CE7200063947 /* CountriesList.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = CountriesList.json; sourceTree = ""; }; ADA50D6C282C1C7B00846943 /* ZappMerchantLib.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = ZappMerchantLib.xcframework; path = Carthage/Build/ZappMerchantLib.xcframework; sourceTree = ""; }; ADA50D6D282C1C7B00846943 /* OHHTTPStubs.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = OHHTTPStubs.xcframework; path = Carthage/Build/OHHTTPStubs.xcframework; sourceTree = ""; }; ADA50D6E282C1C7B00846943 /* DeviceDNA.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = DeviceDNA.xcframework; path = Carthage/Build/DeviceDNA.xcframework; sourceTree = ""; }; @@ -896,12 +900,12 @@ children = ( 0777B993247BC9BB00867B9F /* JudoKit_iOSTests-Bridging-Header.h */, 0777B999247BC9BB00867B9F /* JudoKitTest.swift */, - 0777B983247BC9BB00867B9F /* Sevices */, + 0777B9AF247BC9BB00867B9F /* Extensions */, + 0777B9E0247BC9BB00867B9F /* Helpers */, 0777B994247BC9BB00867B9F /* JsonStubs */, 0777B99A247BC9BB00867B9F /* Models */, - 0777B9AF247BC9BB00867B9F /* Extensions */, 0777B9C0247BC9BB00867B9F /* Modules */, - 0777B9E0247BC9BB00867B9F /* Helpers */, + 0777B983247BC9BB00867B9F /* Sevices */, 0777B9E3247BC9BB00867B9F /* Info.plist */, ); path = JudoKit_iOSTests; @@ -911,12 +915,12 @@ isa = PBXGroup; children = ( 30D3644524B8764C0029BC86 /* ApiService */, - 0777BA19247BCA3200867B9F /* PBBA */, - 0777B984247BC9BB00867B9F /* PostCodesValidation */, + 0777B991247BC9BB00867B9F /* ApplePay */, 0777B988247BC9BB00867B9F /* CardInputValidator */, - 0777B98A247BC9BB00867B9F /* iDeal */, 0777B98E247BC9BB00867B9F /* ConfigurationValidator */, - 0777B991247BC9BB00867B9F /* ApplePay */, + 0777B98A247BC9BB00867B9F /* iDeal */, + 0777BA19247BCA3200867B9F /* PBBA */, + 0777B984247BC9BB00867B9F /* PostCodesValidation */, ); path = Sevices; sourceTree = ""; @@ -924,9 +928,9 @@ 0777B984247BC9BB00867B9F /* PostCodesValidation */ = { isa = PBXGroup; children = ( + 0777B987247BC9BB00867B9F /* JPCanadaPostCodeValidation.swift */, 0777B985247BC9BB00867B9F /* JPUKPostCodeValidation.swift */, 0777B986247BC9BB00867B9F /* JPUSAPostCodeValidation.swift */, - 0777B987247BC9BB00867B9F /* JPCanadaPostCodeValidation.swift */, ); path = PostCodesValidation; sourceTree = ""; @@ -950,8 +954,8 @@ 0777B98E247BC9BB00867B9F /* ConfigurationValidator */ = { isa = PBXGroup; children = ( - 0777B98F247BC9BB00867B9F /* JPConfigurationValidationServiceTest.swift */, 0777B990247BC9BB00867B9F /* JPAppleConfigurationValidationServiceTest.swift */, + 0777B98F247BC9BB00867B9F /* JPConfigurationValidationServiceTest.swift */, ); path = ConfigurationValidator; sourceTree = ""; @@ -959,8 +963,8 @@ 0777B991247BC9BB00867B9F /* ApplePay */ = { isa = PBXGroup; children = ( - 0777B992247BC9BB00867B9F /* JPApplePayServiceTest.swift */, 52D23DD22524BE5C007C79EB /* JPApplePayControllerTest.swift */, + 0777B992247BC9BB00867B9F /* JPApplePayServiceTest.swift */, ); path = ApplePay; sourceTree = ""; @@ -983,32 +987,32 @@ 0777B99A247BC9BB00867B9F /* Models */ = { isa = PBXGroup; children = ( - 52D23DCD252495BC007C79EB /* JPApplePayWrappers */, - 52D23DC82524919F007C79EB /* JPPaymentShippingMethod */, - 52D23DC325248FBE007C79EB /* JPPaymentSummaryItem */, - 300F938224C9B48B003DECA5 /* Requests */, - 077B286024BF0F08009A7183 /* JPRegisterCardRequest */, - 07AA4FF724BDEC8200C21CEA /* JPCountry */, - 079A871624BDDDD200108714 /* JPSessionAuthorization */, 0777B99F247BC9BB00867B9F /* Amount */, 0777B99D247BC9BB00867B9F /* Card */, 0777B9AD247BC9BB00867B9F /* CardStorage */, 0777B9A5247BC9BB00867B9F /* JP3DSConfiguration */, 0777B99B247BC9BB00867B9F /* JPAddress */, + 52D23DCD252495BC007C79EB /* JPApplePayWrappers */, 0777B9A1247BC9BB00867B9F /* JPCardDetails */, 30D3640F24B873A90029BC86 /* JPClientDetails */, 30D3641224B873B10029BC86 /* JPConsumerDevice */, 0777B9AB247BC9BB00867B9F /* JPContactInformation */, + 07AA4FF724BDEC8200C21CEA /* JPCountry */, 30D3641524B873B90029BC86 /* JPEnhancedPaymentDetail */, 0777B9A3247BC9BB00867B9F /* JPOrderDetails */, 30D3641824B873C30029BC86 /* JPPaymentMethod */, + 52D23DC82524919F007C79EB /* JPPaymentShippingMethod */, + 52D23DC325248FBE007C79EB /* JPPaymentSummaryItem */, 30D3641E24B873D70029BC86 /* JPPBBAConfiguration */, 30D3642124B873DF0029BC86 /* JPPrimaryAccountDetails */, 30D3642424B873E60029BC86 /* JPReachability */, + 077B286024BF0F08009A7183 /* JPRegisterCardRequest */, 30D3642A24B873F50029BC86 /* JPSDKInfo */, 30D3642F24B874060029BC86 /* JPSection */, + 079A871624BDDDD200108714 /* JPSessionAuthorization */, 30D3643124B874060029BC86 /* JPThreeDSecure */, 30D3643C24B874250029BC86 /* JPUIConfiguration */, + 300F938224C9B48B003DECA5 /* Requests */, 0777B9A9247BC9BB00867B9F /* SDKInfo */, ); path = Models; @@ -1161,9 +1165,9 @@ 0777B9C0247BC9BB00867B9F /* Modules */ = { isa = PBXGroup; children = ( - 0777B9C1247BC9BB00867B9F /* Transaction */, 0777B9CA247BC9BB00867B9F /* CardCustomization */, 0777B9D3247BC9BB00867B9F /* PaymentMethods */, + 0777B9C1247BC9BB00867B9F /* Transaction */, ); path = Modules; sourceTree = ""; @@ -1172,8 +1176,8 @@ isa = PBXGroup; children = ( 0777B9C2247BC9BB00867B9F /* Mocks */, - 0777B9C6247BC9BB00867B9F /* Presenter */, 0777B9C8247BC9BB00867B9F /* Interactor */, + 0777B9C6247BC9BB00867B9F /* Presenter */, ); path = Transaction; sourceTree = ""; @@ -1182,8 +1186,8 @@ isa = PBXGroup; children = ( 0777B9C3247BC9BB00867B9F /* JPTransactionInteractorMock.swift */, - 0777B9C4247BC9BB00867B9F /* JPTransactionViewMock.swift */, 0777B9C5247BC9BB00867B9F /* JPTransactionRouterMock.swift */, + 0777B9C4247BC9BB00867B9F /* JPTransactionViewMock.swift */, ); path = Mocks; sourceTree = ""; @@ -1208,8 +1212,8 @@ isa = PBXGroup; children = ( 0777B9CB247BC9BB00867B9F /* Mocks */, - 0777B9CF247BC9BB00867B9F /* Presenter */, 0777B9D1247BC9BB00867B9F /* Interactor */, + 0777B9CF247BC9BB00867B9F /* Presenter */, ); path = CardCustomization; sourceTree = ""; @@ -1243,9 +1247,10 @@ 0777B9D3247BC9BB00867B9F /* PaymentMethods */ = { isa = PBXGroup; children = ( + AD13DC1728831C07002B82CD /* JPPaymentMethodsTest.swift */, 0777B9D4247BC9BB00867B9F /* Mocks */, - 0777B9DA247BC9BB00867B9F /* Presenter */, 0777B9DC247BC9BB00867B9F /* Interactor */, + 0777B9DA247BC9BB00867B9F /* Presenter */, 0777B9DE247BC9BB00867B9F /* Router */, ); path = PaymentMethods; @@ -1255,10 +1260,10 @@ isa = PBXGroup; children = ( 0777B9D5247BC9BB00867B9F /* JPApiServiceiDealStub.swift */, - 0777B9D6247BC9BB00867B9F /* JPPaymentMethodsViewControllerMock.swift */, - 0777B9D7247BC9BB00867B9F /* JPPaymentMethodsRouterMock.swift */, 0777B9D8247BC9BB00867B9F /* JPApiServiceStub.swift */, 0777B9D9247BC9BB00867B9F /* JPPaymentMethodsInteractorMock.swift */, + 0777B9D7247BC9BB00867B9F /* JPPaymentMethodsRouterMock.swift */, + 0777B9D6247BC9BB00867B9F /* JPPaymentMethodsViewControllerMock.swift */, ); path = Mocks; sourceTree = ""; @@ -1290,8 +1295,8 @@ 0777B9E0247BC9BB00867B9F /* Helpers */ = { isa = PBXGroup; children = ( - 0777B9E1247BC9BB00867B9F /* JPFormattersTests.swift */, 0777B9E2247BC9BB00867B9F /* FunctionsHelpersTest.swift */, + 0777B9E1247BC9BB00867B9F /* JPFormattersTests.swift */, ); path = Helpers; sourceTree = ""; @@ -1305,14 +1310,14 @@ path = PBBA; sourceTree = ""; }; - 0779B1692490EC05000844AF /* JPCardInputView */ = { + 0779B1692490EC05000844AF /* CardInputView */ = { isa = PBXGroup; children = ( 0779B1722490EC05000844AF /* JPCardInputView.h */, 0779B16A2490EC05000844AF /* JPCardInputView.m */, 0779B16B2490EC05000844AF /* Subviews */, ); - name = JPCardInputView; + name = CardInputView; path = View/CardInputView; sourceTree = ""; }; @@ -1320,11 +1325,11 @@ isa = PBXGroup; children = ( 0779B16C2490EC05000844AF /* JPCardInputField.h */, - 0779B16D2490EC05000844AF /* JPCardNumberField.h */, - 0779B16E2490EC05000844AF /* JPTransactionButton.m */, 0779B16F2490EC05000844AF /* JPCardInputField.m */, + 0779B16D2490EC05000844AF /* JPCardNumberField.h */, 0779B1702490EC05000844AF /* JPCardNumberField.m */, 0779B1712490EC05000844AF /* JPTransactionButton.h */, + 0779B16E2490EC05000844AF /* JPTransactionButton.m */, ); path = Subviews; sourceTree = ""; @@ -1411,9 +1416,9 @@ children = ( 52D23DB625248B92007C79EB /* JPApplePayController.h */, 52D23DB725248B92007C79EB /* JPApplePayController.m */, - 52D23DB525248B92007C79EB /* JPApplePayTypedefs.h */, 30006F2523F697B60099F3C5 /* JPApplePayService.h */, 30006F2423F697B60099F3C5 /* JPApplePayService.m */, + 52D23DB525248B92007C79EB /* JPApplePayTypedefs.h */, ); path = ApplePay; sourceTree = ""; @@ -1640,7 +1645,6 @@ 300071C523F6A78E0099F3C5 /* Models */ = { isa = PBXGroup; children = ( - 44A60A21288AB0F800B360E1 /* NetworkTimeout */, 3000737923FBECCE0099F3C5 /* 3DSConfiguration */, 3000728F23F6AB550099F3C5 /* Address */, 3000726223F6AB540099F3C5 /* Amount */, @@ -1667,6 +1671,7 @@ 300072B423F6AB560099F3C5 /* EnchancedPaymentDetail */, 30489AD32460737A0085B4F2 /* Error */, 3000728423F6AB550099F3C5 /* IDEALBank */, + AD13DC0528831297002B82CD /* NetworkTimeout */, 3000728723F6AB550099F3C5 /* OrderDetails */, 3000727923F6AB550099F3C5 /* PaymentMethod */, 3000725423F6AB540099F3C5 /* PaymentMethods */, @@ -1987,8 +1992,8 @@ isa = PBXGroup; children = ( 449211612469E7A200DF6D14 /* JPTransactionMode.h */, - 449211632469E7F600DF6D14 /* JPTransactionType.h */, 449211652469E83D00DF6D14 /* JPTransactionResult.h */, + 449211632469E7F600DF6D14 /* JPTransactionType.h */, ); path = Transaction; sourceTree = ""; @@ -2051,13 +2056,13 @@ 300F938224C9B48B003DECA5 /* Requests */ = { isa = PBXGroup; children = ( + 300F938B24C9BED5003DECA5 /* JPApplePayRequestTests.swift */, + 300F938F24CADBAC003DECA5 /* JPBankOrderRequestTests.swift */, + 300F938D24CADB28003DECA5 /* JPCheckCardRequestTests.swift */, 300F938324C9B4A4003DECA5 /* JPPaymentRequestTests.swift */, - 300F938524C9B9A0003DECA5 /* JPSaveCardRequestTests.swift */, 300F938724C9BA79003DECA5 /* JPRegisterCardTests.swift */, + 300F938524C9B9A0003DECA5 /* JPSaveCardRequestTests.swift */, 300F938924C9BD31003DECA5 /* JPTokenRequestTests.swift */, - 300F938B24C9BED5003DECA5 /* JPApplePayRequestTests.swift */, - 300F938D24CADB28003DECA5 /* JPCheckCardRequestTests.swift */, - 300F938F24CADBAC003DECA5 /* JPBankOrderRequestTests.swift */, ); path = Requests; sourceTree = ""; @@ -2085,11 +2090,11 @@ 30221C1823FE6D9200BF2823 /* CardCustomization */ = { isa = PBXGroup; children = ( - 30221C1923FE6D9200BF2823 /* Presenter */, - 30221C1C23FE6D9200BF2823 /* View */, 30221C1F23FE6D9200BF2823 /* Builder */, 30221C2223FE6D9200BF2823 /* Interactor */, + 30221C1923FE6D9200BF2823 /* Presenter */, 30221C2523FE6D9200BF2823 /* Router */, + 30221C1C23FE6D9200BF2823 /* View */, ); name = CardCustomization; path = Modules/CardCustomization; @@ -2109,11 +2114,11 @@ 30221C1C23FE6D9200BF2823 /* View */ = { isa = PBXGroup; children = ( - 30221C4A23FE7D7600BF2823 /* Cells */, - 30221C1E23FE6D9200BF2823 /* JPCardCustomizationViewController.h */, - 30221C1D23FE6D9200BF2823 /* JPCardCustomizationViewController.m */, 30221C3B23FE739800BF2823 /* JPCardCustomizationView.h */, 30221C3C23FE739800BF2823 /* JPCardCustomizationView.m */, + 30221C1E23FE6D9200BF2823 /* JPCardCustomizationViewController.h */, + 30221C1D23FE6D9200BF2823 /* JPCardCustomizationViewController.m */, + 30221C4A23FE7D7600BF2823 /* Cells */, ); path = View; sourceTree = ""; @@ -2249,12 +2254,12 @@ 30D08910238FB4CD00480C9E /* Modules */ = { isa = PBXGroup; children = ( + 3000737E23FBED640099F3C5 /* 3DSViewController */, + 30221C1823FE6D9200BF2823 /* CardCustomization */, 525FF3CF252C41CF001F030E /* CardScanController */, 52B4CA37241EF7AA009C28DC /* IDEALViewController */, - 30221C1823FE6D9200BF2823 /* CardCustomization */, - 3000737E23FBED640099F3C5 /* 3DSViewController */, - 52B74D7423F98B4C009FE38C /* Transaction */, 30D61D3123BB741A004E5CEE /* PaymentMethods */, + 52B74D7423F98B4C009FE38C /* Transaction */, ); name = Modules; sourceTree = ""; @@ -2290,8 +2295,8 @@ 30D363A424B5BB420029BC86 /* NSObject */ = { isa = PBXGroup; children = ( - 30D363A524B5BB420029BC86 /* NSObject+Additions.m */, 30D363A624B5BB420029BC86 /* NSObject+Additions.h */, + 30D363A524B5BB420029BC86 /* NSObject+Additions.m */, ); name = NSObject; path = Extensions/NSObject; @@ -2300,8 +2305,8 @@ 30D363F224B5F89A0029BC86 /* NSNumberFormatter */ = { isa = PBXGroup; children = ( - 30D363F324B5F89A0029BC86 /* NSNumberFormatter+Additions.m */, 30D363F424B5F89A0029BC86 /* NSNumberFormatter+Additions.h */, + 30D363F324B5F89A0029BC86 /* NSNumberFormatter+Additions.m */, ); name = NSNumberFormatter; path = Extensions/NSNumberFormatter; @@ -2458,11 +2463,11 @@ 30D61D3A23BB741A004E5CEE /* Subviews */ = { isa = PBXGroup; children = ( - 5273AF0A23F306D4008C6D89 /* CardView */, - 529CCB8323BE8A8700A8DBDD /* Header */, - 30D61DF423BE3A45004E5CEE /* Cells */, 30D61DE323BE3976004E5CEE /* JPPaymentMethodsHeaderView.h */, 30D61DE423BE3976004E5CEE /* JPPaymentMethodsHeaderView.m */, + 5273AF0A23F306D4008C6D89 /* CardView */, + 30D61DF423BE3A45004E5CEE /* Cells */, + 529CCB8323BE8A8700A8DBDD /* Header */, ); path = Subviews; sourceTree = ""; @@ -2557,9 +2562,9 @@ 30DB511923100E6B00B73D66 /* Helpers */ = { isa = PBXGroup; children = ( - 446CD9E2264157D5004908DC /* JPFormatters */, 30DB511B23100E6B00B73D66 /* Functions.h */, 30DB511A23100E6B00B73D66 /* Functions.m */, + 446CD9E2264157D5004908DC /* JPFormatters */, ); path = Helpers; sourceTree = ""; @@ -2567,14 +2572,14 @@ 30DB511E23100E6B00B73D66 /* Services */ = { isa = PBXGroup; children = ( - 0783431D247552FA000DA445 /* PBBA */, - 070F1FE9243B2391005D8FAB /* ConfigurationValidation */, - 3000738823FBEDC80099F3C5 /* CardTransactionService */, + 30006F2F23F697B60099F3C5 /* ApiService */, 30006F2323F697B60099F3C5 /* ApplePay */, + 3000738823FBEDC80099F3C5 /* CardTransactionService */, 30006F2923F697B60099F3C5 /* CardValidation */, + 070F1FE9243B2391005D8FAB /* ConfigurationValidation */, 30006F2C23F697B60099F3C5 /* iDEAL */, 30006F2623F697B60099F3C5 /* Keychain */, - 30006F2F23F697B60099F3C5 /* ApiService */, + 0783431D247552FA000DA445 /* PBBA */, ); path = Services; sourceTree = ""; @@ -2604,8 +2609,8 @@ children = ( 300072AA23F6AB550099F3C5 /* JudoKit_iOS.h */, 3B678BC71C735AB80001DC2F /* JudoKit.h */, - 449211672469E8DD00DF6D14 /* Typedefs.h */, 3B678BC81C735AB80001DC2F /* JudoKit.m */, + 449211672469E8DD00DF6D14 /* Typedefs.h */, 3B678B5B1C6CE5190001DC2F /* Info.plist */, 3B678B731C6CE6500001DC2F /* Extensions */, 30DB511923100E6B00B73D66 /* Helpers */, @@ -2648,12 +2653,12 @@ isa = PBXGroup; children = ( 303FA583259B5C2700C2F279 /* ApplePayButton */, - 0779B1692490EC05000844AF /* JPCardInputView */, - 07B2822E247E996100F9862B /* PBBAButton */, - 30221BC423FD7E4D00BF2823 /* LoadingView */, + 0779B1692490EC05000844AF /* CardInputView */, 30006F4823F698A20099F3C5 /* FloatingTextField */, 30006F5423F698A20099F3C5 /* InputField */, 30006F4523F698A20099F3C5 /* LoadingButton */, + 30221BC423FD7E4D00BF2823 /* LoadingView */, + 07B2822E247E996100F9862B /* PBBAButton */, 30006F4B23F698A20099F3C5 /* RoundedCornerView */, 30006F4E23F698A20099F3C5 /* SectionView */, ); @@ -2663,8 +2668,8 @@ 4431198924B3345200BF961C /* JPRequest */ = { isa = PBXGroup; children = ( - 4431198A24B3345200BF961C /* JPRequest+Additions.m */, 4431198B24B3345200BF961C /* JPRequest+Additions.h */, + 4431198A24B3345200BF961C /* JPRequest+Additions.m */, ); name = JPRequest; path = Extensions/JPRequest; @@ -2679,21 +2684,12 @@ path = JPFormatters; sourceTree = ""; }; - 44A60A21288AB0F800B360E1 /* NetworkTimeout */ = { - isa = PBXGroup; - children = ( - 44A60A22288AB0F800B360E1 /* JPNetworkTimeout.m */, - 44A60A23288AB0F800B360E1 /* JPNetworkTimeout.h */, - ); - path = NetworkTimeout; - sourceTree = ""; - }; 525FF3CF252C41CF001F030E /* CardScanController */ = { isa = PBXGroup; children = ( - 525FF3D0252C41CF001F030E /* JPCardScanControllerDelegate.h */, 525FF3D1252C41CF001F030E /* JPCardScanController.h */, 525FF3D2252C41CF001F030E /* JPCardScanController.m */, + 525FF3D0252C41CF001F030E /* JPCardScanControllerDelegate.h */, 525FF3D3252C41CF001F030E /* View */, ); name = CardScanController; @@ -2703,10 +2699,10 @@ 525FF3D3252C41CF001F030E /* View */ = { isa = PBXGroup; children = ( - 525FF3D4252C41CF001F030E /* JPCardScanView.m */, 525FF3D5252C41CF001F030E /* JPCardScanPreviewLayer.h */, - 525FF3D6252C41CF001F030E /* JPCardScanView.h */, 525FF3D7252C41CF001F030E /* JPCardScanPreviewLayer.m */, + 525FF3D6252C41CF001F030E /* JPCardScanView.h */, + 525FF3D4252C41CF001F030E /* JPCardScanView.m */, ); path = View; sourceTree = ""; @@ -2727,10 +2723,10 @@ 529CCB8323BE8A8700A8DBDD /* Header */ = { isa = PBXGroup; children = ( - 529CCB8B23BE8AA300A8DBDD /* JPPaymentMethodsEmptyHeaderView.h */, - 529CCB8C23BE8AA300A8DBDD /* JPPaymentMethodsEmptyHeaderView.m */, 529CCB8F23BE910500A8DBDD /* JPPaymentMethodsCardHeaderView.h */, 529CCB9023BE910500A8DBDD /* JPPaymentMethodsCardHeaderView.m */, + 529CCB8B23BE8AA300A8DBDD /* JPPaymentMethodsEmptyHeaderView.h */, + 529CCB8C23BE8AA300A8DBDD /* JPPaymentMethodsEmptyHeaderView.m */, ); path = Header; sourceTree = ""; @@ -2776,11 +2772,11 @@ 52B74D7423F98B4C009FE38C /* Transaction */ = { isa = PBXGroup; children = ( - 52B74D7523F98B4C009FE38C /* Presenter */, - 52B74D7B23F98B4C009FE38C /* View */, 52B74D8723F98B4C009FE38C /* Builder */, 52B74D8A23F98B4C009FE38C /* Interactor */, + 52B74D7523F98B4C009FE38C /* Presenter */, 52B74D8D23F98B4C009FE38C /* Router */, + 52B74D7B23F98B4C009FE38C /* View */, ); name = Transaction; path = Modules/Transaction; @@ -2800,9 +2796,9 @@ isa = PBXGroup; children = ( 30D363AC24B5BD3F0029BC86 /* JPCardDetailsMode.h */, + 4492116F2469F77900DF6D14 /* JPInputType.h */, 52B74D7823F98B4C009FE38C /* JPTransactionViewModel.h */, 52B74D7923F98B4C009FE38C /* JPTransactionViewModel.m */, - 4492116F2469F77900DF6D14 /* JPInputType.h */, ); path = ViewModels; sourceTree = ""; @@ -2892,6 +2888,7 @@ 529CCB7723BE775A00A8DBDD /* resources.bundle */, 30C22170235DC518000D6E3A /* icons.bundle */, 829330FE230AF0F900689DC4 /* Localizable.strings */, + AD3C03982885CE7200063947 /* CountriesList.json */, ); path = Resources; sourceTree = ""; @@ -2950,11 +2947,20 @@ path = CardTransactionDetails; sourceTree = ""; }; + AD13DC0528831297002B82CD /* NetworkTimeout */ = { + isa = PBXGroup; + children = ( + AD13DC0728831297002B82CD /* JPNetworkTimeout.h */, + AD13DC0628831297002B82CD /* JPNetworkTimeout.m */, + ); + path = NetworkTimeout; + sourceTree = ""; + }; ADB514AD286DECB600332E47 /* JPResponse */ = { isa = PBXGroup; children = ( - ADB514AE286DECB600332E47 /* JPResponse+Additions.m */, ADB514AF286DECB600332E47 /* JPResponse+Additions.h */, + ADB514AE286DECB600332E47 /* JPResponse+Additions.m */, ); name = JPResponse; path = Extensions/JPResponse; @@ -3075,7 +3081,6 @@ 30221C1123FE617300BF2823 /* NSLayoutConstraint+Additions.h in Headers */, 30D61D6823BB741A004E5CEE /* JPPaymentMethodsView.h in Headers */, 3058351E2406583400B61167 /* JPCardCustomizationSubmitCell.h in Headers */, - 44A60A25288AB0F800B360E1 /* JPNetworkTimeout.h in Headers */, 30006F6223F698A20099F3C5 /* JPInputField.h in Headers */, 300072E123F6AB560099F3C5 /* JPAddress.h in Headers */, 30006F9D23F6993A0099F3C5 /* UIStackView+Additions.h in Headers */, @@ -3117,6 +3122,7 @@ 30221CBE24040F4D00BF2823 /* JPCardCustomizationTextInputCell.h in Headers */, 300072E323F6AB560099F3C5 /* JPResponse.h in Headers */, 52D23DB325248B6B007C79EB /* JPApplePayTypes.h in Headers */, + AD13DC0928831297002B82CD /* JPNetworkTimeout.h in Headers */, 52B4CA26241EF5B6009C28DC /* JPPaymentMethodsIDEALBankCell.h in Headers */, ADB514B5286DECE300332E47 /* JPCardTransactionDetails+Additions.h in Headers */, 300072C523F6AB560099F3C5 /* JPValidationResult.h in Headers */, @@ -3261,6 +3267,7 @@ files = ( 30D0894023901F1F00480C9E /* icons.bundle in Resources */, 829330FC230AF0F900689DC4 /* Localizable.strings in Resources */, + AD3C03992885CE8C00063947 /* CountriesList.json in Resources */, 529CCB7F23BE775B00A8DBDD /* resources.bundle in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -3321,7 +3328,7 @@ 300072DF23F6AB560099F3C5 /* JPCountry.m in Sources */, 4431198C24B3345200BF961C /* JPRequest+Additions.m in Sources */, 30006F9B23F6993A0099F3C5 /* UIApplication+Additions.m in Sources */, - 44A60A24288AB0F800B360E1 /* JPNetworkTimeout.m in Sources */, + AD13DC0828831297002B82CD /* JPNetworkTimeout.m in Sources */, 30221C3523FE6D9200BF2823 /* JPCardCustomizationInteractor.m in Sources */, 52B4CA44241EF7AA009C28DC /* JPIDEALViewController.m in Sources */, 300072F823F6AB560099F3C5 /* JPReference.m in Sources */, @@ -3455,7 +3462,6 @@ 0777BA0F247BC9BB00867B9F /* JPPaymentMethodsViewControllerMock.swift in Sources */, 07AA4FF924BDECDF00C21CEA /* JPCountryTest.swift in Sources */, 0777B9F7247BC9BB00867B9F /* JP3DSConfigurationTest.swift in Sources */, - 0777BA1B247BCA3C00867B9F /* JPPBBAServiceTest.swift in Sources */, 0777BA15247BC9BB00867B9F /* JPPaymentMethodsRouterTest.swift in Sources */, 0777BA11247BC9BB00867B9F /* JPApiServiceStub.swift in Sources */, 30D3643424B874060029BC86 /* JPSectionTest.swift in Sources */, @@ -3466,9 +3472,11 @@ 300F939024CADBAC003DECA5 /* JPBankOrderRequestTests.swift in Sources */, 0777B9E4247BC9BB00867B9F /* JPUKPostCodeValidation.swift in Sources */, 0777BA13247BC9BB00867B9F /* JPPaymentMethodsPresenterTest.swift in Sources */, + AD4B368D2882E1AE00289CB7 /* JPPBBAServiceTest.swift in Sources */, 0777B9F9247BC9BB00867B9F /* SDKInfoTest.swift in Sources */, 300F938C24C9BED5003DECA5 /* JPApplePayRequestTests.swift in Sources */, 0777BA01247BC9BB00867B9F /* NSLayoutConstraintAdditionsTests.swift in Sources */, + AD13DC1828831C07002B82CD /* JPPaymentMethodsTest.swift in Sources */, 0777B9FB247BC9BB00867B9F /* JPCardStorageTest.swift in Sources */, 0777BA12247BC9BB00867B9F /* JPPaymentMethodsInteractorMock.swift in Sources */, 30D3640E24B873790029BC86 /* UIColorAdditionsTest.swift in Sources */, @@ -3498,8 +3506,8 @@ 0777B9E8247BC9BB00867B9F /* JPIDEALServiceTest.swift in Sources */, 0777BA14247BC9BB00867B9F /* JPPaymentMethodsInteractorTest.swift in Sources */, 0777BA07247BC9BB00867B9F /* JPTransactionPresenterTests.swift in Sources */, + AD4B368B2882E18600289CB7 /* JPTransactionRouterMock.swift in Sources */, 0777B9FF247BC9BB00867B9F /* CLLocationAdditionsTest.swift in Sources */, - 0777B9EC247BC9BB00867B9F /* JPApplePayServiceTest.swift in Sources */, 0777B9E6247BC9BB00867B9F /* JPCanadaPostCodeValidation.swift in Sources */, 30D3640024B5FAC00029BC86 /* JPApiServicePBBAStub.swift in Sources */, 30D3641424B873B20029BC86 /* JPConsumerDeviceTest.swift in Sources */, @@ -3510,10 +3518,10 @@ 0777B9FA247BC9BB00867B9F /* JPContactInformationTest.swift in Sources */, 0777B9EA247BC9BB00867B9F /* JPConfigurationValidationServiceTest.swift in Sources */, 300F938A24C9BD31003DECA5 /* JPTokenRequestTests.swift in Sources */, - 0777BA06247BC9BB00867B9F /* JPTransactionRouterMock.swift in Sources */, 0777B9F3247BC9BB00867B9F /* JPCardTest.swift in Sources */, 0777B9FE247BC9BB00867B9F /* NSBundleAdditionsTests.swift in Sources */, 300F938E24CADB28003DECA5 /* JPCheckCardRequestTests.swift in Sources */, + AD4B368C2882E19A00289CB7 /* JPApplePayServiceTest.swift in Sources */, 30D3641724B873B90029BC86 /* JPEnhancedPaymentDetailTest.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/JudoKit_iOSTests/JudoKit_iOSTests-Bridging-Header.h b/JudoKit_iOSTests/JudoKit_iOSTests-Bridging-Header.h index 6ea130798..1b06b07c8 100644 --- a/JudoKit_iOSTests/JudoKit_iOSTests-Bridging-Header.h +++ b/JudoKit_iOSTests/JudoKit_iOSTests-Bridging-Header.h @@ -55,7 +55,6 @@ #import "UIApplication+Additions.h" #import "JPAmount.h" #import "JPCard.h" -#import "JPCardDetails.h" #import "JudoKit.h" #import "JP3DSConfiguration.h" #import "UIImage+Additions.h" @@ -64,3 +63,5 @@ #import "JPPBBAService.h" #import "JPAuthorization.h" #import "JPSessionAuthorization.h" +#import "JPInputType.h" +#import "JPCardDetailsMode.h" diff --git a/JudoKit_iOSTests/Models/JPAddress/JPAddressTests.swift b/JudoKit_iOSTests/Models/JPAddress/JPAddressTests.swift index 628e7e0ef..b1fd88e4f 100644 --- a/JudoKit_iOSTests/Models/JPAddress/JPAddressTests.swift +++ b/JudoKit_iOSTests/Models/JPAddress/JPAddressTests.swift @@ -51,7 +51,6 @@ class JPAddressTests: XCTestCase { address2: "line2", address3: "line3", town: "town", - billingCountry: "billingCountry", postCode: "postCode", countryCode: 123) @@ -75,7 +74,6 @@ class JPAddressTests: XCTestCase { XCTAssertEqual(address.address2, "line2") XCTAssertEqual(address.address3, "line3") XCTAssertEqual(address.town, "town") - XCTAssertEqual(address.billingCountry, "billingCountry") XCTAssertEqual(address.postCode, "postCode") XCTAssertEqual(address.countryCode, 123) } diff --git a/JudoKit_iOSTests/Models/JPClientDetails/JPClientDetailsTest.swift b/JudoKit_iOSTests/Models/JPClientDetails/JPClientDetailsTest.swift index 18b7a9c79..4b184d299 100644 --- a/JudoKit_iOSTests/Models/JPClientDetails/JPClientDetailsTest.swift +++ b/JudoKit_iOSTests/Models/JPClientDetails/JPClientDetailsTest.swift @@ -60,7 +60,7 @@ class JPClientDetailsTest: XCTestCase { */ func test_ToDictionary_WhenDesignatedInit_ShouldCreateDictionaryFromObject() { let sut = JPClientDetails(key: "key", value: "value") - let dic = sut.toDictionary() + let dic = sut._jp_toDictionary() XCTAssertEqual(dic as! Dictionary, ["key":"key", "value":"value"]) } } diff --git a/JudoKit_iOSTests/Models/JPConsumerDevice/JPConsumerDeviceTest.swift b/JudoKit_iOSTests/Models/JPConsumerDevice/JPConsumerDeviceTest.swift index d84d6d1a9..7ca9e974f 100644 --- a/JudoKit_iOSTests/Models/JPConsumerDevice/JPConsumerDeviceTest.swift +++ b/JudoKit_iOSTests/Models/JPConsumerDevice/JPConsumerDeviceTest.swift @@ -67,7 +67,7 @@ class JPConsumerDeviceTest: XCTestCase { */ func test_ToDictionary_WhenDesignatedInit_ShouldCreateDictionaryFromObject() { let sut = JPConsumerDevice.init(ipAddress: "ip", clientDetails: client, geoLocation: location, threeDSecure: secure) - let dic = sut.toDictionary() as NSDictionary + let dic = sut._jp_toDictionary() as NSDictionary XCTAssertEqual(dic["ClientDetails"] as! Dictionary, ["key": "key", "value": "value"]) XCTAssertEqual(dic["IpAddress"] as! String, "ip") XCTAssertEqual(dic["PaymentType"] as! String, "ECOMM") diff --git a/JudoKit_iOSTests/Models/JPCountry/JPCountryTest.swift b/JudoKit_iOSTests/Models/JPCountry/JPCountryTest.swift index 1855463c4..c09e922f1 100644 --- a/JudoKit_iOSTests/Models/JPCountry/JPCountryTest.swift +++ b/JudoKit_iOSTests/Models/JPCountry/JPCountryTest.swift @@ -33,7 +33,7 @@ class JPCountryTest: XCTestCase { * THEN: should return 826 numeric code */ func test_isoCodeForCountry_WhenUK_ShouldReturnRightISOCode() { - XCTAssertEqual(JPCountry.isoCode(forCountry: "UK"), 826) + XCTAssertEqual(JPCountry.isoCode(forCountry: "United Kingdom"), 826) } /* @@ -44,7 +44,7 @@ class JPCountryTest: XCTestCase { * THEN: should return 840 numeric code */ func test_isoCodeForCountry_WhenUSA_ShouldReturnRightISOCode() { - XCTAssertEqual(JPCountry.isoCode(forCountry: "USA"), 840) + XCTAssertEqual(JPCountry.isoCode(forCountry: "United States"), 840) } /* diff --git a/JudoKit_iOSTests/Models/JPEnhancedPaymentDetail/JPEnhancedPaymentDetailTest.swift b/JudoKit_iOSTests/Models/JPEnhancedPaymentDetail/JPEnhancedPaymentDetailTest.swift index 12ddea588..1ae4df7d1 100644 --- a/JudoKit_iOSTests/Models/JPEnhancedPaymentDetail/JPEnhancedPaymentDetailTest.swift +++ b/JudoKit_iOSTests/Models/JPEnhancedPaymentDetail/JPEnhancedPaymentDetailTest.swift @@ -70,7 +70,7 @@ class JPEnhancedPaymentDetailTest: XCTestCase { */ func test_ToDictionary_WhenDesignatedInit_ShouldCreateDictionaryFromObject() { let sut = JPEnhancedPaymentDetail.init(sdkInfo: sdkInfo, consumerDevice: consumerDevice) - let dic = sut.toDictionary() as NSDictionary + let dic = sut._jp_toDictionary() as NSDictionary XCTAssertEqual(dic.object(forKey: "SDK_INFO") as! Dictionary, ["Version":"version", "Name": "name"]) let consumerDevice = dic.object(forKey: "ConsumerDevice") as! Dictionary XCTAssertEqual(consumerDevice["ClientDetails"] as! Dictionary, ["key": "key", "value": "value"]) diff --git a/JudoKit_iOSTests/Models/Requests/JPPaymentRequestTests.swift b/JudoKit_iOSTests/Models/Requests/JPPaymentRequestTests.swift index f6ac8d98e..38e7b5c5e 100644 --- a/JudoKit_iOSTests/Models/Requests/JPPaymentRequestTests.swift +++ b/JudoKit_iOSTests/Models/Requests/JPPaymentRequestTests.swift @@ -72,7 +72,6 @@ class JPPaymentRequestTests: XCTestCase { address2: "Line 2", address3: "Line 3", town: "Town", - billingCountry: "Billing Country", postCode: "Postcode", countryCode: 123) @@ -95,7 +94,6 @@ class JPPaymentRequestTests: XCTestCase { XCTAssertEqual(paymentRequest.cardAddress?.address2, cardDetails.cardAddress?.address2) XCTAssertEqual(paymentRequest.cardAddress?.address3, cardDetails.cardAddress?.address3) XCTAssertEqual(paymentRequest.cardAddress?.town, cardDetails.cardAddress?.town) - XCTAssertEqual(paymentRequest.cardAddress?.billingCountry, cardDetails.cardAddress?.billingCountry) XCTAssertEqual(paymentRequest.cardAddress?.countryCode, cardDetails.cardAddress?.countryCode) XCTAssertEqual(paymentRequest.cardAddress?.postCode, cardDetails.cardAddress?.postCode) } diff --git a/JudoKit_iOSTests/Modules/CardStorage/CardStorageTest.swift b/JudoKit_iOSTests/Modules/CardStorage/CardStorageTest.swift deleted file mode 100644 index f0c1cd202..000000000 --- a/JudoKit_iOSTests/Modules/CardStorage/CardStorageTest.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// CardStorageTest.swift -// JudoKit_iOSTests -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import XCTest - -@testable import JudoKit_iOS - -class CardStorageTest: XCTestCase { - - func testSetCardAsDefaultAtIndex() { - self.addTestCardsInStorage() - JPCardStorage.sharedInstance()?.setCardDefaultState(true, at: 2); - let storedCardsDetails:[JPStoredCardDetails] = JPCardStorage.sharedInstance()?.fetchStoredCardDetails() as! [JPStoredCardDetails] - let selectedCard = storedCardsDetails[0]; - XCTAssert(selectedCard.cardLastFour == "3333") - XCTAssert(selectedCard.expiryDate == "23/23") - XCTAssert(selectedCard.cardNetwork == .JCB) - XCTAssert(selectedCard.cardToken == "cardToken3") - } - - func addTestCardsInStorage() { - let firstStoredCard = JPStoredCardDetails(lastFour: "1111", expiryDate: "11/21", cardNetwork: .visa, cardToken: "cardToken1") - let secondStoredCard = JPStoredCardDetails(lastFour: "2222", expiryDate: "22/22", cardNetwork: .masterCard, cardToken: "cardToken2") - let thirdStoredCard = JPStoredCardDetails(lastFour: "3333", expiryDate: "23/23", cardNetwork: .JCB, cardToken: "cardToken3") - let forthStoredCard = JPStoredCardDetails(lastFour: "4444", expiryDate: "24/24", cardNetwork: .AMEX, cardToken: "cardToken4") - - JPCardStorage.sharedInstance()?.deleteCardDetails() - JPCardStorage.sharedInstance()?.add(firstStoredCard) - JPCardStorage.sharedInstance()?.add(secondStoredCard) - JPCardStorage.sharedInstance()?.add(thirdStoredCard) - JPCardStorage.sharedInstance()?.add(forthStoredCard) - - } -} diff --git a/JudoKit_iOSTests/Modules/PaymentMethods/JPPaymentMethodsTest.swift b/JudoKit_iOSTests/Modules/PaymentMethods/JPPaymentMethodsTest.swift index 4d37bd380..f9b9319aa 100644 --- a/JudoKit_iOSTests/Modules/PaymentMethods/JPPaymentMethodsTest.swift +++ b/JudoKit_iOSTests/Modules/PaymentMethods/JPPaymentMethodsTest.swift @@ -32,6 +32,7 @@ class JPPaymentMethodsTest: XCTestCase { let presenter = JPPaymentMethodsPresenterImpl() let viewController = JPPaymentMethodsViewControllerMock() let interactor = JPPaymentMethodsInteractorMock() + interactor.saveMockCards() presenter.view = viewController presenter.interactor = interactor presenter.viewModelNeedsUpdate() diff --git a/JudoKit_iOSTests/Modules/PaymentMethods/Mocks/JPApiServicePBBAStub.swift b/JudoKit_iOSTests/Modules/PaymentMethods/Mocks/JPApiServicePBBAStub.swift deleted file mode 100644 index fea6f9f59..000000000 --- a/JudoKit_iOSTests/Modules/PaymentMethods/Mocks/JPApiServicePBBAStub.swift +++ /dev/null @@ -1,9 +0,0 @@ -// -// JPApiServicePBBAStub.swift -// JudoKit_iOSTests -// -// Created by Mihai Petrenco on 7/8/20. -// Copyright © 2020 Judo Payments. All rights reserved. -// - -import Foundation diff --git a/JudoKit_iOSTests/Modules/PaymentMethods/Mocks/JPPaymentMethodsInteractorMock.swift b/JudoKit_iOSTests/Modules/PaymentMethods/Mocks/JPPaymentMethodsInteractorMock.swift index b54fafcf2..3dd107fd1 100644 --- a/JudoKit_iOSTests/Modules/PaymentMethods/Mocks/JPPaymentMethodsInteractorMock.swift +++ b/JudoKit_iOSTests/Modules/PaymentMethods/Mocks/JPPaymentMethodsInteractorMock.swift @@ -148,7 +148,8 @@ class JPPaymentMethodsInteractorMock: JPPaymentMethodsInteractor { let validCard = JPStoredCardDetails(lastFour: "1111", expiryDate: notExpiredDateAsString, cardNetwork: .visa, cardToken: "token")! let expiresSoonCard = JPStoredCardDetails(lastFour: "1111", expiryDate: expiresSoonDateAsString, cardNetwork: .visa, cardToken: "token")! let expirdCard = JPStoredCardDetails(lastFour: "1111", expiryDate: expiredDateAsString, cardNetwork: .visa, cardToken: "token")! - + + JPCardStorage.sharedInstance()?.deleteCardDetails() JPCardStorage.sharedInstance()?.add(validCard) JPCardStorage.sharedInstance()?.add(expiresSoonCard) JPCardStorage.sharedInstance()?.add(expirdCard) diff --git a/JudoKit_iOSTests/Modules/Sevices/CardInputValidator/JPCardValidationServiceTest.swift b/JudoKit_iOSTests/Modules/Sevices/CardInputValidator/JPCardValidationServiceTest.swift deleted file mode 100644 index f88402501..000000000 --- a/JudoKit_iOSTests/Modules/Sevices/CardInputValidator/JPCardValidationServiceTest.swift +++ /dev/null @@ -1,171 +0,0 @@ -// -// JPCardValidationServiceTest.swift -// JudoKit_iOSTests -// -// Copyright (c) 2020 Alternative Payments Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import XCTest - -@testable import JudoKit_iOS - -class JPCardValidationServiceTest: XCTestCase { - var configuration: JPConfiguration! = nil - let validationService = JPCardValidationService() - var sut: JPTransactionInteractor! = nil - lazy var reference = JPReference(consumerReference: "consumerReference") - - override func setUp() { - let amount = JPAmount("0.01", currency: "GBR") - configuration = JPConfiguration(judoID: "judoId", amount: amount, reference: reference) - configuration.supportedCardNetworks = [.visa, .masterCard, .AMEX, .dinersClub] - - sut = JPTransactionInteractorImpl(cardValidationService: validationService, transactionService: nil, configuration:configuration, completion: nil) - } - - func testLuhnValidVisa() { - let result = sut.validateCardNumberInput("4929939187355598") - XCTAssertEqual(result!.formattedInput, "4929 9391 8735 5598") - XCTAssertTrue(result!.isValid) - } - - func testLuhnInValidVisa() { - let result = sut.validateCardNumberInput("4129939187355598") - XCTAssertFalse(result!.isValid) - } - - func testValidCardWithSpecialCharacters() { - let result = sut.validateCardNumberInput("41299391873555+!") - XCTAssertFalse(result!.isValid) - } - - func testLuhnValidMaster() { - let result = sut.validateCardNumberInput("5454422955385717") - XCTAssertTrue(result!.isValid) - } - - func testLuhnInValidMaster() { - let result = sut.validateCardNumberInput("5454452295585717") - XCTAssertFalse(result!.isValid) - } - - func testLuhnValidAmex() { - let result = sut.validateCardNumberInput("348570250878868") - XCTAssertEqual(result!.formattedInput, "3485 702508 78868") - XCTAssertTrue(result!.isValid) - } - - func testForValidDiner() { - let result = sut.validateCardNumberInput("30260943491310") - XCTAssertEqual(result!.formattedInput, "3026 094349 1310") - XCTAssertTrue(result!.isValid) - } - - func testLuhnInValidAmex() { - let result = sut.validateCardNumberInput("348570250872868") - XCTAssertFalse(result!.isValid) - } - - func testFormatedIncompleteLenghtAmex() { - let result = sut.validateCardNumberInput("34857025087") - XCTAssertEqual(result!.formattedInput, "3485 702508 7") - } - - func testBiggerFormatedMaximumLenghtVisa() { - let result = sut.validateCardNumberInput("4929939187355598111") - XCTAssertEqual(result!.formattedInput, "4929 9391 8735 5598") - } - - func testFormatedIncompleteLenghtVisa() { - let result = sut.validateCardNumberInput("492993918") - XCTAssertEqual(result!.formattedInput, "4929 9391 8") - } - - func testForTypeRecognizeVisa() { - let result = sut.validateCardNumberInput("4") - XCTAssertEqual(result!.cardNetwork, .visa) - } - - func testForTypeRecognizeUnknown() { - let result = sut.validateCardNumberInput("3") - let unKnownType = JPCardNetworkType(rawValue: 0) - XCTAssertEqual(result!.cardNetwork, unKnownType) - } - - func testForTypeRecognizeMaster() { - let result = sut.validateCardNumberInput("52") - XCTAssertEqual(result!.cardNetwork, .masterCard) - } - - func testForTypeRecognizeAmex() { - let result = sut.validateCardNumberInput("34") - XCTAssertEqual(result!.cardNetwork, .AMEX) - } - - func testForTypeRecognizeDiscover() { - let result = sut.validateCardNumberInput("65") - XCTAssertEqual(result!.cardNetwork, .discover) - } - - func testForTypeRecognizeJCB() { - let result = sut.validateCardNumberInput("3528") - XCTAssertEqual(result!.cardNetwork, .JCB) - } - - func testForTypeRecognizeDiners() { - let result = sut.validateCardNumberInput("36") - XCTAssertEqual(result!.cardNetwork, .dinersClub) - } - - func testForTypeRecognizeMaestro() { - let result = sut.validateCardNumberInput("5018") - XCTAssertEqual(result!.cardNetwork, .maestro) - } - - func testForTypeRecognizeChina() { - let result = sut.validateCardNumberInput("62") - XCTAssertEqual(result!.cardNetwork, .chinaUnionPay) - } - - func testForChangingType() { - var result = sut.validateCardNumberInput("36") - XCTAssertEqual(result!.cardNetwork, .dinersClub) - result = sut.validateCardNumberInput("62") - XCTAssertEqual(result!.cardNetwork, .chinaUnionPay) - } - - func testUnsuportedTypeFromConfig() { - configuration.supportedCardNetworks = [.visa] - let result = sut.validateCardNumberInput("30260943491310") - XCTAssertFalse(result!.isValid) - } - - func testUnsuportedErrorTypeFromConfig() { - configuration.supportedCardNetworks = [.visa] - let result = sut.validateCardNumberInput("30260943491310") - let cardNetworkString = JPCardNetwork.name(of: result!.cardNetwork) - XCTAssertEqual(result!.errorMessage!, "\(cardNetworkString!) is not supported") - } - - func testErrorStringForInvalidCardNumber() { - let result = sut.validateCardNumberInput("4129939187355598") - XCTAssertEqual(result!.errorMessage!, "Check card number") - } -} diff --git a/JudoKit_iOSTests/Modules/Sevices/ConfigurationValidator/JPAppleConfigurationValidationServiceTest.swift b/JudoKit_iOSTests/Modules/Sevices/ConfigurationValidator/JPAppleConfigurationValidationServiceTest.swift deleted file mode 100644 index 54f1cce0f..000000000 --- a/JudoKit_iOSTests/Modules/Sevices/ConfigurationValidator/JPAppleConfigurationValidationServiceTest.swift +++ /dev/null @@ -1,96 +0,0 @@ -// -// JPConfigurationValidationServiceTest.swift -// JudoKit_iOSTests -// -// Copyright (c) 2020 Alternative Payments Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import XCTest - -@testable import JudoKit_iOS - -class JPAppleConfigurationValidationServiceTest: XCTestCase { - var amount: JPAmount! - var configuration: JPConfiguration! - let consumerReference = "judoPay-sample-app" - var configValidation: JPConfigurationValidationService! - lazy var reference = JPReference(consumerReference: consumerReference) - - var applePayConfigurations: JPApplePayConfiguration { - let items = [JPPaymentSummaryItem(label: "item 1", amount: 0.01), - JPPaymentSummaryItem(label: "item 2", amount: 0.02), - JPPaymentSummaryItem(label: "Judo Pay", amount: 0.03)] - let configurations = JPApplePayConfiguration(merchantId: "merchantId", - currency: "EUR", - countryCode: "GB", - paymentSummaryItems: items) - return configurations - } - - override func setUp() { - configValidation = JPConfigurationValidationServiceImp() - amount = JPAmount("fv", currency: "GBR") - configuration = JPConfiguration(judoID: "judoId", amount: self.amount, reference: reference) - configuration.supportedCardNetworks = [.visa, .masterCard, .AMEX] - configuration.applePayConfiguration = applePayConfigurations - } - - func testAppleConfigIfValid() { - let error = configValidation.validateApplePay(configuration) - XCTAssertNil(error, "Error must be nil for a valid Apple Pay configuration") - } - - func testAppleConfigForNil() { - configuration.applePayConfiguration = nil - let error = configValidation.validateApplePay(configuration) - XCTAssertNotNil(error, "Error must not be nil for an invalid Apple Pay configuration") - } - - func testAppleConfigForPaymentSummaryItemsEmpty() { - configuration.applePayConfiguration?.paymentSummaryItems.removeAll() - let error = configValidation.validateApplePay(configuration) - XCTAssertNotNil(error, "Error must not be nil when no Payment Summary Items are present") - } - - func testAppleConfigForShipingMethods() { - configuration.applePayConfiguration?.requiredShippingContactFields = .postalAddress - configuration.applePayConfiguration?.shippingMethods?.removeAll() - let error = configValidation.validateApplePay(configuration) - XCTAssertNotNil(error, "Error must not be nil when no Shipping Methods are specified") - } - - func testAppleConfigForInvalidCountryCode() { - configuration.applePayConfiguration?.countryCode = "" - let error = configValidation.validateApplePay(configuration) - XCTAssertNotNil(error, "Error must not be nil when no Country Code is specified") - } - - func testAppleConfigForInvalidMerchantId() { - configuration.applePayConfiguration?.merchantId = "" - let error = configValidation.validateApplePay(configuration) - XCTAssertNotNil(error, "Error must not be nil when no Merchant ID is specified") - } - - func testAppleConfigForUnsuportedCurrency() { - configuration.applePayConfiguration?.currency = "XYZ" - let error = configValidation.validateApplePay(configuration) - XCTAssertNotNil(error, "Error must not be nil when the Currency Code is invalid") - } -} diff --git a/JudoKit_iOSTests/Modules/Sevices/ConfigurationValidator/JPConfigurationValidationServiceTest.swift b/JudoKit_iOSTests/Modules/Sevices/ConfigurationValidator/JPConfigurationValidationServiceTest.swift deleted file mode 100644 index c465e4cd8..000000000 --- a/JudoKit_iOSTests/Modules/Sevices/ConfigurationValidator/JPConfigurationValidationServiceTest.swift +++ /dev/null @@ -1,67 +0,0 @@ -// -// JPConfigurationValidationServiceTest.swift -// JudoKit_iOSTests -// -// Copyright (c) 2020 Alternative Payments Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import XCTest - -@testable import JudoKit_iOS - -class JPConfigurationValidationServiceTest: XCTestCase { - var amount: JPAmount! - var configuration: JPConfiguration! - let consumerReference = "judoPay-sample-app" - var configValidation: JPConfigurationValidationService! - lazy var reference = JPReference(consumerReference: consumerReference) - - override func setUp() { - configValidation = JPConfigurationValidationServiceImp() - amount = JPAmount("fv", currency: "GBR") - configuration = JPConfiguration(judoID: "judoId", amount: self.amount, reference: reference) - configuration.supportedCardNetworks = [.visa, .masterCard, .AMEX] - } - - func testInvalidCharacters() { - let error = configValidation.validate(configuration, for: .payment) - XCTAssertNotNil(error, "Error must not be nil when invalid amount is specified") - } - - func testEmptyCurrency() { - amount = JPAmount("0.1", currency: "") - configuration.amount = amount - let error = configValidation.validate(configuration, for: .payment) - XCTAssertNotNil(error, "Error must not be nil when no curency is specified") - } - - func testNilConfiguration() { - configuration = nil - let error = configValidation.validate(configuration, for: .payment) - XCTAssertNotNil(error, "Error must not be nil when nil configuration is specified") - } - - func testConsumerReferenceInvalid() { - let reference40Characters = String(repeating: "J", count: Int(kMaximumLengthForConsumerReference + 1)) - configuration.reference = JPReference(consumerReference: reference40Characters) - let error = configValidation.validate(configuration, for: .payment) - XCTAssertNotNil(error, "Error must not be nil when the consumer reference is larger than 40 characters") - } -} diff --git a/JudoKit_iOSTests/Modules/Sevices/PaymentMethod/JPPaymentMethodsInteractorTest.swift b/JudoKit_iOSTests/Modules/Sevices/PaymentMethod/JPPaymentMethodsInteractorTest.swift deleted file mode 100644 index ce7ef25db..000000000 --- a/JudoKit_iOSTests/Modules/Sevices/PaymentMethod/JPPaymentMethodsInteractorTest.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// JPPaymentMethodsInteractorTest.swift -// JudoKit_iOSTests -// -// Copyright (c) 2020 Alternative Payments Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import XCTest - -@testable import JudoKit_iOS - -class JPPaymentMethodsInteractorTest: XCTestCase { - var sut: JPPaymentMethodsInteractor! - let configuration = JPConfiguration(judoID: "judoId", amount: JPAmount("fv", currency: "GBR"), reference: JPReference(consumerReference: "consumerReference")) - - override func setUp() { - super.setUp() - configuration.supportedCardNetworks = [.visa, .masterCard, .AMEX] - let service = JPTransactionService() - sut = JPPaymentMethodsInteractorImpl(mode: .serverToServer, configuration: configuration, transactionService: service, completion: nil) - } - - func testServerToServer() { - let completion: JPCompletionBlock = { (response, error) in - XCTAssertNotNil(response) - XCTAssertNil(error) - } - sut.paymentTransaction(withToken: "", andCompletion: completion) - } - - func testServerToServerApple() { - let completion: JPCompletionBlock = { (response, error) in - XCTAssertNotNil(response) - XCTAssertNil(error) - } - sut.startApplePay(completion: completion) - } -} diff --git a/JudoKit_iOSTests/Modules/Sevices/PostCodesValidation/JPCanadaPostCodeValidation.swift b/JudoKit_iOSTests/Modules/Sevices/PostCodesValidation/JPCanadaPostCodeValidation.swift deleted file mode 100644 index 01eeaa58d..000000000 --- a/JudoKit_iOSTests/Modules/Sevices/PostCodesValidation/JPCanadaPostCodeValidation.swift +++ /dev/null @@ -1,70 +0,0 @@ -// -// JPCanadaPostCodeValidation.swift -// JudoKit_iOSTests -// -// Copyright (c) 2020 Alternative Payments Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import XCTest - -@testable import JudoKit_iOS - -class JPCanadaPostCodeValidation: XCTestCase { - let validationService = JPCardValidationService() - var sut: JPTransactionInteractor! = nil - let configuration = JPConfiguration(judoID: "judoId", - amount: JPAmount("0.01", currency: "GBR"), - reference: JPReference(consumerReference: "consumerReference")) - - override func setUp() { - configuration.supportedCardNetworks = [.visa, .masterCard, .AMEX, .dinersClub] - validationService.validateCountryInput("Canada") - sut = JPTransactionInteractorImpl(cardValidationService: validationService, transactionService: nil, configuration:configuration, completion: nil) - } - - func testValidCode_Canada() { - let result = sut.validatePostalCodeInput("A1A1A1")! - XCTAssertEqual(result.formattedInput, "A1A 1A1") - XCTAssertTrue(result.isValid) - } - - func testValidCodeWithSpaces_Canada() { - let result = sut.validatePostalCodeInput("A1A 1A1")! - XCTAssertEqual(result.formattedInput, "A1A 1A1") - XCTAssertTrue(result.isValid) - } - - func testInValidRegexSpecialSymbols_Canada() { - let result = sut.validatePostalCodeInput("A1! 1A1")! - XCTAssertEqual(result.errorMessage, "Invalid postcode entered") - XCTAssertFalse(result.isValid) - } - - func testEmptyCode_Canada() { - let result = sut.validatePostalCodeInput("") - XCTAssertFalse(result!.isValid) - } - - func testInValidRegexUndersScore_Canada() { - let result = sut.validatePostalCodeInput("A11_1A1")! - XCTAssertEqual(result.errorMessage, "Invalid postcode entered") - XCTAssertFalse(result.isValid) - } -} diff --git a/JudoKit_iOSTests/Modules/Sevices/PostCodesValidation/JPUKPostCodeValidation.swift b/JudoKit_iOSTests/Modules/Sevices/PostCodesValidation/JPUKPostCodeValidation.swift deleted file mode 100644 index 05d23adaa..000000000 --- a/JudoKit_iOSTests/Modules/Sevices/PostCodesValidation/JPUKPostCodeValidation.swift +++ /dev/null @@ -1,82 +0,0 @@ -// -// JPUKPostCodeValidation.swift -// JudoKit_iOSTests -// -// Copyright (c) 2020 Alternative Payments Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import XCTest - -@testable import JudoKit_iOS - -class JPUKPostCodeValidation: XCTestCase { - let validationService = JPCardValidationService() - var sut: JPTransactionInteractor! = nil - let configuration = JPConfiguration(judoID: "judoId", - amount: JPAmount("0.01", currency: "GBR"), - reference: JPReference(consumerReference: "consumerReference")) - - override func setUp() { - configuration.supportedCardNetworks = [.visa, .masterCard, .AMEX, .dinersClub] - validationService.validateCountryInput("UK") - sut = JPTransactionInteractorImpl(cardValidationService: validationService, transactionService: nil, configuration:configuration, completion: nil) - } - - func testValidCode_UK() { - let result = sut.validatePostalCodeInput("EC1A 1BB") - XCTAssertTrue(result!.isValid) - } - - func testValidCodeWithSpaces_UK() { - let result = sut.validatePostalCodeInput("M1 1AE") - XCTAssertTrue(result!.isValid) - } - - func testInValidRegexSpecialSymbols_UK() { - let result = sut.validatePostalCodeInput("B33 8TH") - XCTAssertTrue(result!.isValid) - } - - func testValidCodeWithSpacesWithoutSpaces_UK() { - let result = sut.validatePostalCodeInput("M11AE") - XCTAssertTrue(result!.isValid) - } - - func testInValidRegexSpecialSymbolsWithoutSpaces_UK() { - let result = sut.validatePostalCodeInput("B338TH") - XCTAssertTrue(result!.isValid) - } - - func testInValidErrorMessage_UK() { - let result = sut.validatePostalCodeInput("1 ABCD")! - XCTAssertEqual(result.errorMessage, "Invalid postcode entered") - XCTAssertFalse(result.isValid) - } - - func testInValidCharacters_UK() { - let result = sut.validatePostalCodeInput("B3@ 8TH") - XCTAssertFalse(result!.isValid) - } - - func testEmptyCode_UK() { - let result = sut.validatePostalCodeInput("") - XCTAssertFalse(result!.isValid) - } -} diff --git a/JudoKit_iOSTests/Modules/Sevices/PostCodesValidation/JPUSAPostCodeValidation.swift b/JudoKit_iOSTests/Modules/Sevices/PostCodesValidation/JPUSAPostCodeValidation.swift deleted file mode 100644 index 2607381db..000000000 --- a/JudoKit_iOSTests/Modules/Sevices/PostCodesValidation/JPUSAPostCodeValidation.swift +++ /dev/null @@ -1,82 +0,0 @@ -// -// JPUSAPostCodeValidation.swift -// JudoKit_iOSTests -// -// Copyright (c) 2020 Alternative Payments Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import XCTest - -@testable import JudoKit_iOS - -class JPUSAPostCodeValidation: XCTestCase { - let validationService = JPCardValidationService() - var sut: JPTransactionInteractor! = nil - let configuration = JPConfiguration(judoID: "judoId", - amount: JPAmount("0.01", currency: "GBR"), - reference: JPReference(consumerReference: "consumerReference")) - - override func setUp() { - configuration.supportedCardNetworks = [.visa, .masterCard, .AMEX, .dinersClub] - validationService.validateCountryInput("USA") - sut = JPTransactionInteractorImpl(cardValidationService: validationService, transactionService: nil, configuration:configuration, completion: nil) - } - - func testValidCode_US() { - let result = sut.validatePostalCodeInput("12345") - XCTAssertTrue(result!.isValid) - } - - func testValidCodeWithSpaces_US() { - let result = sut.validatePostalCodeInput("12345-6789") - XCTAssertTrue(result!.isValid) - } - - func testInValidCodeMiddleCharacter_US() { - let result = sut.validatePostalCodeInput("1234@") - XCTAssertFalse(result!.isValid) - } - - func testInValidCodeShort_US() { - let result = sut.validatePostalCodeInput("1234") - XCTAssertFalse(result!.isValid) - } - - func testInValidLastCharatcer_US() { - let result = sut.validatePostalCodeInput("12345-678@") - XCTAssertFalse(result!.isValid) - } - - func testInValidCodeWithSpaces_US() { - let result = sut.validatePostalCodeInput("12345 6789") - XCTAssertTrue(result!.isValid) - } - - func testInValidCodeError_US() { - let result = sut.validatePostalCodeInput("abcde-fghj")! - XCTAssertEqual(result.errorMessage, "Invalid ZIP code entered") - XCTAssertFalse(result.isValid) - } - - func testEmptyCode_US() { - let result = sut.validatePostalCodeInput("") - XCTAssertFalse(result!.isValid) - } -} diff --git a/JudoKit_iOSTests/Modules/Sevices/TransactionService/JPTransactionServiceTest.swift b/JudoKit_iOSTests/Modules/Sevices/TransactionService/JPTransactionServiceTest.swift deleted file mode 100644 index c45359ca3..000000000 --- a/JudoKit_iOSTests/Modules/Sevices/TransactionService/JPTransactionServiceTest.swift +++ /dev/null @@ -1,108 +0,0 @@ -// -// JPTransactionServiceTest.swift -// JudoKit_iOSTests -// -// Copyright (c) 2020 Alternative Payments Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import XCTest - -@testable import JudoKit_iOS - -class JPTransactionServiceTest: XCTestCase { - - let sut = JPTransactionService(token: "TOKEN", andSecret: "SECRET") - lazy var transactionAmmount = JPAmount("100.0", currency: "EUR") - lazy var transactionReference = JPReference(consumerReference: "consumerReference", - paymentReference: "PaymentReference") - lazy var transactionConfigurations = JPConfiguration(judoID: "JUDAID", - amount: transactionAmmount, - reference: transactionReference) - - override func tearDown() { - HTTPStubs.removeAllStubs() - super.tearDown() - } - - func testTransactionWithConfigurations() { - let transaction = sut.transaction(with: transactionConfigurations) - - XCTAssertEqual(transaction.amount!.amount, transactionAmmount.amount) - XCTAssertEqual(transaction.amount!.currency, transactionAmmount.currency) - XCTAssertEqual(transaction.reference!.consumerReference, transactionReference.consumerReference) - XCTAssertEqual(transaction.reference!.paymentReference, transactionReference.paymentReference) - } - - func testIsSandbox() { - XCTAssertFalse(sut.isSandboxed) - sut.isSandboxed = true - XCTAssertTrue(sut.isSandboxed) - } - - func testSendRequest() { - let stubObject = ["paymentMethod":"PBBA", - "siteId": "xxx-xxx-siteId", - "orderDetails": ["orderId": "xxx-orderid", - "orderStatus": "PENDING", - "timestamp": "2020-05-05T07:29:04.663Z", - "currency": "GBP", - "amount": 0.15, - "refundedAmount": 0.0], - "merchantPaymentReference": "xxx-xxx-ref_id", - "merchantConsumerReference": "reference"] as [String : Any] - - stub(condition: isHost("api.judopay.com")) { _ in - return HTTPStubsResponse(jsonObject: stubObject, statusCode: 200, headers: nil) - } - - let expectation = self.expectation(description: "expect") - - sut.sendRequest(withEndpoint: "order/bank/statusrequest/123", - httpMethod: .GET, - parameters: nil) { (response, error) in - XCTAssertEqual("xxx-xxx-siteId", response!.items!.first!.judoId) - XCTAssertEqual("PBBA", response!.items!.first!.paymentMethod) - XCTAssertEqual("xxx-xxx-ref_id", response!.items!.first!.paymentReference) - XCTAssertEqual(stubObject["siteId"] as! String, - response!.items!.first!.rawData["siteId"] as! String) - XCTAssertEqual(stubObject["paymentMethod"] as! String, - response!.items!.first!.rawData["paymentMethod"] as! String) - XCTAssertEqual(stubObject["merchantPaymentReference"] as! String, - response!.items!.first!.rawData["merchantPaymentReference"] as! String) - XCTAssertEqual(stubObject["merchantConsumerReference"] as! String, - response!.items!.first!.rawData["merchantConsumerReference"] as! String) - - let orderDetails = response!.items!.first!.rawData["orderDetails"] as! [String : Any] - let stubOrderDetails = stubObject["orderDetails"] as! [String : Any] - XCTAssertEqual(stubOrderDetails["orderId"] as! String, orderDetails["orderId"] as! String) - XCTAssertEqual(stubOrderDetails["orderStatus"] as! String, orderDetails["orderStatus"] as! String) - XCTAssertEqual(stubOrderDetails["timestamp"] as! String, orderDetails["timestamp"] as! String) - XCTAssertEqual(stubOrderDetails["currency"] as! String, orderDetails["currency"] as! String) - XCTAssertEqual(stubOrderDetails["amount"] as! Double, orderDetails["amount"] as! Double) - XCTAssertEqual(stubOrderDetails["refundedAmount"] as! Double, orderDetails["refundedAmount"] as! Double) - XCTAssertNil(error) - expectation.fulfill() - } - - waitForExpectations(timeout: 5, handler: nil) - } - -} - diff --git a/JudoKit_iOSTests/Modules/Transaction/Interactor/JPTransactionInteractorTest.swift b/JudoKit_iOSTests/Modules/Transaction/Interactor/JPTransactionInteractorTest.swift index 1c21c15a6..2191b45bb 100644 --- a/JudoKit_iOSTests/Modules/Transaction/Interactor/JPTransactionInteractorTest.swift +++ b/JudoKit_iOSTests/Modules/Transaction/Interactor/JPTransactionInteractorTest.swift @@ -96,8 +96,8 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_validateCardNumberInput_WhenLuhnValidVisa_ShouldFormatAndReturnValid() { let result = sut.validateCardNumberInput("4929939187355598") - XCTAssertEqual(result!.formattedInput, "4929 9391 8735 5598") - XCTAssertTrue(result!.isValid) + XCTAssertEqual(result.formattedInput, "4929 9391 8735 5598") + XCTAssertTrue(result.isValid) } /* * GIVEN: validate card number(Visa) @@ -108,7 +108,7 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_validateCardNumberInput_WhenLuhnValidVisa_ShouldReturnInValid() { let result = sut.validateCardNumberInput("4129939187355598") - XCTAssertFalse(result!.isValid) + XCTAssertFalse(result.isValid) } /* @@ -120,7 +120,7 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_validateCardNumberInput_WhenSpecialCharacters_ShouldReturnInValid() { let result = sut.validateCardNumberInput("41299391873555+!") - XCTAssertFalse(result!.isValid) + XCTAssertFalse(result.isValid) } /* @@ -132,7 +132,7 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_validateCardNumberInput_WhenLuhnValidMaster_ShouldReturnValid() { let result = sut.validateCardNumberInput("5454422955385717") - XCTAssertTrue(result!.isValid) + XCTAssertTrue(result.isValid) } /* @@ -144,7 +144,7 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_validateCardNumberInput_WhenLuhnInvalidMaster_ShouldReturnInValid() { let result = sut.validateCardNumberInput("5454452295585717") - XCTAssertFalse(result!.isValid) + XCTAssertFalse(result.isValid) } /* @@ -156,8 +156,8 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_validateCardNumberInput_WhenLuhnValidAmex_ShouldFormatAndReturnValid() { let result = sut.validateCardNumberInput("348570250878868") - XCTAssertEqual(result!.formattedInput, "3485 702508 78868") - XCTAssertTrue(result!.isValid) + XCTAssertEqual(result.formattedInput, "3485 702508 78868") + XCTAssertTrue(result.isValid) } /* @@ -169,8 +169,8 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_validateCardNumberInput_WhenLuhnValidDiner_ShouldFormatAndReturnValid() { let result = sut.validateCardNumberInput("30260943491310") - XCTAssertEqual(result!.formattedInput, "3026 094349 1310") - XCTAssertTrue(result!.isValid) + XCTAssertEqual(result.formattedInput, "3026 094349 1310") + XCTAssertTrue(result.isValid) } /* @@ -182,7 +182,7 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_ValidateCardNumberInput_WhenLuhnValid_ShouldReturnLuhnValidAmex() { let result = sut.validateCardNumberInput("348570250872868") - XCTAssertFalse(result!.isValid) + XCTAssertFalse(result.isValid) } /* @@ -194,7 +194,7 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_ValidateCardNumberInput_WhenAmexValid_ShouldFormateAmex() { let result = sut.validateCardNumberInput("34857025087") - XCTAssertEqual(result!.formattedInput, "3485 702508 7") + XCTAssertEqual(result.formattedInput, "3485 702508 7") } /* @@ -206,7 +206,7 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_ValidateCardNumberInput_WhenInputIsToLong_ShouldFormatInput() { let result = sut.validateCardNumberInput("4929939187355598111") - XCTAssertEqual(result!.formattedInput, "4929 9391 8735 5598") + XCTAssertEqual(result.formattedInput, "4929 9391 8735 5598") } /* @@ -218,7 +218,7 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_ValidateCardNumberInput_WhenInputIsLong_ShouldFormatInput() { let result = sut.validateCardNumberInput("492993918") - XCTAssertEqual(result!.formattedInput, "4929 9391 8") + XCTAssertEqual(result.formattedInput, "4929 9391 8") } /* @@ -230,7 +230,7 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_ValidateCardNumberInput_WhenInputIsVisa_ShouldRecognizeVisa() { let result = sut.validateCardNumberInput("4") - XCTAssertEqual(result!.cardNetwork, .visa) + XCTAssertEqual(result.cardNetwork, .visa) } /* @@ -243,7 +243,7 @@ class JPTransactionInteractorTest: XCTestCase { func test_ValidateCardNumberInput_WhenInputIsUnkwon_ShouldRecognizeUnknown() { let result = sut.validateCardNumberInput("3") let unKnownType = JPCardNetworkType(rawValue: 0) - XCTAssertEqual(result!.cardNetwork, unKnownType) + XCTAssertEqual(result.cardNetwork, unKnownType) } /* @@ -255,7 +255,7 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_ValidateCardNumberInput_WhenInputIsMasterCard_ShouldReturnMasterCard() { let result = sut.validateCardNumberInput("52") - XCTAssertEqual(result!.cardNetwork, .masterCard) + XCTAssertEqual(result.cardNetwork, .masterCard) } /* @@ -267,7 +267,7 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_ValidateCardNumberInput_WhenInputIsAMEX_ShouldReturnAMEX() { let result = sut.validateCardNumberInput("34") - XCTAssertEqual(result!.cardNetwork, .AMEX) + XCTAssertEqual(result.cardNetwork, .AMEX) } /* @@ -279,7 +279,7 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_ValidateCardNumberInput_WhenInputIsDiscover_ShouldReturnDiscover() { let result = sut.validateCardNumberInput("65") - XCTAssertEqual(result!.cardNetwork, .discover) + XCTAssertEqual(result.cardNetwork, .discover) } /* @@ -291,7 +291,7 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_ValidateCardNumberInput_WhenInputIsJCB_ShouldReturnJCB() { let result = sut.validateCardNumberInput("3528") - XCTAssertEqual(result!.cardNetwork, .JCB) + XCTAssertEqual(result.cardNetwork, .JCB) } /* @@ -303,7 +303,7 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_ValidateCardNumberInput_WhenInputIsDinersClub_ShouldReturnDinersClub() { let result = sut.validateCardNumberInput("36") - XCTAssertEqual(result!.cardNetwork, .dinersClub) + XCTAssertEqual(result.cardNetwork, .dinersClub) } /* @@ -315,7 +315,7 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_ValidateCardNumberInput_WhenInputIsMaestro_ShouldReturnMaestro() { let result = sut.validateCardNumberInput("5018") - XCTAssertEqual(result!.cardNetwork, .maestro) + XCTAssertEqual(result.cardNetwork, .maestro) } /* @@ -327,7 +327,7 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_ValidateCardNumberInput_WhenInputIsChinaPay_ShouldReturnChinaPay() { let result = sut.validateCardNumberInput("62") - XCTAssertEqual(result!.cardNetwork, .chinaUnionPay) + XCTAssertEqual(result.cardNetwork, .chinaUnionPay) } /* @@ -339,9 +339,9 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_ValidateCardNumberInput_WhenChangeInput_ShouldChangeResultType() { var result = sut.validateCardNumberInput("36") - XCTAssertEqual(result!.cardNetwork, .dinersClub) + XCTAssertEqual(result.cardNetwork, .dinersClub) result = sut.validateCardNumberInput("62") - XCTAssertEqual(result!.cardNetwork, .chinaUnionPay) + XCTAssertEqual(result.cardNetwork, .chinaUnionPay) } /* @@ -354,7 +354,7 @@ class JPTransactionInteractorTest: XCTestCase { func test_ValidateCardNumberInput_WhenSupportedCardVisaAndInputNotVisa_ShouldReturnUnsuportedType() { configuration.supportedCardNetworks = [.visa] let result = sut.validateCardNumberInput("30260943491310") - XCTAssertFalse(result!.isValid) + XCTAssertFalse(result.isValid) } /* @@ -367,8 +367,8 @@ class JPTransactionInteractorTest: XCTestCase { func test_ValidateCardNumberInput_WhenInputCardIsNotSupporteed_ShowUnsuportedErrorTypeFromConfig() { configuration.supportedCardNetworks = [.visa] let result = sut.validateCardNumberInput("30260943491310") - let cardNetworkString = JPCardNetwork.name(of: result!.cardNetwork) - XCTAssertEqual(result!.errorMessage!, "\(cardNetworkString!) is not supported") + let cardNetworkString = JPCardNetwork.name(of: result.cardNetwork) + XCTAssertEqual(result.errorMessage!, "\(cardNetworkString!) is not supported") } /* @@ -380,7 +380,7 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_ValidateCardNumberInput_WhenIsInvalidCard_ShouldReturnErrorStringForInvalidCardNumber() { let result = sut.validateCardNumberInput("4129939187355598") - XCTAssertEqual(result!.errorMessage!, "Invalid card number") + XCTAssertEqual(result.errorMessage!, "Invalid card number") } /* @@ -392,7 +392,7 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_ValidateSecureCodeInput_WhenMoreThenMax_ShouldSubscriptCode() { let result = sut.validateSecureCodeInput("1234") - XCTAssertEqual(result!.formattedInput!, "123") + XCTAssertEqual(result.formattedInput!, "123") } /* @@ -404,7 +404,7 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_ValidateSecureCodeInput_WhenCorrectLenght_ShouldBeValid() { let result = sut.validateSecureCodeInput("123") - XCTAssertTrue(result!.isInputAllowed) + XCTAssertTrue(result.isInputAllowed) } /* @@ -416,8 +416,8 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_validateSecureCodeInput_WhenLessThenMinimum_ShouldNotBeValid() { let result = sut.validateSecureCodeInput("12") - XCTAssertTrue(result!.isInputAllowed) - XCTAssertFalse(result!.isValid) + XCTAssertTrue(result.isInputAllowed) + XCTAssertFalse(result.isValid) } /* @@ -472,13 +472,13 @@ class JPTransactionInteractorTest: XCTestCase { /* * GIVEN: getting countries from interactor * - * WHEN: we have 4 countries that we support + * WHEN: we have 235 countries that we support * - * THEN: should be returned 4 countries + * THEN: should be returned 235 countries */ func test_GetSelectableCountryNames_WhenCountriesArrayHardcodedInteractor_ShouldReturnTheSame() { - let countries = sut.getSelectableCountryNames() - XCTAssertEqual(countries?.count, 4) + let countries = sut.getFilteredCountries(bySearch: nil) + XCTAssertEqual(countries.count, 235) } /* @@ -517,8 +517,8 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_ValidateCarholderNameInput_WhenNameIsValid_ShouldReturnValidResponse() { let result = sut.validateCardholderNameInput("Alex ABC") - XCTAssertTrue(result!.isInputAllowed) - XCTAssertTrue(result!.isValid) + XCTAssertTrue(result.isInputAllowed) + XCTAssertTrue(result.isValid) } /* @@ -530,8 +530,8 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_ValidateExpiryDateInput_WhenDateIsExpired_ShouldReturnInValidEResult() { let result = sut.validateExpiryDateInput("12/06") - XCTAssertTrue(result!.isInputAllowed) - XCTAssertFalse(result!.isValid) + XCTAssertTrue(result.isInputAllowed) + XCTAssertFalse(result.isValid) } /* @@ -543,8 +543,8 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_ValidateCountryInput_WhenCountryUSAIsSupported_ShouldReturnValidResult() { let result = sut.validateCountryInput("USA") - XCTAssertTrue(result!.isInputAllowed) - XCTAssertTrue(result!.isValid) + XCTAssertTrue(result.isInputAllowed) + XCTAssertTrue(result.isValid) } /* @@ -556,7 +556,7 @@ class JPTransactionInteractorTest: XCTestCase { */ func test_ValidatePostalCodeInput_WhenIsUk_ShouldBeValid() { let result = sut.validatePostalCodeInput("EC1A 1BB") - XCTAssertTrue(result!.isValid) + XCTAssertTrue(result.isValid) } /* @@ -573,11 +573,11 @@ class JPTransactionInteractorTest: XCTestCase { cardDetailsMode: .default, configuration: configuration, cardNetwork: .all, - completion: nil) + completion: { _, _ in }) let error = JPError(domain: "domain", code: JPError.userDidCancelError().code, userInfo: nil) - sut!.completeTransaction(with: JPResponse(), error: error) + sut.completeTransaction(with: JPResponse(), error: error) } /* @@ -615,20 +615,6 @@ class JPTransactionInteractorTest: XCTestCase { sut.resetCardValidationResults() } - /* - * GIVEN: send Transaction - * - * WHEN: with valid card - * - * THEN: should send transaction - */ - func test_sendTransactionWithCard() { - sut.sendTransaction(with: JPCard(cardNumber: "cardNumber", - cardholderName: "cardholderName", - expiryDate: "expiryDate", - secureCode: "secureCode")) { (_, _) in} - } - /* * GIVEN: validate card number(Master) * @@ -639,7 +625,7 @@ class JPTransactionInteractorTest: XCTestCase { func test_validateCardNumberInput_WhenNoSupportedNetworksInConfig_ShouldReturnValid() { configuration.supportedCardNetworks = [] let result = sut.validateCardNumberInput("5454422955385717") - XCTAssertTrue(result!.isValid) + XCTAssertTrue(result.isValid) } /* diff --git a/JudoKit_iOSTests/Modules/Transaction/Mocks/JPTransactionInteractorMock.swift b/JudoKit_iOSTests/Modules/Transaction/Mocks/JPTransactionInteractorMock.swift index 970472bed..dbaa4023c 100644 --- a/JudoKit_iOSTests/Modules/Transaction/Mocks/JPTransactionInteractorMock.swift +++ b/JudoKit_iOSTests/Modules/Transaction/Mocks/JPTransactionInteractorMock.swift @@ -33,6 +33,11 @@ enum SendTransactionTest { } class JPTransactionInteractorMock: JPTransactionInteractor { + + func configuration() -> JPConfiguration { + return JPConfiguration() + } + var testSendTransaction: SendTransactionTest = .validData var type: JPTransactionType = .saveCard lazy var validationService = JPCardValidationService() @@ -48,38 +53,46 @@ class JPTransactionInteractorMock: JPTransactionInteractor { return .visa } - func generatePayButtonTitle() -> String! { + func generatePayButtonTitle() -> String { return "Pay" } - func updateKeychain(withCardModel viewModel: JPTransactionViewModel!, andToken token: String!) { + func updateKeychain(withCardModel viewModel: JPTransactionViewModel, andToken token: String) { } func isAVSEnabled() -> Bool { return true } - + + func getConfiguredTheme() -> JPTheme { + JPTheme() + } + func transactionType() -> JPTransactionType { return type } - func handleCameraPermissions(completion: ((AVAuthorizationStatus) -> Void)!) { + func handleCameraPermissions(completion: ((AVAuthorizationStatus) -> Void)) { } - + + func getFilteredCountries(bySearch searchString: String?) -> [JPCountry] { + return [JPCountry()] + } + func getSelectableCountryNames() -> [String]! { return ["UK"] } - func getConfiguredCardAddress() -> JPAddress! { + func getConfiguredCardAddress() -> JPAddress { return JPAddress() } - func completeTransaction(with response: JPResponse!, error: JPError!) { + func completeTransaction(with response: JPResponse?, error: JPError?) { completeTransaction = true } - func storeError(_ error: Error!) { + func storeError(_ error: Error) { } @@ -87,31 +100,43 @@ class JPTransactionInteractorMock: JPTransactionInteractor { } - func validateCardNumberInput(_ input: String!) -> JPValidationResult! { + func validateCardNumberInput(_ input: String) -> JPValidationResult { return validationService.validateCardNumberInput(input, forSupportedNetworks: .visa) } - - func validateCardholderNameInput(_ input: String!) -> JPValidationResult! { + + func validateCardholderEmailInput(_ input: String) -> JPValidationResult { + return validationService.validateCardholderEmailInput(input) + } + + func validateCardholderPhoneCodeInput(_ input: String) -> JPValidationResult { + return validationService.validateCardholderPhoneCodeInput(input) + } + + func validateCardholderPhoneInput(_ input: String) -> JPValidationResult { + return validationService.validateCardholderPhoneInput(input) + } + + func validateCardholderNameInput(_ input: String) -> JPValidationResult { return validationService.validateCardholderNameInput(input) } - func validateExpiryDateInput(_ input: String!) -> JPValidationResult! { + func validateExpiryDateInput(_ input: String) -> JPValidationResult { return validationService.validateExpiryDateInput(input) } - func validateSecureCodeInput(_ input: String!) -> JPValidationResult! { + func validateSecureCodeInput(_ input: String) -> JPValidationResult { return validationService.validateSecureCodeInput(input) } - func validateCountryInput(_ input: String!) -> JPValidationResult! { + func validateCountryInput(_ input: String) -> JPValidationResult { return validationService.validateCountryInput(input) } - func validatePostalCodeInput(_ input: String!) -> JPValidationResult! { + func validatePostalCodeInput(_ input: String) -> JPValidationResult { return validationService.validatePostalCodeInput(input) } - func sendTransaction(with card: JPCard!, completionHandler: JPCompletionBlock!) { + func sendTransaction(with details: JPCardTransactionDetails, completionHandler: @escaping JPCompletionBlock) { switch testSendTransaction { case .error: let jpError = JPError(domain: "Domain test", code: 123, userInfo: nil) @@ -131,7 +156,7 @@ class JPTransactionInteractorMock: JPTransactionInteractor { trasactionSent = true } } - + var dic = ["receiptId":"receiptId", "orderId": "orderId", "type":"Payment", diff --git a/JudoKit_iOSTests/Modules/Transaction/Mocks/JPTransactionViewMock.swift b/JudoKit_iOSTests/Modules/Transaction/Mocks/JPTransactionViewMock.swift index 0e3efd715..fd40c87fe 100644 --- a/JudoKit_iOSTests/Modules/Transaction/Mocks/JPTransactionViewMock.swift +++ b/JudoKit_iOSTests/Modules/Transaction/Mocks/JPTransactionViewMock.swift @@ -33,10 +33,13 @@ class JPTransactionViewMock: UIViewController, JPTransactionView { func load(with mode: JPCardDetailsMode) { } - func updateView(with viewModel: JPTransactionViewModel) { + func updateView(with viewModel: JPTransactionViewModel, shouldUpdateTargets: Bool) { viewModelSut = viewModel } - + + func applyConfiguredTheme(_ theme: JPTheme) { + } + var error: Error! = nil func updateWithError(_ error: Error) { self.error = error diff --git a/JudoKit_iOSTests/Modules/Transaction/Presenter/JPTransactionPresenterTests.swift b/JudoKit_iOSTests/Modules/Transaction/Presenter/JPTransactionPresenterTests.swift index 301027d57..c79453335 100644 --- a/JudoKit_iOSTests/Modules/Transaction/Presenter/JPTransactionPresenterTests.swift +++ b/JudoKit_iOSTests/Modules/Transaction/Presenter/JPTransactionPresenterTests.swift @@ -52,7 +52,7 @@ class JPTransactionPresenterTests: XCTestCase { XCTAssertEqual(controller.viewModelSut.cardholderNameViewModel.placeholder, "Cardholder Name") XCTAssertEqual(controller.viewModelSut.expiryDateViewModel.placeholder, "MM/YY") XCTAssertEqual(controller.viewModelSut.secureCodeViewModel.placeholder, "CVV2") - XCTAssertEqual(controller.viewModelSut.countryPickerViewModel.placeholder, "country") + XCTAssertEqual(controller.viewModelSut.countryPickerViewModel.placeholder, "Country") XCTAssertEqual(controller.viewModelSut.postalCodeInputViewModel.placeholder, "Postcode") XCTAssertFalse(controller.viewModelSut.addCardButtonViewModel.isEnabled) @@ -66,7 +66,7 @@ class JPTransactionPresenterTests: XCTestCase { * THEN: should fill card number in viewmodel */ func test_handleInputChange_WhenTypeIsCard_ShouldUpdateViewModelWithCardNumber() { - sut.handleInputChange("4444", for: .cardNumber) + sut.handleInputChange("4444", for: .cardNumber, showError: true) XCTAssertEqual(controller.viewModelSut.cardNumberViewModel.text, "4444") } @@ -78,7 +78,7 @@ class JPTransactionPresenterTests: XCTestCase { * THEN: should fill expiry Date ViewModel */ func test_handleInputChange_WhenTypeIsCardExpiryDate_ShouldUpdateViewModelWithCardNumber() { - sut.handleInputChange("10/20", for: .cardExpiryDate) + sut.handleInputChange("10/20", for: .cardExpiryDate, showError: true) XCTAssertEqual(controller.viewModelSut.expiryDateViewModel.text, "10/20") } @@ -90,7 +90,7 @@ class JPTransactionPresenterTests: XCTestCase { * THEN: should fill card secure Code ViewModel */ func test_handleInputChange_WhenTypeIsSecure_ShouldUpdateViewModelWithCardNumber() { - sut.handleInputChange("123", for: .cardSecureCode) + sut.handleInputChange("123", for: .cardSecureCode, showError: true) XCTAssertEqual(controller.viewModelSut.secureCodeViewModel.text, "123") } @@ -102,7 +102,7 @@ class JPTransactionPresenterTests: XCTestCase { * THEN: should fill card holder Name ViewModel */ func test_handleInputChange_WhenTypeIsCardholderName_ShouldUpdateViewModelWithCardNumber() { - sut.handleInputChange("name", for: .cardholderName) + sut.handleInputChange("name", for: .cardholderName, showError: true) XCTAssertEqual(controller.viewModelSut.cardholderNameViewModel.text, "name") } @@ -114,8 +114,8 @@ class JPTransactionPresenterTests: XCTestCase { * THEN: should fill country Picker ViewModel */ func test_handleInputChange_WhenTypeIsCardCountry_ShouldUpdateViewModelWithCardNumber() { - sut.handleInputChange("UK", for: .cardCountry) - XCTAssertEqual(controller.viewModelSut.countryPickerViewModel.text, "UK") + sut.handleInputChange("United Kingdom", for: .cardCountry, showError: true) + XCTAssertEqual(controller.viewModelSut.countryPickerViewModel.text, "United Kingdom") } /* @@ -126,7 +126,7 @@ class JPTransactionPresenterTests: XCTestCase { * THEN: should fill postal Code Input ViewModel */ func test_handleInputChange_WhenTypeIsCardPostalCode_ShouldUpdateViewModelWithCardNumber() { - sut.handleInputChange("1001", for: .cardPostalCode) + sut.handleInputChange("1001", for: .cardPostalCode, showError: true) XCTAssertEqual(controller.viewModelSut.postalCodeInputViewModel.text, "1001") } @@ -253,7 +253,7 @@ class JPTransactionPresenterTests: XCTestCase { */ func test_handleInputChange_WhenTypeSecurityCode_ShouldEnableAddCard() { interactor.mode = .securityCode - sut.handleInputChange("4444", for: .cardNumber) + sut.handleInputChange("4444", for: .cardNumber, showError: true) XCTAssertFalse(controller.viewModelSut.addCardButtonViewModel.isEnabled) } @@ -266,7 +266,7 @@ class JPTransactionPresenterTests: XCTestCase { */ func test_handleInputChange_WhenAVSMode_ShouldEnableAddCard() { interactor.mode = .AVS - sut.handleInputChange("4444", for: .cardNumber) + sut.handleInputChange("4444", for: .cardNumber, showError: true) XCTAssertFalse(controller.viewModelSut.addCardButtonViewModel.isEnabled) } } diff --git a/JudoKit_iOSTests/Sevices/PostCodesValidation/JPCanadaPostCodeValidation.swift b/JudoKit_iOSTests/Sevices/PostCodesValidation/JPCanadaPostCodeValidation.swift index ff6d18cb7..b32edfc68 100644 --- a/JudoKit_iOSTests/Sevices/PostCodesValidation/JPCanadaPostCodeValidation.swift +++ b/JudoKit_iOSTests/Sevices/PostCodesValidation/JPCanadaPostCodeValidation.swift @@ -37,39 +37,39 @@ class JPCanadaPostCodeValidation: XCTestCase { configuration.supportedCardNetworks = [.visa, .masterCard, .AMEX, .dinersClub] validationService.validateCountryInput("Canada") sut = JPTransactionInteractorImpl(cardValidationService: validationService, - transactionService: nil, + transactionService: JPCardTransactionService(), transactionType: .payment, cardDetailsMode: .default, configuration: configuration, cardNetwork: .all, - completion: nil) + completion: { _, _ in }) } func testValidCode_Canada() { - let result = sut.validatePostalCodeInput("A1A1A1")! + let result = sut.validatePostalCodeInput("A1A1A1") XCTAssertEqual(result.formattedInput, "A1A 1A1") XCTAssertTrue(result.isValid) } func testValidCodeWithSpaces_Canada() { - let result = sut.validatePostalCodeInput("A1A 1A1")! + let result = sut.validatePostalCodeInput("A1A 1A1") XCTAssertEqual(result.formattedInput, "A1A 1A1") XCTAssertTrue(result.isValid) } func testInValidRegexSpecialSymbols_Canada() { - let result = sut.validatePostalCodeInput("A1! 1A1")! + let result = sut.validatePostalCodeInput("A1! 1A1") XCTAssertEqual(result.errorMessage, "Invalid postcode entered") XCTAssertFalse(result.isValid) } func testEmptyCode_Canada() { let result = sut.validatePostalCodeInput("") - XCTAssertFalse(result!.isValid) + XCTAssertFalse(result.isValid) } func testInValidRegexUndersScore_Canada() { - let result = sut.validatePostalCodeInput("A11_1A1")! + let result = sut.validatePostalCodeInput("A11_1A1") XCTAssertEqual(result.errorMessage, "Invalid postcode entered") XCTAssertFalse(result.isValid) } diff --git a/JudoKit_iOSTests/Sevices/PostCodesValidation/JPUKPostCodeValidation.swift b/JudoKit_iOSTests/Sevices/PostCodesValidation/JPUKPostCodeValidation.swift index eb25b3072..2e82ae6d2 100644 --- a/JudoKit_iOSTests/Sevices/PostCodesValidation/JPUKPostCodeValidation.swift +++ b/JudoKit_iOSTests/Sevices/PostCodesValidation/JPUKPostCodeValidation.swift @@ -37,52 +37,52 @@ class JPUKPostCodeValidation: XCTestCase { configuration.supportedCardNetworks = [.visa, .masterCard, .AMEX, .dinersClub] validationService.validateCountryInput("UK") sut = JPTransactionInteractorImpl(cardValidationService: validationService, - transactionService: nil, + transactionService: JPCardTransactionService(), transactionType: .payment, cardDetailsMode: .default, configuration: configuration, cardNetwork: .all, - completion: nil) + completion: { _, _ in }) } func testValidCode_UK() { let result = sut.validatePostalCodeInput("EC1A 1BB") - XCTAssertTrue(result!.isValid) + XCTAssertTrue(result.isValid) } func testValidCodeWithSpaces_UK() { let result = sut.validatePostalCodeInput("M1 1AE") - XCTAssertTrue(result!.isValid) + XCTAssertTrue(result.isValid) } func testInValidRegexSpecialSymbols_UK() { let result = sut.validatePostalCodeInput("B33 8TH") - XCTAssertTrue(result!.isValid) + XCTAssertTrue(result.isValid) } func testValidCodeWithSpacesWithoutSpaces_UK() { let result = sut.validatePostalCodeInput("M11AE") - XCTAssertTrue(result!.isValid) + XCTAssertTrue(result.isValid) } func testInValidRegexSpecialSymbolsWithoutSpaces_UK() { let result = sut.validatePostalCodeInput("B338TH") - XCTAssertTrue(result!.isValid) + XCTAssertTrue(result.isValid) } func testInValidErrorMessage_UK() { - let result = sut.validatePostalCodeInput("1 ABCD")! + let result = sut.validatePostalCodeInput("1 ABCD") XCTAssertEqual(result.errorMessage, "Invalid postcode entered") XCTAssertFalse(result.isValid) } func testInValidCharacters_UK() { let result = sut.validatePostalCodeInput("B3@ 8TH") - XCTAssertFalse(result!.isValid) + XCTAssertFalse(result.isValid) } func testEmptyCode_UK() { let result = sut.validatePostalCodeInput("") - XCTAssertFalse(result!.isValid) + XCTAssertFalse(result.isValid) } } diff --git a/JudoKit_iOSTests/Sevices/PostCodesValidation/JPUSAPostCodeValidation.swift b/JudoKit_iOSTests/Sevices/PostCodesValidation/JPUSAPostCodeValidation.swift index 5adcd2bc1..773b028b6 100644 --- a/JudoKit_iOSTests/Sevices/PostCodesValidation/JPUSAPostCodeValidation.swift +++ b/JudoKit_iOSTests/Sevices/PostCodesValidation/JPUSAPostCodeValidation.swift @@ -37,52 +37,52 @@ class JPUSAPostCodeValidation: XCTestCase { configuration.supportedCardNetworks = [.visa, .masterCard, .AMEX, .dinersClub] validationService.validateCountryInput("USA") sut = JPTransactionInteractorImpl(cardValidationService: validationService, - transactionService: nil, + transactionService: JPCardTransactionService(), transactionType: .payment, cardDetailsMode: .default, configuration: configuration, cardNetwork: .all, - completion: nil) + completion: { _, _ in }) } func testValidCode_US() { let result = sut.validatePostalCodeInput("12345") - XCTAssertTrue(result!.isValid) + XCTAssertTrue(result.isValid) } func testValidCodeWithSpaces_US() { let result = sut.validatePostalCodeInput("12345-6789") - XCTAssertTrue(result!.isValid) + XCTAssertTrue(result.isValid) } func testInValidCodeMiddleCharacter_US() { let result = sut.validatePostalCodeInput("1234@") - XCTAssertFalse(result!.isValid) + XCTAssertFalse(result.isValid) } func testInValidCodeShort_US() { let result = sut.validatePostalCodeInput("1234") - XCTAssertFalse(result!.isValid) + XCTAssertFalse(result.isValid) } func testInValidLastCharatcer_US() { let result = sut.validatePostalCodeInput("12345-678@") - XCTAssertFalse(result!.isValid) + XCTAssertFalse(result.isValid) } func testInValidCodeWithSpaces_US() { let result = sut.validatePostalCodeInput("12345 6789") - XCTAssertTrue(result!.isValid) + XCTAssertTrue(result.isValid) } func testInValidCodeError_US() { - let result = sut.validatePostalCodeInput("abcde-fghj")! + let result = sut.validatePostalCodeInput("abcde-fghj") XCTAssertEqual(result.errorMessage, "Invalid ZIP code entered") XCTAssertFalse(result.isValid) } func testEmptyCode_US() { let result = sut.validatePostalCodeInput("") - XCTAssertFalse(result!.isValid) + XCTAssertFalse(result.isValid) } } diff --git a/Resources/CountriesList.json b/Resources/CountriesList.json new file mode 100644 index 000000000..c764d715d --- /dev/null +++ b/Resources/CountriesList.json @@ -0,0 +1,1463 @@ +{ + "countries": [{ + "alpha2Code": "GB", + "name": "United Kingdom", + "dialCode": "44", + "numericCode": "826", + "phoneNumberFormat": "#### ######" + }, + { + "alpha2Code": "AF", + "name": "Afghanistan", + "dialCode": "93", + "numericCode": "004" + }, + { + "alpha2Code": "AL", + "name": "Albania", + "dialCode": "355", + "numericCode": "008" + }, + { + "alpha2Code": "DZ", + "name": "Algeria", + "dialCode": "213", + "numericCode": "012" + }, + { + "alpha2Code": "AS", + "name": "American Samoa", + "dialCode": "1684", + "numericCode": "016" + }, + { + "alpha2Code": "AD", + "name": "Andorra", + "dialCode": "376", + "numericCode": "020" + }, + { + "alpha2Code": "AO", + "name": "Angola", + "dialCode": "244", + "numericCode": "024" + }, + { + "alpha2Code": "AI", + "name": "Anguilla", + "dialCode": "1264", + "numericCode": "660" + }, + { + "alpha2Code": "AG", + "name": "Antigua and Barbuda", + "dialCode": "1268", + "numericCode": "028" + }, + { + "alpha2Code": "AR", + "name": "Argentina", + "dialCode": "54", + "numericCode": "032", + "phoneNumberFormat": "(##) ########" + }, + { + "alpha2Code": "AM", + "name": "Armenia", + "dialCode": "374", + "numericCode": "051" + }, + { + "alpha2Code": "AW", + "name": "Aruba", + "dialCode": "297", + "numericCode": "533" + }, + { + "alpha2Code": "AU", + "name": "Australia", + "dialCode": "61", + "numericCode": "036", + "phoneNumberFormat": "### ### ###" + }, + { + "alpha2Code": "AT", + "name": "Austria", + "dialCode": "43", + "numericCode": "040" + }, + { + "alpha2Code": "AZ", + "name": "Azerbaijan", + "dialCode": "994", + "numericCode": "031" + }, + { + "alpha2Code": "BS", + "name": "Bahamas", + "dialCode": "1242", + "numericCode": "044" + }, + { + "alpha2Code": "BH", + "name": "Bahrain", + "dialCode": "973", + "numericCode": "048" + }, + { + "alpha2Code": "BD", + "name": "Bangladesh", + "dialCode": "880", + "numericCode": "050" + }, + { + "alpha2Code": "BB", + "name": "Barbados", + "dialCode": "1246", + "numericCode": "052" + }, + { + "alpha2Code": "BY", + "name": "Belarus", + "dialCode": "375", + "numericCode": "112", + "phoneNumberFormat": "(##) ### ## ##" + }, + { + "alpha2Code": "BE", + "name": "Belgium", + "dialCode": "32", + "numericCode": "056", + "phoneNumberFormat": "### ## ## ##" + }, + { + "alpha2Code": "BZ", + "name": "Belize", + "dialCode": "501", + "numericCode": "084" + }, + { + "alpha2Code": "BJ", + "name": "Benin", + "dialCode": "229", + "numericCode": "204" + }, + { + "alpha2Code": "BM", + "name": "Bermuda", + "dialCode": "1441", + "numericCode": "060" + }, + { + "alpha2Code": "BT", + "name": "Bhutan", + "dialCode": "975", + "numericCode": "064" + }, + { + "alpha2Code": "BO", + "name": "Bolivia", + "dialCode": "591", + "numericCode": "068" + }, + { + "alpha2Code": "BA", + "name": "Bosnia and Herzegovina", + "dialCode": "387", + "numericCode": "070" + }, + { + "alpha2Code": "BW", + "name": "Botswana", + "dialCode": "267", + "numericCode": "072" + }, + { + "alpha2Code": "BR", + "name": "Brazil", + "dialCode": "55", + "numericCode": "076", + "phoneNumberFormat": "(##) #########" + }, + { + "alpha2Code": "IO", + "name": "British Indian Ocean Territory", + "dialCode": "246", + "numericCode": "086" + }, + { + "alpha2Code": "VG", + "name": "British Virgin Islands", + "dialCode": "1284", + "numericCode": "092" + }, + { + "alpha2Code": "BN", + "name": "Brunei", + "dialCode": "673", + "numericCode": "096" + }, + { + "alpha2Code": "BG", + "name": "Bulgaria", + "dialCode": "359", + "numericCode": "100" + }, + { + "alpha2Code": "BF", + "name": "Burkina Faso", + "dialCode": "226", + "numericCode": "854" + }, + { + "alpha2Code": "BI", + "name": "Burundi", + "dialCode": "257", + "numericCode": "108" + }, + { + "alpha2Code": "KH", + "name": "Cambodia", + "dialCode": "855", + "numericCode": "116" + }, + { + "alpha2Code": "CM", + "name": "Cameroon", + "dialCode": "237", + "numericCode": "120" + }, + { + "alpha2Code": "CA", + "name": "Canada", + "dialCode": "1", + "numericCode": "124", + "phoneNumberFormat": "(###) ###-####" + }, + { + "alpha2Code": "CV", + "name": "Cape Verde", + "dialCode": "238", + "numericCode": "132" + }, + { + "alpha2Code": "BQ", + "name": "Caribbean Netherlands", + "dialCode": "599", + "numericCode": "535" + }, + { + "alpha2Code": "KY", + "name": "Cayman Islands", + "dialCode": "1345", + "numericCode": "136" + }, + { + "alpha2Code": "CF", + "name": "Central African Republic", + "dialCode": "236", + "numericCode": "140" + }, + { + "alpha2Code": "TD", + "name": "Chad", + "dialCode": "235", + "numericCode": "148" + }, + { + "alpha2Code": "CL", + "name": "Chile", + "dialCode": "56", + "numericCode": "152" + }, + { + "alpha2Code": "CN", + "name": "China", + "dialCode": "86", + "numericCode": "156", + "phoneNumberFormat": "##-#########" + }, + { + "alpha2Code": "CO", + "name": "Colombia", + "dialCode": "57", + "numericCode": "170" + }, + { + "alpha2Code": "KM", + "name": "Comoros", + "dialCode": "269", + "numericCode": "174" + }, + { + "alpha2Code": "CD", + "name": "Congo, Democratic Republic of the", + "dialCode": "243", + "numericCode": "180" + }, + { + "alpha2Code": "CG", + "name": "Congo, Republic of the", + "dialCode": "242", + "numericCode": "178" + }, + { + "alpha2Code": "CK", + "name": "Cook Islands", + "dialCode": "682", + "numericCode": "184" + }, + { + "alpha2Code": "CR", + "name": "Costa Rica", + "dialCode": "506", + "numericCode": "188", + "phoneNumberFormat": "####-####" + }, + { + "alpha2Code": "CI", + "name": "Côte d’Ivoire", + "dialCode": "225", + "numericCode": "384" + }, + { + "alpha2Code": "HR", + "name": "Croatia", + "dialCode": "385", + "numericCode": "191" + }, + { + "alpha2Code": "CU", + "name": "Cuba", + "dialCode": "53", + "numericCode": "192" + }, + { + "alpha2Code": "CW", + "name": "Curaçao", + "dialCode": "599", + "numericCode": "531" + }, + { + "alpha2Code": "CY", + "name": "Cyprus", + "dialCode": "357", + "numericCode": "196", + "phoneNumberFormat": "## ######" + }, + { + "alpha2Code": "CZ", + "name": "Czech Republic", + "dialCode": "420", + "numericCode": "203" + }, + { + "alpha2Code": "DK", + "name": "Denmark", + "dialCode": "45", + "numericCode": "208", + "phoneNumberFormat": "## ## ## ##" + }, + { + "alpha2Code": "DJ", + "name": "Djibouti", + "dialCode": "253", + "numericCode": "262" + }, + { + "alpha2Code": "DM", + "name": "Dominica", + "dialCode": "1767", + "numericCode": "212" + }, + { + "alpha2Code": "DO", + "name": "Dominican Republic", + "dialCode": "1809", + "numericCode": "214" + }, + { + "alpha2Code": "EC", + "name": "Ecuador", + "dialCode": "593", + "numericCode": "218" + }, + { + "alpha2Code": "EG", + "name": "Egypt", + "dialCode": "20", + "numericCode": "818" + }, + { + "alpha2Code": "SV", + "name": "El Salvador", + "dialCode": "503", + "numericCode": "222", + "phoneNumberFormat": "####-####" + }, + { + "alpha2Code": "GQ", + "name": "Equatorial Guinea", + "dialCode": "240", + "numericCode": "226" + }, + { + "alpha2Code": "ER", + "name": "Eritrea", + "dialCode": "291", + "numericCode": "232" + }, + { + "alpha2Code": "EE", + "name": "Estonia", + "dialCode": "372", + "numericCode": "233", + "phoneNumberFormat": "#### ######" + }, + { + "alpha2Code": "ET", + "name": "Ethiopia", + "dialCode": "251", + "numericCode": "231" + }, + { + "alpha2Code": "FK", + "name": "Falkland Islands (Malvinas)", + "dialCode": "500", + "numericCode": "238" + }, + { + "alpha2Code": "FO", + "name": "Faroe Islands", + "dialCode": "298", + "numericCode": "234" + }, + { + "alpha2Code": "FJ", + "name": "Fiji", + "dialCode": "679", + "numericCode": "242" + }, + { + "alpha2Code": "FI", + "name": "Finland", + "dialCode": "358", + "numericCode": "246", + "phoneNumberFormat": "## ### ## ##" + }, + { + "alpha2Code": "FR", + "name": "France", + "dialCode": "33", + "numericCode": "250", + "phoneNumberFormat": "# ## ## ## ##" + }, + { + "alpha2Code": "GF", + "name": "French Guiana", + "dialCode": "594", + "numericCode": "254" + }, + { + "alpha2Code": "PF", + "name": "French Polynesia", + "dialCode": "689", + "numericCode": "258" + }, + { + "alpha2Code": "GA", + "name": "Gabon", + "dialCode": "241", + "numericCode": "266" + }, + { + "alpha2Code": "GM", + "name": "Gambia", + "dialCode": "220", + "numericCode": "270" + }, + { + "alpha2Code": "GE", + "name": "Georgia", + "dialCode": "995", + "numericCode": "268" + }, + { + "alpha2Code": "DE", + "name": "Germany", + "dialCode": "49", + "numericCode": "276", + "phoneNumberFormat": "#### ########" + }, + { + "alpha2Code": "GH", + "name": "Ghana", + "dialCode": "233", + "numericCode": "288" + }, + { + "alpha2Code": "GI", + "name": "Gibraltar", + "dialCode": "350", + "numericCode": "292" + }, + { + "alpha2Code": "GR", + "name": "Greece", + "dialCode": "30", + "numericCode": "300" + }, + { + "alpha2Code": "GL", + "name": "Greenland", + "dialCode": "299", + "numericCode": "304" + }, + { + "alpha2Code": "GD", + "name": "Grenada", + "dialCode": "1473", + "numericCode": "308" + }, + { + "alpha2Code": "GP", + "name": "Guadeloupe", + "dialCode": "590", + "numericCode": "312" + }, + { + "alpha2Code": "GU", + "name": "Guam", + "dialCode": "1671", + "numericCode": "316" + }, + { + "alpha2Code": "GT", + "name": "Guatemala", + "dialCode": "502", + "numericCode": "320", + "phoneNumberFormat": "####-####" + }, + { + "alpha2Code": "GG", + "name": "Guernsey", + "dialCode": "44", + "numericCode": "831" + }, + { + "alpha2Code": "GN", + "name": "Guinea", + "dialCode": "224", + "numericCode": "324" + }, + { + "alpha2Code": "GW", + "name": "Guinea-Bissau", + "dialCode": "245", + "numericCode": "624" + }, + { + "alpha2Code": "GY", + "name": "Guyana", + "dialCode": "592", + "numericCode": "328" + }, + { + "alpha2Code": "HT", + "name": "Haiti", + "dialCode": "509", + "numericCode": "332", + "phoneNumberFormat": "####-####" + }, + { + "alpha2Code": "HN", + "name": "Honduras", + "dialCode": "504", + "numericCode": "340" + }, + { + "alpha2Code": "HK", + "name": "Hong Kong", + "dialCode": "852", + "numericCode": "344", + "phoneNumberFormat": "#### ####" + }, + { + "alpha2Code": "HU", + "name": "Hungary", + "dialCode": "36", + "numericCode": "348" + }, + { + "alpha2Code": "IS", + "name": "Iceland", + "dialCode": "354", + "numericCode": "352", + "phoneNumberFormat": "### ####" + }, + { + "alpha2Code": "IN", + "name": "India", + "dialCode": "91", + "numericCode": "356", + "phoneNumberFormat": "#####-#####" + }, + { + "alpha2Code": "ID", + "name": "Indonesia", + "dialCode": "62", + "numericCode": "360" + }, + { + "alpha2Code": "IR", + "name": "Iran, Islamic Republic of", + "dialCode": "98", + "numericCode": "364" + }, + { + "alpha2Code": "IQ", + "name": "Iraq", + "dialCode": "964", + "numericCode": "368" + }, + { + "alpha2Code": "IE", + "name": "Ireland", + "dialCode": "353", + "numericCode": "372", + "phoneNumberFormat": "## #######" + }, + { + "alpha2Code": "IL", + "name": "Israel", + "dialCode": "972", + "numericCode": "376", + "phoneNumberFormat": "### ### ####" + }, + { + "alpha2Code": "IT", + "name": "Italy", + "dialCode": "39", + "numericCode": "380", + "phoneNumberFormat": "### #######" + }, + { + "alpha2Code": "JM", + "name": "Jamaica", + "dialCode": "1876", + "numericCode": "388" + }, + { + "alpha2Code": "JP", + "name": "Japan", + "dialCode": "81", + "numericCode": "392", + "phoneNumberFormat": "## #### ####" + }, + { + "alpha2Code": "JO", + "name": "Jordan", + "dialCode": "962", + "numericCode": "400" + }, + { + "alpha2Code": "KZ", + "name": "Kazakhstan", + "dialCode": "7", + "numericCode": "398", + "phoneNumberFormat": "### ###-##-##" + }, + { + "alpha2Code": "KE", + "name": "Kenya", + "dialCode": "254", + "numericCode": "404" + }, + { + "alpha2Code": "KI", + "name": "Kiribati", + "dialCode": "686", + "numericCode": "296" + }, + { + "alpha2Code": "KP", + "name": "Korea, Democratic People's Republic of ", + "dialCode ": "850", + "numericCode ": "408" + }, + { + + "alpha2Code": "KR", + "name": "Korea, Republic of", + "dialCode": "82", + "numericCode": "410", + "phoneNumberFormat": "### #### ####" + + }, + { + "alpha2Code": "KW", + "name": "Kuwait", + "dialCode": "965", + "numericCode": "414" + }, + { + "alpha2Code": "KG", + "name": "Kyrgyzstan", + "dialCode": "996", + "numericCode": "417" + }, + { + "alpha2Code": "LA", + "name": "Lao People's Democratic Republic ", + "dialCode ": "856 ", + "numericCode ": "418 " + }, + { + "alpha2Code": "LV", + "name": "Latvia", + "dialCode": "371", + "numericCode": "428" + }, + { + "alpha2Code": "LB", + "name": "Lebanon", + "dialCode": "961", + "numericCode": "422" + }, + { + "alpha2Code": "LS", + "name": "Lesotho", + "dialCode": "266", + "numericCode": "426" + }, + { + "alpha2Code": "LR", + "name": "Liberia", + "dialCode": "231", + "numericCode": "430" + }, + { + "alpha2Code": "LY", + "name": "Libya", + "dialCode": "218", + "numericCode": "434" + }, + { + "alpha2Code": "LI", + "name": "Liechtenstein", + "dialCode": "423", + "numericCode": "438" + }, + { + "alpha2Code": "LT", + "name": "Lithuania", + "dialCode": "370", + "numericCode": "440" + }, + { + "alpha2Code": "LU", + "name": "Luxembourg", + "dialCode": "352", + "numericCode": "442" + }, + { + "alpha2Code": "MO", + "name": "Macao", + "dialCode": "853", + "numericCode": "446" + }, + { + "alpha2Code": "MK", + "name": "Macedonia", + "dialCode": "389", + "numericCode": "807" + }, + { + "alpha2Code": "MG", + "name": "Madagascar", + "dialCode": "261", + "numericCode": "450" + }, + { + "alpha2Code": "MW", + "name": "Malawi", + "dialCode": "265", + "numericCode": "454" + }, + { + "alpha2Code": "MY", + "name": "Malaysia", + "dialCode": "60", + "numericCode": "458", + "phoneNumberFormat": "##-####-####" + }, + { + "alpha2Code": "MV", + "name": "Maldives", + "dialCode": "960", + "numericCode": "462" + }, + { + "alpha2Code": "ML", + "name": "Mali", + "dialCode": "223", + "numericCode": "466" + }, + { + "alpha2Code": "MT", + "name": "Malta", + "dialCode": "356", + "numericCode": "470" + }, + { + "alpha2Code": "MH", + "name": "Marshall Islands", + "dialCode": "692", + "numericCode": "584" + }, + { + "alpha2Code": "MQ", + "name": "Martinique", + "dialCode": "596", + "numericCode": "474" + }, + { + "alpha2Code": "MR", + "name": "Mauritania", + "dialCode": "222", + "numericCode": "478" + }, + { + "alpha2Code": "MU", + "name": "Mauritius", + "dialCode": "230", + "numericCode": "480" + }, + { + "alpha2Code": "MX", + "name": "Mexico", + "dialCode": "52", + "numericCode": "484" + }, + { + "alpha2Code": "FM", + "name": "Micronesia, Federated States of", + "dialCode": "691", + "numericCode": "583" + }, + { + + "alpha2Code": "MD", + "name": "Moldova, Republic of", + "dialCode": "373", + "numericCode": "498", + "phoneNumberFormat": "(##) ##-##-##" + + }, + { + "alpha2Code": "MC", + "name": "Monaco", + "dialCode": "377", + "numericCode": "492" + }, + { + "alpha2Code": "MN", + "name": "Mongolia", + "dialCode": "976", + "numericCode": "496" + }, + { + "alpha2Code": "ME", + "name": "Montenegro", + "dialCode": "382", + "numericCode": "499" + }, + { + "alpha2Code": "MS", + "name": "Montserrat", + "dialCode": "1-664", + "numericCode": "500" + }, + { + "alpha2Code": "MA", + "name": "Morocco", + "dialCode": "212", + "numericCode": "504" + }, + { + "alpha2Code": "MZ", + "name": "Mozambique", + "dialCode": "258", + "numericCode": "508" + }, + { + "alpha2Code": "MM", + "name": "Myanmar", + "dialCode": "95", + "numericCode": "104" + }, + { + "alpha2Code": "NA", + "name": "Namibia", + "dialCode": "264", + "numericCode": "516" + }, + { + "alpha2Code": "NR", + "name": "Nauru", + "dialCode": "674", + "numericCode": "520" + }, + { + "alpha2Code": "NP", + "name": "Nepal", + "dialCode": "977", + "numericCode": "524" + }, + { + "alpha2Code": "NL", + "name": "Netherlands", + "dialCode": "31", + "numericCode": "528", + "phoneNumberFormat": "## ########" + }, + { + "alpha2Code": "NC", + "name": "New Caledonia", + "dialCode": "687", + "numericCode": "540" + }, + { + "alpha2Code": "NZ", + "name": "New Zealand", + "dialCode": "64", + "numericCode": "554", + "phoneNumberFormat": "###-###-####" + }, + { + "alpha2Code": "NI", + "name": "Nicaragua", + "dialCode": "505", + "numericCode": "558" + }, + { + "alpha2Code": "NE", + "name": "Niger", + "dialCode": "227", + "numericCode": "562" + }, + { + "alpha2Code": "NG", + "name": "Nigeria", + "dialCode": "234", + "numericCode": "566" + }, + { + "alpha2Code": "NU", + "name": "Niue", + "dialCode": "683", + "numericCode": "570" + }, + { + "alpha2Code": "NF", + "name": "Norfolk Island", + "dialCode": "672", + "numericCode": "574" + }, + { + "alpha2Code": "MP", + "name": "Northern Mariana Islands", + "dialCode": "1670", + "numericCode": "580" + }, + { + "alpha2Code": "NO", + "name": "Norway", + "dialCode": "47", + "numericCode": "578", + "phoneNumberFormat": "### ## ###" + }, + { + "alpha2Code": "OM", + "name": "Oman", + "dialCode": "968", + "numericCode": "512" + }, + { + "alpha2Code": "PK", + "name": "Pakistan", + "dialCode": "92", + "numericCode": "586", + "phoneNumberFormat": "###-#######" + }, + { + "alpha2Code": "PW", + "name": "Palau", + "dialCode": "680", + "numericCode": "585" + }, + { + "alpha2Code": "PS", + "name": "Palestine, State of", + "dialCode": "970", + "numericCode": "275" + }, + { + "alpha2Code": "PA", + "name": "Panama", + "dialCode": "507", + "numericCode": "591" + }, + { + "alpha2Code": "PG", + "name": "Papua New Guinea", + "dialCode": "675", + "numericCode": "598" + }, + { + "alpha2Code": "PY", + "name": "Paraguay", + "dialCode": "595", + "numericCode": "600" + }, + { + "alpha2Code": "PE", + "name": "Peru", + "dialCode": "51", + "numericCode": "604" + }, + { + "alpha2Code": "PH", + "name": "Philippines", + "dialCode": "63", + "numericCode": "608", + "phoneNumberFormat": "#### #######" + }, + { + "alpha2Code": "PL", + "name": "Poland", + "dialCode": "48", + "numericCode": "616", + "phoneNumberFormat": "###-###-###" + }, + { + "alpha2Code": "PT", + "name": "Portugal", + "dialCode": "351", + "numericCode": "620" + }, + { + "alpha2Code": "PR", + "name": "Puerto Rico", + "dialCode": "1", + "numericCode": "630" + }, + { + "alpha2Code": "QA", + "name": "Qatar", + "dialCode": "974", + "numericCode": "634" + }, + { + "alpha2Code": "RE", + "name": "Réunion", + "dialCode": "262", + "numericCode": "638" + }, + { + "alpha2Code": "RO", + "name": "Romania", + "dialCode": "40", + "numericCode": "642" + }, + { + + "alpha2Code": "RU", + "name": "Russian Federation", + "dialCode": "7", + "numericCode": "643", + "phoneNumberFormat": "(###) ###-##-##" + + }, + { + "alpha2Code": "RW", + "name": "Rwanda", + "dialCode": "250", + "numericCode": "646" + }, + { + "alpha2Code": "BL", + "name": "Saint Barthélemy", + "dialCode": "590", + "numericCode": "652" + }, + { + "alpha2Code": "SH", + "name": "Saint Helena", + "dialCode": "290", + "numericCode": "654" + }, + { + "alpha2Code": "KN", + "name": "Saint Kitts and Nevis", + "dialCode": "1869", + "numericCode": "659" + }, + { + "alpha2Code": "LC", + "name": "Saint Lucia", + "dialCode": "1758", + "numericCode": "659" + }, + { + "alpha2Code": "MF", + "name": "Saint Martin (French part)", + "dialCode": "590", + "numericCode": "663" + }, + { + "alpha2Code": "PM", + "name": "Saint Pierre and Miquelon", + "dialCode": "508", + "numericCode": "666" + }, + { + "alpha2Code": "VC", + "name": "Saint Vincent and the Grenadines", + "dialCode": "1784", + "numericCode": "670" + }, + { + "alpha2Code": "WS", + "name": "Samoa", + "dialCode": "685", + "numericCode": "882" + }, + { + "alpha2Code": "SM", + "name": "San Marino", + "dialCode": "378", + "numericCode": "674" + }, + { + "alpha2Code": "ST", + "name": "São Tomé and Príncipe", + "dialCode": "239", + "numericCode": "678" + }, + { + "alpha2Code": "SA", + "name": "Saudi Arabia", + "dialCode": "966", + "numericCode": "682" + }, + { + "alpha2Code": "SN", + "name": "Senegal", + "dialCode": "221", + "numericCode": "686" + }, + { + "alpha2Code": "RS", + "name": "Serbia", + "dialCode": "381", + "numericCode": "688" + }, + { + "alpha2Code": "SC", + "name": "Seychelles", + "dialCode": "248", + "numericCode": "690" + }, + { + "alpha2Code": "SL", + "name": "Sierra Leone", + "dialCode": "232", + "numericCode": "694" + }, + { + "alpha2Code": "SG", + "name": "Singapore", + "dialCode": "65", + "numericCode": "702", + "phoneNumberFormat": "####-####" + }, + { + "alpha2Code": "SX", + "name": "Sint Maarten (Dutch part)", + "dialCode": "1721", + "numericCode": "534" + }, + { + "alpha2Code": "SK", + "name": "Slovakia", + "dialCode": "421", + "numericCode": "703" + }, + { + "alpha2Code": "SI", + "name": "Slovenia", + "dialCode": "386", + "numericCode": "705" + }, + { + "alpha2Code": "SB", + "name": "Solomon Islands", + "dialCode": "677", + "numericCode": "090" + }, + { + "alpha2Code": "SO", + "name": "Somalia", + "dialCode": "252", + "numericCode": "706" + }, + { + "alpha2Code": "ZA", + "name": "South Africa", + "dialCode": "27", + "numericCode": "710" + }, + { + "alpha2Code": "SS", + "name": "South Sudan", + "dialCode": "211", + "numericCode": "728" + }, + { + "alpha2Code": "ES", + "name": "Spain", + "dialCode": "34", + "numericCode": "724", + "phoneNumberFormat": "### ### ###" + }, + { + "alpha2Code": "LK", + "name": "Sri Lanka", + "dialCode": "94", + "numericCode": "144" + }, + { + "alpha2Code": "SD", + "name": "Sudan", + "dialCode": "249", + "numericCode": "729" + }, + { + "alpha2Code": "SR", + "name": "Suriname", + "dialCode": "597", + "numericCode": "740" + }, + { + "alpha2Code": "SZ", + "name": "Eswatini", + "dialCode": "268", + "numericCode": "748" + }, + { + "alpha2Code": "SE", + "name": "Sweden", + "dialCode": "46", + "numericCode": "752", + "phoneNumberFormat": "(##) ###-##-##" + }, + { + "alpha2Code": "CH", + "name": "Switzerland", + "dialCode": "41", + "numericCode": "756", + "phoneNumberFormat": "## ### ## ##" + }, + { + "alpha2Code": "SY", + "name": "Syrian Arab Republic", + "dialCode": "963", + "numericCode": "760" + }, + { + "alpha2Code": "TW", + "name": "Taiwan, Province of China", + "dialCode": "886", + "numericCode": "158" + }, + { + "alpha2Code": "TJ", + "name": "Tajikistan", + "dialCode": "992", + "numericCode": "762" + }, + { + "alpha2Code": "TH", + "name": "Thailand", + "dialCode": "66", + "numericCode": "764" + }, + { + "alpha2Code": "TL", + "name": "Timor-Leste", + "dialCode": "670", + "numericCode": "626" + }, + { + "alpha2Code": "TG", + "name": "Togo", + "dialCode": "228", + "numericCode": "768" + }, + { + "alpha2Code": "TK", + "name": "Tokelau", + "dialCode": "690", + "numericCode": "772" + }, + { + "alpha2Code": "TO", + "name": "Tonga", + "dialCode": "676", + "numericCode": "776" + }, + { + "alpha2Code": "TT", + "name": "Trinidad and Tobago", + "dialCode": "1-868", + "numericCode": "780" + }, + { + "alpha2Code": "TN", + "name": "Tunisia", + "dialCode": "216", + "numericCode": "788" + }, + { + "alpha2Code": "TR", + "name": "Turkey", + "dialCode": "90", + "numericCode": "792", + "phoneNumberFormat": "### ### ## ##" + }, + { + "alpha2Code": "TM", + "name": "Turkmenistan", + "dialCode": "993", + "numericCode": "795" + }, + { + "alpha2Code": "TC", + "name": "Turks and Caicos Islands", + "dialCode": "1649", + "numericCode": "796" + }, + { + "alpha2Code": "TV", + "name": "Tuvalu", + "dialCode": "688", + "numericCode": "798" + }, + { + "alpha2Code": "UG", + "name": "Uganda", + "dialCode": "256", + "numericCode": "800" + }, + { + "alpha2Code": "UA", + "name": "Ukraine", + "dialCode": "380", + "numericCode": "804", + "phoneNumberFormat": "(##) ### ## ##" + }, + { + "alpha2Code": "AE", + "name": "United Arab Emirates", + "dialCode": "971", + "numericCode": "784" + }, + { + "alpha2Code": "TZ", + "name": "United Republic of Tanzania", + "dialCode": "255", + "numericCode": "834" + }, + { + "alpha2Code": "US", + "name": "United States", + "dialCode": "1", + "numericCode": "840", + "phoneNumberFormat": "(###) ###-####" + }, + { + "alpha2Code": "UY", + "name": "Uruguay", + "dialCode": "598", + "numericCode": "858" + }, + { + "alpha2Code": "VI", + "name": "U.S. Virgin Islands", + "dialCode": "1340", + "numericCode": "850" + }, + { + "alpha2Code": "UZ", + "name": "Uzbekistan", + "dialCode": "998", + "numericCode": "860" + }, + { + "alpha2Code": "VU", + "name": "Vanuatu", + "dialCode": "678", + "numericCode": "548" + }, + { + "alpha2Code": "VA", + "name": "Vatican City", + "dialCode": "39", + "numericCode": "336", + "phoneNumberFormat": "## #### ####" + }, + { + "alpha2Code": "VE", + "name": "Venezuela", + "dialCode": "58", + "numericCode": "862" + }, + { + "alpha2Code": "VN", + "name": "Vietnam", + "dialCode": "84", + "numericCode": "704" + }, + { + "alpha2Code": "WF", + "name": "Wallis and Futuna", + "dialCode": "681", + "numericCode": "876" + }, + { + "alpha2Code": "EH", + "name": "Western Sahara", + "dialCode": "212", + "numericCode": "732" + }, + { + "alpha2Code": "YE", + "name": "Yemen", + "dialCode": "967", + "numericCode": "887" + }, + { + "alpha2Code": "ZM", + "name": "Zambia", + "dialCode": "260", + "numericCode": "894" + }, + { + "alpha2Code": "ZW", + "name": "Zimbabwe", + "dialCode": "263", + "numericCode": "716" + } + ] +} diff --git a/Resources/en.lproj/Localizable.strings b/Resources/en.lproj/Localizable.strings index 72a195959..0fd727745 100644 --- a/Resources/en.lproj/Localizable.strings +++ b/Resources/en.lproj/Localizable.strings @@ -27,8 +27,15 @@ "button_done" = "DONE"; "button_edit" = "Edit"; "button_scan_card" = "Scan card"; +"button_add_address_line_card" = "+ Add address line %@ (optional)"; "cancel" = "Cancel"; +"back" = "Back"; +"card_holder_email_hint" = "Email"; "card_holder_hint" = "Cardholder Name"; +"card_holder_country_hint" = "Country"; +"card_holder_phone_hint" = "Mobile number"; +"card_holder_city_hint" = "City"; +"card_holder_adress_line_hint" = "Address line %@"; "card_number_hint" = "Card Number"; "card_subtitle" = "%@ Ending"; "cards" = "Cards"; @@ -64,6 +71,9 @@ "ideal_payment" = "iDeal"; "ideal_transaction" = "iDEAL Transaction"; "invalid_expiry_date_value" = "Invalid date value entered"; +"invalid_email_value" = "Invalid email entered"; +"invalid_phone_code_value" = "Invalid phone code entered"; +"invalid_phone_value" = "Invalid phone entered"; "invalid_postcode" = "Invalid postcode entered"; "invalid_zip_code" = "Invalid ZIP code entered"; "invalid_email_address" = "Please enter a valid email"; @@ -77,6 +87,7 @@ "pay_amount" = "Pay %@"; "pay_by_bank" = "Pay by Bank app"; "pay_now" = "Pay Now"; +"continue" = "Continue"; "post_code_hint" = "Postcode"; "email_hint" = "Email"; "phone_country_code_hint" = "+()"; diff --git a/Resources/es.lproj/Localizable.strings b/Resources/es.lproj/Localizable.strings index b293c9540..0b4b4fb45 100644 --- a/Resources/es.lproj/Localizable.strings +++ b/Resources/es.lproj/Localizable.strings @@ -27,8 +27,15 @@ "button_done" = "Completo"; "button_edit" = "Editar"; "button_scan_card" = "Escanear tarjeta"; +"button_add_address_line_card" = "+ Add address line %@ (optional)"; "cancel" = "Cancelar"; +"back" = "Back"; +"card_holder_email_hint" = "Email"; "card_holder_hint" = "Nombre del titular de la tarejeta"; +"card_holder_country_hint" = "Country"; +"card_holder_phone_hint" = "Mobile number"; +"card_holder_city_hint" = "City"; +"card_holder_adress_line_hint" = "Address line %@"; "card_number_hint" = "Numero de tarjeta "; "card_subtitle" = "%@ Terminación"; "cards" = "Tarjetas "; @@ -64,6 +71,9 @@ "ideal_payment" = "iDeal"; "ideal_transaction" = "Transacción iDEAL "; "invalid_expiry_date_value" = "La fecha ingresada es inválida"; +"invalid_email_value" = "Invalid date value entered"; +"invalid_phone_code_value" = "Invalid phone code entered"; +"invalid_phone_value" = "Invalid phone entered"; "invalid_postcode" = "Código postal inválido"; "invalid_zip_code" = "Código postal inválido"; "invalid_email_address" = "Please enter a valid email"; @@ -77,6 +87,7 @@ "pay_amount" = "Paga %@"; "pay_by_bank" = "Aplicación Paga por Banco"; "pay_now" = "Paga ahora "; +"continue" = "Continue"; "post_code_hint" = "Código postal"; "email_hint" = "Email"; "phone_country_code_hint" = "+()"; diff --git a/Resources/fr.lproj/Localizable.strings b/Resources/fr.lproj/Localizable.strings index 53822469b..dc0898f96 100644 --- a/Resources/fr.lproj/Localizable.strings +++ b/Resources/fr.lproj/Localizable.strings @@ -27,8 +27,15 @@ "button_done" = "Terminer"; "button_edit" = "Editer"; "button_scan_card" = "Scanner carte"; +"button_add_address_line_card" = "+ Add address line %@ (optional)"; "cancel" = "Anuler"; +"back" = "Back"; "card_holder_hint" = "Nom du titulaire de la carte"; +"card_holder_country_hint" = "Country"; +"card_holder_phone_hint" = "Mobile number"; +"card_holder_city_hint" = "City"; +"card_holder_adress_line_hint" = "Address line %@"; +"card_holder_email_hint" = "Email"; "card_number_hint" = "Numéro de carte"; "card_subtitle" = "%@ Se Terminant"; "cards" = "Cartes"; @@ -64,6 +71,9 @@ "ideal_payment" = "iDeal"; "ideal_transaction" = "Paiement iDEAL"; "invalid_expiry_date_value" = "La date entrée est invalide "; +"invalid_email_value" = "Invalid email entered"; +"invalid_phone_code_value" = "Invalid phone code entered"; +"invalid_phone_value" = "Invalid phone entered"; "invalid_postcode" = "Code postal invalide"; "invalid_zip_code" = "Code postal invalide"; "invalid_email_address" = "Please enter a valid email"; @@ -77,6 +87,7 @@ "pay_amount" = "Payer %@"; "pay_by_bank" = "Application Pay by Bank"; "pay_now" = "Payer maintenant"; +"continue" = "Continue"; "post_code_hint" = "Code postal"; "email_hint" = "Email"; "phone_country_code_hint" = "+()"; diff --git a/Source/Extensions/JPCardTransactionDetails/JPCardTransactionDetails+Additions.m b/Source/Extensions/JPCardTransactionDetails/JPCardTransactionDetails+Additions.m index 99649fe09..d04d174b2 100644 --- a/Source/Extensions/JPCardTransactionDetails/JPCardTransactionDetails+Additions.m +++ b/Source/Extensions/JPCardTransactionDetails/JPCardTransactionDetails+Additions.m @@ -48,6 +48,7 @@ - (JPPaymentRequest *)toPaymentRequestWithConfiguration:(JPConfiguration *)confi request.phoneCountryCode = self.phoneCountryCode; request.mobileNumber = self.mobileNumber; request.emailAddress = self.emailAddress; + request.cardAddress = self.billingAddress; JP3DSAuthenticationRequestParameters *params = [transaction getAuthenticationRequestParameters]; @@ -69,6 +70,7 @@ - (JPTokenRequest *)toTokenRequestWithConfiguration:(JPConfiguration *)configura request.phoneCountryCode = self.phoneCountryCode; request.mobileNumber = self.mobileNumber; request.emailAddress = self.emailAddress; + request.cardAddress = self.billingAddress; JP3DSAuthenticationRequestParameters *params = [transaction getAuthenticationRequestParameters]; @@ -88,6 +90,7 @@ - (JPRegisterCardRequest *)toRegisterCardRequestWithConfiguration:(JPConfigurati request.phoneCountryCode = self.phoneCountryCode; request.mobileNumber = self.mobileNumber; request.emailAddress = self.emailAddress; + request.cardAddress = self.billingAddress; JP3DSAuthenticationRequestParameters *params = [transaction getAuthenticationRequestParameters]; @@ -107,6 +110,7 @@ - (JPSaveCardRequest *)toSaveCardRequestWithConfiguration:(JPConfiguration *)con request.phoneCountryCode = self.phoneCountryCode; request.mobileNumber = self.mobileNumber; request.emailAddress = self.emailAddress; + request.cardAddress = self.billingAddress; JP3DSAuthenticationRequestParameters *params = [transaction getAuthenticationRequestParameters]; @@ -126,6 +130,7 @@ - (JPCheckCardRequest *)toCheckCardRequestWithConfiguration:(JPConfiguration *)c request.phoneCountryCode = self.phoneCountryCode; request.mobileNumber = self.mobileNumber; request.emailAddress = self.emailAddress; + request.cardAddress = self.billingAddress; JP3DSAuthenticationRequestParameters *params = [transaction getAuthenticationRequestParameters]; diff --git a/Source/Extensions/JPRequest/JPRequest+Additions.m b/Source/Extensions/JPRequest/JPRequest+Additions.m index 3cd2fceb2..10bccfb44 100644 --- a/Source/Extensions/JPRequest/JPRequest+Additions.m +++ b/Source/Extensions/JPRequest/JPRequest+Additions.m @@ -11,6 +11,7 @@ - (void)setCardDetails:(nonnull JPCard *)card { self.cv2 = card.secureCode; self.startDate = card.startDate; self.issueNumber = card.issueNumber; + self.cardHolderName = card.cardholderName; if (card.cardAddress) { self.cardAddress = card.cardAddress; diff --git a/Source/Extensions/NSBundle/NSBundle+Additions.m b/Source/Extensions/NSBundle/NSBundle+Additions.m index 1af616c9d..fcd606621 100644 --- a/Source/Extensions/NSBundle/NSBundle+Additions.m +++ b/Source/Extensions/NSBundle/NSBundle+Additions.m @@ -31,17 +31,17 @@ + (NSBundle *)_jp_frameworkBundle { static NSBundle *bundle; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - bundle = [NSBundle bundleForClass:[JudoKit class]]; + bundle = [NSBundle bundleForClass:JudoKit.class]; }); return bundle; } + (NSBundle *)_jp_iconsBundle { - static NSBundle *__nullable iconsBundle; + static NSBundle *iconsBundle; static dispatch_once_t onceToken; + NSString *iconBundlePath = [NSBundle pathForResourceBundle:@"icons"]; dispatch_once(&onceToken, ^{ - NSString *iconBundlePath = [NSBundle pathForResourceBundle:@"icons"]; - iconsBundle = [NSBundle bundleWithPath:iconBundlePath]; + iconsBundle = [[NSBundle alloc] initWithPath:iconBundlePath]; }); return iconsBundle; } @@ -49,33 +49,39 @@ + (NSBundle *)_jp_iconsBundle { + (instancetype)_jp_stringsBundle { static NSBundle *bundle; static dispatch_once_t onceToken; + NSString *podPath = [NSBundle._jp_frameworkBundle pathForResource:@"JudoKit_iOS" + ofType:@"bundle"]; + + if (!podPath) { + return nil; + } + dispatch_once(&onceToken, ^{ - NSString *podPath = [NSBundle._jp_frameworkBundle pathForResource:@"JudoKit_iOS" - ofType:@"bundle"]; - bundle = [NSBundle bundleWithPath:podPath]; + bundle = [[NSBundle alloc] initWithPath:podPath]; }); return bundle; } + (instancetype)_jp_resourcesBundle { - static NSBundle *__nullable resourcesBundle; + static NSBundle *resourcesBundle; static dispatch_once_t onceToken; + NSString *iconBundlePath = [NSBundle pathForResourceBundle:@"resources"]; + dispatch_once(&onceToken, ^{ - NSString *iconBundlePath = [NSBundle pathForResourceBundle:@"resources"]; - resourcesBundle = [NSBundle bundleWithPath:iconBundlePath]; + resourcesBundle = [[NSBundle alloc] initWithPath:iconBundlePath]; }); return resourcesBundle; } + (NSString *)pathForResourceBundle:(NSString *)resourceBundle { - for (NSBundle *bundle in [NSBundle allBundles]) { + for (NSBundle *bundle in NSBundle.allBundles) { NSString *bundlePath = [bundle pathForResource:resourceBundle ofType:@"bundle"]; if (bundlePath) { return bundlePath; } } - for (NSBundle *bundle in [NSBundle allFrameworks]) { + for (NSBundle *bundle in NSBundle.allFrameworks) { NSString *bundlePath = [bundle pathForResource:resourceBundle ofType:@"bundle"]; if (bundlePath) { return bundlePath; diff --git a/Source/Extensions/NSString/NSString+Additions.h b/Source/Extensions/NSString/NSString+Additions.h index 13388b083..2469bbd81 100644 --- a/Source/Extensions/NSString/NSString+Additions.h +++ b/Source/Extensions/NSString/NSString+Additions.h @@ -49,6 +49,21 @@ */ - (nullable NSString *)_jp_sanitizedExpiryDate; +/** + * A method which returns YES if the string represents a valid email format + */ +@property (nonatomic, assign, readonly) BOOL _jp_isEmail; + +/** + * A method which returns YES if the string represents a valid email format + */ +@property (nonatomic, assign, readonly) BOOL _jp_isPhoneNumber; + +/** + * A method which returns YES if the string represents a valid phone dial number (country calling code) + */ +@property (nonatomic, assign, readonly) BOOL _jp_isPhoneCode; + /** * A method which returns YES if the string contains only digits */ diff --git a/Source/Extensions/NSString/NSString+Additions.m b/Source/Extensions/NSString/NSString+Additions.m index ae99d9efc..8c4a82b40 100644 --- a/Source/Extensions/NSString/NSString+Additions.m +++ b/Source/Extensions/NSString/NSString+Additions.m @@ -149,6 +149,20 @@ - (NSString *)_jp_sanitizedExpiryDate { return sanitized; } +- (BOOL)_jp_isEmail { + NSString *emailRegEx = @"[a-zA-Z0-9\\+\\.\\_\\%\\-\\+]{1,256}\\@[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}(\\.[a-zA-Z0-9][a-zA-Z0-9\\-]{0,25})+"; + NSPredicate *emailPred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegEx]; + return [emailPred evaluateWithObject:self]; +} + +- (BOOL)_jp_isPhoneCode { + return [self _jp_isNumeric]; +} + +- (BOOL)_jp_isPhoneNumber { + return [self _jp_isNumeric]; +} + - (nonnull NSMutableAttributedString *)_jp_attributedStringWithBoldSubstring:(nonnull NSString *)substring { NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:self]; NSRange substringRange = [self rangeOfString:substring]; diff --git a/Source/Extensions/UIImage/UIImage+Additions.h b/Source/Extensions/UIImage/UIImage+Additions.h index 8abac01da..796833817 100644 --- a/Source/Extensions/UIImage/UIImage+Additions.h +++ b/Source/Extensions/UIImage/UIImage+Additions.h @@ -35,7 +35,7 @@ * * @return a configured UIImage instance */ -+ (nonnull UIImage *)_jp_imageWithIconName:(nonnull NSString *)iconName; ++ (nullable UIImage *)_jp_imageWithIconName:(nonnull NSString *)iconName; /** * Initializes an UIImage based on a resource name contained in the resources bundle @@ -44,7 +44,7 @@ * * @return a configured UIImage instance */ -+ (nonnull UIImage *)_jp_imageWithResourceName:(nonnull NSString *)resourceName; ++ (nullable UIImage *)_jp_imageWithResourceName:(nonnull NSString *)resourceName; /** * Initializes an UIImage based on a card network @@ -53,7 +53,7 @@ * * @return a configured UIImage instance */ -+ (nonnull UIImage *)_jp_imageForCardNetwork:(JPCardNetworkType)network; ++ (nullable UIImage *)_jp_imageForCardNetwork:(JPCardNetworkType)network; /** * Initializes an UIImage to be displayed on top of a card. @@ -63,6 +63,6 @@ * * @return a configured UIImage instance */ -+ (nonnull UIImage *)_jp_headerImageForCardNetwork:(JPCardNetworkType)network; ++ (nullable UIImage *)_jp_headerImageForCardNetwork:(JPCardNetworkType)network; @end diff --git a/Source/Extensions/UIImage/UIImage+Additions.m b/Source/Extensions/UIImage/UIImage+Additions.m index fe275f45f..19d615f10 100644 --- a/Source/Extensions/UIImage/UIImage+Additions.m +++ b/Source/Extensions/UIImage/UIImage+Additions.m @@ -25,15 +25,18 @@ #import "NSBundle+Additions.h" #import "UIImage+Additions.h" +#import @implementation UIImage (Additions) + (UIImage *)_jp_imageWithIconName:(NSString *)iconName { - return [UIImage imageNamed:iconName inBundle:NSBundle._jp_iconsBundle compatibleWithTraitCollection:nil]; + NSBundle *bundle = NSBundle._jp_iconsBundle; + return [UIImage imageNamed:iconName inBundle:bundle compatibleWithTraitCollection:nil]; } + (UIImage *)_jp_imageWithResourceName:(NSString *)resourceName { - return [UIImage imageNamed:resourceName inBundle:NSBundle._jp_resourcesBundle compatibleWithTraitCollection:nil]; + NSBundle *bundle = NSBundle._jp_resourcesBundle; + return [UIImage imageNamed:resourceName inBundle:bundle compatibleWithTraitCollection:nil]; } + (UIImage *)_jp_headerImageForCardNetwork:(JPCardNetworkType)network { diff --git a/Source/Extensions/UITextField/UITextField+Additions.m b/Source/Extensions/UITextField/UITextField+Additions.m index c464aa30b..7d25a39f6 100644 --- a/Source/Extensions/UITextField/UITextField+Additions.m +++ b/Source/Extensions/UITextField/UITextField+Additions.m @@ -29,6 +29,9 @@ @implementation UITextField (Additions) - (void)_jp_placeholderWithText:(NSString *)text color:(UIColor *)color andFont:(UIFont *)font { + if (text == nil) { + return; + } NSDictionary *attributes = @{ NSForegroundColorAttributeName : color, diff --git a/Source/Extensions/UIViewController/UIViewController+Additions.m b/Source/Extensions/UIViewController/UIViewController+Additions.m index 6212faa75..d6c52e6f1 100644 --- a/Source/Extensions/UIViewController/UIViewController+Additions.m +++ b/Source/Extensions/UIViewController/UIViewController+Additions.m @@ -37,6 +37,7 @@ - (UIViewController *)parentController { } - (void)_jp_connectButton:(UIButton *)button withSelector:(SEL)selector { + [button removeTarget:nil action:nil forControlEvents:UIControlEventAllEvents]; [button addTarget:self action:selector forControlEvents:UIControlEventTouchUpInside]; } diff --git a/Source/JudoKit.h b/Source/JudoKit.h index 5bc88dd98..b6ae05879 100644 --- a/Source/JudoKit.h +++ b/Source/JudoKit.h @@ -32,7 +32,7 @@ @protocol JPAuthorization; static NSString *__nonnull const JudoKitName = @"JudoKit_iOS"; -static NSString *__nonnull const JudoKitVersion = @"3.0.3"; +static NSString *__nonnull const JudoKitVersion = @"3.1.0"; @interface JudoKit : NSObject diff --git a/Source/JudoKit_iOS.h b/Source/JudoKit_iOS.h index fd9e204a9..e844b27b1 100644 --- a/Source/JudoKit_iOS.h +++ b/Source/JudoKit_iOS.h @@ -47,6 +47,7 @@ #import "JPError+Additions.h" #import "JPError.h" #import "JPIDEALBank.h" +#import "JPNetworkTimeout.h" #import "JPOrderDetails.h" #import "JPPBBAButton.h" #import "JPPBBAConfiguration.h" @@ -78,7 +79,6 @@ #import "JPComplete3DS2Request.h" #import "JPPaymentRequest.h" #import "JPRequest.h" -#import "JPNetworkTimeout.h" #import "JP3DSecureAuthenticationResult.h" #import "JPApplePayRequest.h" diff --git a/Source/Models/Address/JPAddress.h b/Source/Models/Address/JPAddress.h index 39c95052b..24440bdeb 100644 --- a/Source/Models/Address/JPAddress.h +++ b/Source/Models/Address/JPAddress.h @@ -49,11 +49,6 @@ */ @property (nonatomic, strong, nullable) NSString *town; -/** - * Billing country of the address - */ -@property (nonatomic, strong, nullable) NSString *billingCountry; - /** * Post code of the address */ @@ -81,7 +76,6 @@ address2:(nullable NSString *)address2 address3:(nullable NSString *)address3 town:(nullable NSString *)town - billingCountry:(nullable NSString *)billingCountry postCode:(nullable NSString *)postCode countryCode:(nullable NSNumber *)countryCode; diff --git a/Source/Models/Address/JPAddress.m b/Source/Models/Address/JPAddress.m index 4ed617ab4..4827945bf 100644 --- a/Source/Models/Address/JPAddress.m +++ b/Source/Models/Address/JPAddress.m @@ -30,7 +30,6 @@ - (instancetype)initWithAddress1:(nullable NSString *)address1 address2:(nullable NSString *)address2 address3:(nullable NSString *)address3 town:(nullable NSString *)town - billingCountry:(nullable NSString *)billingCountry postCode:(nullable NSString *)postCode countryCode:(nullable NSNumber *)countryCode { @@ -39,7 +38,6 @@ - (instancetype)initWithAddress1:(nullable NSString *)address1 self.address2 = address2; self.address3 = address3; self.town = town; - self.billingCountry = billingCountry; self.postCode = postCode; self.countryCode = countryCode; } @@ -64,10 +62,6 @@ - (instancetype)initWithDictionary:(NSDictionary *)dictionary { self.town = dictionary[@"town"]; } - if (dictionary[@"billingCountry"]) { - self.billingCountry = dictionary[@"billingCountry"]; - } - if (dictionary[@"postCode"]) { self.postCode = dictionary[@"postCode"]; } diff --git a/Source/Models/Browser/JPBrowser.m b/Source/Models/Browser/JPBrowser.m index b1be31795..949822c43 100644 --- a/Source/Models/Browser/JPBrowser.m +++ b/Source/Models/Browser/JPBrowser.m @@ -53,7 +53,7 @@ - (instancetype)init { } #pragma mark - JPDictionaryConvertible -- (NSDictionary *)toDictionary { +- (NSDictionary *)_jp_toDictionary { return @{ kAcceptHeaderKey : self.acceptHeader, kTimeZoneKey : self.timeZone.abbreviation, diff --git a/Source/Models/CardNetwork/JPCardNetwork.m b/Source/Models/CardNetwork/JPCardNetwork.m index 40b40135b..a9127d87f 100644 --- a/Source/Models/CardNetwork/JPCardNetwork.m +++ b/Source/Models/CardNetwork/JPCardNetwork.m @@ -58,6 +58,10 @@ + (BOOL)doesCardNumber:(NSString *)cardNumber matchRegex:(NSString *)regex { } + (JPCardNetworkType)cardNetworkForCardNumber:(NSString *)cardNumber { + if (cardNumber.length == 0) { + return JPCardNetworkTypeUnknown; + } + if ([self doesCardNumber:cardNumber matchRegex:kRegexVisa]) { return JPCardNetworkTypeVisa; } diff --git a/Source/Models/ClientDetails/JPClientDetails.m b/Source/Models/ClientDetails/JPClientDetails.m index f0cd3de84..36979dc96 100644 --- a/Source/Models/ClientDetails/JPClientDetails.m +++ b/Source/Models/ClientDetails/JPClientDetails.m @@ -47,7 +47,7 @@ + (nonnull instancetype)detailsWithDictionary:(nonnull NSDictionary *)dictionary #pragma mark - JPDictionaryConvertible -- (NSDictionary *)toDictionary { +- (NSDictionary *)_jp_toDictionary { return @{ kClientDetailsKey : self.key, kClientDetailsValueKey : self.value diff --git a/Source/Models/Constants/JPConstants.h b/Source/Models/Constants/JPConstants.h index 2bcb0f6f2..e5ae06e61 100644 --- a/Source/Models/Constants/JPConstants.h +++ b/Source/Models/Constants/JPConstants.h @@ -86,7 +86,7 @@ static NSString *const kCanadaRegex = @"^(\\d{5}(-\\d{4})?|[A-Z]\\d[A-Z] ?\\d[A- static NSString *const kJudoIdRegex = @"^(([0-9]{9})|([0-9]{3}-[0-9]{3}-[0-9]{3})|([0-9]{6}))?$"; // Default 3DS 2.0 maximum timeout value -static int const kDefaultThreeDSTwoMaxTimeout = 120; +static int const kDefaultThreeDSTwoMaxTimeout = 60; // Default 3DS 2.0 protocol message version static NSString *const kThreeDSTwoMessageVersionTwoDotTwo = @"2.2.0"; diff --git a/Source/Models/ConsumerDevice/JPConsumerDevice.m b/Source/Models/ConsumerDevice/JPConsumerDevice.m index 52e620ffa..90766d16b 100644 --- a/Source/Models/ConsumerDevice/JPConsumerDevice.m +++ b/Source/Models/ConsumerDevice/JPConsumerDevice.m @@ -61,12 +61,12 @@ + (instancetype)deviceWithIpAddress:(NSString *)ipAddress } #pragma mark - JPDictionaryConvertible -- (NSDictionary *)toDictionary { +- (NSDictionary *)_jp_toDictionary { return @{ kIPAddressKey : self.ipAddress, - kClientDetailsKey : [self.clientDetails toDictionary], + kClientDetailsKey : [self.clientDetails _jp_toDictionary], kGeoLocationKey : [self.geoLocation _jp_toDictionary], - kThreeDSecureKey : [self.threeDSecure toDictionary], + kThreeDSecureKey : [self.threeDSecure _jp_toDictionary], kPaymentTypeKey : self.paymentType }; } diff --git a/Source/Models/Country/JPCountry.h b/Source/Models/Country/JPCountry.h index f00a2413a..bad0ac9a3 100644 --- a/Source/Models/Country/JPCountry.h +++ b/Source/Models/Country/JPCountry.h @@ -24,37 +24,30 @@ #import -typedef NS_ENUM(NSUInteger, JPCountryType) { - JPCountryTypeUSA, - JPCountryTypeUK, - JPCountryTypeCanada, - JPCountryTypeOther -}; - @interface JPCountry : NSObject -/** - * A string value representing the country's name - */ -@property (nonatomic, strong) NSString *name; - -/** - * Instantiates a country based on a specified country type - * - * @param countryType - a JPCountryType value identifying the country - */ -+ (instancetype)countryWithType:(JPCountryType)countryType; - -/** - * Instantiates a country based on a specified country type - * - * @param countryType - a JPCountryType value identifying the country - */ -- (instancetype)initWithType:(JPCountryType)countryType; - -/** - * Get ISO country code by country String - * - * @param country - country name, based on localization - */ -+ (NSNumber *)isoCodeForCountry:(NSString *)country; + +@property (nonatomic, nullable, copy) NSString *alpha2Code; +@property (nonatomic, nullable, copy) NSString *name; +@property (nonatomic, nullable, copy) NSString *dialCode; +@property (nonatomic, nullable, copy) NSString *numericCode; +@property (nonatomic, nullable, copy) NSString *phoneNumberFormat; + ++ (nullable NSNumber *)isoCodeForCountry:(nonnull NSString *)countryName; + ++ (nullable NSNumber *)dialCodeForCountry:(nonnull NSString *)countryName; + ++ (nullable JPCountry *)forCountryName:(nonnull NSString *)countryName; + +- (nullable instancetype)initWithDictionary:(nullable NSDictionary *)dict; + +@end + +@interface JPCountryList : NSObject + +@property (nonatomic, nullable, copy) NSArray *countries; + +- (nullable instancetype)initWithDictionary:(nullable NSDictionary *)dict; + ++ (nullable instancetype)defaultCountryList; + @end diff --git a/Source/Models/Country/JPCountry.m b/Source/Models/Country/JPCountry.m index 563df44fd..5d52cc485 100644 --- a/Source/Models/Country/JPCountry.m +++ b/Source/Models/Country/JPCountry.m @@ -26,43 +26,84 @@ #import "JPConstants.h" #import "NSString+Additions.h" -@implementation JPCountry +@implementation JPCountryList -+ (instancetype)countryWithType:(JPCountryType)countryType { - return [[JPCountry alloc] initWithType:countryType]; ++ (instancetype)defaultCountryList { + NSBundle *bundle = [NSBundle bundleForClass:[JPCountryList class]]; + NSString *str = [bundle pathForResource:@"CountriesList" ofType:@"json"]; + if (str) { + NSData *data = [NSData dataWithContentsOfFile:str]; + if (data) { + NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil]; + JPCountryList *list = [[JPCountryList alloc] initWithDictionary:dict]; + return list; + } + } + return nil; } -- (instancetype)initWithType:(JPCountryType)countryType { +- (instancetype)initWithDictionary:(NSDictionary *)dict { + if (!dict) { + return nil; + } if (self = [super init]) { - self.name = [self countryNameForType:countryType]; + NSArray *countriesDictionaries = dict[@"countries"]; + NSMutableArray *countries = [NSMutableArray new]; + for (NSDictionary *countryDict in countriesDictionaries) { + if (countryDict) { + JPCountry *country = [[JPCountry alloc] initWithDictionary:countryDict]; + if (country) { + [countries addObject:country]; + } + } + } + self.countries = countries; } return self; } -- (NSString *)countryNameForType:(JPCountryType)type { - switch (type) { - case JPCountryTypeUSA: - return @"country_usa"._jp_localized; - case JPCountryTypeUK: - return @"country_uk"._jp_localized; - case JPCountryTypeCanada: - return @"country_canada"._jp_localized; - case JPCountryTypeOther: - return @"country_other"._jp_localized; +@end + +@implementation JPCountry + ++ (NSNumber *)isoCodeForCountry:(NSString *)countryName { + JPCountryList *list = [JPCountryList defaultCountryList]; + NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == %@", countryName]; + JPCountry *country = [[list.countries filteredArrayUsingPredicate:predicate] firstObject]; + if (country) { + return @([country.numericCode intValue]); } + return nil; } -+ (NSNumber *)isoCodeForCountry:(NSString *)country { - if ([country isEqualToString:@"country_usa"._jp_localized]) { - return @(kJPCountryNumericCodeUSA); ++ (NSNumber *)dialCodeForCountry:(NSString *)countryName { + JPCountryList *list = [JPCountryList defaultCountryList]; + NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == %@", countryName]; + JPCountry *country = [[list.countries filteredArrayUsingPredicate:predicate] firstObject]; + if (country) { + return @([country.dialCode intValue]); } - if ([country isEqualToString:@"country_uk"._jp_localized]) { - return @(kJPCountryNumericCodeUK); + return nil; +} + ++ (nullable JPCountry *)forCountryName:(nonnull NSString *)countryName { + JPCountryList *list = [JPCountryList defaultCountryList]; + NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == %@", countryName]; + return [[list.countries filteredArrayUsingPredicate:predicate] firstObject]; +} + +- (instancetype)initWithDictionary:(NSDictionary *)dict { + if (!dict) { + return nil; } - if ([country isEqualToString:@"country_canada"._jp_localized]) { - return @(kJPCountryNumericCodeCanada); + if (self = [super init]) { + self.alpha2Code = dict[@"alpha2Code"]; + self.name = dict[@"name"]; + self.dialCode = dict[@"dialCode"]; + self.numericCode = dict[@"numericCode"]; + self.phoneNumberFormat = dict[@"phoneNumberFormat"]; } - return nil; + return self; } @end diff --git a/Source/Models/DictionaryConvertible/JPDictionaryConvertible.h b/Source/Models/DictionaryConvertible/JPDictionaryConvertible.h index dee967dfd..d97dfd511 100644 --- a/Source/Models/DictionaryConvertible/JPDictionaryConvertible.h +++ b/Source/Models/DictionaryConvertible/JPDictionaryConvertible.h @@ -25,5 +25,5 @@ #import @protocol JPDictionaryConvertible -- (nonnull NSDictionary *)toDictionary; +- (nonnull NSDictionary *)_jp_toDictionary; @end diff --git a/Source/Models/EnchancedPaymentDetail/JPEnhancedPaymentDetail.m b/Source/Models/EnchancedPaymentDetail/JPEnhancedPaymentDetail.m index 9e84cb56f..e2d3e04a7 100644 --- a/Source/Models/EnchancedPaymentDetail/JPEnhancedPaymentDetail.m +++ b/Source/Models/EnchancedPaymentDetail/JPEnhancedPaymentDetail.m @@ -47,10 +47,10 @@ + (instancetype)detailWithSdkInfo:(JPSDKInfo *)sdkInfo } #pragma mark - JPDictionaryConvertible -- (NSDictionary *)toDictionary { +- (NSDictionary *)_jp_toDictionary { return @{ - kSDKInfoKey : [self.sdkInfo toDictionary], - kConsumerDeviceKey : [self.consumerDevice toDictionary] + kSDKInfoKey : [self.sdkInfo _jp_toDictionary], + kConsumerDeviceKey : [self.consumerDevice _jp_toDictionary] }; } diff --git a/Source/Models/Receipt/JPReceipt.h b/Source/Models/Receipt/JPReceipt.h deleted file mode 100644 index 39af94717..000000000 --- a/Source/Models/Receipt/JPReceipt.h +++ /dev/null @@ -1,50 +0,0 @@ -// -// JPReceipt.h -// JudoKit_iOS -// -// Copyright (c) 2016 Alternative Payments Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#import "Typedefs.h" -#import - -@class JPResponse, JPPagination, JPSession; - -/** - * You can get a copy of the receipt for an individual transaction by creating a Receipt Object and calling `.sendWithCompletion(() -> ())` including the receipt ID for the transaction in the path. - Alternatively, you can receive a list of all the transactions. By default it will return 10 transactions. These results are returned in time-descending order by default, so it will return the latest 10 transactions. - */ -@interface JPReceipt : NSObject - -/** - * the receipt ID - nil for a list of all receipts - */ -@property (nonatomic, strong, readonly) NSString *_Nullable receiptId; - -/** - * Initialization for a Receipt Object, in case you want to use this function, you need to enable it in your judo Dashboard - * - * @param receiptId the receipt ID as a String - if nil, completion function will return a list of all transactions - * - * @return a Receipt Object for reactive usage - */ -- (nonnull instancetype)initWithReceiptId:(nullable NSString *)receiptId; - -@end diff --git a/Source/Models/Receipt/JPReceipt.m b/Source/Models/Receipt/JPReceipt.m deleted file mode 100644 index 66b585b75..000000000 --- a/Source/Models/Receipt/JPReceipt.m +++ /dev/null @@ -1,44 +0,0 @@ -// -// JPReceipt.m -// JudoKit_iOS -// -// Copyright (c) 2016 Alternative Payments Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#import "JPReceipt.h" -#import "JPSession.h" - -@interface JPReceipt () - -@property (nonatomic, strong, readwrite) NSString *receiptId; - -@end - -@implementation JPReceipt - -- (instancetype)initWithReceiptId:(NSString *)receiptId { - self = [super init]; - if (self) { - self.receiptId = receiptId; - } - return self; -} - -@end diff --git a/Source/Models/Request/JPApplePayRequest.m b/Source/Models/Request/JPApplePayRequest.m index 61092ead9..9d0431139 100644 --- a/Source/Models/Request/JPApplePayRequest.m +++ b/Source/Models/Request/JPApplePayRequest.m @@ -105,6 +105,7 @@ - (void)populateApplePayMetadataWithPayment:(PKPayment *)payment { self.pkPayment = [[JPApplePayPayment alloc] initWithPayment:payment]; PKContact *billingContact = payment.billingContact; + CNPostalAddress *postalAddress = billingContact.postalAddress; if (billingContact.emailAddress != nil) { self.emailAddress = billingContact.emailAddress; @@ -113,6 +114,13 @@ - (void)populateApplePayMetadataWithPayment:(PKPayment *)payment { if (billingContact.phoneNumber != nil) { self.mobileNumber = billingContact.phoneNumber.stringValue; } + + self.cardAddress = [[JPAddress alloc] initWithAddress1:postalAddress.street + address2:postalAddress.city + address3:postalAddress.postalCode + town:postalAddress.city + postCode:postalAddress.postalCode + countryCode:[JPCountry isoCodeForCountry:postalAddress.country]]; } @end diff --git a/Source/Models/SDKInfo/JPSDKInfo.m b/Source/Models/SDKInfo/JPSDKInfo.m index ea6a7cd76..edc9f1cb7 100644 --- a/Source/Models/SDKInfo/JPSDKInfo.m +++ b/Source/Models/SDKInfo/JPSDKInfo.m @@ -42,7 +42,7 @@ + (instancetype)infoWithVersion:(NSString *)version name:(NSString *)name { } #pragma mark - JPDictionaryConvertible -- (NSDictionary *)toDictionary { +- (NSDictionary *)_jp_toDictionary { return @{ kVersionKey : self.version, kNameKey : self.name diff --git a/Source/Models/ThreeDSecure/JPThreeDSecure.m b/Source/Models/ThreeDSecure/JPThreeDSecure.m index 2b55ec4dc..de008abf3 100644 --- a/Source/Models/ThreeDSecure/JPThreeDSecure.m +++ b/Source/Models/ThreeDSecure/JPThreeDSecure.m @@ -43,9 +43,9 @@ + (instancetype)secureWithBrowser:(JPBrowser *)browser { } #pragma mark - JPDictionaryConvertible -- (NSDictionary *)toDictionary { +- (NSDictionary *)_jp_toDictionary { return @{ - kBrowserKey : [self.browser toDictionary] + kBrowserKey : [self.browser _jp_toDictionary] }; } diff --git a/Source/Models/Transaction/JPTransactionType.h b/Source/Models/Transaction/JPTransactionType.h index 480a5a610..6efe0f704 100644 --- a/Source/Models/Transaction/JPTransactionType.h +++ b/Source/Models/Transaction/JPTransactionType.h @@ -24,6 +24,9 @@ #import +/* + * An enum that defines the transaction type + */ typedef NS_ENUM(NSUInteger, JPTransactionType) { JPTransactionTypePayment, JPTransactionTypePreAuth, diff --git a/Source/Models/TransactionEnricher/JPRequestEnricher.m b/Source/Models/TransactionEnricher/JPRequestEnricher.m index 21df7a46a..951b7da7f 100644 --- a/Source/Models/TransactionEnricher/JPRequestEnricher.m +++ b/Source/Models/TransactionEnricher/JPRequestEnricher.m @@ -81,7 +81,7 @@ - (void)enrichRequestParameters:(nullable NSDictionary *)dictionary [self.deviceDNA getDeviceSignals:^(NSDictionary *device, NSError *__unused error) { JPEnhancedPaymentDetail *detail = [weakSelf buildEnhancedPaymentDetail:device andLocation:self.lastKnownLocation]; NSMutableDictionary *enrichedRequest = [NSMutableDictionary dictionaryWithDictionary:dictionary]; - enrichedRequest[kEnhancedPaymentDetailKey] = [detail toDictionary]; + enrichedRequest[kEnhancedPaymentDetailKey] = [detail _jp_toDictionary]; enrichedRequest[kClientDetailsKey] = device; completion([NSDictionary dictionaryWithDictionary:enrichedRequest]); }]; diff --git a/Source/Modules/CardCustomization/View/JPCardCustomizationViewController.m b/Source/Modules/CardCustomization/View/JPCardCustomizationViewController.m index e4f26cb77..e0530b5f3 100644 --- a/Source/Modules/CardCustomization/View/JPCardCustomizationViewController.m +++ b/Source/Modules/CardCustomization/View/JPCardCustomizationViewController.m @@ -252,6 +252,9 @@ - (BOOL)inputField:(JPInputField *)inputField shouldChangeText:(NSString *)text return YES; } +- (void)inputField:(JPInputField *)inputField didEndEditing:(NSString *)text { +} + @end @implementation JPCardCustomizationViewController (SubmitDelegate) diff --git a/Source/Modules/PaymentMethods/Presenter/JPPaymentMethodsPresenter.m b/Source/Modules/PaymentMethods/Presenter/JPPaymentMethodsPresenter.m index cb18fa446..5883ec1bf 100644 --- a/Source/Modules/PaymentMethods/Presenter/JPPaymentMethodsPresenter.m +++ b/Source/Modules/PaymentMethods/Presenter/JPPaymentMethodsPresenter.m @@ -24,6 +24,7 @@ #import "JPPaymentMethodsPresenter.h" #import "JPAmount.h" +#import "JPCardDetailsMode.h" #import "JPCardNetwork.h" #import "JPConfiguration.h" #import "JPError+Additions.h" @@ -36,6 +37,7 @@ #import "JPPaymentMethodsViewController.h" #import "JPPaymentMethodsViewModel.h" #import "JPStoredCardDetails.h" +#import "JPTransactionType.h" #import "NSString+Additions.h" @interface JPPaymentMethodsPresenterImpl () diff --git a/Source/Modules/Transaction/Builder/JPTransactionBuilder.m b/Source/Modules/Transaction/Builder/JPTransactionBuilder.m index 528d1f380..eb6b8841c 100644 --- a/Source/Modules/Transaction/Builder/JPTransactionBuilder.m +++ b/Source/Modules/Transaction/Builder/JPTransactionBuilder.m @@ -70,7 +70,6 @@ + (JPTransactionViewController *)buildModuleWithApiService:(JPApiService *)apiSe router.theme = configuration.uiConfiguration.theme; viewController.presenter = presenter; - viewController.theme = configuration.uiConfiguration.theme; return viewController; } diff --git a/Source/Modules/Transaction/Interactor/JPTransactionInteractor.h b/Source/Modules/Transaction/Interactor/JPTransactionInteractor.h index c40baf1b7..a125edded 100644 --- a/Source/Modules/Transaction/Interactor/JPTransactionInteractor.h +++ b/Source/Modules/Transaction/Interactor/JPTransactionInteractor.h @@ -22,14 +22,15 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#import "JPCardDetailsMode.h" -#import "JPTransactionType.h" -#import "JPTransactionViewModel.h" #import "Typedefs.h" #import -#import -@class JPCard, JPConfiguration, JPCardValidationService, JPApiService, JPTransactionViewModel, JPValidationResult, JPError, JPResponse, JPAddress, JPCardTransactionService; +NS_ASSUME_NONNULL_BEGIN + +@class JPCard, JPConfiguration, JPCardValidationService, JPTransactionViewModel, JPValidationResult, JPError, JPResponse, JPAddress, JPCardTransactionService, JPTheme, JPCountry, JPCardTransactionDetails; +typedef NS_ENUM(NSUInteger, JPCardDetailsMode); +typedef NS_ENUM(NSUInteger, JPTransactionType); +typedef NS_OPTIONS(NSUInteger, JPCardNetworkType); @protocol JPTransactionInteractor @@ -43,6 +44,11 @@ */ - (BOOL)isAVSEnabled; +/** + * A method that returns JPTheme from UI Configuration + */ +- (JPTheme *)getConfiguredTheme; + /** * A method that returns the current transaction type */ @@ -63,7 +69,7 @@ /** * A method which returns the countries which the user can select in the country picker */ -- (NSArray *)getSelectableCountryNames; +- (NSArray *)getFilteredCountriesBySearchString:(nullable NSString *)searchString; /** * A method for returning merchant-set card address details @@ -76,8 +82,8 @@ * @param response - the JPResponse returned from the transaction * @param error - the JPError returned from the transaction */ -- (void)completeTransactionWithResponse:(JPResponse *)response - error:(JPError *)error; +- (void)completeTransactionWithResponse:(nullable JPResponse *)response + error:(nullable JPError *)error; /** * A method that stores the errors returned from the Judo API to be sent back to the merchant once the user cancels the payment. @@ -100,6 +106,33 @@ */ - (JPValidationResult *)validateCardNumberInput:(NSString *)input; +/** + * A method for validating the email + * + * @param input - the input email string + * + * @returns a JPValidationResult with the validation status details + */ +- (JPValidationResult *)validateCardholderEmailInput:(NSString *)input; + +/** + * A method for validating the phone dial code + * + * @param input - the input phone dial code string + * + * @returns a JPValidationResult with the validation status details + */ +- (JPValidationResult *)validateCardholderPhoneCodeInput:(NSString *)input; + +/** + * A method for validating the phone number + * + * @param input - the input phone string + * + * @returns a JPValidationResult with the validation status details + */ +- (JPValidationResult *)validateCardholderPhoneInput:(NSString *)input; + /** * A method for validating the cardholder name * @@ -145,14 +178,8 @@ */ - (JPValidationResult *)validatePostalCodeInput:(NSString *)input; -/** - * A method for sending a transaction to the Judo backend with specified card details - * - * @param card - the JPCard object which stores the card details - * @param completionHandler - the completion block with an optional JPResponse / NSError - */ -- (void)sendTransactionWithCard:(JPCard *)card - completionHandler:(JPCompletionBlock)completionHandler; +- (void)sendTransactionWithDetails:(JPCardTransactionDetails *)details + completionHandler:(JPCompletionBlock)completionHandler; /** * A method for updating the keychain information about the card @@ -168,6 +195,8 @@ */ - (NSString *)generatePayButtonTitle; +- (JPConfiguration *)configuration; + @end @interface JPTransactionInteractorImpl : NSObject @@ -177,7 +206,10 @@ * * @param cardValidationService - the service which is used to validate card details * @param transactionService - the service which sends requests to the Judo backend and handles 3DS checks + * @param type - the transaction type + * @param mode - the card details mode * @param configuration - the JPConfiguration object used for customizing the payment flow + * @param cardNetwork - the card network * @param completion - the completion block with an optional JPResponse / NSError */ - (instancetype)initWithCardValidationService:(JPCardValidationService *)cardValidationService @@ -188,3 +220,5 @@ cardNetwork:(JPCardNetworkType)cardNetwork completion:(JPCompletionBlock)completion; @end + +NS_ASSUME_NONNULL_END diff --git a/Source/Modules/Transaction/Interactor/JPTransactionInteractor.m b/Source/Modules/Transaction/Interactor/JPTransactionInteractor.m index 84a001ea3..c7403c5c5 100644 --- a/Source/Modules/Transaction/Interactor/JPTransactionInteractor.m +++ b/Source/Modules/Transaction/Interactor/JPTransactionInteractor.m @@ -23,25 +23,21 @@ // SOFTWARE. #import "JPTransactionInteractor.h" -#import "JP3DSConfiguration.h" #import "JPAddress.h" #import "JPAmount.h" -#import "JPApiService.h" #import "JPCard.h" +#import "JPCardDetailsMode.h" #import "JPCardPattern.h" #import "JPCardStorage.h" #import "JPCardTransactionDetails.h" #import "JPCardTransactionService.h" #import "JPCardValidationService.h" -#import "JPCheckCardRequest.h" #import "JPConfiguration.h" #import "JPCountry.h" #import "JPError+Additions.h" -#import "JPPaymentRequest.h" -#import "JPRegisterCardRequest.h" #import "JPResponse.h" -#import "JPSaveCardRequest.h" #import "JPStoredCardDetails.h" +#import "JPTransactionViewModel.h" #import "JPUIConfiguration.h" #import "JPValidationResult.h" #import "NSNumberFormatter+Additions.h" @@ -49,15 +45,14 @@ @interface JPTransactionInteractorImpl () -@property (nonatomic, strong) JPCompletionBlock completionHandler; -@property (nonatomic, strong) JPConfiguration *configuration; -@property (nonatomic, strong) NSMutableArray *storedErrors; +@property (nonatomic, strong) JPCardValidationService *cardValidationService; +@property (nonatomic, strong) JPCardTransactionService *transactionService; @property (nonatomic, assign) JPTransactionType transactionType; @property (nonatomic, assign) JPCardDetailsMode cardDetailsMode; +@property (nonatomic, strong) JPConfiguration *configuration; @property (nonatomic, assign) JPCardNetworkType cardNetworkType; - -@property (nonatomic, strong) JPCardValidationService *cardValidationService; -@property (nonatomic, strong) JPCardTransactionService *transactionService; +@property (nonatomic, strong) JPCompletionBlock completionHandler; +@property (nonatomic, strong) NSMutableArray *storedErrors; @end @@ -76,11 +71,11 @@ - (instancetype)initWithCardValidationService:(JPCardValidationService *)cardVal if (self = [super init]) { _cardValidationService = cardValidationService; _transactionService = transactionService; - _configuration = configuration; - _completionHandler = completion; _transactionType = type; _cardDetailsMode = mode; + _configuration = configuration; _cardNetworkType = cardNetwork; + _completionHandler = completion; } return self; } @@ -93,7 +88,11 @@ - (BOOL)isAVSEnabled { - (JPCardDetailsMode)cardDetailsMode { if (_cardDetailsMode == JPCardDetailsModeDefault) { - return self.configuration.uiConfiguration.isAVSEnabled ? JPCardDetailsModeAVS : JPCardDetailsModeDefault; // WTF??!! + if (self.configuration.uiConfiguration.isAVSEnabled) { + return JPCardDetailsModeAVS; + } else if (self.transactionType != JPTransactionTypeSaveCard && self.configuration.uiConfiguration.shouldAskForBillingInformation) { + return JPCardDetailsModeThreeDS2; + } } return _cardDetailsMode; } @@ -102,6 +101,10 @@ - (JPAddress *)getConfiguredCardAddress { return self.configuration.cardAddress; } +- (JPTheme *)getConfiguredTheme { + return self.configuration.uiConfiguration.theme; +} + - (void)handleCameraPermissionsWithCompletion:(void (^)(AVAuthorizationStatus))completion { AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; @@ -116,21 +119,24 @@ - (void)handleCameraPermissionsWithCompletion:(void (^)(AVAuthorizationStatus))c } - (NSString *)generatePayButtonTitle { - if ([self cardDetailsMode] == JPCardDetailsModeSecurityCode) { + if (self.cardDetailsMode == JPCardDetailsModeSecurityCode) { return @"pay_now"._jp_localized; } - if ((self.configuration.uiConfiguration.shouldPaymentButtonDisplayAmount)) { - JPAmount *amount = self.configuration.amount; - NSString *formattedAmount = [NSNumberFormatter _jp_formattedAmount:amount.amount withCurrencyCode:amount.currency]; + if (self.configuration.uiConfiguration.shouldPaymentButtonDisplayAmount) { + JPAmount *amount = self.configuration.amount; + NSString *formattedAmount = [NSNumberFormatter _jp_formattedAmount:amount.amount + withCurrencyCode:amount.currency]; +#pragma warning disable S5281 return [NSString stringWithFormat:@"pay_amount"._jp_localized, formattedAmount]; +#pragma warning restore S5281 } + return @"pay_now"._jp_localized; } -- (void)sendTransactionWithCard:(JPCard *)card completionHandler:(JPCompletionBlock)completionHandler { - JPCardTransactionDetails *details = [[JPCardTransactionDetails alloc] initWithConfiguration:self.configuration andCard:card]; - +- (void)sendTransactionWithDetails:(JPCardTransactionDetails *)details + completionHandler:(JPCompletionBlock)completionHandler { switch (self.transactionType) { case JPTransactionTypePayment: [self.transactionService invokePaymentWithDetails:details andCompletion:completionHandler]; @@ -173,10 +179,8 @@ - (void)storeError:(NSError *)error { } - (void)updateKeychainWithCardModel:(JPTransactionViewModel *)viewModel andToken:(NSString *)token { - JPCardNetworkType cardNetwork = viewModel.cardNumberViewModel.cardNetwork; NSString *cardNumberString = viewModel.cardNumberViewModel.text; - NSString *lastFour = [cardNumberString substringFromIndex:cardNumberString.length - 4]; NSString *expiryDate = viewModel.expiryDateViewModel.text; @@ -224,13 +228,13 @@ - (void)resetCardValidationResults { [self.cardValidationService resetCardValidationResults]; } -- (NSArray *)getSelectableCountryNames { - return @[ - [JPCountry countryWithType:JPCountryTypeUK].name, - [JPCountry countryWithType:JPCountryTypeUSA].name, - [JPCountry countryWithType:JPCountryTypeCanada].name, - [JPCountry countryWithType:JPCountryTypeOther].name, - ]; +- (NSArray *)getFilteredCountriesBySearchString:(NSString *)searchString { + NSArray *countries = [[JPCountryList defaultCountryList] countries]; + if (!searchString || searchString.length == 0) { + return countries ? countries : @[]; + } + NSPredicate *bPredicate = [NSPredicate predicateWithFormat:@"SELF.name beginswith[c] %@", searchString]; + return [countries filteredArrayUsingPredicate:bPredicate]; } - (JPValidationResult *)validateCardNumberInput:(NSString *)input { @@ -242,6 +246,18 @@ - (JPValidationResult *)validateCardholderNameInput:(NSString *)input { return [self.cardValidationService validateCardholderNameInput:input]; } +- (JPValidationResult *)validateCardholderEmailInput:(NSString *)input { + return [self.cardValidationService validateCardholderEmailInput:input]; +} + +- (JPValidationResult *)validateCardholderPhoneInput:(NSString *)input { + return [self.cardValidationService validateCardholderPhoneInput:input]; +} + +- (JPValidationResult *)validateCardholderPhoneCodeInput:(NSString *)input { + return [self.cardValidationService validateCardholderPhoneCodeInput:input]; +} + - (JPValidationResult *)validateExpiryDateInput:(NSString *)input { return [self.cardValidationService validateExpiryDateInput:input]; } diff --git a/Source/Modules/Transaction/Presenter/JPTransactionPresenter.h b/Source/Modules/Transaction/Presenter/JPTransactionPresenter.h index c0997fbe2..c4fa78278 100644 --- a/Source/Modules/Transaction/Presenter/JPTransactionPresenter.h +++ b/Source/Modules/Transaction/Presenter/JPTransactionPresenter.h @@ -22,13 +22,14 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#import "JPCardDetailsMode.h" -#import "JPInputType.h" -#import "JPTransactionViewModel.h" #import -@protocol JPTransactionView -, JPTransactionRouter, JPTransactionInteractor; +NS_ASSUME_NONNULL_BEGIN + +@protocol JPTransactionView; +@protocol JPTransactionRouter; +@protocol JPTransactionInteractor; +typedef NS_ENUM(NSUInteger, JPInputType); @protocol JPTransactionPresenter @@ -40,14 +41,25 @@ /** * A method that updates the view model whenever a input field value changes */ -- (void)handleInputChange:(nonnull NSString *)input - forType:(JPInputType)type; +- (void)handleInputChange:(NSString *)input + forType:(JPInputType)type + showError:(BOOL)showError; /** - * A method that handles Add Card button tap + * A method that handles the Pay Now button tap */ - (void)handleTransactionButtonTap; +/** + * A method that handles Continue button tap when the Billing details screen is used + */ +- (void)handleContinueButtonTap; + +/** + * A method that handles Back button tap when the Billing details screen is used + */ +- (void)handleBackButtonTap; + /** * A method that handles Scan Card button tap */ @@ -58,13 +70,18 @@ */ - (void)handleCancelButtonTap; +/** + * A method that handles add addres line button tap + */ +- (void)handleAddAddressLineTap; + /** * A method used to notify the JPTransactionPresenter that the card scan returned valid card details * * @param cardNumber - the detected card number * @param expiryDate - the detected card expiration date */ -- (void)updateViewModelWithCardNumber:(nonnull NSString *)cardNumber +- (void)updateViewModelWithCardNumber:(NSString *)cardNumber andExpiryDate:(nullable NSString *)expiryDate; @end @@ -77,13 +94,15 @@ @property (nonatomic, weak, nullable) id view; /** - * A strong reference to the router that adops the JPTransactionRouter protocol + * A strong reference to the interactor that adops the JPTransactionInteractor protocol */ -@property (nonatomic, strong, nonnull) id router; +@property (nonatomic, strong) id interactor; /** - * A strong reference to the interactor that adops the JPTransactionInteractor protocol + * A strong reference to the router that adops the JPTransactionRouter protocol */ -@property (nonatomic, strong, nonnull) id interactor; +@property (nonatomic, strong) id router; @end + +NS_ASSUME_NONNULL_END diff --git a/Source/Modules/Transaction/Presenter/JPTransactionPresenter.m b/Source/Modules/Transaction/Presenter/JPTransactionPresenter.m index c7eb69f83..477519a46 100644 --- a/Source/Modules/Transaction/Presenter/JPTransactionPresenter.m +++ b/Source/Modules/Transaction/Presenter/JPTransactionPresenter.m @@ -26,8 +26,12 @@ #import "JPAddress.h" #import "JPCard.h" #import "JPCardDetails.h" +#import "JPCardDetailsMode.h" +#import "JPCardNetwork.h" +#import "JPCardTransactionDetails.h" #import "JPCountry.h" #import "JPError+Additions.h" +#import "JPInputType.h" #import "JPResponse.h" #import "JPTransactionInteractor.h" #import "JPTransactionRouter.h" @@ -36,12 +40,18 @@ #import "NSString+Additions.h" @interface JPTransactionPresenterImpl () -@property (nonatomic, strong) JPTransactionViewModel *addCardViewModel; +@property (nonatomic, strong) JPTransactionViewModel *transactionViewModel; @property (nonatomic, assign) BOOL isCardNumberValid; @property (nonatomic, assign) BOOL isCardholderNameValid; @property (nonatomic, assign) BOOL isExpiryDateValid; @property (nonatomic, assign) BOOL isSecureCodeValid; @property (nonatomic, assign) BOOL isPostalCodeValid; +@property (nonatomic, assign) BOOL isEmailValid; +@property (nonatomic, assign) BOOL isPhoneCodeValid; +@property (nonatomic, assign) BOOL isCountryNameValid; +@property (nonatomic, assign) BOOL isCityNameValid; +@property (nonatomic, assign) BOOL isPhoneNumberValid; +@property (nonatomic, assign) BOOL isAddressLine1Valid; @end @implementation JPTransactionPresenterImpl @@ -55,6 +65,12 @@ - (instancetype)init { self.isExpiryDateValid = NO; self.isSecureCodeValid = NO; self.isPostalCodeValid = NO; + self.isEmailValid = YES; + self.isPhoneCodeValid = YES; + self.isCountryNameValid = YES; + self.isCityNameValid = YES; + self.isPhoneNumberValid = YES; + self.isAddressLine1Valid = YES; } return self; } @@ -62,40 +78,60 @@ - (instancetype)init { #pragma mark - Protocol methods - (void)prepareInitialViewModel { - JPTransactionType type = self.interactor.transactionType; - NSString *buttonTitle = [self transactionButtonTitleForType:type]; - self.addCardViewModel.type = type; - self.addCardViewModel.mode = [self.interactor cardDetailsMode]; + self.transactionViewModel.type = type; + self.transactionViewModel.mode = [self.interactor cardDetailsMode]; + + self.transactionViewModel.cardNumberViewModel.placeholder = @"card_number_hint"._jp_localized; + self.transactionViewModel.cardholderNameViewModel.placeholder = @"card_holder_hint"._jp_localized; + self.transactionViewModel.cardholderEmailViewModel.placeholder = @"card_holder_email_hint"._jp_localized; + self.transactionViewModel.cardholderAddressLine1ViewModel.placeholder = [NSString stringWithFormat:@"card_holder_adress_line_hint"._jp_localized, @(1)]; + self.transactionViewModel.cardholderAddressLine2ViewModel.placeholder = [NSString stringWithFormat:@"card_holder_adress_line_hint"._jp_localized, @(2)]; + self.transactionViewModel.cardholderAddressLine3ViewModel.placeholder = [NSString stringWithFormat:@"card_holder_adress_line_hint"._jp_localized, @(3)]; + self.transactionViewModel.cardholderPhoneViewModel.placeholder = @"card_holder_phone_hint"._jp_localized; + self.transactionViewModel.cardholderCityViewModel.placeholder = @"card_holder_city_hint"._jp_localized; + self.transactionViewModel.expiryDateViewModel.placeholder = @"expiry_date"._jp_localized; + + NSString *secureCodePlaceholder = [JPCardNetwork secureCodePlaceholderForNetworkType:[self.interactor cardNetworkType]]; + self.transactionViewModel.secureCodeViewModel.placeholder = secureCodePlaceholder; + + NSArray *selectableCountries = [self.interactor getFilteredCountriesBySearchString:nil]; + if (selectableCountries.count > 0) { + self.transactionViewModel.countryPickerViewModel.placeholder = @"card_holder_country_hint"._jp_localized; + self.transactionViewModel.pickerCountries = selectableCountries; + JPCountry *country = selectableCountries.firstObject; + self.transactionViewModel.countryPickerViewModel.text = country.name; + self.transactionViewModel.cardholderPhoneCodeViewModel.text = country.dialCode; + } + + self.transactionViewModel.postalCodeInputViewModel.placeholder = @"post_code_hint"._jp_localized; - self.addCardViewModel.cardNumberViewModel.placeholder = @"card_number_hint"._jp_localized; - self.addCardViewModel.cardholderNameViewModel.placeholder = @"card_holder_hint"._jp_localized; - self.addCardViewModel.expiryDateViewModel.placeholder = @"expiry_date"._jp_localized; - NSString *placeholder = [JPCardNetwork secureCodePlaceholderForNetworkType:[self.interactor cardNetworkType]]; - self.addCardViewModel.secureCodeViewModel.placeholder = placeholder; + NSString *buttonTitle = [self transactionButtonTitleForType:type]; - NSArray *selectableCountryNames = [self.interactor getSelectableCountryNames]; - self.addCardViewModel.countryPickerViewModel.placeholder = @"country"._jp_localized; - self.addCardViewModel.countryPickerViewModel.pickerTitles = selectableCountryNames; - self.addCardViewModel.countryPickerViewModel.text = selectableCountryNames.firstObject; + if (self.transactionViewModel.mode == JPCardDetailsModeThreeDS2) { + buttonTitle = @"continue"._jp_localized; + } - self.addCardViewModel.postalCodeInputViewModel.placeholder = @"post_code_hint"._jp_localized; + self.transactionViewModel.addCardButtonViewModel.title = buttonTitle.uppercaseString; + self.transactionViewModel.addCardButtonViewModel.isEnabled = NO; - self.addCardViewModel.addCardButtonViewModel.title = buttonTitle.uppercaseString; - self.addCardViewModel.addCardButtonViewModel.isEnabled = false; + self.transactionViewModel.backButtonViewModel.title = @"back".uppercaseString; + self.transactionViewModel.backButtonViewModel.isEnabled = YES; - [self.view loadViewWithMode:self.addCardViewModel.mode]; - [self.view updateViewWithViewModel:self.addCardViewModel]; + [self.view applyConfiguredTheme:[self.interactor getConfiguredTheme]]; + [self.view updateViewWithViewModel:self.transactionViewModel shouldUpdateTargets:YES]; } #pragma mark - Input Handler -- (void)handleInputChange:(NSString *)input forType:(JPInputType)type { - +- (void)handleInputChange:(NSString *)input forType:(JPInputType)type showError:(BOOL)showError { switch (type) { case JPInputTypeCardNumber: [self updateCardNumberViewModelForInput:input]; break; + case JPInputTypeCardholderEmail: + [self updateCardholderEmailViewModelForInput:input showError:showError]; + break; case JPInputTypeCardholderName: [self updateCardholderNameViewModelForInput:input]; break; @@ -112,27 +148,54 @@ - (void)handleInputChange:(NSString *)input forType:(JPInputType)type { case JPInputTypeCardPostalCode: [self updatePostalCodeViewModelForInput:input]; break; + case JPInputTypeCardholderPhone: + [self updateCardholderPhoneViewModelForInput:input]; + break; + case JPInputTypeCardholderAddressLine1: + case JPInputTypeCardholderAddressLine2: + case JPInputTypeCardholderAddressLine3: + [self updateCardholderAddressLineViewModelForInput:input inputType:type]; + break; + case JPInputTypeCardholderPhoneCode: + [self updateCardholderPhoneCodeViewModelForInput:input showError:showError]; + break; + case JPInputTypeCardholderCity: + [self updateCardholderCityViewModelForInput:input]; + break; } [self updateTransactionButtonModelIfNeeded]; - [self.view updateViewWithViewModel:self.addCardViewModel]; + [self.view updateViewWithViewModel:self.transactionViewModel shouldUpdateTargets:NO]; } #pragma mark - Transaction Button Tap - (void)handleTransactionButtonTap { - JPCard *card = [self cardFromViewModel:self.addCardViewModel]; + JPCardTransactionDetails *details = [self cardTransactionDetailsFromViewModel:self.transactionViewModel]; __weak typeof(self) weakSelf = self; - [self.interactor sendTransactionWithCard:card - completionHandler:^(JPResponse *response, JPError *error) { - if (error) { - [weakSelf handleError:error]; - return; - } - - [weakSelf handleResponse:response]; - }]; + [self.interactor sendTransactionWithDetails:details + completionHandler:^(JPResponse *response, JPError *error) { + if (error) { + [weakSelf handleError:error]; + return; + } + [weakSelf handleResponse:response]; + }]; +} + +- (void)handleContinueButtonTap { + self.transactionViewModel.mode = JPCardDetailsModeThreeDS2BillingDetails; + NSString *postalCode = self.transactionViewModel.postalCodeInputViewModel.text; + [self updatePostalCodeViewModelForInput:postalCode]; + [self updateTransactionButtonModelIfNeeded]; + [self.view updateViewWithViewModel:self.transactionViewModel shouldUpdateTargets:YES]; +} + +- (void)handleBackButtonTap { + self.transactionViewModel.mode = JPCardDetailsModeThreeDS2; + [self updateTransactionButtonModelIfNeeded]; + [self.view updateViewWithViewModel:self.transactionViewModel shouldUpdateTargets:YES]; } - (void)handleError:(JPError *)error { @@ -154,7 +217,7 @@ - (void)handleError:(JPError *)error { - (void)handleResponse:(JPResponse *)response { if (self.interactor.transactionType == JPTransactionTypeSaveCard) { NSString *token = response.cardDetails.cardToken; - [self.interactor updateKeychainWithCardModel:self.addCardViewModel + [self.interactor updateKeychainWithCardModel:self.transactionViewModel andToken:token]; } @@ -203,6 +266,10 @@ - (void)handleCancelButtonTap { }]; } +- (void)handleAddAddressLineTap { + [self.view updateViewWithViewModel:self.transactionViewModel shouldUpdateTargets:NO]; +} + #pragma mark - Helper methods - (void)updateViewModelWithCardNumber:(NSString *)cardNumber @@ -214,7 +281,7 @@ - (void)updateViewModelWithCardNumber:(NSString *)cardNumber [self updateExpiryDateViewModelForInput:expiryDate]; [self updateTransactionButtonModelIfNeeded]; - [self.view updateViewWithViewModel:self.addCardViewModel]; + [self.view updateViewWithViewModel:self.transactionViewModel shouldUpdateTargets:NO]; } - (NSString *)transactionButtonTitleForType:(JPTransactionType)type { @@ -234,17 +301,28 @@ - (NSString *)transactionButtonTitleForType:(JPTransactionType)type { } - (void)updateTransactionButtonModelIfNeeded { - JPCardDetailsMode mode = [self.interactor cardDetailsMode]; + NSString *buttonTitle = [self transactionButtonTitleForType:self.transactionViewModel.type]; + if (self.transactionViewModel.mode == JPCardDetailsModeThreeDS2) { + buttonTitle = @"continue"._jp_localized; + } + + self.transactionViewModel.addCardButtonViewModel.title = buttonTitle.uppercaseString; + BOOL isDefaultValid = self.isCardNumberValid && self.isCardholderNameValid && self.isExpiryDateValid && self.isSecureCodeValid; - switch (mode) { + switch (self.transactionViewModel.mode) { case JPCardDetailsModeSecurityCode: - self.addCardViewModel.addCardButtonViewModel.isEnabled = self.isSecureCodeValid; + self.transactionViewModel.addCardButtonViewModel.isEnabled = self.isSecureCodeValid; break; + case JPCardDetailsModeThreeDS2BillingDetails: { + BOOL is3DS2Valid = self.isEmailValid && self.isCountryNameValid && self.isAddressLine1Valid && self.isPhoneNumberValid && self.isCityNameValid && self.isPostalCodeValid; + self.transactionViewModel.addCardButtonViewModel.isEnabled = is3DS2Valid; + } break; case JPCardDetailsModeDefault: - self.addCardViewModel.addCardButtonViewModel.isEnabled = isDefaultValid; + case JPCardDetailsModeThreeDS2: + self.transactionViewModel.addCardButtonViewModel.isEnabled = isDefaultValid; break; case JPCardDetailsModeAVS: - self.addCardViewModel.addCardButtonViewModel.isEnabled = isDefaultValid && self.isPostalCodeValid; + self.transactionViewModel.addCardButtonViewModel.isEnabled = isDefaultValid && self.isPostalCodeValid; break; default: break; @@ -253,79 +331,167 @@ - (void)updateTransactionButtonModelIfNeeded { - (void)updateCardNumberViewModelForInput:(NSString *)input { JPValidationResult *result = [self.interactor validateCardNumberInput:input]; - self.addCardViewModel.cardNumberViewModel.errorText = result.errorMessage; + self.transactionViewModel.cardNumberViewModel.errorText = result.errorMessage; self.isCardNumberValid = result.isValid; [self updateSecureCodePlaceholderForNetworkType:result.cardNetwork]; if (result.isInputAllowed) { - self.addCardViewModel.cardNumberViewModel.text = result.formattedInput; - self.addCardViewModel.cardNumberViewModel.cardNetwork = result.cardNetwork; - return; + self.transactionViewModel.cardNumberViewModel.text = result.formattedInput; + self.transactionViewModel.cardNumberViewModel.cardNetwork = result.cardNetwork; + } +} + +- (void)updateCardholderEmailViewModelForInput:(NSString *)input showError:(BOOL)showError { + if ([input length] > 0) { + JPValidationResult *result = [self.interactor validateCardholderEmailInput:input]; + self.transactionViewModel.cardholderEmailViewModel.errorText = showError ? result.errorMessage : nil; + self.isEmailValid = result.isValid; + self.transactionViewModel.cardholderEmailViewModel.text = result.formattedInput; + } else { + self.transactionViewModel.cardholderEmailViewModel.errorText = nil; + self.isEmailValid = YES; + self.transactionViewModel.cardholderEmailViewModel.text = nil; + } +} + +- (void)updateCardholderPhoneCodeViewModelForInput:(NSString *)input showError:(BOOL)showError { + if ([input length] > 0) { + JPValidationResult *result = [self.interactor validateCardholderPhoneInput:input]; + self.transactionViewModel.cardholderPhoneCodeViewModel.text = result.formattedInput; + self.transactionViewModel.cardholderPhoneCodeViewModel.errorText = showError ? result.errorMessage : nil; + self.isPhoneCodeValid = result.isValid; + } else { + self.transactionViewModel.cardholderPhoneCodeViewModel.errorText = nil; + self.isPhoneCodeValid = YES; + } +} + +- (void)updateCardholderCityViewModelForInput:(NSString *)input { + self.isCityNameValid = YES; + self.transactionViewModel.cardholderCityViewModel.text = input; +} + +- (void)updateCardholderPhoneViewModelForInput:(NSString *)input { + JPValidationResult *result = [self.interactor validateCardholderPhoneInput:input]; + self.transactionViewModel.cardholderPhoneViewModel.errorText = result.errorMessage; + self.isPhoneNumberValid = result.isValid; + self.transactionViewModel.cardholderPhoneViewModel.text = result.formattedInput; +} + +- (void)updateCardholderAddressLineViewModelForInput:(NSString *)input inputType:(JPInputType)inputType { + switch (inputType) { + case JPInputTypeCardholderAddressLine1: { + _isAddressLine1Valid = YES; + self.transactionViewModel.cardholderAddressLine1ViewModel.text = input; + } break; + case JPInputTypeCardholderAddressLine2: + self.transactionViewModel.cardholderAddressLine2ViewModel.text = input; + break; + case JPInputTypeCardholderAddressLine3: + self.transactionViewModel.cardholderAddressLine3ViewModel.text = input; + break; + default: + break; } } - (void)updateSecureCodePlaceholderForNetworkType:(JPCardNetworkType)cardNetwork { - if (self.addCardViewModel.cardNumberViewModel.cardNetwork != cardNetwork) { - self.addCardViewModel.secureCodeViewModel.text = @""; + if (self.transactionViewModel.cardNumberViewModel.cardNetwork != cardNetwork) { + self.transactionViewModel.secureCodeViewModel.text = @""; self.isSecureCodeValid = false; NSString *placeholder = [JPCardNetwork secureCodePlaceholderForNetworkType:cardNetwork]; - self.addCardViewModel.secureCodeViewModel.placeholder = placeholder; + self.transactionViewModel.secureCodeViewModel.placeholder = placeholder; } } - (void)updateCardholderNameViewModelForInput:(NSString *)input { JPValidationResult *result = [self.interactor validateCardholderNameInput:input]; - self.addCardViewModel.cardholderNameViewModel.errorText = result.errorMessage; + self.transactionViewModel.cardholderNameViewModel.errorText = result.errorMessage; self.isCardholderNameValid = result.isValid; if (result.isInputAllowed) { - self.addCardViewModel.cardholderNameViewModel.text = result.formattedInput; - return; + self.transactionViewModel.cardholderNameViewModel.text = result.formattedInput; } } - (void)updateExpiryDateViewModelForInput:(NSString *)input { JPValidationResult *result = [self.interactor validateExpiryDateInput:input]; - self.addCardViewModel.expiryDateViewModel.errorText = result.errorMessage; + self.transactionViewModel.expiryDateViewModel.errorText = result.errorMessage; self.isExpiryDateValid = result.isValid; - if (result.isValid && result.formattedInput.length > 4) { - [self.view changeFocusToSecurityCodeField]; + if (result.isInputAllowed) { + self.transactionViewModel.expiryDateViewModel.text = result.formattedInput; } - if (result.isInputAllowed) { - self.addCardViewModel.expiryDateViewModel.text = result.formattedInput; - return; + if (result.isValid && result.formattedInput.length > 4) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [self.view changeFocusToSecurityCodeField]; + }); } } - (void)updateSecureCodeViewModelForInput:(NSString *)input { JPValidationResult *result = [self.interactor validateSecureCodeInput:input]; - self.addCardViewModel.secureCodeViewModel.errorText = result.errorMessage; + self.transactionViewModel.secureCodeViewModel.errorText = result.errorMessage; self.isSecureCodeValid = result.isValid; - self.addCardViewModel.secureCodeViewModel.text = result.formattedInput; + self.transactionViewModel.secureCodeViewModel.text = result.formattedInput; } - (void)updateCountryViewModelForInput:(NSString *)input { - JPValidationResult *result = [self.interactor validateCountryInput:input]; - self.addCardViewModel.countryPickerViewModel.errorText = result.errorMessage; + JPCountry *country = [JPCountry forCountryName:input]; + NSString *postcodeValidationCountryName; + if ([country.alpha2Code isEqualToString:@"US"]) { + postcodeValidationCountryName = @"country_usa"._jp_localized; + } else if ([country.alpha2Code isEqualToString:@"GB"]) { + postcodeValidationCountryName = @"country_uk"._jp_localized; + } else if ([country.alpha2Code isEqualToString:@"CA"]) { + postcodeValidationCountryName = @"country_canada"._jp_localized; + } else { + postcodeValidationCountryName = @"country_other"._jp_localized; + } + JPValidationResult *result = [self.interactor validateCountryInput:postcodeValidationCountryName]; + self.transactionViewModel.countryPickerViewModel.errorText = result.errorMessage; + self.transactionViewModel.cardholderPhoneCodeViewModel.text = [[JPCountry dialCodeForCountry:input] stringValue]; + [self.view updateViewWithViewModel:self.transactionViewModel shouldUpdateTargets:NO]; if (result.isInputAllowed) { - self.addCardViewModel.countryPickerViewModel.text = result.formattedInput; - return; + self.transactionViewModel.countryPickerViewModel.text = country.name; } } - (void)updatePostalCodeViewModelForInput:(NSString *)input { + if (!input && self.transactionViewModel.mode == JPCardDetailsModeThreeDS2BillingDetails) { + self.transactionViewModel.postalCodeInputViewModel.errorText = nil; + self.isPostalCodeValid = YES; + self.transactionViewModel.postalCodeInputViewModel.text = nil; + return; + } + JPValidationResult *result = [self.interactor validatePostalCodeInput:input]; - self.addCardViewModel.postalCodeInputViewModel.errorText = result.errorMessage; + self.transactionViewModel.postalCodeInputViewModel.errorText = result.errorMessage; self.isPostalCodeValid = result.isValid; - if (result.isInputAllowed) { - self.addCardViewModel.postalCodeInputViewModel.text = result.formattedInput; - return; + self.transactionViewModel.postalCodeInputViewModel.text = result.formattedInput; + } +} + +- (JPCardTransactionDetails *)cardTransactionDetailsFromViewModel:(JPTransactionViewModel *)viewModel { + JPCard *card = [self cardFromViewModel:viewModel]; + JPConfiguration *configuration = self.interactor.configuration; + JPCardTransactionDetails *details = [[JPCardTransactionDetails alloc] initWithConfiguration:configuration + andCard:card]; + + if (viewModel.cardholderEmailViewModel.text.length > 0) { + details.emailAddress = viewModel.cardholderEmailViewModel.text; + } + + if (viewModel.cardholderPhoneCodeViewModel.text.length > 0 && viewModel.cardholderPhoneViewModel.text.length > 0) { + details.phoneCountryCode = viewModel.cardholderPhoneCodeViewModel.text; + details.mobileNumber = viewModel.cardholderPhoneViewModel.text; } + + return details; } - (JPCard *)cardFromViewModel:(JPTransactionViewModel *)viewModel { @@ -334,14 +500,26 @@ - (JPCard *)cardFromViewModel:(JPTransactionViewModel *)viewModel { expiryDate:viewModel.expiryDateViewModel.text secureCode:viewModel.secureCodeViewModel.text]; - JPAddress *configuredAddress = [self.interactor getConfiguredCardAddress]; - card.cardAddress = configuredAddress ? configuredAddress : [JPAddress new]; + card.cardAddress = [self.interactor getConfiguredCardAddress]; if ([self.interactor isAVSEnabled]) { + if (!card.cardAddress) { + card.cardAddress = [JPAddress new]; + } card.cardAddress.countryCode = [JPCountry isoCodeForCountry:viewModel.countryPickerViewModel.text]; card.cardAddress.postCode = viewModel.postalCodeInputViewModel.text; } + if (viewModel.mode == JPCardDetailsModeThreeDS2BillingDetails) { + JPAddress *billingAddress = [[JPAddress alloc] initWithAddress1:viewModel.cardholderAddressLine1ViewModel.text + address2:viewModel.cardholderAddressLine2ViewModel.text + address3:viewModel.cardholderAddressLine3ViewModel.text + town:viewModel.cardholderCityViewModel.text + postCode:viewModel.postalCodeInputViewModel.text + countryCode:[JPCountry isoCodeForCountry:viewModel.countryPickerViewModel.text]]; + card.cardAddress = billingAddress; + } + // TODO: Handle Maestro-specific logic // card.startDate = viewModel.startDateViewModel.text; // card.issueNumber = viewModel.issueNumberViewModel.text; @@ -351,18 +529,26 @@ - (JPCard *)cardFromViewModel:(JPTransactionViewModel *)viewModel { #pragma mark - Lazy properties -- (JPTransactionViewModel *)addCardViewModel { - if (!_addCardViewModel) { - _addCardViewModel = [JPTransactionViewModel new]; - _addCardViewModel.cardNumberViewModel = [JPTransactionNumberInputViewModel new]; - _addCardViewModel.cardholderNameViewModel = [JPTransactionInputFieldViewModel viewModelWithType:JPInputTypeCardholderName]; - _addCardViewModel.expiryDateViewModel = [JPTransactionInputFieldViewModel viewModelWithType:JPInputTypeCardExpiryDate]; - _addCardViewModel.secureCodeViewModel = [JPTransactionInputFieldViewModel viewModelWithType:JPInputTypeCardSecureCode]; - _addCardViewModel.countryPickerViewModel = [JPTransactionPickerViewModel new]; - _addCardViewModel.postalCodeInputViewModel = [JPTransactionInputFieldViewModel viewModelWithType:JPInputTypeCardPostalCode]; - _addCardViewModel.addCardButtonViewModel = [JPTransactionButtonViewModel new]; +- (JPTransactionViewModel *)transactionViewModel { + if (!_transactionViewModel) { + _transactionViewModel = [JPTransactionViewModel new]; + _transactionViewModel.cardNumberViewModel = [JPTransactionNumberInputViewModel new]; + _transactionViewModel.cardholderNameViewModel = [JPTransactionInputFieldViewModel viewModelWithType:JPInputTypeCardholderName]; + _transactionViewModel.cardholderEmailViewModel = [JPTransactionInputFieldViewModel viewModelWithType:JPInputTypeCardholderEmail]; + _transactionViewModel.cardholderPhoneViewModel = [JPTransactionInputFieldViewModel viewModelWithType:JPInputTypeCardholderPhone]; + _transactionViewModel.cardholderCityViewModel = [JPTransactionInputFieldViewModel viewModelWithType:JPInputTypeCardholderCity]; + _transactionViewModel.cardholderAddressLine1ViewModel = [JPTransactionInputFieldViewModel viewModelWithType:JPInputTypeCardholderAddressLine1]; + _transactionViewModel.cardholderAddressLine2ViewModel = [JPTransactionInputFieldViewModel viewModelWithType:JPInputTypeCardholderAddressLine2]; + _transactionViewModel.cardholderAddressLine3ViewModel = [JPTransactionInputFieldViewModel viewModelWithType:JPInputTypeCardholderAddressLine3]; + _transactionViewModel.cardholderPhoneCodeViewModel = [JPTransactionInputFieldViewModel viewModelWithType:JPInputTypeCardholderPhoneCode]; + _transactionViewModel.expiryDateViewModel = [JPTransactionInputFieldViewModel viewModelWithType:JPInputTypeCardExpiryDate]; + _transactionViewModel.secureCodeViewModel = [JPTransactionInputFieldViewModel viewModelWithType:JPInputTypeCardSecureCode]; + _transactionViewModel.countryPickerViewModel = [JPTransactionInputFieldViewModel viewModelWithType:JPInputTypeCardCountry]; + _transactionViewModel.postalCodeInputViewModel = [JPTransactionInputFieldViewModel viewModelWithType:JPInputTypeCardPostalCode]; + _transactionViewModel.addCardButtonViewModel = [JPTransactionButtonViewModel new]; + _transactionViewModel.backButtonViewModel = [JPTransactionButtonViewModel new]; } - return _addCardViewModel; + return _transactionViewModel; } @end diff --git a/Source/Modules/Transaction/Presenter/ViewModels/JPCardDetailsMode.h b/Source/Modules/Transaction/Presenter/ViewModels/JPCardDetailsMode.h index 52c5d2ee0..647dda40c 100644 --- a/Source/Modules/Transaction/Presenter/ViewModels/JPCardDetailsMode.h +++ b/Source/Modules/Transaction/Presenter/ViewModels/JPCardDetailsMode.h @@ -2,7 +2,7 @@ // JPCardDetailsMode.h // JudoKit_iOS // -// Copyright (c) 2020 Alternative Payments Ltd +// Copyright (c) 2022 Alternative Payments Ltd // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -24,8 +24,13 @@ #import +/** + * An enum that defines the card details mode + */ typedef NS_ENUM(NSUInteger, JPCardDetailsMode) { JPCardDetailsModeDefault, JPCardDetailsModeAVS, JPCardDetailsModeSecurityCode, + JPCardDetailsModeThreeDS2, + JPCardDetailsModeThreeDS2BillingDetails }; diff --git a/Source/Modules/Transaction/Presenter/ViewModels/JPInputType.h b/Source/Modules/Transaction/Presenter/ViewModels/JPInputType.h index 1a74a47ab..2b5ef0b29 100644 --- a/Source/Modules/Transaction/Presenter/ViewModels/JPInputType.h +++ b/Source/Modules/Transaction/Presenter/ViewModels/JPInputType.h @@ -2,7 +2,7 @@ // JPInputType.h // JudoKit_iOS // -// Copyright (c) 2020 Alternative Payments Ltd +// Copyright (c) 2022 Alternative Payments Ltd // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -24,14 +24,25 @@ #import +#ifndef JPInputType_h +#define JPInputType_h /** - * An enum that defines the input field types present in the Add Card view + * An enum that defines the input field types present in the Add Card and Billing Details views */ typedef NS_ENUM(NSUInteger, JPInputType) { JPInputTypeCardNumber, JPInputTypeCardholderName, JPInputTypeCardExpiryDate, JPInputTypeCardSecureCode, + JPInputTypeCardholderEmail, JPInputTypeCardCountry, + JPInputTypeCardholderPhoneCode, + JPInputTypeCardholderPhone, + JPInputTypeCardholderAddressLine1, + JPInputTypeCardholderAddressLine2, + JPInputTypeCardholderAddressLine3, + JPInputTypeCardholderCity, JPInputTypeCardPostalCode, }; + +#endif /* JPInputType_h */ diff --git a/Source/Modules/Transaction/Presenter/ViewModels/JPTransactionViewModel.h b/Source/Modules/Transaction/Presenter/ViewModels/JPTransactionViewModel.h index 88c147189..2442e3401 100644 --- a/Source/Modules/Transaction/Presenter/ViewModels/JPTransactionViewModel.h +++ b/Source/Modules/Transaction/Presenter/ViewModels/JPTransactionViewModel.h @@ -22,12 +22,15 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#import "JPCardDetailsMode.h" -#import "JPCardNetwork.h" -#import "JPInputType.h" -#import "JPTransactionType.h" #import +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSUInteger, JPInputType); +typedef NS_OPTIONS(NSUInteger, JPCardNetworkType); +typedef NS_ENUM(NSUInteger, JPTransactionType); +typedef NS_ENUM(NSUInteger, JPCardDetailsMode); + #pragma mark - JPTransactionInputFieldViewModel @interface JPTransactionInputFieldViewModel : NSObject @@ -37,33 +40,33 @@ @property (nonatomic, assign) JPInputType type; /** - * Designated initializer that is configured based on an input type - * - * @param inputType - An instance of JPInputType that is used to define the view model + * The text string of the input field */ -+ (instancetype _Nonnull)viewModelWithType:(JPInputType)inputType; +@property (nonatomic, strong, nullable) NSString *text; /** - * Designated initializer that is configured based on an input type - * - * @param inputType - An instance of JPInputType that is used to define the view model + * The placeholder string of the input field */ -- (instancetype _Nonnull)initWithType:(JPInputType)inputType; +@property (nonatomic, strong, nullable) NSString *placeholder; /** - * The text string of the input field + * The error string of the input field */ -@property (nonatomic, strong) NSString *_Nullable text; +@property (nonatomic, strong, nullable) NSString *errorText; /** - * The placeholder string of the input field + * Designated initializer that is configured based on an input type + * + * @param inputType - An instance of JPInputType that is used to define the view model */ -@property (nonatomic, strong) NSString *_Nonnull placeholder; ++ (instancetype)viewModelWithType:(JPInputType)inputType; /** - * The error string of the input field + * Designated initializer that is configured based on an input type + * + * @param inputType - An instance of JPInputType that is used to define the view model */ -@property (nonatomic, strong) NSString *_Nullable errorText; +- (instancetype)initWithType:(JPInputType)inputType; @end @@ -85,7 +88,7 @@ /** * The title of the button */ -@property (nonatomic, strong) NSString *_Nullable title; +@property (nonatomic, strong, nullable) NSString *title; /** * A boolean value that indicates if the button is enabled @@ -94,19 +97,6 @@ @end -#pragma mark - JPTransactionPickerViewModel - -@interface JPTransactionPickerViewModel : JPTransactionInputFieldViewModel - -/** - * An array of strings that act as picker titles - */ -@property (nonatomic, strong) NSArray *_Nonnull pickerTitles; - -@end - -#pragma mark - JPTransactionScanButtonViewModel - #pragma mark - JPTransactionViewModel @interface JPTransactionViewModel : NSObject @@ -121,39 +111,86 @@ */ @property (nonatomic, assign) JPCardDetailsMode mode; +/** + * An array of JPCountries that act as picker titles + */ +@property (nonatomic, strong) NSArray *pickerCountries; + /** * The JPTransactionInputFieldViewModel for the card number input field */ -@property (nonatomic, strong) JPTransactionNumberInputViewModel *_Nonnull cardNumberViewModel; +@property (nonatomic, strong) JPTransactionNumberInputViewModel *cardNumberViewModel; /** * The JPTransactionInputFieldViewModel for the cardholder name input field */ -@property (nonatomic, strong) JPTransactionInputFieldViewModel *_Nonnull cardholderNameViewModel; +@property (nonatomic, strong) JPTransactionInputFieldViewModel *cardholderNameViewModel; /** * The JPTransactionInputFieldViewModel for the expiry date input field */ -@property (nonatomic, strong) JPTransactionInputFieldViewModel *_Nonnull expiryDateViewModel; +@property (nonatomic, strong) JPTransactionInputFieldViewModel *expiryDateViewModel; /** * The JPTransactionInputFieldViewModel for the secure code input field */ -@property (nonatomic, strong) JPTransactionInputFieldViewModel *_Nonnull secureCodeViewModel; +@property (nonatomic, strong) JPTransactionInputFieldViewModel *secureCodeViewModel; + +/** + * The JPTransactionInputFieldViewModel for the cardholder name email field + */ +@property (nonatomic, strong) JPTransactionInputFieldViewModel *cardholderEmailViewModel; + +/** + * The JPTransactionInputFieldViewModel for the country picker + */ +@property (nonatomic, strong) JPTransactionInputFieldViewModel *countryPickerViewModel; + +/** + * The JPTransactionInputFieldViewModel for the cardholder phone code field + */ +@property (nonatomic, strong) JPTransactionInputFieldViewModel *cardholderPhoneCodeViewModel; + +/** + * The JPTransactionInputFieldViewModel for the cardholder name phone number field + */ +@property (nonatomic, strong) JPTransactionInputFieldViewModel *cardholderPhoneViewModel; + +/** + * The JPTransactionInputFieldViewModel for the cardholder adress line 1 input field + */ +@property (nonatomic, strong) JPTransactionInputFieldViewModel *cardholderAddressLine1ViewModel; + +/** + * The JPTransactionInputFieldViewModel for the cardholder adress line 2 input field + */ +@property (nonatomic, strong) JPTransactionInputFieldViewModel *cardholderAddressLine2ViewModel; /** - * The JPTransactionPickerViewModel for the country picker + * The JPTransactionInputFieldViewModel for the cardholder adress line 3 input field */ -@property (nonatomic, strong) JPTransactionPickerViewModel *_Nonnull countryPickerViewModel; +@property (nonatomic, strong) JPTransactionInputFieldViewModel *cardholderAddressLine3ViewModel; + +/** + * The JPTransactionInputFieldViewModel for the cardholder name phone number field + */ +@property (nonatomic, strong) JPTransactionInputFieldViewModel *cardholderCityViewModel; /** * The JPTransactionInputFieldViewModel for the postal code input field */ -@property (nonatomic, strong) JPTransactionInputFieldViewModel *_Nonnull postalCodeInputViewModel; +@property (nonatomic, strong) JPTransactionInputFieldViewModel *postalCodeInputViewModel; /** * The JPTransactionButtonViewModel for the add card button */ -@property (nonatomic, strong) JPTransactionButtonViewModel *_Nonnull addCardButtonViewModel; +@property (nonatomic, strong) JPTransactionButtonViewModel *addCardButtonViewModel; + +/** + * The JPTransactionButtonViewModel for the back from billing details button + */ +@property (nonatomic, strong) JPTransactionButtonViewModel *backButtonViewModel; @end + +NS_ASSUME_NONNULL_END diff --git a/Source/Modules/Transaction/Presenter/ViewModels/JPTransactionViewModel.m b/Source/Modules/Transaction/Presenter/ViewModels/JPTransactionViewModel.m index 5a51097d0..45ade9c29 100644 --- a/Source/Modules/Transaction/Presenter/ViewModels/JPTransactionViewModel.m +++ b/Source/Modules/Transaction/Presenter/ViewModels/JPTransactionViewModel.m @@ -47,10 +47,6 @@ @implementation JPTransactionButtonViewModel @end -@implementation JPTransactionPickerViewModel - -@end - @implementation JPTransactionViewModel @end diff --git a/Source/Modules/Transaction/View/JPTransactionViewController.h b/Source/Modules/Transaction/View/JPTransactionViewController.h index 50269e4c7..37f5e3ab9 100644 --- a/Source/Modules/Transaction/View/JPTransactionViewController.h +++ b/Source/Modules/Transaction/View/JPTransactionViewController.h @@ -28,7 +28,7 @@ #import @protocol JPTransactionPresenter; -@class JPTheme, JPTransactionViewModel, JPInputField; +@class JPTheme, JPTransactionViewModel; #pragma mark - JPTransactionView @@ -37,12 +37,13 @@ /** * A method that updates the view based on the provided view model */ -- (void)updateViewWithViewModel:(nonnull JPTransactionViewModel *)viewModel; +- (void)updateViewWithViewModel:(nonnull JPTransactionViewModel *)viewModel + shouldUpdateTargets:(BOOL)shouldUpdateTargets; /** - * A method that updates the view based on the provided view model + * A method that sets the view theme */ -- (void)loadViewWithMode:(JPCardDetailsMode)mode; +- (void)applyConfiguredTheme:(nonnull JPTheme *)theme; /** * A method that updates the view with an error @@ -80,11 +81,6 @@ @interface JPTransactionViewController : UIViewController -/** - * A reference to the JPTheme instance responsible for customizing the user interface - */ -@property (nonatomic, strong) JPTheme *_Nullable theme; - /** * An object conforming to the JPTransactionViewDelegate protocol */ diff --git a/Source/Modules/Transaction/View/JPTransactionViewController.m b/Source/Modules/Transaction/View/JPTransactionViewController.m index 5aeb08b14..5c09d745f 100644 --- a/Source/Modules/Transaction/View/JPTransactionViewController.m +++ b/Source/Modules/Transaction/View/JPTransactionViewController.m @@ -23,9 +23,12 @@ // SOFTWARE. #import "JPTransactionViewController.h" +#import "JPCardDetailsMode.h" #import "JPCardInputField.h" #import "JPCardInputView.h" #import "JPCardNumberField.h" +#import "JPCountry.h" +#import "JPInputType.h" #import "JPLoadingButton.h" #import "JPTheme.h" #import "JPTransactionButton.h" @@ -35,26 +38,20 @@ @interface JPTransactionViewController () @property (nonatomic, strong) JPCardInputView *addCardView; -@property (nonatomic, strong) NSArray *countryNames; -@property (nonatomic, assign) JPCardDetailsMode mode; +@property (nonatomic, strong) NSArray *countries; @end @implementation JPTransactionViewController #pragma mark - View Lifecycle -- (void)loadView { - [self.presenter prepareInitialViewModel]; -} - -- (void)loadViewWithMode:(JPCardDetailsMode)mode { - self.mode = mode; - self.addCardView = [[JPCardInputView alloc] initWithCardDetailsMode:self.mode]; +- (void)viewDidLoad { + [super viewDidLoad]; + self.addCardView = [JPCardInputView new]; self.view = self.addCardView; - [self.addCardView applyTheme:self.theme]; - [self addTargets]; + [self.presenter prepareInitialViewModel]; + [self _jp_registerKeyboardObservers]; [self addGestureRecognizers]; - if (@available(iOS 13.0, *)) { self.addCardView.scanCardButton.hidden = NO; } else { @@ -62,11 +59,6 @@ - (void)loadViewWithMode:(JPCardDetailsMode)mode { } } -- (void)viewDidLoad { - [super viewDidLoad]; - [self _jp_registerKeyboardObservers]; -} - - (void)dealloc { [self _jp_removeKeyboardObservers]; } @@ -93,6 +85,14 @@ - (void)onAddCardButtonTap { [self.presenter handleTransactionButtonTap]; } +- (void)onContinueButtonTap { + [self.presenter handleContinueButtonTap]; +} + +- (void)onBackButtonTap { + [self.presenter handleBackButtonTap]; +} + - (void)onPayWithSecurityCodeButtonTap { __weak typeof(self) weakSelf = self; [self dismissViewControllerAnimated:true @@ -108,15 +108,21 @@ - (void)onScanCardButtonTap { #pragma mark - View protocol methods -- (void)updateViewWithViewModel:(JPTransactionViewModel *)viewModel { - if (viewModel.mode == JPCardDetailsModeAVS) { +- (void)updateViewWithViewModel:(JPTransactionViewModel *)viewModel + shouldUpdateTargets:(BOOL)shouldUpdateTargets { + if (viewModel.mode == JPCardDetailsModeAVS || viewModel.mode == JPCardDetailsModeThreeDS2BillingDetails) { self.addCardView.countryPickerView.delegate = self; self.addCardView.countryPickerView.dataSource = self; - self.countryNames = viewModel.countryPickerViewModel.pickerTitles; + self.countries = viewModel.pickerCountries; } + shouldUpdateTargets ? [self updateTargets:viewModel] : NULL; [self.addCardView configureWithViewModel:viewModel]; } +- (void)applyConfiguredTheme:(nonnull JPTheme *)theme { + [self.addCardView applyTheme:theme]; +} + - (void)updateViewWithError:(NSError *)error { [self.addCardView enableUserInterface:YES]; [self.addCardView.addCardButton stopLoading]; @@ -177,13 +183,20 @@ - (void)changeFocusToSecurityCodeField { #pragma mark - Layout setup -- (void)addTargets { +- (void)updateTargets:(JPTransactionViewModel *)viewModel { [self _jp_connectButton:self.addCardView.cancelButton withSelector:@selector(onCancelButtonTap)]; - switch (self.mode) { + [self _jp_connectButton:self.addCardView.scanCardButton withSelector:@selector(onScanCardButtonTap)]; + switch (viewModel.mode) { case JPCardDetailsModeDefault: case JPCardDetailsModeAVS: [self _jp_connectButton:self.addCardView.addCardButton withSelector:@selector(onAddCardButtonTap)]; - [self _jp_connectButton:self.addCardView.scanCardButton withSelector:@selector(onScanCardButtonTap)]; + break; + case JPCardDetailsModeThreeDS2: + [self _jp_connectButton:self.addCardView.addCardButton withSelector:@selector(onContinueButtonTap)]; + break; + case JPCardDetailsModeThreeDS2BillingDetails: + [self _jp_connectButton:self.addCardView.addCardButton withSelector:@selector(onAddCardButtonTap)]; + [self _jp_connectButton:self.addCardView.backButton withSelector:@selector(onBackButtonTap)]; break; case JPCardDetailsModeSecurityCode: [self _jp_connectButton:self.addCardView.addCardButton withSelector:@selector(onPayWithSecurityCodeButtonTap)]; @@ -193,6 +206,13 @@ - (void)addTargets { self.addCardView.cardNumberTextField.delegate = self; self.addCardView.cardHolderTextField.delegate = self; + self.addCardView.cardHolderPhoneTextField.delegate = self; + self.addCardView.cardHolderCityTextField.delegate = self; + self.addCardView.cardHolderAddressLine1TextField.delegate = self; + self.addCardView.cardHolderAddressLine2TextField.delegate = self; + self.addCardView.cardHolderAddressLine3TextField.delegate = self; + self.addCardView.cardHolderPhoneCodeTextField.delegate = self; + self.addCardView.cardHolderEmailTextField.delegate = self; self.addCardView.cardExpiryTextField.delegate = self; self.addCardView.secureCodeTextField.delegate = self; self.addCardView.countryTextField.delegate = self; @@ -206,21 +226,22 @@ - (void)addGestureRecognizers { #pragma mark - Keyboard handling logic - (void)_jp_keyboardWillShow:(NSNotification *)notification { - NSTimeInterval duration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; UIViewAnimationCurve curve = [notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue]; CGSize keyboardSize = [[notification.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size; self.addCardView.bottomSliderConstraint.constant = -keyboardSize.height; + [self.view layoutIfNeeded]; __weak typeof(self) weakSelf = self; [UIView animateWithDuration:duration delay:0.0 options:curve animations:^{ + [weakSelf.addCardView adjustTopSpace]; [weakSelf.view layoutIfNeeded]; } - completion:nil]; + completion:^(BOOL finished){}]; } - (void)_jp_keyboardWillHide:(NSNotification *)notification { @@ -228,15 +249,17 @@ - (void)_jp_keyboardWillHide:(NSNotification *)notification { UIViewAnimationCurve curve = [notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue]; self.addCardView.bottomSliderConstraint.constant = 0; + [self.view layoutIfNeeded]; __weak typeof(self) weakSelf = self; [UIView animateWithDuration:duration delay:0.0 options:curve animations:^{ + [weakSelf.addCardView adjustTopSpace]; [weakSelf.view layoutIfNeeded]; } - completion:nil]; + completion:^(BOOL finished){}]; } @end @@ -250,20 +273,21 @@ - (NSInteger)numberOfComponentsInPickerView:(nonnull UIPickerView *)pickerView { } - (NSInteger)pickerView:(nonnull UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component { - return self.countryNames.count; + return self.countries.count; } - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { - [self.presenter handleInputChange:self.countryNames[row] - forType:JPInputTypeCardCountry]; + JPCountry *country = self.countries[row]; + [self.presenter handleInputChange:country.name forType:JPInputTypeCardCountry showError:YES]; } - (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component { - return self.countryNames[row]; + JPCountry *country = self.countries[row]; + return country.name; } @end @@ -273,8 +297,28 @@ - (NSString *)pickerView:(UIPickerView *)pickerView @implementation JPTransactionViewController (InputFieldDelegate) - (BOOL)inputField:(JPInputField *)inputField shouldChangeText:(NSString *)text { - [self.presenter handleInputChange:text forType:inputField.type]; + BOOL showError = inputField.type != JPInputTypeCardholderEmail && inputField.type != JPInputTypeCardholderPhone; + + [self.presenter handleInputChange:text + forType:inputField.type + showError:showError]; return NO; } +- (void)inputField:(JPInputField *)inputField didEndEditing:(NSString *)text { + [self.presenter handleInputChange:text + forType:inputField.type + showError:inputField.type == JPInputTypeCardholderEmail]; +} + +- (void)inputFieldDidBeginEditing:(JPInputField *)inputField { + // UIScrollView *scrollView = self.addCardView.scrollView; + // CGRect visibleScrollRect = UIEdgeInsetsInsetRect(scrollView.bounds, scrollView.contentInset); + // CGRect fieldFrame = inputField.frame; + // + // if (!CGRectContainsRect(visibleScrollRect, fieldFrame)) { + // [scrollView scrollRectToVisible:CGRectInset(fieldFrame, 0, 80) animated:YES]; + // } +} + @end diff --git a/Source/Services/CardTransactionService/JPCardTransactionService.m b/Source/Services/CardTransactionService/JPCardTransactionService.m index f665ba38a..9b9e1e50d 100644 --- a/Source/Services/CardTransactionService/JPCardTransactionService.m +++ b/Source/Services/CardTransactionService/JPCardTransactionService.m @@ -153,26 +153,22 @@ - (void)performTransactionWithType:(JPCardTransactionType)type details:(JPCardTransactionDetails *)details andCompletion:(JPCompletionBlock)completion { @try { - NSString *dsServerID; + NSString *dsServerID = _apiService.isSandboxed ? @"F000000000" : @"unknown-id"; + switch (details.cardType) { case JPCardNetworkTypeVisa: - dsServerID = @"A000000003"; + dsServerID = _apiService.isSandboxed ? @"F055545342" : @"A000000003"; break; case JPCardNetworkTypeMasterCard: - dsServerID = @"A000000004"; + dsServerID = _apiService.isSandboxed ? @"F155545342" : @"A000000004"; break; case JPCardNetworkTypeAMEX: dsServerID = @"A000000025"; break; default: - dsServerID = @"unknown-id"; break; } - if (_apiService.isSandboxed) { - dsServerID = @"F000000000"; - } - NSString *messageVersion = self.configuration.threeDSTwoMessageVersion; JP3DSTransaction *transaction = [self.threeDSTwoService createTransactionWithDirectoryServerID:dsServerID messageVersion:messageVersion]; diff --git a/Source/Services/CardValidation/JPCardValidationService.h b/Source/Services/CardValidation/JPCardValidationService.h index fa4b206fa..e3f46dbca 100644 --- a/Source/Services/CardValidation/JPCardValidationService.h +++ b/Source/Services/CardValidation/JPCardValidationService.h @@ -25,7 +25,7 @@ #import "JPCardNetworkType.h" #import -@class JPCard, JPValidationResult; +@class JPValidationResult; /** * A class that handles credit card validation @@ -62,6 +62,33 @@ */ - (JPValidationResult *)validateCardholderNameInput:(NSString *)input; +/** + * A method for validating the cardholder email + * + * @param input - an input string + * + * @return an instance of JPValidationResult that contains the validation status + */ +- (JPValidationResult *)validateCardholderEmailInput:(NSString *)input; + +/** + * A method for validating the cardholder phone country code + * + * @param input - an input string + * + * @return an instance of JPValidationResult that contains the validation status + */ +- (JPValidationResult *)validateCardholderPhoneCodeInput:(NSString *)input; + +/** + * A method for validating the cardholder phone number + * + * @param input - an input string + * + * @return an instance of JPValidationResult that contains the validation status + */ +- (JPValidationResult *)validateCardholderPhoneInput:(NSString *)input; + /** * A method for validating the expiry date * diff --git a/Source/Services/CardValidation/JPCardValidationService.m b/Source/Services/CardValidation/JPCardValidationService.m index 79886cf37..66c2c41f7 100644 --- a/Source/Services/CardValidation/JPCardValidationService.m +++ b/Source/Services/CardValidation/JPCardValidationService.m @@ -78,6 +78,10 @@ - (JPValidationResult *)validateCardNumberInput:(NSString *)input error = JPError.invalidCardNumberError; } + if ((cardNumber.length == maxCardLength) && (![cardNumber _jp_isValidCardNumber])) { + error = JPError.invalidCardNumberError; + } + if (![self isInputSupported:cardNumber forSupportedNetworks:networks]) { error = [JPError unsupportedCardNetwork:input._jp_cardNetwork]; } @@ -100,6 +104,30 @@ - (JPValidationResult *)validateCardholderNameInput:(NSString *)input { formattedInput:input]; } +- (JPValidationResult *)validateCardholderEmailInput:(NSString *)input { + BOOL isValid = input._jp_isEmail; + return [JPValidationResult validationWithResult:isValid + inputAllowed:YES + errorMessage:isValid ? nil : @"invalid_email_value"._jp_localized + formattedInput:input]; +} + +- (JPValidationResult *)validateCardholderPhoneCodeInput:(NSString *)input { + BOOL isValid = input._jp_isPhoneCode; + return [JPValidationResult validationWithResult:isValid + inputAllowed:YES + errorMessage:isValid ? nil : @"invalid_phone_code_value"._jp_localized + formattedInput:input]; +} + +- (JPValidationResult *)validateCardholderPhoneInput:(NSString *)input { + BOOL isValid = input._jp_isPhoneNumber; + return [JPValidationResult validationWithResult:isValid + inputAllowed:YES + errorMessage:isValid ? nil : @"invalid_phone_value"._jp_localized + formattedInput:input]; +} + - (JPValidationResult *)validateExpiryDateInput:(NSString *)input { if (input.length == 0) { @@ -151,7 +179,6 @@ - (JPValidationResult *)validateCountryInput:(NSString *)input { } - (JPValidationResult *)validatePostalCodeInput:(NSString *)input { - if ([self.selectedJPBillingCountry isEqualToString:@"country_usa"._jp_localized]) { return [self validatePostalCodeInput:input country:JPBillingCountryUSA]; } diff --git a/Source/View/BillingInformationInputView/JPBillingInformationInputView.h b/Source/View/BillingInformationInputView/JPBillingInformationInputView.h deleted file mode 100644 index 99dd7ba0f..000000000 --- a/Source/View/BillingInformationInputView/JPBillingInformationInputView.h +++ /dev/null @@ -1,29 +0,0 @@ -// -// JPBillingInformationInputView.h -// JudoKit_iOS -// -// Copyright (c) 2019 Alternative Payments Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#import - -@interface JPBillingInformationInputView : UIView - -@end diff --git a/Source/View/BillingInformationInputView/JPBillingInformationInputView.m b/Source/View/BillingInformationInputView/JPBillingInformationInputView.m deleted file mode 100644 index 2cb234b59..000000000 --- a/Source/View/BillingInformationInputView/JPBillingInformationInputView.m +++ /dev/null @@ -1,29 +0,0 @@ -// -// JPBillingInformationInputView.m -// JudoKit_iOS -// -// Copyright (c) 2019 Alternative Payments Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#import "JPBillingInformationInputView.h" - -@implementation JPBillingInformationInputView - -@end diff --git a/Source/View/CardInputView/JPCardInputView.h b/Source/View/CardInputView/JPCardInputView.h index 0e68be40c..e033758c0 100644 --- a/Source/View/CardInputView/JPCardInputView.h +++ b/Source/View/CardInputView/JPCardInputView.h @@ -29,15 +29,7 @@ @interface JPCardInputView : UIView -/** - * Designated Initializer - * - * @param mode - the card details mode - * - * @return a JPCardInputView object - */ -- (nonnull instancetype)initWithCardDetailsMode:(JPCardDetailsMode)mode; - +@property (nonatomic, strong) UIScrollView *_Nullable scrollView; /** * The dimmed, semi-transparent background view that fades in when the add card slider appears */ @@ -48,6 +40,11 @@ */ @property (nonatomic, strong) UIButton *_Nullable cancelButton; +/** + * The add address line button that, when pressed, adds a new address line + */ +@property (nonatomic, strong) UIButton *_Nullable addAddressLineButton; + /** * A button that, when pressed, invokes the card scanning functionality */ @@ -63,6 +60,41 @@ */ @property (nonatomic, strong) JPCardInputField *_Nullable cardHolderTextField; +/** + * The input field for adding the cardholder email + */ +@property (nonatomic, strong) JPCardInputField *_Nullable cardHolderEmailTextField; + +/** + * The input field for adding the cardholder phone code + */ +@property (nonatomic, strong) JPCardInputField *_Nullable cardHolderPhoneCodeTextField; + +/** + * The input field for adding the cardholder adress line 1 + */ +@property (nonatomic, strong) JPCardInputField *_Nullable cardHolderAddressLine1TextField; + +/** + * The input field for adding the cardholder adress line 2 + */ +@property (nonatomic, strong) JPCardInputField *_Nullable cardHolderAddressLine2TextField; + +/** + * The input field for adding the cardholder adress line 3 + */ +@property (nonatomic, strong) JPCardInputField *_Nullable cardHolderAddressLine3TextField; + +/** + * The input field for adding the cardholder phone number + */ +@property (nonatomic, strong) JPCardInputField *_Nullable cardHolderPhoneTextField; + +/** + * The input field for adding the cardholder city name + */ +@property (nonatomic, strong) JPCardInputField *_Nullable cardHolderCityTextField; + /** * The input field for adding the card expiration date */ @@ -93,6 +125,11 @@ */ @property (nonatomic, strong) JPTransactionButton *_Nullable addCardButton; +/** + * The Back button that, when tapped, displays card details view + */ +@property (nonatomic, strong) JPTransactionButton *_Nullable backButton; + /** * The Add Card view's bottom constraint that is used to move the view when the keyboard animates */ @@ -119,4 +156,10 @@ */ - (void)enableUserInterface:(BOOL)shouldEnable; +/** + * A method that adjusts view top space + * + */ +- (void)adjustTopSpace; + @end diff --git a/Source/View/CardInputView/JPCardInputView.m b/Source/View/CardInputView/JPCardInputView.m index f5cbb7c59..385161017 100644 --- a/Source/View/CardInputView/JPCardInputView.m +++ b/Source/View/CardInputView/JPCardInputView.m @@ -22,6 +22,7 @@ // SOFTWARE. #import "JPCardInputView.h" +#import "JPCardDetailsMode.h" #import "JPCardInputField.h" #import "JPCardNumberField.h" #import "JPLoadingButton.h" @@ -38,9 +39,16 @@ @interface JPCardInputView () @property (nonatomic, strong) JPRoundedCornerView *bottomSlider; @property (nonatomic, strong) UIStackView *mainStackView; +@property (nonatomic, strong) UIStackView *inputFieldsStackView; +@property (nonatomic, strong) UIStackView *billingDetails; +@property (nonatomic, strong) UIStackView *avsStackView; +@property (nonatomic, strong) UIStackView *bottomButtons; +@property (nonatomic, strong) UIStackView *securityMessageStackView; @property (nonatomic, strong) UIImageView *lockImageView; @property (nonatomic, strong) UILabel *securityMessageLabel; -@property (nonatomic, strong) NSLayoutConstraint *sliderHeightConstraint; +@property (nonatomic, strong) UILabel *billingDetailsLabel; +@property (nonatomic, strong) NSLayoutConstraint *billingDetailsHeightConstraint; +@property (nonatomic, strong) NSLayoutConstraint *topConstraint; @property (nonatomic, copy) void (^onScanCardButtonTapHandler)(void); @property (nonatomic, assign) JPCardDetailsMode mode; @@ -50,9 +58,6 @@ @implementation JPCardInputView #pragma mark - Constants -static const float kStandardSliderHeight = 365.0F; -static const float kCV2dSliderHeight = 250.0F; -static const float kAVSSliderHeight = 410.0F; static const float kScanButtonCornerRadius = 4.0F; static const float kScanButtonBorderWidth = 1.0F; static const float kContentHorizontalPadding = 24.0F; @@ -64,6 +69,10 @@ @implementation JPCardInputView static const float kSliderCornerRadius = 10.0F; static const float kTightContentSpacing = 8.0F; static const float kLooseContentSpacing = 16.0F; +static const float kSeparatorContentSpacing = 1.0F; +static const float kButtonsContentSpacing = 40.0F; +static const float kAnimationTimeInterval = 0.2F; +static const float kPhoneCodeWidth = 45.0F; #pragma mark - Initializers @@ -81,13 +90,41 @@ - (instancetype)initWithCoder:(NSCoder *)coder { return self; } -- (nonnull instancetype)initWithCardDetailsMode:(JPCardDetailsMode)mode { - if (self = [super initWithFrame:CGRectZero]) { - self.mode = mode; - [self setUpWithMode]; - [self setupSubviews]; - } - return self; +- (void)setupSubviews { + self.mode = -1; + [self addSubview:self.backgroundView]; + [self addSubview:self.bottomSlider]; + [self.bottomSlider addSubview:self.mainStackView]; + [self setupConstraints]; + [self.mainStackView addArrangedSubview:self.topButtonStackView]; + [self.mainStackView addArrangedSubview:self.secureCodeTextField]; + [self.mainStackView addArrangedSubview:self.inputFieldsStackView]; + [self.mainStackView addArrangedSubview:self.scrollView]; + + UIView *contentView = [UIView new]; + [self.scrollView addSubview:contentView]; + [contentView _jp_pinToView:self.scrollView withPadding:0]; + contentView.translatesAutoresizingMaskIntoConstraints = NO; + + UIWindow *window = UIApplication.sharedApplication.windows.firstObject; + CGFloat topPadding = window.safeAreaInsets.top; + _topConstraint = [_bottomSlider.topAnchor constraintGreaterThanOrEqualToAnchor:self._jp_safeTopAnchor constant:topPadding]; + [_topConstraint setActive:YES]; + + _billingDetailsHeightConstraint = [self.scrollView.heightAnchor constraintGreaterThanOrEqualToConstant:0]; + _billingDetailsHeightConstraint.priority = UILayoutPriorityDefaultLow; + _billingDetailsHeightConstraint.constant = 0; + [_billingDetailsHeightConstraint setActive:YES]; + + NSString *title = [NSString stringWithFormat:@"button_add_address_line_card"._jp_localized, @(2)]; + [_addAddressLineButton setTitle:title forState:UIControlStateNormal]; + + [[contentView.widthAnchor constraintEqualToAnchor:self.scrollView.widthAnchor] setActive:YES]; + [contentView addSubview:self.billingDetails]; + [_billingDetails _jp_pinToView:contentView withPadding:0]; + + [self.mainStackView addArrangedSubview:self.buttonStackView]; + _bottomButtons.layoutMarginsRelativeArrangement = YES; } #pragma mark - Theming @@ -97,6 +134,10 @@ - (void)applyTheme:(JPTheme *)theme { [self.cancelButton setTitleColor:theme.jpBlackColor forState:UIControlStateNormal]; + self.addAddressLineButton.titleLabel.font = theme.bodyBold; + [self.addAddressLineButton setTitleColor:theme.jpBlackColor + forState:UIControlStateNormal]; + self.scanCardButton.titleLabel.font = theme.bodyBold; [self.scanCardButton setTitleColor:theme.jpBlackColor forState:UIControlStateNormal]; @@ -111,9 +152,24 @@ - (void)applyTheme:(JPTheme *)theme { [self.addCardButton setTitleColor:theme.buttonTitleColor forState:UIControlStateNormal]; + self.backButton.titleLabel.font = theme.bodyBold; + [self.backButton setTitleColor:theme.jpBlackColor + forState:UIControlStateNormal]; + self.backButton.titleLabel.font = theme.headline; + self.securityMessageLabel.font = theme.caption; self.securityMessageLabel.textColor = theme.jpDarkGrayColor; + self.billingDetailsLabel.font = theme.headline; + self.billingDetailsLabel.textColor = theme.jpDarkGrayColor; + + [self.cardHolderEmailTextField applyTheme:theme]; + [self.cardHolderAddressLine1TextField applyTheme:theme]; + [self.cardHolderAddressLine2TextField applyTheme:theme]; + [self.cardHolderAddressLine3TextField applyTheme:theme]; + [self.cardHolderPhoneTextField applyTheme:theme]; + [self.cardHolderCityTextField applyTheme:theme]; + [self.cardHolderPhoneCodeTextField applyTheme:theme]; [self.cardNumberTextField applyTheme:theme]; [self.cardHolderTextField applyTheme:theme]; [self.cardExpiryTextField applyTheme:theme]; @@ -122,36 +178,72 @@ - (void)applyTheme:(JPTheme *)theme { [self.postcodeTextField applyTheme:theme]; } -- (void)setUpWithMode { - switch (self.mode) { - case JPCardDetailsModeSecurityCode: - [self.mainStackView addArrangedSubview:self.topButtonStackViewSecurityCode]; - [self.mainStackView addArrangedSubview:self.secureCodeTextField]; - [self.mainStackView addArrangedSubview:self.buttonStackView]; - break; - case JPCardDetailsModeDefault: - [self.mainStackView addArrangedSubview:self.topButtonStackView]; - [self.mainStackView addArrangedSubview:self.inputFieldsStackView]; - [self.mainStackView addArrangedSubview:self.buttonStackView]; - break; - case JPCardDetailsModeAVS: - [self.mainStackView addArrangedSubview:self.topButtonStackView]; - [self.mainStackView addArrangedSubview:self.inputFieldsStackViewForAVS]; - [self.mainStackView addArrangedSubview:self.buttonStackView]; - break; +- (void)setMode:(JPCardDetailsMode)mode { + if (self.mode != mode) { + _mode = mode; + [self endEditing:YES]; + [UIView animateWithDuration:kAnimationTimeInterval + animations:^{ + [self.mainStackView setAlpha:0.0]; + } + completion:^(BOOL finished) { + [self adjustSubviews]; + [UIView animateWithDuration:kAnimationTimeInterval + animations:^{ + [self.mainStackView setAlpha:1.0]; + } + completion:nil]; + }]; } +} - [self.bottomSlider addSubview:self.mainStackView]; +- (void)adjustSubviews { + [_topConstraint setActive:NO]; + [_scanCardButton setHidden:_mode == JPCardDetailsModeSecurityCode]; + [_avsStackView setHidden:_mode != JPCardDetailsModeAVS]; + [_billingDetails setHidden:_mode != JPCardDetailsModeThreeDS2BillingDetails]; + [_inputFieldsStackView setHidden:_mode == JPCardDetailsModeThreeDS2BillingDetails]; + [_backButton setHidden:_mode != JPCardDetailsModeThreeDS2BillingDetails]; + [_scanCardButton setHidden:(_mode == JPCardDetailsModeThreeDS2BillingDetails || _mode == JPCardDetailsModeSecurityCode)]; + _mode == JPCardDetailsModeAVS + ? [_avsStackView addArrangedSubview:_postcodeTextField] + : [_billingDetails addArrangedSubview:_postcodeTextField]; + CGFloat leftPadding = _mode == JPCardDetailsModeThreeDS2BillingDetails ? 30 : 0; + _bottomButtons.layoutMargins = UIEdgeInsetsMake(0, leftPadding, 0, 0); + _securityMessageStackView.hidden = _mode == JPCardDetailsModeThreeDS2BillingDetails; + _billingDetailsHeightConstraint.constant = _mode == JPCardDetailsModeThreeDS2BillingDetails ? _billingDetails.frame.size.height : 0; + [self adjustTopSpace]; +} + +- (IBAction)showNewAddressLine:(UIButton *)sender { + NSInteger tag = sender.tag; + _cardHolderAddressLine2TextField.hidden = NO; + _cardHolderAddressLine3TextField.hidden = tag < 1; + _addAddressLineButton.hidden = tag > 0; + NSString *title = [NSString stringWithFormat:@"button_add_address_line_card"._jp_localized, @(tag + 3)]; + [_addAddressLineButton setTitle:title forState:UIControlStateNormal]; + sender.tag++; + [self adjustTopSpace]; +} + +- (void)adjustTopSpace { + [_topConstraint setActive:NO]; + [_bottomSlider layoutIfNeeded]; + UIWindow *window = UIApplication.sharedApplication.windows.firstObject; + CGFloat topPadding = window.safeAreaInsets.top; + [_topConstraint setActive:_bottomSlider.frame.origin.y < topPadding]; } + #pragma mark - View model configuration - (void)configureWithViewModel:(JPTransactionViewModel *)viewModel { + self.mode = viewModel.mode; switch (viewModel.mode) { - case JPCardDetailsModeSecurityCode: [self.secureCodeTextField configureWithViewModel:viewModel.secureCodeViewModel]; break; case JPCardDetailsModeDefault: + case JPCardDetailsModeThreeDS2: [self.cardNumberTextField configureWithViewModel:viewModel.cardNumberViewModel]; [self.cardHolderTextField configureWithViewModel:viewModel.cardholderNameViewModel]; [self.cardExpiryTextField configureWithViewModel:viewModel.expiryDateViewModel]; @@ -165,9 +257,21 @@ - (void)configureWithViewModel:(JPTransactionViewModel *)viewModel { [self.countryTextField configureWithViewModel:viewModel.countryPickerViewModel]; [self.postcodeTextField configureWithViewModel:viewModel.postalCodeInputViewModel]; break; + case JPCardDetailsModeThreeDS2BillingDetails: + [self.cardHolderEmailTextField configureWithViewModel:viewModel.cardholderEmailViewModel]; + [self.cardHolderPhoneTextField configureWithViewModel:viewModel.cardholderPhoneViewModel]; + [self.cardHolderCityTextField configureWithViewModel:viewModel.cardholderCityViewModel]; + [self.cardHolderAddressLine1TextField configureWithViewModel:viewModel.cardholderAddressLine1ViewModel]; + [self.cardHolderAddressLine2TextField configureWithViewModel:viewModel.cardholderAddressLine2ViewModel]; + [self.cardHolderAddressLine3TextField configureWithViewModel:viewModel.cardholderAddressLine3ViewModel]; + [self.cardHolderPhoneCodeTextField configureWithViewModel:viewModel.cardholderPhoneCodeViewModel]; + [self.countryTextField configureWithViewModel:viewModel.countryPickerViewModel]; + [self.postcodeTextField configureWithViewModel:viewModel.postalCodeInputViewModel]; + break; } + [_countryPickerView reloadAllComponents]; [self.addCardButton configureWithViewModel:viewModel.addCardButtonViewModel]; - [self setupConstraints]; + [self.backButton configureWithViewModel:viewModel.backButtonViewModel]; } #pragma mark - Helper methods @@ -177,6 +281,10 @@ - (void)enableUserInterface:(BOOL)shouldEnable { self.scanCardButton.enabled = shouldEnable; self.cardNumberTextField.enabled = shouldEnable; self.cardHolderTextField.enabled = shouldEnable; + self.cardHolderPhoneTextField.enabled = shouldEnable; + self.cardHolderCityTextField.enabled = shouldEnable; + self.cardHolderPhoneCodeTextField.enabled = shouldEnable; + self.cardHolderEmailTextField.enabled = shouldEnable; self.cardExpiryTextField.enabled = shouldEnable; self.secureCodeTextField.enabled = shouldEnable; self.countryTextField.enabled = shouldEnable; @@ -186,11 +294,6 @@ - (void)enableUserInterface:(BOOL)shouldEnable { #pragma mark - Layout setup -- (void)setupSubviews { - [self addSubview:self.backgroundView]; - [self addSubview:self.bottomSlider]; -} - - (void)setupConstraints { [self.backgroundView _jp_pinToView:self withPadding:0.0]; [self setupBottomSliderConstraints]; @@ -200,28 +303,16 @@ - (void)setupConstraints { - (void)setupBottomSliderConstraints { [self.bottomSlider _jp_pinToAnchors:JPAnchorTypeLeading | JPAnchorTypeTrailing forView:self]; + [self.bottomSlider _jp_pinToAnchors:JPAnchorTypeBottom forView:self]; if (self.bottomSliderConstraint == nil) { self.bottomSliderConstraint = [self.bottomSlider.bottomAnchor constraintEqualToAnchor:self.bottomAnchor]; } - switch (self.mode) { - case JPCardDetailsModeSecurityCode: - self.sliderHeightConstraint = [self.bottomSlider.heightAnchor constraintEqualToConstant:kCV2dSliderHeight]; - break; - case JPCardDetailsModeDefault: - self.sliderHeightConstraint = [self.bottomSlider.heightAnchor constraintEqualToConstant:kStandardSliderHeight]; - break; - case JPCardDetailsModeAVS: - self.sliderHeightConstraint = [self.bottomSlider.heightAnchor constraintEqualToConstant:kAVSSliderHeight]; - break; - } self.bottomSliderConstraint.active = YES; - self.sliderHeightConstraint.active = YES; } - (void)setupMainStackViewConstraints { - [self.mainStackView _jp_pinToAnchors:JPAnchorTypeTop | JPAnchorTypeBottom forView:self.bottomSlider withPadding:kContentVerticalPadding]; @@ -233,13 +324,23 @@ - (void)setupMainStackViewConstraints { - (void)setupContentsConstraints { NSArray *constraints = @[ + [self.addAddressLineButton.heightAnchor constraintEqualToConstant:kInputFieldHeight], + [self.cardHolderAddressLine1TextField.heightAnchor constraintEqualToConstant:kInputFieldHeight], + [self.cardHolderAddressLine2TextField.heightAnchor constraintEqualToConstant:kInputFieldHeight], + [self.cardHolderAddressLine3TextField.heightAnchor constraintEqualToConstant:kInputFieldHeight], + [self.cardHolderPhoneCodeTextField.heightAnchor constraintEqualToConstant:kInputFieldHeight], + [self.cardHolderPhoneCodeTextField.widthAnchor constraintGreaterThanOrEqualToConstant:0], + [self.cardHolderPhoneTextField.heightAnchor constraintEqualToConstant:kInputFieldHeight], + [self.cardHolderCityTextField.heightAnchor constraintEqualToConstant:kInputFieldHeight], [self.scanCardButton.heightAnchor constraintEqualToConstant:kScanCardHeight], [self.cardNumberTextField.heightAnchor constraintEqualToConstant:kInputFieldHeight], + [self.cardHolderEmailTextField.heightAnchor constraintEqualToConstant:kInputFieldHeight], [self.cardHolderTextField.heightAnchor constraintEqualToConstant:kInputFieldHeight], [self.cardExpiryTextField.heightAnchor constraintEqualToConstant:kInputFieldHeight], [self.secureCodeTextField.heightAnchor constraintEqualToConstant:kInputFieldHeight], [self.countryTextField.heightAnchor constraintEqualToConstant:kInputFieldHeight], [self.postcodeTextField.heightAnchor constraintEqualToConstant:kInputFieldHeight], + [self.backButton.heightAnchor constraintEqualToConstant:kAddCardButtonHeight], [self.addCardButton.heightAnchor constraintEqualToConstant:kAddCardButtonHeight], [self.lockImageView.widthAnchor constraintEqualToConstant:kLockImageWidth], ]; @@ -261,8 +362,7 @@ - (UIView *)backgroundView { - (UIView *)bottomSlider { if (!_bottomSlider) { UIRectCorner corners = UIRectCornerTopRight | UIRectCornerTopLeft; - _bottomSlider = [[JPRoundedCornerView alloc] initWithRadius:kSliderCornerRadius - forCorners:corners]; + _bottomSlider = [[JPRoundedCornerView alloc] initWithRadius:kSliderCornerRadius forCorners:corners]; _bottomSlider.translatesAutoresizingMaskIntoConstraints = NO; _bottomSlider.backgroundColor = UIColor.whiteColor; } @@ -279,11 +379,20 @@ - (UIButton *)cancelButton { return _cancelButton; } +- (UIButton *)addAddressLineButton { + if (!_addAddressLineButton) { + _addAddressLineButton = [UIButton new]; + _addAddressLineButton.translatesAutoresizingMaskIntoConstraints = NO; + _addAddressLineButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; + [_addAddressLineButton addTarget:self action:@selector(showNewAddressLine:) forControlEvents:UIControlEventTouchUpInside]; + } + return _addAddressLineButton; +} + - (UIButton *)scanCardButton { if (!_scanCardButton) { _scanCardButton = [UIButton new]; _scanCardButton.translatesAutoresizingMaskIntoConstraints = NO; - [_scanCardButton setTitle:@"button_scan_card"._jp_localized.uppercaseString forState:UIControlStateNormal]; [_scanCardButton setImage:[UIImage _jp_imageWithIconName:@"scan-card"] forState:UIControlStateNormal]; @@ -313,6 +422,72 @@ - (JPCardInputField *)cardHolderTextField { return _cardHolderTextField; } +- (JPCardInputField *)cardHolderEmailTextField { + if (!_cardHolderEmailTextField) { + _cardHolderEmailTextField = [JPCardInputField new]; + _cardHolderEmailTextField.accessibilityIdentifier = @"Cardholder Email Field"; + _cardHolderEmailTextField.keyboardType = UIKeyboardTypeEmailAddress; + _cardHolderEmailTextField.autocapitalizationType = UITextAutocapitalizationTypeNone; + } + return _cardHolderEmailTextField; +} + +- (JPCardInputField *)cardHolderPhoneCodeTextField { + if (!_cardHolderPhoneCodeTextField) { + _cardHolderPhoneCodeTextField = [JPCardInputField new]; + _cardHolderPhoneCodeTextField.accessibilityIdentifier = @"Cardholder phone code Field"; + _cardHolderPhoneCodeTextField.keyboardType = UIKeyboardTypeNumberPad; + } + return _cardHolderPhoneCodeTextField; +} + +- (JPCardInputField *)cardHolderAddressLine1TextField { + if (!_cardHolderAddressLine1TextField) { + _cardHolderAddressLine1TextField = [JPCardInputField new]; + _cardHolderAddressLine1TextField.accessibilityIdentifier = @"Cardholder address line 1 code Field"; + _cardHolderAddressLine1TextField.keyboardType = UIKeyboardTypeDefault; + } + return _cardHolderAddressLine1TextField; +} + +- (JPCardInputField *)cardHolderAddressLine2TextField { + if (!_cardHolderAddressLine2TextField) { + _cardHolderAddressLine2TextField = [JPCardInputField new]; + _cardHolderAddressLine2TextField.accessibilityIdentifier = @"Cardholder address line 2 Field"; + _cardHolderAddressLine2TextField.keyboardType = UIKeyboardTypeDefault; + _cardHolderAddressLine2TextField.hidden = YES; + } + return _cardHolderAddressLine2TextField; +} + +- (JPCardInputField *)cardHolderAddressLine3TextField { + if (!_cardHolderAddressLine3TextField) { + _cardHolderAddressLine3TextField = [JPCardInputField new]; + _cardHolderAddressLine3TextField.accessibilityIdentifier = @"Cardholder address line 3 Field"; + _cardHolderAddressLine3TextField.keyboardType = UIKeyboardTypeDefault; + _cardHolderAddressLine3TextField.hidden = YES; + } + return _cardHolderAddressLine3TextField; +} + +- (JPCardInputField *)cardHolderPhoneTextField { + if (!_cardHolderPhoneTextField) { + _cardHolderPhoneTextField = [JPCardInputField new]; + _cardHolderPhoneTextField.accessibilityIdentifier = @"Cardholder phone number Field"; + _cardHolderPhoneTextField.keyboardType = UIKeyboardTypeNumberPad; + } + return _cardHolderPhoneTextField; +} + +- (JPCardInputField *)cardHolderCityTextField { + if (!_cardHolderCityTextField) { + _cardHolderCityTextField = [JPCardInputField new]; + _cardHolderCityTextField.accessibilityIdentifier = @"Cardholder city Field"; + _cardHolderCityTextField.keyboardType = UIKeyboardTypeDefault; + } + return _cardHolderCityTextField; +} + - (JPCardInputField *)cardExpiryTextField { if (!_cardExpiryTextField) { _cardExpiryTextField = [JPCardInputField new]; @@ -357,6 +532,16 @@ - (JPCardInputField *)postcodeTextField { return _postcodeTextField; } +- (JPTransactionButton *)backButton { + if (!_backButton) { + _backButton = [JPTransactionButton new]; + _backButton.translatesAutoresizingMaskIntoConstraints = NO; + _backButton.accessibilityIdentifier = @"Back Button"; + _backButton.clipsToBounds = YES; + } + return _backButton; +} + - (JPTransactionButton *)addCardButton { if (!_addCardButton) { _addCardButton = [JPTransactionButton new]; @@ -387,6 +572,16 @@ - (UILabel *)securityMessageLabel { return _securityMessageLabel; } +- (UILabel *)billingDetailsLabel { + if (!_billingDetailsLabel) { + _billingDetailsLabel = [UILabel new]; + _billingDetailsLabel.translatesAutoresizingMaskIntoConstraints = NO; + _billingDetailsLabel.text = @"billing_details_title"._jp_localized; + _billingDetailsLabel.numberOfLines = 0; + } + return _billingDetailsLabel; +} + #pragma mark - Stack Views - (UIStackView *)mainStackView { @@ -396,23 +591,53 @@ - (UIStackView *)mainStackView { return _mainStackView; } -- (UIStackView *)topButtonStackView { - UIStackView *stackView = [UIStackView new]; - stackView.distribution = UIStackViewDistributionFill; - stackView.axis = UILayoutConstraintAxisHorizontal; +- (UIStackView *)billingDetails { + if (!_billingDetails) { + UIStackView *stackView = [UIStackView _jp_verticalStackViewWithSpacing:kTightContentSpacing]; + [stackView addArrangedSubview:self.billingDetailsLabel]; + [stackView addArrangedSubview:self.cardHolderEmailTextField]; + if (_mode != JPCardDetailsModeAVS) { + [stackView addArrangedSubview:self.countryTextField]; + } + [stackView addArrangedSubview:self.phoneStackView]; + [stackView addArrangedSubview:self.cardHolderAddressLine1TextField]; + [stackView addArrangedSubview:self.cardHolderAddressLine2TextField]; + [stackView addArrangedSubview:self.cardHolderAddressLine3TextField]; + [stackView addArrangedSubview:self.addAddressLineButton]; + [stackView addArrangedSubview:self.cardHolderCityTextField]; + [stackView addArrangedSubview:self.postcodeTextField]; + _billingDetails = stackView; + return stackView; + } + return _billingDetails; +} - [stackView addArrangedSubview:self.cancelButton]; - [stackView addArrangedSubview:[UIView new]]; - [stackView addArrangedSubview:self.scanCardButton]; +- (UIStackView *)bottomButtons { + UIStackView *stackView = [UIStackView _jp_horizontalStackViewWithSpacing:kButtonsContentSpacing]; + [stackView addArrangedSubview:self.backButton]; + [stackView addArrangedSubview:self.addCardButton]; + _bottomButtons = stackView; + return stackView; +} +- (UIStackView *)phoneStackView { + UIStackView *stackView = [UIStackView _jp_horizontalStackViewWithSpacing:kSeparatorContentSpacing]; + [stackView addArrangedSubview:self.cardHolderPhoneCodeTextField]; + [stackView addArrangedSubview:self.cardHolderPhoneTextField]; + NSLayoutConstraint *widthLayout = [self.cardHolderPhoneTextField.widthAnchor constraintGreaterThanOrEqualToConstant:kPhoneCodeWidth]; + [widthLayout setActive:YES]; + widthLayout.priority = UILayoutPriorityDefaultHigh; + NSLayoutConstraint *widthCodeLayout = [self.cardHolderPhoneCodeTextField.widthAnchor constraintEqualToConstant:43]; + [widthCodeLayout setActive:YES]; + widthCodeLayout.priority = UILayoutPriorityDefaultLow; return stackView; } -- (UIStackView *)topButtonStackViewSecurityCode { +- (UIStackView *)topButtonStackView { UIStackView *stackView = [UIStackView new]; - [stackView addArrangedSubview:self.cancelButton]; [stackView addArrangedSubview:[UIView new]]; + [stackView addArrangedSubview:self.scanCardButton]; return stackView; } @@ -432,7 +657,7 @@ - (UIStackView *)inputFieldsStackView { [stackView addArrangedSubview:self.cardNumberTextField]; [stackView addArrangedSubview:self.cardHolderTextField]; [stackView addArrangedSubview:self.additionalInputFieldsStackView]; - + _inputFieldsStackView = stackView; return stackView; } @@ -442,8 +667,9 @@ - (UIStackView *)inputFieldsStackViewForAVS { [stackView addArrangedSubview:self.cardNumberTextField]; [stackView addArrangedSubview:self.cardHolderTextField]; [stackView addArrangedSubview:self.additionalInputFieldsStackView]; - [stackView addArrangedSubview:self.avsStackView]; - + _avsStackView = self.avsStackView; + [stackView addArrangedSubview:_avsStackView]; + _inputFieldsStackView = stackView; return stackView; } @@ -452,7 +678,7 @@ - (UIStackView *)avsStackView { stackView.distribution = UIStackViewDistributionFillEqually; [stackView addArrangedSubview:self.countryTextField]; [stackView addArrangedSubview:self.postcodeTextField]; - + _avsStackView = stackView; return stackView; } @@ -460,14 +686,24 @@ - (UIStackView *)securityMessageStackView { UIStackView *stackView = [UIStackView _jp_horizontalStackViewWithSpacing:kTightContentSpacing]; [stackView addArrangedSubview:self.lockImageView]; [stackView addArrangedSubview:self.securityMessageLabel]; + _securityMessageStackView = stackView; return stackView; } - (UIStackView *)buttonStackView { UIStackView *stackView = [UIStackView _jp_verticalStackViewWithSpacing:kLooseContentSpacing]; - [stackView addArrangedSubview:self.addCardButton]; + [stackView addArrangedSubview:self.bottomButtons]; [stackView addArrangedSubview:self.securityMessageStackView]; return stackView; } +- (UIScrollView *)scrollView { + if (!_scrollView) { + _scrollView = [UIScrollView new]; + [_scrollView setShowsVerticalScrollIndicator:NO]; + _scrollView.translatesAutoresizingMaskIntoConstraints = NO; + } + return _scrollView; +} + @end diff --git a/Source/View/InputField/JPInputField.h b/Source/View/InputField/JPInputField.h index bd5a9b17d..40874eb7d 100644 --- a/Source/View/InputField/JPInputField.h +++ b/Source/View/InputField/JPInputField.h @@ -23,15 +23,15 @@ // SOFTWARE. #import "JPInputFieldDelegate.h" -#import "JPInputType.h" #import -@class JPTheme, JPTransactionViewModel; +@class JPTheme; +typedef NS_ENUM(NSUInteger, JPInputType); @interface JPInputField : UIView /** - * An NS_ENUM which describes the type of the input field + * An enum that describes the type of the input field */ @property (nonatomic, assign) JPInputType type; @@ -81,6 +81,11 @@ */ @property (nonatomic, assign) UIKeyboardType keyboardType; +/** + * A property that changes the auto-capitalization of the input field + */ +@property (nonatomic, assign) UITextAutocapitalizationType autocapitalizationType; + /** * A property that changes the keyboard's return type */ diff --git a/Source/View/InputField/JPInputField.m b/Source/View/InputField/JPInputField.m index f036997af..94c8ad149 100644 --- a/Source/View/InputField/JPInputField.m +++ b/Source/View/InputField/JPInputField.m @@ -24,6 +24,7 @@ #import "JPInputField.h" #import "JPFloatingTextField.h" +#import "JPInputType.h" #import "JPTheme.h" #import "UIColor+Additions.h" #import "UIFont+Additions.h" @@ -105,6 +106,26 @@ - (void)setPlaceholder:(NSString *)placeholder { [self.floatingTextField _jp_placeholderWithText:placeholder color:color andFont:font]; } +- (void)setType:(JPInputType)type { + if (type == JPInputTypeCardholderPhoneCode && !_floatingTextField.leftView) { + _floatingTextField.leftView = [self sideViewWithText:@"+("]; + _floatingTextField.rightView = [self sideViewWithText:@")"]; + _floatingTextField.leftViewMode = UITextFieldViewModeAlways; + _floatingTextField.rightViewMode = UITextFieldViewModeAlways; + } + _type = type; +} + +- (UILabel *)sideViewWithText:(NSString *)text { + UILabel *label = [UILabel new]; + label.text = text; + label.textColor = _theme.jpBlackColor; + label.font = _theme.headlineLight; + label.overrideUserInterfaceStyle = UIUserInterfaceStyleLight; + [label sizeToFit]; + return label; +} + - (void)setInputView:(UIView *)inputView { _inputView = inputView; self.floatingTextField.inputView = inputView; @@ -120,6 +141,11 @@ - (void)setKeyboardType:(UIKeyboardType)keyboardType { self.floatingTextField.keyboardType = keyboardType; } +- (void)setAutocapitalizationType:(UITextAutocapitalizationType)autocapitalizationType { + _autocapitalizationType = autocapitalizationType; + self.floatingTextField.autocapitalizationType = autocapitalizationType; +} + - (void)setReturnType:(UIReturnKeyType)returnType { _returnType = returnType; self.floatingTextField.returnKeyType = returnType; @@ -148,7 +174,6 @@ - (BOOL)resignFirstResponder { #pragma mark - Layout setup - (void)setupViews { - self.layer.cornerRadius = 6.0F; self.backgroundColor = UIColor._jp_lightGrayColor; self.translatesAutoresizingMaskIntoConstraints = NO; @@ -196,4 +221,12 @@ - (BOOL)textFieldShouldReturn:(UITextField *)textField { return YES; } +- (void)textFieldDidEndEditing:(UITextField *)textField { + [self.delegate inputField:self didEndEditing:textField.text]; +} + +- (void)textFieldDidBeginEditing:(UITextField *)textField { + [self.delegate inputFieldDidBeginEditing:self]; +} + @end diff --git a/Source/View/InputField/JPInputFieldDelegate.h b/Source/View/InputField/JPInputFieldDelegate.h index 556ef3dd3..1d66bc502 100644 --- a/Source/View/InputField/JPInputFieldDelegate.h +++ b/Source/View/InputField/JPInputFieldDelegate.h @@ -35,5 +35,6 @@ * @param text - the new input string that should change */ - (BOOL)inputField:(JPInputField *)inputField shouldChangeText:(NSString *)text; - +- (void)inputField:(JPInputField *)inputField didEndEditing:(NSString *)text; +- (void)inputFieldDidBeginEditing:(JPInputField *)inputField; @end diff --git a/Source/include/JPCardCustomizationPatternCell.h b/Source/include/JPCardCustomizationPatternCell.h new file mode 120000 index 000000000..7d6d2b1ab --- /dev/null +++ b/Source/include/JPCardCustomizationPatternCell.h @@ -0,0 +1 @@ +../Modules/CardCustomization/View/Cells/CardCustomizationPatternPickerCell/JPCardCustomizationPatternCell.h \ No newline at end of file diff --git a/Source/include/JPCardCustomizationTitleCell.h b/Source/include/JPCardCustomizationTitleCell.h new file mode 120000 index 000000000..a7fe2038e --- /dev/null +++ b/Source/include/JPCardCustomizationTitleCell.h @@ -0,0 +1 @@ +../Modules/CardCustomization/View/Cells/CardCustomizationTitleCell/JPCardCustomizationTitleCell.h \ No newline at end of file diff --git a/Source/include/JPCardCustomizationView.h b/Source/include/JPCardCustomizationView.h new file mode 120000 index 000000000..9670e0ebd --- /dev/null +++ b/Source/include/JPCardCustomizationView.h @@ -0,0 +1 @@ +../Modules/CardCustomization/View/JPCardCustomizationView.h \ No newline at end of file diff --git a/Source/include/JPCardPaymentMethodView.h b/Source/include/JPCardPaymentMethodView.h new file mode 120000 index 000000000..fb7f038f3 --- /dev/null +++ b/Source/include/JPCardPaymentMethodView.h @@ -0,0 +1 @@ +../Modules/PaymentMethods/View/Subviews/CardView/JPCardPaymentMethodView.h \ No newline at end of file diff --git a/Source/include/JPCardTransactionDetails+Additions.h b/Source/include/JPCardTransactionDetails+Additions.h new file mode 120000 index 000000000..e23e3c233 --- /dev/null +++ b/Source/include/JPCardTransactionDetails+Additions.h @@ -0,0 +1 @@ +../Extensions/JPCardTransactionDetails/JPCardTransactionDetails+Additions.h \ No newline at end of file diff --git a/Source/include/JPOtherPaymentMethodView.h b/Source/include/JPOtherPaymentMethodView.h new file mode 120000 index 000000000..10c9f811b --- /dev/null +++ b/Source/include/JPOtherPaymentMethodView.h @@ -0,0 +1 @@ +../Modules/PaymentMethods/View/Subviews/CardView/JPOtherPaymentMethodView.h \ No newline at end of file diff --git a/Source/include/JPPaymentMethodsCardCell.h b/Source/include/JPPaymentMethodsCardCell.h new file mode 120000 index 000000000..40708e0bd --- /dev/null +++ b/Source/include/JPPaymentMethodsCardCell.h @@ -0,0 +1 @@ +../Modules/PaymentMethods/View/Subviews/Cells/CardCell/JPPaymentMethodsCardCell.h \ No newline at end of file diff --git a/Source/include/JPPaymentMethodsCardListFooterCell.h b/Source/include/JPPaymentMethodsCardListFooterCell.h new file mode 120000 index 000000000..9d9ac9742 --- /dev/null +++ b/Source/include/JPPaymentMethodsCardListFooterCell.h @@ -0,0 +1 @@ +../Modules/PaymentMethods/View/Subviews/Cells/CardListFooterCell/JPPaymentMethodsCardListFooterCell.h \ No newline at end of file diff --git a/Source/include/JPPaymentMethodsEmptyCardListCell.h b/Source/include/JPPaymentMethodsEmptyCardListCell.h new file mode 120000 index 000000000..c5b879ff0 --- /dev/null +++ b/Source/include/JPPaymentMethodsEmptyCardListCell.h @@ -0,0 +1 @@ +../Modules/PaymentMethods/View/Subviews/Cells/EmptyCardListCell/JPPaymentMethodsEmptyCardListCell.h \ No newline at end of file diff --git a/Source/include/JPPaymentMethodsIDEALBankCell.h b/Source/include/JPPaymentMethodsIDEALBankCell.h new file mode 120000 index 000000000..db5c11be1 --- /dev/null +++ b/Source/include/JPPaymentMethodsIDEALBankCell.h @@ -0,0 +1 @@ +../Modules/PaymentMethods/View/Subviews/Cells/iDEALBankCell/JPPaymentMethodsIDEALBankCell.h \ No newline at end of file diff --git a/Source/include/JPPaymentMethodsView.h b/Source/include/JPPaymentMethodsView.h new file mode 120000 index 000000000..495554de4 --- /dev/null +++ b/Source/include/JPPaymentMethodsView.h @@ -0,0 +1 @@ +../Modules/PaymentMethods/View/JPPaymentMethodsView.h \ No newline at end of file diff --git a/Source/include/JPSliderPresentationController.h b/Source/include/JPSliderPresentationController.h new file mode 120000 index 000000000..dda48d0b0 --- /dev/null +++ b/Source/include/JPSliderPresentationController.h @@ -0,0 +1 @@ +../Transitions/JPSliderPresentationController.h \ No newline at end of file diff --git a/Source/include/create_symlinks.sh b/Source/include/create_symlinks.sh index 240083521..5249dde84 100755 --- a/Source/include/create_symlinks.sh +++ b/Source/include/create_symlinks.sh @@ -1,10 +1,12 @@ #!/usr/bin/env bash +# public headers ln -s -f ../JudoKit_iOS.h JudoKit_iOS.h ln -s -f ../Models/CardDetails/JPCardNetworkType.h JPCardNetworkType.h ln -s -f ../Models/ApplePayWrappers/JPApplePayWrappers.h JPApplePayWrappers.h ln -s -f ../Models/CardDetails/JPCardDetails.h JPCardDetails.h ln -s -f ../Models/Transaction/JPTransactionMode.h JPTransactionMode.h +ln -s -f ../View/LoadingButton/JPLoadingButton.h JPLoadingButton.h ln -s -f ../Models/SDKInfo/JPSDKInfo.h JPSDKInfo.h ln -s -f ../Models/Transaction/JPTransactionType.h JPTransactionType.h ln -s -f ../Models/ClientDetails/JPClientDetails.h JPClientDetails.h @@ -19,11 +21,11 @@ ln -s -f ../Models/PBBAConfiguration/JPPBBAConfiguration.h JPPBBAConfiguration.h ln -s -f ../Models/CardStorage/JPCardStorage.h JPCardStorage.h ln -s -f ../Models/IDEALBank/JPIDEALBank.h JPIDEALBank.h ln -s -f ../Services/CardTransactionService/JPCardTransactionService.h JPCardTransactionService.h -ln -s -f ../Models/CardTransactionDetails/JPCardTransactionDetails.h JPCardTransactionDetails.h ln -s -f ../Models/ConsumerDevice/JPConsumerDevice.h JPConsumerDevice.h ln -s -f ../Services/ApplePay/JPApplePayController.h JPApplePayController.h ln -s -f ../Models/DictionaryConvertible/JPDictionaryConvertible.h JPDictionaryConvertible.h ln -s -f ../Models/Section/JPSection.h JPSection.h +ln -s -f ../Models/CardTransactionDetails/JPCardTransactionDetails.h JPCardTransactionDetails.h ln -s -f ../Models/Consumer/JPConsumer.h JPConsumer.h ln -s -f ../Models/Theme/JPTheme.h JPTheme.h ln -s -f ../Models/Constants/JPConstants.h JPConstants.h @@ -38,9 +40,9 @@ ln -s -f ../Models/Country/JPCountry.h JPCountry.h ln -s -f ../Models/PaymentMethod/JPPaymentMethodType.h JPPaymentMethodType.h ln -s -f ../Models/Reference/JPReference.h JPReference.h ln -s -f ../Models/Authorization/Session/JPSessionAuthorization.h JPSessionAuthorization.h +ln -s -f ../Extensions/NSString/NSString+Additions.h NSString+Additions.h ln -s -f ../Models/Reachability/JPReachability.h JPReachability.h ln -s -f ../Models/ThreeDSecure/JPThreeDSecure.h JPThreeDSecure.h -ln -s -f ../Models/ThreeDSecureTwo/JPThreeDSecureTwo.h JPThreeDSecureTwo.h ln -s -f ../Services/ApplePay/JPApplePayTypedefs.h JPApplePayTypedefs.h ln -s -f ../Extensions/UIColor/UIColor+Additions.h UIColor+Additions.h ln -s -f ../Models/StoredCardDetails/JPStoredCardDetails.h JPStoredCardDetails.h @@ -49,14 +51,17 @@ ln -s -f ../Models/3DSConfiguration/JP3DSConfiguration.h JP3DSConfiguration.h ln -s -f ../Models/Authorization/JPAuthorization.h JPAuthorization.h ln -s -f ../Models/Response/JPResponse.h JPResponse.h ln -s -f ../Models/ApplePayWrappers/JPApplePayTypes.h JPApplePayTypes.h +ln -s -f ../Models/NetworkTimeout/JPNetworkTimeout.h JPNetworkTimeout.h ln -s -f ../Models/ValidationResult/JPValidationResult.h JPValidationResult.h ln -s -f ../Models/OrderDetails/JPOrderDetails.h JPOrderDetails.h ln -s -f ../Models/PaymentShippingMethod/JPPaymentShippingMethod.h JPPaymentShippingMethod.h +ln -s -f ../Models/Request/JPComplete3DS2Request.h JPComplete3DS2Request.h ln -s -f ../Extensions/JPError/JPError+Additions.h JPError+Additions.h ln -s -f ../Models/PaymentMethods/JPPaymentMethods.h JPPaymentMethods.h ln -s -f ../Models/CardNetwork/JPCardNetwork.h JPCardNetwork.h ln -s -f ../Extensions/UIFont/UIFont+Additions.h UIFont+Additions.h ln -s -f ../Models/PaymentSummaryItem/JPPaymentSummaryItem.h JPPaymentSummaryItem.h +ln -s -f ../Extensions/NSBundle/NSBundle+Additions.h NSBundle+Additions.h ln -s -f ../Models/Transaction/JPTransactionResult.h JPTransactionResult.h ln -s -f ../Models/PrimaryAccountDetails/JPPrimaryAccountDetails.h JPPrimaryAccountDetails.h ln -s -f ../Models/ApplePayConfiguration/JPApplePayConfiguration.h JPApplePayConfiguration.h @@ -77,88 +82,99 @@ ln -s -f ../Models/Request/JPSaveCardRequest.h JPSaveCardRequest.h ln -s -f ../Models/Request/JPCheckCardRequest.h JPCheckCardRequest.h ln -s -f ../Models/Request/JPApplePayRequest.h JPApplePayRequest.h ln -s -f ../Models/Request/JP3DSecureAuthenticationResult.h JP3DSecureAuthenticationResult.h -ln -s -f ../View/LoadingButton/JPLoadingButton.h JPLoadingButton.h -ln -s -f ../Extensions/NSString/NSString+Additions.h NSString+Additions.h -ln -s -f ../Extensions/NSBundle/NSBundle+Additions.h NSBundle+Additions.h -ln -s -f ../Extensions/UIView/UIView+Additions.h UIView+Additions.h -ln -s -f ../Modules/Transaction/Presenter/ViewModels/JPTransactionViewModel.h JPTransactionViewModel.h -ln -s -f ../Extensions/UIStackView/UIStackView+Additions.h UIStackView+Additions.h -ln -s -f ../Modules/IDEALViewController/TransactionStatusView/JPTransactionStatusView.h JPTransactionStatusView.h -ln -s -f ../Modules/CardScanController/JPCardScanControllerDelegate.h JPCardScanControllerDelegate.h -ln -s -f ../Modules/Transaction/Presenter/ViewModels/JPCardDetailsMode.h JPCardDetailsMode.h -ln -s -f ../View/InputField/JPInputFieldDelegate.h JPInputFieldDelegate.h -ln -s -f ../Extensions/NSArray/NSArray+Additions.h NSArray+Additions.h -ln -s -f ../Extensions/NSObject/NSObject+Additions.h NSObject+Additions.h -ln -s -f ../Helpers/Functions.h Functions.h -ln -s -f ../Extensions/JPRequest/JPRequest+Additions.h JPRequest+Additions.h -ln -s -f ../Modules/PaymentMethods/View/Subviews/Cells/CardListHeaderCell/JPPaymentMethodsCardListHeaderCellDelegate.h JPPaymentMethodsCardListHeaderCellDelegate.h -ln -s -f ../Modules/PaymentMethods/View/Subviews/Cells/JPPaymentMethodConfigurable.h JPPaymentMethodConfigurable.h -ln -s -f ../Services/ApplePay/JPApplePayService.h JPApplePayService.h -ln -s -f ../View/ApplePayButton/JPApplePayButton.h JPApplePayButton.h -ln -s -f ../Modules/Transaction/Presenter/ViewModels/JPInputType.h JPInputType.h -ln -s -f ../Extensions/CLLocation/CLLocation+Additions.h CLLocation+Additions.h -ln -s -f ../Modules/CardCustomization/Presenter/JPCardCustomizationViewModel.h JPCardCustomizationViewModel.h -ln -s -f ../Services/Keychain/JPKeychainService.h JPKeychainService.h -ln -s -f ../Services/iDEAL/JPIDEALService.h JPIDEALService.h -ln -s -f ../View/InputField/JPInputField.h JPInputField.h -ln -s -f ../Extensions/UIImage/UIImage+Additions.h UIImage+Additions.h -ln -s -f ../Modules/CardCustomization/View/Cells/CardCustomizationPatternPickerCell/JPCardCustomizationPatternPickerCellDelegate.h JPCardCustomizationPatternPickerCellDelegate.h -ln -s -f ../Modules/CardCustomization/View/Cells/JPCardCustomizable.h JPCardCustomizable.h -ln -s -f ../Modules/CardCustomization/View/JPCardCustomizationViewController.h JPCardCustomizationViewController.h -ln -s -f ../Modules/CardCustomization/Interactor/JPCardCustomizationInteractor.h JPCardCustomizationInteractor.h -ln -s -f ../Helpers/JPFormatters/JPFormatters.h JPFormatters.h -ln -s -f ../Models/SessionConfiguration/JPSessionConfiguration.h JPSessionConfiguration.h -ln -s -f ../Modules/3DSViewController/JP3DSViewController.h JP3DSViewController.h -ln -s -f ../Modules/CardScanController/View/JPCardScanPreviewLayer.h JPCardScanPreviewLayer.h -ln -s -f ../Modules/Transaction/Interactor/JPTransactionInteractor.h JPTransactionInteractor.h -ln -s -f ../Modules/CardScanController/JPCardScanController.h JPCardScanController.h -ln -s -f ../View/CardInputView/Subviews/JPCardInputField.h JPCardInputField.h -ln -s -f ../Services/CardValidation/JPCardValidationService.h JPCardValidationService.h -ln -s -f ../Modules/PaymentMethods/Presenter/JPPaymentMethodsViewModel.h JPPaymentMethodsViewModel.h -ln -s -f ../Modules/CardCustomization/Builder/JPCardCustomizationBuilder.h JPCardCustomizationBuilder.h -ln -s -f ../Modules/PaymentMethods/Interactor/JPPaymentMethodsInteractor.h JPPaymentMethodsInteractor.h -ln -s -f ../Services/ConfigurationValidation/JPConfigurationValidationService.h JPConfigurationValidationService.h + +# project headers ln -s -f ../View/SectionView/JPSectionViewDelegate.h JPSectionViewDelegate.h -ln -s -f ../Modules/PaymentMethods/View/Subviews/JPPaymentMethodsHeaderView.h JPPaymentMethodsHeaderView.h -ln -s -f ../Modules/PaymentMethods/View/Subviews/CardView/JPCardView.h JPCardView.h -ln -s -f ../View/FloatingTextField/JPFloatingTextField.h JPFloatingTextField.h -ln -s -f ../Modules/CardCustomization/View/Cells/CardCustomizationSubmitCell/JPCardCustomizationSubmitCellDelegate.h JPCardCustomizationSubmitCellDelegate.h +ln -s -f ../Modules/PaymentMethods/Interactor/JPPaymentMethodsInteractor.h JPPaymentMethodsInteractor.h +ln -s -f ../Modules/PaymentMethods/View/Subviews/Cells/CardListFooterCell/JPPaymentMethodsCardListFooterCell.h JPPaymentMethodsCardListFooterCell.h +ln -s -f ../Modules/PaymentMethods/View/Subviews/Cells/CardListHeaderCell/JPPaymentMethodsCardListHeaderCell.h JPPaymentMethodsCardListHeaderCell.h +ln -s -f ../Modules/IDEALViewController/JPIDEALViewController.h JPIDEALViewController.h +ln -s -f ../Extensions/UIViewController/UIViewController+Additions.h UIViewController+Additions.h +ln -s -f ../Modules/Transaction/Interactor/JPTransactionInteractor.h JPTransactionInteractor.h ln -s -f ../Modules/CardCustomization/Presenter/JPCardCustomizationPresenter.h JPCardCustomizationPresenter.h -ln -s -f ../Modules/CardCustomization/Router/JPCardCustomizationRouter.h JPCardCustomizationRouter.h -ln -s -f ../Extensions/NSLayoutConstraint/NSLayoutConstraint+Additions.h NSLayoutConstraint+Additions.h ln -s -f ../Extensions/UIApplication/UIApplication+Additions.h UIApplication+Additions.h -ln -s -f ../View/LoadingView/JPLoadingView.h JPLoadingView.h -ln -s -f ../Modules/CardScanController/View/JPCardScanView.h JPCardScanView.h +ln -s -f ../Modules/Transaction/Builder/JPTransactionBuilder.h JPTransactionBuilder.h +ln -s -f ../Modules/PaymentMethods/View/JPPaymentMethodsViewController.h JPPaymentMethodsViewController.h +ln -s -f ../Modules/Transaction/Presenter/ViewModels/JPInputType.h JPInputType.h +ln -s -f ../Modules/PaymentMethods/View/Subviews/Cells/PaymentMethodSelectionCell/JPPaymentMethodsSelectionCell.h JPPaymentMethodsSelectionCell.h ln -s -f ../View/CardInputView/JPCardInputView.h JPCardInputView.h +ln -s -f ../Modules/PaymentMethods/View/Subviews/Header/JPPaymentMethodsCardHeaderView.h JPPaymentMethodsCardHeaderView.h +ln -s -f ../Extensions/UIImage/UIImage+Additions.h UIImage+Additions.h +ln -s -f ../Modules/3DSViewController/JP3DSViewController.h JP3DSViewController.h +ln -s -f ../Modules/CardCustomization/View/Cells/CardCustomizationSubmitCell/JPCardCustomizationSubmitCellDelegate.h JPCardCustomizationSubmitCellDelegate.h +ln -s -f ../Helpers/JPFormatters/JPFormatters.h JPFormatters.h +ln -s -f ../View/RoundedCornerView/JPRoundedCornerView.h JPRoundedCornerView.h +ln -s -f ../Extensions/CLLocation/CLLocation+Additions.h CLLocation+Additions.h +ln -s -f ../Modules/CardScanController/JPCardScanControllerDelegate.h JPCardScanControllerDelegate.h ln -s -f ../Services/PBBA/JPPBBAService.h JPPBBAService.h -ln -s -f ../Modules/IDEALViewController/JPIDEALViewController.h JPIDEALViewController.h -ln -s -f ../Modules/Transaction/View/JPTransactionViewDelegate.h JPTransactionViewDelegate.h -ln -s -f ../View/SectionView/JPSectionView.h JPSectionView.h +ln -s -f ../Extensions/JPResponse/JPResponse+Additions.h JPResponse+Additions.h +ln -s -f ../Modules/CardCustomization/View/Cells/CardCustomizationTitleCell/JPCardCustomizationTitleCell.h JPCardCustomizationTitleCell.h ln -s -f ../Extensions/UITextField/UITextField+Additions.h UITextField+Additions.h -ln -s -f ../View/CardInputView/Subviews/JPCardNumberField.h JPCardNumberField.h -ln -s -f ../Modules/Transaction/Router/JPTransactionRouter.h JPTransactionRouter.h -ln -s -f ../Modules/CardCustomization/View/Cells/CardCustomizationHeaderCell/JPCardCustomizationHeaderCell.h JPCardCustomizationHeaderCell.h +ln -s -f ../Modules/PaymentMethods/View/Subviews/Header/JPPaymentMethodsEmptyHeaderView.h JPPaymentMethodsEmptyHeaderView.h +ln -s -f ../Extensions/NSArray/NSArray+Additions.h NSArray+Additions.h +ln -s -f ../Modules/IDEALViewController/TransactionStatusView/JPTransactionStatusView.h JPTransactionStatusView.h +ln -s -f ../Services/CardValidation/JPCardValidationService.h JPCardValidationService.h ln -s -f ../Modules/Transaction/Presenter/JPTransactionPresenter.h JPTransactionPresenter.h -ln -s -f ../Extensions/NSNumberFormatter/NSNumberFormatter+Additions.h NSNumberFormatter+Additions.h -ln -s -f ../View/CardInputView/Subviews/JPTransactionButton.h JPTransactionButton.h +ln -s -f ../Modules/CardCustomization/Presenter/JPCardCustomizationViewModel.h JPCardCustomizationViewModel.h +ln -s -f ../Modules/CardCustomization/View/Cells/CardCustomizationPatternPickerCell/JPCardCustomizationPatternCell.h JPCardCustomizationPatternCell.h ln -s -f ../Modules/PaymentMethods/Presenter/JPPaymentMethodsPresenter.h JPPaymentMethodsPresenter.h -ln -s -f ../View/RoundedCornerView/JPRoundedCornerView.h JPRoundedCornerView.h -ln -s -f ../Modules/Transaction/View/JPTransactionViewController.h JPTransactionViewController.h -ln -s -f ../Modules/CardCustomization/View/Cells/CardCustomizationIsDefaultCell/JPCardCustomizationIsDefaultCell.h JPCardCustomizationIsDefaultCell.h -ln -s -f ../Extensions/UIViewController/UIViewController+Additions.h UIViewController+Additions.h -ln -s -f ../Modules/PaymentMethods/View/JPPaymentMethodsViewController.h JPPaymentMethodsViewController.h +ln -s -f ../Modules/PaymentMethods/View/Subviews/JPPaymentMethodsHeaderView.h JPPaymentMethodsHeaderView.h +ln -s -f ../Modules/CardCustomization/Interactor/JPCardCustomizationInteractor.h JPCardCustomizationInteractor.h +ln -s -f ../Services/iDEAL/JPIDEALService.h JPIDEALService.h +ln -s -f ../Modules/Transaction/Presenter/ViewModels/JPTransactionViewModel.h JPTransactionViewModel.h +ln -s -f ../Modules/PaymentMethods/Router/JPPaymentMethodsRouter.h JPPaymentMethodsRouter.h +ln -s -f ../Services/Keychain/JPKeychainService.h JPKeychainService.h +ln -s -f ../Services/ApplePay/JPApplePayService.h JPApplePayService.h +ln -s -f ../View/LoadingView/JPLoadingView.h JPLoadingView.h ln -s -f ../Modules/CardCustomization/View/Cells/CardCustomizationPatternPickerCell/JPCardCustomizationPatternPickerCell.h JPCardCustomizationPatternPickerCell.h +ln -s -f ../View/FloatingTextField/JPFloatingTextField.h JPFloatingTextField.h +ln -s -f ../View/CardInputView/Subviews/JPTransactionButton.h JPTransactionButton.h +ln -s -f ../Modules/PaymentMethods/View/Subviews/Cells/CardListHeaderCell/JPPaymentMethodsCardListHeaderCellDelegate.h JPPaymentMethodsCardListHeaderCellDelegate.h +ln -s -f ../Modules/CardScanController/View/JPCardScanPreviewLayer.h JPCardScanPreviewLayer.h +ln -s -f ../Extensions/NSLayoutConstraint/NSLayoutConstraint+Additions.h NSLayoutConstraint+Additions.h +ln -s -f ../Modules/PaymentMethods/View/JPPaymentMethodsView.h JPPaymentMethodsView.h ln -s -f ../Modules/CardCustomization/View/Cells/CardCustomizationSubmitCell/JPCardCustomizationSubmitCell.h JPCardCustomizationSubmitCell.h -ln -s -f ../Modules/CardCustomization/View/Cells/CardCustomizationTextInputCell/JPCardCustomizationTextInputCell.h JPCardCustomizationTextInputCell.h -ln -s -f ../Transitions/JPSliderTransitioningDelegate.h JPSliderTransitioningDelegate.h -ln -s -f ../Modules/PaymentMethods/View/Subviews/Cells/CardListHeaderCell/JPPaymentMethodsCardListHeaderCell.h JPPaymentMethodsCardListHeaderCell.h -ln -s -f ../Modules/PaymentMethods/View/Subviews/Cells/PaymentMethodSelectionCell/JPPaymentMethodsSelectionCell.h JPPaymentMethodsSelectionCell.h -ln -s -f ../Modules/PaymentMethods/View/Subviews/Header/JPPaymentMethodsCardHeaderView.h JPPaymentMethodsCardHeaderView.h -ln -s -f ../Modules/PaymentMethods/View/Subviews/Header/JPPaymentMethodsEmptyHeaderView.h JPPaymentMethodsEmptyHeaderView.h +ln -s -f ../View/InputField/JPInputField.h JPInputField.h +ln -s -f ../Extensions/UIStackView/UIStackView+Additions.h UIStackView+Additions.h +ln -s -f ../Models/ThreeDSecureTwo/JPThreeDSecureTwo.h JPThreeDSecureTwo.h +ln -s -f ../Modules/PaymentMethods/View/Subviews/Cells/JPPaymentMethodConfigurable.h JPPaymentMethodConfigurable.h +ln -s -f ../Modules/PaymentMethods/View/Subviews/CardView/JPOtherPaymentMethodView.h JPOtherPaymentMethodView.h +ln -s -f ../Modules/CardCustomization/View/Cells/CardCustomizationPatternPickerCell/JPCardCustomizationPatternPickerCellDelegate.h JPCardCustomizationPatternPickerCellDelegate.h +ln -s -f ../Modules/PaymentMethods/View/Subviews/Cells/EmptyCardListCell/JPPaymentMethodsEmptyCardListCell.h JPPaymentMethodsEmptyCardListCell.h +ln -s -f ../Modules/PaymentMethods/View/Subviews/CardView/JPCardView.h JPCardView.h +ln -s -f ../Helpers/Functions.h Functions.h ln -s -f ../Modules/PaymentMethods/Builder/JPPaymentMethodsBuilder.h JPPaymentMethodsBuilder.h -ln -s -f ../Modules/PaymentMethods/Router/JPPaymentMethodsRouter.h JPPaymentMethodsRouter.h -ln -s -f ../Modules/Transaction/Builder/JPTransactionBuilder.h JPTransactionBuilder.h -ln -s -f ../Models/Request/JPComplete3DS2Request.h JPComplete3DS2Request.h -ln -s -f ../Extensions/JPResponse/JPResponse+Additions.h JPResponse+Additions.h +ln -s -f ../Transitions/JPSliderTransitioningDelegate.h JPSliderTransitioningDelegate.h +ln -s -f ../Modules/Transaction/Router/JPTransactionRouter.h JPTransactionRouter.h +ln -s -f ../View/ApplePayButton/JPApplePayButton.h JPApplePayButton.h +ln -s -f ../Services/ConfigurationValidation/JPConfigurationValidationService.h JPConfigurationValidationService.h +ln -s -f ../View/CardInputView/Subviews/JPCardInputField.h JPCardInputField.h +ln -s -f ../View/SectionView/JPSectionView.h JPSectionView.h +ln -s -f ../Modules/CardScanController/JPCardScanController.h JPCardScanController.h +ln -s -f ../Modules/Transaction/View/JPTransactionViewController.h JPTransactionViewController.h +ln -s -f ../Modules/CardCustomization/Builder/JPCardCustomizationBuilder.h JPCardCustomizationBuilder.h +ln -s -f ../Modules/PaymentMethods/View/Subviews/CardView/JPCardPaymentMethodView.h JPCardPaymentMethodView.h +ln -s -f ../Modules/CardCustomization/View/Cells/CardCustomizationTextInputCell/JPCardCustomizationTextInputCell.h JPCardCustomizationTextInputCell.h +ln -s -f ../Modules/PaymentMethods/View/Subviews/Cells/iDEALBankCell/JPPaymentMethodsIDEALBankCell.h JPPaymentMethodsIDEALBankCell.h +ln -s -f ../Extensions/JPCardTransactionDetails/JPCardTransactionDetails+Additions.h JPCardTransactionDetails+Additions.h +ln -s -f ../Modules/PaymentMethods/Presenter/JPPaymentMethodsViewModel.h JPPaymentMethodsViewModel.h +ln -s -f ../Modules/CardCustomization/View/JPCardCustomizationViewController.h JPCardCustomizationViewController.h +ln -s -f ../Modules/CardCustomization/View/Cells/JPCardCustomizable.h JPCardCustomizable.h +ln -s -f ../Transitions/JPSliderPresentationController.h JPSliderPresentationController.h +ln -s -f ../Extensions/JPRequest/JPRequest+Additions.h JPRequest+Additions.h +ln -s -f ../Modules/CardCustomization/View/Cells/CardCustomizationHeaderCell/JPCardCustomizationHeaderCell.h JPCardCustomizationHeaderCell.h +ln -s -f ../Extensions/UIView/UIView+Additions.h UIView+Additions.h +ln -s -f ../Modules/CardCustomization/View/JPCardCustomizationView.h JPCardCustomizationView.h +ln -s -f ../Modules/CardScanController/View/JPCardScanView.h JPCardScanView.h +ln -s -f ../Modules/CardCustomization/Router/JPCardCustomizationRouter.h JPCardCustomizationRouter.h +ln -s -f ../Modules/CardCustomization/View/Cells/CardCustomizationIsDefaultCell/JPCardCustomizationIsDefaultCell.h JPCardCustomizationIsDefaultCell.h +ln -s -f ../Modules/PaymentMethods/View/Subviews/Cells/CardCell/JPPaymentMethodsCardCell.h JPPaymentMethodsCardCell.h +ln -s -f ../View/CardInputView/Subviews/JPCardNumberField.h JPCardNumberField.h +ln -s -f ../Extensions/NSObject/NSObject+Additions.h NSObject+Additions.h +ln -s -f ../Modules/Transaction/View/JPTransactionViewDelegate.h JPTransactionViewDelegate.h +ln -s -f ../View/InputField/JPInputFieldDelegate.h JPInputFieldDelegate.h +ln -s -f ../Models/SessionConfiguration/JPSessionConfiguration.h JPSessionConfiguration.h +ln -s -f ../Extensions/NSNumberFormatter/NSNumberFormatter+Additions.h NSNumberFormatter+Additions.h ln -s -f ../Models/CReqParameters/JPCReqParameters.h JPCReqParameters.h +ln -s -f ../Modules/Transaction/Presenter/ViewModels/JPCardDetailsMode.h JPCardDetailsMode.h ln -s -f ../Models/NetworkTimeout/JPNetworkTimeout.h JPNetworkTimeout.h