A
Anonymous

Styled Card - Copy this React, Mui Component to your project

Import React, { useEffect, useState } from "react"; import { clearCartAPI, getCartAPI, removeFromCartAPI, updateCartAPI, } from "../axios/cartService"; import { Box, Typography, List, ListItem, ListItemText, Button, TextField, // Thêm TextField để chỉnh sửa số lượng Dialog, DialogTitle, DialogContent, DialogActions, Divider, } from "@mui/material"; import { useDispatch, useSelector } from "react redux"; import { setCartItems, setTotalAmount, removeCartItems, clearCart, } from "../redux/cartSlice"; import { createOrderAPI } from "../axios/orderService"; import { fetchPatient } from "../redux/patientsSlice"; const Cart = () => { const [isDialogOpen, setDialogOpen] = useState(false); const [isErrorDialogOpen, setErrorDialogOpen] = useState(false); const dispatch = useDispatch(); const cartItems = useSelector((state) => state.cart.items); const cartId = useSelector((state) => state.cart?.cartId); const totalAmount = useSelector((state) => state.cart.totalAmount); const patient = useSelector((state) => state.patients?.patient); const patientId = patient?.patientId; useEffect(() => { dispatch(fetchPatient(patientId)); }, [dispatch, patientId]); // fetch data cart const fetchCartData = async () => { try { const res = await getCartAPI(cartId); if (res) { dispatch(setCartItems(res.items || [])); dispatch(setTotalAmount(res.totalAmount)); } else { console.error("Cart data is invalid."); } } catch (error) { console.error("Error fetching cart data:", error); } }; // handle remove cart item const handleRemoveFromCartItems = async (itemId) => { try { await removeFromCartAPI(cartId, itemId); dispatch(removeCartItems(itemId)); await fetchCartData(); } catch (error) { console.error("Error removing product:", error); alert("Không thể xóa sản phẩm."); } }; // handle clear all cart const handleClearAllCart = async () => { try { await clearCartAPI(cartId); dispatch(clearCart(cartId)); await fetchCartData(); } catch (error) { console.error("Error clearing cart:", error); } }; // handle payment const handleCheckoutClick = async () => { try { await createOrderAPI(patientId); setDialogOpen(true); } catch (error) { console.error("Error during checkout:", error); setErrorDialogOpen(true); } }; //handle update quantity const handleUpdateQuantity = async (itemId, newQuantity) => { if (newQuantity < 1) { alert("Số lượng phải lớn hơn 0."); return; } try { await updateCartAPI(cartId, itemId, newQuantity); await fetchCartData(); } catch (error) { console.error("Error updating quantity:", error); alert("Không thể cập nhật số lượng."); } }; const handleCloseDialog = () => { setDialogOpen(false); setErrorDialogOpen(false); }; return ( <Box sx={{ width: "93%", maxWidth: "400px", padding: "20px", borderRadius: "12px", boxShadow: "0px 4px 12px rgba(0, 0, 0, 0.1)", backgroundColor: "#fff", margin: "10px auto", }} > <Typography variant="h5" sx={{ fontWeight: "bold", textAlign: "center", mb: 2, color: "#1976d2", }} > Giỏ hàng của bạn </Typography> <Divider sx={{ mb: 2 }} /> <List> {(cartItems || []).map((item) => ( <ListItem key={item?.id} sx={{ display: "flex", flexDirection: "column", alignItems: "flex start", mb: 1, padding: "10px 15px", borderRadius: "8px", backgroundColor: "#f9f9f9", boxShadow: "0px 2px 8px rgba(0, 0, 0, 0.05)", }} > <Box sx={{ width: "100%" }}> <Typography variant="subtitle1" sx={{ fontWeight: "bold", color: "#333" }} > {item?.product?.name} </Typography> <Typography variant="body2" sx={{ color: "#555", mt: 0.5 }}> Giá: {item?.unitPrice?.toLocaleString()} VND </Typography> <Box sx={{ display: "flex", alignItems: "center", mt: 1, gap: 1, }} > <Typography variant="body2" sx={{ color: "#555" }}> Số lượng: </Typography> <TextField type="number" value={item?.quantity} onChange={(e) => handleUpdateQuantity(item.id, parseInt(e.target.value, 10)) } size="small" sx={{ width: "50px" }} /> </Box> </Box> <Button onClick={() => handleRemoveFromCartItems(item.id)} variant="contained" color="error" sx={{ minWidth: "80px", fontSize: "0.875rem", fontWeight: "bold", mt: 1, alignSelf: "flex end", }} > Xóa </Button> </ListItem> ))} </List> <Divider sx={{ my: 2 }} /> <Typography variant="h6" sx={{ fontWeight: "bold", textAlign: "right", mb: 2, color: "#1976d2", }} > Tổng tiền:{" "} <span style={{ color: "#e53935" }}> {totalAmount.toLocaleString()} VND </span> </Typography> <Box sx={{ display: "flex", justifyContent: "space between", gap: 2 }}> <Button variant="outlined" color="error" onClick={handleClearAllCart} sx={{ flex: 1, fontWeight: "bold", borderColor: "#e53935", color: "#e53935", "&:hover": { backgroundColor: "#ffe5e5", }, }} > Xóa toàn bộ </Button> <Button variant="contained" onClick={handleCheckoutClick} sx={{ flex: 1, fontWeight: "bold", backgroundColor: "#43a047", "&:hover": { backgroundColor: "#388e3c", }, }} > Mua </Button> </Box> {/* Dialogs */} <Dialog open={isDialogOpen} onClose={handleCloseDialog}> <DialogTitle>Thanh toán thành công!</DialogTitle> <DialogContent>Cảm ơn bạn đã mua hàng.</DialogContent> <DialogActions> <Button onClick={handleCloseDialog}>Đóng</Button> </DialogActions> </Dialog> <Dialog open={isErrorDialogOpen} onClose={handleCloseDialog}> <DialogTitle>Lỗi</DialogTitle> <DialogContent>Số dư không đủ.</DialogContent> <DialogActions> <Button onClick={handleCloseDialog}>Đóng</Button> </DialogActions> </Dialog> </Box> ); }; export default Cart; redesign for me

Prompt
Component Preview

About

StyledCard - A customizable cart component with item management, quantity updates, and checkout dialogs, professionally built with React and MUI. Get free template!

Share

Last updated 1 month ago