Untitled
unknown
plain_text
a year ago
18 kB
7
Indexable
import { useState, useEffect } from "react";
import Main from "../ultils/container";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faTrash } from "@fortawesome/free-solid-svg-icons";
import "../assets/styles/ShoppingCart.scss";
import { ConfigProvider, Table, Checkbox, Button, Input } from "antd";
import { createStyles } from "antd-style";
import { getCart, deleteCart, updateCart } from "../api/ShoppingCart";
import OptionCart from "../components/UpdateOptionCart/OptionCart";
const useStyle = createStyles(({ css, token }) => {
const { antCls } = token;
return {
customTable: css`
${antCls}-table-container {
max-height: 500px; /* Đặt chiều cao tối đa cho bảng */
overflow-y: auto; /* Cuộn theo chiều dọc */
overflow-x: auto; /* Cuộn theo chiều ngang nếu cần */
${antCls}-table-body {
max-height: 500px;
overflow-y: auto;
scrollbar-width: thin;
scrollbar-color: #eaeaea transparent;
scrollbar-gutter: stable;
}
/* Scrollbar tùy chỉnh */
&::-webkit-scrollbar {
width: 8px; /* Chiều rộng của thanh cuộn */
height: 8px; /* Chiều cao của thanh cuộn ngang */
}
&::-webkit-scrollbar-track {
background: transparent; /* Màu nền thanh cuộn */
}
&::-webkit-scrollbar-thumb {
background-color: #eaeaea; /* Màu thanh cuộn */
border-radius: 4px; /* Bo góc */
}
}
`,
};
});
const ShoppingCart = () => {
const { styles } = useStyle();
const [cartItems, setCartItems] = useState([]);
const [selectedItems, setSelectedItems] = useState([]);
const [isSystemLocked, setIsSystemLocked] = useState(false);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [showSizePopup, setShowSizePopup] = useState(false);
const [currentItemId, setCurrentItemId] = useState(null);
// Categories để cập nhật size/color
const categories = [
{ name: "Size", tags: ["S", "M", "L", "XL"] },
{ name: "Color", tags: ["Red", "Black", "White"] },
];
const [selectedTags, setSelectedTags] = useState({});
// Hàm gọi API
const fetchCartItems = async () => {
const token = localStorage.getItem("token");
try {
setLoading(true);
const data = await getCart(token); // Gọi API từ file ShoppingCart.js
const formattedData = data.map((item) => ({
id: item.cartItemId,
name: item.productName || "Unknown Product",
size: item.optionValue1 || "N/A",
color: item.optionValue2 || "N/A",
price: item.price || 0, // Giá mặc định nếu không có giá trị
quantity: item.quantity || 1, // Số lượng mặc định
maxQuantity: item.maxQuantity || 50, // Giá trị mặc định của maxQuantity
image:
item.productImages?.find((img) => img.isFeatured)?.urlImage || // Tìm ảnh nổi bật
item.productImages?.[0]?.urlImage || // Nếu không có ảnh nổi bật, lấy ảnh đầu tiên
"/img/default-image.jpg", // Ảnh mặc định nếu không có ảnh
selected: false,
}));
setCartItems(formattedData);
setLoading(false);
} catch (error) {
setError(error.message);
setLoading(false);
}
};
useEffect(() => {
fetchCartItems();
}, []);
const handleSelectItem = (id) => {
setSelectedItems((prevSelected) =>
prevSelected.includes(id)
? prevSelected.filter((item) => item !== id)
: [...prevSelected, id]
);
};
const handleRemoveSelectedItems = async () => {
const token = localStorage.getItem("token"); // Lấy token từ localStorage
const confirmRemove = window.confirm(
"Are you sure you want to remove the selected items from your cart?"
);
if (!confirmRemove) return;
try {
setIsSystemLocked(true); // Khóa hệ thống trong khi xóa
const promises = selectedItems.map((id) =>
deleteCart(id, token) // Gọi API xóa từng mục
);
await Promise.all(promises); // Chờ tất cả API hoàn thành
// Cập nhật lại giỏ hàng sau khi xóa
setCartItems((prevItems) =>
prevItems.filter((item) => !selectedItems.includes(item.id))
);
setSelectedItems([]); // Reset danh sách đã chọn
} catch (error) {
alert(`Error: ${error.message}`); // Hiển thị lỗi nếu có
} finally {
setIsSystemLocked(false); // Mở khóa hệ thống
}
};
const handleSelectAll = () => {
if (selectedItems.length === cartItems.length) {
setSelectedItems([]); // Bỏ chọn tất cả
} else {
setSelectedItems(cartItems.map((item) => item.id)); // Chọn tất cả
}
};
const renderHeader = () => {
if (selectedItems.length > 0) {
return (
<div className="selected-header">
<Checkbox
indeterminate={
selectedItems.length > 0 && selectedItems.length < cartItems.length
}
checked={selectedItems.length === cartItems.length}
onChange={handleSelectAll}
className="custom-checkbox"
disabled={isSystemLocked} // Không cho phép chọn khi hệ thống bị khóa
/>
<span className="selected-text">
Selected ({selectedItems.length})
</span>
<Button
danger
onClick={handleRemoveSelectedItems} // Gọi hàm xóa các mục đã chọn
className="delete-selected-btn"
disabled={isSystemLocked} // Không cho phép xóa khi hệ thống bị khóa
>
<FontAwesomeIcon
icon={faTrash}
style={{
fontSize: "15px",
}}
/>
</Button>
</div>
);
}
return null;
};
const handleDecreaseQuantityWithConfirm = (id) => {
const token = localStorage.getItem("token"); // Lấy token từ localStorage
let isConfirmed = false;
setCartItems((prevItems) => {
const item = prevItems.find((item) => item.id === id);
if (!item) return prevItems;
const newQuantity = item.quantity - 1;
if (newQuantity <= 0 && !isConfirmed) {
isConfirmed = true;
setTimeout(() => {
const confirmRemove = window.confirm(
"The number of products has reached 0. Do you want to remove this product from your cart?"
);
if (confirmRemove) {
// Xóa sản phẩm khỏi giỏ hàng
setCartItems((currentItems) =>
currentItems.filter((item) => item.id !== id)
);
// Gọi API để xóa sản phẩm
deleteCart(id, token).catch((error) => {
alert(`Error: ${error.message}`);
});
} else {
// Đặt lại số lượng thành 1
setCartItems((currentItems) =>
currentItems.map((item) =>
item.id === id ? { ...item, quantity: 1 } : item
)
);
// Gọi API để cập nhật số lượng thành 1
updateCart(id, 1, token).catch((error) => {
alert(`Error: ${error.message}`);
});
}
}, 0);
} else {
// Gọi API để cập nhật số lượng
updateCart(id, newQuantity, token).catch((error) => {
alert(`Error: ${error.message}`);
});
}
return prevItems.map((item) =>
item.id === id ? { ...item, quantity: newQuantity } : item
);
});
};
const handleQuantityInputChange = (id, value) => {
// Cập nhật trực tiếp giá trị người dùng đang nhập
setCartItems((prevItems) =>
prevItems.map((item) =>
item.id === id ? { ...item, quantity: value } : item
)
);
};
const handleBlurQuantity = (id) => {
const token = localStorage.getItem("token"); // Lấy token từ localStorage
const currentItem = cartItems.find((item) => item.id === id);
if (!currentItem) return;
let newQuantity = parseInt(currentItem.quantity, 10);
// Kiểm tra logic chỉ khi người dùng blur (rời khỏi ô nhập liệu)
if (isNaN(newQuantity) || newQuantity < 1) {
// Nếu giá trị không hợp lệ hoặc nhỏ hơn 1, đặt thành 1
alert("Invalid value! Quantity must be greater than or equal to 1.");
newQuantity = 1;
} else if (newQuantity > 10) {
// Nếu giá trị vượt quá 10, đặt thành 10 và hiển thị thông báo
alert("Product quantity limit is 10. If you want to buy more, please contact us.");
newQuantity = 10;
}
// Gọi API để cập nhật số lượng sau khi kiểm tra
updateCart(id, newQuantity, token)
.then(() => {
// Thành công, cập nhật lại state
setCartItems((prevItems) =>
prevItems.map((item) =>
item.id === id ? { ...item, quantity: newQuantity.toString() } : item
)
);
})
.catch((error) => {
alert(`Error: ${error.message}`);
});
};
const handleQuantityChange = (id, type) => {
const token = localStorage.getItem("token");
setCartItems((prevItems) => {
return prevItems.map((item) => {
if (item.id === id) {
const newQuantity =
type === "increase" ? item.quantity + 1 : item.quantity - 1;
if (newQuantity < 0) return item;
// Gọi API cập nhật số lượng
updateCart(id, newQuantity, token).catch((error) => {
alert(`Error: ${error.message}`);
});
return { ...item, quantity: newQuantity };
}
return item;
});
});
};
const handleEditSize = (id) => {
const item = cartItems.find((item) => item.id === id);
setCurrentItemId(id);
setSelectedTags({
Size: item.size,
Color: item.color,
});
setShowSizePopup(true);
};
const handleSaveSize = async () => {
const token = localStorage.getItem("token");
const currentItem = cartItems.find((item) => item.id === currentItemId);
if (!currentItem) return;
try {
const requestBody = {
cartItemId: currentItemId,
variantId: currentItem.variantId,
quantity: currentItem.quantity,
options: {
...selectedTags, // Dynamically include the selected options
},
};
// Call the API
await updateCart(requestBody, token);
// Update the cart state
setCartItems((prevItems) =>
prevItems.map((item) =>
item.id === currentItemId
? {
...item,
options: {
...item.options,
...selectedTags, // Update selected options
},
}
: item
)
);
alert("Options updated successfully!");
} catch (error) {
alert(`Error: ${error.message}`);
} finally {
setShowSizePopup(false);
}
};
const handleRemoveItem = async (cartItemId) => {
const token = localStorage.getItem("token");
const confirmRemove = window.confirm(
"Are you sure you want to remove this item from your cart?"
);
if (!confirmRemove) return;
try {
setIsSystemLocked(true);
await deleteCart(cartItemId, token); // Gọi hàm xóa
setCartItems((prevItems) => prevItems.filter((item) => item.id !== cartItemId)); // Cập nhật lại giỏ hàng
} catch (error) {
alert(`Error: ${error.message}`); // Hiển thị lỗi nếu có
} finally {
setIsSystemLocked(false);
}
};
const columns = [
{
title: selectedItems.length === 0 ? (
<Checkbox
indeterminate={
selectedItems.length > 0 &&
selectedItems.length < cartItems.length
}
checked={selectedItems.length === cartItems.length}
onChange={handleSelectAll}
disabled={isSystemLocked}
>
Select All
</Checkbox>
) : null,
dataIndex: "selected",
width: 105,
render: (_, record) => (
<Checkbox
checked={selectedItems.includes(record.id)}
onChange={() => handleSelectItem(record.id)}
disabled={isSystemLocked}
/>
),
},
{
title: "Product",
dataIndex: "name",
width: 350,
render: (_, record) => {
console.log("Image URL:", record.image); // Log đường dẫn image vào console
return (
<div className="product-info">
<img
src={record.image}
alt={record.name}
className="product-info-image"
style={{
width: "50px",
height: "50px",
objectFit: "cover",
marginRight: "10px",
}}
/>
<div className="product-info-details">
<p className="product-info-name">{record.name}</p>
<p className="product-info-size">
<Button
type="link"
onClick={() => handleEditSize(record.id)}
disabled={isSystemLocked}
>
{record.size}, {record.color}
</Button>
</p>
</div>
</div>
);
},
},
{
title: "Price",
dataIndex: "price",
width: 135,
align: "center",
render: (price) => `${price.toLocaleString()} $`,
},
{
title: "Quantity",
dataIndex: "quantity",
align: "center",
width: 140,
render: (_, record) => (
<div className="quantity-controls">
{/* Nút giảm số lượng */}
<Button
onClick={() => handleDecreaseQuantityWithConfirm(record.id)}
disabled={isSystemLocked} // Không khóa giảm số lượng
>
-
</Button>
{/* Ô nhập số lượng */}
<Input
type="number"
value={record.quantity} // Hiển thị số lượng hiện tại
onChange={(e) => handleQuantityInputChange(record.id, e.target.value)} // Cập nhật khi nhập
onBlur={() => handleBlurQuantity(record.id)} // Kiểm tra logic khi mất tiêu điểm
className="quantity-input"
style={{ textAlign: "center" }}
/>
{/* Nút tăng số lượng */}
<Button
onClick={() => handleQuantityChange(record.id, "increase")}
disabled={isSystemLocked} // Cho phép tăng mà không giới hạn
>
+
</Button>
</div>
),
},
{
title: "Into Money",
dataIndex: "intoMoney",
width: 135,
align: "center",
render: (_, record) => {
const price = record.price || 0; // Giá trị mặc định nếu null hoặc undefined
const quantity = record.quantity || 0; // Giá trị mặc định nếu null hoặc undefined
const intoMoney = price * quantity;
return (
<span style={{ color: "#ff385c", fontWeight: "bold" }}>
{intoMoney.toLocaleString()} $
</span>
);
},
},
{
title: "Remove",
dataIndex: "actions",
width: 70,
align: "center",
render: (_, record) => (
<Button danger onClick={() => handleRemoveItem(record.id)}>
<FontAwesomeIcon icon={faTrash} />
</Button>
),
},
];
if (loading) {
return <div>Loading...</div>;
}
if (error) {
return <div>Error: {error}</div>;
}
return (
<ConfigProvider
theme={{
token: {
colorPrimary: "#ff385c",
colorPrimaryHover: "#e0314b",
},
}}
>
<Main>
<div className="shopping-cart">
<h2 className="shopping-cart-title">User Shopping Cart</h2>
<p className="shopping-cart-subtitle">Final Step Before Your Payment</p>
<div> {renderHeader()}
<Table
className={styles.customTable}
columns={columns}
dataSource={cartItems.map((item) => ({ ...item, key: item.id }))}
pagination={false}
locale={{
emptyText: (
<div className="empty-cart-table">
<img
src="/img/Empty-Cart.jpg" // Đường dẫn ảnh giỏ hàng trống
alt="Empty Cart"
style={{ width: "200px", marginBottom: "10px" }}
/>
<p style={{ fontSize: "18px", fontWeight: "bold", color: "#555" }}>
Your cart is empty. Start shopping now!
</p>
</div>
),
}}
/>
</div>
</div>
{showSizePopup && (
<OptionCart
categories={categories} // Truyền danh mục option từ API hoặc static
selectedTags={selectedTags} // Trạng thái option đã chọn
onChange={(category, tag) =>
setSelectedTags({ ...selectedTags, [category]: tag })
} // Cập nhật khi chọn option
onSave={handleSaveSize} // Hàm lưu và gọi API
onCancel={() => setShowSizePopup(false)} // Đóng popup
/>
)}
</Main>
</ConfigProvider>
);
};
export default ShoppingCart;
Editor is loading...
Leave a Comment