with complete info button
Fri Mar 21 2025 09:56:55 GMT+0000 (Coordinated Universal Time)
Saved by @Urvashi
import React, { useState, useEffect, useRef } from 'react'; import '../styles/slotmachine.scss'; import '../styles/tooltip.scss'; import Title from '../components/Title'; import Reel from '../components/Reel'; import { GameButton } from '../components/GameButton'; import Registration from './Registration'; import axiosInstance from '../utils/axiosInstance'; import { AxiosError } from 'axios'; import { GameConfig } from '../index'; import Model from '../components/Model'; import Tooltip from '../components/Tooltip'; interface SlotImage { id: number; image_path: string; section_number: number; prize_name?: string; // Optional field for prize name } const SlotMachine: React.FC<GameConfig> = ({ gameTitle = '', titleColor = '', backgroundImage = '', reelBorder = '', buttonBackgroundColor = '', buttonTextColor = '', }) => { const [reels, setReels] = useState<string[][]>([]); const [isSoundOn, setIsSoundOn] = useState(true); const [slotImages, setSlotImages] = useState<SlotImage[]>([]); const [error, setError] = useState<string | null>(null); const [isSpinning, setIsSpinning] = useState(false); const [completedReels, setCompletedReels] = useState(0); const [isRegistrationOpen, setIsRegistrationOpen] = useState(false); const [spinCombination, setSpinCombination] = useState<string | null>(null); const [spinResult, setSpinResult] = useState<'win' | 'loss' | null>(null); const [spinKey, setSpinKey] = useState(0); const [isInfoOpen, setIsInfoOpen] = useState(false); const [tooltips, setTooltips] = useState({ sound: false, info: false, }); const spinAudioRef = useRef<HTMLAudioElement | null>(null); const winAudioRef = useRef<HTMLAudioElement | null>(null); const loseAudioRef = useRef<HTMLAudioElement | null>(null); const baseSpinDuration = 2000; const delayBetweenStops = 600; const DEFAULT_SLOT_COUNT = 3; const API_BASE_URL = process.env.REACT_APP_API_URL; const SPIN_AUDIO_URL = `${API_BASE_URL}audio/wheel-spin.mp3`; const WIN_AUDIO_URL = `${API_BASE_URL}audio/winning_sound.mp3`; const LOSE_AUDIO_URL = `${API_BASE_URL}audio/losing_game.mp3`; useEffect(() => { const fetchImages = async () => { try { const response = await axiosInstance.get('/api/slot/images'); if (response.data.status && response.data.data.images.length > 0) { setSlotImages(response.data.data.images); } else { throw new Error(response.data.message || 'Failed to fetch images'); } } catch (error) { console.error('Error fetching slot images:', error); const axiosError = error as AxiosError; if (axiosError.message === 'Network Error' || !axiosError.response) { setError('Server not responding'); } else { setError('Error fetching slot images'); } setIsRegistrationOpen(true); } }; fetchImages(); setReels(Array.from({ length: DEFAULT_SLOT_COUNT }, () => [])); }, []); useEffect(() => { if (!spinAudioRef.current) { spinAudioRef.current = new Audio(SPIN_AUDIO_URL); spinAudioRef.current.loop = true; } }, []); useEffect(() => { if (!winAudioRef.current) { winAudioRef.current = new Audio(WIN_AUDIO_URL); winAudioRef.current.loop = false; } }, []); useEffect(() => { if (!loseAudioRef.current) { loseAudioRef.current = new Audio(LOSE_AUDIO_URL); loseAudioRef.current.loop = false; } }, []); const handleSpin = () => { if (!isSpinning) { setIsRegistrationOpen(true); setSpinResult(null); } }; const handleRegistrationSubmit = ( username: string, phone: string, eligible: boolean, combination: string, result: string, ) => { if (eligible) { setSpinCombination(combination); // This will be used for game info setSpinResult(result as 'win' | 'loss'); setIsSpinning(true); setCompletedReels(0); setIsRegistrationOpen(false); setSpinKey((prev) => prev + 1); if (isSoundOn && spinAudioRef.current) { spinAudioRef.current.currentTime = 0; spinAudioRef.current.play().catch((err) => console.error('Error playing spin audio:', err)); } } }; useEffect(() => { if (completedReels === reels.length && isSpinning) { setIsSpinning(false); setTimeout(() => { if (spinAudioRef.current && !spinAudioRef.current.paused) { spinAudioRef.current.pause(); spinAudioRef.current.currentTime = 0; } if (isSoundOn) { if (spinResult === 'win' && winAudioRef.current) { winAudioRef.current.currentTime = 0; winAudioRef.current .play() .catch((err) => console.error('Error playing win audio:', err)); } else if (spinResult === 'loss' && loseAudioRef.current) { loseAudioRef.current.currentTime = 0; loseAudioRef.current .play() .catch((err) => console.error('Error playing lose audio:', err)); } } setIsRegistrationOpen(true); }, 3600); } }, [completedReels, reels.length, isSpinning, spinResult, isSoundOn]); const handleReelComplete = () => { setCompletedReels((prev) => prev + 1); }; const toggleSound = () => { setIsSoundOn((prev) => { const newSoundState = !prev; if (!newSoundState) { if (spinAudioRef.current && !spinAudioRef.current.paused) { spinAudioRef.current.pause(); spinAudioRef.current.currentTime = 0; } if (winAudioRef.current && !winAudioRef.current.paused) { winAudioRef.current.pause(); winAudioRef.current.currentTime = 0; } if (loseAudioRef.current && !loseAudioRef.current.paused) { loseAudioRef.current.pause(); loseAudioRef.current.currentTime = 0; } } else if (newSoundState && isSpinning && spinAudioRef.current) { spinAudioRef.current.currentTime = 0; spinAudioRef.current.play().catch((err) => console.error('Error playing spin audio:', err)); } return newSoundState; }); }; const infomessage = () => { setIsInfoOpen(true); }; const handleSoundMouseEnter = () => setTooltips((prev) => ({ ...prev, sound: true })); const handleSoundMouseLeave = () => setTooltips((prev) => ({ ...prev, sound: false })); const handleInfoMouseEnter = () => setTooltips((prev) => ({ ...prev, info: true })); const handleInfoMouseLeave = () => setTooltips((prev) => ({ ...prev, info: false })); const renderGameInfo = () => { // For now, use spinCombination or a fallback if API isn't ready const combination = spinCombination || '123'; // Fallback to '123' until API is integrated // Placeholder logic: assume combination maps to a single prize (e.g., first digit or full string as key) // Replace this with actual API mapping when available const prizeId = parseInt(combination[0]); // Temporary: using first digit as prize ID const slot = slotImages.find((img) => img.id === prizeId) || { id: prizeId, image_path: 'placeholder.png', // Placeholder until API data prize_name: `Prize for ${combination}`, }; return ( <div className="game-info-container"> <h3 className="game-info-title">Combination Prize Preview</h3> <div className="game-info-item"> <img src={slot.image_path} alt={`Prize for ${combination}`} className="game-info-image" /> <p className="game-info-prize">{slot.prize_name || `Prize for ${combination}`}</p> </div> </div> ); }; return ( <div className="main-slotmachine"> <div className="slot-machine"> <div id="framework-center" style={{ backgroundImage: `url(${backgroundImage})`, backgroundSize: 'cover', backgroundPosition: 'center', backgroundRepeat: 'no-repeat', }} > <div className="game-title" style={{ color: titleColor }}> <Title gameTitle={gameTitle} titleColor={titleColor} /> </div> <div className="control-buttons-container"> <Tooltip text={isSoundOn ? 'Mute Sound' : 'Unmute Sound'} visible={tooltips.sound} position="bottom" > <GameButton variant="sound" isActive={isSoundOn} onClick={toggleSound} onMouseEnter={handleSoundMouseEnter} onMouseLeave={handleSoundMouseLeave} /> </Tooltip> <Tooltip text="View Info" visible={tooltips.info} position="bottom"> <GameButton variant="info" onClick={infomessage} onMouseEnter={handleInfoMouseEnter} onMouseLeave={handleInfoMouseLeave} /> </Tooltip> </div> <div className="reels-container" style={{ borderColor: reelBorder }}> {reels.map((_, index) => { const targetId = spinCombination ? parseInt(spinCombination[index] || '0') : -1; return ( <Reel key={`${index}-${spinKey}`} slotImages={slotImages} isSpinning={isSpinning} spinDuration={baseSpinDuration + index * delayBetweenStops} onSpinComplete={handleReelComplete} targetId={targetId} reelBorder={reelBorder} /> ); })} </div> <div className="spin-container"> <div className="spin-button-wrapper"> <GameButton variant="spin" onClick={handleSpin} disabled={isSpinning} buttonBackgroundColor={buttonBackgroundColor} buttonTextColor={buttonTextColor} reelBorder={reelBorder} /> </div> </div> </div> <Registration isOpen={isRegistrationOpen} setIsOpen={setIsRegistrationOpen} onSubmit={handleRegistrationSubmit} spinResult={isSpinning ? null : spinResult} error={error} /> <Model isOpen={isInfoOpen} onClose={() => setIsInfoOpen(false)} title="Game Rules" content={ <div> <p>Welcome to the Slot Machine Game!</p> {slotImages.length > 0 ? renderGameInfo() : <p>Loading prize preview...</p>} </div> } showCloseButton={true} /> </div> </div> ); }; export default SlotMachine;
Comments