Hlo
import React, { useState, useRef, useEffect } from 'react';
import { Trash2, Plus, Shuffle, Trophy, Volume2, VolumeX } from 'lucide-react';
import confetti from 'canvas-confetti';
const UltimatePickerWheel = () => {
// State for the items on the wheel
const [items, setItems] = useState([
{ id: 1, text: 'Pizza', color: '#FF6B6B' },
{ id: 2, text: 'Burger', color: '#4ECDC4' },
{ id: 3, text: 'Sushi', color: '#45B7D1' },
{ id: 4, text: 'Salad', color: '#FFA07A' },
{ id: 5, text: 'Tacos', color: '#98D8C8' },
]);
const [inputValue, setInputValue] = useState('');
const [isSpinning, setIsSpinning] = useState(false);
const [winner, setWinner] = useState(null);
const [rotation, setRotation] = useState(0);
const [soundEnabled, setSoundEnabled] = useState(true);
// Sound Refs (You can replace these URLs with your own hosted files)
const spinSound = useRef(new Audio('https://assets.mixkit.co/sfx/preview/mixkit-drum-roll-566.mp3'));
const winSound = useRef(new Audio('https://assets.mixkit.co/sfx/preview/mixkit-winning-chimes-2015.mp3'));
// Colors to cycle through when adding new items
const colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8', '#F7DC6F', '#BB8FCE', '#A3E4D7'];
const handleAddItem = (e) => {
e.preventDefault();
if (!inputValue.trim()) return;
const newItem = {
id: Date.now(),
text: inputValue,
color: colors[items.length % colors.length]
};
setItems([...items, newItem]);
setInputValue('');
};
const handleRemoveItem = (id) => {
setItems(items.filter(item => item.id !== id));
};
const triggerConfetti = () => {
const duration = 3000;
const end = Date.now() + duration;
(function frame() {
confetti({
particleCount: 5,
angle: 60,
spread: 55,
origin: { x: 0 },
colors: colors
});
confetti({
particleCount: 5,
angle: 120,
spread: 55,
origin: { x: 1 },
colors: colors
});
if (Date.now() < end) {
requestAnimationFrame(frame);
}
}());
};
const spinWheel = () => {
if (isSpinning || items.length < 2) return;
setIsSpinning(true);
setWinner(null);
if (soundEnabled) {
spinSound.current.currentTime = 0;
spinSound.current.play().catch(() => {});
}
// Calculate a new random rotation
// Min 5 spins (1800 deg) + random variance
const newRotation = rotation + 1800 + Math.floor(Math.random() * 360);
setRotation(newRotation);
// Calculate winner index
// The pointer is usually at the top (270deg) or right (0deg).
// Assuming CSS rotates clockwise and pointer is at the right (0deg):
// We need to find where the wheel stops.
setTimeout(() => {
const actualDeg = newRotation % 360;
const segmentSize = 360 / items.length;
// Calculate index based on pointer position (Right side pointer logic)
// Note: CSS conic gradients start at 12 o'clock usually, adjustments needed based on CSS
const winningIndex = Math.floor((360 - actualDeg) / segmentSize) % items.length;
const winningItem = items[winningIndex];
setWinner(winningItem);
setIsSpinning(false);
if (soundEnabled) {
spinSound.current.pause();
winSound.current.play().catch(() => {});
}
triggerConfetti();
}, 4000); // Duration matches CSS transition
};
// Create Conic Gradient for the wheel
const wheelGradient = `conic-gradient(
${items.map((item, index) => {
const start = (index / items.length) * 100;
const end = ((index + 1) / items.length) * 100;
return `${item.color} ${start}% ${end}%`;
}).join(', ')}
)`;
return (
{/* Header / Ad Space Placeholder */}
)}
{/* SEO Text / Explanation (Vital for the business model) */}
);
};
export default UltimatePickerWheel;
Pick-A-Winner
The Ultimate Random Decision Maker
{/* LEFT SIDE: The Wheel */}
{/* RIGHT SIDE: Controls */}
{/* Winner Modal */}
{winner && !isSpinning && (
{/* Pointer */}
{/* The Wheel */}
{/* Text Labels inside Wheel */}
{items.map((item, index) => {
const angle = (360 / items.length) * index + (360 / items.length) / 2;
return (
{/* Center Cap */}
{item.text}
);
})}
Inputs
{items.map((item) => (
))}
{item.text}
{items.length} options available
We have a winner!
{winner.text}
Use this wheel to randomly pick a winner, decide what to eat, or choose a name.


Comments
Post a Comment