Skip to content

Commit 5cf72ea

Browse files
authored
[0.2.0] Add support for Web Pixel events (#57)
* Add support for Web Pixel events
1 parent f24f2a2 commit 5cf72ea

File tree

24 files changed

+1131
-82
lines changed

24 files changed

+1131
-82
lines changed

.github/actions/setup/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ runs:
77
- name: Setup Node.js
88
uses: actions/setup-node@v3
99
with:
10-
node-version: 18
10+
node-version: 20
1111

1212
- name: Cache turbo build setup
1313
uses: actions/cache@v3

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,4 @@ modules/@shopify/checkout-sheet-kit/android/gradlew.bat
9191

9292
# Sample bundle
9393
**/index.android.bundle
94+
.xcode.env.local

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## 0.2.0 - January 30, 2024
4+
5+
Exposes a new `pixel` event type, which enables you to consume
6+
[Standard](https://shopify.dev/docs/api/web-pixels-api/standard-events) and
7+
[Custom](https://shopify.dev/docs/api/web-pixels-api/emitting-data#publishing-custom-events)
8+
Web Pixels from Checkout and relay them to your third-party analytics providers.
9+
310
## 0.1.1 - January 15, 2024
411

512
Updates the README on the NPM regsitry entry page.

README.md

Lines changed: 56 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@
44

55
![image](https://github.com/Shopify/checkout-sheet-kit-react-native/assets/2034704/73246cc6-bd39-4130-a7df-69b06907b897)
66

7-
**Shopify Checkout Sheet Kit** is a Native Module that enables React Native apps to provide the world’s highest converting, customizable, one-page checkout within the app. The presented experience is a fully-featured checkout that preserves all of the store customizations: Checkout UI extensions, Functions, branding, and more. It also provides platform idiomatic defaults such as support for light and dark mode, and convenient developer APIs to embed, customize, and follow the lifecycle of the checkout experience.
7+
**Shopify Checkout Sheet Kit** is a Native Module that enables React Native apps
8+
to provide the world’s highest converting, customizable, one-page checkout
9+
within the app. The presented experience is a fully-featured checkout that
10+
preserves all of the store customizations: Checkout UI extensions, Functions,
11+
branding, and more. It also provides platform idiomatic defaults such as support
12+
for light and dark mode, and convenient developer APIs to embed, customize, and
13+
follow the lifecycle of the checkout experience.
814

915
Check out our blog to
1016
[learn how and why we built the Shopify Checkout Sheet Kit](https://www.shopify.com/partners/blog/mobile-checkout-sdks-for-ios-and-android).
@@ -24,9 +30,10 @@ experiences.
2430

2531
### Getting Started
2632

27-
Shopify Checkout Sheet Kit is an open-source NPM package.
33+
Shopify Checkout Sheet Kit is an open-source NPM package.
2834

29-
Use the following steps to get started with adding it to your React Native application:
35+
Use the following steps to get started with adding it to your React Native
36+
application:
3037

3138
#### 1. Install
3239

@@ -113,8 +120,8 @@ to get a checkoutUrl to pass to the SDK.
113120

114121
To use the library without React context, import the `ShopifyCheckoutSheet`
115122
class from the package and instantiate it. We recommend to instantiating the
116-
class at a relatively high level in your application, and exporting it for use throughout
117-
your app.
123+
class at a relatively high level in your application, and exporting it for use
124+
throughout your app.
118125

119126
```tsx
120127
// shopify.ts
@@ -320,7 +327,7 @@ behavior can be customized via the `colorScheme` property:
320327
| ----------- | ------- | ------------------------------------------------------------------------------------------------ |
321328
| `automatic` | ✔ | Alternates between an idiomatic light and dark theme - depending on the users device preference. |
322329
| `light` | | Force the idomatic light theme. |
323-
| `dark` | | Force the idomatic dark theme. |
330+
| `dark` | | Force the idomatic dark theme. |
324331
| `web` | | Force your storefront web theme, as rendered by a mobile browser. |
325332

326333
#### `colors`
@@ -434,11 +441,12 @@ There are currently 3 checkout events exposed through the Native Module. You can
434441
subscribe to these events using `addEventListener` and `removeEventListeners`
435442
methods - available on both the context provider as well as the class instance.
436443

437-
| Name | Callback | Description |
438-
| ----------- | ------------------------------------ | -------------------------------------------------------- |
439-
| `close` | `() => void` | Fired when the checkout has been closed. |
440-
| `completed` | `() => void` | Fired when the checkout has been successfully completed. |
441-
| `error` | `(error: {message: string}) => void` | Fired when a checkout exception has been raised. |
444+
| Name | Callback | Description |
445+
| ----------- | ------------------------------------ | ------------------------------------------------------------ |
446+
| `close` | `() => void` | Fired when the checkout has been closed. |
447+
| `completed` | `() => void` | Fired when the checkout has been successfully completed. |
448+
| `error` | `(error: {message: string}) => void` | Fired when a checkout exception has been raised. |
449+
| `pixel` | `(event: PixelEvent) => void` | Fired when a Web Pixel event has been relayed from checkout. |
442450

443451
#### `addEventListener(eventName, callback)`
444452

@@ -459,16 +467,30 @@ useEffect(() => {
459467
// Do something on checkout completion
460468
});
461469

462-
const error = shopifyCheckout.addEventListener('error', error => {
463-
// Do something on checkout error
464-
// console.log(error.message)
465-
});
470+
const error = shopifyCheckout.addEventListener(
471+
'error',
472+
(error: CheckoutError) => {
473+
// Do something on checkout error
474+
// console.log(error.message)
475+
},
476+
);
477+
478+
const pixel = shopifyCheckout.addEventListener(
479+
'pixel',
480+
(event: PixelEvent) => {
481+
// Dispatch web pixel events to third-party services
482+
if (hasPermissionToTrack) {
483+
sendEventToAnalyticsProvider(event);
484+
}
485+
},
486+
);
466487

467488
return () => {
468489
// It is important to clear the subscription on unmount to prevent memory leaks
469490
close?.remove();
470491
completed?.remove();
471492
error?.remove();
493+
pixel?.remove();
472494
};
473495
}, [shopifyCheckout]);
474496
```
@@ -482,10 +504,24 @@ On the rare occasion that you want to remove all event listeners for a given
482504

483505
App developers can use
484506
[lifecycle events](#monitoring-the-lifecycle-of-a-checkout-session) to monitor
485-
and log the status of a checkout session. Web Pixel events are currently not
486-
executed within rendered checkout. Support for customer events and behavioral
487-
analytics is under development and will be available prior to the general
488-
availability of SDK.
507+
and log the status of a checkout session.
508+
509+
\*\*For behavioural monitoring,
510+
[standard](https://shopify.dev/docs/api/web-pixels-api/standard-events) and
511+
[custom](https://shopify.dev/docs/api/web-pixels-api#custom-web-pixels) Web
512+
Pixel events will be relayed back to your application through the `"pixel"`
513+
event listener. The responsibility then falls on the application developer to
514+
ensure adherence to Apple's privacy policy and local regulations like GDPR and
515+
ePrivacy directive before disseminating these events to first-party and
516+
third-party systems.
517+
518+
_Note that you will likely need to augment these events with customer/session
519+
information derived from app state._
520+
521+
_Also note that the customData attribute of CustomPixelEvent can take on any
522+
shape. As such, this attribute will be returned as a String. Client applications
523+
should define a custom data type and deserialize the customData string into that
524+
type._
489525

490526
### Integrating identity & customer accounts
491527

@@ -517,8 +553,7 @@ external identity system and initialize a buyer-aware checkout session.
517553
"email": "<Customer's email address>",
518554
"created_at": "<Current timestamp in ISO8601 encoding>",
519555
"remote_ip": "<Client IP address>",
520-
"return_to": "<Checkout URL obtained from Storefront API>",
521-
...
556+
"return_to": "<Checkout URL obtained from Storefront API>"
522557
}
523558
```
524559

modules/@shopify/checkout-sheet-kit/.swiftlint.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ disabled_rules:
22
- line_length
33
- redundant_void_return
44
- todo
5+
- switch_case_alignment
56

67
opt_in_rules:
78
- array_init

modules/@shopify/checkout-sheet-kit/RNShopifyCheckoutSheetKit.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Pod::Spec.new do |s|
2020
s.source_files = "ios/*.{h,m,mm,swift}"
2121

2222
s.dependency "React-Core"
23-
s.dependency "ShopifyCheckoutSheetKit", "~> 0.9"
23+
s.dependency "ShopifyCheckoutSheetKit", "~> 0.10.1"
2424

2525
if fabric_enabled
2626
install_modules_dependencies(s)

modules/@shopify/checkout-sheet-kit/android/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,9 @@ dependencies {
9090
// For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
9191
//noinspection GradleDynamicVersion
9292
implementation "com.facebook.react:react-native:+"
93-
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.7.0"
93+
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.9.0"
9494
implementation("com.shopify:checkout-sheet-kit:${SHOPIFY_CHECKOUT_SDK_VERSION}")
95+
implementation("com.fasterxml.jackson.core:jackson-databind:2.12.5")
9596
debugImplementation("com.shopify:checkout-sheet-kit:${SHOPIFY_CHECKOUT_SDK_VERSION}")
9697
}
9798

modules/@shopify/checkout-sheet-kit/android/gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ ndkVersion=23.1.7779620
55
buildToolsVersion = "33.0.0"
66

77
# Version of Shopify Checkout SDK to use with React Native
8-
SHOPIFY_CHECKOUT_SDK_VERSION=0.4.1
8+
SHOPIFY_CHECKOUT_SDK_VERSION=0.5.0

modules/@shopify/checkout-sheet-kit/android/src/main/java/com/shopify/reactnative/checkoutsheetkit/CustomCheckoutEventProcessor.java

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,19 @@ of this software and associated documentation files (the "Software"), to deal
2424
package com.shopify.reactnative.checkoutsheetkit;
2525

2626
import android.content.Context;
27+
import android.util.Log;
28+
import androidx.annotation.NonNull;
2729
import com.shopify.checkoutsheetkit.*;
2830
import com.facebook.react.modules.core.DeviceEventManagerModule;
29-
import com.facebook.react.bridge.ReactMethod;
30-
import com.facebook.react.bridge.ReactApplicationContext;
31-
import com.facebook.react.bridge.ReactContextBaseJavaModule;
3231
import com.facebook.react.bridge.ReactContext;
33-
import com.facebook.react.bridge.WritableMap;
34-
import com.facebook.react.bridge.JavaOnlyMap;
32+
import com.facebook.react.bridge.WritableNativeMap;
33+
import com.shopify.checkoutsheetkit.pixelevents.PixelEvent;
34+
import com.fasterxml.jackson.databind.ObjectMapper;
3535
import org.jetbrains.annotations.Nullable;
36+
import java.io.IOException;
3637

3738
public class CustomCheckoutEventProcessor extends DefaultCheckoutEventProcessor {
38-
private ReactContext reactContext;
39+
private final ReactContext reactContext;
3940

4041
public CustomCheckoutEventProcessor(Context context, ReactContext reactContext) {
4142
super(context);
@@ -45,26 +46,43 @@ public CustomCheckoutEventProcessor(Context context, ReactContext reactContext)
4546

4647
@Override
4748
public void onCheckoutCompleted() {
48-
sendEvent(this.reactContext, "completed", null);
49+
sendEvent("completed", null);
50+
}
51+
52+
@Override
53+
public void onWebPixelEvent(@NonNull PixelEvent event) {
54+
try {
55+
ObjectMapper mapper = new ObjectMapper();
56+
String data = mapper.writeValueAsString(event);
57+
sendPixelEvent(data);
58+
} catch (IOException e) {
59+
Log.e("ShopifyCheckoutSheetKit", "Error processing pixel event", e);
60+
}
4961
}
5062

5163
@Override
5264
public void onCheckoutFailed(CheckoutException checkoutError) {
53-
JavaOnlyMap error = new JavaOnlyMap();
65+
WritableNativeMap error = new WritableNativeMap();
5466

5567
error.putString("message", checkoutError.getErrorDescription());
5668

57-
sendEvent(this.reactContext, "error", error);
69+
sendEvent("error", error);
5870
}
5971

6072
@Override
6173
public void onCheckoutCanceled() {
62-
sendEvent(this.reactContext, "close", null);
74+
sendEvent("close", null);
6375
}
6476

65-
private void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap params) {
77+
private void sendEvent(String eventName, @Nullable WritableNativeMap params) {
6678
reactContext
6779
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
6880
.emit(eventName, params);
6981
}
82+
83+
private void sendPixelEvent(String data) {
84+
reactContext
85+
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
86+
.emit("pixel", data);
87+
}
7088
}

0 commit comments

Comments
 (0)