149 lines
5.5 KiB
JavaScript
149 lines
5.5 KiB
JavaScript
import React, { useEffect, useState } from "react";
|
|
import { Swiper, SwiperSlide } from "swiper/react";
|
|
import { Navigation } from "swiper/modules";
|
|
import "swiper/css";
|
|
import "swiper/css/navigation";
|
|
import { Zap } from "lucide-react";
|
|
import { Flex } from "antd";
|
|
import { useGetFlashSalesQuery } from "../../app/api/flashSalesApi";
|
|
import ProductCard from "../ProductCard";
|
|
import styles from "./FlashSales.module.scss";
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
const parseTime = (timeStr) => {
|
|
if (!timeStr) return { hours: "00", minutes: "00", seconds: "00" };
|
|
const parts = timeStr.split(":");
|
|
return {
|
|
hours: parts[0] || "00",
|
|
minutes: parts[1] || "00",
|
|
seconds: parts[2] || "00",
|
|
};
|
|
};
|
|
|
|
const FlashSales = () => {
|
|
const { t } = useTranslation();
|
|
const { data, isLoading, isError } = useGetFlashSalesQuery();
|
|
const [timers, setTimers] = useState([]);
|
|
|
|
const getTimeLeft = (end) => {
|
|
const endTime = new Date(end).getTime();
|
|
const now = new Date().getTime();
|
|
let diff = endTime - now;
|
|
if (diff <= 0) return "00:00:00";
|
|
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
|
|
diff = diff % (1000 * 60 * 60 * 24);
|
|
const hours = String(Math.floor(diff / (1000 * 60 * 60))).padStart(2, "0");
|
|
const minutes = String(Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60))).padStart(2, "0");
|
|
const seconds = String(Math.floor((diff % (1000 * 60)) / 1000)).padStart(2, "0");
|
|
if (days > 0) {
|
|
return `${days}g ${hours}:${minutes}:${seconds}`;
|
|
}
|
|
return `${hours}:${minutes}:${seconds}`;
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (!data?.data) return;
|
|
const updateTimers = () => {
|
|
setTimers(data.data.map((flashSale) => getTimeLeft(flashSale.ends_at)));
|
|
};
|
|
updateTimers();
|
|
const interval = setInterval(updateTimers, 1000);
|
|
return () => clearInterval(interval);
|
|
}, [data]);
|
|
|
|
if (isLoading || isError || !data?.data?.length) return null;
|
|
|
|
return (
|
|
<div>
|
|
{data.data.map((flashSale, idx) => {
|
|
// Timer parse
|
|
let days = 0, hours = "00", minutes = "00", seconds = "00";
|
|
if (timers[idx]) {
|
|
const match = timers[idx].match(/(?:(\d+)g )?(\d{2}):(\d{2}):(\d{2})/);
|
|
if (match) {
|
|
days = match[1] ? Number(match[1]) : 0;
|
|
hours = match[2];
|
|
minutes = match[3];
|
|
seconds = match[4];
|
|
}
|
|
}
|
|
|
|
return (
|
|
<section className={styles.flashSales} key={flashSale.id}>
|
|
{/* ── Header ── */}
|
|
<Flex
|
|
align="center"
|
|
justify="space-between"
|
|
wrap="wrap"
|
|
className={styles.header}
|
|
>
|
|
{/* Left: icon + title */}
|
|
<Flex align="center" gap={10} className={styles.flashLabel}>
|
|
<span className={styles.zapWrapper}>
|
|
<Zap size={22} className={styles.zapIcon} />
|
|
</span>
|
|
<span className={styles.flashText}>{t("flashSales.flash_sale")}</span>
|
|
{flashSale.title && (
|
|
<span className={styles.saleTitle}>{flashSale.title}</span>
|
|
)}
|
|
</Flex>
|
|
|
|
{/* Right: countdown timer */}
|
|
<Flex align="center" gap={8} className={styles.timerWrapper}>
|
|
<span className={styles.timerLabel}>{t("flashSales.ends_in")}</span>
|
|
<Flex align="center" gap={4}>
|
|
{days > 0 && (
|
|
<div className={styles.timerBlock}>
|
|
<span className={styles.timerDigit}>{days}</span>
|
|
<span className={styles.timerUnit}>{t("flashSales.day")}</span>
|
|
</div>
|
|
)}
|
|
<div className={styles.timerBlock}>
|
|
<span className={styles.timerDigit}>{hours}</span>
|
|
<span className={styles.timerUnit}>{t("flashSales.hour")}</span>
|
|
</div>
|
|
<span className={styles.timerSep}>:</span>
|
|
<div className={styles.timerBlock}>
|
|
<span className={styles.timerDigit}>{minutes}</span>
|
|
<span className={styles.timerUnit}>{t("flashSales.minute")}</span>
|
|
</div>
|
|
<span className={styles.timerSep}>:</span>
|
|
<div className={styles.timerBlock}>
|
|
<span className={styles.timerDigit}>{seconds}</span>
|
|
<span className={styles.timerUnit}>{t("flashSales.second")}</span>
|
|
</div>
|
|
</Flex>
|
|
</Flex>
|
|
</Flex>
|
|
|
|
{/* ── Products Carousel ── */}
|
|
<div className={styles.swiperWrapper}>
|
|
<Swiper
|
|
modules={[Navigation]}
|
|
navigation
|
|
slidesPerView={4}
|
|
spaceBetween={16}
|
|
breakpoints={{
|
|
0: { slidesPerView: 1.5, spaceBetween: 10 },
|
|
480: { slidesPerView: 2.2, spaceBetween: 12 },
|
|
768: { slidesPerView: 3, spaceBetween: 14 },
|
|
1024: { slidesPerView: 4, spaceBetween: 16 },
|
|
}}
|
|
className={styles.swiper}
|
|
>
|
|
{flashSale.products.map((product) => (
|
|
<SwiperSlide key={product.id} className={styles.slide}>
|
|
<ProductCard product={product} />
|
|
</SwiperSlide>
|
|
))}
|
|
</Swiper>
|
|
</div>
|
|
</section>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default FlashSales;
|