rollingCounter fix
This commit is contained in:
parent
16cc50a958
commit
ae71097b11
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -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',
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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]}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
Loading…
Reference in New Issue