Skip to content

Commit ff22788

Browse files
authored
[Sample] Add Product Details Screen (#36)
1 parent 47133e2 commit ff22788

File tree

10 files changed

+284
-14
lines changed

10 files changed

+284
-14
lines changed

sample/@types/index.d.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,21 @@ interface CartCost {
1313
totalTaxAmount: Price;
1414
}
1515

16+
export interface ProductVariant {
17+
id: string;
18+
price: Price;
19+
}
20+
1621
export interface ShopifyProduct {
1722
id: string;
1823
title: string;
24+
description: string;
1925
images: Edges<{
2026
id: string;
2127
altText: string;
2228
url: string;
2329
}>;
24-
variants: Edges<{
25-
id: string;
26-
price: Price;
27-
}>;
30+
variants: Edges<ProductVariant>;
2831
}
2932

3033
export interface CartItem {

sample/ios/Podfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,6 @@ SPEC CHECKSUMS:
682682
SwiftLint: c1de071d9d08c8aba837545f6254315bc900e211
683683
Yoga: b76f1acfda8212aa16b7e26bcce3983230c82603
684684

685-
PODFILE CHECKSUM: 4ffd968bdaf7e2f60158b7f23d95cb764cee0100
685+
PODFILE CHECKSUM: 2c889c450154705b85659f65cb37a00caf7dfcb8
686686

687687
COCOAPODS: 1.14.3

sample/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"@react-native-community/masked-view": "^0.1.11",
2121
"@react-navigation/bottom-tabs": "^6.5.11",
2222
"@react-navigation/native": "^6.1.9",
23+
"@react-navigation/native-stack": "^6.9.17",
2324
"graphql": "^16.8.1",
2425
"react-native": "0.72.6",
2526
"react-native-dotenv": "^3.4.9",

sample/src/App.tsx

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SO
2424
import React, {PropsWithChildren, ReactNode} from 'react';
2525
import {NavigationContainer} from '@react-navigation/native';
2626
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
27+
import {createNativeStackNavigator} from '@react-navigation/native-stack';
2728
import {ApolloClient, InMemoryCache, ApolloProvider} from '@apollo/client';
2829
import {STOREFRONT_DOMAIN, STOREFRONT_ACCESS_TOKEN} from '@env';
2930
import Icon from 'react-native-vector-icons/Entypo';
@@ -41,6 +42,8 @@ import {ThemeProvider, getNavigationTheme, useTheme} from './context/Theme';
4142
import {Appearance, StatusBar} from 'react-native';
4243
import {CartProvider, useCart} from './context/Cart';
4344
import CartScreen from './screens/CartScreen';
45+
import ProductDetailsScreen from './screens/ProductDetailsScreen';
46+
import {ProductVariant, ShopifyProduct} from '../@types';
4447

4548
const colorScheme = ColorScheme.web;
4649

@@ -63,7 +66,16 @@ const config: Configuration = {
6366

6467
Appearance.setColorScheme('light');
6568

66-
const Tab = createBottomTabNavigator();
69+
export type RootStackParamList = {
70+
Catalog: undefined;
71+
CatalogScreen: undefined;
72+
ProductDetails: {product: ShopifyProduct; variant?: ProductVariant};
73+
Cart: {userId: string};
74+
Settings: undefined;
75+
};
76+
77+
const Tab = createBottomTabNavigator<RootStackParamList>();
78+
const Stack = createNativeStackNavigator<RootStackParamList>();
6779

6880
const client = new ApolloClient({
6981
uri: `https://${STOREFRONT_DOMAIN}/api/2023-10/graphql.json`,
@@ -104,6 +116,31 @@ function AppWithContext({children}: PropsWithChildren) {
104116
);
105117
}
106118

119+
function CatalogStack() {
120+
return (
121+
<Stack.Navigator
122+
screenOptions={{
123+
headerBackTitleVisible: true,
124+
}}>
125+
<Stack.Screen
126+
name="CatalogScreen"
127+
component={CatalogScreen}
128+
options={{headerShown: true, headerTitle: 'Catalog'}}
129+
/>
130+
<Stack.Screen
131+
name="ProductDetails"
132+
component={ProductDetailsScreen}
133+
options={({route}) => ({
134+
headerTitle: route.params.product.title,
135+
headerShown: true,
136+
headerBackVisible: true,
137+
headerBackTitle: 'Back',
138+
})}
139+
/>
140+
</Stack.Navigator>
141+
);
142+
}
143+
107144
function AppWithNavigation() {
108145
const {colorScheme, preference} = useTheme();
109146
const {totalQuantity} = useCart();
@@ -113,8 +150,9 @@ function AppWithNavigation() {
113150
<Tab.Navigator>
114151
<Tab.Screen
115152
name="Catalog"
116-
component={CatalogScreen}
153+
component={CatalogStack}
117154
options={{
155+
headerShown: false,
118156
tabBarIcon: createNavigationIcon('shop'),
119157
}}
120158
/>

sample/src/context/Cart.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,6 @@ export const CartProvider: React.FC<PropsWithChildren> = ({children}) => {
165165
},
166166
});
167167

168-
dispatch({type: 'remove', variantId});
169-
170168
setCheckoutURL(data.cartLinesRemove.cart.checkoutUrl);
171169
setTotalQuantity(data.cartLinesRemove.cart.totalQuantity);
172170

@@ -175,12 +173,14 @@ export const CartProvider: React.FC<PropsWithChildren> = ({children}) => {
175173
}
176174

177175
if (cartId) {
178-
fetchCart({
176+
await fetchCart({
179177
variables: {
180178
cartId,
181179
},
182180
});
183181
}
182+
183+
dispatch({type: 'remove', variantId});
184184
},
185185
[
186186
cartId,

sample/src/hooks/useShopify.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ const PRODUCTS_QUERY = gql`
7272
node {
7373
id
7474
title
75+
description
7576
variants(first: 1) {
7677
edges {
7778
node {

sample/src/screens/CartScreen.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ function createStyles(colors: Colors) {
335335
paddingBottom: 65,
336336
paddingHorizontal: 2,
337337
borderTopWidth: 1,
338-
borderTopColor: '#e2e2e2',
338+
borderTopColor: colors.border,
339339
},
340340
costBlock: {
341341
display: 'flex',

sample/src/screens/CatalogScreen.tsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,12 @@ import useShopify from '../hooks/useShopify';
3939
import type {ShopifyProduct} from '../../@types';
4040
import {Colors, useTheme} from '../context/Theme';
4141
import {useCart} from '../context/Cart';
42+
import {NativeStackScreenProps} from '@react-navigation/native-stack';
43+
import {RootStackParamList} from '../App';
4244

43-
function CatalogScreen(): JSX.Element {
45+
type Props = NativeStackScreenProps<RootStackParamList, 'CatalogScreen'>;
46+
47+
function CatalogScreen({navigation}: Props) {
4448
const ShopifyCheckoutKit = useShopifyCheckoutKit();
4549
const {checkoutURL, totalQuantity, addToCart, addingToCart} = useCart();
4650
const {colors} = useTheme();
@@ -89,6 +93,12 @@ function CatalogScreen(): JSX.Element {
8993
<Product
9094
key={node.id}
9195
product={node}
96+
onPress={() => {
97+
navigation.navigate('ProductDetails', {
98+
product: node,
99+
variant: getVariant(node),
100+
});
101+
}}
92102
loading={addingToCart.has(getVariant(node)?.id ?? '')}
93103
onAddToCart={addToCart}
94104
/>
@@ -118,9 +128,11 @@ function Product({
118128
product,
119129
onAddToCart,
120130
loading = false,
131+
onPress,
121132
}: {
122133
product: ShopifyProduct;
123134
loading?: boolean;
135+
onPress: () => void;
124136
onAddToCart: (variantId: string) => void;
125137
}) {
126138
const {colors} = useTheme();
@@ -129,7 +141,7 @@ function Product({
129141
const variant = getVariant(product);
130142

131143
return (
132-
<View key={product.id} style={styles.productItem}>
144+
<Pressable key={product.id} style={styles.productItem} onPress={onPress}>
133145
<Image
134146
resizeMethod="resize"
135147
resizeMode="cover"
@@ -159,7 +171,7 @@ function Product({
159171
)}
160172
</View>
161173
</View>
162-
</View>
174+
</Pressable>
163175
);
164176
}
165177

0 commit comments

Comments
 (0)