Commit 79e3657f authored by Shahzad Bhatti's avatar Shahzad Bhatti

add to cart functionality

parent 462df178
...@@ -3,9 +3,14 @@ import Lottie from 'lottie-react-native'; ...@@ -3,9 +3,14 @@ import Lottie from 'lottie-react-native';
import Home from './src/components/Home'; import Home from './src/components/Home';
import Login from './src/components/Login'; import Login from './src/components/Login';
import Signup from './src/components/Signup'; import Signup from './src/components/Signup';
import Cart from './src/components/Cart';
import Icon from 'react-native-vector-icons/FontAwesome';
import ProductDetail from './src/components/ProductDetail';
import MedicineList from './src/components/MedicineList'; import MedicineList from './src/components/MedicineList';
import {NavigationContainer} from '@react-navigation/native'; import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack'; import {createNativeStackNavigator} from '@react-navigation/native-stack';
import CartProvider from './src/store/CartContext';
import {Colors} from './src/constants/Constants';
const Stack = createNativeStackNavigator(); const Stack = createNativeStackNavigator();
...@@ -26,14 +31,42 @@ function App() { ...@@ -26,14 +31,42 @@ function App() {
); );
} }
return ( return (
<NavigationContainer> <CartProvider>
<Stack.Navigator> <NavigationContainer>
<Stack.Screen name="Home" component={Home} /> <Stack.Navigator>
<Stack.Screen name="Signup" component={Signup} /> <Stack.Screen name="Home" component={Home} options={{title: ''}} />
<Stack.Screen name="Login" component={Login} /> <Stack.Screen name="Signup" component={Signup} />
<Stack.Screen name="MedicineList" component={MedicineList} /> <Stack.Screen name="Login" component={Login} />
</Stack.Navigator> <Stack.Screen
</NavigationContainer> name="MedicineList"
component={MedicineList}
options={{
title: 'Product List',
headerRight: () => (
<Icon
name="shopping-cart"
size={30}
color={Colors.primary500}></Icon>
),
}}
/>
<Stack.Screen
name="ProductDetail"
component={ProductDetail}
options={{
title: 'Product Detail',
headerRight: () => (
<Icon
name="shopping-cart"
size={30}
color={Colors.primary500}></Icon>
),
}}
/>
<Stack.Screen name="Cart" component={Cart} />
</Stack.Navigator>
</NavigationContainer>
</CartProvider>
); );
} }
......
...@@ -18,7 +18,9 @@ ...@@ -18,7 +18,9 @@
"react-native": "0.71.1", "react-native": "0.71.1",
"react-native-safe-area-context": "^4.5.0", "react-native-safe-area-context": "^4.5.0",
"react-native-screens": "^3.19.0", "react-native-screens": "^3.19.0",
"react-native-vector-icons": "^9.2.0" "react-native-vector-icons": "^9.2.0",
"react-redux": "^8.0.5",
"redux": "^4.2.1"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.20.0", "@babel/core": "^7.20.0",
...@@ -28,6 +30,7 @@ ...@@ -28,6 +30,7 @@
"@tsconfig/react-native": "^2.0.2", "@tsconfig/react-native": "^2.0.2",
"@types/jest": "^29.2.1", "@types/jest": "^29.2.1",
"@types/react": "^18.0.24", "@types/react": "^18.0.24",
"@types/react-native-vector-icons": "^6.4.13",
"@types/react-test-renderer": "^18.0.0", "@types/react-test-renderer": "^18.0.0",
"babel-jest": "^29.2.1", "babel-jest": "^29.2.1",
"eslint": "^8.19.0", "eslint": "^8.19.0",
......
import React, {useContext, useState} from 'react';
import {View, Text, StyleSheet, Button, Image} from 'react-native';
import {CartContext} from '../store/CartContext';
const CartItem = ({item}) => {
const {removeFromCart, updateQuantity} = useContext(CartContext);
const handleRemoveFromCart = () => {
removeFromCart(item.product);
};
const handleUpdateQuantity = newQuantity => {
updateQuantity(item.product, newQuantity);
};
// setTotal(total + (item.product.price * item.quantity));
return (
<View style={styles.itemContainer}>
<View style={styles.imageContainer}>
<Image source={item.product.image} style={styles.image} />
</View>
<View style={styles.detailContainer}>
<Text>{item.product.name}</Text>
<Text style={styles.price}>{item.product.price}</Text>
</View>
<View style={styles.qtyContainer}>
<Button title="-" onPress={handleRemoveFromCart} />
<Button
title="-"
onPress={() => handleUpdateQuantity(item.quantity - 1)}
/>
<Text>{item.product.quantity}</Text>
<Button
title="+"
onPress={() => handleUpdateQuantity(item.quantity + 1)}
/>
</View>
</View>
);
};
const Cart = () => {
const {cart} = useContext(CartContext);
const [total, setTotal] = useState(0);
return (
<View style={styles.cartContiner}>
{cart.map(item => (
<CartItem key={item.product.id} item={item} />
))}
<Text style={styles.title}>Total</Text>
</View>
);
};
const styles = StyleSheet.create({
cartContiner: {
flex: 1,
},
itemContainer: {
flex: 0.5,
padding: 10,
flexDirection: 'row',
justifyContent: 'flex-start',
height: '10%',
},
imageContainer: {
flex: 1,
backgroundColor: 'blue',
},
detailContainer: {
flex: 3,
backgroundColor: '#ccc',
},
title: {
fontSize: 20,
fontWeight: 'bold',
marginBottom: 10,
},
qtyContainer: {
flex: 2,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 10,
borderBottomWidth: 1,
borderBottomColor: '#ccc',
paddingBottom: 5,
},
name: {
fontSize: 16,
fontWeight: 'bold',
},
quantity: {
fontSize: 14,
color: '#888',
},
image: {
width: 80,
height: 80,
},
price: {
fontSize: 14,
color: '#888',
},
});
export default Cart;
import React from 'react'; import React from 'react';
import {TextInput} from 'react-native'; import {TextInput} from 'react-native';
import {darkGreen} from '../constants/Constants'; import {Colors} from '../constants/Constants';
const Field = props => { const Field = props => {
return ( return (
<TextInput <TextInput
{...props} {...props}
style={{borderRadius: 100, color: darkGreen, paddingHorizontal: 10, width: '78%', backgroundColor: 'rgb(220,220, 220)', marginVertical: 10}} style={{borderRadius: 100, color: Colors.darkGreen, paddingHorizontal: 10, width: '78%', backgroundColor: 'rgb(220,220, 220)', marginVertical: 10}}
placeholderTextColor={darkGreen}></TextInput> placeholderTextColor={Colors.darkGreen}></TextInput>
); );
}; };
......
...@@ -2,21 +2,21 @@ import React from 'react'; ...@@ -2,21 +2,21 @@ import React from 'react';
import {View, StyleSheet} from 'react-native'; import {View, StyleSheet} from 'react-native';
import Background from './Background'; import Background from './Background';
import Btn from './Button'; import Btn from './Button';
import {darkGreen, green} from '../constants/Constants'; import {Colors} from '../constants/Constants';
const Home = props => { const Home = props => {
return ( return (
<Background> <Background>
<View style={{marginHorizontal: 20, marginVertical: 100}}> <View style={{marginHorizontal: 20, marginVertical: 100}}>
<Btn <Btn
bgColor={green} bgColor={Colors.green}
textColor="white" textColor="white"
btnLabel="Login" btnLabel="Login"
Press={() => props.navigation.navigate('Login')} Press={() => props.navigation.navigate('Login')}
/> />
<Btn <Btn
bgColor="white" bgColor="white"
textColor={darkGreen} textColor={Colors.darkGreen}
btnLabel="Signup" btnLabel="Signup"
Press={() => props.navigation.navigate('Signup')} Press={() => props.navigation.navigate('Signup')}
/> />
......
...@@ -3,7 +3,7 @@ import {View, Text, StyleSheet, TouchableOpacity} from 'react-native'; ...@@ -3,7 +3,7 @@ import {View, Text, StyleSheet, TouchableOpacity} from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome'; import Icon from 'react-native-vector-icons/FontAwesome';
import Background from './Background'; import Background from './Background';
import Btn from './Button'; import Btn from './Button';
import {darkGreen} from '../constants/Constants'; import {Colors} from '../constants/Constants';
import Field from './Field'; import Field from './Field';
const Login = props => { const Login = props => {
...@@ -12,7 +12,7 @@ const Login = props => { ...@@ -12,7 +12,7 @@ const Login = props => {
<View style={{alignItems: 'center', width: '100%'}}> <View style={{alignItems: 'center', width: '100%'}}>
<Text <Text
style={{ style={{
color: 'green', color: Colors.green,
fontSize: 32, fontSize: 32,
fontWeight: 'bold', fontWeight: 'bold',
marginVertical: 20, marginVertical: 20,
...@@ -38,13 +38,13 @@ const Login = props => { ...@@ -38,13 +38,13 @@ const Login = props => {
paddingRight: 16, paddingRight: 16,
marginBottom: 200, marginBottom: 200,
}}> }}>
<Text style={{color: darkGreen, fontWeight: 'bold', fontSize: 16}}> <Text style={{color: Colors.darkGreen, fontWeight: 'bold', fontSize: 16}}>
Forgot Password ? Forgot Password ?
</Text> </Text>
</View> </View>
<Btn <Btn
textColor="white" textColor="white"
bgColor={darkGreen} bgColor={Colors.darkGreen}
btnLabel="Login" btnLabel="Login"
Press={() => alert('Logged In')} Press={() => alert('Logged In')}
/> />
...@@ -60,7 +60,7 @@ const Login = props => { ...@@ -60,7 +60,7 @@ const Login = props => {
<TouchableOpacity <TouchableOpacity
onPress={() => props.navigation.navigate('Signup')}> onPress={() => props.navigation.navigate('Signup')}>
<Text <Text
style={{color: darkGreen, fontWeight: 'bold', fontSize: 16}}> style={{color: Colors.darkGreen, fontWeight: 'bold', fontSize: 16}}>
Signup Signup
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
......
import React from 'react'; import React from 'react';
import {View, FlatList, Image, StyleSheet, Text} from 'react-native'; import {
View,
FlatList,
Image,
StyleSheet,
Text,
TouchableOpacity,
} from 'react-native';
import {useNavigation} from '@react-navigation/native';
import {addToCart} from './cartActions';
const items = [ const items = [
{ {
...@@ -40,22 +49,25 @@ const items = [ ...@@ -40,22 +49,25 @@ const items = [
}, },
]; ];
const Item = ({name, image, price}) => ( const Item = ({item, navigation}) => (
<View style={styles.itemContainer}> <TouchableOpacity
<Image source={image} style={styles.image} /> style={styles.container}
<Text style={styles.text}>{name}</Text> onPress={() => navigation.navigate('ProductDetail', {item})}>
<Text style={styles.text}>Rs. {parseFloat(price.toFixed(2))}</Text> <View style={styles.itemContainer}>
</View> <Image source={item.image} style={styles.image} />
<Text style={styles.text}>{item.name}</Text>
<Text style={styles.text}>Rs. {parseFloat(item.price.toFixed(2))}</Text>
</View>
</TouchableOpacity>
); );
const MedicineList = () => { const MedicineList = () => {
const navigation = useNavigation();
return ( return (
<FlatList <FlatList
data={items} data={items}
numColumns={2} numColumns={2}
renderItem={({item}) => ( renderItem={({item}) => <Item item={item} navigation={navigation} />}
<Item name={item.name} image={item.image} price={item.price} />
)}
keyExtractor={item => item.id.toString()} keyExtractor={item => item.id.toString()}
/> />
); );
......
import React, {useContext, useState} from 'react';
import {View, Text, Image, Button, StyleSheet} from 'react-native';
import {useNavigation} from '@react-navigation/native';
import {CartContext} from '../store/CartContext';
import FlatButton from './ui/FlatButton';
const ProductDetail = porps => {
const item = porps.route.params.item;
const [quantity, setQuantity] = useState(1);
const navigation = useNavigation();
const {addToCart} = useContext(CartContext);
console.log(item);
const handleBuyNow = () => {
addToCart({...item, quantity});
navigation.navigate('Cart');
};
const handleAddToCart = () => {
addToCart({...item, quantity});
navigation.navigate('ProductDetail');
};
const incrementQuantity = () => {
setQuantity(prevQuantity => prevQuantity + 1);
};
const decrementQuantity = () => {
setQuantity(prevQuantity => (prevQuantity > 1 ? prevQuantity - 1 : 1));
};
return (
<View style={styles.container}>
<View style={styles.productContainer}>
<Image source={item.image} style={{width: 300, height: 300}} />
<View style={styles.productTitle}>
<Text style={{flex: 2, fontSize: 24}}>{item.name}</Text>
<Text style={{flex: 1, fontSize: 24}}>Rs. {item.price}</Text>
</View>
</View>
<View style={styles.cartIconContainer}>
<Text>{item.description}</Text>
<View style={styles.quantity}>
<Text style={styles.quantityLabel}>Quantity:</Text>
<Button
title="-"
style={styles.roundButton}
onPress={decrementQuantity}
/>
<Text style={styles.quantityValue}>{quantity}</Text>
<Button title="+" onPress={incrementQuantity} />
</View>
<View
style={{
flex: 1,
flexDirection: 'row',
justifyContent: 'space-evenly',
}}>
<FlatButton onPress={handleBuyNow}>Buy Now</FlatButton>
<FlatButton onPress={handleAddToCart}>Add to Cart</FlatButton>
</View>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
padding: 1,
},
productContainer: {
flex: 1,
width: '100%',
alignItems: 'center',
justifyContent: 'center',
},
productTitle: {
alignItems: 'center',
flex: 1,
width: '100%',
flexDirection: 'row',
justifyContent: 'flex-end',
},
quantityLabel: {
width: '70%',
fontSize: 16,
},
quantity: {
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
},
roundButton: {
borderRadius: 25,
},
cartIconContainer: {
flex: 1,
width: '100%',
},
});
const mapStateToProps = (state, ownProps) => {
const {productId} = ownProps.route.params;
return {
product: state.products.find(product => product.id === productId),
};
};
export default ProductDetail;
// export default connect(mapStateToProps, {addToCart})(ProductDetail);
...@@ -3,7 +3,7 @@ import {View, Text, StyleSheet, TouchableOpacity} from 'react-native'; ...@@ -3,7 +3,7 @@ import {View, Text, StyleSheet, TouchableOpacity} from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome'; import Icon from 'react-native-vector-icons/FontAwesome';
import Background from './Background'; import Background from './Background';
import Btn from './Button'; import Btn from './Button';
import {darkGreen} from '../constants/Constants'; import {Colors} from '../constants/Constants';
import Field from './Field'; import Field from './Field';
const Signup = props => { const Signup = props => {
...@@ -12,7 +12,7 @@ const Signup = props => { ...@@ -12,7 +12,7 @@ const Signup = props => {
<View style={{alignItems: 'center', width: '100%'}}> <View style={{alignItems: 'center', width: '100%'}}>
<Text <Text
style={{ style={{
color: 'green', color: Colors.green,
fontSize: 32, fontSize: 32,
fontWeight: 'bold', fontWeight: 'bold',
marginTop: 10, marginTop: 10,
...@@ -42,7 +42,7 @@ const Signup = props => { ...@@ -42,7 +42,7 @@ const Signup = props => {
}}></View> }}></View>
<Btn <Btn
textColor="white" textColor="white"
bgColor={darkGreen} bgColor={Colors.darkGreen}
btnLabel="Signup" btnLabel="Signup"
Press={() => { Press={() => {
alert('Accoutn created'); alert('Accoutn created');
...@@ -61,7 +61,7 @@ const Signup = props => { ...@@ -61,7 +61,7 @@ const Signup = props => {
<TouchableOpacity <TouchableOpacity
onPress={() => props.navigation.navigate('Login')}> onPress={() => props.navigation.navigate('Login')}>
<Text <Text
style={{color: darkGreen, fontWeight: 'bold', fontSize: 16}}> style={{color: Colors.darkGreen, fontWeight: 'bold', fontSize: 16}}>
Login Login
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
......
import {Pressable, StyleSheet, Text, View} from 'react-native';
import {Colors} from '../../constants/Constants';
function Button({children, onPress}) {
return (
<Pressable
style={({pressed}) => [styles.button, pressed && styles.pressed]}
onPress={onPress}>
<View>
<Text style={styles.buttonText}>{children}</Text>
</View>
</Pressable>
);
}
export default Button;
const styles = StyleSheet.create({
button: {
borderRadius: 6,
paddingVertical: 6,
paddingHorizontal: 12,
backgroundColor: Colors.primary500,
elevation: 2,
shadowColor: 'black',
shadowOffset: {width: 1, height: 1},
shadowOpacity: 0.25,
shadowRadius: 4,
},
pressed: {
opacity: 0.7,
},
buttonText: {
textAlign: 'center',
color: 'white',
fontSize: 16,
fontWeight: 'bold',
},
});
import {Pressable, StyleSheet, Text, View} from 'react-native';
import {Colors} from '../../constants/Constants';
function FlatButton({children, onPress}) {
return (
<Pressable
style={({pressed}) => [styles.button, pressed && styles.pressed]}
onPress={onPress}>
<View>
<Text style={styles.buttonText}>{children}</Text>
</View>
</Pressable>
);
}
export default FlatButton;
const styles = StyleSheet.create({
button: {
paddingVertical: 6,
paddingHorizontal: 12,
},
pressed: {
opacity: 0.7,
},
buttonText: {
textAlign: 'center',
color: Colors.primary800,
},
});
import { ActivityIndicator, StyleSheet, Text, View } from 'react-native';
function LoadingOverlay({ message }) {
return (
<View style={styles.rootContainer}>
<Text style={styles.message}>{message}</Text>
<ActivityIndicator size="large" />
</View>
);
}
export default LoadingOverlay;
const styles = StyleSheet.create({
rootContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 32,
},
message: {
fontSize: 16,
marginBottom: 12,
},
});
export const green = '#2BB789'; export const Colors = {
export const darkGreen = '#006A42'; green: '#2BB789',
\ No newline at end of file darkGreen: '#006A42',
primary100: '#f9beda',
primary500: '#1e1931',
primary800: '#610440',
error100: '#fcdcbf',
error500: '#f37c13',
};
import {createContext, useContext, useState} from 'react';
export const CartContext = createContext(undefined);
export const CartProvider = ({children}) => {
const [cart, setCart] = useState([]);
const addToCart = (product, quantity) => {
// Add a product to the cart
const item = {product, quantity};
setCart([...cart, item]);
};
const removeFromCart = product => {
// Remove a product from the cart
const updatedCart = cart.filter(item => item.product.id !== product.id);
setCart(updatedCart);
};
const updateQuantity = (product, quantity) => {
// Update the quantity of a product in the cart
const updatedCart = cart.map(item => {
if (item.product.id === product.id) {
return {...item, quantity};
} else {
return item;
}
});
setCart(updatedCart);
};
return (
// Make the cart data and functions available to child components
<CartContext.Provider
value={{cart, addToCart, removeFromCart, updateQuantity}}>
{children}
</CartContext.Provider>
);
};
// A custom hook to access the cart context
// export const useCart = () => useContext(CartContext);
export default CartProvider;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment