From 2512676cf783dc5ac51461c78ab2619e4d4930c9 Mon Sep 17 00:00:00 2001 From: Bux42 Date: Thu, 19 Jun 2025 14:31:22 +0200 Subject: [PATCH 1/5] update to node v22.14.0, update react to v18, update react-three/drei to v7.14.3, uniform eslint & prettier config --- .prettierrc.json | 6 + app/.eslintrc.js | 7 +- .../statistics/FastestTimeProgression.tsx | 197 +- app/components/users/UserHeader.tsx | 32 +- app/components/viewer/ReplayCars.tsx | 139 +- .../viewer/ReplayChartHoverLocation.tsx | 27 +- app/components/viewer/ReplayDnf.tsx | 16 +- app/components/viewer/ReplayGears.tsx | 21 +- app/components/viewer/ReplayLines.tsx | 42 +- .../viewer/SceneDirectionalLight.tsx | 21 +- app/components/viewer/Viewer3D.tsx | 35 +- app/components/viewer/timeline/TimeLine.tsx | 57 +- .../viewer/timeline/TimelineSlider.tsx | 21 +- app/lib/charts/chartData.ts | 3 +- app/lib/charts/chartOptions.ts | 3 +- app/lib/contexts/AuthContext.tsx | 37 +- app/lib/popups/performanceWarning.tsx | 13 +- app/lib/utils/fastestTimeProgression.ts | 3 +- app/lib/utils/logging.ts | 2 + app/lib/utils/replay.ts | 6 +- app/lib/utils/time.ts | 10 +- app/package-lock.json | 26508 ++++++---------- app/package.json | 118 +- app/pages/_app.tsx | 50 +- app/pages/index.tsx | 12 +- app/pages/maps/[mapUId]/index.tsx | 131 +- app/tsconfig.json | 27 +- 27 files changed, 10535 insertions(+), 17009 deletions(-) create mode 100644 .prettierrc.json diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 00000000..91bd42ad --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "tabWidth": 4, + "singleQuote": true, + "trailingComma": "all", + "singleAttributePerLine": true +} diff --git a/app/.eslintrc.js b/app/.eslintrc.js index be0657c7..ce4668b6 100644 --- a/app/.eslintrc.js +++ b/app/.eslintrc.js @@ -6,7 +6,7 @@ module.exports = { extends: [ 'plugin:react/recommended', 'airbnb', - 'plugin:react-hooks/recommended', + 'plugin:react-hooks/recommended' ], globals: { React: true, @@ -43,6 +43,11 @@ module.exports = { 'no-use-before-define': 'off', 'no-unused-vars': 'off', 'react/require-default-props': 'off', + 'operator-linebreak': ['error', 'after'], + 'object-curly-newline': ["error", { "consistent": true }], + "react/no-unknown-property": "off", + "react/jsx-one-expression-per-line": "off", + "implicit-arrow-linebreak": "beside", // due to DB IDs we have to disable this 'no-underscore-dangle': 'off', camelcase: ['error', { diff --git a/app/components/mapStats/statistics/FastestTimeProgression.tsx b/app/components/mapStats/statistics/FastestTimeProgression.tsx index 41b0f497..19160280 100644 --- a/app/components/mapStats/statistics/FastestTimeProgression.tsx +++ b/app/components/mapStats/statistics/FastestTimeProgression.tsx @@ -17,11 +17,12 @@ interface ChartDataPoint { replay: ReplayInfo; } -const replaysToDataPoints = (replays_: ReplayInfo[]): ChartDataPoint[] => replays_.map((replay) => ({ - x: replay.date, - y: replay.endRaceTime, - replay, -})); +const replaysToDataPoints = (replays_: ReplayInfo[]): ChartDataPoint[] => + replays_.map((replay) => ({ + x: replay.date, + y: replay.endRaceTime, + replay, + })); const replaysToProgressionDataPoints = (replays: ReplayInfo[]) => { const progression = calculateFastestTimeProgressions(replays); @@ -29,8 +30,13 @@ const replaysToProgressionDataPoints = (replays: ReplayInfo[]) => { return dataPoints; }; -const filterReplaysByUser = (loggedInUser: AuthUserInfo, inputReplays: ReplayInfo[]) => { - const filtered = inputReplays.filter((r) => r.webId === loggedInUser.accountId); +const filterReplaysByUser = ( + loggedInUser: AuthUserInfo, + inputReplays: ReplayInfo[], +) => { + const filtered = inputReplays.filter( + (r) => r.webId === loggedInUser.accountId, + ); return filtered; }; @@ -44,42 +50,53 @@ const FastestTimeProgression = ({ onlyShowUserProgression, userToShowProgression, }: FastestTimeProgressionProps) => { - const finishedReplays = useMemo(() => replays.filter((r) => r.raceFinished === 1), [replays]); + const finishedReplays = useMemo( + () => replays.filter((r) => r.raceFinished === 1), + [replays], + ); const timeProgressionData: ChartDataPoint[] = useMemo( () => replaysToProgressionDataPoints(replays).reverse(), [replays], ); - const personalTimeProgressionData: ChartDataPoint[] | undefined = useMemo( - () => { + const personalTimeProgressionData: ChartDataPoint[] | undefined = + useMemo(() => { if (userToShowProgression === undefined) { return undefined; } - const filteredReplays = filterReplaysByUser(userToShowProgression, finishedReplays); + const filteredReplays = filterReplaysByUser( + userToShowProgression, + finishedReplays, + ); return replaysToProgressionDataPoints(filteredReplays).reverse(); - }, - [userToShowProgression, finishedReplays], - ); + }, [userToShowProgression, finishedReplays]); + + const allDataPoints: ChartDataPoint[] = useMemo(() => { + let filteredReplays = finishedReplays; - const allDataPoints: ChartDataPoint[] = useMemo( - () => { - let filteredReplays = finishedReplays; + filteredReplays = filteredReplays.filter( + (r1) => + !some( + timeProgressionData, + (r2: ChartDataPoint) => r1._id === r2.replay._id, + null, + ), + ); + if (personalTimeProgressionData) { filteredReplays = filteredReplays.filter( - (r1) => !some(timeProgressionData, (r2: ChartDataPoint) => r1._id === r2.replay._id, null), + (r1) => + !some( + personalTimeProgressionData, + (r2: ChartDataPoint) => r1._id === r2.replay._id, + null, + ), ); + } - if (personalTimeProgressionData) { - filteredReplays = filteredReplays.filter( - (r1) => !some(personalTimeProgressionData, (r2: ChartDataPoint) => r1._id === r2.replay._id, null), - ); - } - - return replaysToDataPoints(filteredReplays); - }, - [finishedReplays, timeProgressionData, personalTimeProgressionData], - ); + return replaysToDataPoints(filteredReplays); + }, [finishedReplays, timeProgressionData, personalTimeProgressionData]); const options = { credits: { @@ -150,7 +167,10 @@ const FastestTimeProgression = ({
- ${timeDifference(new Date().getTime(), this.point.replay.date)} + ${timeDifference( + new Date().getTime(), + this.point.replay.date, + )}
@@ -168,7 +188,9 @@ const FastestTimeProgression = ({ enabled: true, formatter: function dataLabelFormatter(this: any) { // eslint-disable-next-line react/no-this-in-sfc - return `${this.point.replay.playerName} - ${getRaceTimeStr(this.y)}`; + return `${ + this.point.replay.playerName + } - ${getRaceTimeStr(this.y)}`; }, color: 'white', shadow: false, @@ -181,68 +203,81 @@ const FastestTimeProgression = ({ animation: false, }, }, - series: [{ - type: 'line', - name: 'Best Times', - // Set timeProgressionData to undefined to disable the line when only showing user progression - data: onlyShowUserProgression ? undefined : timeProgressionData, - step: 'left', - color: 'green', - }, { - type: 'line', - name: 'Personal Best Times', - data: personalTimeProgressionData, - step: 'left', - color: 'orange', - }, { - type: 'scatter', - name: 'Other Times', - data: allDataPoints, - visible: false, - color: 'gray', - marker: { - symbol: 'circle', - radius: 2, + series: [ + { + type: 'line', + name: 'Best Times', + // Set timeProgressionData to undefined to disable the line when only showing user progression + data: onlyShowUserProgression ? undefined : timeProgressionData, + step: 'left', + color: 'green', + }, + { + type: 'line', + name: 'Personal Best Times', + data: personalTimeProgressionData, + step: 'left', + color: 'orange', + }, + { + type: 'scatter', + name: 'Other Times', + data: allDataPoints, + visible: false, + color: 'gray', + marker: { + symbol: 'circle', + radius: 2, + }, }, - }], + ], }; // Filter series for which the data is undefined options.series = options.series.filter((s) => s.data !== undefined); - const allFastestTime = timeProgressionData && timeProgressionData.length > 0 - ? timeProgressionData[0] - : undefined; + const allFastestTime = + timeProgressionData && timeProgressionData.length > 0 + ? timeProgressionData[0] + : undefined; - const personalFastestTime = personalTimeProgressionData !== undefined && personalTimeProgressionData.length > 0 - ? personalTimeProgressionData[0] - : undefined; + const personalFastestTime = + personalTimeProgressionData !== undefined && + personalTimeProgressionData.length > 0 + ? personalTimeProgressionData[0] + : undefined; const fastestTime = allFastestTime || personalFastestTime; - return ( - fastestTime ? ( - <> -
-
- Note: All these times are from TMDojo data only. - It does not represent a WR progression, but a progression of the best times stored on TMDojo. -
-
Fastest Time
-
- {getRaceTimeStr(fastestTime.replay.endRaceTime)} - {' by '} - -
-
{timeDifference(new Date().getTime(), fastestTime.replay.date)}
+ return fastestTime ? ( + <> +
+
+ Note: All these times are from TMDojo data only. It does not + represent a WR progression, but a progression of the best + times stored on TMDojo.
- - - ) : null - ); +
+ Fastest Time +
+
+ {getRaceTimeStr(fastestTime.replay.endRaceTime)} + {' by '} + +
+
+ {timeDifference( + new Date().getTime(), + fastestTime.replay.date, + )} +
+
+ + + ) : null; }; export default FastestTimeProgression; diff --git a/app/components/users/UserHeader.tsx b/app/components/users/UserHeader.tsx index e17bf60c..8d551886 100644 --- a/app/components/users/UserHeader.tsx +++ b/app/components/users/UserHeader.tsx @@ -12,28 +12,30 @@ interface Props { const UserHeader = ({ userInfo }: Props): JSX.Element => { const router = useRouter(); - const headerTitle = userInfo ? `User profile of ${userInfo.playerName}` : 'Profile not found'; - const tmioURL = userInfo ? `https://trackmania.io/#/player/${userInfo.webId}` : ''; + const headerTitle = userInfo + ? `User profile of ${userInfo.playerName}` + : 'Profile not found'; + const tmioURL = userInfo + ? `https://trackmania.io/#/player/${userInfo.webId}` + : ''; return ( router.push('/')} title={headerTitle} - subTitle={( + subTitle={
- {userInfo - && ( - - - - - - )} - + {userInfo && ( + + + + + + )}
- )} + } extra={} /> ); diff --git a/app/components/viewer/ReplayCars.tsx b/app/components/viewer/ReplayCars.tsx index 6aab61db..3f065d95 100644 --- a/app/components/viewer/ReplayCars.tsx +++ b/app/components/viewer/ReplayCars.tsx @@ -1,19 +1,13 @@ -import { - useFrame, useThree, Camera, -} from '@react-three/fiber'; +import { useFrame, useThree, Camera } from '@react-three/fiber'; import * as THREE from 'three'; -import React, { - useRef, useState, -} from 'react'; +import React, { useRef, useState } from 'react'; import { useFBX } from '@react-three/drei'; import { ReplayData } from '../../lib/api/requests/replays'; import { ReplayDataPoint } from '../../lib/replays/replayData'; import vecToQuat from '../../lib/utils/math'; import { CameraMode } from '../../lib/contexts/SettingsContext'; import InputOverlay from './InputOverlay'; -import { - getSampleNearTime, interpolateSamples, -} from '../../lib/utils/replay'; +import { getSampleNearTime, interpolateSamples } from '../../lib/utils/replay'; import GlobalTimeLineInfos from '../../lib/singletons/timeLineInfos'; const BACK_WHEEL_Y = 35.232017517089844; @@ -29,7 +23,12 @@ interface ReplayCarProps { } const ReplayCar = ({ - replay, camera, orbitControlsRef, showInputOverlay, fbx, replayCarOpacity, + replay, + camera, + orbitControlsRef, + showInputOverlay, + fbx, + replayCarOpacity, }: ReplayCarProps) => { const mesh = useRef(); const stadiumCarMesh = useRef(); @@ -44,7 +43,8 @@ const ReplayCar = ({ // Get own material from loaded car model const carMesh: THREE.Mesh = fbx.children[0] as THREE.Mesh; - const material: THREE.MeshPhongMaterial = carMesh.material as THREE.MeshPhongMaterial; + const material: THREE.MeshPhongMaterial = + carMesh.material as THREE.MeshPhongMaterial; const matClone = material.clone(); matClone.opacity = replayCarOpacity; matClone.color = new THREE.Color( @@ -64,21 +64,38 @@ const ReplayCar = ({ useFrame((state, delta) => { timeLineGlobal.tickTime = delta * 1000; - if (mesh.current - && camPosRef.current) { - const followed = timeLineGlobal.followedReplay != null && timeLineGlobal.followedReplay._id === replay._id; - const hovered = timeLineGlobal.hoveredReplay != null && timeLineGlobal.hoveredReplay._id === replay._id; + if (mesh.current && camPosRef.current) { + const followed = + timeLineGlobal.followedReplay != null && + timeLineGlobal.followedReplay._id === replay._id; + const hovered = + timeLineGlobal.hoveredReplay != null && + timeLineGlobal.hoveredReplay._id === replay._id; // Get closest sample to TimeLine.currentRaceTime - const curSample = getSampleNearTime(replay, timeLineGlobal.currentRaceTime); + const curSample = getSampleNearTime( + replay, + timeLineGlobal.currentRaceTime, + ); currentSampleRef.current = curSample; - prevSampleRef.current = replay.samples[replay.samples.indexOf(curSample) - 1]; + prevSampleRef.current = + replay.samples[replay.samples.indexOf(curSample) - 1]; if (timeLineGlobal.currentRaceTime < replay.endRaceTime) { - interpolateSamples(prevSampleRef.current, curSample, smoothSample, timeLineGlobal.currentRaceTime); + interpolateSamples( + prevSampleRef.current, + curSample, + smoothSample, + timeLineGlobal.currentRaceTime, + ); } else { - interpolateSamples(prevSampleRef.current, curSample, smoothSample, curSample.currentRaceTime); + interpolateSamples( + prevSampleRef.current, + curSample, + smoothSample, + curSample.currentRaceTime, + ); } // Get car rotation @@ -88,7 +105,11 @@ const ReplayCar = ({ ); // Move & rotate 3D car from current sample rot & pos - mesh.current.position.set(smoothSample.position.x, smoothSample.position.y, smoothSample.position.z); + mesh.current.position.set( + smoothSample.position.x, + smoothSample.position.y, + smoothSample.position.z, + ); if (stadiumCarMesh.current) { stadiumCarMesh.current.rotation.setFromQuaternion(carRotation); @@ -103,35 +124,51 @@ const ReplayCar = ({ frontRigthWheel.rotation.y = smoothSample.wheelAngle; // FR // Set wheel suspensions - rearRightWheel.position.setY(BACK_WHEEL_Y - (smoothSample.rRDamperLen * 100)); // RR - frontLeftWheel.position.setY(FRONT_WHEEL_Y - (smoothSample.fLDamperLen * 100)); // FL - rearLeftWheel.position.setY(BACK_WHEEL_Y - (smoothSample.rLDamperLen * 100)); // RL - frontRigthWheel.position.setY(FRONT_WHEEL_Y - (smoothSample.fRDamperLen * 100)); // FR + rearRightWheel.position.setY( + BACK_WHEEL_Y - smoothSample.rRDamperLen * 100, + ); // RR + frontLeftWheel.position.setY( + FRONT_WHEEL_Y - smoothSample.fLDamperLen * 100, + ); // FL + rearLeftWheel.position.setY( + BACK_WHEEL_Y - smoothSample.rLDamperLen * 100, + ); // RL + frontRigthWheel.position.setY( + FRONT_WHEEL_Y - smoothSample.fRDamperLen * 100, + ); // FR } // Camera target replay if selected if (followed) { if (orbitControlsRef && orbitControlsRef.current) { - orbitControlsRef.current.target.lerp(smoothSample.position, 0.2); + orbitControlsRef.current.target.lerp( + smoothSample.position, + 0.2, + ); if (timeLineGlobal.cameraMode === CameraMode.Follow) { // move camPosMesh to Follow position - camPosRef.current.rotation.setFromQuaternion(carRotation); + camPosRef.current.rotation.setFromQuaternion( + carRotation, + ); // move toward where the car is heading const velocitySpeed = smoothSample.velocity.length(); // Set camera position behind the car const backwardMax = 6; - const backward = (backwardMax - (velocitySpeed / backwardMax)); + const backward = + backwardMax - velocitySpeed / backwardMax; camPosRef.current.position.set( - (-smoothSample.velocity.x / 4), - (-smoothSample.velocity.y / 4), - (-smoothSample.velocity.z / 4), + -smoothSample.velocity.x / 4, + -smoothSample.velocity.y / 4, + -smoothSample.velocity.z / 4, ); // Do not force camera behind the car above a certain speed - camPosRef.current.translateZ(backward < 0 ? 0 : -backward); + camPosRef.current.translateZ( + backward < 0 ? 0 : -backward, + ); camPosRef.current.translateY(3); // move camera to camPosMesh world position const camWorldPos: THREE.Vector3 = new THREE.Vector3(); @@ -144,9 +181,15 @@ const ReplayCar = ({ // Scale car up if hovered in LoadedReplays if (stadiumCarMesh.current) { if (hovered) { - stadiumCarMesh.current.scale.lerp(new THREE.Vector3(0.02, 0.02, 0.02), 0.2); + stadiumCarMesh.current.scale.lerp( + new THREE.Vector3(0.02, 0.02, 0.02), + 0.2, + ); } else { - stadiumCarMesh.current.scale.lerp(new THREE.Vector3(0.01, 0.01, 0.01), 0.2); + stadiumCarMesh.current.scale.lerp( + new THREE.Vector3(0.01, 0.01, 0.01), + 0.2, + ); } } } @@ -169,10 +212,7 @@ const ReplayCar = ({ return ( <> - + {replayCarOpacity > 0 && ( )} - {showInputOverlay - && } - - - + {showInputOverlay && ( + + )} + + + - ); diff --git a/app/components/viewer/ReplayChartHoverLocation.tsx b/app/components/viewer/ReplayChartHoverLocation.tsx index 694d4c0b..dc45a111 100644 --- a/app/components/viewer/ReplayChartHoverLocation.tsx +++ b/app/components/viewer/ReplayChartHoverLocation.tsx @@ -20,9 +20,16 @@ const ReplayChartHoverLocation = ({ useFrame(() => { if (sphereRef.current) { if (globalChartsData.hoveredRaceTime !== undefined) { - const curSample = getSampleNearTime(replay, globalChartsData.hoveredRaceTime); + const curSample = getSampleNearTime( + replay, + globalChartsData.hoveredRaceTime, + ); - sphereRef.current.position.set(curSample.position.x, curSample.position.y, curSample.position.z); + sphereRef.current.position.set( + curSample.position.x, + curSample.position.y, + curSample.position.z, + ); sphereRef.current.scale.set(0.5, 0.5, 0.5); } else { sphereRef.current.scale.lerp(new THREE.Vector3(0, 0, 0), 0.1); @@ -30,13 +37,15 @@ const ReplayChartHoverLocation = ({ } }); - return globalChartsData.hoveredRaceTime === undefined - ? ( - - - - ) - : null; + return globalChartsData.hoveredRaceTime === undefined ? ( + + + + ) : null; }; export default ReplayChartHoverLocation; diff --git a/app/components/viewer/ReplayDnf.tsx b/app/components/viewer/ReplayDnf.tsx index 707fc0f8..d0176bf0 100644 --- a/app/components/viewer/ReplayDnf.tsx +++ b/app/components/viewer/ReplayDnf.tsx @@ -5,14 +5,18 @@ import { DoubleSide } from 'three'; import { ReplayData } from '../../lib/api/requests/replays'; interface ReplayDnfProps { - replay: ReplayData; + replay: ReplayData; } const ReplayDnf = ({ replay }: ReplayDnfProps): JSX.Element => { const mesh = useRef(); const dnfTextColor = new THREE.Color(1, 1, 1); return ( <> - + { opacity={0.5} /> - + { anchorX="center" anchorY="middle" > - + DNF diff --git a/app/components/viewer/ReplayGears.tsx b/app/components/viewer/ReplayGears.tsx index b589ae85..f61ac479 100644 --- a/app/components/viewer/ReplayGears.tsx +++ b/app/components/viewer/ReplayGears.tsx @@ -14,8 +14,15 @@ const GearIndicator = ({ gearChange }: GearIndicatorProps) => { const color = getColorFromMap(gearChange.engineCurGear, COLOR_MAP_GEARS); return ( - - + + ); }; @@ -32,7 +39,6 @@ const GearText = ({ gearChange }: GearTextProps) => { gearChange.sample.position, new THREE.Vector3(0, 5, 0), )} - args={[0, 0]} > { anchorX="center" anchorY="middle" > - + {gearChange.engineCurGear} @@ -82,7 +92,8 @@ const ReplayGears = ({ replay }: ReplayGearsProps): JSX.Element => { changes.push({ sample: curSample, engineCurGear: curSample.engineCurGear, - gearUp: curSample.engineCurGear > prevSample.engineCurGear, + gearUp: + curSample.engineCurGear > prevSample.engineCurGear, }); } } diff --git a/app/components/viewer/ReplayLines.tsx b/app/components/viewer/ReplayLines.tsx index d6a248fb..351b13fa 100644 --- a/app/components/viewer/ReplayLines.tsx +++ b/app/components/viewer/ReplayLines.tsx @@ -1,6 +1,4 @@ -import React, { - useCallback, useEffect, useMemo, useRef, -} from 'react'; +import React, { useCallback, useEffect, useMemo, useRef } from 'react'; import * as THREE from 'three'; import { ReplayData } from '../../lib/api/requests/replays'; import useUpdateReplayLineTrail from '../../lib/hooks/viewer/replayLines/useUpdateReplayLineTrail'; @@ -28,7 +26,10 @@ export interface LineType { export const LineTypes: { [name: string]: LineType } = { default: { name: 'Default', colorsCallback: defaultReplayColors }, speed: { name: 'Speed', colorsCallback: speedReplayColors }, - acceleration: { name: 'Acceleration', colorsCallback: accelerationReplayColors }, + acceleration: { + name: 'Acceleration', + colorsCallback: accelerationReplayColors, + }, gear: { name: 'Gear', colorsCallback: gearReplayColors }, rpm: { name: 'RPM', colorsCallback: rpmReplayColors }, inputs: { name: 'Inputs', colorsCallback: inputReplayColors }, @@ -40,10 +41,15 @@ interface ReplayLineProps { replayLineOpacity: number; } const ReplayLine = ({ - replay, lineType, replayLineOpacity, + replay, + lineType, + replayLineOpacity, }: ReplayLineProps) => { const bufferGeom = useRef(); - const points = useMemo(() => replay.samples.map((sample) => sample.position), [replay.samples]); + const points = useMemo( + () => replay.samples.map((sample) => sample.position), + [replay.samples], + ); const colorBuffer = useMemo(() => { const colors = lineType.colorsCallback(replay); @@ -55,7 +61,7 @@ const ReplayLine = ({ }, [replay, replay.color, lineType]); const onUpdate = useCallback( - (self) => { + (self: THREE.BufferGeometry) => { self.setFromPoints(points); self.setAttribute('color', colorBuffer); }, @@ -63,7 +69,11 @@ const ReplayLine = ({ ); // Update the replay line trail based on trail settings - const { manualLineTrailUpdate } = useUpdateReplayLineTrail(bufferGeom, replay, TRAIL_FADE_SEGMENT_TIME); + const { manualLineTrailUpdate } = useUpdateReplayLineTrail( + bufferGeom, + replay, + TRAIL_FADE_SEGMENT_TIME, + ); useEffect(() => { if (!bufferGeom.current) return; @@ -114,11 +124,19 @@ export const ReplayLines = ({ replay={replay} /> {showGearChanges && ( - - )} - {(replay.dnfPos.x !== 0 && replay.dnfPos.y !== 0 && replay.dnfPos.z !== 0) && ( - + )} + {replay.dnfPos.x !== 0 && + replay.dnfPos.y !== 0 && + replay.dnfPos.z !== 0 && ( + + )} {/* Removed until fully implemented: */} {/* diff --git a/app/components/viewer/SceneDirectionalLight.tsx b/app/components/viewer/SceneDirectionalLight.tsx index 566fdfc1..30ce60fe 100644 --- a/app/components/viewer/SceneDirectionalLight.tsx +++ b/app/components/viewer/SceneDirectionalLight.tsx @@ -1,15 +1,16 @@ import React, { useCallback, useEffect, useRef } from 'react'; -import { - Color, DirectionalLight, Group, Vector3, -} from 'three'; +import { Color, DirectionalLight, Group, Vector3 } from 'three'; import { Sphere } from '@react-three/drei'; import { ReplayData } from '../../lib/api/requests/replays'; interface SceneDirectionalLightProps { replays: ReplayData[]; - showDebugLocation?: boolean + showDebugLocation?: boolean; } -const SceneDirectionalLight = ({ replays, showDebugLocation }: SceneDirectionalLightProps) => { +const SceneDirectionalLight = ({ + replays, + showDebugLocation, +}: SceneDirectionalLightProps) => { const ref = useRef(); const targetRef = useRef(); @@ -79,7 +80,10 @@ const SceneDirectionalLight = ({ replays, showDebugLocation }: SceneDirectionalL {/* Debug Location */} {showDebugLocation && ( - + )} @@ -88,7 +92,10 @@ const SceneDirectionalLight = ({ replays, showDebugLocation }: SceneDirectionalL {showDebugLocation && ( - + )} diff --git a/app/components/viewer/Viewer3D.tsx b/app/components/viewer/Viewer3D.tsx index b8019ad5..c486a519 100644 --- a/app/components/viewer/Viewer3D.tsx +++ b/app/components/viewer/Viewer3D.tsx @@ -1,5 +1,9 @@ import React, { - Suspense, useContext, useEffect, useRef, useState, + Suspense, + useContext, + useEffect, + useRef, + useState, } from 'react'; import * as THREE from 'three'; import { Canvas } from '@react-three/fiber'; @@ -37,11 +41,15 @@ const Viewer3D = ({ replaysData }: Props): JSX.Element => { if (!orbitControlsRef.current) return; if (prevReplaysData.current) { - if (prevReplaysData.current.length === 0 && replaysData.length > 0) { + if ( + prevReplaysData.current.length === 0 && + replaysData.length > 0 + ) { // If previous replay data was empty and current one isn't, meaning first replay selected, // set target to first sample of the first replay if (replaysData[0].samples.length > 0) { - orbitControlsRef.current.target = replaysData[0].samples[0].position.clone(); + orbitControlsRef.current.target = + replaysData[0].samples[0].position.clone(); } } } @@ -51,7 +59,10 @@ const Viewer3D = ({ replaysData }: Props): JSX.Element => { }, [replaysData, orbitControlsRef]); return ( -
+
{ shadows > - + @@ -73,7 +89,10 @@ const Viewer3D = ({ replaysData }: Props): JSX.Element => { target={DEFAULT_GRID_POS} /> - + { {showFPS && } - +
); }; diff --git a/app/components/viewer/timeline/TimeLine.tsx b/app/components/viewer/timeline/TimeLine.tsx index 1c02c37e..6851ba84 100644 --- a/app/components/viewer/timeline/TimeLine.tsx +++ b/app/components/viewer/timeline/TimeLine.tsx @@ -1,8 +1,6 @@ import { useState } from 'react'; import { Slider } from 'antd'; -import { - CaretRightOutlined, PauseOutlined, -} from '@ant-design/icons'; +import { CaretRightOutlined, PauseOutlined } from '@ant-design/icons'; import { ReplayData } from '../../../lib/api/requests/replays'; import { getRaceTimeStr } from '../../../lib/utils/time'; import GlobalTimeLineInfos from '../../../lib/singletons/timeLineInfos'; @@ -33,7 +31,12 @@ const TimeLineView = ({ replaysData }: TimeLineViewProps) => { timeLineGlobal.currentRaceTime = timeLineTime; if (timeLineGlobal.followedReplay !== null) { - if (!replaysData.some((replay: ReplayData) => replay._id === timeLineGlobal.followedReplay?._id)) { + if ( + !replaysData.some( + (replay: ReplayData) => + replay._id === timeLineGlobal.followedReplay?._id, + ) + ) { timeLineGlobal.followedReplay = undefined; } } @@ -50,8 +53,12 @@ const TimeLineView = ({ replaysData }: TimeLineViewProps) => { } replaysData.forEach((replay) => { - if (replay.samples[replay.samples.length - 1].currentRaceTime > timeLineGlobal.maxRaceTime) { - timeLineGlobal.maxRaceTime = replay.samples[replay.samples.length - 1].currentRaceTime; + if ( + replay.samples[replay.samples.length - 1].currentRaceTime > + timeLineGlobal.maxRaceTime + ) { + timeLineGlobal.maxRaceTime = + replay.samples[replay.samples.length - 1].currentRaceTime; } }); @@ -83,7 +90,8 @@ const TimeLineView = ({ replaysData }: TimeLineViewProps) => { const intervalCallback = () => { const raceTimeIncrement = timeLineGlobal.tickTime * speed; - const nextRaceTime = timeLineGlobal.currentRaceTime + raceTimeIncrement; + const nextRaceTime = + timeLineGlobal.currentRaceTime + raceTimeIncrement; if (nextRaceTime > timeLineGlobal.maxRaceTime || nextRaceTime < 0) { // Loop time back to 0 if time is past the max // and ensure time stays at least 0 @@ -93,7 +101,10 @@ const TimeLineView = ({ replaysData }: TimeLineViewProps) => { } }; - playInterval = setTimeout(() => startSteadyLoop(intervalCallback), timeLineGlobal.tickTime); + playInterval = setTimeout( + () => startSteadyLoop(intervalCallback), + timeLineGlobal.tickTime, + ); }; const onTogglePlay = (shouldPlay: boolean = !playing) => { @@ -116,7 +127,8 @@ const TimeLineView = ({ replaysData }: TimeLineViewProps) => { } }; - const timeFormat = (v: number | undefined) => (v !== undefined ? `${getRaceTimeStr(v)}` : ''); + const timeFormat = (v: number | undefined) => + v !== undefined ? `${getRaceTimeStr(v)}` : ''; return (
{ />
-
+
{timeFormat(timeLineTime)}
@@ -147,19 +157,14 @@ const TimeLineView = ({ replaysData }: TimeLineViewProps) => { role="button" tabIndex={0} > - {playing - ? - : } + {playing ? : }
{`Speed: ${timelineSpeed.toFixed(2)}x`}
-
- {MIN_SPEED} - x -
+
{MIN_SPEED}x
{ tooltipVisible={false} />
-
- {MAX_SPEED} - x -
+
{MAX_SPEED}x
@@ -191,11 +193,12 @@ interface TimeLineProps { replaysData: ReplayData[]; } -const TimeLine = ({ - replaysData, -}: TimeLineProps): JSX.Element => ( +const TimeLine = ({ replaysData }: TimeLineProps): JSX.Element => ( <> - + ); diff --git a/app/components/viewer/timeline/TimelineSlider.tsx b/app/components/viewer/timeline/TimelineSlider.tsx index ae8cb5dc..282d2df1 100644 --- a/app/components/viewer/timeline/TimelineSlider.tsx +++ b/app/components/viewer/timeline/TimelineSlider.tsx @@ -5,9 +5,7 @@ interface SliderProps { onChange: (value: number) => void; yDragMargin?: number; } -const TimelineSlider = ({ - onChange, yDragMargin, -}: SliderProps) => { +const TimelineSlider = ({ onChange, yDragMargin }: SliderProps) => { const ref = useRef(null); const timeLineGlobal = GlobalTimeLineInfos.getInstance(); @@ -32,14 +30,16 @@ const TimelineSlider = ({ if (ref.current) { const { clientX, clientY } = e; - const { - x, y, width, height, - } = ref.current.getBoundingClientRect(); + const { x, y, width, height } = ref.current.getBoundingClientRect(); const dragMargin = yDragMargin || 0; - if (clientX >= x && clientX <= x + width - && clientY >= y - dragMargin && clientY <= y + height + dragMargin) { + if ( + clientX >= x && + clientX <= x + width && + clientY >= y - dragMargin && + clientY <= y + height + dragMargin + ) { isDraggingSlider = true; updateValueUsingMousePos(clientX); } @@ -88,7 +88,10 @@ const TimelineSlider = ({ className="h-full" style={{ backgroundColor: '#007CD6', - width: `${mapValueToPercent(timeLineGlobal.currentRaceTime) * 100.0}%`, + width: `${ + mapValueToPercent(timeLineGlobal.currentRaceTime) * + 100.0 + }%`, }} /> diff --git a/app/lib/charts/chartData.ts b/app/lib/charts/chartData.ts index e4b101f6..be0debd7 100644 --- a/app/lib/charts/chartData.ts +++ b/app/lib/charts/chartData.ts @@ -35,8 +35,7 @@ export const metricChartData = ( allRaceTimes.forEach((raceTime: number) => { for (let i = 0; i < replay.samples.length; i++) { lastSample = replay.samples[i]; - if (lastSample.currentRaceTime === raceTime - || lastSample.currentRaceTime > raceTime) { + if (lastSample.currentRaceTime === raceTime || lastSample.currentRaceTime > raceTime) { chartData.data.push([raceTime, chartDataInfo.dataCallback(lastSample)]); break; } diff --git a/app/lib/charts/chartOptions.ts b/app/lib/charts/chartOptions.ts index 30ce470f..b4773d4e 100644 --- a/app/lib/charts/chartOptions.ts +++ b/app/lib/charts/chartOptions.ts @@ -98,8 +98,7 @@ export const chartOptionsTemplate = (): Highcharts.Options => { shared: true, formatter() { return [`${getRaceTimeStr(this.x)}
`].concat( - this.points - ? this.points.map((point) => ` + this.points ? this.points.map((point) => ` ${point.series.name}: ${point.y.toFixed(3)}
`) : [], ); diff --git a/app/lib/contexts/AuthContext.tsx b/app/lib/contexts/AuthContext.tsx index 2fd2af58..81e01ffa 100644 --- a/app/lib/contexts/AuthContext.tsx +++ b/app/lib/contexts/AuthContext.tsx @@ -1,26 +1,24 @@ import { useRouter } from 'next/router'; -import React, { - createContext, useCallback, useEffect, useState, -} from 'react'; +import React, { createContext, useCallback, useEffect, useState } from 'react'; import API from '../api/apiWrapper'; import { AuthUserInfo } from '../api/requests/auth'; import { generateAuthUrl } from '../utils/auth'; import openAuthWindow from '../utils/authPopup'; export interface AuthContextProps { - user?: AuthUserInfo, - setUser: (user?: AuthUserInfo) => void, - loginUser: (code: string, state?: string) => Promise, - logoutUser: () => Promise - startAuthFlow: () => void + user?: AuthUserInfo; + setUser: (user?: AuthUserInfo) => void; + loginUser: (code: string, state?: string) => Promise; + logoutUser: () => Promise; + startAuthFlow: () => void; } export const AuthContext = createContext({ user: undefined, - setUser: (user?: AuthUserInfo) => { }, - loginUser: async (code: string, state?: string) => { }, - logoutUser: async () => { }, - startAuthFlow: () => { }, + setUser: (user?: AuthUserInfo) => {}, + loginUser: async (code: string, state?: string) => {}, + logoutUser: async () => {}, + startAuthFlow: () => {}, }); export const AuthProvider = ({ children }: any): JSX.Element => { @@ -71,14 +69,20 @@ export const AuthProvider = ({ children }: any): JSX.Element => { if (code === undefined || code === null || typeof code !== 'string') { return; } - if (state === undefined || state === null || typeof state !== 'string') { + if ( + state === undefined || + state === null || + typeof state !== 'string' + ) { return; } const storedState = localStorage.getItem('state'); localStorage.removeItem('state'); if (storedState !== state) { - console.log(`Stored state (${storedState}) did not match incoming state (${state})`); + console.log( + `Stored state (${storedState}) did not match incoming state (${state})`, + ); return; } @@ -88,7 +92,10 @@ export const AuthProvider = ({ children }: any): JSX.Element => { // helper function to make login callable from outside the Context const loginUser = async (code: string, state?: string) => { try { - const userInfo = await API.auth.authorizeWithAccessCode(code, state); + const userInfo = await API.auth.authorizeWithAccessCode( + code, + state, + ); setUser(userInfo); } catch (e) { console.log(e); diff --git a/app/lib/popups/performanceWarning.tsx b/app/lib/popups/performanceWarning.tsx index eeb9d368..cbe4584e 100644 --- a/app/lib/popups/performanceWarning.tsx +++ b/app/lib/popups/performanceWarning.tsx @@ -7,7 +7,8 @@ const STOP_SHOWING_PERFORMANCE_WARNING_KEY = 'stopShowingPerformanceWarning'; const showPerformanceWarning = () => { // Don't show the warning if the user has already dismissed it - const stopShowingPerformanceWarning = localStorage.getItem(STOP_SHOWING_PERFORMANCE_WARNING_KEY) !== null; + const stopShowingPerformanceWarning = + localStorage.getItem(STOP_SHOWING_PERFORMANCE_WARNING_KEY) !== null; if (stopShowingPerformanceWarning) return; // Assign key to notification so we can close it later @@ -17,13 +18,17 @@ const showPerformanceWarning = () => { notification.warning({ key, message: 'Potential performance issues', - description: 'Based on your detected hardware, you may get lower framerates in the 3D viewer. ' - + 'If you experience issues, try using a different device.', + description: + 'Based on your detected hardware, you may get lower framerates in the 3D viewer. ' + + 'If you experience issues, try using a different device.', btn: (