11import { Activity , AssignmentCode , Person } from '@wca/helpers' ;
2+ import classNames from 'classnames' ;
23import { useCallback , useEffect , useMemo } from 'react' ;
34import { useTranslation } from 'react-i18next' ;
4- import { Link } from 'react-router-dom' ;
5+ import { Link , Navigate , useNavigate } from 'react-router-dom' ;
56import { Breadcrumbs } from '@/components/Breadcrumbs/Breadcrumbs' ;
67import { CutoffTimeLimitPanel } from '@/components/CutoffTimeLimitPanel' ;
78import { getRoomData , getRooms } from '@/lib/activities' ;
@@ -24,6 +25,7 @@ interface EventGroupProps {
2425export function EventActivity ( { competitionId, activity, persons } : EventGroupProps ) {
2526 const { t } = useTranslation ( ) ;
2627
28+ const navigate = useNavigate ( ) ;
2729 const { setTitle, wcif } = useWCIF ( ) ;
2830 const { eventId, roundNumber } = parseActivityCodeFlexible ( activity ?. activityCode || '' ) ;
2931 const event = useMemo (
@@ -182,6 +184,76 @@ export function EventActivity({ competitionId, activity, persons }: EventGroupPr
182184
183185 const groupNumber = parseActivityCodeFlexible ( activity . activityCode ) . groupNumber ;
184186
187+ const allActivitiesInStage = useMemo (
188+ ( ) =>
189+ room ?. activities
190+ . flatMap ( ( i ) => i . childActivities )
191+ . filter ( ( i ) => {
192+ const stage = getRoomData ( room , i ) ;
193+ if ( stage && roomData ) {
194+ return stage ?. name === roomData ?. name ;
195+ }
196+
197+ return true ;
198+ } )
199+ . sort ( ( a , b ) => new Date ( a . startTime ) . getTime ( ) - new Date ( b . startTime ) . getTime ( ) ) ,
200+ [ room , roomData ] ,
201+ ) ;
202+
203+ const currentIndex = useMemo ( ( ) => {
204+ return allActivitiesInStage ?. findIndex ( ( i ) => i . id === activity . id ) ;
205+ } , [ activity . id , allActivitiesInStage ] ) ;
206+
207+ const prev = useMemo (
208+ ( ) =>
209+ allActivitiesInStage && currentIndex !== undefined
210+ ? allActivitiesInStage [ currentIndex - 1 ]
211+ : undefined ,
212+ [ allActivitiesInStage , currentIndex ] ,
213+ ) ;
214+ const next = useMemo (
215+ ( ) =>
216+ allActivitiesInStage && currentIndex !== undefined
217+ ? allActivitiesInStage [ currentIndex + 1 ]
218+ : undefined ,
219+ [ allActivitiesInStage , currentIndex ] ,
220+ ) ;
221+
222+ const prevUrl = prev && `/competitions/${ competitionId } /activities/${ prev ?. id } ` ;
223+ const nextUrl = next && `/competitions/${ competitionId } /activities/${ next ?. id } ` ;
224+
225+ const goToPrev = useCallback ( ( ) => {
226+ if ( prevUrl ) {
227+ navigate ( prevUrl ) ;
228+ }
229+ } , [ navigate , prevUrl ] ) ;
230+
231+ const goToNext = useCallback ( ( ) => {
232+ if ( nextUrl ) {
233+ navigate ( nextUrl ) ;
234+ }
235+ } , [ navigate , nextUrl ] ) ;
236+
237+ useEffect ( ( ) => {
238+ const handleKeydown = ( event : KeyboardEvent ) => {
239+ if ( event . key === 'ArrowLeft' ) {
240+ goToPrev ( ) ;
241+ }
242+
243+ if ( event . key === 'ArrowRight' ) {
244+ goToNext ( ) ;
245+ }
246+ } ;
247+
248+ document . addEventListener ( 'keydown' , handleKeydown ) ;
249+
250+ return ( ) => {
251+ document . removeEventListener ( 'keydown' , handleKeydown ) ;
252+ } ;
253+ } , [ wcif , activity , goToPrev , goToNext ] ) ;
254+
255+ console . log ( { prev, next } ) ;
256+
185257 return (
186258 < >
187259 { wcif && (
@@ -207,6 +279,33 @@ export function EventActivity({ competitionId, activity, persons }: EventGroupPr
207279 ] ) ,
208280 ] }
209281 />
282+ < div className = "flex space-x-2" >
283+ < Link
284+ to = { prevUrl || '' }
285+ className = { classNames (
286+ 'w-full border rounded-md p-2 px-2 flex cursor-pointer transition-colors my-1 justify-end' ,
287+ {
288+ 'pointer-events-none opacity-25' : ! prev ,
289+ 'hover:bg-slate-100 group cursor-pointer' : prev ,
290+ } ,
291+ ) } >
292+ < span className = "fa fa-arrow-left self-center mr-2 group-hover:-translate-x-2 transition-all" />
293+ { t ( 'competition.groups.previousGroup' ) }
294+ </ Link >
295+ < Link
296+ to = { nextUrl || '' }
297+ className = { classNames (
298+ 'w-full border rounded-md p-2 px-2 flex cursor-pointer group hover:bg-slate-100 transition-colors my-1' ,
299+ {
300+ 'pointer-events-none opacity-25' : ! next ,
301+ 'hover:bg-slate-100 group' : next ,
302+ } ,
303+ ) } >
304+ { t ( 'competition.groups.nextGroup' ) }
305+ < span className = "fa fa-arrow-right self-center ml-2 group-hover:translate-x-2 transition-all" />
306+ </ Link >
307+ </ div >
308+
210309 < div className = "space-y-1" >
211310 < span className = "px-2" >
212311 { formatDateTimeRange ( activity . startTime , activity . endTime , 5 , timeZone ) }
0 commit comments