11'use client' ;
22
3- import { useState , useEffect } from 'react' ;
3+ import { useState , useEffect , useRef } from 'react' ;
44import { motion } from 'framer-motion' ;
55import { useWallet } from '@/contexts/WalletContext' ;
66import { useHathor } from '@/contexts/HathorContext' ;
@@ -44,6 +44,7 @@ export default function FortuneTigerBetCard({ selectedToken }: FortuneTigerBetCa
4444 const [ potentialPayout , setPotentialPayout ] = useState ( 20 ) ;
4545 const [ isPlacingBet , setIsPlacingBet ] = useState ( false ) ;
4646 const [ isSpinning , setIsSpinning ] = useState ( false ) ;
47+ const [ isIdleSpinning , setIsIdleSpinning ] = useState ( false ) ;
4748 const [ luckyNumber , setLuckyNumber ] = useState ( 0 ) ;
4849 const [ pendingBetTxId , setPendingBetTxId ] = useState < string | null > ( null ) ;
4950 const [ betResult , setBetResult ] = useState < 'win' | 'lose' | null > ( null ) ;
@@ -52,6 +53,39 @@ export default function FortuneTigerBetCard({ selectedToken }: FortuneTigerBetCa
5253 const [ showWalletModal , setShowWalletModal ] = useState ( false ) ;
5354 const [ showAnimationSelector , setShowAnimationSelector ] = useState ( false ) ;
5455 const [ debugMode , setDebugMode ] = useState ( false ) ;
56+ const [ preloadedVideos , setPreloadedVideos ] = useState < { win : string | null ; lose : string | null } > ( { win : null , lose : null } ) ;
57+
58+ const idleTimerRef = useRef < NodeJS . Timeout | null > ( null ) ;
59+ const IDLE_TIMEOUT = 15000 ; // 15 seconds of inactivity
60+
61+ // Video animation lists for preloading
62+ const WIN_VIDEO_PATHS = [
63+ '/videos/win/b0386440-e311-447f-9ad9-66fcae177139.mp4' ,
64+ '/videos/win/victory-is-yours.mp4' ,
65+ ] ;
66+
67+ const LOSE_VIDEO_PATHS = [
68+ '/videos/lose/4a51eae1-9047-41d8-8a99-2d03cb543766.mp4' ,
69+ '/videos/lose/51b786d4-3f76-4881-9aa6-95f6f106c4cc.mp4' ,
70+ '/videos/lose/e8029c41-709d-4dd6-85ef-fa15357ce592.mp4' ,
71+ '/videos/lose/fracasso-baiano-1.mp4' ,
72+ '/videos/lose/fracasso-baiano-2.mp4' ,
73+ '/videos/lose/fracasso-baiano-3.mp4' ,
74+ ] ;
75+
76+ // Preload videos while spinning
77+ const preloadVideos = ( ) => {
78+ const randomWinVideo = WIN_VIDEO_PATHS [ Math . floor ( Math . random ( ) * WIN_VIDEO_PATHS . length ) ] ;
79+ const randomLoseVideo = LOSE_VIDEO_PATHS [ Math . floor ( Math . random ( ) * LOSE_VIDEO_PATHS . length ) ] ;
80+ setPreloadedVideos ( { win : randomWinVideo , lose : randomLoseVideo } ) ;
81+
82+ // Fetch videos to cache them
83+ [ randomWinVideo , randomLoseVideo ] . forEach ( path => {
84+ fetch ( path ) . catch ( ( ) => {
85+ // Silently fail - we just want to cache if possible
86+ } ) ;
87+ } ) ;
88+ } ;
5589
5690 const contractState = getContractStateForToken ( selectedToken ) ;
5791 const randomBitLength = contractState ?. random_bit_length || 16 ;
@@ -106,10 +140,8 @@ export default function FortuneTigerBetCard({ selectedToken }: FortuneTigerBetCa
106140 selectedAnimation = loseAnimations [ Math . floor ( Math . random ( ) * loseAnimations . length ) ] ;
107141 }
108142
109- // Show animation after a delay
110- setTimeout ( ( ) => {
111- setActiveAnimation ( selectedAnimation ) ;
112- } , 500 ) ;
143+ // Show animation immediately - no delay
144+ setActiveAnimation ( selectedAnimation ) ;
113145 }
114146 } , [ allBets , pendingBetTxId ] ) ;
115147
@@ -136,6 +168,53 @@ export default function FortuneTigerBetCard({ selectedToken }: FortuneTigerBetCa
136168 return ( ) => window . removeEventListener ( 'storage' , handleStorageChange ) ;
137169 } , [ ] ) ;
138170
171+ // Reset idle timer on user activity
172+ const resetIdleTimer = ( ) => {
173+ if ( idleTimerRef . current ) {
174+ clearTimeout ( idleTimerRef . current ) ;
175+ }
176+ setIsIdleSpinning ( false ) ;
177+
178+ idleTimerRef . current = setTimeout ( ( ) => {
179+ // Only start idle spinning if not currently spinning or in other interaction
180+ if ( ! isSpinning && ! isPlacingBet && ! activeAnimation ) {
181+ setIsIdleSpinning ( true ) ;
182+ }
183+ } , IDLE_TIMEOUT ) ;
184+ } ;
185+
186+ // Set up idle timer and user interaction listeners
187+ useEffect ( ( ) => {
188+ resetIdleTimer ( ) ;
189+
190+ const handleUserActivity = ( ) => {
191+ resetIdleTimer ( ) ;
192+ } ;
193+
194+ // Listen for various user interactions
195+ window . addEventListener ( 'mousedown' , handleUserActivity ) ;
196+ window . addEventListener ( 'keydown' , handleUserActivity ) ;
197+ window . addEventListener ( 'scroll' , handleUserActivity ) ;
198+ window . addEventListener ( 'touchstart' , handleUserActivity ) ;
199+
200+ return ( ) => {
201+ window . removeEventListener ( 'mousedown' , handleUserActivity ) ;
202+ window . removeEventListener ( 'keydown' , handleUserActivity ) ;
203+ window . removeEventListener ( 'scroll' , handleUserActivity ) ;
204+ window . removeEventListener ( 'touchstart' , handleUserActivity ) ;
205+ if ( idleTimerRef . current ) {
206+ clearTimeout ( idleTimerRef . current ) ;
207+ }
208+ } ;
209+ } , [ isSpinning , isPlacingBet , activeAnimation ] ) ;
210+
211+ // Stop idle spinning when actual spinning starts
212+ useEffect ( ( ) => {
213+ if ( isSpinning || isPlacingBet ) {
214+ setIsIdleSpinning ( false ) ;
215+ }
216+ } , [ isSpinning , isPlacingBet ] ) ;
217+
139218 const setQuickAmount = ( percentage : number ) => {
140219 const amount = totalBalance * percentage ;
141220 const maxAllowed = Number ( maxBetAmount ) / 100 ;
@@ -165,6 +244,10 @@ export default function FortuneTigerBetCard({ selectedToken }: FortuneTigerBetCa
165244 // Simulate wallet confirmation after 2 seconds
166245 setTimeout ( ( ) => {
167246 setIsPlacingBet ( false ) ;
247+
248+ // Preload videos while spinning
249+ preloadVideos ( ) ;
250+
168251 // Start spinning AFTER wallet confirmation
169252 setIsSpinning ( true ) ;
170253 toast . success ( '🎰 Debug: Transaction confirmed! Spinning...' ) ;
@@ -184,10 +267,8 @@ export default function FortuneTigerBetCard({ selectedToken }: FortuneTigerBetCa
184267 setIsSpinning ( false ) ;
185268 setBetResult ( isWin ? 'win' : 'lose' ) ;
186269
187- // Show the selected animation after a delay
188- setTimeout ( ( ) => {
189- setActiveAnimation ( animationId ) ;
190- } , 500 ) ;
270+ // Show the selected animation immediately
271+ setActiveAnimation ( animationId ) ;
191272 } , 7000 ) ; // 7 seconds of spinning
192273 } , 2000 ) ; // 2 seconds for wallet confirmation
193274 } ;
@@ -242,6 +323,9 @@ export default function FortuneTigerBetCard({ selectedToken }: FortuneTigerBetCa
242323 const result = await placeBet ( betAmount , threshold , selectedToken , contractId , tokenUid , contractBalance ) ;
243324 setPendingBetTxId ( result . response . hash ) ;
244325
326+ // Preload videos while spinning
327+ preloadVideos ( ) ;
328+
245329 // Start spinning AFTER wallet confirmation
246330 setIsSpinning ( true ) ;
247331 toast . success ( '🎰 Transaction confirmed! Spinning...' ) ;
@@ -289,7 +373,7 @@ export default function FortuneTigerBetCard({ selectedToken }: FortuneTigerBetCa
289373 { /* Slot Machine Area */ }
290374 < div className = "mb-8" >
291375 < SlotMachineAnimation
292- isSpinning = { isSpinning }
376+ isSpinning = { isSpinning || isIdleSpinning }
293377 finalNumber = { luckyNumber }
294378 result = { betResult }
295379 />
0 commit comments