update
This commit is contained in:
16
src/app/cart/page.tsx
Normal file
16
src/app/cart/page.tsx
Normal 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 />
|
||||
</>
|
||||
);
|
||||
}
|
||||
82
src/components/Cart/Home/FormCart/index.tsx
Normal file
82
src/components/Cart/Home/FormCart/index.tsx
Normal 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="">Hà 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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
110
src/components/Cart/Home/ItemCart/index.tsx
Normal file
110
src/components/Cart/Home/ItemCart/index.tsx
Normal 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>
|
||||
);
|
||||
};
|
||||
179
src/components/Cart/Home/index.tsx
Normal file
179
src/components/Cart/Home/index.tsx
Normal 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 có 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;
|
||||
@@ -44,7 +44,7 @@ const ItemProduct: React.FC<ProductItemProps> = ({ item }) => {
|
||||
{item.marketPrice.toLocaleString()}
|
||||
<u>đ</u>
|
||||
</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 className="product-martket-main flex items-center"></div>
|
||||
|
||||
@@ -1,11 +1,30 @@
|
||||
'use client';
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import { FaMapMarkerAlt, FaBars } from 'react-icons/fa';
|
||||
import BoxShowroom from '@/components/Common/BoxShowroom';
|
||||
import { TypeCartItem } from '@/types/cart';
|
||||
import { formatCurrency } from '@/lib/formatPrice';
|
||||
|
||||
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 modal = document.getElementById('boxShowroom') as HTMLDialogElement;
|
||||
modal?.showModal();
|
||||
@@ -63,7 +82,7 @@ const HeaderMid: React.FC = () => {
|
||||
</div>
|
||||
|
||||
<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">
|
||||
<i className="sprite sprite-buildpc-header"></i>
|
||||
</p>
|
||||
@@ -72,7 +91,7 @@ const HeaderMid: React.FC = () => {
|
||||
|
||||
<Link
|
||||
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">
|
||||
<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>
|
||||
</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">
|
||||
<i className="sprite sprite-article-header"></i>
|
||||
</p>
|
||||
<span className="font-weight-500">Tin tức công nghệ</span>
|
||||
</Link>
|
||||
|
||||
<div id="js-header-cart" className="position-relative">
|
||||
<Link href="/cart" className="item-tab-header flex-column flex items-center gap-4">
|
||||
<div id="js-header-cart" className="relative">
|
||||
<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">
|
||||
<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>
|
||||
<span className="font-weight-500">Giỏ hàng</span>
|
||||
</Link>
|
||||
<div className="cau-noi"></div>
|
||||
<div className="cart-ttip" id="js-cart-tooltip">
|
||||
<div className="cart-ttip-item-container"></div>
|
||||
<div className="cart-ttip-price justify-content-end flex items-center gap-6">
|
||||
<div className="cart-ttip-item-container">
|
||||
{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 id="js-header-cart-quantity" className="font-weight-500"></p>
|
||||
<p id="js-header-cart-total-price" className="font-weight-700"></p>
|
||||
<p id="js-header-cart-quantity" className="font-[500]">
|
||||
({cartQuantity} sản phẩm)
|
||||
</p>
|
||||
<p id="js-header-cart-total-price" className="font-bold">
|
||||
{formatCurrency(cartTotal)}đ
|
||||
</p>
|
||||
</div>
|
||||
<Link
|
||||
href="/cart"
|
||||
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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Link
|
||||
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">
|
||||
<i className="sprite sprite-account-header"></i>
|
||||
</p>
|
||||
<span className="font-weight-500">Tài khoản</span>
|
||||
<span className="font-[500]">Tài khoản</span>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,22 @@
|
||||
'use client';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import type { ProductDetailData } from '@/types';
|
||||
import Link from 'next/link';
|
||||
|
||||
import { BoxPrice } from './BoxPrice';
|
||||
import { BoxBought } from './BoxBought';
|
||||
|
||||
// thêm giỏ hàng
|
||||
import { addToCart } from '@/lib/ButtonCart';
|
||||
|
||||
export const BoxInfoRight = (item: ProductDetailData) => {
|
||||
const router = useRouter();
|
||||
|
||||
const handleBuyNow = () => {
|
||||
router.push('/cart');
|
||||
addToCart(item.product_info.productId);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1 className="product-name color-black line-clamp-3 font-bold">
|
||||
@@ -81,32 +93,42 @@ export const BoxInfoRight = (item: ProductDetailData) => {
|
||||
+{' '}
|
||||
</p>
|
||||
</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>
|
||||
<p className="title-cart">Thêm vào giỏ hàng</p>
|
||||
</Link>
|
||||
</button>
|
||||
<input type="hidden" className="js-buy-quantity-temp" value="1" />
|
||||
</div>
|
||||
|
||||
<div id="detail-buy-ads" className="detail-buy grid grid-cols-2 gap-2">
|
||||
<Link href="#" className="detail-buy-now col-span-2">
|
||||
<div
|
||||
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>
|
||||
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Ồ SƠ</span>
|
||||
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>
|
||||
Chỉ từ 1.332.500₫/ tháng
|
||||
</Link>
|
||||
</button>
|
||||
</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' }}>
|
||||
<h2 className="title font-[600]">Yên tâm mua hàng</h2>
|
||||
<div className="list-showroom-detail flex flex-wrap justify-between">
|
||||
|
||||
@@ -28,7 +28,7 @@ export const ListComment = () => {
|
||||
</div>
|
||||
</div>{' '}
|
||||
{/* content */}
|
||||
<div className="comment-content mt-3 rounded p-2">
|
||||
<div className="comment-content relative mt-3 rounded p-2">
|
||||
<p>{item.content}</p>
|
||||
<div className="info_feeback mt-2 flex items-center gap-2">
|
||||
<i className="sprite sprite-icon-reply-detail"></i>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
69
src/lib/ButtonCart/index.ts
Normal file
69
src/lib/ButtonCart/index.ts
Normal 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));
|
||||
};
|
||||
@@ -3433,7 +3433,7 @@ textarea::placeholder {
|
||||
-o-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;
|
||||
text-align: center;
|
||||
background: #0a76e4;
|
||||
@@ -3441,16 +3441,16 @@ textarea::placeholder {
|
||||
color: #fff;
|
||||
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;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
.page-product-detail .box-content-product-detail .detail-buy a span {
|
||||
.page-product-detail .box-content-product-detail .detail-buy button span {
|
||||
width: 100%;
|
||||
float: left;
|
||||
font-weight: 20px;
|
||||
@@ -4458,7 +4458,7 @@ textarea::placeholder {
|
||||
color: var(--swiper-theme-color);
|
||||
}
|
||||
.page-cart .box-info-cart {
|
||||
padding: 12px 0;
|
||||
padding: 12px;
|
||||
margin-bottom: 44px;
|
||||
}
|
||||
.page-cart .box-delete-all {
|
||||
@@ -4497,10 +4497,13 @@ textarea::placeholder {
|
||||
}
|
||||
.page-cart .cart-item-info .quantity-change {
|
||||
border: 1px solid #d6d6d6;
|
||||
padding: 10px 8px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
cursor: pointer;
|
||||
color: #b8b8b8;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.page-cart .cart-item-info .quantity-change:hover {
|
||||
color: var(--swiper-theme-color);
|
||||
@@ -4540,12 +4543,12 @@ textarea::placeholder {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.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 select,
|
||||
.page-cart .box-cart-info-customer .list-info-customer textarea {
|
||||
width: 100%;
|
||||
width: 97%;
|
||||
border: 1px solid #d6d6d6;
|
||||
padding: 13px 12px;
|
||||
border-radius: 5px;
|
||||
@@ -4554,7 +4557,7 @@ textarea::placeholder {
|
||||
outline: 0;
|
||||
}
|
||||
.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 textarea::-webkit-input-placeholder {
|
||||
@@ -4589,9 +4592,7 @@ textarea::placeholder {
|
||||
width: max-content;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.page-cart .box-payment {
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.page-cart .box-payment .list-method-payment {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
@@ -4603,7 +4604,7 @@ textarea::placeholder {
|
||||
}
|
||||
.page-cart .box-payment .has-vat {
|
||||
width: 100%;
|
||||
float: left;
|
||||
display: block;
|
||||
font-size: 16px;
|
||||
text-align: right;
|
||||
margin-top: 10px;
|
||||
@@ -4645,8 +4646,7 @@ textarea::placeholder {
|
||||
.page-cart .not-cart {
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
padding: 30px 0;
|
||||
padding: 0 8px;
|
||||
padding: 50px 8px;
|
||||
max-width: 1216px;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
|
||||
46
src/types/cart/index.ts
Normal file
46
src/types/cart/index.ts
Normal 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;
|
||||
}
|
||||
@@ -56,25 +56,24 @@ export interface Category {
|
||||
}
|
||||
|
||||
export interface Extend {
|
||||
pixel_code?: string;
|
||||
review_count?: string;
|
||||
review_score?: string;
|
||||
buy_count?: string;
|
||||
pixel_code?: string;
|
||||
review_count?: string;
|
||||
review_score?: string;
|
||||
buy_count?: string;
|
||||
}
|
||||
|
||||
export interface SpecialOfferItem {
|
||||
id: number;
|
||||
title: string;
|
||||
type: string;
|
||||
thumbnail: string;
|
||||
cash_value: number;
|
||||
quantity: number;
|
||||
from_time: string;
|
||||
to_time: string;
|
||||
url: string;
|
||||
description:
|
||||
string;
|
||||
status: number;
|
||||
export interface SpecialOfferItem {
|
||||
id: number;
|
||||
title: string;
|
||||
type: string;
|
||||
thumbnail: string;
|
||||
cash_value: number;
|
||||
quantity: number;
|
||||
from_time: string;
|
||||
to_time: string;
|
||||
url: string;
|
||||
description: string;
|
||||
status: number;
|
||||
}
|
||||
|
||||
export interface Product {
|
||||
@@ -83,7 +82,7 @@ export interface Product {
|
||||
priceUnit: string;
|
||||
marketPrice: number;
|
||||
price: string | number;
|
||||
price_off: number;
|
||||
price_off: number | string;
|
||||
currency: string;
|
||||
sale_rules: SaleRules;
|
||||
lastUpdate: string;
|
||||
@@ -108,7 +107,7 @@ export interface Product {
|
||||
config_count: number;
|
||||
configurable: number;
|
||||
component_count: number;
|
||||
specialOffer: { other?: SpecialOfferItem[], all?: SpecialOfferItem[] };
|
||||
specialOffer: { other?: SpecialOfferItem[]; all?: SpecialOfferItem[] };
|
||||
specialOfferGroup: [];
|
||||
productType: {
|
||||
isNew: number;
|
||||
@@ -131,5 +130,4 @@ export interface Product {
|
||||
categories: Category[];
|
||||
}
|
||||
|
||||
|
||||
export type TypeListProduct = Product[];
|
||||
export type TypeListProduct = Product[];
|
||||
|
||||
@@ -19,14 +19,14 @@ interface Brand {
|
||||
}
|
||||
|
||||
// Product Image
|
||||
export interface ProductImage {
|
||||
export interface ProductImageDetail {
|
||||
small: string;
|
||||
large: string;
|
||||
original: string;
|
||||
}
|
||||
|
||||
export interface ProductImageGallery {
|
||||
size: ProductImage;
|
||||
size: ProductImageDetail;
|
||||
alt: string;
|
||||
folder: string;
|
||||
}
|
||||
@@ -135,7 +135,7 @@ export interface ProductInfo {
|
||||
productSKU: string;
|
||||
productUrl: string;
|
||||
productName: string;
|
||||
productImage: ProductImage;
|
||||
productImage: ProductImageDetail;
|
||||
price: string;
|
||||
quantity: string;
|
||||
currency: string;
|
||||
|
||||
Reference in New Issue
Block a user