confetti added. react-confetti & zustand added

This commit is contained in:
Kakabay 2024-11-25 14:34:54 +05:00
parent a5eb37b26d
commit 2717fbc571
10 changed files with 753 additions and 808 deletions

View File

@ -1,7 +1,7 @@
import CountDown from '@/components/lottery/countDown/CountDown';
import SpinWheel from '@/components/lottery/spinWheel/SpinWheel';
import Image from 'next/image';
import React from 'react';
import LotteryCountDown from "@/components/lottery/countDown/LotteryCountDown";
import SpinWheel from "@/components/lottery/spinWheel/SpinWheel";
import Image from "next/image";
import React from "react";
const page = () => {
return (
@ -20,7 +20,7 @@ const page = () => {
/>
</div>
<CountDown />
<LotteryCountDown startDate="2024-11-25" />
</div>
</div>
</section>
@ -32,7 +32,9 @@ const page = () => {
<div className="flex flex-col w-full p-8 gap-4">
<div className="flex flex-col gap-2 pb-4 border-b border-lightOutlineVariant">
<h4 className="font-heading-3-regular">Results</h4>
<p className="font-base-medium">The results after each stage will be shown here.</p>
<p className="font-base-medium">
The results after each stage will be shown here.
</p>
</div>
{/* {[...Array(5)].map((item, index) => (
@ -60,10 +62,11 @@ const page = () => {
<h3 className="font-heading-5-regular">Umumy düzgünler:</h3>
<ul className="list-disc flex flex-col gap-4 pl-[16px]">
{Array(5)
.fill(' ')
.fill(" ")
.map((item, i) => (
<li className="font-small-regular" key={i}>
Ilkinji we dogry jogap beren sanawda ilkinji ýeri eýelýär
Ilkinji we dogry jogap beren sanawda ilkinji ýeri
eýelýär
</li>
))}
</ul>
@ -73,7 +76,7 @@ const page = () => {
<h3 className="font-heading-5-regular">Üns beriň:</h3>
<ul className="list-disc flex flex-col gap-4 pl-[16px]">
{Array(1)
.fill(' ')
.fill(" ")
.map((item) => (
<li className="font-small-regular">SMS = 1 manat</li>
))}

View File

@ -1,7 +1,7 @@
'use client';
"use client";
import React, { useEffect, useState } from 'react';
import { cn } from '@/lib/utils'; // Assuming `cn` is defined in `lib/utils`
import React, { useEffect, useState } from "react";
import { cn } from "@/lib/utils"; // Assuming `cn` is defined in `lib/utils`
const Confetti: React.FC = () => {
const [confetti, setConfetti] = useState<number[]>([]);
@ -19,11 +19,11 @@ const Confetti: React.FC = () => {
const randomColor = () => {
const colors = [
'linear-gradient(45deg, #5D5D72, #8589DE)',
'linear-gradient(45deg, #E1E0FF, #575992)',
'#8589DE',
'#575992',
'#E1E0FF',
"linear-gradient(45deg, #5D5D72, #8589DE)",
"linear-gradient(45deg, #E1E0FF, #575992)",
"#8589DE",
"#575992",
"#E1E0FF",
];
return colors[Math.floor(Math.random() * colors.length)];
};
@ -44,7 +44,7 @@ const Confetti: React.FC = () => {
return (
<div
key={i}
className={cn('absolute', 'confetti-piece')}
className={cn("absolute", "confetti-piece")}
style={
{
top: `${randomStartY}%`,
@ -55,9 +55,10 @@ const Confetti: React.FC = () => {
animationDuration: `${randomDuration}s`,
animationDelay: `${randomDelay}s`,
transform: `rotate(${randomRotation}deg)`,
'--end-x': `${randomEndX}vw`,
"--end-x": `${randomEndX}vw`,
} as React.CSSProperties
}></div>
}
></div>
);
})}
</div>

View File

@ -1,57 +0,0 @@
const CountDown = () => {
return (
<div className="bg-lightSurfaceContainer pb-8 flex flex-col w-full gap-2 rounded-[12px]">
{/* Countdown */}
<div className="flex items-center gap-6">
{/* {Array(5)
.fill(' ')
.map((item, index) =>
index % 2 === 0 ? (
<div className="flex flex-col items-center justify-center flex-1 p-6">
<h3 className="text-[80px] leading-[88px] -tracking-[1%]">12</h3>
<h4 className="font-medium text-[20px] leading-[28px] -tracking-[1%]">sagat</h4>
</div>
) : (
<div className="flex flex-col gap-3">
<div className="w-3 h-3 rounded-full bg-lightOutlineVariant"></div>
<div className="w-3 h-3 rounded-full bg-lightOutlineVariant"></div>
</div>
),
)} */}
<div className="flex flex-col items-center justify-center flex-1 p-6">
<h3 className="text-[80px] leading-[88px] -tracking-[1%]">12</h3>
<h4 className="font-medium text-[20px] leading-[28px] -tracking-[1%]">sagat</h4>
</div>
<div className="flex flex-col gap-3">
<div className="w-3 h-3 rounded-full bg-lightOutlineVariant"></div>
<div className="w-3 h-3 rounded-full bg-lightOutlineVariant"></div>
</div>
<div className="flex flex-col items-center justify-center flex-1 p-6">
<h3 className="text-[80px] leading-[88px] -tracking-[1%]">44</h3>
<h4 className="font-medium text-[20px] leading-[28px] -tracking-[1%]">minut</h4>
</div>
<div className="flex flex-col gap-3">
<div className="w-3 h-3 rounded-full bg-lightOutlineVariant"></div>
<div className="w-3 h-3 rounded-full bg-lightOutlineVariant"></div>
</div>
<div className="flex flex-col items-center justify-center flex-1 p-6">
<h3 className="text-[80px] leading-[88px] -tracking-[1%]">36</h3>
<h4 className="font-medium text-[20px] leading-[28px] -tracking-[1%]">sekund</h4>
</div>
</div>
{/* Seperator */}
<div className="w-full bg-lightOutlineVariant h-[1px]"></div>
<div className="flex items-center justify-center text-lightOnSurface font-heading-1-regular">
<span>-dan başlar</span>
</div>
</div>
);
};
export default CountDown;

View File

@ -0,0 +1,95 @@
"use client";
import React, { useState, useEffect } from "react";
interface LotteryCountDownProps {
startDate: string; // Event start date in "YYYY-MM-DD" format
}
const LotteryCountDown: React.FC<LotteryCountDownProps> = ({ startDate }) => {
const [timeLeft, setTimeLeft] = useState({
hours: 0,
minutes: 0,
seconds: 0,
});
const calculateTimeLeft = () => {
const now = new Date();
const eventDate = new Date(`${startDate}T00:00:00+05:00`); // Set the time to midnight UTC+5
const timeDifference = eventDate.getTime() - now.getTime();
if (timeDifference <= 0) {
return { hours: 0, minutes: 0, seconds: 0 }; // Event has started or passed
}
const hours = Math.floor(timeDifference / (1000 * 60 * 60));
const minutes = Math.floor(
(timeDifference % (1000 * 60 * 60)) / (1000 * 60)
);
const seconds = Math.floor((timeDifference % (1000 * 60)) / 1000);
return { hours, minutes, seconds };
};
useEffect(() => {
// Update time left every second
const timer = setInterval(() => {
setTimeLeft(calculateTimeLeft());
}, 1000);
return () => clearInterval(timer); // Clean up interval on component unmount
}, [startDate]);
return (
<div className="bg-lightSurfaceContainer pb-8 flex flex-col w-full gap-2 rounded-[12px]">
{/* LotteryCountDown */}
<div className="flex items-center gap-6">
<div className="flex flex-col items-center justify-center flex-1 p-6">
<h3 className="text-[80px] leading-[88px] -tracking-[1%]">
{timeLeft.hours}
</h3>
<h4 className="font-medium text-[20px] leading-[28px] -tracking-[1%]">
hours
</h4>
</div>
<div className="flex flex-col gap-3">
<div className="w-3 h-3 rounded-full bg-lightOutlineVariant"></div>
<div className="w-3 h-3 rounded-full bg-lightOutlineVariant"></div>
</div>
<div className="flex flex-col items-center justify-center flex-1 p-6">
<h3 className="text-[80px] leading-[88px] -tracking-[1%]">
{timeLeft.minutes}
</h3>
<h4 className="font-medium text-[20px] leading-[28px] -tracking-[1%]">
minutes
</h4>
</div>
<div className="flex flex-col gap-3">
<div className="w-3 h-3 rounded-full bg-lightOutlineVariant"></div>
<div className="w-3 h-3 rounded-full bg-lightOutlineVariant"></div>
</div>
<div className="flex flex-col items-center justify-center flex-1 p-6">
<h3 className="text-[80px] leading-[88px] -tracking-[1%]">
{timeLeft.seconds}
</h3>
<h4 className="font-medium text-[20px] leading-[28px] -tracking-[1%]">
seconds
</h4>
</div>
</div>
{/* Separator */}
<div className="w-full bg-lightOutlineVariant h-[1px]"></div>
<div className="flex items-center justify-center text-lightOnSurface font-heading-1-regular">
<span>-dan başlar</span>
</div>
</div>
);
};
export default LotteryCountDown;

View File

@ -3,13 +3,15 @@ interface IProps {
title: string;
}
const CountDownCell = ({ number, title }: IProps) => {
const LotteryCountDownCell = ({ number, title }: IProps) => {
return (
<div className="flex flex-col items-center justify-center flex-1 p-6">
<h3 className="text-[80px] leading-[88px] -tracking-[1%]">{number}</h3>
<h4 className="font-medium text-[20px] leading-[28px] -tracking-[1%]">{title}</h4>
<h4 className="font-medium text-[20px] leading-[28px] -tracking-[1%]">
{title}
</h4>
</div>
);
};
export default CountDownCell;
export default LotteryCountDownCell;

View File

@ -1,4 +1,4 @@
const CountDownSemicolmn = () => {
const LotteryCountDownSemicolmn = () => {
return (
<div className="flex flex-col gap-3">
<div className="w-3 h-3 rounded-full bg-lightOutlineVariant"></div>
@ -7,4 +7,4 @@ const CountDownSemicolmn = () => {
);
};
export default CountDownSemicolmn;
export default LotteryCountDownSemicolmn;

View File

@ -1,223 +1,85 @@
'use client';
"use client";
import Image from 'next/image';
// import React, { useRef, useState, useEffect } from "react";
// const SpinWheel: React.FC = () => {
// const canvasRef = useRef<HTMLCanvasElement | null>(null);
// const [isSpinning, setIsSpinning] = useState<boolean>(false);
// const [countdown, setCountdown] = useState<number>(5);
// const totalSize = 554; // Total size including borders
// const outerBorderWidth = 12; // Outer border width
// const innerBorderWidth = 15; // Inner border width
// const wheelSize = totalSize - outerBorderWidth - innerBorderWidth; // Inner wheel size
// const drawWheel = (angleOffset: number = 0): void => {
// const canvas = canvasRef.current;
// if (!canvas) return;
// const ctx = canvas.getContext("2d");
// if (!ctx) return;
// const radius = wheelSize / 2;
// // Clear the canvas and set background color
// ctx.fillStyle = "#FFF";
// ctx.fillRect(0, 0, totalSize, totalSize);
// // Draw the outermost border
// ctx.beginPath();
// ctx.arc(totalSize / 2, totalSize / 2, totalSize / 2, 0, 2 * Math.PI);
// ctx.fillStyle = "#5D5D72"; // Outer border color
// ctx.fill();
// ctx.closePath();
// // Draw the inner border
// ctx.beginPath();
// ctx.arc(
// totalSize / 2,
// totalSize / 2,
// (totalSize - outerBorderWidth) / 2,
// 0,
// 2 * Math.PI
// );
// ctx.fillStyle = "#8589DE"; // Inner border color
// ctx.fill();
// ctx.closePath();
// // Draw the wheel
// const segmentAngle = (2 * Math.PI) / 24; // 24 segments
// for (let i = 0; i < 24; i++) {
// ctx.beginPath();
// ctx.moveTo(totalSize / 2, totalSize / 2);
// ctx.arc(
// totalSize / 2,
// totalSize / 2,
// radius,
// segmentAngle * i + angleOffset,
// segmentAngle * (i + 1) + angleOffset
// );
// ctx.fillStyle = i % 2 === 0 ? "#E1E0FF" : "#575992"; // Alternate colors
// ctx.fill();
// ctx.stroke();
// ctx.closePath();
// }
// // Draw central ellipse
// ctx.beginPath();
// ctx.ellipse(
// totalSize / 2,
// totalSize / 2,
// 105 / 2,
// 105 / 2,
// 0,
// 0,
// 2 * Math.PI
// );
// ctx.fillStyle = "#FFF";
// ctx.fill();
// ctx.stroke();
// // Add countdown text in the ellipse
// ctx.fillStyle = "#79536A"; // Text color
// ctx.font = "60px Roboto";
// ctx.textAlign = "center";
// ctx.textBaseline = "middle";
// ctx.fillText(countdown.toString(), totalSize / 2, totalSize / 2);
// };
// const spinWheel = (): void => {
// if (isSpinning) return;
// setIsSpinning(true);
// setCountdown(5); // Reset countdown
// let currentAngle = 0;
// const spinDuration = 5000; // Spin for 5 seconds
// const spinStartTime = Date.now();
// // Countdown Timer Logic
// const countdownInterval = setInterval(() => {
// setCountdown((prev) => {
// if (prev === 0) {
// clearInterval(countdownInterval);
// return 0;
// }
// return prev - 1;
// });
// }, 1000);
// // Spinning Logic
// const spin = () => {
// const elapsedTime = Date.now() - spinStartTime;
// if (elapsedTime >= spinDuration) {
// setIsSpinning(false);
// return;
// }
// // Update angle
// const progress = elapsedTime / spinDuration;
// const easedProgress = easeOutCubic(progress); // Easing for smooth deceleration
// currentAngle = easedProgress * 10 * Math.PI; // Spin multiple times
// drawWheel(currentAngle);
// requestAnimationFrame(spin);
// };
// spin();
// };
// // Easing function for smooth deceleration
// const easeOutCubic = (t: number): number => 1 - Math.pow(1 - t, 3);
// // Initial draw
// useEffect(() => {
// drawWheel();
// }, [countdown]);
// return (
// <div className="flex flex-col items-center justify-center">
// <canvas
// ref={canvasRef}
// width={totalSize}
// height={totalSize}
// className="rounded-full shadow-lg"
// ></canvas>
// <button
// onClick={spinWheel}
// disabled={isSpinning}
// className={`mt-4 px-6 py-2 rounded-full text-white font-bold ${
// isSpinning
// ? "bg-gray-400 cursor-not-allowed"
// : "bg-blue-500 hover:bg-blue-700"
// }`}
// >
// {isSpinning ? "Spinning..." : "Spin the Wheel"}
// </button>
// </div>
// );
// };
// export default SpinWheel;
import { useState } from 'react';
import ConfettiExplosion, { ConfettiProps } from 'react-confetti-explosion';
const largeProps: ConfettiProps = {
force: 0.8,
duration: 3000,
particleCount: 300,
width: 1600,
colors: ['#041E43', '#1471BF', '#5BB4DC', '#FC027B', '#66D805'],
};
import Image from "next/image";
import { useState } from "react";
import Confetti from "react-confetti";
import { useWindowSize } from "react-use";
const SpinWheel: React.FC = () => {
const [isSpinning, setIsSpinning] = useState(false);
const [isCountingDown, setIsCountingDown] = useState(false);
const [countdown, setCountdown] = useState(5);
const [rotation, setRotation] = useState(0);
const [showConfetti, setShowConfetti] = useState(false);
const { width, height } = useWindowSize();
const triggerConfetti = () => {
setShowConfetti(true);
setTimeout(() => setShowConfetti(false), 5000); // Hide confetti after 5 seconds
setTimeout(() => {
setShowConfetti(false);
setCountdown(5); // Reset countdown after confetti
}, 6000); // Hide confetti after 6 seconds
};
const startCountdown = () => {
setIsCountingDown(true); // Start countdown state
let currentCountdown = 5;
const countdownInterval = setInterval(() => {
setCountdown(currentCountdown--); // Update countdown
if (currentCountdown < 0) {
clearInterval(countdownInterval); // Clear countdown interval
setIsCountingDown(false); // End countdown
spinWheel(); // Trigger spin after countdown
}
}, 1000);
};
const spinWheel = () => {
if (isSpinning) return;
setIsSpinning(true);
setCountdown(5); // Reset countdown
setIsSpinning(true); // Start spinning
const totalSpin = rotation + 360 * 10 + Math.random() * 360; // 10 full rotations + random offset
setRotation(totalSpin); // Update rotation to a new value
// Countdown logic
const countdownInterval = setInterval(() => {
setCountdown((prev) => {
if (prev === 0) {
clearInterval(countdownInterval);
return 0;
}
return prev - 1;
});
}, 1000);
// Reset everything after the spin duration
setTimeout(() => {
setIsSpinning(false);
setRotation((prev) => prev % 360); // Normalize the rotation
setCountdown(5); // Reset countdown for the next spin
triggerConfetti();
}, 6000); // Spin duration
triggerConfetti(); // Show confetti after spinning
}, 5000); // Spin duration
};
const handleSpinClick = () => {
if (!isSpinning && !isCountingDown) {
startCountdown(); // Start the countdown first
}
};
return (
<div className="flex flex-col items-center">
{/* {showConfetti && <ConfettiExplosion {...largeProps} />} */}
{showConfetti && (
<div className="fixed top-0 left-0 z-50">
<Confetti
width={width}
height={height}
recycle={false}
numberOfPieces={2000}
tweenDuration={10000}
run={true}
colors={[
"linear-gradient(45deg, #5D5D72, #8589DE)",
"linear-gradient(45deg, #E1E0FF, #575992)",
"#8589DE",
"#575992",
"#E1E0FF",
]}
/>
</div>
)}
<div className="relative rounded-full w-[554px] h-[554px]">
{/* Wheel triangle */}
<Image
src={'/wheel-triangle.svg'}
src={"/wheel-triangle.svg"}
alt="wheel"
height={34}
width={35}
@ -228,12 +90,13 @@ const SpinWheel: React.FC = () => {
<div
style={{
transform: `rotate(${rotation}deg)`,
transition: isSpinning ? 'transform 5s ease-out' : '',
transition: isSpinning ? "transform 5s ease-out" : "",
}}
className="p-3 bg-[#5D5D72] rounded-full overflow-hidden">
className="p-3 bg-[#5D5D72] rounded-full overflow-hidden"
>
<div className="p-[15px] bg-[#8589DE] rounded-full ">
<Image
src={'/wheel-circle-inner.png'}
src={"/wheel-circle-inner.png"}
alt="wheel"
height={530}
width={530}
@ -252,12 +115,19 @@ const SpinWheel: React.FC = () => {
{/* Spin Button */}
<button
onClick={spinWheel}
disabled={isSpinning}
onClick={handleSpinClick}
disabled={isSpinning || isCountingDown}
className={`mt-6 px-6 py-3 rounded-full text-white font-bold ${
isSpinning ? 'bg-gray-400 cursor-not-allowed' : 'bg-blue-500 hover:bg-blue-700'
}`}>
{isSpinning ? 'Spinning...' : 'Spin the Wheel'}
isSpinning || isCountingDown
? "bg-gray-400 cursor-not-allowed"
: "bg-blue-500 hover:bg-blue-700"
}`}
>
{isCountingDown
? `Starting in ${countdown}...`
: isSpinning
? "Spinning..."
: "Spin the Wheel"}
</button>
</div>
);

View File

@ -1,6 +1,6 @@
import { Dispatch, SetStateAction, useEffect, useState } from 'react';
import { differenceInSeconds, parseISO, addHours } from 'date-fns';
import GradientTitle from './GradientTitle';
import { Dispatch, SetStateAction, useEffect, useState } from "react";
import { differenceInSeconds, parseISO, addHours } from "date-fns";
import GradientTitle from "./GradientTitle";
interface CountdownProps {
startsAt: string;
@ -17,12 +17,12 @@ const Countdown: React.FC<CountdownProps> = ({
setEventStatus,
eventStatus,
}) => {
const [timeLeft, setTimeLeft] = useState<string>('');
const [timeLeft, setTimeLeft] = useState<string>("");
useEffect(() => {
// Parsing the start and end times to Date objects in the correct format
const startsAtDate = addHours(parseISO(startsAt.replace(' ', 'T')), 5); // Adjusting start time to UTC+5
const endsAtDate = addHours(parseISO(endsAt.replace(' ', 'T')), 5); // Adjusting end time to UTC+5
const startsAtDate = addHours(parseISO(startsAt.replace(" ", "T")), 5); // Adjusting start time to UTC+5
const endsAtDate = addHours(parseISO(endsAt.replace(" ", "T")), 5); // Adjusting end time to UTC+5
// Function to calculate time left
const calculateTimeLeft = () => {
@ -31,14 +31,14 @@ const Countdown: React.FC<CountdownProps> = ({
let difference;
if (nowUTC5 < startsAtDate) {
setEventStatus('Not started');
setEventStatus("Not started");
difference = differenceInSeconds(startsAtDate, nowUTC5);
} else if (nowUTC5 < endsAtDate) {
setEventStatus('Started');
setEventStatus("Started");
difference = differenceInSeconds(endsAtDate, nowUTC5);
} else {
setEventStatus('Finished');
setVoteStatus('closed');
setEventStatus("Finished");
setVoteStatus("closed");
return;
}
@ -47,9 +47,9 @@ const Countdown: React.FC<CountdownProps> = ({
const seconds = difference % 60;
setTimeLeft(
`${hours < 10 ? '0' + hours : hours}:${minutes < 10 ? '0' + minutes : minutes}:${
seconds < 10 ? '0' + seconds : seconds
}`,
`${hours < 10 ? "0" + hours : hours}:${
minutes < 10 ? "0" + minutes : minutes
}:${seconds < 10 ? "0" + seconds : seconds}`
);
};
@ -60,23 +60,41 @@ const Countdown: React.FC<CountdownProps> = ({
return (
<div>
{eventStatus === 'Finished' ? (
<GradientTitle title={'Netijeler'} size="big" />
) : eventStatus === 'Started' ? (
{eventStatus === "Finished" ? (
<GradientTitle title={"Netijeler"} size="big" />
) : eventStatus === "Started" ? (
<div className="flex flex-col justify-center items-center">
<div className="text-[44px] sm:text-[100px] leading-[100%] flex items-end font-bold bg-fancyTitle bg-clip-text text-transparent text-center">
<h2 className="flex flex-col items-center justify-center">{timeLeft.split(':')[0]}</h2>:
<h2 className="flex flex-col items-center justify-center">{timeLeft.split(':')[1]}</h2>:
<h2 className="flex flex-col items-center justify-center">{timeLeft.split(':')[2]}</h2>
<h2 className="flex flex-col items-center justify-center">
{timeLeft.split(":")[0]}
</h2>
:
<h2 className="flex flex-col items-center justify-center">
{timeLeft.split(":")[1]}
</h2>
:
<h2 className="flex flex-col items-center justify-center">
{timeLeft.split(":")[2]}
</h2>
</div>
</div>
) : eventStatus === 'Not started' ? (
) : eventStatus === "Not started" ? (
<div className="flex flex-col justify-center items-center">
<h1 className="font-semibold text-[24px] uppercase text-fillNavyBlue">Ses bermeklik</h1>
<h1 className="font-semibold text-[24px] uppercase text-fillNavyBlue">
Ses bermeklik
</h1>
<div className="text-[44px] sm:text-[100px] leading-[100%] flex items-end font-bold bg-fancyTitle bg-clip-text text-transparent text-center">
<h2 className="flex flex-col items-center justify-center">{timeLeft.split(':')[0]}</h2>:
<h2 className="flex flex-col items-center justify-center">{timeLeft.split(':')[1]}</h2>:
<h2 className="flex flex-col items-center justify-center">{timeLeft.split(':')[2]}</h2>
<h2 className="flex flex-col items-center justify-center">
{timeLeft.split(":")[0]}
</h2>
:
<h2 className="flex flex-col items-center justify-center">
{timeLeft.split(":")[1]}
</h2>
:
<h2 className="flex flex-col items-center justify-center">
{timeLeft.split(":")[2]}
</h2>
</div>
<h1 className="font-semibold text-[24px] uppercase text-fillNavyBlue mt-[16px]">
sagatdan başlaýar

1011
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -35,20 +35,22 @@
"next-seo": "^6.0.0",
"postcss": "8.4.23",
"react": "^18.2.0",
"react-confetti-explosion": "^2.1.2",
"react-confetti": "^6.1.0",
"react-day-picker": "^8.10.1",
"react-dom": "^18.2.0",
"react-fast-marquee": "^1.3.5",
"react-hook-form": "^7.43.9",
"react-icons": "^4.8.0",
"react-player": "^2.12.0",
"react-use": "^17.5.1",
"swiper": "^9.2.4",
"tailwind-merge": "^2.4.0",
"tailwindcss": "3.3.1",
"tailwindcss-animate": "^1.0.7",
"typescript": "^5.2.2",
"usehooks-ts": "^2.9.1",
"uuid": "^9.0.0"
"uuid": "^9.0.0",
"zustand": "^5.0.1"
},
"devDependencies": {
"@types/date-fns": "^2.6.0",