Skip to content

Commit ff0b2a8

Browse files
authored
Add support for international pricing in sample app (#49)
1 parent 1a93341 commit ff0b2a8

File tree

6 files changed

+98
-25
lines changed

6 files changed

+98
-25
lines changed

sample/@types/index.d.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,20 @@ export interface CartItem {
4545
};
4646
}
4747

48+
export interface CartLineItem {
49+
id: string;
50+
merchandise: CartItem;
51+
quantity: number;
52+
cost: {
53+
totalAmount: {
54+
currencyCode: string;
55+
amount: string;
56+
};
57+
};
58+
}
59+
4860
export interface ShopifyCart {
4961
cost: CartCost;
50-
lines: Edges<{
51-
id: string;
52-
merchandise: CartItem;
53-
quantity: number;
54-
}>;
62+
lines: Edges<CartLineItem>;
5563
totalQuantity: number;
5664
}

sample/src/hooks/useShopify.ts

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SO
2323

2424
import {gql, useLazyQuery, useMutation} from '@apollo/client';
2525
import type {Edges, ShopifyProduct, ShopifyCart} from '../../@types';
26+
import {getLocale} from '../utils';
2627

2728
const moneyFragment = gql`
2829
fragment Price on MoneyV2 {
@@ -66,7 +67,8 @@ const cartCostFragment = gql`
6667
`;
6768

6869
const PRODUCTS_QUERY = gql`
69-
query FetchProducts {
70+
query FetchProducts($country: CountryCode = CA)
71+
@inContext(country: $country) {
7072
products(first: 10) {
7173
edges {
7274
node {
@@ -77,6 +79,9 @@ const PRODUCTS_QUERY = gql`
7779
edges {
7880
node {
7981
id
82+
unitPrice {
83+
...Price
84+
}
8085
price {
8186
...Price
8287
}
@@ -102,7 +107,8 @@ const PRODUCTS_QUERY = gql`
102107
`;
103108

104109
const CART_QUERY = gql`
105-
query FetchCart($cartId: ID!) {
110+
query FetchCart($cartId: ID!, $country: CountryCode = CA)
111+
@inContext(country: $country) {
106112
cart(id: $cartId) {
107113
id
108114
totalQuantity
@@ -134,7 +140,8 @@ const CART_QUERY = gql`
134140
`;
135141

136142
const CREATE_CART_MUTATION = gql`
137-
mutation CreateCart($input: CartInput) {
143+
mutation CreateCart($input: CartInput, $country: CountryCode = CA)
144+
@inContext(country: $country) {
138145
cartCreate(input: $input) {
139146
cart {
140147
id
@@ -145,7 +152,11 @@ const CREATE_CART_MUTATION = gql`
145152
`;
146153

147154
const ADD_TO_CART_MUTATION = gql`
148-
mutation AddToCart($cartId: ID!, $lines: [CartLineInput!]!) {
155+
mutation AddToCart(
156+
$cartId: ID!
157+
$lines: [CartLineInput!]!
158+
$country: CountryCode = CA
159+
) @inContext(country: $country) {
149160
cartLinesAdd(cartId: $cartId, lines: $lines) {
150161
cart {
151162
id
@@ -157,7 +168,11 @@ const ADD_TO_CART_MUTATION = gql`
157168
`;
158169

159170
const REMOVE_FROM_CART_MUTATION = gql`
160-
mutation RemoveFromCart($cartId: ID!, $lineIds: [ID!]!) {
171+
mutation RemoveFromCart(
172+
$cartId: ID!
173+
$lineIds: [ID!]!
174+
$country: CountryCode = CA
175+
) @inContext(country: $country) {
161176
cartLinesRemove(cartId: $cartId, lineIds: $lineIds) {
162177
cart {
163178
id
@@ -169,15 +184,26 @@ const REMOVE_FROM_CART_MUTATION = gql`
169184
`;
170185

171186
function useShopify() {
187+
const [, country] = getLocale().split('_');
188+
const includeCountry = {
189+
variables: {
190+
country,
191+
},
192+
};
172193
const products = useLazyQuery<{products: Edges<ShopifyProduct>}>(
173194
PRODUCTS_QUERY,
195+
includeCountry,
174196
);
175197
const cart = useLazyQuery<{cart: ShopifyCart}>(CART_QUERY, {
176198
fetchPolicy: 'network-only',
199+
...includeCountry,
177200
});
178-
const cartCreate = useMutation(CREATE_CART_MUTATION);
179-
const cartLinesAdd = useMutation(ADD_TO_CART_MUTATION);
180-
const cartLinesRemove = useMutation(REMOVE_FROM_CART_MUTATION);
201+
const cartCreate = useMutation(CREATE_CART_MUTATION, includeCountry);
202+
const cartLinesAdd = useMutation(ADD_TO_CART_MUTATION, includeCountry);
203+
const cartLinesRemove = useMutation(
204+
REMOVE_FROM_CART_MUTATION,
205+
includeCountry,
206+
);
181207

182208
return {
183209
queries: {

sample/src/screens/CartScreen.tsx

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,10 @@ import Icon from 'react-native-vector-icons/Entypo';
3838
import {useShopifyCheckoutSheet} from '@shopify/checkout-sheet-kit';
3939
import useShopify from '../hooks/useShopify';
4040

41-
import type {CartItem} from '../../@types';
41+
import type {CartItem, CartLineItem} from '../../@types';
4242
import {Colors, useTheme} from '../context/Theme';
4343
import {useCart} from '../context/Cart';
44+
import {currency} from '../utils';
4445

4546
function CartScreen(): JSX.Element {
4647
const ShopifyCheckout = useShopifyCheckoutSheet();
@@ -122,7 +123,7 @@ function CartScreen(): JSX.Element {
122123
{data?.cart.lines.edges.map(({node}) => (
123124
<CartItem
124125
key={node.merchandise.id}
125-
item={node.merchandise}
126+
item={node}
126127
quantity={node.quantity}
127128
loading={addingToCart.has(node.id)}
128129
onRemove={() => removeFromCart(node.id)}
@@ -175,8 +176,8 @@ function price(value: {amount: string; currencyCode: string}) {
175176
return '-';
176177
}
177178

178-
const {amount} = value;
179-
return ${Number(amount).toFixed(2)}`;
179+
const {amount, currencyCode} = value;
180+
return currency(amount, currencyCode);
180181
}
181182

182183
function CartItem({
@@ -185,7 +186,7 @@ function CartItem({
185186
onRemove,
186187
loading,
187188
}: {
188-
item: CartItem;
189+
item: CartLineItem;
189190
quantity: number;
190191
loading?: boolean;
191192
onRemove: () => void;
@@ -204,16 +205,20 @@ function CartItem({
204205
resizeMethod="resize"
205206
resizeMode="cover"
206207
style={styles.productImage}
207-
alt={item.image?.altText}
208-
source={{uri: item.image?.url}}
208+
alt={item.merchandise.image?.altText}
209+
source={{uri: item.merchandise.image?.url}}
209210
/>
210211
<View style={styles.productText}>
211212
<View style={styles.productTextContainer}>
212-
<Text style={styles.productTitle}>{item.product.title}</Text>
213+
<Text style={styles.productTitle}>
214+
{item.merchandise.product.title}
215+
</Text>
213216
<Text style={styles.productDescription}>Quantity: {quantity}</Text>
214217
</View>
215218
<View>
216-
<Text style={styles.productPrice}>{price(item?.price)}</Text>
219+
<Text style={styles.productPrice}>
220+
{price(item.cost?.totalAmount)}
221+
</Text>
217222
<Pressable style={styles.removeButton} onPress={onRemove}>
218223
{loading ? (
219224
<ActivityIndicator size="small" />

sample/src/screens/CatalogScreen.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import {Colors, useTheme} from '../context/Theme';
4141
import {useCart} from '../context/Cart';
4242
import {NativeStackScreenProps} from '@react-navigation/native-stack';
4343
import {RootStackParamList} from '../App';
44+
import {currency} from '../utils';
4445

4546
type Props = NativeStackScreenProps<RootStackParamList, 'CatalogScreen'>;
4647

@@ -153,8 +154,7 @@ function Product({
153154
<View>
154155
<Text style={styles.productTitle}>{product.title}</Text>
155156
<Text style={styles.productPrice}>
156-
£{Number(variant?.price.amount).toFixed(2)}{' '}
157-
{variant?.price.currencyCode}
157+
{currency(variant?.price.amount, variant?.price.currencyCode)}
158158
</Text>
159159
</View>
160160
<View style={styles.addToCartButtonContainer}>

sample/src/screens/ProductDetailsScreen.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {Colors, useTheme} from '../context/Theme';
3838
import {useCart} from '../context/Cart';
3939
import {NativeStackScreenProps} from '@react-navigation/native-stack';
4040
import {RootStackParamList} from '../App';
41+
import {currency} from '../utils';
4142

4243
type Props = NativeStackScreenProps<RootStackParamList, 'ProductDetails'>;
4344

@@ -110,7 +111,8 @@ function ProductDetails({
110111
<ActivityIndicator size="small" color="white" />
111112
) : (
112113
<Text style={styles.addToCartButtonText}>
113-
Add to cart &bull; £{Number(variant?.price.amount).toFixed(2)}
114+
Add to cart &bull;{' '}
115+
{currency(variant?.price.amount, variant?.price.currencyCode)}
114116
</Text>
115117
)}
116118
</Pressable>

sample/src/utils.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
ZIP,
1212
PHONE,
1313
} from '@env';
14+
import {NativeModules, Platform} from 'react-native';
1415
import {AppConfig} from './context/Config';
1516

1617
export function createBuyerIdentityCartInput(appConfig: AppConfig) {
@@ -38,3 +39,34 @@ export function createBuyerIdentityCartInput(appConfig: AppConfig) {
3839
},
3940
};
4041
}
42+
43+
export function getLocale(): string {
44+
const fallbackLocale = 'en_CA';
45+
46+
return (
47+
(Platform.OS === 'ios'
48+
? NativeModules.SettingsManager?.settings.AppleLocale ||
49+
NativeModules.SettingsManager?.settings.AppleLanguages[0]
50+
: NativeModules.I18nManager?.localeIdentifier) ?? fallbackLocale
51+
);
52+
}
53+
54+
export function currency(amount?: string, currency?: string): string {
55+
if (typeof amount === 'undefined' && typeof currency === 'undefined') {
56+
return '';
57+
}
58+
59+
const currencyCode = currency ? ` ${currency}` : '';
60+
61+
try {
62+
const locale = getLocale();
63+
return (
64+
new Intl.NumberFormat(locale.replace(/_/, '-'), {
65+
style: 'currency',
66+
currency: currency,
67+
}).format(Number(amount ?? 0)) + currencyCode
68+
);
69+
} catch (error) {
70+
return `${Number(amount ?? 0).toFixed(2)}` + currencyCode;
71+
}
72+
}

0 commit comments

Comments
 (0)