diff --git a/.gitignore b/.gitignore index 86e3ab40..472337f8 100644 --- a/.gitignore +++ b/.gitignore @@ -106,3 +106,6 @@ sample/vendor # Sample app sample/**/AndroidManifest.xml + +.claude/ +CLAUDE.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 51318ce2..ba51ea9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## 3.3.0 - Aug 12, 2025 + +- Upgrades Swift dependency to 3.3.0 +- Upgrades Android dependency to 3.5.0 +- Adds GooglePay support for eligible devices in Android +- Adds isFirstOrder to web pixel events +- Allow customizing sheet close button color +- React Native dependency updates +- Sample updates - fix for automatic scheme, stringify objects before logging. + ## 3.2.0 - December 18, 2024 - Handle geolocation requests for Android devices diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 204e3187..7cd5b7d6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,7 +11,7 @@ This repo is subdivided into 3 parts using yarn workspaces: - The `@shopify/checkout-sheet-kit` Native Module (workspace name = `module`) - The sample application (workspace name = `sample`) -Each of the worksapces contains a separate `package.json` to manage tasks +Each of the workspaces contains a separate `package.json` to manage tasks specific to each workspace. ## Getting started @@ -132,7 +132,7 @@ Replace the details in the `sample/.env.example` file and rename it to # Storefront Details STOREFRONT_DOMAIN="YOUR_STORE.myshopify.com" STOREFRONT_ACCESS_TOKEN="YOUR_PUBLIC_STOREFRONT_ACCESS_TOKEN" -STOREFRONT_VERSION="2024-04" +STOREFRONT_VERSION="2025-07" ``` ### Start the sample app diff --git a/README.md b/README.md index 41a2ba54..d54f47cd 100644 --- a/README.md +++ b/README.md @@ -204,7 +204,7 @@ import {STOREFRONT_NAME, STOREFRONT_ACCESS_TOKEN} from '@env'; // Create a new instance of the ApolloClient const client = new ApolloClient({ - uri: `https://${STOREFRONT_NAME}.myshopify.com/api/2024-01/graphql.json`, + uri: `https://${STOREFRONT_NAME}.myshopify.com/api/2025-07/graphql.json`, headers: { 'X-Shopify-Storefront-Access-Token': STOREFRONT_ACCESS_TOKEN, }, @@ -384,12 +384,14 @@ const config: Configuration = { ios: { backgroundColor: '#ffffff', tintColor: '#000000', + closeButtonColor: '#333333', }, android: { backgroundColor: '#ffffff', progressIndicator: '#2d2a38', headerBackgroundColor: '#ffffff', headerTextColor: '#000000', + closeButtonColor: '#333333', }, }, }; @@ -416,12 +418,14 @@ const config: Configuration = { progressIndicator: '#2d2a38', headerBackgroundColor: '#ffffff', headerTextColor: '#000000', + closeButtonColor: '#000000', }, dark: { backgroundColor: '#000000', progressIndicator: '#0087ff', headerBackgroundColor: '#000000', headerTextColor: '#ffffff', + closeButtonColor: '#ffffff', }, }, }, diff --git a/modules/@shopify/checkout-sheet-kit/RNShopifyCheckoutSheetKit.podspec b/modules/@shopify/checkout-sheet-kit/RNShopifyCheckoutSheetKit.podspec index 649744ca..8181628d 100644 --- a/modules/@shopify/checkout-sheet-kit/RNShopifyCheckoutSheetKit.podspec +++ b/modules/@shopify/checkout-sheet-kit/RNShopifyCheckoutSheetKit.podspec @@ -20,7 +20,7 @@ Pod::Spec.new do |s| s.source_files = "ios/*.{h,m,mm,swift}" s.dependency "React-Core" - s.dependency "ShopifyCheckoutSheetKit", "~> 3.1.2" + s.dependency "ShopifyCheckoutSheetKit", "~> 3.3.0" if fabric_enabled install_modules_dependencies(s) diff --git a/modules/@shopify/checkout-sheet-kit/android/build.gradle b/modules/@shopify/checkout-sheet-kit/android/build.gradle index 87cf79ae..82b9a034 100644 --- a/modules/@shopify/checkout-sheet-kit/android/build.gradle +++ b/modules/@shopify/checkout-sheet-kit/android/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath "com.android.tools.build:gradle:7.4.2" + classpath "com.android.tools.build:gradle:8.11.0" } } @@ -32,10 +32,10 @@ static def supportsNamespace() { return (major == 7 && minor >= 3) || major >= 8 } -buildToolsVersion = "33.0.0" +buildToolsVersion = "35.0.0" minSdkVersion = 23 -compileSdkVersion = 33 -targetSdkVersion = 33 +compileSdkVersion = 36 +targetSdkVersion = 35 // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP. ndkVersion = "23.1.7779620" diff --git a/modules/@shopify/checkout-sheet-kit/android/gradle.properties b/modules/@shopify/checkout-sheet-kit/android/gradle.properties index e1758975..4bb0c3a3 100644 --- a/modules/@shopify/checkout-sheet-kit/android/gradle.properties +++ b/modules/@shopify/checkout-sheet-kit/android/gradle.properties @@ -1,8 +1,8 @@ minSdkVersion=23 -targetSdkVersion=33 -compileSdkVersion=33 +targetSdkVersion=35 +compileSdkVersion=36 ndkVersion=23.1.7779620 -buildToolsVersion = "33.0.0" +buildToolsVersion = "35.0.0" # Version of Shopify Checkout SDK to use with React Native -SHOPIFY_CHECKOUT_SDK_VERSION=3.3.0 +SHOPIFY_CHECKOUT_SDK_VERSION=3.5.0 diff --git a/modules/@shopify/checkout-sheet-kit/android/src/main/java/com/shopify/reactnative/checkoutsheetkit/ShopifyCheckoutSheetKitModule.java b/modules/@shopify/checkout-sheet-kit/android/src/main/java/com/shopify/reactnative/checkoutsheetkit/ShopifyCheckoutSheetKitModule.java index ef2638b2..dd778fcf 100644 --- a/modules/@shopify/checkout-sheet-kit/android/src/main/java/com/shopify/reactnative/checkoutsheetkit/ShopifyCheckoutSheetKitModule.java +++ b/modules/@shopify/checkout-sheet-kit/android/src/main/java/com/shopify/reactnative/checkoutsheetkit/ShopifyCheckoutSheetKitModule.java @@ -194,14 +194,21 @@ private boolean isValidColorConfig(ReadableMap config) { return false; } - String[] colorKeys = { "backgroundColor", "progressIndicator", "headerTextColor", "headerBackgroundColor" }; + String[] requiredColorKeys = { "backgroundColor", "progressIndicator", "headerTextColor", "headerBackgroundColor" }; - for (String key : colorKeys) { + for (String key : requiredColorKeys) { if (!config.hasKey(key) || config.getString(key) == null || parseColor(config.getString(key)) == null) { return false; } } + // closeButtonColor is optional, so we only validate it if it's present + if (config.hasKey("closeButtonColor") && config.getString("closeButtonColor") != null) { + if (parseColor(config.getString("closeButtonColor")) == null) { + return false; + } + } + return true; } @@ -242,13 +249,18 @@ private Colors createColorsFromConfig(ReadableMap config) { Color headerBackground = parseColorFromConfig(config, "headerBackgroundColor"); Color headerFont = parseColorFromConfig(config, "headerTextColor"); Color progressIndicator = parseColorFromConfig(config, "progressIndicator"); + Color closeButtonColor = parseColorFromConfig(config, "closeButtonColor"); if (webViewBackground != null && progressIndicator != null && headerFont != null && headerBackground != null) { return new Colors( webViewBackground, headerBackground, headerFont, - progressIndicator); + progressIndicator, + // Parameter allows passing a custom drawable, we'll just support custom color for now + null, + closeButtonColor + ); } return null; diff --git a/modules/@shopify/checkout-sheet-kit/ios/ShopifyCheckoutSheetKit.swift b/modules/@shopify/checkout-sheet-kit/ios/ShopifyCheckoutSheetKit.swift index 442e547c..299a60a8 100644 --- a/modules/@shopify/checkout-sheet-kit/ios/ShopifyCheckoutSheetKit.swift +++ b/modules/@shopify/checkout-sheet-kit/ios/ShopifyCheckoutSheetKit.swift @@ -242,6 +242,10 @@ class RCTShopifyCheckoutSheetKit: RCTEventEmitter, CheckoutDelegate { if let backgroundColorHex = iosConfig?["backgroundColor"] as? String { ShopifyCheckoutSheetKit.configuration.backgroundColor = UIColor(hex: backgroundColorHex) } + + if let closeButtonColorHex = iosConfig?["closeButtonColor"] as? String { + ShopifyCheckoutSheetKit.configuration.closeButtonTintColor = UIColor(hex: closeButtonColorHex) + } } @objc func getConfig(_ resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) { @@ -250,7 +254,8 @@ class RCTShopifyCheckoutSheetKit: RCTEventEmitter, CheckoutDelegate { "preloading": ShopifyCheckoutSheetKit.configuration.preloading.enabled, "colorScheme": ShopifyCheckoutSheetKit.configuration.colorScheme.rawValue, "tintColor": ShopifyCheckoutSheetKit.configuration.tintColor, - "backgroundColor": ShopifyCheckoutSheetKit.configuration.backgroundColor + "backgroundColor": ShopifyCheckoutSheetKit.configuration.backgroundColor, + "closeButtonColor": ShopifyCheckoutSheetKit.configuration.closeButtonTintColor ] resolve(config) diff --git a/modules/@shopify/checkout-sheet-kit/package.json b/modules/@shopify/checkout-sheet-kit/package.json index 1602e715..1a15a1e9 100644 --- a/modules/@shopify/checkout-sheet-kit/package.json +++ b/modules/@shopify/checkout-sheet-kit/package.json @@ -1,7 +1,7 @@ { "name": "@shopify/checkout-sheet-kit", "license": "MIT", - "version": "3.2.0", + "version": "3.3.0", "main": "lib/commonjs/index.js", "types": "src/index.ts", "source": "src/index.ts", diff --git a/modules/@shopify/checkout-sheet-kit/src/index.d.ts b/modules/@shopify/checkout-sheet-kit/src/index.d.ts index 2101d906..1c9192d8 100644 --- a/modules/@shopify/checkout-sheet-kit/src/index.d.ts +++ b/modules/@shopify/checkout-sheet-kit/src/index.d.ts @@ -56,6 +56,10 @@ export interface IosColors { * A HEX color value for customizing the background color of the webview. */ backgroundColor?: string; + /** + * A HEX color value for customizing the color of the close button. + */ + closeButtonColor?: string; } export interface AndroidColors { @@ -75,6 +79,10 @@ export interface AndroidColors { * A HEX color value for customizing the text color of the webview header. */ headerTextColor: string; + /** + * A HEX color value for customizing the color of the close button. + */ + closeButtonColor?: string; } export interface AndroidAutomaticColors { diff --git a/modules/@shopify/checkout-sheet-kit/src/pixels.d.ts b/modules/@shopify/checkout-sheet-kit/src/pixels.d.ts index 777bbd60..f60c24ca 100644 --- a/modules/@shopify/checkout-sheet-kit/src/pixels.d.ts +++ b/modules/@shopify/checkout-sheet-kit/src/pixels.d.ts @@ -491,6 +491,8 @@ interface Order { interface OrderCustomer { /* The ID of the customer. */ id?: string; + /* Indicates whether the customer is a first-time buyer. */ + isFirstOrder?: boolean; } /** diff --git a/sample/.env.example b/sample/.env.example index f3108037..c9b08ac0 100644 --- a/sample/.env.example +++ b/sample/.env.example @@ -3,7 +3,7 @@ STOREFRONT_DOMAIN="YOUR_STORE.myshopify.com" STOREFRONT_ACCESS_TOKEN="YOUR_PUBLIC_STOREFRONT_ACCESS_TOKEN" # Storefront API version -STOREFRONT_VERSION="2024-04" +STOREFRONT_VERSION="2025-07" # Prefilled buyer information EMAIL="checkout-kit@shopify.com" diff --git a/sample/android/app/build.gradle b/sample/android/app/build.gradle index 271be4db..99744e71 100644 --- a/sample/android/app/build.gradle +++ b/sample/android/app/build.gradle @@ -74,7 +74,7 @@ android { lintOptions { checkDependencies false } - tasks.whenTaskAdded { task -> + tasks.configureEach { task -> if (task.name == 'lintAnalyzeDebug' || task.name == 'generateReleaseLintVitalReportModel') { task.dependsOn 'copyReactNativeVectorIconFonts' } @@ -85,8 +85,8 @@ android { applicationId "com.shopify.checkoutkitreactnative" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 5 - versionName "1.0" + versionCode 11 + versionName "1.1" } signingConfigs { debug { diff --git a/sample/android/app/proguard-rules.pro b/sample/android/app/proguard-rules.pro index 11b02572..a7136906 100644 --- a/sample/android/app/proguard-rules.pro +++ b/sample/android/app/proguard-rules.pro @@ -8,3 +8,4 @@ # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: +-keep class com.shopify.checkoutkitreactnative.BuildConfig { *; } diff --git a/sample/android/app/src/test/java/com/shopify/checkoutkitreactnative/ShopifyCheckoutSheetKitModuleTest.java b/sample/android/app/src/test/java/com/shopify/checkoutkitreactnative/ShopifyCheckoutSheetKitModuleTest.java index b1adf2ea..a197d2a4 100644 --- a/sample/android/app/src/test/java/com/shopify/checkoutkitreactnative/ShopifyCheckoutSheetKitModuleTest.java +++ b/sample/android/app/src/test/java/com/shopify/checkoutkitreactnative/ShopifyCheckoutSheetKitModuleTest.java @@ -30,6 +30,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.mockito.Mockito.*; import android.content.Context; @@ -76,6 +77,18 @@ public class ShopifyCheckoutSheetKitModuleTest { @Mock private CheckoutException mockCheckoutException; + // Test constants for color configuration + private static final String BACKGROUND_COLOR = "#FFFFFF"; + private static final String PROGRESS_INDICATOR = "#000000"; + private static final String HEADER_BACKGROUND_COLOR = "#FFFFFF"; + private static final String HEADER_TEXT_COLOR = "#000000"; + + // Dark theme colors + private static final String DARK_BACKGROUND_COLOR = "#000000"; + private static final String DARK_PROGRESS_INDICATOR = "#FFFFFF"; + private static final String DARK_HEADER_BACKGROUND_COLOR = "#000000"; + private static final String DARK_HEADER_TEXT_COLOR = "#FFFFFF"; + @Before public void setup() { when(mockReactContext.getCurrentActivity()).thenReturn(mockComponentActivity); @@ -129,6 +142,73 @@ public void setsInternalConfig() { assertEquals(colorScheme, "dark"); } + @Test + public void setsConfigWithCloseButtonColor() { + JavaOnlyMap androidColors = createLightAndroidColors(); + androidColors.putString("closeButtonColor", "#FF0000"); + JavaOnlyMap config = createConfigWithAndroidColors("light", androidColors); + + shopifyCheckoutSheetKitModule.setConfig(config); + + String colorScheme = ShopifyCheckoutSheetKitModule.checkoutConfig.getColorScheme().getId(); + assertEquals("light", colorScheme); + } + + @Test + public void setsConfigWithMissingCloseButtonColor() { + // Missing closeButtonColor - should not crash + JavaOnlyMap androidColors = createLightAndroidColors(); + JavaOnlyMap config = createConfigWithAndroidColors("light", androidColors); + + shopifyCheckoutSheetKitModule.setConfig(config); + + String colorScheme = ShopifyCheckoutSheetKitModule.checkoutConfig.getColorScheme().getId(); + assertEquals("light", colorScheme); + } + + @Test + public void setsConfigWithInvalidCloseButtonColor() { + JavaOnlyMap androidColors = createLightAndroidColors(); + androidColors.putString("closeButtonColor", "invalid-color"); + JavaOnlyMap config = createConfigWithAndroidColors("light", androidColors); + + // The method should not throw an exception when given invalid close button color + try { + shopifyCheckoutSheetKitModule.setConfig(config); + } catch (Exception e) { + fail("setConfig should not throw exception for invalid close button color: " + e.getMessage()); + } + + // Verify the color scheme was set correctly despite invalid close button color + String colorScheme = ShopifyCheckoutSheetKitModule.checkoutConfig.getColorScheme().getId(); + assertEquals("light", colorScheme); + } + + @Test + public void setsAutomaticConfigWithCloseButtonColors() { + JavaOnlyMap lightColors = createLightAndroidColors(); + lightColors.putString("closeButtonColor", "#000000"); + + JavaOnlyMap darkColors = createDarkAndroidColors(); + darkColors.putString("closeButtonColor", "#FFFFFF"); + + JavaOnlyMap androidColors = new JavaOnlyMap(); + androidColors.putMap("light", lightColors); + androidColors.putMap("dark", darkColors); + + JavaOnlyMap colorsConfig = new JavaOnlyMap(); + colorsConfig.putMap("android", androidColors); + + JavaOnlyMap config = new JavaOnlyMap(); + config.putString("colorScheme", "automatic"); + config.putMap("colors", colorsConfig); + + shopifyCheckoutSheetKitModule.setConfig(config); + + String colorScheme = ShopifyCheckoutSheetKitModule.checkoutConfig.getColorScheme().getId(); + assertEquals("automatic", colorScheme); + } + @Test public void sendsStandardPixelEventOnWebPixelEvent() { PixelEvent event = new StandardPixelEvent( @@ -295,4 +375,37 @@ public void sendsGeneralErrorEventOnCheckoutFailed() { assertTrue(capturedString.contains("\"code\":\"unknown\"")); assertTrue(capturedString.contains("\"recoverable\":true")); } + + // Helper methods + + private JavaOnlyMap createLightAndroidColors() { + JavaOnlyMap androidColors = new JavaOnlyMap(); + androidColors.putString("backgroundColor", BACKGROUND_COLOR); + androidColors.putString("progressIndicator", PROGRESS_INDICATOR); + androidColors.putString("headerBackgroundColor", HEADER_BACKGROUND_COLOR); + androidColors.putString("headerTextColor", HEADER_TEXT_COLOR); + return androidColors; + } + + private JavaOnlyMap createDarkAndroidColors() { + JavaOnlyMap androidColors = new JavaOnlyMap(); + androidColors.putString("backgroundColor", DARK_BACKGROUND_COLOR); + androidColors.putString("progressIndicator", DARK_PROGRESS_INDICATOR); + androidColors.putString("headerBackgroundColor", DARK_HEADER_BACKGROUND_COLOR); + androidColors.putString("headerTextColor", DARK_HEADER_TEXT_COLOR); + return androidColors; + } + + /** + * Creates a configuration with the given color scheme and Android colors + */ + private JavaOnlyMap createConfigWithAndroidColors(String colorScheme, JavaOnlyMap androidColors) { + JavaOnlyMap colorsConfig = new JavaOnlyMap(); + colorsConfig.putMap("android", androidColors); + + JavaOnlyMap config = new JavaOnlyMap(); + config.putString("colorScheme", colorScheme); + config.putMap("colors", colorsConfig); + return config; + } } diff --git a/sample/android/gradle.properties b/sample/android/gradle.properties index 09a06ff9..9e4f3016 100644 --- a/sample/android/gradle.properties +++ b/sample/android/gradle.properties @@ -43,4 +43,4 @@ newArchEnabled=false hermesEnabled=true # Note: only used here for testing -SHOPIFY_CHECKOUT_SDK_VERSION=3.3.0 +SHOPIFY_CHECKOUT_SDK_VERSION=3.5.0 diff --git a/sample/ios/Podfile.lock b/sample/ios/Podfile.lock index cf0a9a36..a6b4f771 100644 --- a/sample/ios/Podfile.lock +++ b/sample/ios/Podfile.lock @@ -935,9 +935,9 @@ PODS: - React-Mapbuffer (0.74.1): - glog - React-debug - - react-native-config (1.5.3): - - react-native-config/App (= 1.5.3) - - react-native-config/App (1.5.3): + - react-native-config (1.5.5): + - react-native-config/App (= 1.5.5) + - react-native-config/App (1.5.5): - React-Core - react-native-safe-area-context (4.14.0): - React-Core @@ -1170,8 +1170,27 @@ PODS: - React-logger (= 0.74.1) - React-perflogger (= 0.74.1) - React-utils (= 0.74.1) - - RNCMaskedView (0.3.1): + - RNCMaskedView (0.3.2): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.01.01.00) + - RCTRequired + - RCTTypeSafety + - React-Codegen - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - RNGestureHandler (2.15.0): - DoubleConversion - glog @@ -1302,9 +1321,9 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - RNShopifyCheckoutSheetKit (3.1.2): + - RNShopifyCheckoutSheetKit (3.3.0): - React-Core - - ShopifyCheckoutSheetKit (~> 3.1.2) + - ShopifyCheckoutSheetKit (~> 3.3.0) - RNVectorIcons (10.2.0): - DoubleConversion - glog @@ -1326,7 +1345,7 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - ShopifyCheckoutSheetKit (3.1.2) + - ShopifyCheckoutSheetKit (3.3.0) - SocketRocket (0.7.0) - SwiftLint (0.57.0) - Yoga (0.0.0) @@ -1562,7 +1581,7 @@ SPEC CHECKSUMS: React-jsitracing: dd0e541a34027b3ab668ad94cf268482ad6f82fb React-logger: 6070f362a1657bb53335eb1fc903d3f49fd79842 React-Mapbuffer: 2c95cbabc3d75a17747452381e998c35208ea3ee - react-native-config: ea75335a7cca1d3326de1da384227e580a7c082e + react-native-config: 644074ab88db883fcfaa584f03520ec29589d7df react-native-safe-area-context: b13be9714d9771fbde0120bc519c963484de3a71 React-nativeconfig: b0073a590774e8b35192fead188a36d1dca23dec React-NativeModulesApple: 61b07ab32af3ea4910ba553932c0a779e853c082 @@ -1587,17 +1606,17 @@ SPEC CHECKSUMS: React-runtimescheduler: 87b14969bb0b10538014fb8407d472f9904bc8cd React-utils: 67574b07bff4429fd6c4d43a7fad8254d814ee20 ReactCommon: 64c64f4ae1f2debe3fab1800e00cb8466a4477b7 - RNCMaskedView: de80352547bd4f0d607bf6bab363d826822bd126 + RNCMaskedView: af7c1703f39cdef08a99275bfcadf324aa403403 RNGestureHandler: 293aea360e79439e2272b8a5ffebd582a1e4c486 RNReanimated: af5545657216ca1794252c132f9e6e8ceb475462 RNScreens: 02747ebee17d2e322af4ee383877367cf82a3cd6 - RNShopifyCheckoutSheetKit: 26cb201d8ef66263aaec45c2bfa9649606576a2a + RNShopifyCheckoutSheetKit: 31d302a9150b461f5fac739bbdcc18cd0f750a6b RNVectorIcons: 6c795cacc9276decc31d8e1a139b9cc6fc0479ca - ShopifyCheckoutSheetKit: 5ae02dbed0047689b94c977bdcf6287752d17ce4 + ShopifyCheckoutSheetKit: 5ee0c9753132d79924089ddef7e73ba4aa84fe37 SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d SwiftLint: eb47480d47c982481592c195c221d11013a679cc Yoga: 348f8b538c3ed4423eb58a8e5730feec50bce372 PODFILE CHECKSUM: 9efd19a381198fb46f36acf3d269233039fb9dc5 -COCOAPODS: 1.16.1 +COCOAPODS: 1.16.2 diff --git a/sample/ios/ReactNativeTests/ShopifyCheckoutSheetKitTests.swift b/sample/ios/ReactNativeTests/ShopifyCheckoutSheetKitTests.swift index bfdbbcc0..3f876eb8 100644 --- a/sample/ios/ReactNativeTests/ShopifyCheckoutSheetKitTests.swift +++ b/sample/ios/ReactNativeTests/ShopifyCheckoutSheetKitTests.swift @@ -43,6 +43,7 @@ class ShopifyCheckoutSheetKitTests: XCTestCase { private func resetShopifyCheckoutSheetKitDefaults() { ShopifyCheckoutSheetKit.configuration.preloading = Configuration.Preloading(enabled: true) ShopifyCheckoutSheetKit.configuration.colorScheme = .automatic + ShopifyCheckoutSheetKit.configuration.closeButtonTintColor = nil } private func getShopifyCheckoutSheetKit() -> RCTShopifyCheckoutSheetKit { @@ -106,6 +107,71 @@ class ShopifyCheckoutSheetKitTests: XCTestCase { XCTAssertEqual(ShopifyCheckoutSheetKit.configuration.tintColor, defaultColorFallback) } + func testConfigureWithCloseButtonColor() { + let configuration: [AnyHashable: Any] = [ + "colors": [ + "ios": [ + "closeButtonColor": "#FF0000" + ] + ] + ] + + shopifyCheckoutSheetKit.setConfig(configuration) + + XCTAssertEqual(ShopifyCheckoutSheetKit.configuration.closeButtonTintColor, UIColor(hex: "#FF0000")) + } + + func testConfigureWithInvalidCloseButtonColor() { + let configuration: [AnyHashable: Any] = [ + "colors": [ + "ios": [ + "closeButtonColor": "invalid" + ] + ] + ] + + let defaultColorFallback = UIColor(red: 0, green: 0, blue: 0, alpha: 1) + shopifyCheckoutSheetKit.setConfig(configuration) + + XCTAssertEqual(ShopifyCheckoutSheetKit.configuration.closeButtonTintColor, defaultColorFallback) + } + + func testConfigureWithoutCloseButtonColor() { + let configuration: [AnyHashable: Any] = [ + "colors": [ + "ios": [ + "tintColor": "#FF0000" + ] + ] + ] + + shopifyCheckoutSheetKit.setConfig(configuration) + + // closeButtonTintColor should remain nil when not specified (uses system default) + XCTAssertNil(ShopifyCheckoutSheetKit.configuration.closeButtonTintColor) + } + + func testGetConfigIncludesCloseButtonColor() { + // Set a close button color + let configuration: [AnyHashable: Any] = [ + "colors": [ + "ios": [ + "closeButtonColor": "#00FF00" + ] + ] + ] + shopifyCheckoutSheetKit.setConfig(configuration) + + // Call getConfig and capture the result + var result: [String: Any]? + shopifyCheckoutSheetKit.getConfig({ config in result = config as? [String: Any] }, reject: { _, _, _ in }) + + // Verify that getConfig returned the close button color + XCTAssertNotNil(result?["closeButtonColor"]) + let returnedColor = result?["closeButtonColor"] as? UIColor + XCTAssertEqual(returnedColor, UIColor(hex: "#00FF00")) + } + /// checkoutDidComplete func testCheckoutDidCompleteSendsEvent() { let event = CheckoutCompletedEvent( diff --git a/sample/src/App.tsx b/sample/src/App.tsx index 4bc9947d..32cc79a0 100644 --- a/sample/src/App.tsx +++ b/sample/src/App.tsx @@ -33,7 +33,7 @@ import { import {createBottomTabNavigator} from '@react-navigation/bottom-tabs'; import {createNativeStackNavigator} from '@react-navigation/native-stack'; import {ApolloClient, InMemoryCache, ApolloProvider} from '@apollo/client'; -import env from 'react-native-config'; +import Config from 'react-native-config'; import Icon from 'react-native-vector-icons/Entypo'; import CatalogScreen from './screens/CatalogScreen'; @@ -67,12 +67,14 @@ const config: Configuration = { ios: { backgroundColor: '#f0f0e8', tintColor: '#2d2a38', + closeButtonColor: '#2d2a38', }, android: { backgroundColor: '#f0f0e8', progressIndicator: '#2d2a38', headerBackgroundColor: '#f0f0e8', headerTextColor: '#2d2a38', + closeButtonColor: '#2d2a38', }, }, }; @@ -92,11 +94,11 @@ const Stack = createNativeStackNavigator(); export const cache = new InMemoryCache(); const client = new ApolloClient({ - uri: `https://${env.STOREFRONT_DOMAIN}/api/${env.STOREFRONT_VERSION}/graphql.json`, + uri: `https://${Config.STOREFRONT_DOMAIN}/api/${Config.STOREFRONT_VERSION}/graphql.json`, cache, headers: { 'Content-Type': 'application/json', - 'X-Shopify-Storefront-Access-Token': env.STOREFRONT_ACCESS_TOKEN ?? '', + 'X-Shopify-Storefront-Access-Token': Config.STOREFRONT_ACCESS_TOKEN ?? '', }, connectToDevTools: true, }); @@ -170,14 +172,18 @@ function AppWithContext({children}: PropsWithChildren) { }); const pixel = shopify.addEventListener('pixel', (event: PixelEvent) => { - console.log('[CheckoutPixelEvent]', event.name, event); + console.log( + '[CheckoutPixelEvent]', + event.name, + JSON.stringify(event, null, 2), + ); }); const completed = shopify.addEventListener( 'completed', (event: CheckoutCompletedEvent) => { console.log('[CheckoutCompletedEvent]', event.orderDetails.id); - console.log('[CheckoutCompletedEvent]', event); + console.log('[CheckoutCompletedEvent]', JSON.stringify(event, null, 2)); }, ); diff --git a/sample/src/context/Theme.tsx b/sample/src/context/Theme.tsx index 7b7dcdb8..de91c8af 100644 --- a/sample/src/context/Theme.tsx +++ b/sample/src/context/Theme.tsx @@ -27,6 +27,7 @@ export const darkColors: Colors = { webViewProgressIndicator: '#0B96F1', webviewHeaderBackgroundColor: '#1D1D1F', webviewHeaderTextColor: '#ffffff', + webviewCloseButtonColor: '#ffffff', }; export const lightColors: Colors = { @@ -44,6 +45,7 @@ export const lightColors: Colors = { webViewProgressIndicator: '#0087ff', webviewHeaderBackgroundColor: '#ffffff', webviewHeaderTextColor: '#000000', + webviewCloseButtonColor: '#000000', }; export const webColors: Colors = { @@ -61,6 +63,7 @@ export const webColors: Colors = { webViewProgressIndicator: '#2c2a38', webviewHeaderBackgroundColor: '#f0f0e8', webviewHeaderTextColor: '#2c2a38', + webviewCloseButtonColor: '#2c2a38', }; const ThemeContext = createContext({ @@ -84,6 +87,7 @@ export interface Colors { webViewProgressIndicator: string; webviewHeaderBackgroundColor: string; webviewHeaderTextColor: string; + webviewCloseButtonColor: string; } export function getNavigationTheme( diff --git a/sample/src/screens/SettingsScreen.tsx b/sample/src/screens/SettingsScreen.tsx index 45ddc970..f05f1a7c 100644 --- a/sample/src/screens/SettingsScreen.tsx +++ b/sample/src/screens/SettingsScreen.tsx @@ -33,6 +33,7 @@ import { View, } from 'react-native'; import pkg from '../../../package.json'; +import Config from 'react-native-config'; import {useConfig} from '../context/Config'; import { ColorScheme, @@ -109,12 +110,14 @@ function SettingsScreen() { progressIndicator: lightColors.webViewProgressIndicator, headerBackgroundColor: lightColors.webviewBackgroundColor, headerTextColor: lightColors.webviewHeaderTextColor, + closeButtonColor: lightColors.webviewCloseButtonColor, }, dark: { backgroundColor: darkColors.webviewBackgroundColor, progressIndicator: darkColors.webViewProgressIndicator, headerBackgroundColor: darkColors.webviewBackgroundColor, headerTextColor: darkColors.webviewHeaderTextColor, + closeButtonColor: darkColors.webviewCloseButtonColor, }, }, }, @@ -126,12 +129,14 @@ function SettingsScreen() { ios: { backgroundColor: updatedColors.webviewBackgroundColor, tintColor: updatedColors.webViewProgressIndicator, + closeButtonColor: updatedColors.webviewCloseButtonColor, }, android: { backgroundColor: updatedColors.webviewBackgroundColor, progressIndicator: updatedColors.webViewProgressIndicator, headerBackgroundColor: updatedColors.webviewBackgroundColor, headerTextColor: updatedColors.webviewHeaderTextColor, + closeButtonColor: updatedColors.webviewCloseButtonColor, }, }, }); @@ -216,6 +221,16 @@ function SettingsScreen() { type: SectionType.Text, value: pkg.version, }, + { + title: 'Storefront Domain', + type: SectionType.Text, + value: Config.STOREFRONT_DOMAIN || 'undefined', + }, + { + title: 'Storefront Access Token (last 4)', + type: SectionType.Text, + value: Config.STOREFRONT_ACCESS_TOKEN?.slice(-4) || 'undefined', + }, ], [ShopifyCheckout.version], ); diff --git a/sample/src/utils.ts b/sample/src/utils.ts index 0afda116..56131a9d 100644 --- a/sample/src/utils.ts +++ b/sample/src/utils.ts @@ -1,4 +1,4 @@ -import env from 'react-native-config'; +import Config from 'react-native-config'; import {NativeModules, Platform} from 'react-native'; import type {AppConfig} from './context/Config'; @@ -14,7 +14,7 @@ const { PROVINCE, ZIP, PHONE, -} = env; +} = Config; export function createBuyerIdentityCartInput(appConfig: AppConfig) { if (!appConfig.prefillBuyerInformation) {