From 7ed13f49af579b99694e796d6a9e1d733c571a0d Mon Sep 17 00:00:00 2001 From: Stian Fredrik Aune Date: Thu, 1 Dec 2022 23:31:05 +0100 Subject: [PATCH] KPM --- webui-react/src/hooks/kpm.ts | 52 ++++++++++++++++++++++++ webui-react/src/pages/PlayPage.tsx | 3 ++ webui-react/src/primitives/misc/Misc.tsx | 6 ++- 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 webui-react/src/hooks/kpm.ts diff --git a/webui-react/src/hooks/kpm.ts b/webui-react/src/hooks/kpm.ts new file mode 100644 index 0000000..80d386f --- /dev/null +++ b/webui-react/src/hooks/kpm.ts @@ -0,0 +1,52 @@ +import {useContext, useEffect, useReducer} from "react"; +import RuntimeContext from "../contexts/RuntimeContext"; +import {Values} from "../models/Shared"; +import {WorkoutState} from "../models/Workouts"; + +interface UseKpmReducerState { + lastStates: WorkoutState[] + kpm: number +} + +export function useKpm() { + const {lastEvent} = useContext(RuntimeContext); + + const [state, dispatch] = useReducer((state: UseKpmReducerState, newState: WorkoutState) => { + if (newState.time === 0) { + return { + lastStates: [], + kpm: 0, + }; + } + + const lastSeconds = Math.max(0, ...state.lastStates.map(s => s.time)); + if (newState.time > lastSeconds) { + const sixtySecondsAgo = Math.max(0, newState.time - 60); + const inRange = state.lastStates.filter(s => s.time >= sixtySecondsAgo); + const first = inRange[0] || { time: 0, calories: 0 }; + const duration = newState.time - first.time; + + return { + lastStates: [...inRange, newState], + kpm: inRange.length > 30 + ? Math.round(((newState.calories || 0) - (first.calories || 0)) * 60 / duration) + : 0, + } + } + + return state; + }, { + lastStates: [], + kpm: 0, + }); + + useEffect(() => { + if (lastEvent?.workoutStates) { + for (const state of lastEvent.workoutStates) { + dispatch(state); + } + } + }, [lastEvent]); + + return state.kpm; +} diff --git a/webui-react/src/pages/PlayPage.tsx b/webui-react/src/pages/PlayPage.tsx index a5cec2c..044826c 100644 --- a/webui-react/src/pages/PlayPage.tsx +++ b/webui-react/src/pages/PlayPage.tsx @@ -19,6 +19,7 @@ import {ControlsBoi} from "./runtime/ControlsBoi"; import MessageBoi from "./runtime/MessageBoi"; import ProgramBoi from "./runtime/ProgramBoi"; import MilestoneBoi from "./runtime/MilestoneBoi"; +import {useKpm} from "../hooks/kpm"; function PlayPage(): JSX.Element { const {active, ready, ended, workout, reset, resume} = useContext(RuntimeContext); @@ -176,6 +177,7 @@ function CreatePlayPage(): JSX.Element { function RunPlayPage(): JSX.Element { const {workout} = useContext(RuntimeContext); const lastState = useLastState(); + const kpm = useKpm(); if (!workout || workout.status === WorkoutStatus.Created) { return ; @@ -193,6 +195,7 @@ function RunPlayPage(): JSX.Element { + {kpm > 0 && } )} diff --git a/webui-react/src/primitives/misc/Misc.tsx b/webui-react/src/primitives/misc/Misc.tsx index b16dbd2..4b68d0f 100644 --- a/webui-react/src/primitives/misc/Misc.tsx +++ b/webui-react/src/primitives/misc/Misc.tsx @@ -11,7 +11,7 @@ export function TitleLine({children}: WithChildren) { interface ValueProps { raw: Values | number - valueKey: keyof Values + valueKey: keyof Values | "kpm" } export function FluffyValue({raw, valueKey}: ValueProps): JSX.Element | null { @@ -61,6 +61,10 @@ export function Value({raw, valueKey}: ValueProps): JSX.Element | null { return <>{actual} rpm } + if (valueKey === "kpm") { + return <>{actual} kpm + } + if (valueKey === "pulse") { return ( <>