diff --git a/package-lock.json b/package-lock.json
index cbc977b..8c3d90e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,6 +12,7 @@
"@react-native-async-storage/async-storage": "^1.19.5",
"@react-native-community/masked-view": "^0.1.11",
"@react-native-community/netinfo": "^9.4.1",
+ "@react-navigation/drawer": "^6.6.6",
"@react-navigation/native": "^6.1.9",
"@react-navigation/native-stack": "^6.9.16",
"@reduxjs/toolkit": "^1.9.7",
@@ -19,6 +20,7 @@
"axios": "^1.6.0",
"react": "18.2.0",
"react-native": "0.72.6",
+ "react-native-elements": "^3.4.3",
"react-native-gesture-handler": "^2.9.0",
"react-native-modal": "^13.0.1",
"react-native-reanimated": "^3.5.4",
@@ -27,7 +29,7 @@
"react-native-simple-toast": "^3.0.2",
"react-native-svg": "^13.14.0",
"react-native-svg-transformer": "^1.1.0",
- "react-native-vector-icons": "^10.0.1",
+ "react-native-vector-icons": "^10.0.2",
"react-query": "^3.39.3",
"react-redux": "^8.1.3",
"redux": "^4.2.1",
@@ -41,6 +43,7 @@
"@react-native/metro-config": "^0.72.11",
"@tsconfig/react-native": "^3.0.0",
"@types/react": "^18.0.24",
+ "@types/react-native-vector-icons": "^6.4.18",
"@types/react-redux": "^7.1.28",
"@types/react-test-renderer": "^18.0.0",
"babel-jest": "^29.2.1",
@@ -4216,6 +4219,25 @@
"react": "*"
}
},
+ "node_modules/@react-navigation/drawer": {
+ "version": "6.6.6",
+ "resolved": "https://registry.npmjs.org/@react-navigation/drawer/-/drawer-6.6.6.tgz",
+ "integrity": "sha512-DW/oNRisSOGOqvZfCzfhKBxnzT97Teqtg1Gal85g+K3gnVbM1jOBE2PdnYsKU0fULfFtDwvp/QZSbcgjDpr12A==",
+ "dependencies": {
+ "@react-navigation/elements": "^1.3.21",
+ "color": "^4.2.3",
+ "warn-once": "^0.1.0"
+ },
+ "peerDependencies": {
+ "@react-navigation/native": "^6.0.0",
+ "react": "*",
+ "react-native": "*",
+ "react-native-gesture-handler": ">= 1.0.0",
+ "react-native-reanimated": ">= 1.0.0",
+ "react-native-safe-area-context": ">= 3.0.0",
+ "react-native-screens": ">= 3.0.0"
+ }
+ },
"node_modules/@react-navigation/elements": {
"version": "1.3.21",
"resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.21.tgz",
@@ -4838,6 +4860,23 @@
"csstype": "^3.0.2"
}
},
+ "node_modules/@types/react-native": {
+ "version": "0.70.18",
+ "resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.70.18.tgz",
+ "integrity": "sha512-M06e2opOY8PyLVfVSWd70X2yrIDZrgiOw677HsOrI/fT27aqvKGuFE44tDUBLEvQ8XEPC+T5pW2h5Az6gX7hdA==",
+ "dependencies": {
+ "@types/react": "*"
+ }
+ },
+ "node_modules/@types/react-native-vector-icons": {
+ "version": "6.4.18",
+ "resolved": "https://registry.npmjs.org/@types/react-native-vector-icons/-/react-native-vector-icons-6.4.18.tgz",
+ "integrity": "sha512-YGlNWb+k5laTBHd7+uZowB9DpIK3SXUneZqAiKQaj1jnJCZM0x71GDim5JCTMi4IFkhc9m8H/Gm28T5BjyivUw==",
+ "dependencies": {
+ "@types/react": "*",
+ "@types/react-native": "^0.70"
+ }
+ },
"node_modules/@types/react-redux": {
"version": "7.1.30",
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.30.tgz",
@@ -6186,6 +6225,18 @@
"integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==",
"dev": true
},
+ "node_modules/color": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
+ "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
+ "dependencies": {
+ "color-convert": "^2.0.1",
+ "color-string": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=12.5.0"
+ }
+ },
"node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -6199,6 +6250,31 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
},
+ "node_modules/color-string": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+ "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+ "dependencies": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
+ }
+ },
+ "node_modules/color/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+ },
"node_modules/colorette": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz",
@@ -11065,6 +11141,11 @@
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
},
+ "node_modules/lodash.isequal": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+ "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
+ },
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -12466,6 +12547,14 @@
"node": ">=8"
}
},
+ "node_modules/opencollective-postinstall": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
+ "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==",
+ "bin": {
+ "opencollective-postinstall": "index.js"
+ }
+ },
"node_modules/optionator": {
"version": "0.9.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
@@ -13090,6 +13179,35 @@
"prop-types": "^15.7.2"
}
},
+ "node_modules/react-native-elements": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/react-native-elements/-/react-native-elements-3.4.3.tgz",
+ "integrity": "sha512-VtZc25EecPZyUBER85zFK9ZbY6kkUdcm1ZwJ9hdoGSCr1R/GFgxor4jngOcSYeMvQ+qimd5No44OVJW3rSJECA==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@types/react-native-vector-icons": "^6.4.6",
+ "color": "^3.1.2",
+ "deepmerge": "^4.2.2",
+ "hoist-non-react-statics": "^3.3.2",
+ "lodash.isequal": "^4.5.0",
+ "opencollective-postinstall": "^2.0.3",
+ "react-native-ratings": "8.0.4",
+ "react-native-size-matters": "^0.3.1"
+ },
+ "peerDependencies": {
+ "react-native-safe-area-context": ">= 3.0.0",
+ "react-native-vector-icons": ">7.0.0"
+ }
+ },
+ "node_modules/react-native-elements/node_modules/color": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
+ "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
+ "dependencies": {
+ "color-convert": "^1.9.3",
+ "color-string": "^1.6.0"
+ }
+ },
"node_modules/react-native-gesture-handler": {
"version": "2.13.4",
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.13.4.tgz",
@@ -13119,6 +13237,18 @@
"react-native": ">=0.65.0"
}
},
+ "node_modules/react-native-ratings": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/react-native-ratings/-/react-native-ratings-8.0.4.tgz",
+ "integrity": "sha512-Xczu5lskIIRD6BEdz9A0jDRpEck/SFxRqiglkXi0u67yAtI1/pcJC76P4MukCbT8K4BPVl+42w83YqXBoBRl7A==",
+ "dependencies": {
+ "lodash": "^4.17.15"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
"node_modules/react-native-reanimated": {
"version": "3.5.4",
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.5.4.tgz",
@@ -13174,6 +13304,14 @@
"react-native": ">=0.71.0"
}
},
+ "node_modules/react-native-size-matters": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/react-native-size-matters/-/react-native-size-matters-0.3.1.tgz",
+ "integrity": "sha512-mKOfBLIBFBcs9br1rlZDvxD5+mAl8Gfr5CounwJtxI6Z82rGrMO+Kgl9EIg3RMVf3G855a85YVqHJL2f5EDRlw==",
+ "peerDependencies": {
+ "react-native": "*"
+ }
+ },
"node_modules/react-native-svg": {
"version": "13.14.0",
"resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-13.14.0.tgz",
@@ -14015,6 +14153,19 @@
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
},
+ "node_modules/simple-swizzle": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+ "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
+ "dependencies": {
+ "is-arrayish": "^0.3.1"
+ }
+ },
+ "node_modules/simple-swizzle/node_modules/is-arrayish": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
+ },
"node_modules/sisteransi": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
diff --git a/package.json b/package.json
index 6cfe13d..1e12dd7 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,7 @@
"@react-native-async-storage/async-storage": "^1.19.5",
"@react-native-community/masked-view": "^0.1.11",
"@react-native-community/netinfo": "^9.4.1",
+ "@react-navigation/drawer": "^6.6.6",
"@react-navigation/native": "^6.1.9",
"@react-navigation/native-stack": "^6.9.16",
"@reduxjs/toolkit": "^1.9.7",
@@ -21,6 +22,7 @@
"axios": "^1.6.0",
"react": "18.2.0",
"react-native": "0.72.6",
+ "react-native-elements": "^3.4.3",
"react-native-gesture-handler": "^2.9.0",
"react-native-modal": "^13.0.1",
"react-native-reanimated": "^3.5.4",
@@ -29,7 +31,7 @@
"react-native-simple-toast": "^3.0.2",
"react-native-svg": "^13.14.0",
"react-native-svg-transformer": "^1.1.0",
- "react-native-vector-icons": "^10.0.1",
+ "react-native-vector-icons": "^10.0.2",
"react-query": "^3.39.3",
"react-redux": "^8.1.3",
"redux": "^4.2.1",
@@ -43,6 +45,7 @@
"@react-native/metro-config": "^0.72.11",
"@tsconfig/react-native": "^3.0.0",
"@types/react": "^18.0.24",
+ "@types/react-native-vector-icons": "^6.4.18",
"@types/react-redux": "^7.1.28",
"@types/react-test-renderer": "^18.0.0",
"babel-jest": "^29.2.1",
diff --git a/res/menu_black_24dp.svg b/res/menu_black_24dp.svg
new file mode 100644
index 0000000..16fbd60
--- /dev/null
+++ b/res/menu_black_24dp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/application/App.tsx b/src/application/App.tsx
index 3ea4f22..09f6d2a 100644
--- a/src/application/App.tsx
+++ b/src/application/App.tsx
@@ -1,28 +1,96 @@
+import {createDrawerNavigator} from '@react-navigation/drawer';
import {NavigationContainer} from '@react-navigation/native';
import {
createNativeStackNavigator,
NativeStackNavigationProp,
} from '@react-navigation/native-stack';
import React from 'react';
-import {Text, useColorScheme} from 'react-native';
+import {StyleSheet, Text, TouchableOpacity, useColorScheme} from 'react-native';
import {GestureHandlerRootView} from 'react-native-gesture-handler';
import {SafeAreaProvider} from 'react-native-safe-area-context';
import {Colors} from 'react-native/Libraries/NewAppScreen';
import {Provider} from 'react-redux';
import {PersistGate} from 'redux-persist/integration/react';
-import CartScreen from '../features/cart/CartScreen';
+import ArrowBack from '../../res/arrow_back.svg';
+import MenuIcon from '../../res/menu_black_24dp.svg';
+import CartScreen, {MARGIN_HORIZONTAL} from '../features/cart/CartScreen';
+import CartButton from '../features/products/components/CartButton';
import ProductsScreen from '../features/products/ProductsScreen';
+import PurchasesScreen from '../features/purchases/PurchasesScreen';
import {colors} from '../features/shared/colors';
import {QueryProvider} from '../infrastructure/query';
+import {useAppSelector} from '../infrastructure/store/hooks/hooks';
import store, {persistor} from '../infrastructure/store/store';
-type AppStackParamList = {
+export type AppStackParamList = {
Products: undefined;
Cart: undefined;
};
+type PurchasesParamList = {
+ Purchases: undefined;
+};
+
+const StoreNavigator = createNativeStackNavigator();
+const PurchasesNavigator = createNativeStackNavigator();
+const AppNavigator = createDrawerNavigator();
+
+const StoreFlow = () => (
+
+
+
+
+);
+
+const PurchasesFlow = () => {
+ return (
+
+
+
+ );
+};
+
export type NavigationProp = NativeStackNavigationProp;
-const appNavigator = createNativeStackNavigator();
+
+const StoreFlowNavigationOptions = ({navigation}) => {
+ const state = navigation.getState();
+ const isCartEmpty = useAppSelector(state => state.cart.cart.length === 0);
+
+ const stackState = state.routes.find(route => route.state)?.state;
+ const currentScreen = stackState?.routes[stackState?.index]?.name;
+ console.log('currentScreen: ', currentScreen);
+ const isCartScreen = currentScreen === 'Cart';
+ return {
+ headerRight: () =>
+ !isCartScreen && (
+ navigation.navigate('Cart')}
+ isEnabled={isCartEmpty}
+ />
+ ),
+ headerLeft: () =>
+ isCartScreen ? (
+ {
+ navigation.goBack();
+ }}>
+
+
+ ) : (
+ {
+ navigation.openDrawer();
+ }}>
+
+
+ ),
+ };
+};
function App(): JSX.Element {
const isDarkMode = useColorScheme() === 'dark';
@@ -32,28 +100,40 @@ function App(): JSX.Element {
};
return (
-
-
-
-
-
-
+
+
+
+
);
}
+const styles = StyleSheet.create({
+ headerButton: {
+ marginHorizontal: MARGIN_HORIZONTAL,
+ },
+});
+
export default () => {
return (
-
-
- Loading...} persistor={persistor}>
-
-
-
-
-
-
+
+
+
+ Loading...}
+ persistor={persistor}>
+
+
+
+
+
+
+
);
};
diff --git a/src/features/cart/CartScreen.tsx b/src/features/cart/CartScreen.tsx
index c218ded..1fa61b4 100644
--- a/src/features/cart/CartScreen.tsx
+++ b/src/features/cart/CartScreen.tsx
@@ -1,16 +1,8 @@
import {BottomSheetModal, BottomSheetModalProvider} from '@gorhom/bottom-sheet';
import {useNavigation} from '@react-navigation/native';
import React, {useEffect, useMemo, useRef, useState} from 'react';
-import {
- Platform,
- SafeAreaView,
- StyleSheet,
- Text,
- TouchableOpacity,
- View,
-} from 'react-native';
+import {Platform, SafeAreaView, StyleSheet, Text, View} from 'react-native';
import Toast from 'react-native-simple-toast';
-import ArrowBack from '../../../res/arrow_back.svg';
import {NavigationProp} from '../../application/App';
import {cleanCart, editQuantity} from '../../infrastructure/store/cartSlice';
import {
@@ -90,13 +82,6 @@ const CartScreen = () => {
- {
- navigation.goBack();
- }}>
-
-
Shopping Cart
void;
-}) => {
+ onPress?: () => void;
+};
+
+const CartItem: React.FC = ({product, style, onPress}) => {
return (
{product.name}
- {'$' + product.price.toFixed(2)}
+ {'$' + product.price?.toFixed(2) || '0'}
{product.quantity + ' units'}
diff --git a/src/features/cart/queries.ts b/src/features/cart/queries.ts
index d65b769..4f42af4 100644
--- a/src/features/cart/queries.ts
+++ b/src/features/cart/queries.ts
@@ -1,7 +1,14 @@
-import {useMutation} from '@tanstack/react-query';
+import {useMutation, useQueryClient} from '@tanstack/react-query';
import {makeCheckout} from '../../infrastructure/api';
+import {purchasesKeys} from '../purchases/queries';
-export const useCheckoutMutation = () =>
- useMutation({
+export const useCheckoutMutation = () => {
+ const queryClient = useQueryClient();
+
+ return useMutation({
mutationFn: makeCheckout,
+ onSuccess: () => {
+ queryClient.invalidateQueries({queryKey: purchasesKeys});
+ },
});
+};
diff --git a/src/features/products/ProductsScreen.tsx b/src/features/products/ProductsScreen.tsx
index 25b93ab..45debfa 100644
--- a/src/features/products/ProductsScreen.tsx
+++ b/src/features/products/ProductsScreen.tsx
@@ -1,35 +1,16 @@
-import {useNavigation} from '@react-navigation/native';
import React, {useState} from 'react';
-import {StyleSheet, TouchableOpacity, View} from 'react-native';
+import {StyleSheet, View} from 'react-native';
import {SafeAreaView} from 'react-native-safe-area-context';
-import EnabledShoppingCart from '../../../res/shopping-cart-enabled.svg';
-import ShoppingCart from '../../../res/shopping-cart.svg';
-import {NavigationProp} from '../../application/App';
-import {useAppSelector} from '../../infrastructure/store/hooks/hooks';
import Carrousel from './components/Carrousel';
import {ProductsList} from './components/ProductsList';
import SearchBar from './components/SearchBar';
const ProductsScreen = () => {
- const isEmpty = useAppSelector(state => state.cart.cart.length === 0);
const [query, setQuery] = useState('');
- const navigation = useNavigation();
-
- const cartImage = isEmpty ? (
-
- ) : (
- {
- navigation.navigate('Cart');
- }}>
-
-
- );
return (
-
+
- {cartImage}
{
const styles = StyleSheet.create({
container: {
flex: 1,
+ marginTop: 12,
},
carrousel: {
width: '100%',
height: 250,
},
- cartButton: {
- marginEnd: 29,
- marginVertical: 16,
- alignSelf: 'flex-end',
- },
searchBar: {
marginTop: 24,
},
diff --git a/src/features/products/components/CartButton.tsx b/src/features/products/components/CartButton.tsx
new file mode 100644
index 0000000..222521c
--- /dev/null
+++ b/src/features/products/components/CartButton.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import {StyleSheet, TouchableOpacity, View} from 'react-native';
+import EnabledShoppingCart from '../../../../res/shopping-cart-enabled.svg';
+import ShoppingCart from '../../../../res/shopping-cart.svg';
+
+const CartButton = ({
+ isEnabled,
+ onPress,
+}: {
+ isEnabled: boolean;
+ onPress: () => void;
+}) => {
+ const cartImage = isEnabled ? (
+
+ ) : (
+
+
+
+ );
+
+ return {cartImage};
+};
+
+const styles = StyleSheet.create({
+ cartButton: {
+ marginEnd: 29,
+ },
+});
+
+export default CartButton;
diff --git a/src/features/products/components/ProductsList.tsx b/src/features/products/components/ProductsList.tsx
index f1719d8..d61286b 100644
--- a/src/features/products/components/ProductsList.tsx
+++ b/src/features/products/components/ProductsList.tsx
@@ -6,6 +6,7 @@ import {
} from '../../../infrastructure/store/cartSlice';
import {useAppDispatch} from '../../../infrastructure/store/hooks/hooks';
import {colors} from '../../shared/colors';
+import {productsSeparator} from '../../shared/components/ProductsSeparator';
import {useDisplayList} from '../hooks/useDisplayList';
import {Product} from '../types/Product';
import HeaderListItem from './HeaderListItem';
@@ -48,12 +49,6 @@ export const ProductsList = ({query}: {query: string}) => {
);
};
-const productsSeparator = () => {
- return (
-
- );
-};
-
const styles = StyleSheet.create({
productContainer: {
marginHorizontal: 16,
diff --git a/src/features/purchases/PurchasesScreen.tsx b/src/features/purchases/PurchasesScreen.tsx
new file mode 100644
index 0000000..a91f046
--- /dev/null
+++ b/src/features/purchases/PurchasesScreen.tsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import {SectionList, StyleSheet} from 'react-native';
+import {SafeAreaView} from 'react-native-safe-area-context';
+import HeaderListItem from '../products/components/HeaderListItem';
+import {productsSeparator} from '../shared/components/ProductsSeparator';
+import {PurchaseListItem} from './components/PurchaseListItem';
+import {usePurchases} from './queries';
+
+const PurchaseScreen = () => {
+ const {data: purchases} = usePurchases();
+ const purchasesList = purchases ?? [];
+
+ return (
+
+ }
+ ItemSeparatorComponent={productsSeparator}
+ keyExtractor={(item, index) => item.date + index}
+ renderSectionHeader={({
+ section: {title},
+ }: {
+ section: {title: string};
+ }) => }
+ />
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ },
+});
+
+export default PurchaseScreen;
diff --git a/src/features/purchases/components/PurchaseListItem.tsx b/src/features/purchases/components/PurchaseListItem.tsx
new file mode 100644
index 0000000..2e4afb5
--- /dev/null
+++ b/src/features/purchases/components/PurchaseListItem.tsx
@@ -0,0 +1,43 @@
+import React from 'react';
+import {FlatList, StyleSheet, View} from 'react-native';
+import {MARGIN_BETWEEN_COLUMNS, MARGIN_HORIZONTAL} from '../../cart/CartScreen';
+import CartItem from '../../cart/components/CartItem';
+import {colors} from '../../shared/colors';
+import {Purchase} from '../types/Purchase';
+
+export const PurchaseListItem = ({purchase}: {purchase: Purchase}) => {
+ return (
+
+ {
+ return {...purchaseItem.product, quantity: purchaseItem.quantity};
+ })}
+ contentContainerStyle={styles.contentContainer}
+ renderItem={({item, index}) => (
+
+ )}
+ />
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ borderColor: colors.purple,
+ marginBottom: 16,
+ borderWidth: 2,
+ },
+ contentContainer: {
+ paddingTop: 24,
+ alignItems: 'stretch',
+ marginHorizontal: MARGIN_HORIZONTAL,
+ },
+});
diff --git a/src/features/purchases/index.ts b/src/features/purchases/index.ts
new file mode 100644
index 0000000..e69de29
diff --git a/src/features/purchases/queries.ts b/src/features/purchases/queries.ts
new file mode 100644
index 0000000..7f45569
--- /dev/null
+++ b/src/features/purchases/queries.ts
@@ -0,0 +1,26 @@
+import {useQuery} from '@tanstack/react-query';
+import {getPurchases} from '../../infrastructure/api';
+import {Purchase} from './types/Purchase';
+
+export const purchasesKeys = ['all'];
+
+export const usePurchases = () => {
+ return useQuery({
+ queryKey: purchasesKeys,
+ queryFn: getPurchases,
+ select: data => {
+ const datesPurchasesMap = data.reduce((acc, purchase) => {
+ const date = purchase.date.split('T')[0];
+ const group = acc.get(date) || [];
+ group.push(purchase);
+ acc.set(date, group);
+ return acc;
+ }, new Map());
+
+ return Array.from(datesPurchasesMap, ([date, purchases]) => ({
+ title: date,
+ data: purchases,
+ })).reverse();
+ },
+ });
+};
diff --git a/src/features/purchases/types/Purchase.ts b/src/features/purchases/types/Purchase.ts
new file mode 100644
index 0000000..ef2bf15
--- /dev/null
+++ b/src/features/purchases/types/Purchase.ts
@@ -0,0 +1,6 @@
+import {ApiProduct} from '../../../infrastructure/api';
+
+export interface Purchase {
+ date: string;
+ items: {product: ApiProduct; quantity: number}[];
+}
diff --git a/src/features/shared/components/ProductsSeparator.tsx b/src/features/shared/components/ProductsSeparator.tsx
new file mode 100644
index 0000000..1d03327
--- /dev/null
+++ b/src/features/shared/components/ProductsSeparator.tsx
@@ -0,0 +1,11 @@
+import React from 'react';
+import {StyleSheet, View} from 'react-native';
+import {colors} from '../colors';
+
+export const productsSeparator = () => {
+ return ;
+};
+
+const styles = StyleSheet.create({
+ lineStyle: {height: 1, width: '90%', backgroundColor: colors.gray},
+});
diff --git a/src/infrastructure/api/endpoints.ts b/src/infrastructure/api/endpoints.ts
index 3ae989c..7fe7cca 100644
--- a/src/infrastructure/api/endpoints.ts
+++ b/src/infrastructure/api/endpoints.ts
@@ -1,3 +1,4 @@
+import {Purchase} from '../../features/purchases/types/Purchase';
import {CartProduct} from '../store/cartSlice';
import {instance} from './instance';
@@ -44,6 +45,22 @@ export const makeCheckout = (cart: CartProduct[]) => {
});
};
+export const getPurchases = (): Promise => {
+ return instance
+ .get('/purchases')
+ .then(response => {
+ if (response.status === 200) {
+ return response.data;
+ } else {
+ throw new Error('Error fetching products');
+ }
+ })
+ .catch(error => {
+ console.log(error);
+ throw error;
+ });
+};
+
export interface Banner {
id: number;
name: string;