import React, { useState, useEffect, useRef, useCallback } from 'react'; // === KONFIGURASI GAME === const TARGET_SCORE = 500; const GAME_1_DURATION = 50; const ICONS = [ { type: 'healthy', emoji: '🍎', points: 10 }, { type: 'healthy', emoji: '🍊', points: 10 }, { type: 'healthy', emoji: '🍋', points: 10 }, { type: 'healthy', emoji: '🍉', points: 10 }, { type: 'healthy', emoji: '🍯', points: 10 }, { type: 'unhealthy', emoji: '🍔', points: -10 }, { type: 'unhealthy', emoji: '🍟', points: -10 }, { type: 'unhealthy', emoji: '🥤', points: -10 }, ]; // --- KOMPONEN: LAYAR UTAMA --- const Home = ({ playerName, setPlayerName, setScore, setTimeDiff, setScreen, initAudio, audioEnabled, setAudioEnabled }) => (
🥤🍋

Fresh & Healthy Stand

Mainkan game singkat ini sebelum memesan dan dapatkan kesempatan memenangkan Minuman GRATIS atau diskon menarik!

setPlayerName(e.target.value)} />
); // --- KOMPONEN: GAME 1 (HEALTHY CATCH) --- const Game1 = ({ score, setScore, setScreen, setReward, saveToLeaderboard, playSound }) => { const [timeLeft, setTimeLeft] = useState(GAME_1_DURATION); const [items, setItems] = useState([]); // Timer Mundur useEffect(() => { if (timeLeft > 0) { const timer = setInterval(() => setTimeLeft(t => t - 1), 1000); return () => clearInterval(timer); } }, [timeLeft]); // Cek kalau skor langsung tercapai (langsung lanjut ke 10 detik tanpa nunggu waktu abis) useEffect(() => { if (score >= TARGET_SCORE) { playSound('win'); setScreen('GAME2'); } }, [score, playSound, setScreen]); // Cek kalau waktu abis tapi skor kurang (TETAP LANJUT KE GAME 2) useEffect(() => { if (timeLeft <= 0 && score < TARGET_SCORE) { playSound('lose'); // Cuma kasih suara "womp womp" penanda waktu habis setScreen('GAME2'); // Tapi TETAP lanjut ke game 10 detik } }, [timeLeft, score, playSound, setScreen]); // Game Loop: Munculin Buah useEffect(() => { const spawner = setInterval(() => { const randomIcon = ICONS[Math.floor(Math.random() * ICONS.length)]; const newItem = { id: Math.random().toString(), ...randomIcon, x: Math.floor(Math.random() * 80) + 10, y: -10, speed: Math.random() * 2 + 1.5 // Kecepatan variatif }; setItems(prev => [...prev, newItem]); }, 350); // Buah dibikin lebih sering turun biar gampang capai target 500 const mover = setInterval(() => { setItems(prev => prev.map(item => ({...item, y: item.y + item.speed})).filter(item => item.y < 110)); }, 50); return () => { clearInterval(spawner); clearInterval(mover); }; }, []); const catchItem = (id, type, points) => { if (type === 'healthy') { playSound('catchGood'); } else { playSound('catchBad'); } setScore(s => s + points); setItems(prev => prev.filter(item => item.id !== id)); }; return (

TARGET: {TARGET_SCORE}

= TARGET_SCORE ? 'text-green-600' : 'text-gray-700'}`}>Skor: {score}

WAKTU

{timeLeft}s

Klik yang sehat!
{items.map(item => (
catchItem(item.id, item.type, item.points)} className="absolute text-5xl hover:scale-110 transition-transform select-none drop-shadow-md" style={{ left: `${item.x}%`, top: `${item.y}%`, cursor: 'pointer' }} > {item.emoji}
))}
); }; // --- KOMPONEN: GAME 2 (10-SECOND CHALLENGE) --- const Game2 = ({ setScreen, timeDiff, setTimeDiff, setReward, saveToLeaderboard, playSound }) => { const [gameState, setGameState] = useState('IDLE'); const [displayTime, setDisplayTime] = useState('0.00'); const startTimeRef = useRef(null); const animationRef = useRef(null); const startTimer = () => { setGameState('RUNNING'); playSound('catchGood'); startTimeRef.current = performance.now(); const updateTimer = () => { const now = performance.now(); const elapsed = (now - startTimeRef.current) / 1000; if (elapsed > 3.0) { setDisplayTime('??.??'); } else { setDisplayTime(elapsed.toFixed(2)); } animationRef.current = requestAnimationFrame(updateTimer); }; animationRef.current = requestAnimationFrame(updateTimer); }; const stopTimer = () => { cancelAnimationFrame(animationRef.current); const now = performance.now(); const elapsed = (now - startTimeRef.current) / 1000; const diff = Math.abs(10 - elapsed); setDisplayTime(elapsed.toFixed(2)); setGameState('DONE'); setTimeDiff(diff); let finalReward = ''; if (diff === 0) { finalReward = 'GRAND PRIZE: GRATIS 1 CUP!'; playSound('win'); } else if (diff <= 0.15) { finalReward = 'DISKON 50%'; playSound('win'); } else if (diff <= 0.50) { finalReward = 'GRATIS EXTRA TOPPING'; playSound('win'); } else { finalReward = 'Harga Normal. Semangat ya!'; playSound('lose'); } setReward(finalReward); saveToLeaderboard(diff, finalReward); setTimeout(() => { setScreen('RESULT'); }, 2500); }; return (

Bonus Round!

Hentikan timer tepat di angka 10.00 detik.
Timer akan menghilang di detik ke-3.

{displayTime}
{gameState === 'IDLE' && ( )} {gameState === 'RUNNING' && ( )} {gameState === 'DONE' && (
{timeDiff <= 0.5 ? '🎉 Wah Hampir Tepat! 🎉' : 'Aduh Meleset...'}
)}
); }; // --- KOMPONEN: LAYAR HASIL --- const ResultScreen = ({ playerName, setPlayerName, score, timeDiff, reward, setScreen }) => (
{timeDiff !== null && timeDiff <= 0.5 && (
{[...Array(20)].map((_, i) => (
))}
)}

TANTANGAN SELESAI!

Pemain: {playerName}

Skor Nangkep Buah

{score} Poin

{timeDiff !== null && (

Selisih Waktu Fokus

± {timeDiff.toFixed(2)} detik

)}

REWARD KAMU:

{reward}

); // --- KOMPONEN: LEADERBOARD --- const LeaderboardScreen = ({ leaderboard, setLeaderboard, setScreen }) => (

🏆 WALL OF FAME 🏆

Pemain dengan fokus terbaik hari ini!

{leaderboard.length === 0 ? ( ) : ( leaderboard.map((entry, index) => ( )) )}
Rank Nama Selisih Waktu
Belum ada yang main. Jadilah yang pertama!
{index === 0 ? '🥇' : index === 1 ? '🥈' : index === 2 ? '🥉' : index + 1} {entry.name}
{entry.reward}
{entry.diff !== null ? `±${entry.diff.toFixed(2)}s` : 'Gagal Babak 1'}
); export default function App() { const [screen, setScreen] = useState('HOME'); const [playerName, setPlayerName] = useState(''); const [score, setScore] = useState(0); const [timeDiff, setTimeDiff] = useState(null); const [reward, setReward] = useState(''); const [leaderboard, setLeaderboard] = useState([]); const [audioEnabled, setAudioEnabled] = useState(true); // Load leaderboard useEffect(() => { const saved = localStorage.getItem('standLeaderboard'); if (saved) setLeaderboard(JSON.parse(saved)); }, []); const saveToLeaderboard = useCallback((finalDiff, finalReward) => { const newEntry = { name: playerName, score: score, diff: finalDiff, reward: finalReward, date: new Date().toLocaleTimeString() }; const newLeaderboard = [...leaderboard, newEntry].sort((a, b) => { if (a.diff === null) return 1; if (b.diff === null) return -1; return a.diff - b.diff; }).slice(0, 5); setLeaderboard(newLeaderboard); localStorage.setItem('standLeaderboard', JSON.stringify(newLeaderboard)); }, [leaderboard, playerName, score]); const audioCtxRef = useRef(null); const initAudio = () => { if (!audioCtxRef.current) { audioCtxRef.current = new (window.AudioContext || window.webkitAudioContext)(); } if (audioCtxRef.current.state === 'suspended') { audioCtxRef.current.resume(); } }; const playSound = useCallback((type) => { if (!audioEnabled || !audioCtxRef.current) return; const ctx = audioCtxRef.current; const osc = ctx.createOscillator(); const gainNode = ctx.createGain(); osc.connect(gainNode); gainNode.connect(ctx.destination); const now = ctx.currentTime; if (type === 'catchGood') { osc.type = 'sine'; osc.frequency.setValueAtTime(800, now); osc.frequency.exponentialRampToValueAtTime(1200, now + 0.1); gainNode.gain.setValueAtTime(0.3, now); gainNode.gain.exponentialRampToValueAtTime(0.01, now + 0.1); osc.start(now); osc.stop(now + 0.1); } else if (type === 'catchBad') { osc.type = 'sawtooth'; osc.frequency.setValueAtTime(150, now); gainNode.gain.setValueAtTime(0.3, now); gainNode.gain.exponentialRampToValueAtTime(0.01, now + 0.2); osc.start(now); osc.stop(now + 0.2); } else if (type === 'win') { osc.type = 'square'; osc.frequency.setValueAtTime(400, now); osc.frequency.setValueAtTime(500, now + 0.1); osc.frequency.setValueAtTime(600, now + 0.2); osc.frequency.setValueAtTime(800, now + 0.3); gainNode.gain.setValueAtTime(0.3, now); gainNode.gain.linearRampToValueAtTime(0, now + 0.5); osc.start(now); osc.stop(now + 0.5); } else if (type === 'lose') { osc.type = 'triangle'; osc.frequency.setValueAtTime(300, now); osc.frequency.exponentialRampToValueAtTime(100, now + 0.5); gainNode.gain.setValueAtTime(0.5, now); gainNode.gain.linearRampToValueAtTime(0, now + 0.5); osc.start(now); osc.stop(now + 0.5); } }, [audioEnabled]); return (
{screen === 'HOME' && } {screen === 'GAME1' && } {screen === 'GAME2' && } {screen === 'RESULT' && } {screen === 'LEADERBOARD' && }
); }