diff --git a/modules/@shopify/checkout-sheet-kit/android/src/main/java/com/shopify/reactnative/checkoutsheetkit/RCTCheckoutWebView.java b/modules/@shopify/checkout-sheet-kit/android/src/main/java/com/shopify/reactnative/checkoutsheetkit/RCTCheckoutWebView.java index 512133da..a8d4004f 100644 --- a/modules/@shopify/checkout-sheet-kit/android/src/main/java/com/shopify/reactnative/checkoutsheetkit/RCTCheckoutWebView.java +++ b/modules/@shopify/checkout-sheet-kit/android/src/main/java/com/shopify/reactnative/checkoutsheetkit/RCTCheckoutWebView.java @@ -55,6 +55,8 @@ of this software and associated documentation files (the "Software"), to deal import com.shopify.checkoutsheetkit.lifecycleevents.CheckoutStartEvent; import com.shopify.checkoutsheetkit.rpc.events.CheckoutAddressChangeStart; import com.shopify.checkoutsheetkit.rpc.events.CheckoutAddressChangeStartEvent; +import com.shopify.checkoutsheetkit.rpc.events.CheckoutSubmitStart; +import com.shopify.checkoutsheetkit.rpc.events.CheckoutSubmitStartEvent; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; @@ -351,6 +353,26 @@ public void onAddressChangeStart(@NonNull CheckoutAddressChangeStart event) { } } + @Override + public void onSubmitStart(@NonNull CheckoutSubmitStart event) { + try { + CheckoutSubmitStartEvent params = event.getParams(); + Map eventData = new HashMap<>(); + + eventData.put("id", event.getId()); + eventData.put("type", "submitStart"); + eventData.put("cart", params.getCart()); + + Map checkoutData = new HashMap<>(); + checkoutData.put("id", params.getCheckout().getId()); + eventData.put("checkout", checkoutData); + + sendEvent("onSubmitStart", serializeToWritableMap(eventData)); + } catch (Exception e) { + Log.e(TAG, "Error processing submit start event", e); + } + } + @Override public void onLinkClick(@NonNull Uri uri) { WritableMap params = Arguments.createMap(); diff --git a/modules/@shopify/checkout-sheet-kit/android/src/main/java/com/shopify/reactnative/checkoutsheetkit/RCTCheckoutWebViewManager.java b/modules/@shopify/checkout-sheet-kit/android/src/main/java/com/shopify/reactnative/checkoutsheetkit/RCTCheckoutWebViewManager.java index 96ac7206..45b7f93d 100644 --- a/modules/@shopify/checkout-sheet-kit/android/src/main/java/com/shopify/reactnative/checkoutsheetkit/RCTCheckoutWebViewManager.java +++ b/modules/@shopify/checkout-sheet-kit/android/src/main/java/com/shopify/reactnative/checkoutsheetkit/RCTCheckoutWebViewManager.java @@ -91,6 +91,7 @@ public Map getExportedCustomDirectEventTypeConstants() { events.put("onCancel", createEventMap("onCancel")); events.put("onLinkClick", createEventMap("onLinkClick")); events.put("onAddressChangeStart", createEventMap("onAddressChangeStart")); + events.put("onSubmitStart", createEventMap("onSubmitStart")); return events; } diff --git a/modules/@shopify/checkout-sheet-kit/android/src/main/java/com/shopify/reactnative/checkoutsheetkit/SheetCheckoutEventProcessor.java b/modules/@shopify/checkout-sheet-kit/android/src/main/java/com/shopify/reactnative/checkoutsheetkit/SheetCheckoutEventProcessor.java index 45a3279e..64ba94bb 100644 --- a/modules/@shopify/checkout-sheet-kit/android/src/main/java/com/shopify/reactnative/checkoutsheetkit/SheetCheckoutEventProcessor.java +++ b/modules/@shopify/checkout-sheet-kit/android/src/main/java/com/shopify/reactnative/checkoutsheetkit/SheetCheckoutEventProcessor.java @@ -44,6 +44,8 @@ of this software and associated documentation files (the "Software"), to deal import com.shopify.checkoutsheetkit.lifecycleevents.CheckoutStartEvent; import com.shopify.checkoutsheetkit.rpc.events.CheckoutAddressChangeStart; import com.shopify.checkoutsheetkit.rpc.events.CheckoutAddressChangeStartEvent; +import com.shopify.checkoutsheetkit.rpc.events.CheckoutSubmitStart; +import com.shopify.checkoutsheetkit.rpc.events.CheckoutSubmitStartEvent; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; @@ -172,6 +174,31 @@ public void onAddressChangeStart(@NonNull CheckoutAddressChangeStart event) { } } + @Override + public void onSubmitStart(@NonNull CheckoutSubmitStart event) { + try { + CheckoutSubmitStartEvent params = event.getParams(); + if (params == null) { + Log.e("ShopifyCheckoutSheetKit", "Submit start event has null params"); + return; + } + + Map eventData = new HashMap<>(); + eventData.put("id", event.getId()); + eventData.put("type", "submitStart"); + eventData.put("cart", params.getCart()); + + Map checkoutData = new HashMap<>(); + checkoutData.put("id", params.getCheckout().getId()); + eventData.put("checkout", checkoutData); + + String data = mapper.writeValueAsString(eventData); + sendEventWithStringData("submitStart", data); + } catch (IOException e) { + Log.e("ShopifyCheckoutSheetKit", "Error processing submit start event", e); + } + } + // Private private Map populateErrorDetails(CheckoutException error) { diff --git a/modules/@shopify/checkout-sheet-kit/ios/RCTCheckoutWebView.swift b/modules/@shopify/checkout-sheet-kit/ios/RCTCheckoutWebView.swift index 52179437..6548cdb8 100644 --- a/modules/@shopify/checkout-sheet-kit/ios/RCTCheckoutWebView.swift +++ b/modules/@shopify/checkout-sheet-kit/ios/RCTCheckoutWebView.swift @@ -85,6 +85,7 @@ class RCTCheckoutWebView: UIView { @objc var onLinkClick: RCTBubblingEventBlock? @objc var onAddressChangeStart: RCTBubblingEventBlock? @objc var onPaymentChangeIntent: RCTBubblingEventBlock? + @objc var onSubmitStart: RCTBubblingEventBlock? override init(frame: CGRect) { super.init(frame: frame) @@ -324,4 +325,30 @@ extension RCTCheckoutWebView: CheckoutDelegate { onPaymentChangeIntent?(eventData) } + + /// Called when the buyer attempts to submit the checkout. + /// + /// This event is only emitted when native payment delegation is configured + /// for the authenticated app. + /// + /// - Parameter event: The submit start event containing: + /// - id: Unique identifier for responding to the event + /// - cart: Current cart state + /// - checkout: Checkout session information + func checkoutDidStartSubmit(event: CheckoutSubmitStart) { + guard let id = event.id else { return } + + self.events.set(key: id, event: event) + + let cartJSON = ShopifyEventSerialization.encodeToJSON(from: event.params.cart) + + onSubmitStart?([ + "id": event.id, + "type": "submitStart", + "cart": cartJSON, + "checkout": [ + "id": event.params.checkout.id + ], + ]) + } } diff --git a/modules/@shopify/checkout-sheet-kit/ios/ShopifyCheckoutSheetKit+EventSerialization.swift b/modules/@shopify/checkout-sheet-kit/ios/ShopifyCheckoutSheetKit+EventSerialization.swift index a096c89f..e76ca7fe 100644 --- a/modules/@shopify/checkout-sheet-kit/ios/ShopifyCheckoutSheetKit+EventSerialization.swift +++ b/modules/@shopify/checkout-sheet-kit/ios/ShopifyCheckoutSheetKit+EventSerialization.swift @@ -85,6 +85,20 @@ internal enum ShopifyEventSerialization { ] } + /** + * Converts a CheckoutSubmitStart to a React Native compatible dictionary. + */ + static func serialize(checkoutSubmitStart event: CheckoutSubmitStart) -> [String: Any] { + return [ + "id": event.id as Any, + "type": "submitStart", + "cart": encodeToJSON(from: event.params.cart), + "checkout": [ + "id": event.params.checkout.id + ] + ] + } + static func serialize(clickEvent url: URL) -> [String: URL] { return ["url": url] } diff --git a/modules/@shopify/checkout-sheet-kit/ios/ShopifyCheckoutSheetKit.mm b/modules/@shopify/checkout-sheet-kit/ios/ShopifyCheckoutSheetKit.mm index 873083bb..e6a80e75 100644 --- a/modules/@shopify/checkout-sheet-kit/ios/ShopifyCheckoutSheetKit.mm +++ b/modules/@shopify/checkout-sheet-kit/ios/ShopifyCheckoutSheetKit.mm @@ -128,6 +128,11 @@ @interface RCT_EXTERN_MODULE (RCTCheckoutWebViewManager, RCTViewManager) */ RCT_EXPORT_VIEW_PROPERTY(onPaymentChangeIntent, RCTBubblingEventBlock) + /** + * Emitted when the buyer attempts to submit the checkout + */ + RCT_EXPORT_VIEW_PROPERTY(onSubmitStart, RCTBubblingEventBlock) + /** * Emitted when a link is clicked */ diff --git a/modules/@shopify/checkout-sheet-kit/ios/ShopifyCheckoutSheetKit.swift b/modules/@shopify/checkout-sheet-kit/ios/ShopifyCheckoutSheetKit.swift index 5e4883a2..5657dd06 100644 --- a/modules/@shopify/checkout-sheet-kit/ios/ShopifyCheckoutSheetKit.swift +++ b/modules/@shopify/checkout-sheet-kit/ios/ShopifyCheckoutSheetKit.swift @@ -53,7 +53,7 @@ class RCTShopifyCheckoutSheetKit: RCTEventEmitter, CheckoutDelegate { } override func supportedEvents() -> [String]! { - return ["close", "complete", "start", "error", "addressChangeStart"] + return ["close", "complete", "start", "error", "addressChangeStart", "submitStart"] } override func startObserving() { @@ -82,6 +82,12 @@ class RCTShopifyCheckoutSheetKit: RCTEventEmitter, CheckoutDelegate { } } + func checkoutDidStartSubmit(event: CheckoutSubmitStart) { + if hasListeners { + sendEvent(withName: "submitStart", body: ShopifyEventSerialization.serialize(checkoutSubmitStart: event)) + } + } + func shouldRecoverFromError(error: CheckoutError) -> Bool { return error.isRecoverable } diff --git a/modules/@shopify/checkout-sheet-kit/src/components/Checkout.tsx b/modules/@shopify/checkout-sheet-kit/src/components/Checkout.tsx index 194ff601..ef23e98e 100644 --- a/modules/@shopify/checkout-sheet-kit/src/components/Checkout.tsx +++ b/modules/@shopify/checkout-sheet-kit/src/components/Checkout.tsx @@ -35,7 +35,11 @@ import type { CheckoutException, } from '..'; import {useCheckoutEvents} from '../CheckoutEventProvider'; -import type {CheckoutAddressChangeStart, CheckoutStartEvent} from '../events'; +import type { + CheckoutAddressChangeStart, + CheckoutStartEvent, + CheckoutSubmitStart +} from '../events'; export interface CheckoutProps { /** @@ -81,6 +85,14 @@ export interface CheckoutProps { */ onAddressChangeStart?: (event: CheckoutAddressChangeStart) => void; + /** + * Called when the buyer attempts to submit the checkout. + * + * Note: This callback is only invoked when native payment delegation is configured + * for the authenticated app. + */ + onSubmitStart?: (event: CheckoutSubmitStart) => void; + /** * Style for the webview container */ @@ -110,6 +122,7 @@ interface NativeCheckoutWebViewProps { onCancel?: () => void; onLinkClick?: (event: {nativeEvent: {url: string}}) => void; onAddressChangeStart?: (event: {nativeEvent: CheckoutAddressChangeStart}) => void; + onSubmitStart?: (event: {nativeEvent: CheckoutSubmitStart}) => void; } const RCTCheckoutWebView = @@ -167,6 +180,7 @@ export const Checkout = forwardRef( onCancel, onLinkClick, onAddressChangeStart, + onSubmitStart, style, testID, }, @@ -239,6 +253,16 @@ export const Checkout = forwardRef( [onAddressChangeStart], ); + const handleSubmitStart = useCallback< + Required['onSubmitStart'] + >( + (event: {nativeEvent: CheckoutSubmitStart}) => { + if (!event.nativeEvent) return; + onSubmitStart?.(event.nativeEvent); + }, + [onSubmitStart], + ); + const reload = useCallback(() => { if (!webViewRef.current) { return; @@ -273,6 +297,7 @@ export const Checkout = forwardRef( onCancel={handleCancel} onLinkClick={handleLinkClick} onAddressChangeStart={handleAddressChangeStart} + onSubmitStart={handleSubmitStart} /> ); }, diff --git a/modules/@shopify/checkout-sheet-kit/src/events.d.ts b/modules/@shopify/checkout-sheet-kit/src/events.d.ts index e2d9f19d..06c29607 100644 --- a/modules/@shopify/checkout-sheet-kit/src/events.d.ts +++ b/modules/@shopify/checkout-sheet-kit/src/events.d.ts @@ -379,7 +379,6 @@ export interface CheckoutResponseError { /** * Mailing address input for delivery. - * Aligns with Storefront API MailingAddressInput. * * @see https://shopify.dev/docs/api/storefront/latest/input-objects/MailingAddressInput */ @@ -428,7 +427,6 @@ export interface CartDeliveryAddressInput { /** * Delivery-related fields for the cart. - * Aligns with Storefront API CartDeliveryInput. * * @see https://shopify.dev/docs/api/storefront/latest/input-objects/CartDeliveryInput */ @@ -441,7 +439,6 @@ export interface CartDeliveryInput { /** * The customer associated with the cart. - * Aligns with Storefront API CartBuyerIdentityInput. * * @see https://shopify.dev/docs/api/storefront/latest/input-objects/CartBuyerIdentityInput */ @@ -523,7 +520,7 @@ export interface CheckoutAddressChangeStart { */ export interface CheckoutAddressChangeStartResponse { /** - * Updated cart input with the delivery address to set. + * Updated cart input with the delivery addresses to set. */ cart?: CartInput; /** @@ -548,3 +545,71 @@ export interface CheckoutPaymentChangeIntent { brand: string; }; } + +/** + * Checkout session information. + */ +export interface CheckoutSession { + /** Globally unique identifier for the checkout session */ + id: string; +} + +/** + * Event emitted when the buyer attempts to submit the checkout. + * + * This event is only emitted when native payment delegation is configured + * for the authenticated app. + */ +export interface CheckoutSubmitStart { + /** + * Unique identifier for this event instance. + * Use this ID with the CheckoutEventProvider to respond to the event. + */ + id: string; + + /** + * The event type identifier + */ + type: 'submitStart'; + + /** + * The current cart state when the event was emitted. + */ + cart: Cart; + + /** + * The checkout session information. + */ + checkout: CheckoutSession; +} + +/** + * Payment token input for delegated payment processing. + */ +export interface PaymentTokenInput { + token: string; + tokenType: string; + tokenProvider: string; +} + +/** + * Response payload for CheckoutSubmitStart event. + * Use with CheckoutEventProvider.respondToEvent() or useShopifyEvent().respondWith() + * + * Note: This response is only used when native payment delegation is enabled + * for the authenticated app. + */ +export interface CheckoutSubmitStartResponse { + /** + * Optional payment token information for delegated payment processing. + */ + payment?: PaymentTokenInput; + /** + * Updated cart input with delivery addresses and optional buyer identity. + */ + cart?: CartInput; + /** + * Optional array of errors if the submission failed. + */ + errors?: CheckoutResponseError[]; +} diff --git a/modules/@shopify/checkout-sheet-kit/src/index.d.ts b/modules/@shopify/checkout-sheet-kit/src/index.d.ts index c151d356..86d8804c 100644 --- a/modules/@shopify/checkout-sheet-kit/src/index.d.ts +++ b/modules/@shopify/checkout-sheet-kit/src/index.d.ts @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SO */ import type {EmitterSubscription} from 'react-native'; -import type {CheckoutCompleteEvent, CheckoutStartEvent} from './events'; +import type {CheckoutCompleteEvent, CheckoutStartEvent, CheckoutSubmitStart} from './events'; import type {CheckoutException} from './errors'; export type Maybe = T | undefined; @@ -153,6 +153,7 @@ export type CheckoutEvent = | 'start' | 'error' | 'addressChangeStart' + | 'submitStart' | 'geolocationRequest'; export interface GeolocationRequestEvent { @@ -173,6 +174,9 @@ export type CheckoutStartEventCallback = ( export type CheckoutAddressChangeStartCallback = ( event: CheckoutAddressChangeStart, ) => void; +export type CheckoutSubmitStartCallback = ( + event: CheckoutSubmitStart, +) => void; export type CheckoutEventCallback = | CloseEventCallback @@ -180,6 +184,7 @@ export type CheckoutEventCallback = | CheckoutCompleteEventCallback | CheckoutStartEventCallback | CheckoutAddressChangeStartCallback + | CheckoutSubmitStartCallback | GeolocationRequestEventCallback; /** @@ -263,6 +268,11 @@ function addEventListener( callback: CheckoutAddressChangeStartCallback, ): Maybe; +function addEventListener( + event: 'submitStart', + callback: CheckoutSubmitStartCallback, +): Maybe; + function addEventListener( event: 'error', callback: CheckoutExceptionCallback, diff --git a/modules/@shopify/checkout-sheet-kit/src/index.ts b/modules/@shopify/checkout-sheet-kit/src/index.ts index 1898d79d..0e444dcc 100644 --- a/modules/@shopify/checkout-sheet-kit/src/index.ts +++ b/modules/@shopify/checkout-sheet-kit/src/index.ts @@ -188,6 +188,9 @@ class ShopifyCheckoutSheet implements ShopifyCheckoutSheetKit { case 'addressChangeStart': eventCallback = this.interceptEventEmission('addressChangeStart', callback); break; + case 'submitStart': + eventCallback = this.interceptEventEmission('submitStart', callback); + break; case 'error': eventCallback = this.interceptEventEmission( 'error', @@ -502,12 +505,16 @@ export type { CartDeliveryAddressInput, CartDeliveryInput, CartInput, + PaymentTokenInput, + CheckoutSession, CheckoutAddressChangeStart, CheckoutAddressChangeStartResponse, CheckoutCompleteEvent, CheckoutPaymentChangeIntent, CheckoutResponseError, CheckoutStartEvent, + CheckoutSubmitStart, + CheckoutSubmitStartResponse, MailingAddressInput, } from './events.d'; diff --git a/modules/@shopify/checkout-sheet-kit/tests/CheckoutSubmitStart.test.tsx b/modules/@shopify/checkout-sheet-kit/tests/CheckoutSubmitStart.test.tsx new file mode 100644 index 00000000..cae80639 --- /dev/null +++ b/modules/@shopify/checkout-sheet-kit/tests/CheckoutSubmitStart.test.tsx @@ -0,0 +1,106 @@ +// Mock the native view component BEFORE imports +jest.mock('react-native', () => { + const RN = jest.requireActual('react-native'); + const React = jest.requireActual('react'); + + RN.UIManager.getViewManagerConfig = jest.fn(() => ({ + Commands: {}, + })); + + // Create mock component + const MockRCTCheckoutWebView = (props: any) => { + return React.createElement('View', props); + }; + + return Object.setPrototypeOf( + { + requireNativeComponent: jest.fn(() => MockRCTCheckoutWebView), + }, + RN, + ); +}); + +import React from 'react'; +import {render, act} from '@testing-library/react-native'; +import {Checkout} from '../src/components/Checkout'; +import {createTestCart, createTestCheckout} from './testFixtures'; + +describe('Checkout Component - Submit Start Events', () => { + const mockCheckoutUrl = 'https://example.myshopify.com/checkout'; + + it('calls onSubmitStart callback with event data', () => { + const onSubmitStart = jest.fn(); + + const {getByTestId} = render( + , + ); + + const nativeComponent = getByTestId('checkout-webview'); + const testCart = createTestCart(); + const testCheckout = createTestCheckout(); + + act(() => { + nativeComponent.props.onSubmitStart({ + nativeEvent: { + id: 'test-event-123', + type: 'submitStart', + cart: testCart, + checkout: testCheckout, + }, + }); + }); + + expect(onSubmitStart).toHaveBeenCalledTimes(1); + expect(onSubmitStart).toHaveBeenCalledWith({ + id: 'test-event-123', + type: 'submitStart', + cart: testCart, + checkout: testCheckout, + }); + }); + + it('does not crash when onSubmitStart prop is not provided', () => { + const {getByTestId} = render( + , + ); + + const nativeComponent = getByTestId('checkout-webview'); + + expect(() => { + act(() => { + nativeComponent.props.onSubmitStart({ + nativeEvent: { + id: 'test-event', + type: 'submitStart', + cart: createTestCart(), + checkout: createTestCheckout(), + }, + }); + }); + }).not.toThrow(); + }); + + it('does not call callback when nativeEvent is missing', () => { + const onSubmitStart = jest.fn(); + + const {getByTestId} = render( + , + ); + + const nativeComponent = getByTestId('checkout-webview'); + + act(() => { + nativeComponent.props.onSubmitStart({}); + }); + + expect(onSubmitStart).not.toHaveBeenCalled(); + }); +}); diff --git a/modules/@shopify/checkout-sheet-kit/tests/index.test.ts b/modules/@shopify/checkout-sheet-kit/tests/index.test.ts index 9985a77b..3781fa57 100644 --- a/modules/@shopify/checkout-sheet-kit/tests/index.test.ts +++ b/modules/@shopify/checkout-sheet-kit/tests/index.test.ts @@ -422,6 +422,42 @@ describe('ShopifyCheckoutSheetKit', () => { }); }); + describe('Submit Start Event', () => { + it('parses submitStart event data', () => { + const instance = new ShopifyCheckoutSheet(); + const callback = jest.fn(); + instance.addEventListener('submitStart', callback); + + eventEmitter.emit('submitStart', { + id: 'test-event-id', + type: 'submitStart', + cart: {id: 'test-cart-id'}, + checkout: {id: 'checkout-session-123'}, + }); + + expect(callback).toHaveBeenCalledWith({ + id: 'test-event-id', + type: 'submitStart', + cart: {id: 'test-cart-id'}, + checkout: {id: 'checkout-session-123'}, + }); + }); + + it('prints an error if the submitStart event data cannot be parsed', () => { + const mock = jest.spyOn(global.console, 'error'); + const instance = new ShopifyCheckoutSheet(); + const callback = jest.fn(); + instance.addEventListener('submitStart', callback); + + eventEmitter.emit('submitStart', 'INVALID JSON'); + + expect(mock).toHaveBeenCalledWith( + expect.any(LifecycleEventParseError), + 'INVALID JSON', + ); + }); + }); + describe('Error Event', () => { const internalError = { __typename: CheckoutNativeErrorType.InternalError, diff --git a/modules/@shopify/checkout-sheet-kit/tests/testFixtures.ts b/modules/@shopify/checkout-sheet-kit/tests/testFixtures.ts index ea1755de..a2174a72 100644 --- a/modules/@shopify/checkout-sheet-kit/tests/testFixtures.ts +++ b/modules/@shopify/checkout-sheet-kit/tests/testFixtures.ts @@ -21,7 +21,7 @@ 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 type {Cart} from '../src/events.d'; +import type {Cart, CheckoutSession} from '../src/events.d'; /** * Shared test fixtures for creating test objects. @@ -73,3 +73,22 @@ export function createTestCart(overrides?: Partial): Cart { }; } +/** + * Creates a test CheckoutSession instance with sensible defaults. + * + * @param overrides - Optional partial CheckoutSession object to override defaults + * @returns A CheckoutSession instance suitable for testing + * + * @example + * ```typescript + * const checkout = createTestCheckout(); + * const checkoutWithCustomId = createTestCheckout({ id: 'custom-session-id' }); + * ``` + */ +export function createTestCheckout(overrides?: Partial): CheckoutSession { + return { + id: 'checkout-session-123', + ...overrides, + }; +} + diff --git a/sample/src/screens/BuyNow/CheckoutScreen.tsx b/sample/src/screens/BuyNow/CheckoutScreen.tsx index 73832f6b..3e02cd17 100644 --- a/sample/src/screens/BuyNow/CheckoutScreen.tsx +++ b/sample/src/screens/BuyNow/CheckoutScreen.tsx @@ -26,6 +26,8 @@ import { type CheckoutCompleteEvent, type CheckoutRef, type CheckoutStartEvent, + type CheckoutSubmitStart, + useCheckoutEvents, } from '@shopify/checkout-sheet-kit'; import type {BuyNowStackParamList} from './types'; import {StyleSheet} from 'react-native'; @@ -37,9 +39,10 @@ export default function CheckoutScreen(props: { }) { const navigation = useNavigation>(); const ref = useRef(null); + const eventContext = useCheckoutEvents(); - const onCheckoutStart = (event: CheckoutStartEvent) => { - console.log(' onCheckoutStart: ', event); + const onStart = (event: CheckoutStartEvent) => { + console.log(' onStart', event); }; const onAddressChangeStart = (event: CheckoutAddressChangeStart) => { @@ -47,6 +50,21 @@ export default function CheckoutScreen(props: { navigation.navigate('Address', {id: event.id}); }; + const onSubmitStart = async (event: CheckoutSubmitStart) => { + console.log(' onSubmitStart', event); + try { + await eventContext?.respondToEvent(event.id, { + payment: { + token: '1234567890', + tokenType: 'delegated', + tokenProvider: 'shopify', + }, + }); + } catch (error) { + console.error('Failed to respond to submit event:', error); + } + }; + const onCancel = () => { console.log(' onCancel: '); navigation.getParent()?.goBack(); @@ -68,8 +86,9 @@ export default function CheckoutScreen(props: { checkoutUrl={props.route.params.url} auth={props.route.params.auth} style={styles.container} - onStart={onCheckoutStart} + onStart={onStart} onAddressChangeStart={onAddressChangeStart} + onSubmitStart={onSubmitStart} onCancel={onCancel} onError={onError} onComplete={onComplete}