useGame.jsx 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. import React, { useContext } from "react";
  2. import { useSetRecoilState, useRecoilCallback } from "recoil";
  3. import { nanoid } from "nanoid";
  4. import { getGame } from "../utils/api";
  5. import SubscribeGameEvents from "../components/SubscribeGameEvents";
  6. import { useItems } from "../components/Board/Items";
  7. import {
  8. AvailableItemListAtom,
  9. AllItemsSelector,
  10. BoardConfigAtom,
  11. } from "../components/Board";
  12. import useBoardConfig from "../components/useBoardConfig";
  13. export const GameContext = React.createContext({});
  14. export const GameProvider = ({ gameId, game, children }) => {
  15. const { setItemList } = useItems();
  16. const setAvailableItemList = useSetRecoilState(AvailableItemListAtom);
  17. const [, setBoardConfig] = useBoardConfig();
  18. const [gameLoaded, setGameLoaded] = React.useState(false);
  19. const setGame = React.useCallback(
  20. async (newGame) => {
  21. try {
  22. const originalGame = await getGame(gameId);
  23. setAvailableItemList(
  24. originalGame.availableItems.map((item) => ({
  25. ...item,
  26. id: nanoid(),
  27. }))
  28. );
  29. } catch {
  30. setAvailableItemList(
  31. newGame.availableItems.map((item) => ({ ...item, id: nanoid() }))
  32. );
  33. }
  34. setItemList(newGame.items.filter((item) => item)); // The filter avoid the empty item bug on reload
  35. setBoardConfig(newGame.board, false);
  36. setGameLoaded(true);
  37. },
  38. [setAvailableItemList, setBoardConfig, setItemList, gameId]
  39. );
  40. const getCurrentGame = useRecoilCallback(
  41. ({ snapshot }) => async () => {
  42. const availableItemList = await snapshot.getPromise(
  43. AvailableItemListAtom
  44. );
  45. const boardConfig = await snapshot.getPromise(BoardConfigAtom);
  46. const itemList = await snapshot.getPromise(AllItemsSelector);
  47. const currentGame = {
  48. items: itemList,
  49. board: boardConfig,
  50. availableItems: availableItemList,
  51. };
  52. return currentGame;
  53. },
  54. []
  55. );
  56. React.useEffect(() => {
  57. if (game) {
  58. setGame(game);
  59. }
  60. }, [game, setGame]);
  61. return (
  62. <GameContext.Provider
  63. value={{ setGame, getGame: getCurrentGame, gameId, gameLoaded }}
  64. >
  65. {gameLoaded && children}
  66. <SubscribeGameEvents getGame={getCurrentGame} setGame={setGame} />
  67. </GameContext.Provider>
  68. );
  69. };
  70. export const useGame = () => {
  71. return useContext(GameContext);
  72. };
  73. export default GameProvider;