rollingCounter fix

This commit is contained in:
Kakabay 2024-12-24 17:19:08 +05:00
parent 16cc50a958
commit ae71097b11
5 changed files with 53 additions and 250 deletions

View File

@ -1,25 +1,25 @@
"use client"; 'use client';
import { useLotteryAuth } from "@/store/useLotteryAuth"; import { useLotteryAuth } from '@/store/useLotteryAuth';
import ProtectedRoute from "@/components/lottery/auth/ProtectedRoute"; import ProtectedRoute from '@/components/lottery/auth/ProtectedRoute';
import { useLottery } from "@/lib/hooks/useLottery"; import { useLottery } from '@/lib/hooks/useLottery';
import { LOTTERY_CONFIG } from "@/constants/lottery"; import { LOTTERY_CONFIG } from '@/constants/lottery';
import LotteryHeader from "@/components/lottery/LotteryHeader"; import LotteryHeader from '@/components/lottery/LotteryHeader';
import LotteryCounter from "@/components/lottery/RollingCounter/RollingCounter"; import LotteryCounter from '@/components/lottery/RollingCounter/RollingCounter';
import LotteryWinnersSection from "@/components/lottery/LotteryWinnersSection"; import LotteryWinnersSection from '@/components/lottery/LotteryWinnersSection';
import LotteryRulesSection from "@/components/lottery/rules/LotteryRulesSection"; import LotteryRulesSection from '@/components/lottery/rules/LotteryRulesSection';
import RollingCounter from '@/components/lottery/RollingCounter/RollingCounter';
const LotteryPage = () => { const LotteryPage = () => {
const { lotteryData } = useLotteryAuth(); const { lotteryData } = useLotteryAuth();
const { status, currentNumber } = useLottery( const { status, currentNumber } = useLottery(LOTTERY_CONFIG.START_DATE, LOTTERY_CONFIG.END_DATE);
LOTTERY_CONFIG.START_DATE,
LOTTERY_CONFIG.END_DATE
);
return ( return (
<ProtectedRoute> <ProtectedRoute>
<div className="flex flex-col md:gap-[128px] gap-[80px] font-roboto md:pt-[64px] sm:pt-[48px] pt-[40px] pb-[128px] text-lightOnSurface"> <div className="flex flex-col md:gap-[128px] gap-[80px] font-roboto md:pt-[64px] sm:pt-[48px] pt-[40px] pb-[128px] text-lightOnSurface">
<RollingCounter numberString={'00-00-00-00-00'} />
{lotteryData && ( {lotteryData && (
<LotteryHeader <LotteryHeader
title={lotteryData.data.title} title={lotteryData.data.title}
@ -31,9 +31,7 @@ const LotteryPage = () => {
<LotteryRulesSection /> <LotteryRulesSection />
{(status === "ended" || status === "started") && ( {(status === 'ended' || status === 'started') && <LotteryWinnersSection />}
<LotteryWinnersSection />
)}
</div> </div>
</ProtectedRoute> </ProtectedRoute>
); );

View File

@ -9,6 +9,7 @@ import { Alexandria } from 'next/font/google';
import 'swiper/swiper-bundle.css'; import 'swiper/swiper-bundle.css';
import './globals.css'; import './globals.css';
import QueryProvider from '@/providers/QueryProvider'; import QueryProvider from '@/providers/QueryProvider';
import { HtmlContext } from 'next/dist/shared/lib/html-context.shared-runtime';
// FONTS // FONTS
const aeroport = localFont({ const aeroport = localFont({
src: '../fonts/Aeroport.otf', src: '../fonts/Aeroport.otf',

View File

@ -1,11 +1,11 @@
"use client"; 'use client';
import LotteryWinnersList from "./winners/LotteryWinnersList"; import LotteryWinnersList from './winners/LotteryWinnersList';
import SpinWheel from "./spinWheel/SpinWheel"; import SpinWheel from './spinWheel/SpinWheel';
import { useState, useEffect } from "react"; import { useState, useEffect } from 'react';
import RollingCounterWorking from "./RollingCounter/RollingCounterWorking"; import { useLotteryAuth } from '@/store/useLotteryAuth';
import { useLotteryAuth } from "@/store/useLotteryAuth"; import { LotteryWinnerData } from '@/typings/lottery/lottery.types';
import { LotteryWinnerData } from "@/typings/lottery/lottery.types"; import RollingCounter from './RollingCounter/RollingCounter';
const LotteryWinnersSection = () => { const LotteryWinnersSection = () => {
const [winners, setWinners] = useState<LotteryWinnerData[]>([]); const [winners, setWinners] = useState<LotteryWinnerData[]>([]);
@ -17,13 +17,13 @@ const LotteryWinnersSection = () => {
setWinners(lotteryData.data.winners); setWinners(lotteryData.data.winners);
} }
const wsUrl = "https://sms.turkmentv.gov.tm/api/ws/lottery"; const wsUrl = 'https://sms.turkmentv.gov.tm/api/ws/lottery';
const ws = new WebSocket(wsUrl); const ws = new WebSocket(wsUrl);
ws.onmessage = (event) => { ws.onmessage = (event) => {
console.log("WebSocket message received:", event.data); console.log('WebSocket message received:', event.data);
const newWinner = JSON.parse(event.data); const newWinner = JSON.parse(event.data);
console.log("Parsed WebSocket data:", newWinner); console.log('Parsed WebSocket data:', newWinner);
setWinners((prev) => [...prev, newWinner]); setWinners((prev) => [...prev, newWinner]);
}; };
@ -45,8 +45,6 @@ const LotteryWinnersSection = () => {
{/* <SpinWheel setWinners={setWinners} /> */} {/* <SpinWheel setWinners={setWinners} /> */}
</div> </div>
</div> </div>
<RollingCounterWorking numberString={"81-34-52-35-61"} />
</div> </div>
</div> </div>
</section> </section>

View File

@ -1,72 +1,36 @@
'use client'; 'use client';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { useCallback, useMemo, useState, useEffect } from 'react'; import { useCallback, useMemo, useState } from 'react';
interface RollingCounterProps { interface RollingCounterProps {
numberString: string; numberString: string;
} }
// Move constants outside component
const ROLLS = 2; const ROLLS = 2;
const DIGIT_HEIGHT = 104; const DIGIT_HEIGHT = 104;
const INITIAL_OFFSET = 38; const INITIAL_OFFSET = 38;
const EXTRA_NUMBERS_AFTER = 5; const EXTRA_NUMBERS_AFTER = 5;
const EXTRA_NUMBERS_BEFORE = 2;
const getNumbers = (targetValue: number, previousValue?: number) => { // Memoize number generation function
const getNumbers = (targetValue: number) => {
const numbers = []; const numbers = [];
if (previousValue === undefined) { // Add complete rolls
// Initial load
for (let i = 0; i < ROLLS; i++) { for (let i = 0; i < ROLLS; i++) {
for (let n = 0; n < 10; n++) { for (let n = 0; n < 10; n++) {
numbers.push(n); numbers.push(n);
} }
} }
// Add sequence before target // Add sequence to target
for (let n = EXTRA_NUMBERS_BEFORE; n > 0; n--) { for (let n = 0; n <= targetValue; n++) {
numbers.push((targetValue - n + 10) % 10); numbers.push(n);
} }
numbers.push(targetValue);
// Add extra numbers after target // Add extra numbers after target
for (let n = 1; n <= EXTRA_NUMBERS_AFTER; n++) { for (let n = (targetValue + 1) % 10; n < ((targetValue + 1) % 10) + EXTRA_NUMBERS_AFTER; n++) {
numbers.push((targetValue + n) % 10); numbers.push(n % 10);
}
} else {
// Keep the previous sequence
for (let i = 0; i < ROLLS; i++) {
for (let n = 0; n < 10; n++) {
numbers.push(n);
}
}
// Add sequence before previous value
for (let n = EXTRA_NUMBERS_BEFORE; n > 0; n--) {
numbers.push((previousValue - n + 10) % 10);
}
numbers.push(previousValue);
// Add complete rolls between previous and target
for (let i = 0; i < ROLLS; i++) {
for (let n = 0; n < 10; n++) {
numbers.push(n);
}
}
// Add sequence before target
for (let n = EXTRA_NUMBERS_BEFORE; n > 0; n--) {
numbers.push((targetValue - n + 10) % 10);
}
numbers.push(targetValue);
// Add extra numbers after target
for (let n = 1; n <= EXTRA_NUMBERS_AFTER; n++) {
numbers.push((targetValue + n) % 10);
}
} }
return numbers; return numbers;
@ -78,27 +42,22 @@ const RollingDigit = ({
onAnimationComplete, onAnimationComplete,
isStopped, isStopped,
showHyphen, showHyphen,
previousValue,
}: { }: {
targetValue: number; targetValue: number;
index: number; index: number;
onAnimationComplete: () => void; onAnimationComplete: () => void;
isStopped: boolean; isStopped: boolean;
showHyphen: boolean; showHyphen: boolean;
previousValue?: number;
}) => { }) => {
const numbers = useMemo( const numbers = useMemo(() => getNumbers(targetValue), [targetValue]);
() => getNumbers(targetValue, previousValue),
[targetValue, previousValue],
);
return ( return (
<div className="flex items-center"> <div className="flex items-center">
<div className="overflow-hidden h-[180px] w-[77px] relative"> <div className="overflow-hidden h-[180px] w-[77px] relative">
<motion.div <motion.div
initial={false} // Don't reset to initial state initial={{ y: INITIAL_OFFSET }}
animate={{ animate={{
y: -(numbers.length - EXTRA_NUMBERS_AFTER - 1) * DIGIT_HEIGHT + INITIAL_OFFSET, y: -((ROLLS * 10 + targetValue + 1) * DIGIT_HEIGHT) + INITIAL_OFFSET + DIGIT_HEIGHT,
}} }}
transition={{ transition={{
duration: 2, duration: 2,
@ -124,34 +83,25 @@ const RollingDigit = ({
}; };
const RollingCounter: React.FC<RollingCounterProps> = ({ numberString }) => { const RollingCounter: React.FC<RollingCounterProps> = ({ numberString }) => {
const [isInitialLoading, setIsInitialLoading] = useState(true);
const [isStopped, setIsStopped] = useState<boolean[]>([]); const [isStopped, setIsStopped] = useState<boolean[]>([]);
const [previousNumbers, setPreviousNumbers] = useState<number[]>([]);
const [isNewNumber, setIsNewNumber] = useState(false);
useEffect(() => { const { numbers, isInitialLoading } = useMemo(() => {
if (!isInitialLoading) { if (!numberString) {
setPreviousNumbers(numbers); return { numbers: [], isInitialLoading: true };
setIsStopped(new Array(numberString.replace(/-/g, '').length).fill(false));
setIsNewNumber(true);
} }
}, [numberString, isInitialLoading]);
const numbers = useMemo(() => {
if (!numberString) return [];
const parsed = numberString const parsed = numberString
.replace(/-/g, '') .replace(/-/g, '')
.split('') .split('')
.map((char) => parseInt(char, 10)); .map((char) => parseInt(char, 10));
if (isInitialLoading) {
setIsStopped(new Array(parsed.length).fill(false)); setIsStopped(new Array(parsed.length).fill(false));
setIsInitialLoading(false);
}
return parsed; return {
}, [numberString, isInitialLoading]); numbers: parsed,
isInitialLoading: false,
};
}, [numberString]);
const handleAnimationComplete = useCallback((index: number) => { const handleAnimationComplete = useCallback((index: number) => {
setIsStopped((prev) => { setIsStopped((prev) => {
@ -175,7 +125,6 @@ const RollingCounter: React.FC<RollingCounterProps> = ({ numberString }) => {
<RollingDigit <RollingDigit
key={`${index}-${num}`} key={`${index}-${num}`}
targetValue={num} targetValue={num}
previousValue={previousNumbers[index]}
index={index} index={index}
onAnimationComplete={() => handleAnimationComplete(index)} onAnimationComplete={() => handleAnimationComplete(index)}
isStopped={isStopped[index]} isStopped={isStopped[index]}

View File

@ -1,143 +0,0 @@
'use client';
import { motion } from 'framer-motion';
import { useCallback, useMemo, useState } from 'react';
interface RollingCounterWorkingProps {
numberString: string;
}
// Move constants outside component
const ROLLS = 5;
const DIGIT_HEIGHT = 104;
const INITIAL_OFFSET = 38;
const EXTRA_NUMBERS_AFTER = 5;
const EXTRA_NUMBERS_BEFORE = 2;
// Memoize number generation function
const getNumbers = (targetValue: number) => {
const numbers = [];
// Add complete rolls
for (let i = 0; i < ROLLS; i++) {
for (let n = 0; n < 10; n++) {
numbers.push(n);
}
}
// Add sequence before target
for (let n = EXTRA_NUMBERS_BEFORE; n > 0; n--) {
numbers.push((targetValue - n + 10) % 10);
}
// Add target
numbers.push(targetValue);
// Add extra numbers after target
for (let n = 1; n <= EXTRA_NUMBERS_AFTER; n++) {
numbers.push((targetValue + n) % 10);
}
return numbers;
};
const RollingDigit = ({
targetValue,
index,
onAnimationComplete,
isStopped,
showHyphen,
}: {
targetValue: number;
index: number;
onAnimationComplete: () => void;
isStopped: boolean;
showHyphen: boolean;
}) => {
const numbers = useMemo(() => getNumbers(targetValue), [targetValue]);
const targetIndex = ROLLS * 10 + EXTRA_NUMBERS_BEFORE;
return (
<div className="flex items-center">
<div className="overflow-hidden h-[180px] w-[77px] relative">
<motion.div
initial={{ y: INITIAL_OFFSET }}
animate={{
y: -(targetIndex * DIGIT_HEIGHT) + INITIAL_OFFSET,
}}
transition={{
duration: 5,
delay: index * 4,
ease: 'easeInOut',
}}
onAnimationComplete={onAnimationComplete}
className="absolute flex flex-col">
{numbers.map((num, i) => (
<div
key={`${index}-${i}`}
className={`h-[${DIGIT_HEIGHT}px] w-[77px] flex items-center justify-center numeric-display-1 transition-colors duration-500 ${
isStopped && num === targetValue ? 'text-white' : 'text-[#B0B1CD]'
}`}>
{num}
</div>
))}
</motion.div>
</div>
{showHyphen && <div className="w-[32px] h-[4px] bg-lightOnPrimary mx-5 self-center" />}
</div>
);
};
const RollingCounterWorking: React.FC<RollingCounterWorkingProps> = ({ numberString }) => {
const [isInitialLoading, setIsInitialLoading] = useState(true);
const [isStopped, setIsStopped] = useState<boolean[]>([]);
const numbers = useMemo(() => {
if (!numberString) return [];
const parsed = numberString
.replace(/-/g, '')
.split('')
.map((char) => parseInt(char, 10));
if (isInitialLoading) {
setIsStopped(new Array(parsed.length).fill(false));
setIsInitialLoading(false);
}
return parsed;
}, [numberString, isInitialLoading]);
const handleAnimationComplete = useCallback((index: number) => {
setIsStopped((prev) => {
const newState = [...prev];
newState[index] = true;
return newState;
});
}, []);
if (isInitialLoading) {
return (
<div className="flex items-center justify-center bg-lightPrimary text-white py-4 px-6 rounded-full">
Loading...
</div>
);
}
return (
<div className="flex items-center justify-center bg-lightPrimary text-white py-4 px-6 rounded-full">
{numbers.map((num, index) => (
<RollingDigit
key={`${index}-${num}`}
targetValue={num}
index={index}
onAnimationComplete={() => handleAnimationComplete(index)}
isStopped={isStopped[index]}
showHyphen={(index + 1) % 2 === 0 && index !== numbers.length - 1}
/>
))}
</div>
);
};
export default RollingCounterWorking;