Untitled

 avatar
unknown
plain_text
a month ago
18 kB
2
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