Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 0 additions & 116 deletions StripePaymentSheet/StripePaymentSheet/Resources/JSON/form_specs.json
Original file line number Diff line number Diff line change
@@ -1,120 +1,4 @@
[
{
"type": "afterpay_clearpay",
"async": false,
"fields": [
{
"type": "afterpay_header"
},
{
"type": "name",
"api_path": {
"v1": "billing_details[name]"
}
},
{
"type": "email",
"api_path": {
"v1": "billing_details[email]"
}
},
{
"type": "placeholder",
"for": "phone"
},
{
"type": "billing_address",
"allowed_country_codes": null
}
],
"next_action_spec": {
"confirm_response_status_specs": {
"requires_action": {
"type": "redirect_to_url"
}
},
"post_confirm_handling_pi_status_specs": {
"succeeded": {
"type": "finished"
},
"requires_action": {
"type": "canceled"
}
}
}
},
{
"type": "affirm",
"async": false,
"fields": [
{
"type": "affirm_header"
}
],
"next_action_spec": {
"confirm_response_status_specs": {
"requires_action": {
"type": "redirect_to_url"
}
},
"post_confirm_handling_pi_status_specs": {
"succeeded": {
"type": "finished"
},
"requires_action": {
"type": "canceled"
}
}
}
},
{
"type": "klarna",
"async": false,
"fields": [
{
"type": "klarna_header"
},
{
"type": "placeholder",
"for": "name"
},
{
"type": "email",
"api_path": {
"v1": "billing_details[email]"
}
},
{
"type": "placeholder",
"for": "phone"
},
{
"type": "klarna_country",
"api_path": {
"v1": "billing_details[address][country]"
}
},
{
"type": "placeholder",
"for": "billing_address_without_country"
}
],
"next_action_spec": {
"confirm_response_status_specs": {
"requires_action": {
"type": "redirect_to_url"
}
},
"post_confirm_handling_pi_status_specs": {
"succeeded": {
"type": "finished"
},
"requires_action": {
"type": "canceled"
}
}
}
},
{
"type": "ideal",
"async": false,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// PaymentSheetFormFactory+Affirm.swift
// StripePaymentSheet
//

import Foundation
@_spi(STP) import StripeCore
@_spi(STP) import StripeUICore

extension PaymentSheetFormFactory {
func makeAffirm() -> PaymentMethodElement {
let headerElement = SubtitleElement(
view: AffirmCopyLabel(theme: theme),
isHorizontalMode: configuration.isHorizontalMode
)
let formElement = FormElement(elements: [headerElement], theme: theme)
return makeDefaultsApplierWrapper(for: formElement)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// PaymentSheetFormFactory+AfterpayClearpay.swift
// StripePaymentSheet
//

import Foundation
@_spi(STP) import StripeCore
@_spi(STP) import StripeUICore

extension PaymentSheetFormFactory {

func makeAfterpayClearpay() -> PaymentMethodElement {
let headerElement = makeAfterpayClearpayHeader()

// Name and email are required by Afterpay, phone is optional
let contactInfoSection = makeContactInformationSection(
nameRequiredByPaymentMethod: true,
emailRequiredByPaymentMethod: true,
phoneRequiredByPaymentMethod: false
)

let addressElement = makeBillingAddressSectionIfNecessary(requiredByPaymentMethod: true)

let allElements: [Element?] = [
headerElement,
contactInfoSection,
addressElement,
]
let formElement = FormElement(autoSectioningElements: allElements.compactMap { $0 }, theme: theme)
return makeDefaultsApplierWrapper(for: formElement)
}

func makeAfterpayClearpayHeader() -> SubtitleElement {
return SubtitleElement(
view: AfterpayPriceBreakdownView(
currency: currency,
appearance: configuration.appearance
),
isHorizontalMode: configuration.isHorizontalMode
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//
// PaymentSheetFormFactory+Klarna.swift
// StripePaymentSheet
//

import Foundation
@_spi(STP) import StripeCore
@_spi(STP) import StripeUICore

extension PaymentSheetFormFactory {
func makeKlarna() -> PaymentMethodElement {
let headerElement = makeCopyLabel(text: .Localized.buy_now_or_pay_later_with_klarna)

// Email is required by Klarna, name and phone are optional
let contactInfoSection = makeContactInformationSection(
nameRequiredByPaymentMethod: false,
emailRequiredByPaymentMethod: true,
phoneRequiredByPaymentMethod: false
)

let phoneElement = contactInfoSection?.elements.compactMap {
$0 as? PaymentMethodElementWrapper<PhoneNumberElement>
}.first

// Klarna requires country selection
let countryElement = makeKlarnaCountry()

// Address without country - only show if config requires full address
let addressElement = configuration.billingDetailsCollectionConfiguration.address == .full
? makeBillingAddressSection(
collectionMode: .noCountry,
countries: configuration.billingDetailsCollectionConfiguration.allowedCountriesArray
)
: nil

connectBillingDetailsFields(
countryElement: countryElement as? PaymentMethodElementWrapper<DropdownFieldElement>,
addressElement: addressElement,
phoneElement: phoneElement
)

// Mandate is required when setting up
let mandateElement: SimpleMandateElement? = isSettingUp ? makeKlarnaMandate() : nil

let allElements: [Element?] = [
headerElement,
contactInfoSection,
countryElement,
addressElement,
mandateElement,
]
let formElement = FormElement(autoSectioningElements: allElements.compactMap { $0 }, theme: theme)
return makeDefaultsApplierWrapper(for: formElement)
}

func makeKlarnaMandate() -> SimpleMandateElement {
let doesMerchantNameEndWithPeriod = configuration.merchantDisplayName.last == "."
let endOfSentenceMerchantName = doesMerchantNameEndWithPeriod ? String(configuration.merchantDisplayName.dropLast()) : configuration.merchantDisplayName
let mandateText = String(format: String.Localized.klarna_mandate_text,
configuration.merchantDisplayName,
endOfSentenceMerchantName)
return makeMandate(mandateText: mandateText)
}

func makeKlarnaCountry() -> PaymentMethodElement? {
let countryCodes = Locale.current.sortedByTheirLocalizedNames(addressSpecProvider.countries)
let defaultValue = defaultBillingDetails().address.country
let country = PaymentMethodElementWrapper(
DropdownFieldElement.Address.makeCountry(
label: String.Localized.country,
countryCodes: countryCodes,
theme: theme,
defaultCountry: defaultValue,
locale: Locale.current
)
) { dropdown, params in
let countryCode = countryCodes[dropdown.selectedIndex]
let address = STPPaymentMethodAddress()
address.country = countryCode
params.paymentMethodParams.nonnil_billingDetails.address = address
return params
}
return country
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,6 @@ extension PaymentSheetFormFactory {
return makeMandate(mandateText: mandateText)
}

func makeKlarnaMandate() -> SimpleMandateElement {
let doesMerchantNameEndWithPeriod = configuration.merchantDisplayName.last == "."
let endOfSentenceMerchantName = doesMerchantNameEndWithPeriod ? String(configuration.merchantDisplayName.dropLast()) : configuration.merchantDisplayName
let mandateText = String(format: String.Localized.klarna_mandate_text,
configuration.merchantDisplayName,
endOfSentenceMerchantName)
return makeMandate(mandateText: mandateText)
}

func makeAmazonPayMandate() -> SimpleMandateElement {
let mandateText = String(format: String.Localized.amazon_pay_mandate_text, configuration.merchantDisplayName)
return makeMandate(mandateText: mandateText)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,9 +230,6 @@ class PaymentSheetFormFactory {
} else if paymentMethod == .revolutPay && isSettingUp {
// special case, display mandate for revolutPay when setting up or pi+sfu
additionalElements = [makeRevolutPayMandate()]
} else if paymentMethod == .klarna && isSettingUp {
// special case, display mandate for Klarna when setting up or pi+sfu
additionalElements = [makeKlarnaMandate()]
} else if paymentMethod == .amazonPay && isSettingUp {
// special case, display mandate for Amazon Pay when setting up or pi+sfu
additionalElements = [makeAmazonPayMandate()]
Expand All @@ -253,6 +250,12 @@ class PaymentSheetFormFactory {
return makeBoleto()
} else if paymentMethod == .swish {
return makeSwish()
} else if paymentMethod == .afterpayClearpay {
return makeAfterpayClearpay()
} else if paymentMethod == .affirm {
return makeAffirm()
} else if paymentMethod == .klarna {
return makeKlarna()
}

guard let spec = FormSpecProvider.shared.formSpec(for: paymentMethod.identifier) else {
Expand Down Expand Up @@ -815,17 +818,8 @@ extension PaymentSheetFormFactory {
}
}

func makeAfterpayClearpayHeader() -> SubtitleElement {
return SubtitleElement(
view: AfterpayPriceBreakdownView(
currency: currency,
appearance: configuration.appearance
),
isHorizontalMode: configuration.isHorizontalMode
)
}

func makeKlarnaCountry(apiPath: String? = nil) -> PaymentMethodElement? {
/// Creates a country dropdown for Klarna form specs with API path support
func makeKlarnaCountry(apiPath: String?) -> PaymentMethodElement? {
let countryCodes = Locale.current.sortedByTheirLocalizedNames(addressSpecProvider.countries)
let defaultValue = getPreviousCustomerInput(for: apiPath) ?? defaultBillingDetails(countryAPIPath: apiPath).address.country
let country = PaymentMethodElementWrapper(
Expand Down
Loading
Loading