added story, flash sale, satyjy button
This commit is contained in:
148
src/components/FlashSales/index.jsx
Normal file
148
src/components/FlashSales/index.jsx
Normal file
@@ -0,0 +1,148 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user