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); const [hidden, setHidden] = useState(false); 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}) => { const body = JSON.parse(data); if (typeof body.workout !== "undefined") { setWorkout({...body.workout, ...workout}); } 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}}); } }; return () => { socket.onmessage = null; } }, [socket, workout, program, msDispatch]); 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 activeAndConnected = activeWorkouts.filter(w => w.state !== "disconnected"); const count = activeAndConnected.length; const last = count > 0 ? activeAndConnected[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 ( {children} ) };