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
67 changes: 56 additions & 11 deletions dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,29 @@ up:
- custom:
name: Install NPM dependencies
met?: ls -l | grep node_modules
meet: |
yarn
meet: yarn
- custom:
name: Sample .env file exists
met?: test -f sample/.env
meet: cp ./sample/.env.example ./sample/.env
- custom:
name: Generate iOS xcconfig from env
met?:
test -f sample/ios/JSEnvironment.xcconfig && test sample/.env -ot
sample/ios/JSEnvironment.xcconfig
meet: |
yarn env-to-xcconfig
meet: yarn env-to-xcconfig
- custom:
name: Install gems
met?: (cd sample/ios && bundle check)
meet: |
(cd sample/ios && bundle install)
meet: (cd sample/ios && bundle install)
- custom:
name: Install pods
met?: (cd sample/ios && bundle exec pod check --ignore-dev-pods)
meet: |
yarn pod-install
meet: yarn pod-install
- custom:
name: Build node module
met?: (cd modules/@shopify/checkout-sheet-kit && ls -l | grep lib)
meet: |
yarn module build
meet: yarn module build

check:
lint_swift: ./scripts/lint_swift
Expand All @@ -56,14 +55,58 @@ commands:
run: |
yarn module build
yarn build:android
subcommands:
ios:
desc: Build iOS sample app
run: yarn sample build:ios
android:
desc: Build Android sample app
run: yarn sample build:android

test:
desc: Run all tests (Jest, iOS, Android)
run: |
yarn test
yarn sample test:ios
yarn sample test:android
subcommands:
ios:
desc: Run iOS integration tests
run: yarn sample test:ios
android:
desc: Run Android integration tests
run: yarn sample test:android

style:
desc: Run linting across module, sample, and Swift code
aliases: [lint]
run: |
yarn module lint
yarn sample lint
./scripts/lint_swift

server:
desc: 'Start development server'
run: yarn sample start --reset-cache

ios:
desc: 'Run iOS simulator'
run: yarn sample ios
run: |
if [[ ! -f sample/.env ]]; then
echo ""
echo "╔════════════════════════════════════════════════════════════════╗"
echo "║ ❌ ERROR: Missing .env configuration file ║"
echo "╠════════════════════════════════════════════════════════════════╣"
echo "║ ║"
echo "║ To fix, run: ║"
echo "║ cp sample/.env.example sample/.env ║"
echo "║ ║"
echo "║ Then update with your storefront credentials. ║"
echo "╚════════════════════════════════════════════════════════════════╝"
echo ""
exit 1
fi
yarn sample ios

android:
desc: 'Run Android emulator'
Expand All @@ -83,4 +126,6 @@ commands:
fix:
desc: Fix linting
run: |
yarn module format
yarn sample format
./scripts/lint_swift fix
3 changes: 2 additions & 1 deletion modules/@shopify/checkout-sheet-kit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"scripts": {
"clean": "rm -rf lib",
"build": "bob build",
"lint": "yarn typecheck && eslint src",
"lint": "yarn typecheck && eslint src && prettier src --check",
"format": "eslint src --fix && prettier src --write",
"typecheck": "tsc --noEmit"
},
"files": [
Expand Down
30 changes: 18 additions & 12 deletions modules/@shopify/checkout-sheet-kit/src/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ export function ShopifyCheckoutSheetProvider({
}

await instance.current?.setConfig(configuration);
const isAvailable = await instance.current.isAcceleratedCheckoutAvailable();
const isAvailable =
await instance.current.isAcceleratedCheckoutAvailable();
setAcceleratedCheckoutsAvailable(isAvailable);
}

Expand All @@ -96,18 +97,23 @@ export function ShopifyCheckoutSheetProvider({
instance.current?.removeEventListeners(eventName);
}, []);

const present = useCallback((checkoutUrl: string, options?: CheckoutOptions) => {
if (checkoutUrl) {
instance.current?.present(checkoutUrl, options
);
}
}, []);
const present = useCallback(
(checkoutUrl: string, options?: CheckoutOptions) => {
if (checkoutUrl) {
instance.current?.present(checkoutUrl, options);
}
},
[],
);

const preload = useCallback((checkoutUrl: string, options?: CheckoutOptions) => {
if (checkoutUrl) {
instance.current?.preload(checkoutUrl, options);
}
}, []);
const preload = useCallback(
(checkoutUrl: string, options?: CheckoutOptions) => {
if (checkoutUrl) {
instance.current?.preload(checkoutUrl, options);
}
},
[],
);

const invalidate = useCallback(() => {
instance.current?.invalidate();
Expand Down
4 changes: 3 additions & 1 deletion modules/@shopify/checkout-sheet-kit/src/errors.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,9 @@ function getCheckoutErrorCode(code: string | undefined): CheckoutErrorCode {
const normalizedCode = code.toUpperCase();

const codeKey = Object.keys(CheckoutErrorCode).find(
key => CheckoutErrorCode[key as keyof typeof CheckoutErrorCode] === normalizedCode,
key =>
CheckoutErrorCode[key as keyof typeof CheckoutErrorCode] ===
normalizedCode,
);

return codeKey
Expand Down
4 changes: 2 additions & 2 deletions modules/@shopify/checkout-sheet-kit/src/events.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -430,8 +430,8 @@ export interface CheckoutStartEvent {
method: 'checkout.start';
/** Initial cart state when checkout started */
cart: Cart;
/**
* Locale of the checkout
/**
* Locale of the checkout
**/
locale: string;
}
Expand Down
10 changes: 6 additions & 4 deletions modules/@shopify/checkout-sheet-kit/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ 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, CheckoutSubmitStartEvent} from './events';
import type {
CheckoutCompleteEvent,
CheckoutStartEvent,
CheckoutSubmitStartEvent,
} from './events';
import type {CheckoutException} from './errors';

export type Maybe<T> = T | undefined;
Expand Down Expand Up @@ -168,9 +172,7 @@ export type CheckoutExceptionCallback = (error: CheckoutException) => void;
export type CheckoutCompleteEventCallback = (
event: CheckoutCompleteEvent,
) => void;
export type CheckoutStartEventCallback = (
event: CheckoutStartEvent,
) => void;
export type CheckoutStartEventCallback = (event: CheckoutStartEvent) => void;
export type CheckoutAddressChangeStartCallback = (
event: CheckoutAddressChangeStartEvent,
) => void;
Expand Down
4 changes: 4 additions & 0 deletions sample/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ios/Pods/
vendor/
node_modules/
android/build/
2 changes: 1 addition & 1 deletion sample/ios/ReactNative.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\nif [[ -z $DISPLAY_NAME ]]; then\n echo \"DISPLAY_NAME is nil\" \n exit 1\nfi\n\n";
shellScript = "if [[ -z $DISPLAY_NAME ]]; then\n echo \"error: DISPLAY_NAME is nil - .env file may be missing or invalid\"\n echo \"Run: cp sample/.env.example sample/.env\"\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
E5E915CDFAA811FAB9901380 /* [CP] Embed Pods Frameworks */ = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"images" : [
"images": [
{
"filename" : "1024.jpg",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
"filename": "1024.jpg",
"idiom": "universal",
"platform": "ios",
"size": "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
"info": {
"author": "xcode",
"version": 1
}
}
6 changes: 3 additions & 3 deletions sample/ios/ReactNative/Images.xcassets/Contents.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
"info": {
"version": 1,
"author": "xcode"
}
}
3 changes: 2 additions & 1 deletion sample/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"build:android": "sh ./scripts/build_android",
"release:android": "sh ./scripts/release_android",
"build:ios": "sh ./scripts/build_ios",
"lint": "yarn typecheck && eslint .",
"lint": "yarn typecheck && eslint . && prettier . --check",
"format": "eslint . --fix && prettier . --write",
"ios": "react-native run-ios --simulator 'iPhone 15 Pro'",
"start": "react-native start -- --simulator 'iPhone 15 Pro' --reset-cache",
"typecheck": "tsc --noEmit",
Expand Down
24 changes: 19 additions & 5 deletions sample/src/context/Cart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,12 @@ type AddingToCartAction =
const checkoutURLState = atom<Context['checkoutURL']>(defaultCheckoutURL);
const cartIdState = atom<Context['cartId']>(defaultCartId);
const totalQuantityState = atom<Context['totalQuantity']>(defaultTotalQuantity);
const selectedAddressIndexState = atom<Context['selectedAddressIndex']>(defaultSelectedAddressIndex);
const selectedPaymentIndexState = atom<Context['selectedPaymentIndex']>(defaultSelectedPaymentIndex);
const selectedAddressIndexState = atom<Context['selectedAddressIndex']>(
defaultSelectedAddressIndex,
);
const selectedPaymentIndexState = atom<Context['selectedPaymentIndex']>(
defaultSelectedPaymentIndex,
);

export const CartProvider: React.FC<PropsWithChildren> = ({children}) => {
const shopify = useShopifyCheckoutSheet();
Expand All @@ -65,9 +69,13 @@ export const CartProvider: React.FC<PropsWithChildren> = ({children}) => {
// Keep track of the number of items in the cart
const [totalQuantity, setTotalQuantity] = useAtom(totalQuantityState);
// Keep track of the selected address index
const [selectedAddressIndex, setSelectedAddressIndex] = useAtom(selectedAddressIndexState);
const [selectedAddressIndex, setSelectedAddressIndex] = useAtom(
selectedAddressIndexState,
);
// Keep track of the selected payment index
const [selectedPaymentIndex, setSelectedPaymentIndex] = useAtom(selectedPaymentIndexState);
const [selectedPaymentIndex, setSelectedPaymentIndex] = useAtom(
selectedPaymentIndexState,
);
// Maintain a loading state for items being added to the cart
const addingToCartReducer = (
state: Set<string>,
Expand Down Expand Up @@ -99,7 +107,13 @@ export const CartProvider: React.FC<PropsWithChildren> = ({children}) => {
setTotalQuantity(0);
setSelectedAddressIndex(defaultSelectedAddressIndex);
setSelectedPaymentIndex(defaultSelectedPaymentIndex);
}, [setCartId, setCheckoutURL, setTotalQuantity, setSelectedAddressIndex, setSelectedPaymentIndex]);
}, [
setCartId,
setCheckoutURL,
setTotalQuantity,
setSelectedAddressIndex,
setSelectedPaymentIndex,
]);

useEffect(() => {
const subscription = shopify.addEventListener('complete', () => {
Expand Down
5 changes: 3 additions & 2 deletions sample/src/context/Config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ const ConfigContext = createContext<Context>({
export const ConfigProvider: React.FC<
PropsWithChildren<{config?: AppConfig}>
> = ({children, config}) => {
const [appConfig, setInternalAppConfig] =
useState<AppConfig>(config ?? defaultAppConfig);
const [appConfig, setInternalAppConfig] = useState<AppConfig>(
config ?? defaultAppConfig,
);
const {setColorScheme} = useTheme();

// Update theme when appConfig changes (not just initial config prop)
Expand Down
17 changes: 11 additions & 6 deletions sample/src/screens/BuyNow/AddressScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,14 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SO
import type {RouteProp} from '@react-navigation/native';
import {useNavigation, useRoute} from '@react-navigation/native';
import React, {useState} from 'react';
import {Alert, Button, StyleSheet, Text, TouchableOpacity, View} from 'react-native';
import {
Alert,
Button,
StyleSheet,
Text,
TouchableOpacity,
View,
} from 'react-native';
import {useShopifyEvent} from '@shopify/checkout-sheet-kit';
import type {CheckoutAddressChangeStartResponsePayload} from '@shopify/checkout-sheet-kit';
import {useCart} from '../../context/Cart';
Expand Down Expand Up @@ -110,11 +117,9 @@ export default function AddressScreen() {
const errorMessage =
error instanceof Error ? error.message : 'Failed to update address';

Alert.alert(
'Address Update Failed',
errorMessage,
[{text: 'OK', onPress: () => setIsSubmitting(false)}],
);
Alert.alert('Address Update Failed', errorMessage, [
{text: 'OK', onPress: () => setIsSubmitting(false)},
]);
}
};

Expand Down
7 changes: 5 additions & 2 deletions sample/src/screens/BuyNow/PaymentScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,17 @@ export default function PaymentScreen() {
</View>
<View style={styles.paymentInfo}>
<View style={styles.cardHeader}>
<Text style={styles.cardIcon}>{getCardIcon(option.instrument.brand)}</Text>
<Text style={styles.cardIcon}>
{getCardIcon(option.instrument.brand)}
</Text>
<Text style={styles.paymentLabel}>{option.label}</Text>
</View>
<Text style={styles.cardDetails}>
{option.instrument.brand} •••• {option.instrument.lastDigits}
</Text>
<Text style={styles.billingInfo}>
{option.instrument.billingAddress?.city}, {option.instrument.billingAddress?.provinceCode}
{option.instrument.billingAddress?.city},{' '}
{option.instrument.billingAddress?.provinceCode}
</Text>
</View>
</TouchableOpacity>
Expand Down
5 changes: 4 additions & 1 deletion sample/src/screens/BuyNow/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ export default function BuyNowStack(props: BuyNowStackProps) {
<BuyNowStackNavigator.Screen
name="Checkout"
component={CheckoutScreen} // This component renders the @shopify CheckoutWebView component
initialParams={{url: props.route.params.url, auth: props.route.params.auth}}
initialParams={{
url: props.route.params.url,
auth: props.route.params.auth,
}}
options={{title: 'Shopify Checkout'}}
/>
<BuyNowStackNavigator.Screen
Expand Down
2 changes: 1 addition & 1 deletion sample/src/screens/BuyNow/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type {Cart} from '@shopify/checkout-sheet-kit';

export type BuyNowStackParamList = {
Checkout: {url: string, auth?: string};
Checkout: {url: string; auth?: string};
Address: {id: string; cart: Cart};
Payment: {id: string; cart: Cart};
};
Loading
Loading