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.

169 lines
4.2 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
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. const [hidden, setHidden] = useState(false);
  39. useEffect(() => {
  40. if (programs === null) {
  41. fetchPrograms().then(newPrograms => setPrograms(newPrograms));
  42. }
  43. }, [programs]);
  44. useEffect(() => {
  45. if (bikes === null) {
  46. fetchBikes().then(newBikes => {
  47. setBikes(newBikes);
  48. if (newBikes.length === 1) {
  49. setBike(newBikes[0]);
  50. }
  51. });
  52. }
  53. }, [bikes]);
  54. useEffect(() => {
  55. if (bike === null && program === null && workout === null) {
  56. resume();
  57. }
  58. }, [bike, program, workout]);
  59. useEffect(() => {
  60. if (bikes === null || programs === null) {
  61. setState("loading");
  62. } else if (workout !== null) {
  63. setState(workout.state || "unknown");
  64. } else if (bike === null) {
  65. setState("bike");
  66. } else if (program === null) {
  67. setState("program");
  68. }
  69. }, [bike, program, workout, bikes, programs]);
  70. useEffect(() => {
  71. if (socket === null) {
  72. return;
  73. }
  74. if (workout === null) {
  75. socket.close();
  76. setSocket(null);
  77. return;
  78. }
  79. socket.onmessage = ({data}) => {
  80. const body = JSON.parse(data);
  81. if (typeof body.workout !== "undefined") {
  82. setWorkout({...body.workout, ...workout});
  83. }
  84. if (typeof body.workoutStatusBackfill !== "undefined") {
  85. body.workoutStatusBackfill.forEach(wsbf => {
  86. setWorkoutStatus(wsbf);
  87. msDispatch({type: "measure", payload: {...wsbf, program}});
  88. });
  89. }
  90. if (typeof body.workoutStatus !== "undefined") {
  91. setWorkoutStatus(body.workoutStatus);
  92. msDispatch({type: "measure", payload: {...body.workoutStatus, program}});
  93. }
  94. };
  95. return () => {
  96. socket.onmessage = null;
  97. }
  98. }, [socket, workout, program, msDispatch]);
  99. async function create(myProgram = null) {
  100. setWorkoutStatus(null);
  101. let newWorkout = await createNewWorkout(bike, myProgram || program);
  102. setWorkout(newWorkout);
  103. setWorkout(await connectWorkout(newWorkout));
  104. setSocket(openWebsocket(newWorkout));
  105. }
  106. async function resume() {
  107. const activeWorkouts = await fetchActiveWorkouts();
  108. const activeAndConnected = activeWorkouts.filter(w => w.state !== "disconnected");
  109. const count = activeAndConnected.length;
  110. const last = count > 0 ? activeAndConnected[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. prevDiff, prevLongDiff,
  138. hidden, setHidden,
  139. }}>
  140. {children}
  141. </StatusContext.Provider>
  142. )
  143. };