Game.jsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import React, { useState } from "react";
  2. import {
  3. PRE_GAME,
  4. PRE_ROUND,
  5. IN_ROUND,
  6. POST_ROUND,
  7. POST_GAME,
  8. ERROR,
  9. } from "./GameState";
  10. import HeaderAndFooter from "./HeaderAndFooter";
  11. import PreGame from '../screens/PreGame';
  12. import PreRound from '../screens/PreRound';
  13. import GamePanel from "../screens/GamePanel";
  14. import RoundSummary from '../screens/RoundSummary';
  15. import PlayerScores from "../screens/PlayerScores";
  16. const initialState = {
  17. gameState: PRE_GAME,
  18. gameId: null,
  19. playerName: null,
  20. lastRound: null,
  21. joined: false,
  22. }
  23. const extractAndRemoveSearchParam = param => {
  24. const u = new URL(window.location.href);
  25. const extracted = u.searchParams.get(param);
  26. u.searchParams.delete(param);
  27. window.history.replaceState({}, document.title, u.href);
  28. return extracted;
  29. }
  30. const Game = () => {
  31. const [ state, rawSetState ] = useState(initialState);
  32. const setGameState = gameState => rawSetState({ ...state, gameState });
  33. const setGameStateAnd = (gameState, updates) => rawSetState({ ...state, gameState, ...updates });
  34. const onGameJoined = ({ gameId, playerName }) => setGameStateAnd(PRE_ROUND, { gameId, playerName, joined: true });
  35. const joinCode = extractAndRemoveSearchParam("join");
  36. if (joinCode) {
  37. setGameStateAnd(PRE_ROUND, { gameId: joinCode, joined: false });
  38. }
  39. const summaryCode = extractAndRemoveSearchParam("summary");
  40. if (summaryCode) {
  41. setGameStateAnd(POST_GAME, { gameId: summaryCode });
  42. }
  43. switch (state.gameState) {
  44. case PRE_GAME:
  45. return (
  46. <HeaderAndFooter>
  47. <PreGame
  48. initPlayerName={state.playerName}
  49. onGameJoined={onGameJoined}
  50. />
  51. </HeaderAndFooter>
  52. );
  53. case PRE_ROUND:
  54. return (
  55. <HeaderAndFooter>
  56. <PreRound
  57. gameId={state.gameId}
  58. playerName={state.playerName}
  59. joined={state.joined}
  60. onGameJoined={onGameJoined}
  61. onStart={() => setGameState(IN_ROUND)}
  62. />
  63. </HeaderAndFooter>
  64. );
  65. case IN_ROUND:
  66. return <GamePanel
  67. gameId={state.gameId}
  68. playerName={state.playerName}
  69. onRoundEnd={lastRound => setGameStateAnd(POST_ROUND, { lastRound })}
  70. onGameEnd={() => setGameState(POST_GAME)}
  71. />
  72. case POST_ROUND:
  73. return <RoundSummary
  74. gameId={state.gameId}
  75. playerName={state.playerName}
  76. round={state.lastRound}
  77. onNext={() => setGameState(IN_ROUND)}
  78. />
  79. case POST_GAME:
  80. return (
  81. <HeaderAndFooter>
  82. <PlayerScores
  83. gameId={state.gameId}
  84. onReturnToStart={() => setGameStateAnd(PRE_GAME, { gameId: null, joined: false })}
  85. />
  86. </HeaderAndFooter>
  87. );
  88. case ERROR:
  89. // TODO - would be nice to hook this into the sub-components, maybe with a HOC?
  90. return <p>Application encountered unrecoverable error, please refresh the page.</p>
  91. default:
  92. setGameState(ERROR);
  93. return <p>Application state is inconsistent, please refresh and rejoin your previous game.</p>
  94. }
  95. }
  96. export default Game;