last work on lottery/

This commit is contained in:
Kakabay 2025-01-09 19:53:20 +05:00
parent 28d98cd790
commit 687a7f0f81
5 changed files with 117 additions and 69 deletions

View File

@ -329,6 +329,11 @@ big {
.rolling-number {
@apply text-[24px] px-1;
}
.slot-seperator {
content: url('/dash-md.svg');
@apply !mx-1;
}
}
@media (max-width: 320px) {

View File

@ -1,5 +1,5 @@
import { cn } from '@/lib/utils';
import { motion } from 'framer-motion';
import { AnimatePresence, motion } from 'framer-motion';
interface AnimatedTextProps {
text: string;
@ -23,31 +23,38 @@ const AnimatedText = ({
const characters = text.split('');
return (
<div className="overflow-hidden">
<motion.div className="overflow-hidden">
<motion.p
className={cn(`flex `, className)}
initial={{ translateY: initialY, opacity: 0 }}
animate={{ translateY: 0, opacity: 1 }}
exit={{ translateY: exitY, opacity: 0 }}>
{characters.map((character, i) => (
<motion.div
key={i}
initial={{ translateY: initialY, opacity: 0 }}
animate={{ translateY: 0, opacity: 1 }}
exit={{ translateY: exitY, opacity: 0 }}
transition={{
duration,
delay: characterDelay + (i / 2) * duration,
ease: 'easeOut',
}}
className={cn(`block `, characterClassName, {
'animate-dotsFlash': text === '...',
})}>
{character}
</motion.div>
))}
className={cn(`flex`, className)}
variants={{
enter: {
transition: { staggerChildren: 1, delayChildren: 0.5 },
},
exit: {
transition: { staggerChildren: 0.05, staggerDirection: -1 },
},
}}>
<AnimatePresence>
{characters.map((character, i) => (
<motion.div
key={i}
initial={{ translateY: '-100%', opacity: 0 }}
animate={{ translateY: 0, opacity: 1 }}
exit={{ translateY: '100%', opacity: 0 }}
transition={{
duration,
delay: characterDelay + (i / 5) * duration,
ease: 'easeOut',
}}
className={cn(`block`, characterClassName, {
'animate-dotsFlash': text === '...',
})}>
{character === ' ' ? '\u00A0' : character}
</motion.div>
))}
</AnimatePresence>
</motion.p>
</div>
</motion.div>
);
};

View File

@ -3,6 +3,7 @@
import { useState, useEffect } from 'react';
import ReactConfetti from 'react-confetti';
import { useWindowSize } from 'react-use';
import { useMediaQuery } from 'usehooks-ts';
const Confetti = ({
numberOfPieces = 200,
@ -21,13 +22,15 @@ const Confetti = ({
'#FF3131',
];
const mobile = useMediaQuery('(max-width: 426px)');
return (
<div className="fixed top-0 left-0 z-50">
<ReactConfetti
width={width}
height={height}
recycle={showConfetti}
numberOfPieces={numberOfPieces}
numberOfPieces={mobile ? numberOfPieces / 3 : numberOfPieces}
tweenDuration={500}
// run={true}
colors={colors}

View File

@ -8,9 +8,10 @@ import { useWindowSize } from 'react-use';
import AnimatedText from '@/components/common/AnimatedText';
import { useWebsocketLottery } from '@/hooks/useWebSocketLottery';
import Confetti from '../common/Confetti';
import { AnimatePresence, motion } from 'framer-motion';
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 [winners, setWinners] = useState<LotteryWinnerDataSimplified[]>([]);
@ -39,7 +40,7 @@ const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) =>
setWinners(simplifiedWinners);
setCurrentNumber(lotteryData.data.winners.at(-1)?.ticket || '00-00-00-00-00');
setWinnerSelectingStatus('selected');
setTopText('Ýeňiji');
setTopText(`${lotteryData.data.winners.at(-1)?.winner_no}-nji(y) ýeňiji`);
setBottomText(lotteryData.data.winners.at(-1)?.client || '');
setIsConfettiActive(true);
}
@ -60,9 +61,7 @@ const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) =>
ticket: newWinner.ticket,
};
setTimeout(() => {
setIsConfettiActive(false);
}, 1000);
setIsConfettiActive(false);
setTopText(`${winnerData.winner_no}-nji(y) ýeňiji saýlanýar`);
setBottomText('...');
setWinnerSelectingStatus('is-selecting');
@ -70,12 +69,12 @@ const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) =>
setCurrentNumber(winnerData.ticket);
setTimeout(() => {
setTopText('Ýeniji');
setTopText(`${winnerData.winner_no}-nji(y) ýeňiji`);
setBottomText(winnerData.client);
setWinnerSelectingStatus('selected');
setIsConfettiActive(true);
setWinners((prev) => [...prev, winnerData]);
}, SLOT_COUNTER_DURATION + 500);
}, SLOT_COUNTER_DURATION);
});
return () => {
@ -83,6 +82,25 @@ const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) =>
};
}, [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 (
<section>
{wsStatus === 'error' && (
@ -95,47 +113,62 @@ const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) =>
style={{
background: 'linear-gradient(180deg, #F0ECF4 0%, #E1E0FF 43.5%)',
}}>
<div className="flex items-center justify-center w-full min-h-[240px]">
{winnerSelectingStatus === 'not-selected' ? (
// <TextMaskReveal
// text={topText}
// className="text-center flex items-center justify-center text-[100px] leading-[108px] text-[#E65E19]"
// duration={0.5}
// />
<AnimatedText
text={topText}
className="text-center flex items-center justify-center text-[100px] leading-[108px] text-[#E65E19]"
duration={0.4}
/>
) : (
<div className="flex flex-col items-center justify-center">
{/* <TextMaskReveal
<AnimatePresence>
<div className="flex items-center justify-center w-full sm:min-h-[240px] pt-6">
{winnerSelectingStatus === 'not-selected' ? (
// <TextMaskReveal
// text={topText}
// className="text-center flex items-center justify-center text-[100px] leading-[108px] text-[#E65E19]"
// duration={0.5}
// />
<AnimatedText
key={topText}
text={topText}
className="text-center flex items-center justify-center sm:text-[100px] text-[48px] leading-[120%] text-[#E65E19]"
duration={0.4}
/>
) : (
<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}
className="text-center text-[56px] leading-[64px] text-[#E65E19]"
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
text={bottomText}
className="text-center text-[80px] leading-[88px] text-[#E65E19]"
key={topText}
text={topText}
className="text-center sm:text-[56px] text-[24px] w-full leading-[120%] text-[#E65E19]"
duration={0.4}
characterDelay={1.3}
/>
)}
</div>
)}
</div>
{bottomText && (
// <TextMaskReveal
// text={bottomText}
// 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">
{currentNumber && <LotterySlotCounter numberString={currentNumber} />}
</div>

View File

@ -27,7 +27,7 @@ const LotterySlotCounter = ({ numberString }: LotterySlotCounterProps) => {
alt="roller-triangle"
width={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
@ -45,7 +45,7 @@ const LotterySlotCounter = ({ numberString }: LotterySlotCounterProps) => {
alt="roller-triangle"
width={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
@ -58,7 +58,7 @@ const LotterySlotCounter = ({ numberString }: LotterySlotCounterProps) => {
)}
<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={{
background:
'linear-gradient(180deg, #454673 0%, #575992 10.5%, #575992 90%, #454673 100%)',