useSession.jsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. import React, { useContext } from "react";
  2. import { useSetRecoilState, useRecoilCallback } from "recoil";
  3. import { updateSession, getSession, getGame } from "../utils/api";
  4. import SubscribeSessionEvents from "../components/SubscribeSessionEvents";
  5. import { useItems } from "../components/board/Items";
  6. import {
  7. AvailableItemListAtom,
  8. AllItemsSelector,
  9. BoardConfigAtom,
  10. } from "../components/board";
  11. import { MessagesAtom, parseMessage } from "../components/message/useMessage";
  12. import useBoardConfig from "../components/useBoardConfig";
  13. import { useC2C } from "react-sync-board";
  14. export const SessionContext = React.createContext({});
  15. const emtpyBoard = {
  16. items: [],
  17. availableItems: [],
  18. board: {
  19. size: 1000,
  20. scale: 1,
  21. translations: [
  22. {
  23. language: "fr",
  24. name: "Choississez un jeu",
  25. description: "...",
  26. },
  27. ],
  28. defaultName: "Choose a game",
  29. defaultLanguage: "en",
  30. defaultDescription: "...",
  31. gridSize: 1,
  32. },
  33. };
  34. export const SessionProvider = ({ sessionId, fromGameId, children }) => {
  35. const { c2c } = useC2C("board");
  36. const { setItemList } = useItems();
  37. const setAvailableItemList = useSetRecoilState(AvailableItemListAtom);
  38. const [, setBoardConfig] = useBoardConfig();
  39. const setMessages = useSetRecoilState(MessagesAtom);
  40. const [sessionLoaded, setSessionLoaded] = React.useState(false);
  41. const [currentGameId, setCurrentGameId] = React.useState(fromGameId);
  42. const loadSession = React.useCallback(async () => {
  43. let sessionData;
  44. // Init session from server
  45. try {
  46. // First from session if exists
  47. sessionData = await getSession(sessionId);
  48. const sessionGameId = sessionData.gameId;
  49. // Update availableItems from original game
  50. if (sessionGameId) {
  51. const { availableItems } = await getGame(sessionGameId);
  52. sessionData.availableItems = availableItems;
  53. setCurrentGameId(sessionGameId);
  54. }
  55. } catch {
  56. if (fromGameId) {
  57. // Then from initial game
  58. sessionData = await getGame(fromGameId);
  59. } else {
  60. // Empty board
  61. sessionData = emtpyBoard;
  62. }
  63. }
  64. return sessionData;
  65. }, [fromGameId, sessionId]);
  66. const setSession = React.useCallback(
  67. async (newData, sync = false) => {
  68. const { availableItems, items, board, messages = [] } = newData;
  69. setAvailableItemList(availableItems);
  70. // The filter prevent the empty item bug on reload
  71. setItemList(items.filter((item) => item));
  72. setBoardConfig(board, false);
  73. setMessages(messages.map((m) => parseMessage(m)));
  74. if (sync) {
  75. // Send loadSession event for other user
  76. c2c.publish("loadSession", newData);
  77. }
  78. setSessionLoaded(true);
  79. },
  80. [c2c, setAvailableItemList, setBoardConfig, setItemList, setMessages]
  81. );
  82. const getCurrentSession = useRecoilCallback(
  83. ({ snapshot }) => async () => {
  84. const availableItemList = await snapshot.getPromise(
  85. AvailableItemListAtom
  86. );
  87. const messages = await snapshot.getPromise(MessagesAtom);
  88. const boardConfig = await snapshot.getPromise(BoardConfigAtom);
  89. const itemList = await snapshot.getPromise(AllItemsSelector);
  90. const currentSession = {
  91. items: itemList,
  92. board: boardConfig,
  93. availableItems: availableItemList,
  94. messages: messages.slice(-50),
  95. timestamp: Date.now(),
  96. gameId: fromGameId,
  97. };
  98. return currentSession;
  99. },
  100. [fromGameId]
  101. );
  102. const changeGame = React.useCallback(
  103. async (newGameId) => {
  104. const newGame = await getGame(newGameId);
  105. const currentSession = getCurrentSession();
  106. setSession({ ...currentSession, ...newGame }, true);
  107. },
  108. [getCurrentSession, setSession]
  109. );
  110. const saveSession = React.useCallback(async () => {
  111. const currentSession = await getCurrentSession();
  112. if (currentSession.items.length) {
  113. try {
  114. return await updateSession(sessionId, currentSession);
  115. } catch (e) {
  116. console.log(e);
  117. }
  118. }
  119. }, [sessionId, getCurrentSession]);
  120. return (
  121. <SessionContext.Provider
  122. value={{
  123. loadSession,
  124. changeGame,
  125. setSession,
  126. getSession: getCurrentSession,
  127. saveSession,
  128. sessionLoaded,
  129. sessionId,
  130. gameId: currentGameId,
  131. }}
  132. >
  133. {children}
  134. <SubscribeSessionEvents
  135. getSession={getCurrentSession}
  136. setSession={setSession}
  137. />
  138. </SessionContext.Provider>
  139. );
  140. };
  141. export const useSession = () => {
  142. return useContext(SessionContext);
  143. };
  144. export default useSession;