You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

167 lines
4.0 KiB

import React, {createContext, useEffect, useState} from "react";
import {
connectWorkout,
createNewWorkout,
fetchActiveWorkouts, fetchBikes, fetchPrograms,
openWebsocket, pauseWorkout,
startWorkout,
stopWorkout
} from "../hooks/net";
import useMilestones from "../hooks/milestones";
export const StatusContext = createContext({
bike: null,
program: null,
bikes: null,
programs: null,
workout: null,
workoutStatus: null,
setBike: null,
setProgram: null,
state: null,
milestones: [],
create: () => null,
resume: () => null,
start: () => null,
pause: () => null,
stop: () => null,
});
export const StatusContextProvider = ({children}) => {
const [bike, setBike] = useState(null);
const [program, setProgram] = useState(null);
const [bikes, setBikes] = useState(null);
const [programs, setPrograms] = useState(null);
const [workout, setWorkout] = useState(null);
const [workoutStatus, setWorkoutStatus] = useState(null);
const [state, setState] = useState("offline");
const {milestones, prevDiff, prevLongDiff, msDispatch} = useMilestones();
const [socket, setSocket] = useState(null);
useEffect(() => {
if (programs === null) {
fetchPrograms().then(newPrograms => setPrograms(newPrograms));
}
}, [programs]);
useEffect(() => {
if (bikes === null) {
fetchBikes().then(newBikes => {
setBikes(newBikes);
if (newBikes.length === 1) {
setBike(newBikes[0]);
}
});
}
}, [bikes]);
useEffect(() => {
if (bike === null && program === null && workout === null) {
resume();
}
}, [bike, program, workout]);
useEffect(() => {
if (bikes === null || programs === null) {
setState("loading");
} else if (workout !== null) {
setState(workout.state || "unknown");
} else if (bike === null) {
setState("bike");
} else if (program === null) {
setState("program");
}
}, [bike, program, workout, bikes, programs]);
useEffect(() => {
if (socket === null) {
return;
}
if (workout === null) {
socket.close();
setSocket(null);
return;
}
socket.onmessage = ({data}) => {
onSocketMessage(workout, program, JSON.parse(data));
};
return () => {
socket.onmessage = null;
}
}, [socket, workout, program]);
function onSocketMessage(myWorkout, program, body) {
if (typeof body.workout !== "undefined") {
setWorkout({...body.workout, ...myWorkout});
}
if (typeof body.workoutStatusBackfill !== "undefined") {
body.workoutStatusBackfill.forEach(wsbf => {
setWorkoutStatus(wsbf);
msDispatch({type: "measure", payload: {...wsbf, program}});
});
}
if (typeof body.workoutStatus !== "undefined") {
setWorkoutStatus(body.workoutStatus);
msDispatch({type: "measure", payload: {...body.workoutStatus, program}});
}
}
async function create(myProgram = null) {
setWorkoutStatus(null);
let newWorkout = await createNewWorkout(bike, myProgram || program);
setWorkout(newWorkout);
setWorkout(await connectWorkout(newWorkout));
setSocket(openWebsocket(newWorkout));
}
async function resume() {
const activeWorkouts = await fetchActiveWorkouts();
const count = activeWorkouts.length;
const last = count > 0 ? activeWorkouts[count - 1] : null;
if (last !== null) {
setProgram(last.program);
setWorkout(last);
setBike(last.bike);
setSocket(openWebsocket(last));
}
}
async function start() {
setWorkout(await startWorkout(workout));
}
async function pause() {
setWorkout(await pauseWorkout(workout));
}
async function stop() {
await stopWorkout(workout);
setBike(null);
setProgram(null);
setWorkout(null);
msDispatch({type: "clear"});
}
return (
<StatusContext.Provider value={{
bike, program, workout, workoutStatus, state, milestones,
setBike, setProgram,
create, resume, start, pause, stop,
programs, bikes,
}}>
{children}
</StatusContext.Provider>
)
};