cart
This commit is contained in:
200
components/CartItemCard.tsx
Normal file
200
components/CartItemCard.tsx
Normal file
@@ -0,0 +1,200 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
Image,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
Alert,
|
||||
} from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { CartItem } from '../services/cart';
|
||||
|
||||
interface CartItemCardProps {
|
||||
item: CartItem;
|
||||
onUpdateQuantity: (cartItemId: number, quantity: number) => Promise<boolean>;
|
||||
onRemove: (cartItemId: number) => Promise<boolean>;
|
||||
}
|
||||
|
||||
export default function CartItemCard({
|
||||
item,
|
||||
onUpdateQuantity,
|
||||
onRemove,
|
||||
}: CartItemCardProps) {
|
||||
const handleDecrease = async () => {
|
||||
if (item.quantity > 1) {
|
||||
const success = await onUpdateQuantity(item.cartItemId, item.quantity - 1);
|
||||
if (!success) {
|
||||
Alert.alert('Lỗi', 'Không thể cập nhật số lượng');
|
||||
}
|
||||
} else {
|
||||
Alert.alert(
|
||||
'Xác nhận',
|
||||
'Bạn có muốn xóa sản phẩm này khỏi giỏ hàng?',
|
||||
[
|
||||
{ text: 'Hủy', style: 'cancel' },
|
||||
{
|
||||
text: 'Xóa',
|
||||
onPress: async () => {
|
||||
const success = await onRemove(item.cartItemId);
|
||||
if (!success) {
|
||||
Alert.alert('Lỗi', 'Không thể xóa sản phẩm');
|
||||
}
|
||||
},
|
||||
style: 'destructive'
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const handleIncrease = async () => {
|
||||
const success = await onUpdateQuantity(item.cartItemId, item.quantity + 1);
|
||||
if (!success) {
|
||||
Alert.alert('Lỗi', 'Không thể cập nhật số lượng');
|
||||
}
|
||||
};
|
||||
|
||||
const handleRemove = () => {
|
||||
Alert.alert(
|
||||
'Xác nhận',
|
||||
'Bạn có chắc muốn xóa sản phẩm này?',
|
||||
[
|
||||
{ text: 'Hủy', style: 'cancel' },
|
||||
{
|
||||
text: 'Xóa',
|
||||
onPress: async () => {
|
||||
const success = await onRemove(item.cartItemId);
|
||||
if (!success) {
|
||||
Alert.alert('Lỗi', 'Không thể xóa sản phẩm');
|
||||
}
|
||||
},
|
||||
style: 'destructive'
|
||||
},
|
||||
]
|
||||
);
|
||||
};
|
||||
|
||||
const formatPrice = (price: number) => {
|
||||
return new Intl.NumberFormat('vi-VN', {
|
||||
style: 'currency',
|
||||
currency: 'VND',
|
||||
}).format(price);
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Image
|
||||
source={{ uri: item.productImage }}
|
||||
style={styles.image}
|
||||
resizeMode="cover"
|
||||
/>
|
||||
|
||||
<View style={styles.info}>
|
||||
<Text style={styles.name} numberOfLines={2}>
|
||||
{item.productName}
|
||||
</Text>
|
||||
|
||||
<Text style={styles.price}>{formatPrice(item.price)}</Text>
|
||||
|
||||
<View style={styles.footer}>
|
||||
<View style={styles.quantityContainer}>
|
||||
<TouchableOpacity
|
||||
style={styles.quantityButton}
|
||||
onPress={handleDecrease}
|
||||
>
|
||||
<Ionicons name="remove" size={18} color="#333" />
|
||||
</TouchableOpacity>
|
||||
|
||||
<Text style={styles.quantity}>{item.quantity}</Text>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.quantityButton}
|
||||
onPress={handleIncrease}
|
||||
>
|
||||
<Ionicons name="add" size={18} color="#333" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<Text style={styles.subtotal}>{formatPrice(item.subtotal)}</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<TouchableOpacity style={styles.deleteButton} onPress={handleRemove}>
|
||||
<Ionicons name="trash-outline" size={20} color="#ff4444" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flexDirection: 'row',
|
||||
backgroundColor: '#fff',
|
||||
padding: 12,
|
||||
marginBottom: 12,
|
||||
borderRadius: 12,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowOpacity: 0.1,
|
||||
shadowRadius: 4,
|
||||
elevation: 3,
|
||||
},
|
||||
image: {
|
||||
width: 80,
|
||||
height: 80,
|
||||
borderRadius: 8,
|
||||
backgroundColor: '#f0f0f0',
|
||||
},
|
||||
info: {
|
||||
flex: 1,
|
||||
marginLeft: 12,
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
name: {
|
||||
fontSize: 15,
|
||||
fontWeight: '600',
|
||||
color: '#333',
|
||||
marginBottom: 4,
|
||||
},
|
||||
price: {
|
||||
fontSize: 14,
|
||||
color: '#ff6b6b',
|
||||
fontWeight: '500',
|
||||
},
|
||||
footer: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginTop: 8,
|
||||
},
|
||||
quantityContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#f5f5f5',
|
||||
borderRadius: 6,
|
||||
paddingHorizontal: 4,
|
||||
},
|
||||
quantityButton: {
|
||||
width: 28,
|
||||
height: 28,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
quantity: {
|
||||
fontSize: 15,
|
||||
fontWeight: '600',
|
||||
color: '#333',
|
||||
minWidth: 30,
|
||||
textAlign: 'center',
|
||||
},
|
||||
subtotal: {
|
||||
fontSize: 16,
|
||||
fontWeight: '700',
|
||||
color: '#ff6b6b',
|
||||
},
|
||||
deleteButton: {
|
||||
padding: 8,
|
||||
justifyContent: 'flex-start',
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user