last work on lottery/
This commit is contained in:
parent
28d98cd790
commit
687a7f0f81
|
|
@ -329,6 +329,11 @@ big {
|
||||||
.rolling-number {
|
.rolling-number {
|
||||||
@apply text-[24px] px-1;
|
@apply text-[24px] px-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.slot-seperator {
|
||||||
|
content: url('/dash-md.svg');
|
||||||
|
@apply !mx-1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 320px) {
|
@media (max-width: 320px) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { motion } from 'framer-motion';
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
|
|
||||||
interface AnimatedTextProps {
|
interface AnimatedTextProps {
|
||||||
text: string;
|
text: string;
|
||||||
|
|
@ -23,31 +23,38 @@ const AnimatedText = ({
|
||||||
const characters = text.split('');
|
const characters = text.split('');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="overflow-hidden">
|
<motion.div className="overflow-hidden">
|
||||||
<motion.p
|
<motion.p
|
||||||
className={cn(`flex `, className)}
|
className={cn(`flex`, className)}
|
||||||
initial={{ translateY: initialY, opacity: 0 }}
|
variants={{
|
||||||
animate={{ translateY: 0, opacity: 1 }}
|
enter: {
|
||||||
exit={{ translateY: exitY, opacity: 0 }}>
|
transition: { staggerChildren: 1, delayChildren: 0.5 },
|
||||||
{characters.map((character, i) => (
|
},
|
||||||
<motion.div
|
exit: {
|
||||||
key={i}
|
transition: { staggerChildren: 0.05, staggerDirection: -1 },
|
||||||
initial={{ translateY: initialY, opacity: 0 }}
|
},
|
||||||
animate={{ translateY: 0, opacity: 1 }}
|
}}>
|
||||||
exit={{ translateY: exitY, opacity: 0 }}
|
<AnimatePresence>
|
||||||
transition={{
|
{characters.map((character, i) => (
|
||||||
duration,
|
<motion.div
|
||||||
delay: characterDelay + (i / 2) * duration,
|
key={i}
|
||||||
ease: 'easeOut',
|
initial={{ translateY: '-100%', opacity: 0 }}
|
||||||
}}
|
animate={{ translateY: 0, opacity: 1 }}
|
||||||
className={cn(`block `, characterClassName, {
|
exit={{ translateY: '100%', opacity: 0 }}
|
||||||
'animate-dotsFlash': text === '...',
|
transition={{
|
||||||
})}>
|
duration,
|
||||||
{character}
|
delay: characterDelay + (i / 5) * duration,
|
||||||
</motion.div>
|
ease: 'easeOut',
|
||||||
))}
|
}}
|
||||||
|
className={cn(`block`, characterClassName, {
|
||||||
|
'animate-dotsFlash': text === '...',
|
||||||
|
})}>
|
||||||
|
{character === ' ' ? '\u00A0' : character}
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</AnimatePresence>
|
||||||
</motion.p>
|
</motion.p>
|
||||||
</div>
|
</motion.div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import ReactConfetti from 'react-confetti';
|
import ReactConfetti from 'react-confetti';
|
||||||
import { useWindowSize } from 'react-use';
|
import { useWindowSize } from 'react-use';
|
||||||
|
import { useMediaQuery } from 'usehooks-ts';
|
||||||
|
|
||||||
const Confetti = ({
|
const Confetti = ({
|
||||||
numberOfPieces = 200,
|
numberOfPieces = 200,
|
||||||
|
|
@ -21,13 +22,15 @@ const Confetti = ({
|
||||||
'#FF3131',
|
'#FF3131',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const mobile = useMediaQuery('(max-width: 426px)');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed top-0 left-0 z-50">
|
<div className="fixed top-0 left-0 z-50">
|
||||||
<ReactConfetti
|
<ReactConfetti
|
||||||
width={width}
|
width={width}
|
||||||
height={height}
|
height={height}
|
||||||
recycle={showConfetti}
|
recycle={showConfetti}
|
||||||
numberOfPieces={numberOfPieces}
|
numberOfPieces={mobile ? numberOfPieces / 3 : numberOfPieces}
|
||||||
tweenDuration={500}
|
tweenDuration={500}
|
||||||
// run={true}
|
// run={true}
|
||||||
colors={colors}
|
colors={colors}
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,10 @@ import { useWindowSize } from 'react-use';
|
||||||
import AnimatedText from '@/components/common/AnimatedText';
|
import AnimatedText from '@/components/common/AnimatedText';
|
||||||
import { useWebsocketLottery } from '@/hooks/useWebSocketLottery';
|
import { useWebsocketLottery } from '@/hooks/useWebSocketLottery';
|
||||||
import Confetti from '../common/Confetti';
|
import Confetti from '../common/Confetti';
|
||||||
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
|
|
||||||
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 SLOT_COUNTER_DURATION = 100000;
|
const SLOT_COUNTER_DURATION = 30000;
|
||||||
|
|
||||||
const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) => {
|
const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) => {
|
||||||
const [winners, setWinners] = useState<LotteryWinnerDataSimplified[]>([]);
|
const [winners, setWinners] = useState<LotteryWinnerDataSimplified[]>([]);
|
||||||
|
|
@ -39,7 +40,7 @@ const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) =>
|
||||||
setWinners(simplifiedWinners);
|
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');
|
||||||
setWinnerSelectingStatus('selected');
|
setWinnerSelectingStatus('selected');
|
||||||
setTopText('Ýeňiji');
|
setTopText(`${lotteryData.data.winners.at(-1)?.winner_no}-nji(y) ýeňiji`);
|
||||||
setBottomText(lotteryData.data.winners.at(-1)?.client || '');
|
setBottomText(lotteryData.data.winners.at(-1)?.client || '');
|
||||||
setIsConfettiActive(true);
|
setIsConfettiActive(true);
|
||||||
}
|
}
|
||||||
|
|
@ -60,9 +61,7 @@ const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) =>
|
||||||
ticket: newWinner.ticket,
|
ticket: newWinner.ticket,
|
||||||
};
|
};
|
||||||
|
|
||||||
setTimeout(() => {
|
setIsConfettiActive(false);
|
||||||
setIsConfettiActive(false);
|
|
||||||
}, 1000);
|
|
||||||
setTopText(`${winnerData.winner_no}-nji(y) ýeňiji saýlanýar`);
|
setTopText(`${winnerData.winner_no}-nji(y) ýeňiji saýlanýar`);
|
||||||
setBottomText('...');
|
setBottomText('...');
|
||||||
setWinnerSelectingStatus('is-selecting');
|
setWinnerSelectingStatus('is-selecting');
|
||||||
|
|
@ -70,12 +69,12 @@ const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) =>
|
||||||
setCurrentNumber(winnerData.ticket);
|
setCurrentNumber(winnerData.ticket);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setTopText('Ýeniji');
|
setTopText(`${winnerData.winner_no}-nji(y) ýeňiji`);
|
||||||
setBottomText(winnerData.client);
|
setBottomText(winnerData.client);
|
||||||
setWinnerSelectingStatus('selected');
|
setWinnerSelectingStatus('selected');
|
||||||
setIsConfettiActive(true);
|
setIsConfettiActive(true);
|
||||||
setWinners((prev) => [...prev, winnerData]);
|
setWinners((prev) => [...prev, winnerData]);
|
||||||
}, SLOT_COUNTER_DURATION + 500);
|
}, SLOT_COUNTER_DURATION);
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
|
@ -83,6 +82,25 @@ const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) =>
|
||||||
};
|
};
|
||||||
}, [subscribeToMessages]);
|
}, [subscribeToMessages]);
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
// setTimeout(() => {
|
||||||
|
// setIsConfettiActive(false);
|
||||||
|
// setTopText(`${1}-nji(y) ýeňiji saýlanýar`);
|
||||||
|
// setBottomText('...');
|
||||||
|
// setWinnerSelectingStatus('is-selecting');
|
||||||
|
// // setPendingWinner(winnerData);
|
||||||
|
// setCurrentNumber('55-44-33-22-11');
|
||||||
|
|
||||||
|
// setTimeout(() => {
|
||||||
|
// setTopText('Ýeniji');
|
||||||
|
// setBottomText('99361245555');
|
||||||
|
// setWinnerSelectingStatus('selected');
|
||||||
|
// setIsConfettiActive(true);
|
||||||
|
// // setWinners((prev) => [...prev, winnerData]);
|
||||||
|
// }, SLOT_COUNTER_DURATION);
|
||||||
|
// }, 10000);
|
||||||
|
// }, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
{wsStatus === 'error' && (
|
{wsStatus === 'error' && (
|
||||||
|
|
@ -95,47 +113,62 @@ const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) =>
|
||||||
style={{
|
style={{
|
||||||
background: 'linear-gradient(180deg, #F0ECF4 0%, #E1E0FF 43.5%)',
|
background: 'linear-gradient(180deg, #F0ECF4 0%, #E1E0FF 43.5%)',
|
||||||
}}>
|
}}>
|
||||||
<div className="flex items-center justify-center w-full min-h-[240px]">
|
<AnimatePresence>
|
||||||
{winnerSelectingStatus === 'not-selected' ? (
|
<div className="flex items-center justify-center w-full sm:min-h-[240px] pt-6">
|
||||||
// <TextMaskReveal
|
{winnerSelectingStatus === 'not-selected' ? (
|
||||||
// text={topText}
|
// <TextMaskReveal
|
||||||
// className="text-center flex items-center justify-center text-[100px] leading-[108px] text-[#E65E19]"
|
// text={topText}
|
||||||
// duration={0.5}
|
// className="text-center flex items-center justify-center text-[100px] leading-[108px] text-[#E65E19]"
|
||||||
// />
|
// duration={0.5}
|
||||||
<AnimatedText
|
// />
|
||||||
text={topText}
|
<AnimatedText
|
||||||
className="text-center flex items-center justify-center text-[100px] leading-[108px] text-[#E65E19]"
|
key={topText}
|
||||||
duration={0.4}
|
text={topText}
|
||||||
/>
|
className="text-center flex items-center justify-center sm:text-[100px] text-[48px] leading-[120%] text-[#E65E19]"
|
||||||
) : (
|
duration={0.4}
|
||||||
<div className="flex flex-col items-center justify-center">
|
/>
|
||||||
{/* <TextMaskReveal
|
) : (
|
||||||
|
<motion.div
|
||||||
|
variants={{
|
||||||
|
enter: {
|
||||||
|
transition: { staggerChildren: 1, delayChildren: 0.5 },
|
||||||
|
},
|
||||||
|
exit: {
|
||||||
|
transition: { staggerChildren: 0.05, staggerDirection: -1 },
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
className="flex flex-col items-center justify-center">
|
||||||
|
{/* <TextMaskReveal
|
||||||
text={topText}
|
text={topText}
|
||||||
className="text-center text-[56px] leading-[64px] text-[#E65E19]"
|
className="text-center text-[56px] leading-[64px] text-[#E65E19]"
|
||||||
duration={0.4}
|
duration={0.4}
|
||||||
/> */}
|
/> */}
|
||||||
<AnimatedText
|
|
||||||
text={topText}
|
|
||||||
className="text-center text-[56px] leading-[64px] text-[#E65E19]"
|
|
||||||
duration={0.4}
|
|
||||||
/>
|
|
||||||
{bottomText && (
|
|
||||||
// <TextMaskReveal
|
|
||||||
// text={bottomText}
|
|
||||||
// className="text-center text-[80px] leading-[88px] text-[#E65E19]"
|
|
||||||
// duration={0.4}
|
|
||||||
// startDelay={3}
|
|
||||||
// />
|
|
||||||
<AnimatedText
|
<AnimatedText
|
||||||
text={bottomText}
|
key={topText}
|
||||||
className="text-center text-[80px] leading-[88px] text-[#E65E19]"
|
text={topText}
|
||||||
|
className="text-center sm:text-[56px] text-[24px] w-full leading-[120%] text-[#E65E19]"
|
||||||
duration={0.4}
|
duration={0.4}
|
||||||
characterDelay={1.3}
|
|
||||||
/>
|
/>
|
||||||
)}
|
{bottomText && (
|
||||||
</div>
|
// <TextMaskReveal
|
||||||
)}
|
// text={bottomText}
|
||||||
</div>
|
// className="text-center text-[80px] leading-[88px] text-[#E65E19]"
|
||||||
|
// duration={0.4}
|
||||||
|
// startDelay={3}
|
||||||
|
// />
|
||||||
|
<AnimatedText
|
||||||
|
key={bottomText}
|
||||||
|
text={bottomText}
|
||||||
|
className="text-center sm:text-[80px] text-[32px] leading-[120%] text-[#E65E19]"
|
||||||
|
duration={0.4}
|
||||||
|
// characterDelay={2}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</AnimatePresence>
|
||||||
|
|
||||||
<div className="z-10">
|
<div className="z-10">
|
||||||
{currentNumber && <LotterySlotCounter numberString={currentNumber} />}
|
{currentNumber && <LotterySlotCounter numberString={currentNumber} />}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ const LotterySlotCounter = ({ numberString }: LotterySlotCounterProps) => {
|
||||||
alt="roller-triangle"
|
alt="roller-triangle"
|
||||||
width={24}
|
width={24}
|
||||||
height={24}
|
height={24}
|
||||||
className="absolute left-0 top-1/2 -translate-y-1/2 -translate-x-1/2 z-20"
|
className="absolute left-0 top-1/2 -translate-y-1/2 -translate-x-2/3 z-20"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Image
|
<Image
|
||||||
|
|
@ -45,7 +45,7 @@ const LotterySlotCounter = ({ numberString }: LotterySlotCounterProps) => {
|
||||||
alt="roller-triangle"
|
alt="roller-triangle"
|
||||||
width={24}
|
width={24}
|
||||||
height={24}
|
height={24}
|
||||||
className="absolute right-0 top-1/2 -translate-y-1/2 translate-x-1/2 z-20 rotate-180"
|
className="absolute right-0 top-1/2 -translate-y-1/2 translate-x-2/3 z-20 rotate-180"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Image
|
<Image
|
||||||
|
|
@ -58,7 +58,7 @@ const LotterySlotCounter = ({ numberString }: LotterySlotCounterProps) => {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
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"
|
className="flex items-center h-fit md:max-w-[1132px] sm:max-w-[640px] max-w-[400px] 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={{
|
style={{
|
||||||
background:
|
background:
|
||||||
'linear-gradient(180deg, #454673 0%, #575992 10.5%, #575992 90%, #454673 100%)',
|
'linear-gradient(180deg, #454673 0%, #575992 10.5%, #575992 90%, #454673 100%)',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue