Skip to content
Merged
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
6 changes: 3 additions & 3 deletions platforms/swift/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ iOS handles checkout geolocation permission prompts through the system prompt. I

### Configure accelerated checkouts

Create shared configuration objects and inject them into your SwiftUI hierarchy:
Create shared configuration values and inject them into your SwiftUI hierarchy:

```swift
import ShopifyAcceleratedCheckouts
Expand All @@ -325,8 +325,8 @@ struct YourApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(checkoutConfig)
.environmentObject(applePayConfig)
.environment(\.shopifyAcceleratedCheckoutsConfiguration, checkoutConfig)
.environment(\.shopifyApplePayConfiguration, applePayConfig)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,15 @@ struct CartView: View {
print("[AcceleratedCheckout] Cancelled")
}
.connect(client)
.environmentObject(
.environment(
\.shopifyAcceleratedCheckoutsConfiguration,
ShopifyAcceleratedCheckouts.Configuration(
storefrontDomain: InfoDictionary.shared.domain,
storefrontAccessToken: InfoDictionary.shared.accessToken
)
)
.environmentObject(
.environment(
\.shopifyApplePayConfiguration,
ShopifyAcceleratedCheckouts.ApplePayConfiguration(
merchantIdentifier: InfoDictionary.shared.merchantIdentifier,
contactFields: [.email, .phone]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,15 @@ struct ProductView: View {
.onCancel {
print("[AcceleratedCheckout] Cancelled")
}
.environmentObject(
.environment(
\.shopifyAcceleratedCheckoutsConfiguration,
ShopifyAcceleratedCheckouts.Configuration(
storefrontDomain: InfoDictionary.shared.domain,
storefrontAccessToken: InfoDictionary.shared.accessToken
)
)
.environmentObject(
.environment(
\.shopifyApplePayConfiguration,
ShopifyAcceleratedCheckouts.ApplePayConfiguration(
merchantIdentifier: InfoDictionary.shared.merchantIdentifier,
contactFields: [.email, .phone]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ struct ShopifyAcceleratedCheckoutsApp: App {
@AppStorage(AppStorageKeys.email.rawValue) var email: String = ""
@AppStorage(AppStorageKeys.phone.rawValue) var phone: String = ""
@AppStorage(AppStorageKeys.supportedCountries.rawValue) var supportedCountriesString: String = ""
@StateObject private var configuration: ShopifyAcceleratedCheckouts.Configuration
@State private var configuration: ShopifyAcceleratedCheckouts.Configuration

init() {
let email = UserDefaults.standard.string(forKey: AppStorageKeys.email.rawValue) ?? ""
let phone = UserDefaults.standard.string(forKey: AppStorageKeys.phone.rawValue) ?? ""
_configuration = StateObject(
wrappedValue: ShopifyAcceleratedCheckouts.Configuration(
_configuration = State(
initialValue: ShopifyAcceleratedCheckouts.Configuration(
storefrontDomain: EnvironmentVariables.storefrontDomain,
storefrontAccessToken: EnvironmentVariables.storefrontAccessToken,
customer: Self.customer(email: email, phone: phone)
Expand Down Expand Up @@ -51,8 +51,8 @@ struct ShopifyAcceleratedCheckoutsApp: App {
ShopifyAcceleratedCheckouts.logLevel = logLevel
updateConfiguration()
}
.environmentObject(configuration)
.environmentObject(applePayConfiguration)
.environment(\.shopifyAcceleratedCheckoutsConfiguration, configuration)
.environment(\.shopifyApplePayConfiguration, applePayConfiguration)
}
.environment(\.locale, Locale(identifier: locale))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,25 @@ import SwiftUI

@available(iOS 16.0, *)
extension ShopifyAcceleratedCheckouts {
public class Configuration: ObservableObject, Copyable {
public struct Configuration: Sendable, Equatable {
/// The domain of the shop without the protocol.
///
/// Example: `my-shop.myshopify.com`
///
/// See: https://shopify.dev/docs/storefronts/themes/getting-started/build-a-theme#get-the-shop-domain
@Published public var storefrontDomain: String
public var storefrontDomain: String

/// The storefront access token.
///
/// See: https://shopify.dev/docs/storefronts/themes/getting-started/build-a-theme#get-the-storefront-access-token
@Published public var storefrontAccessToken: String
public var storefrontAccessToken: String

/// Data to attach to the buyerIdentity during cart creation
/// - Apple Pay sheet will skip requesting email/phone number fields if provided here
/// - Customer will *override* existing cart.buyerIdentity if you are using cartId
///
/// See: https://shopify.dev/docs/api/storefront/latest/mutations/cartBuyerIdentityUpdate
@Published public var customer: Customer?
public var customer: Customer?

public init(
storefrontDomain: String,
Expand All @@ -32,12 +32,6 @@ extension ShopifyAcceleratedCheckouts {
self.storefrontAccessToken = storefrontAccessToken
self.customer = customer
}

package required init(copy: Configuration) {
storefrontDomain = copy.storefrontDomain
storefrontAccessToken = copy.storefrontAccessToken
customer = copy.customer
}
}

public struct Customer: Sendable, Equatable {
Expand All @@ -63,3 +57,16 @@ extension ShopifyAcceleratedCheckouts {
}
}
}

@available(iOS 16.0, *)
private struct ShopifyAcceleratedCheckoutsConfigurationKey: EnvironmentKey {
static let defaultValue: ShopifyAcceleratedCheckouts.Configuration? = nil
}

@available(iOS 16.0, *)
extension EnvironmentValues {
public var shopifyAcceleratedCheckoutsConfiguration: ShopifyAcceleratedCheckouts.Configuration? {
get { self[ShopifyAcceleratedCheckoutsConfigurationKey.self] }
set { self[ShopifyAcceleratedCheckoutsConfigurationKey.self] = newValue }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ public enum RenderState: Equatable {
/// - omission of the `wallets` modifier will render all buttons
@available(iOS 16.0, *)
public struct AcceleratedCheckoutButtons: View {
@EnvironmentObject
private var configuration: ShopifyAcceleratedCheckouts.Configuration
@Environment(\.shopifyAcceleratedCheckoutsConfiguration)
private var configuration: ShopifyAcceleratedCheckouts.Configuration?

let identifier: CheckoutIdentifier
public var wallets: [Wallet] = [.shopPay, .applePay]
Expand Down Expand Up @@ -95,11 +95,19 @@ public struct AcceleratedCheckoutButtons: View {
}
}

private var resolvedConfiguration: ShopifyAcceleratedCheckouts.Configuration {
guard let configuration else {
fatalError("Missing ShopifyAcceleratedCheckouts.Configuration. Add .environment(\\.shopifyAcceleratedCheckoutsConfiguration, ...) to an ancestor view.")
}
return configuration
}

private func loadShopSettings() async {
guard identifier.isValid() else { return }

do {
currentRenderState = .loading
let configuration = resolvedConfiguration
let storefront = StorefrontAPI(
storefrontDomain: configuration.storefrontDomain,
storefrontAccessToken: configuration.storefrontAccessToken
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import SwiftUI
@available(macOS, unavailable)
struct ApplePayButton: View {
/// The configuration for Apple Pay
@EnvironmentObject
private var configuration: ShopifyAcceleratedCheckouts.Configuration
@Environment(\.shopifyAcceleratedCheckoutsConfiguration)
private var configuration: ShopifyAcceleratedCheckouts.Configuration?

/// The shop settings
@EnvironmentObject
private var shopSettings: ShopSettings

@EnvironmentObject
private var applePayConfiguration: ShopifyAcceleratedCheckouts.ApplePayConfiguration
@Environment(\.shopifyApplePayConfiguration)
private var applePayConfiguration: ShopifyAcceleratedCheckouts.ApplePayConfiguration?

/// The identifier to use for checkout
private let identifier: CheckoutIdentifier
Expand Down Expand Up @@ -58,8 +58,8 @@ struct ApplePayButton: View {
label: label,
style: style,
configuration: ApplePayConfigurationWrapper(
common: configuration,
applePay: applePayConfiguration,
common: resolvedConfiguration,
applePay: resolvedApplePayConfiguration,
shopSettings: shopSettings
),
eventHandlers: eventHandlers,
Expand All @@ -69,6 +69,20 @@ struct ApplePayButton: View {
}
}

private var resolvedConfiguration: ShopifyAcceleratedCheckouts.Configuration {
guard let configuration else {
fatalError("Missing ShopifyAcceleratedCheckouts.Configuration. Add .environment(\\.shopifyAcceleratedCheckoutsConfiguration, ...) to an ancestor view.")
}
return configuration
}

private var resolvedApplePayConfiguration: ShopifyAcceleratedCheckouts.ApplePayConfiguration {
guard let applePayConfiguration else {
fatalError("Missing ShopifyAcceleratedCheckouts.ApplePayConfiguration. Add .environment(\\.shopifyApplePayConfiguration, ...) to an ancestor view.")
}
return applePayConfiguration
}

func applePayStyle(_ style: PayWithApplePayButtonStyle) -> some View {
var view = self
view.style = style
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import Foundation
import PassKit
import SwiftUI

@available(iOS 16.0, *)
extension ShopifyAcceleratedCheckouts {
/// Contact field types that can be required during Apple Pay checkout.
public enum RequiredContactFields: String {
public enum RequiredContactFields: String, Sendable {
case email
case phone
}
Expand All @@ -14,7 +13,7 @@ extension ShopifyAcceleratedCheckouts {
/// This class encapsulates all necessary settings for enabling Apple Pay as a payment method,
/// including merchant identification and required contact information. Supported payment networks
/// are automatically determined based on the merchant's Shopify configuration.
public class ApplePayConfiguration: ObservableObject, Copyable {
public struct ApplePayConfiguration: Sendable, Equatable {
/// The merchant identifier for Apple Pay transactions.
///
/// This value must match one of the merchant identifiers specified by the Merchant IDs
Expand Down Expand Up @@ -64,12 +63,19 @@ extension ShopifyAcceleratedCheckouts {
self.contactFields = contactFields
self.supportedShippingCountries = supportedShippingCountries
}
}
}

package required init(copy: ApplePayConfiguration) {
merchantIdentifier = copy.merchantIdentifier
contactFields = copy.contactFields
supportedShippingCountries = copy.supportedShippingCountries
}
@available(iOS 16.0, *)
private struct ShopifyApplePayConfigurationKey: EnvironmentKey {
static let defaultValue: ShopifyAcceleratedCheckouts.ApplePayConfiguration? = nil
}

@available(iOS 16.0, *)
extension EnvironmentValues {
public var shopifyApplePayConfiguration: ShopifyAcceleratedCheckouts.ApplePayConfiguration? {
get { self[ShopifyApplePayConfigurationKey.self] }
set { self[ShopifyApplePayConfigurationKey.self] = newValue }
}
}

Expand All @@ -94,8 +100,8 @@ class ApplePayConfigurationWrapper: Copyable {
}

package required init(copy: ApplePayConfigurationWrapper) {
common = copy.common.copy()
applePay = copy.applePay.copy()
common = copy.common
applePay = copy.applePay
shopSettings = copy.shopSettings
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import SwiftUI

@available(iOS 16.0, *)
internal struct ShopPayButton: View {
@EnvironmentObject private var configuration: ShopifyAcceleratedCheckouts.Configuration
@Environment(\.shopifyAcceleratedCheckoutsConfiguration)
private var configuration: ShopifyAcceleratedCheckouts.Configuration?

let identifier: CheckoutIdentifier
let eventHandlers: EventHandlers
Expand All @@ -29,13 +30,20 @@ internal struct ShopPayButton: View {
default:
Internal_ShopPayButton(
identifier: identifier,
configuration: configuration,
configuration: resolvedConfiguration,
eventHandlers: eventHandlers,
cornerRadius: cornerRadius,
client: clientContainer.client
)
}
}

private var resolvedConfiguration: ShopifyAcceleratedCheckouts.Configuration {
guard let configuration else {
fatalError("Missing ShopifyAcceleratedCheckouts.Configuration. Add .environment(\\.shopifyAcceleratedCheckoutsConfiguration, ...) to an ancestor view.")
}
return configuration
}
}

/// Internal_ wrapper component allows `ShopifyAcceleratedCheckouts.Configuration` to be
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ final class AcceleratedCheckoutButtonsRenderStateTests: XCTestCase {
expectation.fulfill()
}
}
.environmentObject(ShopifyAcceleratedCheckouts.Configuration.testConfiguration)
.environment(\.shopifyAcceleratedCheckoutsConfiguration, ShopifyAcceleratedCheckouts.Configuration.testConfiguration)

// Render the view to trigger onAppear
let hostingController = UIHostingController(rootView: testView)
Expand All @@ -47,7 +47,7 @@ final class AcceleratedCheckoutButtonsRenderStateTests: XCTestCase {
expectation.fulfill()
}
}
.environmentObject(ShopifyAcceleratedCheckouts.Configuration.testConfiguration)
.environment(\.shopifyAcceleratedCheckoutsConfiguration, ShopifyAcceleratedCheckouts.Configuration.testConfiguration)

// Render the view to trigger onAppear
let hostingController = UIHostingController(rootView: testView)
Expand All @@ -74,7 +74,7 @@ final class AcceleratedCheckoutButtonsRenderStateTests: XCTestCase {
expectation.fulfill()
}
}
.environmentObject(ShopifyAcceleratedCheckouts.Configuration.testConfiguration)
.environment(\.shopifyAcceleratedCheckoutsConfiguration, ShopifyAcceleratedCheckouts.Configuration.testConfiguration)

// Render the view to trigger onAppear
let hostingController = UIHostingController(rootView: testView)
Expand All @@ -101,7 +101,7 @@ final class AcceleratedCheckoutButtonsRenderStateTests: XCTestCase {
expectation.fulfill()
}
}
.environmentObject(ShopifyAcceleratedCheckouts.Configuration.testConfiguration)
.environment(\.shopifyAcceleratedCheckoutsConfiguration, ShopifyAcceleratedCheckouts.Configuration.testConfiguration)

// Render the view to trigger onAppear
let hostingController = UIHostingController(rootView: testView)
Expand All @@ -128,7 +128,7 @@ final class AcceleratedCheckoutButtonsRenderStateTests: XCTestCase {
expectation.fulfill()
}
}
.environmentObject(ShopifyAcceleratedCheckouts.Configuration.testConfiguration)
.environment(\.shopifyAcceleratedCheckoutsConfiguration, ShopifyAcceleratedCheckouts.Configuration.testConfiguration)

// Render the view to trigger onAppear
let hostingController = UIHostingController(rootView: testView)
Expand All @@ -155,7 +155,7 @@ final class AcceleratedCheckoutButtonsRenderStateTests: XCTestCase {
expectation.fulfill()
}
}
.environmentObject(ShopifyAcceleratedCheckouts.Configuration.testConfiguration)
.environment(\.shopifyAcceleratedCheckoutsConfiguration, ShopifyAcceleratedCheckouts.Configuration.testConfiguration)

// Render the view to trigger onAppear
let hostingController = UIHostingController(rootView: testView)
Expand Down
Loading
Loading