From 9d4178f1de1eff2d03aa00421c1c7c8b1bcf9c11 Mon Sep 17 00:00:00 2001
From: Kakabay <2kakabayashyrberdyew@gmail.com>
Date: Fri, 20 Dec 2024 18:23:26 +0500
Subject: [PATCH] rolling counter added
---
.../lottery/RollingCounter/RollingCounter.tsx | 215 ++++++++++++++----
.../RollingCounter/RollingCounterWorking.tsx | 143 ++++++++++++
2 files changed, 310 insertions(+), 48 deletions(-)
create mode 100644 components/lottery/RollingCounter/RollingCounterWorking.tsx
diff --git a/components/lottery/RollingCounter/RollingCounter.tsx b/components/lottery/RollingCounter/RollingCounter.tsx
index 79b5e24..afab738 100644
--- a/components/lottery/RollingCounter/RollingCounter.tsx
+++ b/components/lottery/RollingCounter/RollingCounter.tsx
@@ -1,67 +1,186 @@
'use client';
import { motion } from 'framer-motion';
-import { useEffect, useState } from 'react';
+import { useCallback, useMemo, useState, useEffect } from 'react';
interface RollingCounterProps {
- numberString: string; // A 10-character string, e.g., "05-12-34-56-78"
+ numberString: string;
}
+const ROLLS = 2;
+const DIGIT_HEIGHT = 104;
+const INITIAL_OFFSET = 38;
+const EXTRA_NUMBERS_AFTER = 5;
+const EXTRA_NUMBERS_BEFORE = 2;
+
+const getNumbers = (targetValue: number, previousValue?: number) => {
+ const numbers = [];
+
+ if (previousValue === undefined) {
+ // Initial load
+ 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);
+ }
+ } 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;
+};
+
+const RollingDigit = ({
+ targetValue,
+ index,
+ onAnimationComplete,
+ isStopped,
+ showHyphen,
+ previousValue,
+}: {
+ targetValue: number;
+ index: number;
+ onAnimationComplete: () => void;
+ isStopped: boolean;
+ showHyphen: boolean;
+ previousValue?: number;
+}) => {
+ const numbers = useMemo(
+ () => getNumbers(targetValue, previousValue),
+ [targetValue, previousValue],
+ );
+
+ return (
+
+
+
+ {numbers.map((num, i) => (
+
+ {num}
+
+ ))}
+
+
+ {showHyphen &&
}
+
+ );
+};
+
const RollingCounter: React.FC = ({ numberString }) => {
- const [rollingValues, setRollingValues] = useState([]);
- const [isStopped, setIsStopped] = useState([]); // Track stopped numbers
+ const [isInitialLoading, setIsInitialLoading] = useState(true);
+ const [isStopped, setIsStopped] = useState([]);
+ const [previousNumbers, setPreviousNumbers] = useState([]);
+ const [isNewNumber, setIsNewNumber] = useState(false);
useEffect(() => {
- // Parse input string into an array of numbers, removing hyphens
- const targetNumbers = numberString
+ if (!isInitialLoading) {
+ setPreviousNumbers(numbers);
+ setIsStopped(new Array(numberString.replace(/-/g, '').length).fill(false));
+ setIsNewNumber(true);
+ }
+ }, [numberString, isInitialLoading]);
+
+ const numbers = useMemo(() => {
+ if (!numberString) return [];
+
+ const parsed = numberString
.replace(/-/g, '')
.split('')
.map((char) => parseInt(char, 10));
- setRollingValues(targetNumbers);
- setIsStopped(new Array(targetNumbers.length).fill(false));
- }, [numberString]);
- const getNumbers = () => Array.from({ length: 10 }, (_, i) => i);
+ 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 (
+
+ Loading...
+
+ );
+ }
return (
- {rollingValues.map((targetValue, index) => (
-
- {/* Container to display numbers */}
-
-
{
- // Mark this number as stopped
- setIsStopped((prev) => {
- const newStatus = [...prev];
- newStatus[index] = true;
- return newStatus;
- });
- }}
- className="absolute top-1/2 -translate-y-1/2 flex flex-col -mt-[52px]">
- {getNumbers().map((num) => (
-
- {num}
-
- ))}
-
-
- {/* Add a hyphen every two digits */}
- {(index + 1) % 2 === 0 && index !== rollingValues.length - 1 && (
-
- )}
-
+ {numbers.map((num, index) => (
+
handleAnimationComplete(index)}
+ isStopped={isStopped[index]}
+ showHyphen={(index + 1) % 2 === 0 && index !== numbers.length - 1}
+ />
))}
);
diff --git a/components/lottery/RollingCounter/RollingCounterWorking.tsx b/components/lottery/RollingCounter/RollingCounterWorking.tsx
new file mode 100644
index 0000000..4f0bf74
--- /dev/null
+++ b/components/lottery/RollingCounter/RollingCounterWorking.tsx
@@ -0,0 +1,143 @@
+'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 (
+
+
+
+ {numbers.map((num, i) => (
+
+ {num}
+
+ ))}
+
+
+ {showHyphen &&
}
+
+ );
+};
+
+const RollingCounterWorking: React.FC = ({ numberString }) => {
+ const [isInitialLoading, setIsInitialLoading] = useState(true);
+ const [isStopped, setIsStopped] = useState([]);
+
+ 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 (
+
+ Loading...
+
+ );
+ }
+
+ return (
+
+ {numbers.map((num, index) => (
+ handleAnimationComplete(index)}
+ isStopped={isStopped[index]}
+ showHyphen={(index + 1) % 2 === 0 && index !== numbers.length - 1}
+ />
+ ))}
+
+ );
+};
+
+export default RollingCounterWorking;