useSession.jsx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. import React, { useContext } from "react";
  2. import {
  3. useItemActions,
  4. useMessage,
  5. useBoardConfig,
  6. useWire,
  7. } from "react-sync-board";
  8. import { useTranslation } from "react-i18next";
  9. import SubscribeSessionEvents from "./SubscribeSessionEvents";
  10. import { updateSession, getSession, getGame } from "../utils/api";
  11. import demoEn from "../games/demo_en.json?url";
  12. import demoFr from "../games/demo_fr.json?url";
  13. import demoIt from "../games/demo_it.json?url"
  14. export const SessionContext = React.createContext({});
  15. const demos = {
  16. fr: demoFr,
  17. it: demoIt
  18. };
  19. const emtpyBoard = {
  20. items: [],
  21. availableItems: [],
  22. board: {
  23. translations: [
  24. {
  25. language: "fr",
  26. name: "Choisissez un jeu",
  27. description: "...",
  28. },
  29. {
  30. language: "it",
  31. name: "Scegli un gioco",
  32. description: "...",
  33. },
  34. ],
  35. defaultName: "Choose a game",
  36. defaultLanguage: "en",
  37. defaultDescription: "...",
  38. gridSize: 1,
  39. },
  40. };
  41. export const SessionProvider = ({ sessionId, fromGameId, children }) => {
  42. const { i18n } = useTranslation();
  43. const { setItemList, getItemList } = useItemActions();
  44. const { messages, setMessages } = useMessage();
  45. const [availableItems, setAvailableItems] = React.useState([]);
  46. const [boardConfig, setBoardConfig] = useBoardConfig();
  47. const [sessionLoaded, setSessionLoaded] = React.useState(false);
  48. const [currentGameId, setCurrentGameId] = React.useState(fromGameId);
  49. const { wire } = useWire("board");
  50. const loadSession = React.useCallback(async () => {
  51. let sessionData;
  52. // Init session from server
  53. try {
  54. // First from session if exists
  55. sessionData = await getSession(sessionId);
  56. const sessionGameId = sessionData.gameId;
  57. // Update availableItems from original game
  58. if (sessionGameId) {
  59. const { availableItems } = await getGame(sessionGameId);
  60. sessionData.availableItems = availableItems;
  61. setCurrentGameId(sessionGameId);
  62. }
  63. } catch {
  64. if (fromGameId) {
  65. // Then from initial game
  66. if (fromGameId === "demo") {
  67. const foundLang = i18n.languages.find((lang) => demos[lang]);
  68. if (foundLang) {
  69. sessionData = await (await fetch(demos[foundLang])).json();
  70. } else {
  71. sessionData = await (await fetch(demoEn)).json();
  72. }
  73. } else {
  74. sessionData = await getGame(fromGameId);
  75. }
  76. } else {
  77. // Empty board
  78. sessionData = emtpyBoard;
  79. }
  80. }
  81. return sessionData;
  82. }, [fromGameId, i18n.languages, sessionId]);
  83. const setSession = React.useCallback(
  84. async (newData, sync = false) => {
  85. const { availableItems, items, board, messages = [] } = newData;
  86. setAvailableItems(availableItems);
  87. // The filter prevents the empty item bug or missing type on reload
  88. setItemList(items.filter((item) => item && item.type));
  89. setBoardConfig(board, false);
  90. setMessages(messages);
  91. if (sync) {
  92. // Send loadSession event for other user
  93. wire.publish("loadSession", newData);
  94. }
  95. setSessionLoaded(true);
  96. },
  97. [wire, setBoardConfig, setItemList, setMessages]
  98. );
  99. const getCurrentSession = React.useCallback(async () => {
  100. const currentSession = {
  101. items: await getItemList(),
  102. board: boardConfig,
  103. availableItems: availableItems,
  104. messages: messages.slice(-50),
  105. timestamp: Date.now(),
  106. gameId: fromGameId,
  107. };
  108. return currentSession;
  109. }, [availableItems, boardConfig, fromGameId, getItemList, messages]);
  110. const changeGame = React.useCallback(
  111. async (newGameId) => {
  112. const newGame = await getGame(newGameId);
  113. const currentSession = getCurrentSession();
  114. setSession({ ...currentSession, ...newGame }, true);
  115. },
  116. [getCurrentSession, setSession]
  117. );
  118. const saveSession = React.useCallback(async () => {
  119. const currentSession = await getCurrentSession();
  120. if (currentSession.items.length) {
  121. try {
  122. return await updateSession(sessionId, currentSession);
  123. } catch (e) {
  124. console.log(e);
  125. }
  126. }
  127. }, [getCurrentSession, sessionId]);
  128. return (
  129. <SessionContext.Provider
  130. value={{
  131. loadSession,
  132. changeGame,
  133. setSession,
  134. getSession: getCurrentSession,
  135. saveSession,
  136. sessionLoaded,
  137. sessionId,
  138. gameId: currentGameId,
  139. availableItems,
  140. boardConfig,
  141. messages,
  142. }}
  143. >
  144. {children}
  145. <SubscribeSessionEvents
  146. getSession={getCurrentSession}
  147. setSession={setSession}
  148. />
  149. </SessionContext.Provider>
  150. );
  151. };
  152. export const useSession = () => {
  153. return useContext(SessionContext);
  154. };
  155. export default useSession;