This commit is contained in:
2025-12-29 17:29:51 +07:00
parent 1bb5ad52ed
commit bf063f244c
14 changed files with 2922 additions and 66 deletions

16
src/app/cart/page.tsx Normal file
View File

@@ -0,0 +1,16 @@
import React from 'react';
import HomeCart from '@/components/Cart/Home';
import { Metadata } from 'next';
export const metadata: Metadata = {
title: 'Thông tin giỏ hàng',
description: 'Xem các sản phẩm đã thêm vào trong giỏ hàng',
};
export default function CartPage() {
return (
<>
<HomeCart />
</>
);
}

View File

@@ -0,0 +1,82 @@
import { useState } from 'react';
export const FormCart = () => {
const [showTax, setShowTax] = useState(false);
return (
<>
<div className="box-cart-info-customer">
<p className="title-section-cart font-[600]">Thông tin khách hàng</p>
<div className="list-info-customer">
<input type="text" placeholder="Họ tên*" name="user_info[name]" id="buyer_name" />
<div className="flex justify-between gap-2">
<input type="text" placeholder="Số điện thoại*" name="user_info[tel]" id="buyer_tel" />
<input type="text" name="user_info[email]" id="buyer_email" placeholder="Email" />
</div>
<input type="text" placeholder="Địa chỉ*" id="buyer_address" name="user_info[address]" />
<div className="flex justify-between gap-2">
<select name="user_info[province]" className="text-black" id="buyer_province">
<option value="0">Tỉnh/Thành phố</option>
<option value=""> Nội</option>
</select>
<select name="user_info[district]" id="js-district-holder">
<option value="0">Quận/Huyện</option>
</select>
</div>
<textarea placeholder="Ghi chú" name="user_info[note]" id="buyer_note"></textarea>
<div className="form-group-taxt">
<label className="tax-title label flex items-center gap-2">
<input
type="checkbox"
className="w-[20px]"
checked={showTax}
onChange={(e) => setShowTax(e.target.checked)}
/>
Yêu cầu xuất hóa đơn công ty
</label>
</div>
{showTax && (
<div className="js-tax-group">
<div className="form-group row">
<div className="input-taxt">
<input
type="text"
id="txtTaxName"
placeholder="Tên công ty"
className="form-control"
name="user_info[tax_company]"
/>
</div>
</div>
<div className="form-group row">
<div className="input-taxt">
<input
type="text"
id="txtTaxAddress"
placeholder="Địa chỉ công ty"
className="form-control"
name="user_info[tax_address]"
/>
</div>
</div>
<div className="form-group row">
<div className="input-taxt">
<input
type="text"
id="txtTaxCode"
placeholder="Mã số thuế"
className="form-control"
name="user_info[tax_code]"
/>
</div>
</div>
</div>
)}
</div>
</div>
</>
);
};

View File

@@ -0,0 +1,110 @@
import Image from 'next/image';
import Link from 'next/link';
import { TypeCartItem } from '@/types/cart';
import { FaSortDown, FaTrashCan } from 'react-icons/fa6';
import { formatCurrency } from '@/lib/formatPrice';
interface PropsCart {
item: TypeCartItem;
onUpdate: (id: string, quantity: number) => void;
onDelete: (id: string) => void;
}
export const ItemCart: React.FC<PropsCart> = ({ item, onUpdate, onDelete }) => {
const handleChangeQuantity = (delta: number) => {
const newQuantity = Math.max(1, parseInt(item.in_cart.quantity) + delta);
onUpdate(item._id, newQuantity);
};
return (
<div className="cart-item-info js-item-row flex justify-between">
<div className="cart-item-left flex">
<Link className="cart-item-img relative" href={item.item_info.productUrl}>
<Image
src={item.item_info.productImage.large}
alt="model"
className="bk-product-image lazy"
width={100}
height={100}
/>
{item.item_info.sale_rules?.type == 'deal' && (
<Image
className="icon-deal-cart lazy"
src="https://nguyencongpc.vn/static/assets/nguyencong_2023/images/static-icon-cart-deal.png"
width={100}
height={100}
alt="deal"
/>
)}
</Link>
<div className="cart-info-item flex-1">
<Link
href={item.item_info.productUrl}
className="cart-item-name bk-product-name line-clamp-2"
>
{item.item_info.productName}
</Link>
{item.item_info.specialOffer?.all && (
<div className="item-offer relative mt-3">
<p className="title flex items-center pl-0">
Khuyến mại{' '}
<span className="flex gap-2">
{' '}
(Chi tiết)
<FaSortDown />
</span>
</p>
<div className="item-offer-content">
{item.item_info.specialOffer.all.map((_item, idx) => (
<div key={idx} dangerouslySetInnerHTML={{ __html: _item.title }} />
))}
</div>
</div>
)}
</div>
<div className="box-change-quantity flex items-center">
<button
onClick={() => handleChangeQuantity(-1)}
className="js-quantity-change quantity-change flex items-center"
data-value="-1"
>
-
</button>
<input
type="text"
className="js-buy-quantity js-quantity-change bk-product-qty font-bold"
value={item.in_cart.quantity}
onChange={() => handleChangeQuantity(1)}
/>
<button
onClick={() => handleChangeQuantity(1)}
className="js-quantity-change quantity-change flex items-center"
data-value="1"
>
+
</button>
</div>
</div>
<div className="box-item-right flex flex-col items-end justify-between">
<div className="price-cart-item">
{item.in_cart.price == '0' ? (
<p className="price cart-item-price item-cart-price js-total-item-price font-bold">
0 đ
</p>
) : (
<p className="price cart-item-price item-cart-price js-total-item-price font-bold">
{formatCurrency(item.in_cart.total_price)} đ
</p>
)}
</div>
<button
onClick={() => onDelete(item._id)}
className="delete-item-cart item-cart-icon js-delete-item flex cursor-pointer items-center justify-center"
>
<FaTrashCan />
</button>
</div>
</div>
);
};

View File

@@ -0,0 +1,179 @@
'use client';
import { useState } from 'react';
import Image from 'next/image';
import Link from 'next/link';
import { FaChevronLeft } from 'react-icons/fa6';
import { Breadcrumb } from '@/components/Common/Breadcrumb';
import { TypeCartItem } from '@/types/cart';
import { ItemCart } from './ItemCart';
import { FormCart } from './FormCart';
import { formatCurrency } from '@/lib/formatPrice';
const HomeCart = () => {
const breadcrumbItems = [{ name: 'Giỏ hàng', url: '/cart' }];
const [cart, setCart] = useState<TypeCartItem[]>(() => {
const storedCart = localStorage.getItem('cart');
return storedCart ? JSON.parse(storedCart) : [];
});
const [payMethod, setPayMethod] = useState('2');
const updateCartItem = (id: string, quantity: number) => {
const newCart = cart.map((item) =>
item._id === id
? {
...item,
in_cart: {
...item.in_cart,
quantity: quantity.toString(),
total_price: quantity * Number(item.in_cart.price),
},
}
: item,
);
setCart(newCart);
localStorage.setItem('cart', JSON.stringify(newCart));
};
const deleteCartItem = (id: string) => {
const isConfirm = confirm('Bạn có chắc chắn xóa sản phẩm này không ?');
if (isConfirm) {
const newCart = cart.filter((item) => item._id !== id);
setCart(newCart);
localStorage.setItem('cart', JSON.stringify(newCart));
}
};
const deleteCart = () => {
const isConfirm = confirm('Bạn có chắc chắn xóa sản phẩm này không ?');
if (isConfirm) {
setCart([]);
localStorage.removeItem('cart');
}
};
// tính tổng tiền
const getTotalPrice = () => {
return formatCurrency(cart.reduce((sum, item) => sum + Number(item.in_cart.total_price), 0));
};
return (
<>
<div className="container">
<Breadcrumb items={breadcrumbItems} />
</div>
<section className="page-cart">
{cart.length === 0 ? (
<div className="not-cart pt-5">
<Image
src="https://nguyencongpc.vn/static/assets/nguyencong_2023/images/cart-home-min.png"
className="lazy"
width={130}
height={130}
alt="icon-cart"
/>
<p>Không sản phẩm nào trong giỏ hàng của bạn.</p>
<Link href="/" className="back-cart">
Tiết tục mua sắm
</Link>
</div>
) : (
<>
<div className="container-cart cart-header-title flex items-center justify-between">
<p>Giỏ hàng của bạn</p>
<Link className="back-homepage flex items-center gap-2" href="/">
<FaChevronLeft />
Mua thêm sản phẩm khác
</Link>
</div>
<div className="box-info-cart container-cart">
<div className="box-delete-all flex justify-end">
<button className="delete-cart-all" onClick={() => deleteCart()}>
{' '}
Xóa giỏ hàng{' '}
</button>
</div>
<div className="box-cart-item-list">
{cart.map((item, index) => (
<ItemCart
item={item}
key={index}
onUpdate={updateCartItem}
onDelete={deleteCartItem}
/>
))}
</div>
{/* form mua hàng */}
<FormCart />
<div className="box-payment">
<p className="title-section-cart font-bold">Phương thức thanh toán</p>
<div className="list-method-payment">
<label className="label">
<input
type="radio"
name="pay_method"
id="pay2"
value="2"
checked={payMethod === '2'}
onChange={(e) => setPayMethod(e.target.value)}
/>
Thanh toán khi nhận hàng
</label>
</div>
<p className="title-section-cart font-bold">Tổng tiền</p>
<div className="list-price">
<p className="price-total1 flex items-center justify-between">
<b className="txt">Tổng cộng</b>
<b className="price js-total-before-fee-cart-price" id="total-cart-price">
{getTotalPrice()}
</b>
</p>
<p className="price-total2 flex items-center justify-between">
<b className="txt">Thành tiền</b>
<b className="price color-red js-total-cart-price font-bold">
{getTotalPrice()} đ
</b>
</p>
<span className="has-vat">(Giá đã bao gồm VAT)</span>
</div>
</div>
<div className="list-btn-cart">
<button type="submit" className="js-send-cart font-bold">
Đt hàng
</button>
<div className="list-print-cart flex justify-between gap-2">
<Link
href="/export_file.php?file_type=xls&content_type=shopping-cart"
className="down-excel font-bold"
target="_blank"
>
Tải file excel
</Link>
<Link
href="javascript:void(0)"
rel="nofollow"
className="down-img-cart font-bold"
>
Tải nh báo giá
</Link>
<Link
href="/print/user.php?view=cart"
target="_blank"
className="print-cart font-bold"
>
in báo giá
</Link>
</div>
</div>
</div>
</>
)}
</section>
</>
);
};
export default HomeCart;

View File

@@ -44,7 +44,7 @@ const ItemProduct: React.FC<ProductItemProps> = ({ item }) => {
{item.marketPrice.toLocaleString()} {item.marketPrice.toLocaleString()}
<u>đ</u> <u>đ</u>
</p> </p>
<div className="product-percent-price">-{Math.round(item.price_off)} %</div> <div className="product-percent-price">-{Math.round(Number(item.price_off))} %</div>
</div> </div>
) : ( ) : (
<div className="product-martket-main flex items-center"></div> <div className="product-martket-main flex items-center"></div>

View File

@@ -1,11 +1,30 @@
'use client'; 'use client';
import React, { useState } from 'react'; import React, { useState, useEffect } from 'react';
import Image from 'next/image'; import Image from 'next/image';
import Link from 'next/link'; import Link from 'next/link';
import { FaMapMarkerAlt, FaBars } from 'react-icons/fa'; import { FaMapMarkerAlt, FaBars } from 'react-icons/fa';
import BoxShowroom from '@/components/Common/BoxShowroom'; import BoxShowroom from '@/components/Common/BoxShowroom';
import { TypeCartItem } from '@/types/cart';
import { formatCurrency } from '@/lib/formatPrice';
const HeaderMid: React.FC = () => { const HeaderMid: React.FC = () => {
const [cartCount, setCartCount] = useState(() => {
const storedCart = localStorage.getItem('cart');
return storedCart ? JSON.parse(storedCart).length : 0;
});
const [cart, setCart] = useState<TypeCartItem[]>(() => {
const storedCart = localStorage.getItem('cart');
return storedCart ? JSON.parse(storedCart) : [];
});
const [cartQuantity, setCartQuantity] = useState(() => {
return cart.reduce((sum: number, item) => sum + Number(item.in_cart.quantity), 0);
});
const [cartTotal, setCartTotal] = useState(() => {
return cart.reduce((sum: number, item) => sum + Number(item.in_cart.total_price), 0);
});
const PopupAddress = () => { const PopupAddress = () => {
const modal = document.getElementById('boxShowroom') as HTMLDialogElement; const modal = document.getElementById('boxShowroom') as HTMLDialogElement;
modal?.showModal(); modal?.showModal();
@@ -63,7 +82,7 @@ const HeaderMid: React.FC = () => {
</div> </div>
<div className="box-tabs-header flex items-center"> <div className="box-tabs-header flex items-center">
<Link href="/buildpc" className="item-tab-header flex-column flex items-center gap-4"> <Link href="/buildpc" className="item-tab-header flex flex-col items-center gap-4">
<p className="icon-item-tab flex items-center justify-center"> <p className="icon-item-tab flex items-center justify-center">
<i className="sprite sprite-buildpc-header"></i> <i className="sprite sprite-buildpc-header"></i>
</p> </p>
@@ -72,7 +91,7 @@ const HeaderMid: React.FC = () => {
<Link <Link
href="javascript:void(0)" href="javascript:void(0)"
className="item-tab-header flex-column flex items-center gap-4" className="item-tab-header flex flex-col items-center gap-4"
> >
<p className="icon-item-tab flex items-center justify-center"> <p className="icon-item-tab flex items-center justify-center">
<i className="sprite sprite-lienhe-header"></i> <i className="sprite sprite-lienhe-header"></i>
@@ -80,46 +99,83 @@ const HeaderMid: React.FC = () => {
<span className="font-500">Khách hàng liên hệ</span> <span className="font-500">Khách hàng liên hệ</span>
</Link> </Link>
<Link href="/tin-tuc" className="item-tab-header flex-column flex items-center gap-4"> <Link href="/tin-tuc" className="item-tab-header flex flex-col items-center gap-4">
<p className="icon-item-tab flex items-center justify-center"> <p className="icon-item-tab flex items-center justify-center">
<i className="sprite sprite-article-header"></i> <i className="sprite sprite-article-header"></i>
</p> </p>
<span className="font-weight-500">Tin tức công nghệ</span> <span className="font-weight-500">Tin tức công nghệ</span>
</Link> </Link>
<div id="js-header-cart" className="position-relative"> <div id="js-header-cart" className="relative">
<Link href="/cart" className="item-tab-header flex-column flex items-center gap-4"> <Link href="/cart" className="item-tab-header flex flex-col items-center gap-4">
<p className="icon-item-tab icon-cart-header flex items-center justify-center"> <p className="icon-item-tab icon-cart-header flex items-center justify-center">
<i className="sprite sprite-cart-header"></i> <i className="sprite sprite-cart-header"></i>
<u className="cart-count header-features-cart-amount">1</u> <u className="cart-count header-features-cart-amount">{cartCount}</u>
</p> </p>
<span className="font-weight-500">Giỏ hàng</span> <span className="font-weight-500">Giỏ hàng</span>
</Link> </Link>
<div className="cau-noi"></div> <div className="cau-noi"></div>
<div className="cart-ttip" id="js-cart-tooltip"> <div className="cart-ttip" id="js-cart-tooltip">
<div className="cart-ttip-item-container"></div> <div className="cart-ttip-item-container">
<div className="cart-ttip-price justify-content-end flex items-center gap-6"> {cart.map((item, index) => (
<div
className="compare-item js-compare-item flex items-center gap-2"
key={index}
>
<Link className="img-compare" href={item.item_info.productUrl}>
<Image
src={item.item_info.productImage.large}
width={80}
height={80}
alt={item.item_info.productName}
/>
</Link>
<div className="compare-item-text flex-1">
<Link
href={item.item_info.productUrl}
className="name-compare-item mb-10 line-clamp-2"
>
{item.item_info.productName}
</Link>
<div className="header-cart-item-price flex justify-between">
<b>x {item.in_cart.quantity}</b>
<b className="price-compare">
{item.in_cart.price == '0'
? 'Liên Hệ'
: `${formatCurrency(item.in_cart.total_price)} đ`}
</b>
</div>
</div>
</div>
))}
{/* end item */}
</div>
<div className="cart-ttip-price flex items-center justify-end gap-2">
<p>Tổng tiền hàng</p> <p>Tổng tiền hàng</p>
<p id="js-header-cart-quantity" className="font-weight-500"></p> <p id="js-header-cart-quantity" className="font-[500]">
<p id="js-header-cart-total-price" className="font-weight-700"></p> ({cartQuantity} sản phẩm)
</p>
<p id="js-header-cart-total-price" className="font-bold">
{formatCurrency(cartTotal)}đ
</p>
</div> </div>
<Link <Link
href="/cart" href="/cart"
className="cart-ttip-price-button flex items-center justify-center" className="cart-ttip-price-button flex items-center justify-center"
> >
<p className="font-weight-700">THANH TOÁN NGAY </p> <p className="font-bold">THANH TOÁN NGAY </p>
</Link> </Link>
</div> </div>
</div> </div>
<Link <Link
href="/taikhoan" href="/taikhoan"
className="user-header item-tab-header flex-column flex items-center gap-4" className="user-header item-tab-header flex flex-col items-center gap-4"
> >
<p className="icon-item-tab flex items-center justify-center"> <p className="icon-item-tab flex items-center justify-center">
<i className="sprite sprite-account-header"></i> <i className="sprite sprite-account-header"></i>
</p> </p>
<span className="font-weight-500">Tài khoản</span> <span className="font-[500]">Tài khoản</span>
</Link> </Link>
</div> </div>
</div> </div>

View File

@@ -1,10 +1,22 @@
'use client';
import { useRouter } from 'next/navigation';
import type { ProductDetailData } from '@/types'; import type { ProductDetailData } from '@/types';
import Link from 'next/link'; import Link from 'next/link';
import { BoxPrice } from './BoxPrice'; import { BoxPrice } from './BoxPrice';
import { BoxBought } from './BoxBought'; import { BoxBought } from './BoxBought';
// thêm giỏ hàng
import { addToCart } from '@/lib/ButtonCart';
export const BoxInfoRight = (item: ProductDetailData) => { export const BoxInfoRight = (item: ProductDetailData) => {
const router = useRouter();
const handleBuyNow = () => {
router.push('/cart');
addToCart(item.product_info.productId);
};
return ( return (
<> <>
<h1 className="product-name color-black line-clamp-3 font-bold"> <h1 className="product-name color-black line-clamp-3 font-bold">
@@ -81,32 +93,42 @@ export const BoxInfoRight = (item: ProductDetailData) => {
+{' '} +{' '}
</p> </p>
</div> </div>
<Link href="#" className="addCart flex flex-wrap items-center justify-center gap-3"> <button
className="addCart flex cursor-pointer flex-wrap items-center justify-center gap-3"
onClick={() => {
addToCart(item.product_info.productId);
alert('Sản phẩm đã được thêm vào giỏ hàng!');
}}
>
<i className="sprite sprite-cart-detail"></i> <i className="sprite sprite-cart-detail"></i>
<p className="title-cart">Thêm vào giỏ hàng</p> <p className="title-cart">Thêm vào giỏ hàng</p>
</Link> </button>
<input type="hidden" className="js-buy-quantity-temp" value="1" /> <input type="hidden" className="js-buy-quantity-temp" value="1" />
</div> </div>
<div id="detail-buy-ads" className="detail-buy grid grid-cols-2 gap-2"> <div
<Link href="#" className="detail-buy-now col-span-2"> id="detail-buy-ads"
className="detail-buy grid grid-cols-2 gap-2"
onClick={() => handleBuyNow()}
>
<button className="detail-buy-now col-span-2 cursor-pointer">
<span>ĐT MUA NGAY</span> <span>ĐT MUA NGAY</span>
Giao hàng tận nơi nhanh chóng Giao hàng tận nơi nhanh chóng
</Link> </button>
<Link href="#" className="detail-add-cart"> <button className="detail-add-cart">
<span>TRẢ GÓP QUA HỒ </span> <span>TRẢ GÓP QUA HỒ </span>
Chỉ từ 2.665.000/ tháng Chỉ từ 2.665.000/ tháng
</Link> </button>
<Link href="#" className="detail-add-cart"> <button className="detail-add-cart">
<span>TRẢ GÓP QUA THẺ</span> <span>TRẢ GÓP QUA THẺ</span>
Chỉ từ 1.332.500/ tháng Chỉ từ 1.332.500/ tháng
</Link> </button>
</div> </div>
</> </>
)} )}
n{/* yên tâm mua hàng */} {/* yên tâm mua hàng */}
<div className="box-product-policy-detal boder-radius-10" style={{ marginTop: '24px' }}> <div className="box-product-policy-detal boder-radius-10" style={{ marginTop: '24px' }}>
<h2 className="title font-[600]">Yên tâm mua hàng</h2> <h2 className="title font-[600]">Yên tâm mua hàng</h2>
<div className="list-showroom-detail flex flex-wrap justify-between"> <div className="list-showroom-detail flex flex-wrap justify-between">

View File

@@ -28,7 +28,7 @@ export const ListComment = () => {
</div> </div>
</div>{' '} </div>{' '}
{/* content */} {/* content */}
<div className="comment-content mt-3 rounded p-2"> <div className="comment-content relative mt-3 rounded p-2">
<p>{item.content}</p> <p>{item.content}</p>
<div className="info_feeback mt-2 flex items-center gap-2"> <div className="info_feeback mt-2 flex items-center gap-2">
<i className="sprite sprite-icon-reply-detail"></i> <i className="sprite sprite-icon-reply-detail"></i>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,69 @@
import { TypeCartItem } from '@/types/cart';
// data
import { productData } from '@/data/ListProduct';
export const addToCart = (productId: string | number) => {
// Lấy giỏ hàng hiện tại từ localStorage
const cart: TypeCartItem[] = JSON.parse(localStorage.getItem('cart') || '[]');
console.log('chay tiếp');
const product = productData.find((p) => p.productId == productId);
if (!product) return;
// Kiểm tra sản phẩm đã có trong giỏ chưa
const existing = cart.find((item) => item.item_info.id == productId);
if (existing) {
// Nếu có rồi thì tăng số lượng
existing.in_cart.quantity = (parseInt(existing.in_cart.quantity) + 1).toString();
existing.in_cart.total_price =
Number(existing.in_cart.quantity) * Number(existing.in_cart.price);
} else {
// Nếu chưa có thì thêm mới
const cartItem = {
_id: `product-${product.id}-0`,
item_type: 'product',
item_id: `${product.id}-0`,
item_info: {
id: product.productId,
priceUnit: product.priceUnit,
marketPrice: product.marketPrice,
hasVAT: product.hasVAT,
weight: product.weight,
price: product.price,
currency: product.currency,
bulk_price: product.bulk_price,
configurable: product.configurable,
productName: product.productName,
productImage: product.productImage,
productUrl: product.productUrl,
brand: product.brand,
productSKU: product.productSKU,
quantity: product.quantity,
addon: product.addon,
warranty: product.warranty,
variants: product.variants,
variant_option: product.variant_option,
extend: product.extend,
categories: product.categories,
specialOffer: product.specialOffer,
specialOfferGroup: product.specialOfferGroup,
sale_rules: product.sale_rules,
},
in_cart: {
quantity: '1',
buyer_note: '',
price: product.price,
total_price: Number(product.quantity) * Number(product.price),
weight: '0',
total_weight: '0',
},
};
cart.push(cartItem);
}
// Lưu lại vào localStorage
localStorage.setItem('cart', JSON.stringify(cart));
};

View File

@@ -3433,7 +3433,7 @@ textarea::placeholder {
-o-transition: color 0.2s ease-out; -o-transition: color 0.2s ease-out;
transition: color 0.2s ease-out; transition: color 0.2s ease-out;
} }
.page-product-detail .box-content-product-detail .detail-buy a { .page-product-detail .box-content-product-detail .detail-buy button {
padding: 8px 12px; padding: 8px 12px;
text-align: center; text-align: center;
background: #0a76e4; background: #0a76e4;
@@ -3441,16 +3441,16 @@ textarea::placeholder {
color: #fff; color: #fff;
font-size: 13px; font-size: 13px;
} }
.page-product-detail .box-content-product-detail .detail-buy a:first-child { .page-product-detail .box-content-product-detail .detail-buy button:first-child {
background: #e31223; background: #e31223;
} }
.page-product-detail .box-content-product-detail .detail-buy a:hover { .page-product-detail .box-content-product-detail .detail-buy button:hover {
background: #007eff !important; background: #007eff !important;
} }
.page-product-detail .box-content-product-detail .detail-buy a:first-child:hover { .page-product-detail .box-content-product-detail .detail-buy button:first-child:hover {
background: #ff0015 !important; background: #ff0015 !important;
} }
.page-product-detail .box-content-product-detail .detail-buy a span { .page-product-detail .box-content-product-detail .detail-buy button span {
width: 100%; width: 100%;
float: left; float: left;
font-weight: 20px; font-weight: 20px;
@@ -4458,7 +4458,7 @@ textarea::placeholder {
color: var(--swiper-theme-color); color: var(--swiper-theme-color);
} }
.page-cart .box-info-cart { .page-cart .box-info-cart {
padding: 12px 0; padding: 12px;
margin-bottom: 44px; margin-bottom: 44px;
} }
.page-cart .box-delete-all { .page-cart .box-delete-all {
@@ -4497,10 +4497,13 @@ textarea::placeholder {
} }
.page-cart .cart-item-info .quantity-change { .page-cart .cart-item-info .quantity-change {
border: 1px solid #d6d6d6; border: 1px solid #d6d6d6;
padding: 10px 8px; width: 32px;
height: 32px; height: 32px;
cursor: pointer; cursor: pointer;
color: #b8b8b8; color: #b8b8b8;
display: flex;
align-items: center;
justify-content: center;
} }
.page-cart .cart-item-info .quantity-change:hover { .page-cart .cart-item-info .quantity-change:hover {
color: var(--swiper-theme-color); color: var(--swiper-theme-color);
@@ -4540,12 +4543,12 @@ textarea::placeholder {
margin-bottom: 12px; margin-bottom: 12px;
} }
.page-cart .box-cart-info-customer { .page-cart .box-cart-info-customer {
margin: 20px 12px 16px; margin: 20px 0;
} }
.page-cart .box-cart-info-customer .list-info-customer input, .page-cart .box-cart-info-customer .list-info-customer input,
.page-cart .box-cart-info-customer .list-info-customer select, .page-cart .box-cart-info-customer .list-info-customer select,
.page-cart .box-cart-info-customer .list-info-customer textarea { .page-cart .box-cart-info-customer .list-info-customer textarea {
width: 100%; width: 97%;
border: 1px solid #d6d6d6; border: 1px solid #d6d6d6;
padding: 13px 12px; padding: 13px 12px;
border-radius: 5px; border-radius: 5px;
@@ -4554,7 +4557,7 @@ textarea::placeholder {
outline: 0; outline: 0;
} }
.page-cart .box-cart-info-customer .list-info-customer select { .page-cart .box-cart-info-customer .list-info-customer select {
color: #b8b8b8; color: #000;
} }
.page-cart .box-cart-info-customer .list-info-customer input::-webkit-input-placeholder, .page-cart .box-cart-info-customer .list-info-customer input::-webkit-input-placeholder,
.page-cart .box-cart-info-customer .list-info-customer textarea::-webkit-input-placeholder { .page-cart .box-cart-info-customer .list-info-customer textarea::-webkit-input-placeholder {
@@ -4589,9 +4592,7 @@ textarea::placeholder {
width: max-content; width: max-content;
margin-bottom: 0; margin-bottom: 0;
} }
.page-cart .box-payment {
padding: 0 12px;
}
.page-cart .box-payment .list-method-payment { .page-cart .box-payment .list-method-payment {
margin-bottom: 16px; margin-bottom: 16px;
} }
@@ -4603,7 +4604,7 @@ textarea::placeholder {
} }
.page-cart .box-payment .has-vat { .page-cart .box-payment .has-vat {
width: 100%; width: 100%;
float: left; display: block;
font-size: 16px; font-size: 16px;
text-align: right; text-align: right;
margin-top: 10px; margin-top: 10px;
@@ -4645,8 +4646,7 @@ textarea::placeholder {
.page-cart .not-cart { .page-cart .not-cart {
margin: 0 auto; margin: 0 auto;
text-align: center; text-align: center;
padding: 30px 0; padding: 50px 8px;
padding: 0 8px;
max-width: 1216px; max-width: 1216px;
display: -webkit-box; display: -webkit-box;
display: -ms-flexbox; display: -ms-flexbox;

46
src/types/cart/index.ts Normal file
View File

@@ -0,0 +1,46 @@
import { ProductImage, Brand, Category, SaleRules, Extend, SpecialOfferItem } from '@/types';
export interface CartProductInfo {
id: number;
productName: string;
price: string | number;
productImage: ProductImage;
productUrl: string;
brand: Brand;
warranty: string;
quantity: number;
priceUnit?: string;
marketPrice?: number;
hasVAT?: number;
weight?: number;
currency?: string;
bulk_price?: [];
configurable?: number;
addon?: [];
variants?: [];
variant_option?: [];
extend?: Extend;
categories?: Category[];
specialOffer?: { other?: SpecialOfferItem[]; all?: SpecialOfferItem[] };
specialOfferGroup?: [];
sale_rules?: SaleRules;
}
// Thông tin sản phẩm trong giỏ
export interface InCart {
quantity: string;
buyer_note: string;
price: number | string;
total_price: number;
weight: string;
total_weight: string;
}
// Item trong giỏ hàng
export interface TypeCartItem {
_id: string;
item_type: string;
item_id: string;
item_info: CartProductInfo;
in_cart: InCart;
}

View File

@@ -72,8 +72,7 @@ export interface SpecialOfferItem {
from_time: string; from_time: string;
to_time: string; to_time: string;
url: string; url: string;
description: description: string;
string;
status: number; status: number;
} }
@@ -83,7 +82,7 @@ export interface Product {
priceUnit: string; priceUnit: string;
marketPrice: number; marketPrice: number;
price: string | number; price: string | number;
price_off: number; price_off: number | string;
currency: string; currency: string;
sale_rules: SaleRules; sale_rules: SaleRules;
lastUpdate: string; lastUpdate: string;
@@ -108,7 +107,7 @@ export interface Product {
config_count: number; config_count: number;
configurable: number; configurable: number;
component_count: number; component_count: number;
specialOffer: { other?: SpecialOfferItem[], all?: SpecialOfferItem[] }; specialOffer: { other?: SpecialOfferItem[]; all?: SpecialOfferItem[] };
specialOfferGroup: []; specialOfferGroup: [];
productType: { productType: {
isNew: number; isNew: number;
@@ -131,5 +130,4 @@ export interface Product {
categories: Category[]; categories: Category[];
} }
export type TypeListProduct = Product[]; export type TypeListProduct = Product[];

View File

@@ -19,14 +19,14 @@ interface Brand {
} }
// Product Image // Product Image
export interface ProductImage { export interface ProductImageDetail {
small: string; small: string;
large: string; large: string;
original: string; original: string;
} }
export interface ProductImageGallery { export interface ProductImageGallery {
size: ProductImage; size: ProductImageDetail;
alt: string; alt: string;
folder: string; folder: string;
} }
@@ -135,7 +135,7 @@ export interface ProductInfo {
productSKU: string; productSKU: string;
productUrl: string; productUrl: string;
productName: string; productName: string;
productImage: ProductImage; productImage: ProductImageDetail;
price: string; price: string;
quantity: string; quantity: string;
currency: string; currency: string;