-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d143866
commit 8161771
Showing
10 changed files
with
335 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
front-end/src/components/sync-effects/sync-match-occurring-to-recoil.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { Match, MatchSocketEvent, MatchState } from '@toa-lib/models'; | ||
import { FC, useEffect } from 'react'; | ||
import { useRecoilCallback } from 'recoil'; | ||
import { useSocket } from 'src/api/use-socket'; | ||
import { matchOccurringAtom, matchStateAtom } from 'src/stores/recoil'; | ||
|
||
interface Props { | ||
stopAfterMatchEnd?: boolean; | ||
} | ||
|
||
export const SyncMatchOccurringToRecoil: FC<Props> = ({ | ||
stopAfterMatchEnd | ||
}) => { | ||
const [socket, connected] = useSocket(); | ||
|
||
useEffect(() => { | ||
if (connected) { | ||
socket?.on(MatchSocketEvent.UPDATE, onUpdate); | ||
} | ||
}, [connected]); | ||
|
||
useEffect(() => { | ||
return () => { | ||
socket?.removeListener(MatchSocketEvent.UPDATE, onUpdate); | ||
}; | ||
}, []); | ||
|
||
const onUpdate = useRecoilCallback( | ||
({ snapshot, set }) => | ||
async (newMatch: Match<any>) => { | ||
const state = await snapshot.getPromise(matchStateAtom); | ||
if (stopAfterMatchEnd && state >= MatchState.MATCH_COMPLETE) { | ||
// Don't update anything. | ||
return; | ||
} else { | ||
set(matchOccurringAtom, newMatch); | ||
} | ||
} | ||
); | ||
|
||
return null; | ||
}; |
58 changes: 58 additions & 0 deletions
58
front-end/src/components/sync-effects/sync-match-state-to-recoil.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { MatchSocketEvent, MatchState } from '@toa-lib/models'; | ||
import { FC, useEffect } from 'react'; | ||
import { useSetRecoilState } from 'recoil'; | ||
import { useSocket } from 'src/api/use-socket'; | ||
import { matchStatusAtom, matchStateAtom } from 'src/stores/recoil'; | ||
|
||
export const SyncMatchStateToRecoil: FC = () => { | ||
const setState = useSetRecoilState(matchStateAtom); | ||
const setMode = useSetRecoilState(matchStatusAtom); | ||
const [socket, connected] = useSocket(); | ||
|
||
useEffect(() => { | ||
if (connected) { | ||
socket?.on(MatchSocketEvent.PRESTART, onMatchPrestart); | ||
socket?.on(MatchSocketEvent.START, onMatchStart); | ||
socket?.on(MatchSocketEvent.END, onMatchEnd); | ||
socket?.on(MatchSocketEvent.ABORT, onMatchAbort); | ||
|
||
socket?.on(MatchSocketEvent.TELEOPERATED, onMatchTele); | ||
socket?.on(MatchSocketEvent.ENDGAME, onMatchEndGame); | ||
} | ||
}, [connected]); | ||
|
||
useEffect(() => { | ||
return () => { | ||
socket?.off(MatchSocketEvent.PRESTART, onMatchPrestart); | ||
socket?.off(MatchSocketEvent.START, onMatchStart); | ||
socket?.off(MatchSocketEvent.END, onMatchEnd); | ||
socket?.off(MatchSocketEvent.ABORT, onMatchAbort); | ||
|
||
socket?.off(MatchSocketEvent.TELEOPERATED, onMatchTele); | ||
socket?.off(MatchSocketEvent.ENDGAME, onMatchEndGame); | ||
}; | ||
}, []); | ||
|
||
const onMatchPrestart = () => { | ||
setState(MatchState.PRESTART_COMPLETE); | ||
setMode('PRESTART COMPLETE'); | ||
}; | ||
|
||
const onMatchStart = () => { | ||
setState(MatchState.MATCH_IN_PROGRESS); | ||
setMode('MATCH STARTED'); | ||
}; | ||
const onMatchEnd = () => { | ||
setState(MatchState.MATCH_COMPLETE); | ||
setMode('MATCH COMPLETE'); | ||
}; | ||
const onMatchAbort = () => { | ||
setState(MatchState.MATCH_ABORTED); | ||
setMode('MATCH ABORTED'); | ||
}; | ||
|
||
const onMatchTele = () => setMode('TELEOPERATED'); | ||
const onMatchEndGame = () => setMode('ENDGAME'); | ||
|
||
return null; | ||
}; |
19 changes: 19 additions & 0 deletions
19
front-end/src/components/sync-effects/sync-matches-to-recoi.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { FC, useEffect } from 'react'; | ||
import { useRecoilValue, useSetRecoilState } from 'recoil'; | ||
import { useMatchesForEvent } from 'src/api/use-match-data'; | ||
import { currentEventKeyAtom } from 'src/stores/NewRecoil'; | ||
import { matchesByEventKeyAtomFam } from 'src/stores/recoil'; | ||
|
||
export const SyncMatchesToRecoil: FC = () => { | ||
const eventKey = useRecoilValue(currentEventKeyAtom); | ||
const setMatches = useSetRecoilState( | ||
matchesByEventKeyAtomFam(eventKey) ?? '' | ||
); | ||
const { data: matches } = useMatchesForEvent(eventKey); | ||
useEffect(() => { | ||
if (matches) { | ||
setMatches(matches); | ||
} | ||
}, [matches]); | ||
return null; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
import { | ||
FGC_MATCH_CONFIG, | ||
FRC_MATCH_CONFIG, | ||
MatchKey, | ||
MatchSocketEvent, | ||
MatchState, | ||
TimerEventPayload, | ||
getSeasonKeyFromEventKey | ||
} from '@toa-lib/models'; | ||
import { Duration } from 'luxon'; | ||
import { FC, useEffect } from 'react'; | ||
import { useRecoilState, useRecoilValue } from 'recoil'; | ||
import { useSocket } from 'src/api/use-socket'; | ||
import { | ||
initAudio, | ||
MATCH_START, | ||
MATCH_TELE, | ||
MATCH_TRANSITION, | ||
MATCH_ABORT, | ||
MATCH_ENDGAME, | ||
MATCH_END | ||
} from 'src/apps/AudienceDisplay/Audio'; | ||
import { | ||
matchOccurringAtom, | ||
matchStateAtom, | ||
matchTimeAtom, | ||
matchTimeModeAtom, | ||
timer | ||
} from 'src/stores/recoil'; | ||
|
||
const startAudio = initAudio(MATCH_START); | ||
const transitionAudio = initAudio(MATCH_TRANSITION); | ||
const teleAudio = initAudio(MATCH_TELE); | ||
const abortAudio = initAudio(MATCH_ABORT); | ||
const endgameAudio = initAudio(MATCH_ENDGAME); | ||
const endAudio = initAudio(MATCH_END); | ||
|
||
interface Props { | ||
audio?: boolean; | ||
mode?: 'modeTime' | 'timeLeft'; | ||
} | ||
|
||
export const MatchTimer: FC<Props> = ({ audio, mode = 'timeLeft' }) => { | ||
const matchState = useRecoilValue(matchStateAtom); | ||
const [time, setTime] = useRecoilState(matchTimeAtom); | ||
const [modeTime, setModeTime] = useRecoilState(matchTimeModeAtom); | ||
const currentMatch = useRecoilValue(matchOccurringAtom); | ||
const [socket, connected] = useSocket(); | ||
|
||
useEffect(() => { | ||
if (connected) { | ||
socket?.on(MatchSocketEvent.PRESTART, onPrestart); | ||
socket?.on(MatchSocketEvent.START, onStart); | ||
socket?.on(MatchSocketEvent.ABORT, onAbort); | ||
|
||
timer.on('timer:transition', onTransition); | ||
timer.on('timer:tele', onTele); | ||
timer.on('timer:endgame', onEndgame); | ||
timer.on('timer:end', onEnd); | ||
} | ||
}, [connected]); | ||
|
||
useEffect(() => { | ||
if (!timer.inProgress()) { | ||
timer.reset(); | ||
setTime(timer.timeLeft); | ||
setModeTime(timer.modeTimeLeft); | ||
} | ||
|
||
const tick = setInterval(() => { | ||
setTime(timer.timeLeft); | ||
setModeTime(timer.modeTimeLeft); | ||
}, 500); | ||
|
||
return () => { | ||
socket?.off(MatchSocketEvent.PRESTART, onPrestart); | ||
socket?.off(MatchSocketEvent.START, onStart); | ||
socket?.off(MatchSocketEvent.ABORT, onAbort); | ||
|
||
timer.off('timer:transition', onTransition); | ||
timer.off('timer:tele', onTele); | ||
timer.off('timer:endgame', onEndgame); | ||
timer.off('timer:end', onEnd); | ||
clearInterval(tick); | ||
}; | ||
}, []); | ||
|
||
useEffect(() => { | ||
if (matchState === MatchState.MATCH_IN_PROGRESS && timer.inProgress()) { | ||
setTime(timer.timeLeft); | ||
setModeTime(timer.modeTimeLeft); | ||
} | ||
}, [matchState]); | ||
|
||
const timeDuration = Duration.fromObject({ | ||
seconds: mode === 'timeLeft' ? time : modeTime | ||
}); | ||
|
||
const onPrestart = (e: MatchKey) => { | ||
timer.reset(); | ||
|
||
determineTimerConfig(e.eventKey); | ||
|
||
setTime(timer.timeLeft); | ||
}; | ||
|
||
const onStart = () => { | ||
if (audio) startAudio.play(); | ||
if (currentMatch) determineTimerConfig(currentMatch.eventKey); | ||
timer.start(); | ||
}; | ||
const onTransition = (payload: TimerEventPayload) => { | ||
if (audio && payload.allowAudio) transitionAudio.play(); | ||
}; | ||
const onTele = (payload: TimerEventPayload) => { | ||
if (audio && payload.allowAudio) teleAudio.play(); | ||
}; | ||
const onAbort = () => { | ||
if (audio) abortAudio.play(); | ||
timer.abort(); | ||
}; | ||
const onEnd = (payload: TimerEventPayload) => { | ||
if (audio && payload.allowAudio) endAudio.play(); | ||
timer.stop(); | ||
}; | ||
const onEndgame = (payload: TimerEventPayload) => { | ||
if (audio && payload.allowAudio) endgameAudio.play(); | ||
}; | ||
|
||
const determineTimerConfig = (eventKeyLike: string) => { | ||
// Get season key frome event key | ||
const seasonKey = getSeasonKeyFromEventKey(eventKeyLike).toLowerCase(); | ||
|
||
// Set match config based on season key | ||
const matchConfig = seasonKey.includes('frc') | ||
? FRC_MATCH_CONFIG | ||
: FGC_MATCH_CONFIG; | ||
timer.matchConfig = matchConfig; | ||
}; | ||
|
||
return ( | ||
<> | ||
{mode === 'timeLeft' | ||
? timeDuration.toFormat('m:ss') | ||
: timeDuration.toFormat('s')} | ||
</> | ||
); | ||
}; |
Oops, something went wrong.