lotteryWinnersSection update
This commit is contained in:
parent
6c03d191b6
commit
fb6090d9fd
|
|
@ -1,24 +1,8 @@
|
|||
"use client";
|
||||
'use client';
|
||||
|
||||
import LotteryAuthForm from "@/components/lottery/auth/LotteryAuthForm";
|
||||
import { useEffect } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useLotteryAuth } from "@/store/useLotteryAuth";
|
||||
import LotteryAuthForm from '@/components/lottery/auth/LotteryAuthForm';
|
||||
|
||||
const LotteryAuthPage = () => {
|
||||
const router = useRouter();
|
||||
const { isAuthenticated, logout } = useLotteryAuth();
|
||||
|
||||
useEffect(() => {
|
||||
if (isAuthenticated) {
|
||||
router.push("/lottery");
|
||||
}
|
||||
}, [isAuthenticated, router]);
|
||||
|
||||
useEffect(() => {
|
||||
logout();
|
||||
}, [logout]);
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
<div className="flex justify-center items-center min-h-[50vh] py-[200px]">
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import LotteryWinnersSection from '@/components/lottery/LotteryWinnersSection';
|
|||
import LotteryRulesSection from '@/components/lottery/rules/LotteryRulesSection';
|
||||
import LotteryCountDown from '@/components/lottery/countDown/LotteryCountDown';
|
||||
import LotteryCountDownAllert from '@/components/lottery/countDown/countDownAllert/LotteryCountDownAllert';
|
||||
import { LotteryWinnerDataSimplified } from '@/typings/lottery/lottery.types';
|
||||
|
||||
const LotteryPage = () => {
|
||||
const { lotteryData } = useLotteryAuth();
|
||||
|
|
@ -42,15 +43,7 @@ const LotteryPage = () => {
|
|||
<LotteryRulesSection />
|
||||
|
||||
{lotteryData && (status === 'ended' || status === 'started') && (
|
||||
<div className="flex flex-col gap-[0px]">
|
||||
<LotteryCountDownAllert
|
||||
lotteryStatus={status}
|
||||
setLotteryStatus={setStatus}
|
||||
endDate={lotteryData.data.end_time}
|
||||
startDate={lotteryData.data.start_time}
|
||||
/>
|
||||
<LotteryWinnersSection lotteryStatus={status} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</ProtectedRoute>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
import { motion } from 'framer-motion';
|
||||
|
||||
interface AnimatedTextProps {
|
||||
text: string;
|
||||
className?: string;
|
||||
wordClassName?: string;
|
||||
initialY?: number;
|
||||
duration?: number;
|
||||
wordDelay?: number;
|
||||
}
|
||||
|
||||
const AnimatedText = ({
|
||||
text,
|
||||
className = '',
|
||||
wordClassName = '',
|
||||
initialY = -100,
|
||||
duration = 0.5,
|
||||
wordDelay = 0.2,
|
||||
}: AnimatedTextProps) => {
|
||||
const words = text.split(' ');
|
||||
|
||||
return (
|
||||
<div className="overflow-hidden">
|
||||
<motion.p
|
||||
className={className}
|
||||
initial={{ y: initialY, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
exit={{ y: initialY, opacity: 0 }}>
|
||||
{words.map((word, i) => (
|
||||
<motion.span
|
||||
key={i}
|
||||
initial={{ y: initialY, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
exit={{ y: initialY, opacity: 0 }}
|
||||
transition={{
|
||||
duration,
|
||||
delay: i * wordDelay,
|
||||
ease: 'easeOut',
|
||||
}}
|
||||
className={`inline-block mx-2 ${wordClassName}`}>
|
||||
{word}
|
||||
</motion.span>
|
||||
))}
|
||||
</motion.p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AnimatedText;
|
||||
|
|
@ -16,25 +16,6 @@ const LotteryHeader = ({ title, description, image, smsCode }: LotteryHeaderProp
|
|||
{title}
|
||||
</h1>
|
||||
<p className="text-center text-textLarge leading-textLarge">{description}</p>
|
||||
<div className="flex items-center gap-[8px] px-4 py-3 bg-lightInfoAllertContainer">
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M4.92893 4.92893C6.8043 3.05357 9.34784 2 12 2C14.6522 2 17.1957 3.05357 19.0711 4.92893C20.9464 6.8043 22 9.34784 22 12C22 13.3132 21.7413 14.6136 21.2388 15.8268C20.7362 17.0401 19.9997 18.1425 19.0711 19.0711C18.1425 19.9997 17.0401 20.7362 15.8268 21.2388C14.6136 21.7413 13.3132 22 12 22C10.6868 22 9.38642 21.7413 8.17317 21.2388C6.95991 20.7362 5.85752 19.9997 4.92893 19.0711C4.00035 18.1425 3.26375 17.0401 2.7612 15.8268C2.25866 14.6136 2 13.3132 2 12C2 9.34784 3.05357 6.8043 4.92893 4.92893ZM12 4C9.87827 4 7.84344 4.84285 6.34315 6.34315C4.84285 7.84344 4 9.87827 4 12C4 13.0506 4.20693 14.0909 4.60896 15.0615C5.011 16.0321 5.60028 16.914 6.34315 17.6569C7.08601 18.3997 7.96793 18.989 8.93853 19.391C9.90914 19.7931 10.9494 20 12 20C13.0506 20 14.0909 19.7931 15.0615 19.391C16.0321 18.989 16.914 18.3997 17.6569 17.6569C18.3997 16.914 18.989 16.0321 19.391 15.0615C19.7931 14.0909 20 13.0506 20 12C20 9.87827 19.1571 7.84344 17.6569 6.34315C16.1566 4.84285 14.1217 4 12 4ZM11 9C11 8.44772 11.4477 8 12 8H12.01C12.5623 8 13.01 8.44772 13.01 9C13.01 9.55228 12.5623 10 12.01 10H12C11.4477 10 11 9.55228 11 9ZM10 12C10 11.4477 10.4477 11 11 11H12C12.5523 11 13 11.4477 13 12V15C13.5523 15 14 15.4477 14 16C14 16.5523 13.5523 17 13 17H12C11.4477 17 11 16.5523 11 16V13C10.4477 13 10 12.5523 10 12Z"
|
||||
fill="#1E3A5F"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<span className="font-base-medium text-lightOnInfoAllertContainer">
|
||||
SMS-kod: {smsCode}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{image && (
|
||||
<div className="md:mb-8 sm:mb-[40px] mb-[16px]">
|
||||
|
|
|
|||
|
|
@ -1,42 +1,40 @@
|
|||
"use client";
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
import { useLotteryAuth } from "@/store/useLotteryAuth";
|
||||
import { LotteryWinnerDataSimplified } from "@/typings/lottery/lottery.types";
|
||||
import LotteryWinnersList from "./winners/LotteryWinnersList";
|
||||
import LotterySlotCounter from "./slotCounter/LotterySlotCounter";
|
||||
import ReactConfetti from "react-confetti";
|
||||
import { useWindowSize } from "react-use";
|
||||
import LotteryCountDownAllert from "./countDown/countDownAllert/LotteryCountDownAllert";
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
import { useLotteryAuth } from '@/store/useLotteryAuth';
|
||||
import { LotteryWinnerDataSimplified } from '@/typings/lottery/lottery.types';
|
||||
import LotteryWinnersList from './winners/LotteryWinnersList';
|
||||
import LotterySlotCounter from './slotCounter/LotterySlotCounter';
|
||||
import ReactConfetti from 'react-confetti';
|
||||
import { useWindowSize } from 'react-use';
|
||||
import LotteryCountDownAllert from './countDown/countDownAllert/LotteryCountDownAllert';
|
||||
import { motion } from 'framer-motion';
|
||||
import AnimatedText from '@/components/common/AnimatedText';
|
||||
|
||||
const WEBSOCKET_URL = "wss://sms.turkmentv.gov.tm/ws/lottery?dst=0506";
|
||||
const WEBSOCKET_URL = 'wss://sms.turkmentv.gov.tm/ws/lottery?dst=0506';
|
||||
const PING_INTERVAL = 25000;
|
||||
const SLOT_COUNTER_DURATION = 20000;
|
||||
|
||||
const LotteryWinnersSection = ({
|
||||
lotteryStatus,
|
||||
}: {
|
||||
lotteryStatus: string;
|
||||
}) => {
|
||||
const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) => {
|
||||
// UI States
|
||||
const [winners, setWinners] = useState<LotteryWinnerDataSimplified[]>([]);
|
||||
const [currentNumber, setCurrentNumber] = useState<string>("00-00-00-00-00");
|
||||
const [currentNumber, setCurrentNumber] = useState<string>('00-00-00-00-00');
|
||||
const [isConfettiActive, setIsConfettiActive] = useState(false);
|
||||
|
||||
const [wsStatus, setWsStatus] = useState<
|
||||
"connecting" | "connected" | "error"
|
||||
>("connecting");
|
||||
const [wsStatus, setWsStatus] = useState<'connecting' | 'connected' | 'error'>('connecting');
|
||||
const { width, height } = useWindowSize();
|
||||
const { lotteryData } = useLotteryAuth();
|
||||
const [isSlotCounterAnimating, setIsSlotCounterAnimating] = useState(false);
|
||||
const [pendingWinner, setPendingWinner] =
|
||||
useState<LotteryWinnerDataSimplified | null>(null);
|
||||
const [pendingWinner, setPendingWinner] = useState<LotteryWinnerDataSimplified | null>(null);
|
||||
|
||||
// Refs
|
||||
const wsRef = useRef<WebSocket | null>(null);
|
||||
const pingIntervalRef = useRef<NodeJS.Timeout>();
|
||||
const mountedRef = useRef(false);
|
||||
|
||||
// Add new state for display text
|
||||
const [displayText, setDisplayText] = useState<string>('...');
|
||||
|
||||
// Initialize winners from lottery data
|
||||
useEffect(() => {
|
||||
if (lotteryData?.data.winners) {
|
||||
|
|
@ -46,9 +44,7 @@ const LotteryWinnersSection = ({
|
|||
ticket: winner.ticket,
|
||||
}));
|
||||
setWinners(simplifiedWinners);
|
||||
setCurrentNumber(
|
||||
lotteryData.data.winners.at(-1)?.ticket || "00-00-00-00-00"
|
||||
);
|
||||
setCurrentNumber(lotteryData.data.winners.at(-1)?.ticket || '00-00-00-00-00');
|
||||
}
|
||||
}, [lotteryData]);
|
||||
|
||||
|
|
@ -61,21 +57,21 @@ const LotteryWinnersSection = ({
|
|||
const socket = new WebSocket(WEBSOCKET_URL);
|
||||
wsRef.current = socket;
|
||||
|
||||
socket.addEventListener("open", () => {
|
||||
socket.addEventListener('open', () => {
|
||||
if (!mountedRef.current) return;
|
||||
console.log("WebSocket Connected");
|
||||
setWsStatus("connected");
|
||||
console.log('WebSocket Connected');
|
||||
setWsStatus('connected');
|
||||
|
||||
pingIntervalRef.current = setInterval(() => {
|
||||
if (socket.readyState === WebSocket.OPEN) {
|
||||
socket.send(JSON.stringify({ type: "ping" }));
|
||||
socket.send(JSON.stringify({ type: 'ping' }));
|
||||
}
|
||||
}, PING_INTERVAL);
|
||||
});
|
||||
|
||||
socket.addEventListener("message", async (event) => {
|
||||
socket.addEventListener('message', async (event) => {
|
||||
if (!mountedRef.current) return;
|
||||
console.log("Message received:", event.data);
|
||||
console.log('Message received:', event.data);
|
||||
|
||||
try {
|
||||
const newWinner = JSON.parse(event.data);
|
||||
|
|
@ -85,67 +81,58 @@ const LotteryWinnersSection = ({
|
|||
ticket: newWinner.ticket,
|
||||
};
|
||||
|
||||
// Set initial animation text
|
||||
setDisplayText(`${winnerData.winner_no}-nji ýeňiji saýlanýar`);
|
||||
|
||||
// Start the sequence
|
||||
setIsSlotCounterAnimating(true);
|
||||
setPendingWinner(winnerData);
|
||||
setCurrentNumber(winnerData.ticket);
|
||||
|
||||
// Wait for slot counter animation
|
||||
await new Promise((resolve) =>
|
||||
setTimeout(resolve, SLOT_COUNTER_DURATION)
|
||||
);
|
||||
await new Promise((resolve) => setTimeout(resolve, SLOT_COUNTER_DURATION));
|
||||
|
||||
// Update text to show winner's phone
|
||||
setDisplayText(winnerData.client);
|
||||
|
||||
setIsConfettiActive(true);
|
||||
setWinners((prev) => [...prev, winnerData]);
|
||||
|
||||
// Hide confetti after 5 seconds
|
||||
// setTimeout(() => {
|
||||
// if (mountedRef.current) {
|
||||
// setIsConfettiActive(false);
|
||||
// setIsSlotCounterAnimating(false);
|
||||
// setPendingWinner(null);
|
||||
// }
|
||||
// }, 5000);
|
||||
|
||||
// Show confetti and add winner simultaneously
|
||||
if (mountedRef.current) {
|
||||
setIsConfettiActive(true);
|
||||
setWinners((prev) => [...prev, winnerData]);
|
||||
|
||||
// Hide confetti after 5 seconds
|
||||
// Reset everything after 5 seconds
|
||||
setTimeout(() => {
|
||||
if (mountedRef.current) {
|
||||
setIsConfettiActive(false);
|
||||
setIsSlotCounterAnimating(false);
|
||||
setPendingWinner(null);
|
||||
setDisplayText('...'); // Reset text
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error processing message:", error);
|
||||
console.error('Error processing message:', error);
|
||||
setIsSlotCounterAnimating(false);
|
||||
setPendingWinner(null);
|
||||
setDisplayText('...'); // Reset text on error
|
||||
}
|
||||
});
|
||||
|
||||
socket.addEventListener("error", (error) => {
|
||||
socket.addEventListener('error', (error) => {
|
||||
if (!mountedRef.current) return;
|
||||
console.error("WebSocket Error:", error);
|
||||
setWsStatus("error");
|
||||
console.error('WebSocket Error:', error);
|
||||
setWsStatus('error');
|
||||
});
|
||||
|
||||
socket.addEventListener("close", () => {
|
||||
socket.addEventListener('close', () => {
|
||||
if (!mountedRef.current) return;
|
||||
console.log("WebSocket Closed");
|
||||
setWsStatus("error");
|
||||
console.log('WebSocket Closed');
|
||||
setWsStatus('error');
|
||||
|
||||
if (pingIntervalRef.current) {
|
||||
clearInterval(pingIntervalRef.current);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error creating WebSocket:", error);
|
||||
setWsStatus("error");
|
||||
console.error('Error creating WebSocket:', error);
|
||||
setWsStatus('error');
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -165,7 +152,7 @@ const LotteryWinnersSection = ({
|
|||
|
||||
return (
|
||||
<section>
|
||||
{wsStatus === "error" && (
|
||||
{wsStatus === 'error' && (
|
||||
<div className="text-red-500 text-center mb-2">
|
||||
Connection error. Please refresh the page.
|
||||
</div>
|
||||
|
|
@ -181,26 +168,29 @@ const LotteryWinnersSection = ({
|
|||
tweenDuration={10000}
|
||||
run={true}
|
||||
colors={[
|
||||
"linear-gradient(45deg, #5D5D72, #8589DE)",
|
||||
"linear-gradient(45deg, #E1E0FF, #575992)",
|
||||
"#8589DE",
|
||||
"#575992",
|
||||
"#E1E0FF",
|
||||
"#BA1A1A",
|
||||
'linear-gradient(45deg, #5D5D72, #8589DE)',
|
||||
'linear-gradient(45deg, #E1E0FF, #575992)',
|
||||
'#8589DE',
|
||||
'#575992',
|
||||
'#E1E0FF',
|
||||
'#BA1A1A',
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="container">
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="translate-y-1/2 z-10">
|
||||
<LotterySlotCounter
|
||||
numberString={currentNumber}
|
||||
isAnimating={isSlotCounterAnimating}
|
||||
<div
|
||||
className="flex flex-col items-center rounded-[32px] pt-[40px]"
|
||||
style={{ background: 'linear-gradient(180deg, #F0ECF4 0%, #E1E0FF 43.5%)' }}>
|
||||
<AnimatedText
|
||||
text={displayText}
|
||||
className="text-center text-[100px] leading-[108px] text-[#E65E19]"
|
||||
/>
|
||||
<div className="translate-y-1/2 z-10">
|
||||
<LotterySlotCounter numberString={currentNumber} isAnimating={isSlotCounterAnimating} />
|
||||
</div>
|
||||
<div className="flex gap-6 bg-lightPrimaryContainer rounded-[12px] flex-1 w-full items-center justify-center md:pt-[122px] sm:pt-[90px] pt-[40px] sm:pb-[62px] pb-[32px] px-4">
|
||||
<div className="flex gap-6 rounded-[12px] flex-1 w-full items-center justify-center md:pt-[122px] sm:pt-[90px] pt-[40px] sm:pb-[62px] pb-[32px] px-4">
|
||||
<LotteryWinnersList winners={winners} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,24 +1,41 @@
|
|||
'use client';
|
||||
|
||||
import { useEffect } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useLotteryAuth } from '@/store/useLotteryAuth';
|
||||
import { Queries } from '@/api/queries';
|
||||
|
||||
interface ProtectedRouteProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const ProtectedRoute = ({ children }: ProtectedRouteProps) => {
|
||||
const ProtectedRoute = ({ children }: { children: React.ReactNode }) => {
|
||||
const router = useRouter();
|
||||
const { isAuthenticated } = useLotteryAuth();
|
||||
const { isAuthenticated, phone, code, setAuth } = useLotteryAuth();
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isAuthenticated) {
|
||||
const checkAuth = async () => {
|
||||
// First, check if we have credentials in localStorage
|
||||
if (phone && code) {
|
||||
try {
|
||||
// Try to authenticate with stored credentials
|
||||
const response = await Queries.authenticateLottery(phone, code);
|
||||
setAuth(response, phone, code);
|
||||
setIsLoading(false);
|
||||
return; // Exit early if authentication successful
|
||||
} catch (err) {
|
||||
console.error('Authentication failed:', err);
|
||||
// Only redirect if API request fails
|
||||
router.replace('/lottery/auth');
|
||||
}
|
||||
}, [isAuthenticated, router]);
|
||||
} else {
|
||||
// Only redirect if no credentials found
|
||||
router.replace('/lottery/auth');
|
||||
}
|
||||
};
|
||||
|
||||
if (!isAuthenticated) {
|
||||
checkAuth();
|
||||
}, []);
|
||||
|
||||
// Show nothing while checking auth
|
||||
if (isLoading) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,27 +1,24 @@
|
|||
"use client";
|
||||
import Image from "next/image";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import SlotCounter from "react-slot-counter";
|
||||
import { useMediaQuery } from "usehooks-ts";
|
||||
'use client';
|
||||
import Image from 'next/image';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import SlotCounter from 'react-slot-counter';
|
||||
import { useMediaQuery } from 'usehooks-ts';
|
||||
|
||||
interface LotterySlotCounterProps {
|
||||
numberString: string;
|
||||
isAnimating: boolean;
|
||||
}
|
||||
|
||||
const LotterySlotCounter = ({
|
||||
numberString,
|
||||
isAnimating,
|
||||
}: LotterySlotCounterProps) => {
|
||||
const LotterySlotCounter = ({ numberString, isAnimating }: LotterySlotCounterProps) => {
|
||||
const [formattedNumber, setFormattedNumber] = useState(numberString);
|
||||
|
||||
useEffect(() => {
|
||||
const formatted = numberString.replace(/-/g, ",");
|
||||
const formatted = numberString.replace(/-/g, ',');
|
||||
setFormattedNumber(formatted);
|
||||
}, [numberString]);
|
||||
|
||||
const tablet = useMediaQuery("(max-width: 769px)");
|
||||
const mobile = useMediaQuery("(max-width: 426px)");
|
||||
const tablet = useMediaQuery('(max-width: 769px)');
|
||||
const mobile = useMediaQuery('(max-width: 426px)');
|
||||
|
||||
return (
|
||||
<div className="relative w-fit">
|
||||
|
|
@ -65,31 +62,29 @@ const LotterySlotCounter = ({
|
|||
className="flex items-center h-fit md:max-w-[1132px] sm:max-w-[640px] max-w-[324px] w-full justify-center text-white md:py-4 md:px-6 rounded-full overflow-y-hidden overflow-x-visible relative border-4 border-lightPrimary"
|
||||
style={{
|
||||
background:
|
||||
"linear-gradient(180deg, #454673 0%, #575992 10.5%, #575992 90%, #454673 100%)",
|
||||
boxShadow: "0px 4px 4px 0px #00000040",
|
||||
}}
|
||||
>
|
||||
'linear-gradient(180deg, #454673 0%, #575992 10.5%, #575992 90%, #454673 100%)',
|
||||
boxShadow: '0px 4px 4px 0px #00000040',
|
||||
}}>
|
||||
{/* Highlight */}
|
||||
<div
|
||||
className="absolute top-[50%] -translate-y-1/2 left-0 w-full h-full"
|
||||
style={{
|
||||
background:
|
||||
"linear-gradient(180deg, rgba(87, 89, 146, 0) 0%, #7274AB 50%, rgba(87, 89, 146, 0) 100%)",
|
||||
}}
|
||||
></div>
|
||||
'linear-gradient(180deg, rgba(87, 89, 146, 0) 0%, #7274AB 50%, rgba(87, 89, 146, 0) 100%)',
|
||||
}}></div>
|
||||
|
||||
<div className="z-10">
|
||||
<SlotCounter
|
||||
value={formattedNumber}
|
||||
// startValue={'00,00,00,00,00'}
|
||||
startValue={formattedNumber}
|
||||
charClassName="rolling-number"
|
||||
separatorClassName="slot-seperator"
|
||||
duration={2}
|
||||
speed={2}
|
||||
startFromLastDigit
|
||||
delay={2}
|
||||
animateUnchanged={true}
|
||||
// autoAnimationStart={false}
|
||||
animateUnchanged={false}
|
||||
autoAnimationStart={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,9 @@
|
|||
import {
|
||||
LotteryWinnerData,
|
||||
LotteryWinnerDataSimplified,
|
||||
} from "@/typings/lottery/lottery.types";
|
||||
import LotteryWinner from "./LotteryWinner";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { v4 } from "uuid";
|
||||
import { LotteryWinnerData, LotteryWinnerDataSimplified } from '@/typings/lottery/lottery.types';
|
||||
import LotteryWinner from './LotteryWinner';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
const LotteryWinnersList = ({
|
||||
winners,
|
||||
}: {
|
||||
winners: LotteryWinnerDataSimplified[];
|
||||
}) => {
|
||||
const LotteryWinnersList = ({ winners }: { winners: LotteryWinnerDataSimplified[] }) => {
|
||||
return (
|
||||
<div className="flex flex-col gap-4 w-full max-w-[1028px]">
|
||||
<div className="flex flex-col gap-2 w-full pb-4 border-b border-[#CECCFF]">
|
||||
|
|
@ -21,9 +14,8 @@ const LotteryWinnersList = ({
|
|||
</div>
|
||||
<motion.div
|
||||
layout
|
||||
className="grid md:grid-cols-3 sm:grid-cols-2 grid-cols-1 gap-x-2 gap-y-4 w-full h-[244px] overflow-y-auto lottery-scrollbar"
|
||||
>
|
||||
<AnimatePresence mode="popLayout">
|
||||
className="grid md:grid-cols-3 sm:grid-cols-2 grid-cols-1 gap-x-2 gap-y-4 w-full ">
|
||||
<AnimatePresence mode="wait">
|
||||
{winners.map((item, index) => (
|
||||
<LotteryWinner
|
||||
key={v4()}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { create } from 'zustand';
|
||||
import { ILotteryResponse } from '@/models/lottery/lottery.model';
|
||||
import { persist } from 'zustand/middleware';
|
||||
|
||||
interface LotteryAuthState {
|
||||
isAuthenticated: boolean;
|
||||
|
|
@ -10,21 +11,30 @@ interface LotteryAuthState {
|
|||
logout: () => void;
|
||||
}
|
||||
|
||||
export const useLotteryAuth = create<LotteryAuthState>((set) => ({
|
||||
export const useLotteryAuth = create<LotteryAuthState>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
isAuthenticated: false,
|
||||
lotteryData: null,
|
||||
phone: null,
|
||||
code: null,
|
||||
setAuth: (data, phone, code) => set({
|
||||
setAuth: (data, phone, code) =>
|
||||
set({
|
||||
isAuthenticated: true,
|
||||
lotteryData: data,
|
||||
phone,
|
||||
code
|
||||
code,
|
||||
}),
|
||||
logout: () => set({
|
||||
logout: () =>
|
||||
set({
|
||||
isAuthenticated: false,
|
||||
lotteryData: null,
|
||||
phone: null,
|
||||
code: null
|
||||
code: null,
|
||||
}),
|
||||
}));
|
||||
}),
|
||||
{
|
||||
name: 'lottery-auth-storage',
|
||||
},
|
||||
),
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in New Issue