update 30/01
This commit is contained in:
12549
package-lock.json
generated
12549
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fancyapps/ui": "5.0",
|
"@fancyapps/ui": "5.0",
|
||||||
|
"html-react-parser": "^5.2.14",
|
||||||
"next": "16.1.0",
|
"next": "16.1.0",
|
||||||
|
"photoswipe": "^5.4.4",
|
||||||
"react": "19.2.3",
|
"react": "19.2.3",
|
||||||
"react-dom": "19.2.3",
|
"react-dom": "19.2.3",
|
||||||
"swiper": "^12.0.3"
|
"swiper": "^12.0.3"
|
||||||
|
|||||||
53
src/components/product/detail/image/PhotoSwipeImage.tsx
Normal file
53
src/components/product/detail/image/PhotoSwipeImage.tsx
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useEffect, useRef } from 'react'
|
||||||
|
import PhotoSwipeLightbox from 'photoswipe/lightbox'
|
||||||
|
import 'photoswipe/style.css'
|
||||||
|
|
||||||
|
export default function PhotoSwipeImage({
|
||||||
|
images,
|
||||||
|
activeIndex
|
||||||
|
}: {
|
||||||
|
images: string[]
|
||||||
|
activeIndex: number
|
||||||
|
}) {
|
||||||
|
const galleryRef = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!galleryRef.current) return
|
||||||
|
|
||||||
|
const lightbox = new PhotoSwipeLightbox({
|
||||||
|
gallery: '#pswp-gallery',
|
||||||
|
children: 'a',
|
||||||
|
pswpModule: () => import('photoswipe')
|
||||||
|
})
|
||||||
|
|
||||||
|
lightbox.init()
|
||||||
|
|
||||||
|
return () => lightbox.destroy()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
id="pswp-gallery"
|
||||||
|
ref={galleryRef}
|
||||||
|
className="w-full"
|
||||||
|
>
|
||||||
|
{images.map((img, index) => (
|
||||||
|
<a
|
||||||
|
key={index}
|
||||||
|
href={img}
|
||||||
|
data-pswp-width="1200"
|
||||||
|
data-pswp-height="1200"
|
||||||
|
className={index === activeIndex ? 'block' : 'hidden'}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={img}
|
||||||
|
alt=""
|
||||||
|
className="w-full object-contain cursor-zoom-in"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,84 +1,56 @@
|
|||||||
export default function ProductImage() {
|
'use client'
|
||||||
|
|
||||||
|
import { useState } from 'react'
|
||||||
|
import dynamic from 'next/dynamic'
|
||||||
|
import { Swiper, SwiperSlide } from 'swiper/react'
|
||||||
|
import { Navigation } from 'swiper/modules'
|
||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
|
const PhotoSwipeImage = dynamic(
|
||||||
|
() => import('./PhotoSwipeImage'),
|
||||||
|
{ ssr: false }
|
||||||
|
)
|
||||||
|
|
||||||
|
export default function ProductImage({ data }: any) {
|
||||||
|
const images: string[] = Array.from(
|
||||||
|
new Set([
|
||||||
|
data.productImage.large.replace('250_', ''),
|
||||||
|
...(data.imageCollection?.map((i: any) =>
|
||||||
|
i.image.large.replace('250_', '')
|
||||||
|
) || [])
|
||||||
|
])
|
||||||
|
)
|
||||||
|
|
||||||
|
const [activeIndex, setActiveIndex] = useState(0)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="pd-image-top mb-3">
|
<div className="pd-image-top mb-4">
|
||||||
<a
|
<PhotoSwipeImage
|
||||||
className="MagicZoom"
|
images={images}
|
||||||
id="Zoomer"
|
activeIndex={activeIndex}
|
||||||
rel="selectors-effect-speed: 600"
|
|
||||||
href="images/product-1.jpg"
|
|
||||||
>
|
|
||||||
<img src="images/product-1.jpg" alt="" />
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
href="javascript:void(0)"
|
|
||||||
className="pd-image-btn"
|
|
||||||
/>
|
|
||||||
<a
|
|
||||||
href="javascript:void(0)"
|
|
||||||
className="pd-image-btn btn-next"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="pd-gallery-list">
|
<div className="pd-gallery-list">
|
||||||
<div className="swiper w-full" id="js-pd-gallery">
|
<Swiper
|
||||||
<div className="swiper-wrapper">
|
modules={[Navigation]}
|
||||||
<div className="swiper-slide">
|
spaceBetween={12}
|
||||||
<a
|
slidesPerView={5}
|
||||||
href="images/product-1.jpg"
|
>
|
||||||
rel="zoom-id:Zoomer"
|
{images.map((img, index) => (
|
||||||
rev="images/product-1.jpg"
|
<SwiperSlide key={img}>
|
||||||
>
|
<img
|
||||||
<img src="images/product-1.jpg" alt="" />
|
src={img}
|
||||||
</a>
|
onClick={() => setActiveIndex(index)}
|
||||||
</div>
|
className={`cursor-pointer border rounded-md
|
||||||
<div className="swiper-slide">
|
${activeIndex === index
|
||||||
<a
|
? 'border-[#0678DB]'
|
||||||
href="images/product-2.jpg"
|
: 'border-transparent'}`}
|
||||||
rel="zoom-id:Zoomer"
|
/>
|
||||||
rev="images/product-2.jpg"
|
</SwiperSlide>
|
||||||
>
|
))}
|
||||||
<img src="images/product-2.jpg" alt="" />
|
</Swiper>
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className="swiper-slide">
|
|
||||||
<a
|
|
||||||
href="images/product-3.jpg"
|
|
||||||
rel="zoom-id:Zoomer"
|
|
||||||
rev="images/product-3.jpg"
|
|
||||||
>
|
|
||||||
<img src="images/product-3.jpg" alt="" />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className="swiper-slide">
|
|
||||||
<a
|
|
||||||
href="images/product-4.jpg"
|
|
||||||
rel="zoom-id:Zoomer"
|
|
||||||
rev="images/product-4.jpg"
|
|
||||||
>
|
|
||||||
<img src="images/product-4.jpg" alt="" />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className="swiper-slide">
|
|
||||||
<a
|
|
||||||
href="images/product-5.jpg"
|
|
||||||
rel="zoom-id:Zoomer"
|
|
||||||
rev="images/product-5.jpg"
|
|
||||||
>
|
|
||||||
<img src="images/product-5.jpg" alt="" />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className="swiper-slide">
|
|
||||||
<a
|
|
||||||
href="images/product-6.jpg"
|
|
||||||
rel="zoom-id:Zoomer"
|
|
||||||
rev="images/product-6.jpg"
|
|
||||||
>
|
|
||||||
<img src="images/product-6.jpg" alt="" />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -17,10 +17,22 @@ export default async function ProductDetail({ slug }: any) {
|
|||||||
review,
|
review,
|
||||||
visit,
|
visit,
|
||||||
quantity,
|
quantity,
|
||||||
productSummary
|
productSummary,
|
||||||
|
productImage, imageCollection,
|
||||||
|
price, marketPrice, deal_list, price_off, sale_rules,
|
||||||
|
hasVAT, warranty,
|
||||||
|
specialOffer
|
||||||
} = slug
|
} = slug
|
||||||
|
|
||||||
|
const image = {
|
||||||
|
productImage,
|
||||||
|
imageCollection
|
||||||
|
}
|
||||||
|
|
||||||
|
const priceData = {
|
||||||
|
price, marketPrice, deal_list, price_off, sale_rules, hasVAT, warranty, quantity
|
||||||
|
}
|
||||||
|
|
||||||
console.log(slug)
|
console.log(slug)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -33,7 +45,7 @@ export default async function ProductDetail({ slug }: any) {
|
|||||||
|
|
||||||
<div className="gap-6 flex flex-wrap items-start leading-[18px]">
|
<div className="gap-6 flex flex-wrap items-start leading-[18px]">
|
||||||
<div className="col-left-group w-[424px] sticky top-[90px]">
|
<div className="col-left-group w-[424px] sticky top-[90px]">
|
||||||
<ProductImage />
|
<ProductImage data={image} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="col-middle-group w-[464px]">
|
<div className="col-middle-group w-[464px]">
|
||||||
@@ -69,9 +81,9 @@ export default async function ProductDetail({ slug }: any) {
|
|||||||
<ProductSummary item={productSummary} />
|
<ProductSummary item={productSummary} />
|
||||||
}
|
}
|
||||||
|
|
||||||
<ProductPrice />
|
<ProductPrice item={priceData} />
|
||||||
|
|
||||||
<ProductOffer />
|
<ProductOffer item={specialOffer}/>
|
||||||
|
|
||||||
<Buttons />
|
<Buttons />
|
||||||
|
|
||||||
|
|||||||
@@ -1,43 +1,21 @@
|
|||||||
export default function ProductOffer() {
|
import { formatTextList } from "@/lib/utils"
|
||||||
|
import parse from 'html-react-parser';
|
||||||
|
|
||||||
|
export default function ProductOffer({ item }: any) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* Khuyến mại hấp dẫn */}
|
{item.all.length > 0 &&
|
||||||
<div className="pd-offer-group mb-4 bg-[linear-gradient(182.15deg,#FFA480_-18.44%,#EB0C23_60.76%)] p-1 pt-2 rounded-[8px]">
|
<div className="pd-offer-group mb-4 bg-[linear-gradient(182.15deg,#FFA480_-18.44%,#EB0C23_60.76%)] p-1 pt-2 rounded-[8px]">
|
||||||
<div className="group-title font-600 text-white flex items-center leading-[22px] mb-2 px-2 text-16">
|
<div className="group-title font-600 text-white flex items-center leading-[22px] mb-2 px-2 text-16">
|
||||||
<i className="icons icon-discount mr-[6px] animation-tada" />
|
<i className="icons icon-gift mr-2 animation-tada -mt-1" />
|
||||||
<span> Khuyến mại hấp dẫn </span>
|
<span> Quà tặng và ưu đãi kèm theo </span>
|
||||||
</div>
|
|
||||||
<div className="rounded-[8px] bg-[#FEF2F2] px-2 py-4">
|
|
||||||
<div className="item">
|
|
||||||
{" "}
|
|
||||||
Giảm ngay 100.000đ khi mua thêm Màn Hình Máy Tính.
|
|
||||||
</div>
|
</div>
|
||||||
<div className="item"> Giảm ngay 100.000đ khi mua thêm RAM </div>
|
|
||||||
<div className="item">
|
|
||||||
{" "}
|
|
||||||
Giảm ngay 100.000đ khi mua thêm Card màn hình{" "}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Quà tặng và ưu đãi kèm theo */}
|
<div className="rounded-[8px] bg-[#FEF2F2] px-2 py-4">
|
||||||
<div className="pd-offer-group mb-4 bg-[linear-gradient(182.15deg,#FFA480_-18.44%,#EB0C23_60.76%)] p-1 pt-2 rounded-[8px]">
|
{parse(formatTextList(item.all[0].title))}
|
||||||
<div className="group-title font-600 text-white flex items-center leading-[22px] mb-2 px-2 text-16">
|
|
||||||
<i className="icons icon-gift mr-2 animation-tada -mt-1" />
|
|
||||||
<span> Quà tặng và ưu đãi kèm theo </span>
|
|
||||||
</div>
|
|
||||||
<div className="rounded-[8px] bg-[#FEF2F2] px-2 py-4">
|
|
||||||
<div className="item">
|
|
||||||
{" "}
|
|
||||||
Giảm ngay 100.000đ khi mua thêm Màn Hình Máy Tính.
|
|
||||||
</div>
|
|
||||||
<div className="item"> Giảm ngay 100.000đ khi mua thêm RAM </div>
|
|
||||||
<div className="item">
|
|
||||||
{" "}
|
|
||||||
Giảm ngay 100.000đ khi mua thêm Card màn hình{" "}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
92
src/components/product/detail/price/DealPrice.tsx
Normal file
92
src/components/product/detail/price/DealPrice.tsx
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
import { formatPrice } from "@/lib/utils";
|
||||||
|
import { DealCountdown } from "@/lib/times"
|
||||||
|
|
||||||
|
export default function DealPrice( {item} : any ) {
|
||||||
|
|
||||||
|
const price = item.sale_rules.price;
|
||||||
|
const normal_price = item.sale_rules.normal_price;
|
||||||
|
const discount = Math.ceil(((normal_price - price) / normal_price) * 100);
|
||||||
|
|
||||||
|
const sale_quantity = item.deal_list[0].sale_quantity;
|
||||||
|
const quantity = item.deal_list[0].quantity;
|
||||||
|
const saleRemainPercent = 100 - (sale_quantity / quantity) * 100;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="pd-deal-group rounded-[12px] bg-[#FEF2F2] overflow-hidden border border-[#FA354A] my-3">
|
||||||
|
<div className="group-title p-2 bg-[linear-gradient(270.05deg,#CB0F23_0.04%,#FF3246_99.97%)] flex items-center flex-wrap justify-between gap-2">
|
||||||
|
<p className="m-0 leading-7 font-600 text-18 flex items-center gap-[6px] text-white">
|
||||||
|
<i className="icons icon-flame animation-beat" />
|
||||||
|
<span> BIG SALE </span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="relative bg-[#EBEBEB] rounded-[20px] text-center font-500 text-13 leading-[22px] px-[51px]">
|
||||||
|
<i className="w-[22px] h-[28px] absolute left-[-8px] top-[-4px] z-[1] bg-no-repeat bg-center bg-[length:100%_100%] animation-bounce lazy"
|
||||||
|
data-bg="url(images/deal-icon-bolt.png)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<i className="bg-[#FFE078] absolute inset-0 max-w-[100%] rounded-[20px]"
|
||||||
|
style={{ width: saleRemainPercent+"%" }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<span className="relative z-[1] block">
|
||||||
|
Còn: {sale_quantity}/{quantity} sản phẩm
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="p-4">
|
||||||
|
<div className="leading-8 flex items-baseline flex-wrap mb-1">
|
||||||
|
<p className="pd-price text-[#FF4E2A] font-bold mb-0 mr-3 text-24">
|
||||||
|
{formatPrice(price)} đ
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{ discount > 0 &&
|
||||||
|
<>
|
||||||
|
<del className="mr-2 text-16">
|
||||||
|
{ formatPrice(normal_price) } đ
|
||||||
|
</del>
|
||||||
|
|
||||||
|
<span className="pd-discount bg-[#FA354A] text-white leading-4 rounded-[20px] px-[6px] font-500">
|
||||||
|
-{discount}%
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-wrap gap-1 font-500 text-[#2563EB] leading-[22px]">
|
||||||
|
{item.hasVAT == 1 &&
|
||||||
|
<p className="m-0 bg-[#EFF6FF] rounded-[6px] px-2"> Giá đã bao gồm VAT </p>
|
||||||
|
}
|
||||||
|
|
||||||
|
{item.hasVAT == 2 &&
|
||||||
|
<p className="m-0 bg-[#EFF6FF] rounded-[6px] px-2"> Giá chưa bao gồm VAT </p>
|
||||||
|
}
|
||||||
|
|
||||||
|
{item.warranty &&
|
||||||
|
<p className="m-0 bg-[#EFF6FF] rounded-[6px] px-2"> {item.warranty} </p>
|
||||||
|
}
|
||||||
|
|
||||||
|
<p className="m-0 bg-[#EFF6FF] rounded-[6px] px-2">
|
||||||
|
{ item.quantity > 0 ? 'Còn hàng' : 'Liên hệ' }
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="my-2 flex items-center leading-6 gap-2">
|
||||||
|
<p className="m-0"> Kết thúc sau: </p>
|
||||||
|
|
||||||
|
<div className="deal-time-holder flex items-center gap-5 text-white text-14 font-600">
|
||||||
|
<DealCountdown endTime={item.deal_list[0].to_time} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="m-0 font-600 text-13 leading-4 text-[#FF4E2A] mt-3">
|
||||||
|
*KHÔNG ÁP DỤNG CỘNG DỒN CHƯƠNG TRÌNH KHUYẾN MẠI KHÁC
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
40
src/components/product/detail/price/Price.tsx
Normal file
40
src/components/product/detail/price/Price.tsx
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { formatPrice } from "@/lib/utils";
|
||||||
|
|
||||||
|
export default function Price( {item} : any ) {
|
||||||
|
return (
|
||||||
|
<div className="my-3 border border-[#FA354A] rounded-[12px] leading-[22px] p-4 pd-price-group">
|
||||||
|
<div className="leading-8 flex items-baseline flex-wrap mb-1">
|
||||||
|
<p className="pd-price text-[#FF4E2A] font-bold mb-0 mr-3 text-24">
|
||||||
|
{item.price > 0 ? formatPrice(item.price) + 'đ' : ''}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{ item.price_off &&
|
||||||
|
<>
|
||||||
|
<del className="mr-2 text-16"> {formatPrice(item.marketPrice)} đ </del>
|
||||||
|
<span className="pd-discount bg-[#FA354A] text-white leading-4 rounded-[20px] px-[6px] font-500">
|
||||||
|
-{item.price_off}%
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-wrap gap-1 font-500 text-[#2563EB]">
|
||||||
|
{item.hasVAT == 1 &&
|
||||||
|
<p className="m-0 bg-[#EFF6FF] rounded-[6px] px-2"> Giá đã bao gồm VAT </p>
|
||||||
|
}
|
||||||
|
|
||||||
|
{item.hasVAT == 2 &&
|
||||||
|
<p className="m-0 bg-[#EFF6FF] rounded-[6px] px-2"> Giá chưa bao gồm VAT </p>
|
||||||
|
}
|
||||||
|
|
||||||
|
{item.warranty &&
|
||||||
|
<p className="m-0 bg-[#EFF6FF] rounded-[6px] px-2"> {item.warranty} </p>
|
||||||
|
}
|
||||||
|
|
||||||
|
<p className="m-0 bg-[#EFF6FF] rounded-[6px] px-2">
|
||||||
|
{ item.quantity > 0 ? 'Còn hàng' : 'Liên hệ' }
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,86 +1,18 @@
|
|||||||
export default function ProductPrice() {
|
import DealPrice from "./DealPrice";
|
||||||
|
import Price from "./Price";
|
||||||
|
|
||||||
|
export default function ProductPrice({ item }: any) {
|
||||||
|
if (!item) return null
|
||||||
|
|
||||||
|
const isDeal = item?.sale_rules?.type === 'deal';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* Deal */}
|
{isDeal ? (
|
||||||
<div className="pd-deal-group rounded-[12px] bg-[#FEF2F2] overflow-hidden border border-[#FA354A] ">
|
<DealPrice item={item} />
|
||||||
<div className="group-title p-2 bg-[linear-gradient(270.05deg,#CB0F23_0.04%,#FF3246_99.97%)] flex items-center flex-wrap justify-between gap-2">
|
) : (
|
||||||
<p className="m-0 leading-7 font-600 text-18 flex items-center gap-[6px] text-white">
|
<Price item={item} />
|
||||||
<i className="icons icon-flame animation-beat" />
|
)}
|
||||||
<span> BIG SALE </span>
|
|
||||||
</p>
|
|
||||||
<div className="relative bg-[#EBEBEB] rounded-[20px] text-center font-500 text-13 leading-[22px] px-[51px]">
|
|
||||||
<i
|
|
||||||
className="w-[22px] h-[28px] absolute left-[-8px] top-[-4px] z-[1] bg-no-repeat bg-center bg-[length:100%_100%] animation-bounce lazy"
|
|
||||||
data-bg="url(images/deal-icon-bolt.png)"
|
|
||||||
/>
|
|
||||||
<i
|
|
||||||
className="bg-[#FFE078] absolute inset-0 max-w-[100%] rounded-[20px]"
|
|
||||||
style={{ width: "50%" }}
|
|
||||||
/>
|
|
||||||
<span className="relative z-[1] block"> Còn: 3/5 sản phẩm </span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="p-4">
|
|
||||||
<div className="leading-8 flex items-baseline flex-wrap mb-1">
|
|
||||||
<p className="pd-price text-[#FF4E2A] font-bold mb-0 mr-3 text-24">
|
|
||||||
{" "}
|
|
||||||
48.990.000 đ{" "}
|
|
||||||
</p>
|
|
||||||
<del className="mr-2 text-16"> 52.000.000 đ </del>
|
|
||||||
<span className="pd-discount bg-[#FA354A] text-white leading-4 rounded-[20px] px-[6px] font-500">
|
|
||||||
{" "}
|
|
||||||
-6%{" "}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-wrap gap-1 font-500 text-[#2563EB] leading-[22px]">
|
|
||||||
<p className="m-0 bg-[#EFF6FF] rounded-[6px] px-2">
|
|
||||||
{" "}
|
|
||||||
Giá đã bao gồm VAT{" "}
|
|
||||||
</p>
|
|
||||||
<p className="m-0 bg-[#EFF6FF] rounded-[6px] px-2">
|
|
||||||
{" "}
|
|
||||||
Bảo hành theo từng linh kiện{" "}
|
|
||||||
</p>
|
|
||||||
<p className="m-0 bg-[#EFF6FF] rounded-[6px] px-2"> Liên hệ </p>
|
|
||||||
</div>
|
|
||||||
<div className="my-2 flex items-center leading-6 gap-2">
|
|
||||||
<p className="m-0"> Kết thúc sau: </p>
|
|
||||||
<div className="deal-time-holder flex items-center gap-5 text-white text-14 font-600">
|
|
||||||
<p> 00 </p> <p> 00 </p> <p> 00 </p> <p> 00 </p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p className="m-0 font-600 text-13 leading-4 text-[#FF4E2A] mt-3">
|
|
||||||
{" "}
|
|
||||||
*KHÔNG ÁP DỤNG CỘNG DỒN CHƯƠNG TRÌNH KHUYẾN MẠI KHÁC{" "}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Price */}
|
|
||||||
<div className="my-3 border border-[#FA354A] rounded-[12px] leading-[22px] p-4 pd-price-group">
|
|
||||||
<div className="leading-8 flex items-baseline flex-wrap mb-1">
|
|
||||||
<p className="pd-price text-[#FF4E2A] font-bold mb-0 mr-3 text-24">
|
|
||||||
{" "}
|
|
||||||
48.990.000 đ{" "}
|
|
||||||
</p>
|
|
||||||
<del className="mr-2 text-16"> 52.000.000 đ </del>
|
|
||||||
<span className="pd-discount bg-[#FA354A] text-white leading-4 rounded-[20px] px-[6px] font-500">
|
|
||||||
{" "}
|
|
||||||
-6%{" "}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-wrap gap-1 font-500 text-[#2563EB]">
|
|
||||||
<p className="m-0 bg-[#EFF6FF] rounded-[6px] px-2">
|
|
||||||
{" "}
|
|
||||||
Giá đã bao gồm VAT{" "}
|
|
||||||
</p>
|
|
||||||
<p className="m-0 bg-[#EFF6FF] rounded-[6px] px-2">
|
|
||||||
{" "}
|
|
||||||
Bảo hành theo từng linh kiện{" "}
|
|
||||||
</p>
|
|
||||||
<p className="m-0 bg-[#EFF6FF] rounded-[6px] px-2"> Liên hệ </p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,11 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import Link from "next/link"
|
||||||
|
import FancyboxWrapper from "@/components/shared/FancyboxWrapper"
|
||||||
|
|
||||||
export default function Static() {
|
export default function Static() {
|
||||||
return (
|
return (
|
||||||
<>
|
<FancyboxWrapper>
|
||||||
<div className="group relative border border-[#D6DAE1] leading-[38px] rounded-[8px] pl-3 pr-2 mb-3">
|
<div className="group relative border border-[#D6DAE1] leading-[38px] rounded-[8px] pl-3 pr-2 mb-3">
|
||||||
<p className="m-0 flex items-center justify-between cursor-pointer">
|
<p className="m-0 flex items-center justify-between cursor-pointer">
|
||||||
<span> Xem chi nhánh còn hàng </span>
|
<span> Xem chi nhánh còn hàng </span>
|
||||||
@@ -11,7 +16,7 @@ export default function Static() {
|
|||||||
<b className="block underline px-2 font-600 mb-2">
|
<b className="block underline px-2 font-600 mb-2">
|
||||||
Showroom Miền Bắc:
|
Showroom Miền Bắc:
|
||||||
</b>
|
</b>
|
||||||
<a
|
<Link
|
||||||
href="https://goo.gl/maps/56ARHjWKoVhpWBCF6"
|
href="https://goo.gl/maps/56ARHjWKoVhpWBCF6"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="nofollow"
|
rel="nofollow"
|
||||||
@@ -19,8 +24,8 @@ export default function Static() {
|
|||||||
>
|
>
|
||||||
<i className="icons icon-location" />
|
<i className="icons icon-location" />
|
||||||
<span> 41 Khúc Thừa Dụ, Phường Cầu Giấy, Hà Nội </span>
|
<span> 41 Khúc Thừa Dụ, Phường Cầu Giấy, Hà Nội </span>
|
||||||
</a>
|
</Link>
|
||||||
<a
|
<Link
|
||||||
href="https://g.page/hoanghapc?share"
|
href="https://g.page/hoanghapc?share"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="nofollow"
|
rel="nofollow"
|
||||||
@@ -28,13 +33,13 @@ export default function Static() {
|
|||||||
>
|
>
|
||||||
<i className="icons icon-location" />
|
<i className="icons icon-location" />
|
||||||
<span> 94E-94F Đường Láng, Phường Đống Đa, Hà Nội </span>
|
<span> 94E-94F Đường Láng, Phường Đống Đa, Hà Nội </span>
|
||||||
</a>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="my-3">
|
<div className="my-3">
|
||||||
<b className="block underline px-2 font-600 mb-2">
|
<b className="block underline px-2 font-600 mb-2">
|
||||||
Showroom Miền Trung:
|
Showroom Miền Trung:
|
||||||
</b>
|
</b>
|
||||||
<a
|
<Link
|
||||||
href="https://goo.gl/maps/1HQrD6mdf4VMYccs6"
|
href="https://goo.gl/maps/1HQrD6mdf4VMYccs6"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="nofollow"
|
rel="nofollow"
|
||||||
@@ -42,13 +47,13 @@ export default function Static() {
|
|||||||
>
|
>
|
||||||
<i className="icons icon-location" />
|
<i className="icons icon-location" />
|
||||||
<span>72 Lê Lợi, Thành Vinh, Nghệ An </span>
|
<span>72 Lê Lợi, Thành Vinh, Nghệ An </span>
|
||||||
</a>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="my-3">
|
<div className="my-3">
|
||||||
<b className="block underline px-2 font-600 mb-2">
|
<b className="block underline px-2 font-600 mb-2">
|
||||||
Showroom Miền Nam:
|
Showroom Miền Nam:
|
||||||
</b>
|
</b>
|
||||||
<a
|
<Link
|
||||||
href="https://g.page/hoanghapchcm?share"
|
href="https://g.page/hoanghapchcm?share"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="nofollow"
|
rel="nofollow"
|
||||||
@@ -56,102 +61,102 @@ export default function Static() {
|
|||||||
>
|
>
|
||||||
<i className="icons icon-location" />
|
<i className="icons icon-location" />
|
||||||
<span>
|
<span>
|
||||||
{" "}
|
|
||||||
K8bis Bửu Long, Phường Hoà Hưng, Thành phố Hồ Chí Minh
|
K8bis Bửu Long, Phường Hoà Hưng, Thành phố Hồ Chí Minh
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<i className="block red my-3 px-2">
|
<i className="block red my-3 px-2">
|
||||||
Chú ý: Sản phẩm có thể điều chuyển kho theo yêu cầu của quý khách.
|
Chú ý: Sản phẩm có thể điều chuyển kho theo yêu cầu của quý khách.
|
||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Yên Tâm Mua Sắm Tại HoangHaPC */}
|
{/* Yên Tâm Mua Sắm Tại HoangHaPC */}
|
||||||
<div className="pd-static-group mb-3 rounded-[12px] bg-[linear-gradient(180.3deg,#259AFF_-18.56%,#114CDD_100.92%)] p-1 pt-2">
|
<div className="pd-static-group mb-3 rounded-[12px] bg-[linear-gradient(180.3deg,#259AFF_-18.56%,#114CDD_100.92%)] p-1 pt-2">
|
||||||
<p className="group-title text-white leading-[21px] text-16 font-600 mb-2 text-center">
|
<p className="group-title text-white leading-[21px] text-16 font-600 mb-2 text-center">
|
||||||
{" "}
|
Yên Tâm Mua Sắm Tại HoangHaPC
|
||||||
Yên Tâm Mua Sắm Tại HoangHaPC{" "}
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="pd-static-list bg-white p-[16px_8px] leading-[18px] font-500 rounded-[8px]">
|
<div className="pd-static-list bg-white p-[16px_8px] leading-[18px] font-500 rounded-[8px]">
|
||||||
<p className="last:mb-0 mb-2 item-circle">
|
<p className="last:mb-0 mb-2 item-circle">
|
||||||
{" "}
|
Đội ngũ kỹ thuật tư vấn chuyên sâu
|
||||||
Đội ngũ kỹ thuật tư vấn chuyên sâu{" "}
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p className="last:mb-0 mb-2 item-circle">
|
<p className="last:mb-0 mb-2 item-circle">
|
||||||
{" "}
|
Thanh toán thuận tiện
|
||||||
Thanh toán thuận tiện{" "}
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p className="last:mb-0 mb-2 item-circle">
|
<p className="last:mb-0 mb-2 item-circle">
|
||||||
{" "}
|
Sản phẩm 100% chính hãng
|
||||||
Sản phẩm 100% chính hãng{" "}
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p className="last:mb-0 mb-2 item-circle">
|
<p className="last:mb-0 mb-2 item-circle">
|
||||||
{" "}
|
Bảo hành 1 đổi 1 tại nơi sử dụng
|
||||||
Bảo hành 1 đổi 1 tại nơi sử dụng{" "}
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p className="last:mb-0 mb-2 item-circle">
|
<p className="last:mb-0 mb-2 item-circle">
|
||||||
{" "}
|
Giá cạnh tranh nhất thị trường
|
||||||
Giá cạnh tranh nhất thị trường{" "}
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Liên Hệ Với Kinh Doanh Online */}
|
|
||||||
<div className="pd-static-group mb-3 rounded-[12px] bg-[linear-gradient(180.3deg,#259AFF_-18.56%,#114CDD_100.92%)] p-1 pt-2">
|
<div className="pd-static-group mb-3 rounded-[12px] bg-[linear-gradient(180.3deg,#259AFF_-18.56%,#114CDD_100.92%)] p-1 pt-2">
|
||||||
<p className="group-title text-white leading-[21px] text-16 font-600 mb-2 text-center">
|
<p className="group-title text-white leading-[21px] text-16 font-600 mb-2 text-center">
|
||||||
{" "}
|
Liên Hệ Với Kinh Doanh Online
|
||||||
Liên Hệ Với Kinh Doanh Online{" "}
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="pd-static-list bg-white p-[16px_8px] leading-[18px] font-500 rounded-[8px]">
|
<div className="pd-static-list bg-white p-[16px_8px] leading-[18px] font-500 rounded-[8px]">
|
||||||
<div className="last:mb-0 mb-2 flex gap-2">
|
<div className="last:mb-0 mb-2 flex gap-2">
|
||||||
<i className="icons icon-phone" />
|
<i className="icons icon-phone" />
|
||||||
<p className="m-0">
|
<p className="m-0">
|
||||||
Hotline Hà Nội:{" "}
|
Hotline Hà Nội:
|
||||||
<a href="tel:0969123666" className="red font-500">
|
<Link href="tel:0969123666" className="red font-500">
|
||||||
{" "}
|
0969123666
|
||||||
0969123666{" "}
|
</Link>
|
||||||
</a>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="last:mb-0 mb-2 flex gap-2">
|
<div className="last:mb-0 mb-2 flex gap-2">
|
||||||
<i className="icons icon-phone" />
|
<i className="icons icon-phone" />
|
||||||
<p className="m-0">
|
<p className="m-0">
|
||||||
Hotline Vinh, Nghệ An:{" "}
|
Hotline Vinh, Nghệ An:
|
||||||
<a href="tel:0988.163.666" className="red font-500">
|
<Link href="tel:0988.163.666" className="red font-500">
|
||||||
{" "}
|
0988.163.666
|
||||||
0988.163.666{" "}
|
</Link>
|
||||||
</a>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="last:mb-0 mb-2 flex gap-2">
|
<div className="last:mb-0 mb-2 flex gap-2">
|
||||||
<i className="icons icon-phone" />
|
<i className="icons icon-phone" />
|
||||||
<p className="m-0">
|
<p className="m-0">
|
||||||
Hotline Hồ Chí Minh:{" "}
|
Hotline Hồ Chí Minh:
|
||||||
<a href="tel:0968.123.666" className="red font-500">
|
<Link href="tel:0968.123.666" className="red font-500">
|
||||||
{" "}
|
0968.123.666
|
||||||
0968.123.666{" "}
|
</Link>
|
||||||
</a>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="last:mb-0 mb-2 flex gap-2">
|
<div className="last:mb-0 mb-2 flex gap-2">
|
||||||
<i className="icons icon-phone" />
|
<i className="icons icon-phone" />
|
||||||
<p className="m-0">
|
<p className="m-0">
|
||||||
Hotline Bảo Hành:{" "}
|
Hotline Bảo Hành:
|
||||||
<a href="tel:1900.6100" className="red font-500">
|
<Link href="tel:1900.6100" className="red font-500">
|
||||||
{" "}
|
1900.6100
|
||||||
1900.6100{" "}
|
</Link>
|
||||||
</a>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="border border-[#0678DB] rounded-[12px] px-3 py-4 gap-[6px] flex flex-wrap items-center">
|
<div className="border border-[#0678DB] rounded-[12px] px-3 py-4 gap-[6px] flex flex-wrap items-center">
|
||||||
<a
|
<a
|
||||||
href="https://hoanghapc.vn/media/lib/17-10-2022/qr-hoang-ha-pc-nhom.png"
|
href="https://hoanghapc.vn/media/lib/17-10-2022/qr-hoang-ha-pc-nhom.png"
|
||||||
data-fancybox=""
|
data-fancybox="gallery"
|
||||||
className="w-[110px]"
|
className="w-[110px]"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
data-src="https://hoanghapc.vn/media/lib/17-10-2022/qr-hoang-ha-pc-nhom.png"
|
src="https://hoanghapc.vn/media/lib/17-10-2022/qr-hoang-ha-pc-nhom.png"
|
||||||
alt="QR code"
|
alt="QR code"
|
||||||
width={110}
|
width={110}
|
||||||
height={110}
|
height={110}
|
||||||
@@ -159,11 +164,11 @@ export default function Static() {
|
|||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
<p className="m-0 font-500 w-[calc(100%-116px)]">
|
<p className="m-0 font-500 w-[calc(100%-116px)]">
|
||||||
{" "}
|
|
||||||
Tham gia Cộng đồng "Cẩm Nang Build PC - Đồ Họa, Render, Giả Lập" để
|
Tham gia Cộng đồng "Cẩm Nang Build PC - Đồ Họa, Render, Giả Lập" để
|
||||||
theo dõi các ưu đãi dành riêng cho thành viên{" "}
|
theo dõi các ưu đãi dành riêng cho thành viên
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</FancyboxWrapper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,17 @@
|
|||||||
|
|
||||||
'use client';
|
'use client';
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
export default function ProductSummary({ item }: any) {
|
export default function ProductSummary({ item }: any) {
|
||||||
|
const [mounted, setMounted] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMounted(true)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
if (!mounted) return null
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mb-3 pd-summary-group">
|
<div className="mb-3 pd-summary-group">
|
||||||
<p className="leading-6 mb-2 text-16 font-600"> Thông số sản phẩm </p>
|
<p className="leading-6 mb-2 text-16 font-600"> Thông số sản phẩm </p>
|
||||||
@@ -12,33 +22,33 @@ export default function ProductSummary({ item }: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function renderSummary(data:any) {
|
function renderSummary(data: any) {
|
||||||
if (!data) return null;
|
if (!data) return null;
|
||||||
|
|
||||||
if (typeof data === 'string' && data.includes('<')) {
|
if (typeof data === 'string' && data.includes('<')) {
|
||||||
if (typeof window === 'undefined') return null;
|
const parser = new DOMParser()
|
||||||
|
const doc = parser.parseFromString(data, 'text/html')
|
||||||
const parser = new DOMParser();
|
|
||||||
const doc = parser.parseFromString(data, 'text/html');
|
|
||||||
|
|
||||||
return Array.from(doc.body.childNodes)
|
return Array.from(doc.body.childNodes)
|
||||||
.filter(
|
.filter(
|
||||||
node =>
|
node =>
|
||||||
node.nodeType === 1 && node.textContent !== null && node.textContent.trim() !== ''
|
node.nodeType === 1 &&
|
||||||
|
node.textContent &&
|
||||||
|
node.textContent.trim() !== ''
|
||||||
)
|
)
|
||||||
.map((node, index) => (
|
.map((node, index) => (
|
||||||
<div key={index} className="item-circle">
|
<div key={index} className="item-circle">
|
||||||
{node.textContent?.trim()}
|
{node.textContent!.trim()}
|
||||||
</div>
|
</div>
|
||||||
));
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
return data
|
return data
|
||||||
.split(/\r?\n/)
|
.split(/\r?\n/)
|
||||||
.filter((line:any) => line.trim() !== '')
|
.filter((line: string) => line.trim() !== '')
|
||||||
.map((line:any, index:any) => (
|
.map((line: string, index: number) => (
|
||||||
<div key={index} className="item-circle">
|
<div key={index} className="item-circle">
|
||||||
{line.trim()}
|
{line.trim()}
|
||||||
</div>
|
</div>
|
||||||
));
|
))
|
||||||
}
|
}
|
||||||
|
|||||||
19
src/components/shared/FancyboxWrapper.tsx
Normal file
19
src/components/shared/FancyboxWrapper.tsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { Fancybox as NativeFancybox } from '@fancyapps/ui';
|
||||||
|
|
||||||
|
|
||||||
|
export default function FancyboxWrapper({ children }: { children: React.ReactNode }) {
|
||||||
|
useEffect(() => {
|
||||||
|
NativeFancybox.bind('[data-fancybox]', {
|
||||||
|
// Options
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
NativeFancybox.destroy();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return <>{children}</>;
|
||||||
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { formatPrice } from "@/lib/utils";
|
import { formatPrice,formatTextList } from "@/lib/utils";
|
||||||
import { useProductItem } from "@/hooks/useProductItem"
|
import { useProductItem } from "@/hooks/useProductItem"
|
||||||
import { useCart } from '@/hooks/useCart';
|
import { useCart } from '@/hooks/useCart';
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import parse from 'html-react-parser';
|
||||||
|
|
||||||
export default function ProductItem({item}:any){
|
export default function ProductItem({item}:any){
|
||||||
const [mounted, setMounted] = useState(false);
|
const [mounted, setMounted] = useState(false);
|
||||||
@@ -131,8 +132,7 @@ export default function ProductItem({item}:any){
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="tooltip-spec">
|
<div className="tooltip-spec">
|
||||||
<div suppressHydrationWarning
|
{parse(formatTextList(displaySummary, 5))}
|
||||||
dangerouslySetInnerHTML={{ __html: displaySummary }}/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@@ -145,8 +145,7 @@ export default function ProductItem({item}:any){
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="tooltip-offer rounded-[8px] bg-[#FEF2F2] px-2 py-4">
|
<div className="tooltip-offer rounded-[8px] bg-[#FEF2F2] px-2 py-4">
|
||||||
<div suppressHydrationWarning
|
{parse(formatTextList(displayOffer, 5))}
|
||||||
dangerouslySetInnerHTML={{ __html: displayOffer }}/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
55
src/lib/times.tsx
Normal file
55
src/lib/times.tsx
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
'use client';
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
export function DealCountdown({ endTime }: { endTime: number }) {
|
||||||
|
const [mounted, setMounted] = useState(false);
|
||||||
|
const [timeLeft, setTimeLeft] = useState(getTimeLeft(endTime));
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMounted(true);
|
||||||
|
|
||||||
|
const timer = setInterval(() => {
|
||||||
|
setTimeLeft(getTimeLeft(endTime));
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
return () => clearInterval(timer);
|
||||||
|
}, [endTime]);
|
||||||
|
|
||||||
|
if (!mounted) return null;
|
||||||
|
|
||||||
|
if (timeLeft.total <= 0) {
|
||||||
|
return <span className="text-red-500">Deal đã kết thúc</span>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>{timeLeft.days}</p>
|
||||||
|
<p>{timeLeft.hours}</p>
|
||||||
|
<p>{timeLeft.minutes}</p>
|
||||||
|
<p>{timeLeft.seconds}</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTimeLeft(endTime: number) {
|
||||||
|
const now = Math.floor(Date.now() / 1000);
|
||||||
|
const distance = endTime - now;
|
||||||
|
|
||||||
|
if (distance <= 0) {
|
||||||
|
return {
|
||||||
|
total : 0,
|
||||||
|
days : '00',
|
||||||
|
hours : '00',
|
||||||
|
minutes : '00',
|
||||||
|
seconds : '00'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
total : distance,
|
||||||
|
days : String(Math.floor(distance / 86400)).padStart(2, '0'),
|
||||||
|
hours : String(Math.floor((distance % 86400) / 3600)).padStart(2, '0'),
|
||||||
|
minutes : String(Math.floor((distance % 3600) / 60)).padStart(2, '0'),
|
||||||
|
seconds : String(distance % 60).padStart(2, '0'),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ export function getAllProducts() {
|
|||||||
|
|
||||||
export function formatTextList(
|
export function formatTextList(
|
||||||
text?: string | any[],
|
text?: string | any[],
|
||||||
limit = 5
|
limit?: number | undefined
|
||||||
) {
|
) {
|
||||||
if (!text) return '';
|
if (!text) return '';
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
@import url('https://cdn.boxicons.com/fonts/basic/boxicons.min.css');
|
@import url('https://cdn.boxicons.com/fonts/basic/boxicons.min.css');
|
||||||
@import url('https://fonts.cdnfonts.com/css/sf-pro-display');
|
@import url('https://fonts.cdnfonts.com/css/sf-pro-display');
|
||||||
|
|
||||||
@import "@fancyapps/ui/dist/fancybox/fancybox.css";
|
@import "@fancyapps/ui/dist/fancybox/fancybox.css";
|
||||||
|
|
||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
@import 'swiper/css';
|
@import 'swiper/css';
|
||||||
@import 'swiper/css/navigation';
|
@import 'swiper/css/navigation';
|
||||||
@@ -11,5 +9,5 @@
|
|||||||
@import "../../public/styles/tailwind.css";
|
@import "../../public/styles/tailwind.css";
|
||||||
@import './pc_style.css';
|
@import './pc_style.css';
|
||||||
|
|
||||||
|
|
||||||
.fancybox__dialog .fancybox__container.is-ready {opacity: 1;}
|
.fancybox__dialog .fancybox__container.is-ready {opacity: 1;}
|
||||||
|
.mz-thumb:not(.mz-thumb-selected):hover img{border: 0 !important}
|
||||||
@@ -273,7 +273,7 @@ body{min-width:1248px;background:#E8ECF6}
|
|||||||
.item-circle::after{content:"";background:#fff;width:3.5px;height:3.5px;border-radius:50%;position:absolute;left:6.5px;top:6px}
|
.item-circle::after{content:"";background:#fff;width:3.5px;height:3.5px;border-radius:50%;position:absolute;left:6.5px;top:6px}
|
||||||
.item-circle * {margin: 0;}
|
.item-circle * {margin: 0;}
|
||||||
.pd-gallery-list a{border:2px solid transparent;overflow:hidden;display:block;pointer-events:auto!important}
|
.pd-gallery-list a{border:2px solid transparent;overflow:hidden;display:block;pointer-events:auto!important}
|
||||||
.pd-gallery-list img{filter:unset!important;display:block;margin:auto;max-width:100%;max-height:100%}
|
.pd-gallery-list img{filter:unset!important;display:block;margin:auto;max-width:100%;max-height:100%;border-width: 2px}
|
||||||
.pd-gallery-list .mz-thumb-selected{border-color:#0678DB}
|
.pd-gallery-list .mz-thumb-selected{border-color:#0678DB}
|
||||||
.pd-offer-group .icon-discount{background-position:-76px -194px}
|
.pd-offer-group .icon-discount{background-position:-76px -194px}
|
||||||
.pd-offer-group .item{margin:0 0 8px}
|
.pd-offer-group .item{margin:0 0 8px}
|
||||||
|
|||||||
Reference in New Issue
Block a user