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

5 years ago
  1. import React, {createContext, useEffect, useState} from "react";
  2. import {
  3. connectWorkout,
  4. createNewWorkout,
  5. fetchActiveWorkouts, fetchBikes, fetchPrograms,
  6. openWebsocket, pauseWorkout,
  7. startWorkout,
  8. stopWorkout
  9. } from "../hooks/net";
  10. import useMilestones from "../hooks/milestones";
  11. export const StatusContext = createContext({
  12. bike: null,
  13. program: null,
  14. bikes: null,
  15. programs: null,
  16. workout: null,
  17. workoutStatus: null,
  18. setBike: null,
  19. setProgram: null,
  20. state: null,
  21. milestones: [],
  22. create: () => null,
  23. resume: () => null,
  24. start: () => null,
  25. pause: () => null,
  26. stop: () => null,
  27. });
  28. export const StatusContextProvider = ({children}) => {
  29. const [bike, setBike] = useState(null);
  30. const [program, setProgram] = useState(null);
  31. const [bikes, setBikes] = useState(null);
  32. const [programs, setPrograms] = useState(null);
  33. const [workout, setWorkout] = useState(null);
  34. const [workoutStatus, setWorkoutStatus] = useState(null);
  35. const [state, setState] = useState("offline");
  36. const {milestones, prevDiff, prevLongDiff, msDispatch} = useMilestones();
  37. const [socket, setSocket] = useState(null);
  38. useEffect(() => {
  39. if (programs === null) {
  40. fetchPrograms().then(newPrograms => setPrograms(newPrograms));
  41. }
  42. }, [programs]);
  43. useEffect(() => {
  44. if (bikes === null) {
  45. fetchBikes().then(newBikes => {
  46. setBikes(newBikes);
  47. if (newBikes.length === 1) {
  48. setBike(newBikes[0]);
  49. }
  50. });
  51. }
  52. }, [bikes]);
  53. useEffect(() => {
  54. if (bike === null && program === null && workout === null) {
  55. resume();
  56. }
  57. }, [bike, program, workout]);
  58. useEffect(() => {
  59. if (bikes === null || programs === null) {
  60. setState("loading");
  61. } else if (workout !== null) {
  62. setState(workout.state || "unknown");
  63. } else if (bike === null) {
  64. setState("bike");
  65. } else if (program === null) {
  66. setState("program");
  67. }
  68. }, [bike, program, workout, bikes, programs]);
  69. useEffect(() => {
  70. if (socket === null) {
  71. return;
  72. }
  73. if (workout === null) {
  74. socket.close();
  75. setSocket(null);
  76. return;
  77. }
  78. socket.onmessage = ({data}) => {
  79. onSocketMessage(workout, program, JSON.parse(data));
  80. };
  81. return () => {
  82. socket.onmessage = null;
  83. }
  84. }, [socket, workout, program]);
  85. function onSocketMessage(myWorkout, program, body) {
  86. if (typeof body.workout !== "undefined") {
  87. setWorkout({...body.workout, ...myWorkout});
  88. }
  89. if (typeof body.workoutStatusBackfill !== "undefined") {
  90. body.workoutStatusBackfill.forEach(wsbf => {
  91. setWorkoutStatus(wsbf);
  92. msDispatch({type: "measure", payload: {...wsbf, program}});
  93. });
  94. }
  95. if (typeof body.workoutStatus !== "undefined") {
  96. setWorkoutStatus(body.workoutStatus);
  97. msDispatch({type: "measure", payload: {...body.workoutStatus, program}});
  98. }
  99. }
  100. async function create(myProgram = null) {
  101. setWorkoutStatus(null);
  102. let newWorkout = await createNewWorkout(bike, myProgram || program);
  103. setWorkout(newWorkout);
  104. setWorkout(await connectWorkout(newWorkout));
  105. setSocket(openWebsocket(newWorkout));
  106. }
  107. async function resume() {
  108. const activeWorkouts = await fetchActiveWorkouts();
  109. const count = activeWorkouts.length;
  110. const last = count > 0 ? activeWorkouts[count - 1] : null;
  111. if (last !== null) {
  112. setProgram(last.program);
  113. setWorkout(last);
  114. setBike(last.bike);
  115. setSocket(openWebsocket(last));
  116. }
  117. }
  118. async function start() {
  119. setWorkout(await startWorkout(workout));
  120. }
  121. async function pause() {
  122. setWorkout(await pauseWorkout(workout));
  123. }
  124. async function stop() {
  125. await stopWorkout(workout);
  126. setBike(null);
  127. setProgram(null);
  128. setWorkout(null);
  129. msDispatch({type: "clear"});
  130. }
  131. return (
  132. <StatusContext.Provider value={{
  133. bike, program, workout, workoutStatus, state, milestones,
  134. setBike, setProgram,
  135. create, resume, start, pause, stop,
  136. programs, bikes,
  137. }}>
  138. {children}
  139. </StatusContext.Provider>
  140. )
  141. };