Skip to content

Commit e19a43f

Browse files
committed
add Cart screen with items, billing and checkout
1 parent 18a9afa commit e19a43f

1 file changed

Lines changed: 104 additions & 0 deletions

File tree

mobile/src/screens/CartScreen.js

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import React from 'react';
2+
import { View, Text, FlatList, Image, TouchableOpacity, StyleSheet } from 'react-native';
3+
import { SafeAreaView } from 'react-native-safe-area-context';
4+
import { Trash2, ShoppingBag } from 'lucide-react-native';
5+
import { colors } from '../theme/colors';
6+
import { useApp } from '../context/AppContext';
7+
8+
export default function CartScreen({ navigation }) {
9+
const { cartItems, removeFromCart, cartTotal, user } = useApp();
10+
const shipping = cartTotal > 999 ? 0 : 99;
11+
12+
const handleCheckout = () => {
13+
if (!user) { navigation.navigate('Login'); return; }
14+
navigation.navigate('Checkout');
15+
};
16+
17+
if (cartItems.length === 0) {
18+
return (
19+
<SafeAreaView style={styles.safe}>
20+
<View style={styles.topBar}>
21+
<Text style={styles.title}>SHOPPING BAG</Text>
22+
</View>
23+
<View style={styles.empty}>
24+
<ShoppingBag size={56} color={colors.border} />
25+
<Text style={styles.emptyTitle}>Your bag is empty</Text>
26+
<TouchableOpacity style={styles.shopBtn} onPress={() => navigation.goBack()}>
27+
<Text style={styles.shopBtnTxt}>CONTINUE SHOPPING</Text>
28+
</TouchableOpacity>
29+
</View>
30+
</SafeAreaView>
31+
);
32+
}
33+
34+
return (
35+
<SafeAreaView style={styles.safe}>
36+
<View style={styles.topBar}>
37+
<Text style={styles.title}>SHOPPING BAG</Text>
38+
<Text style={styles.count}>{cartItems.length} item{cartItems.length > 1 ? 's' : ''}</Text>
39+
</View>
40+
41+
<FlatList
42+
data={cartItems}
43+
keyExtractor={(item, i) => `${item.id}-${item.size}-${i}`}
44+
contentContainerStyle={styles.list}
45+
renderItem={({ item }) => (
46+
<View style={styles.item}>
47+
<Image source={{ uri: item.image }} style={styles.itemImg} resizeMode="cover" />
48+
<View style={styles.itemInfo}>
49+
<Text style={styles.itemName} numberOfLines={2}>{item.name}</Text>
50+
<Text style={styles.itemMeta}>Size: UK {item.size} · Qty: {item.qty}</Text>
51+
<Text style={styles.itemPrice}>{(item.price * item.qty).toLocaleString('en-IN')}</Text>
52+
</View>
53+
<TouchableOpacity style={styles.removeBtn} onPress={() => removeFromCart(item.id, item.size)}>
54+
<Trash2 size={16} color={colors.gray} />
55+
</TouchableOpacity>
56+
</View>
57+
)}
58+
/>
59+
60+
<View style={styles.footer}>
61+
<View style={styles.billRow}><Text style={styles.billLabel}>Cart Total</Text><Text style={styles.billVal}>{cartTotal.toLocaleString('en-IN')}</Text></View>
62+
<View style={styles.billRow}>
63+
<Text style={styles.billLabel}>Shipping</Text>
64+
<Text style={[styles.billVal, { color: colors.success }]}>{shipping === 0 ? 'FREE' : `₹ ${shipping}`}</Text>
65+
</View>
66+
<View style={[styles.billRow, styles.totalRow]}>
67+
<Text style={styles.totalLabel}>Total</Text>
68+
<Text style={styles.totalVal}>{(cartTotal + shipping).toLocaleString('en-IN')}</Text>
69+
</View>
70+
<TouchableOpacity style={styles.checkoutBtn} onPress={handleCheckout}>
71+
<Text style={styles.checkoutTxt}>PROCEED TO CHECKOUT</Text>
72+
</TouchableOpacity>
73+
</View>
74+
</SafeAreaView>
75+
);
76+
}
77+
78+
const styles = StyleSheet.create({
79+
safe: { flex: 1, backgroundColor: colors.white },
80+
topBar: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingHorizontal: 20, paddingVertical: 14, borderBottomWidth: 1, borderBottomColor: colors.border },
81+
title: { fontSize: 16, fontWeight: '800', letterSpacing: 1.5, color: colors.dark },
82+
count: { fontSize: 13, color: colors.gray },
83+
list: { padding: 16, gap: 12 },
84+
item: { flexDirection: 'row', gap: 12, backgroundColor: colors.white, borderRadius: 12, padding: 12, shadowColor: '#000', shadowOpacity: 0.05, shadowRadius: 6, elevation: 2 },
85+
itemImg: { width: 80, height: 80, borderRadius: 10, backgroundColor: colors.lightGray },
86+
itemInfo: { flex: 1 },
87+
itemName: { fontSize: 13, fontWeight: '700', color: colors.dark, marginBottom: 4 },
88+
itemMeta: { fontSize: 12, color: colors.gray, marginBottom: 6 },
89+
itemPrice: { fontSize: 15, fontWeight: '800', color: colors.brand },
90+
removeBtn: { padding: 4 },
91+
footer: { padding: 20, borderTopWidth: 1, borderTopColor: colors.border, gap: 8 },
92+
billRow: { flexDirection: 'row', justifyContent: 'space-between' },
93+
billLabel: { fontSize: 14, color: colors.gray },
94+
billVal: { fontSize: 14, fontWeight: '600', color: colors.dark },
95+
totalRow: { paddingTop: 8, borderTopWidth: 1, borderTopColor: colors.border, marginTop: 4 },
96+
totalLabel: { fontSize: 16, fontWeight: '800', color: colors.dark },
97+
totalVal: { fontSize: 18, fontWeight: '900', color: colors.dark },
98+
checkoutBtn: { backgroundColor: colors.brand, borderRadius: 14, paddingVertical: 16, alignItems: 'center', marginTop: 8 },
99+
checkoutTxt: { color: colors.white, fontWeight: '800', fontSize: 14, letterSpacing: 1 },
100+
empty: { flex: 1, alignItems: 'center', justifyContent: 'center', gap: 16 },
101+
emptyTitle: { fontSize: 16, fontWeight: '700', color: colors.gray },
102+
shopBtn: { backgroundColor: colors.brand, paddingHorizontal: 24, paddingVertical: 12, borderRadius: 10 },
103+
shopBtnTxt: { color: colors.white, fontWeight: '700', fontSize: 13 },
104+
});

0 commit comments

Comments
 (0)