11import React , { useEffect , useRef , useState } from 'react' ;
22
3+ // 1. Import video files directly at the top
4+ // This is the modern and most reliable way to handle static assets.
5+ import circleVideo from '../assets/smooth-pursuit/Circle.mp4' ;
6+ import squareVideo from '../assets/smooth-pursuit/Square.mp4' ;
7+ import infinityVideo from '../assets/smooth-pursuit/Infinity.mp4' ;
8+ import starVideo from '../assets/smooth-pursuit/Star.mp4' ;
9+ import triangleVideo from '../assets/smooth-pursuit/Triangle.mp4' ;
10+ import leftRightVideo from '../assets/smooth-pursuit/left_right.mp4' ;
11+
12+ // Use the imported variables in your array.
13+ // The 'type' property is no longer needed as we set the src directly.
314const SMOOTH_PURSUIT_VIDEOS = [
4- {
5- src : require ( '../assets/smooth-pursuit/Circle.mp4' ) ,
6- name : 'Circle' ,
7- type : 'video/mp4' ,
8- } ,
9- {
10- src : require ( '../assets/smooth-pursuit/Square.mp4' ) ,
11- name : 'Square' ,
12- type : 'video/mp4' ,
13- } ,
14- {
15- src : require ( '../assets/smooth-pursuit/Infinity.mp4' ) ,
16- name : 'Infinity' ,
17- type : 'video/mp4' ,
18- } ,
19- {
20- src : require ( '../assets/smooth-pursuit/Star.mp4' ) ,
21- name : 'Star' ,
22- type : 'video/mp4' ,
23- } ,
24- {
25- src : require ( '../assets/smooth-pursuit/Triangle.mp4' ) ,
26- name : 'Triangle' ,
27- type : 'video/mp4' ,
28- } ,
29- {
30- src : require ( '../assets/smooth-pursuit/left_right.mp4' ) ,
31- name : 'Left to Right' ,
32- type : 'video/mp4' ,
33- } ,
15+ { src : circleVideo , name : 'Circle' } ,
16+ { src : squareVideo , name : 'Square' } ,
17+ { src : infinityVideo , name : 'Infinity' } ,
18+ { src : starVideo , name : 'Star' } ,
19+ { src : triangleVideo , name : 'Triangle' } ,
20+ { src : leftRightVideo , name : 'Left to Right' } ,
3421] ;
3522
3623const SmoothPursuitVideoTask = ( { onSubmit, onTaskComplete } ) => {
@@ -43,29 +30,22 @@ const SmoothPursuitVideoTask = ({ onSubmit, onTaskComplete }) => {
4330 const currentVideo = SMOOTH_PURSUIT_VIDEOS [ currentVideoIndex ] ;
4431 const isLastVideo = currentVideoIndex === SMOOTH_PURSUIT_VIDEOS . length - 1 ;
4532
46- // Handle phase transitions for each video
33+ // This logic remains the same
4734 useEffect ( ( ) => {
4835 setPhase ( 'cross' ) ;
4936 setVideoEnded ( false ) ;
5037 setVideoError ( false ) ;
5138
52- // Cross phase (1 second)
53- const crossTimer = setTimeout ( ( ) => {
54- setPhase ( 'instruction' ) ;
55- } , 1000 ) ;
56-
57- // Instruction phase (1 second)
58- const instructionTimer = setTimeout ( ( ) => {
59- setPhase ( 'video' ) ;
60- } , 2000 ) ;
39+ const crossTimer = setTimeout ( ( ) => setPhase ( 'instruction' ) , 1000 ) ;
40+ const instructionTimer = setTimeout ( ( ) => setPhase ( 'video' ) , 2000 ) ;
6141
6242 return ( ) => {
6343 clearTimeout ( crossTimer ) ;
6444 clearTimeout ( instructionTimer ) ;
6545 } ;
6646 } , [ currentVideoIndex ] ) ;
6747
68- // Handle video events
48+ // This logic remains the same
6949 useEffect ( ( ) => {
7050 const video = videoRef . current ;
7151 if ( ! video || phase !== 'video' ) return ;
@@ -76,57 +56,35 @@ const SmoothPursuitVideoTask = ({ onSubmit, onTaskComplete }) => {
7656 onTaskComplete ?. ( ) ;
7757 }
7858 } ;
79-
80- const handleError = ( ) => {
59+ const handleError = ( e ) => {
8160 setVideoError ( true ) ;
82- console . error ( 'Video playback error for :' , currentVideo . src ) ;
61+ console . error ( 'Video playback error:' , currentVideo . name , e ) ;
8362 } ;
84-
8563 const handleCanPlay = ( ) => {
8664 setVideoError ( false ) ;
87- // Auto-play when video is ready
88- video . play ( ) . catch ( error => {
89- console . warn ( 'Autoplay failed:' , error ) ;
90- } ) ;
91- } ;
92-
93- // Prevent fullscreen attempts
94- const preventFullscreen = ( e ) => {
95- e . preventDefault ( ) ;
96- e . stopPropagation ( ) ;
97- return false ;
65+ video . play ( ) . catch ( error => console . warn ( 'Autoplay failed:' , error ) ) ;
9866 } ;
9967
10068 video . addEventListener ( 'ended' , handleEnded ) ;
10169 video . addEventListener ( 'error' , handleError ) ;
10270 video . addEventListener ( 'canplay' , handleCanPlay ) ;
103- video . addEventListener ( 'dblclick' , preventFullscreen ) ;
104- video . addEventListener ( 'webkitbeginfullscreen' , preventFullscreen ) ;
105- video . addEventListener ( 'mozfullscreenchange' , preventFullscreen ) ;
106- video . addEventListener ( 'fullscreenchange' , preventFullscreen ) ;
10771
10872 return ( ) => {
10973 video . removeEventListener ( 'ended' , handleEnded ) ;
11074 video . removeEventListener ( 'error' , handleError ) ;
11175 video . removeEventListener ( 'canplay' , handleCanPlay ) ;
112- video . removeEventListener ( 'dblclick' , preventFullscreen ) ;
113- video . removeEventListener ( 'webkitbeginfullscreen' , preventFullscreen ) ;
114- video . removeEventListener ( 'mozfullscreenchange' , preventFullscreen ) ;
115- video . removeEventListener ( 'fullscreenchange' , preventFullscreen ) ;
11676 } ;
117- } , [ phase , currentVideo ] ) ;
77+ } , [ phase , currentVideo , isLastVideo , onTaskComplete ] ) ;
11878
11979 const handleNextVideo = ( ) => {
12080 if ( isLastVideo ) {
121- // All videos completed - store data and signal task completion
12281 const completionData = {
12382 videosCompleted : SMOOTH_PURSUIT_VIDEOS . length ,
12483 completedAt : new Date ( ) . toISOString ( )
12584 } ;
12685 onSubmit ?. ( completionData ) ;
127- onTaskComplete ?. ( ) ; // Signal that the task is complete to show next button
86+ onTaskComplete ?. ( ) ;
12887 } else {
129- // Move to next video
13088 setCurrentVideoIndex ( prev => prev + 1 ) ;
13189 }
13290 } ;
@@ -139,35 +97,30 @@ const SmoothPursuitVideoTask = ({ onSubmit, onTaskComplete }) => {
13997 < div style = { styles . cross } > +</ div >
14098 </ div >
14199 ) ;
142-
143100 case 'instruction' :
144101 return (
145102 < div style = { styles . phaseContainer } >
146- < h2 style = { styles . instructionText } >
147- Track the ball in the video
148- </ h2 >
103+ < h2 style = { styles . instructionText } > Track the ball in the video</ h2 >
149104 </ div >
150105 ) ;
151-
152106 case 'video' :
153107 return (
154108 < div style = { styles . videoContainer } >
155109 { videoError ? (
156110 < div style = { styles . errorContainer } >
157111 < h3 > Video Loading Error</ h3 >
158112 < p > There was an issue loading: { currentVideo . name } </ p >
159- < button
160- onClick = { handleNextVideo }
161- style = { styles . errorButton }
162- >
163- { isLastVideo ? 'Finish Videos' : 'Skip to Next Video' }
113+ < button onClick = { handleNextVideo } style = { styles . errorButton } >
114+ { isLastVideo ? 'Finish Task' : 'Skip to Next Video' }
164115 </ button >
165116 </ div >
166117 ) : (
167118 < >
119+ { /* 2. Set the 'src' attribute directly on the <video> tag */ }
168120 < video
169121 ref = { videoRef }
170122 style = { styles . video }
123+ src = { currentVideo . src }
171124 controls
172125 muted
173126 playsInline
@@ -177,35 +130,27 @@ const SmoothPursuitVideoTask = ({ onSubmit, onTaskComplete }) => {
177130 onContextMenu = { ( e ) => e . preventDefault ( ) }
178131 onDoubleClick = { ( e ) => e . preventDefault ( ) }
179132 >
180- < source src = { currentVideo . src } type = { currentVideo . type } />
181133 Your browser does not support the video tag.
182134 </ video >
183135
184136 { videoEnded && ! isLastVideo && (
185- < button
186- onClick = { handleNextVideo }
187- style = { styles . nextButton }
188- >
189- { 'Next Video' }
137+ < button onClick = { handleNextVideo } style = { styles . nextButton } >
138+ Next Video
190139 </ button >
191140 ) }
192141 </ >
193142 ) }
194143 </ div >
195144 ) ;
196-
197145 default :
198146 return null ;
199147 }
200148 } ;
201149
202- return (
203- < div style = { styles . container } >
204- { renderContent ( ) }
205- </ div >
206- ) ;
150+ return < div style = { styles . container } > { renderContent ( ) } </ div > ;
207151} ;
208152
153+ // Styles remain the same
209154const styles = {
210155 container : {
211156 height : '100vh' ,
0 commit comments