Правильное выпадение в рулетке
Есть рулетка, в неё передаются данные из колеса. Из этих данных рулетка выбирает случайный. Схема БД realtime firebase такая:
После нажатия кнопки крутится колесо, после остановки колеса должна начать крутиться рулетка с переданной редкостью. Рулетка крутится, но выпадает не то, на что показывает указатель (примерно на 2 карточки раньше как я понял). А ещё иногда рулетка вообще не крутится и стоит на месте, а после времени на кручение в консоль выводится то что она остановилась и т.п.
import { Wheel } from "react-custom-roulette";
import styles from "./DailyGift.module.css";
import { Link } from "react-router-dom";
import RoulettePro from "react-roulette-pro";
import "react-roulette-pro/dist/index.css";
import { database } from "../firebase";
import { ref, get } from "firebase/database";
const rarities = [
{ option: "Редкая", rarity: "Редкая", probability: 60 },
{ option: "Эпическая", rarity: "Эпическая", probability: 25 },
{ option: "Мифическая", rarity: "Мифическая", probability: 10 },
{ option: "Легендарная", rarity: "Легендарная", probability: 5 },
];
const rarityOptions = rarities.map((r) => ({ option: r.rarity }));
const weightedRarities = [];
rarities.forEach((r) => {
for (let i = 0; i < r.probability; i++) {
weightedRarities.push(r.rarity);
}
});
export default function DailyGift() {
const [mustSpin, setMustSpin] = useState(false);
const [prizeNumber, setPrizeNumber] = useState(0);
const [cars, setCars] = useState(rarityOptions);
const [start, setStart] = useState(false);
const [prizeIndex, setPrizeIndex] = useState(0);
const [spinning, setSpinning] = useState(false);
const [prizes, setPrizes] = useState([]);
const [showCars, setShowCars] = useState(false);
useEffect(() => {
console.log("Prizes updated:", prizes);
}, [prizes]);
const getItemsByRarity = useCallback(async (rarity) => {
const itemsRef = ref(database, "cars");
try {
const snapshot = await get(itemsRef);
if (snapshot.exists()) {
const itemsObject = snapshot.val();
console.log("All fetched items:", itemsObject);
const itemsArray = Object.keys(itemsObject).map((key) => ({
id: key,
...itemsObject[key],
}));
const filteredItems = itemsArray.filter(
(item) => item.rarityName === rarity
);
console.log(`Filtered items for rarity "${rarity}":`, filteredItems);
return filteredItems;
} else {
console.log("No items found in database");
return [];
}
} catch (error) {
console.error("Error fetching data:", error);
return [];
}
}, []);
const getRandomItems = (items, count) => {
const shuffled = items.sort(() => 0.5 - Math.random());
return shuffled.slice(0, count);
};
const getRandomItemsByRarity = useCallback(
async (rarity, count = 9) => {
const items = await getItemsByRarity(rarity);
if (items.length > 0) {
return getRandomItems(items, count);
} else {
return [];
}
},
[getItemsByRarity]
);
const generateId = () =>
`${Date.now().toString(36)}+${Math.random().toString(36).substring(2)}`;
const handleSpinClick = () => {
if (!mustSpin) {
setSpinning(true);
const selectedRarity =
weightedRarities[Math.floor(Math.random() * weightedRarities.length)];
const newPrizeNumber = rarityOptions.findIndex(
(r) => r.option === selectedRarity
);
setPrizeNumber(newPrizeNumber);
setMustSpin(true);
setShowCars(false); // До остановки колеса показываем вопросительные знаки
}
};
const handleStopSpinning = async () => {
setMustSpin(false);
setSpinning(false); // Останавливаем вращение
const selectedElement = cars[prizeNumber];
console.log("Selected Element:", selectedElement);
const randomItems = await getRandomItemsByRarity(selectedElement.option);
console.log("Random Items:", randomItems);
setPrizes(randomItems);
console.log("Prizes:", randomItems); // Выводите рандомные призы
setShowCars(true); // Показываем реальные призы
setStart(true);
setPrizeIndex(Math.floor(Math.random() * randomItems.length)); // Рандомный выбор индекса приза
};
const handlePrizeDefined = () => {
setStart(false); // Останавливаем рулетку
const selectedPrize = prizes[prizeIndex];
console.log("? Prize defined! ?", selectedPrize);
setShowCars(false); // Возвращаемся к вопросительным знакам после определения приза
};
const questionMarksObject = {
logoUrl:
"https://static.wikia.nocookie.net/6b13a411-b39d-4eaa-b1c2-d16c72439a3d",
};
const questionMarks = Array.from({ length: 9 }, () => ({
...questionMarksObject,
id: generateId(),
}));
const prizesToDisplay = showCars ? prizes : questionMarks;
const reproductionArray = (array = [], length = 0) => [
...Array(length)
.fill("_")
.map(() => array[Math.floor(Math.random() * array.length)]),
];
const reproducedPrizeList = [
...prizesToDisplay,
...reproductionArray(prizesToDisplay, prizesToDisplay.length * 3),
...prizesToDisplay,
...reproductionArray(prizesToDisplay, prizesToDisplay.length),
];
const prizeList = reproducedPrizeList.map((prize, index) => ({
...prize,
id: `${generateId()}-${index}`, // Убедитесь, что каждый ID уникален
}));
return (
<div className={styles.container}>
<Link to={"/HomePage"} className={styles.LinkBack}>
Назад
</Link>
<div className={styles.wheelContainer}>
<Wheel
mustStartSpinning={mustSpin}
prizeNumber={prizeNumber}
data={cars}
onStopSpinning={handleStopSpinning}
spinDuration={0.5}
/>
<button
onClick={handleSpinClick}
className={styles.btnSPIN}
style={{
cursor: spinning ? "not-allowed" : "",
backgroundColor: spinning ? "grey" : "",
}}>
{spinning ? "spinning..." : "spin"}
</button>
</div>
<div className={styles.RoulProContainer}>
<RoulettePro
prizes={prizeList}
prizeIndex={prizeIndex}
start={start}
spinningTime={6}
onPrizeDefined={handlePrizeDefined}
prizeItemRenderFunction={(prize) => (
<div style={{ textAlign: "center" }} className={styles.card}>
<img
src={prize.logoUrl} // Используйте правильное поле
alt="car logo"
className={styles.carlogo}
/>
</div>
)}
/>
</div>
</div>
);
}
display: flex;
flex-direction: row;
}
.wheelContainer {
display: block;
position: relative;
width: 30%;
}
.RoulProContainer {
width: 1250px;
height: 170px;
background-color: rgba(240, 248, 255, 0.301);
backdrop-filter: blur(8px);
padding: 20px 0 20px 0;
border-radius: 10px;
}
.btnSPIN {
position: absolute;
left: 10px;
background-color: rgb(87, 87, 185);
border: transparent;
height: 30px;
width: 150px;
border-radius: 5px;
transition: ease-in-out 0.3s;
}
.btnSPIN:hover,
.btnSPINRpro:hover {
background-color: rgb(76, 76, 114);
cursor: pointer;
transition: ease-in-out 0.3s;
}
.btnSPIN:active,
.btnSPINRpro:active {
background-color: rgb(149, 149, 221);
transition: ease-in-out 0.1s;
}
.btnSPINRpro {
background-color: rgb(87, 87, 185);
border: transparent;
height: 30px;
width: 150px;
border-radius: 5px;
transition: ease-in-out 0.3s;
}
.LinkBack {
background-color: rgba(255, 255, 255, 0.39);
backdrop-filter: blur(8px);
border-radius: 5px;
height: 20px;
width: 60px;
padding: 5px;
text-decoration: none;
color: black;
}
.card {
position: relative;
width: 150px;
height: 150px;
background: rgba(255, 255, 255, 0.1);
border-radius: 10px;
backdrop-filter: blur(10px);
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
overflow: hidden;
transition: transform 0.3s;
display: flex;
align-items: center;
justify-content: center;
margin-left: 5px;
}
.carlogo {
width: 100px;
height: auto;
transition: transform 0.3s;
}