App.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import React, { useEffect, useRef, useState } from 'react';
  2. import { CSSTransition } from 'react-transition-group';
  3. import styles from './App.module.css';
  4. import GamePanel from './components/screens/GamePanel';
  5. import GameSummary from './components/screens/GameSummary';
  6. import HomePage from './components/screens/HomePage';
  7. import Lobby from './components/screens/Lobby';
  8. import RoundSummary from './components/screens/RoundSummary';
  9. import ApiInfo from './components/util/ApiInfo';
  10. import { ERROR, IN_ROUND, POST_GAME, POST_ROUND, PRE_GAME, PRE_ROUND } from './domain/GameState';
  11. import { dispatch, useGameState } from './domain/gameStore';
  12. const needsHeaderFooter = {
  13. [PRE_GAME]: true,
  14. [PRE_ROUND]: true,
  15. [IN_ROUND]: false,
  16. [POST_ROUND]: false,
  17. [POST_GAME]: false,
  18. [ERROR]: true
  19. };
  20. const Header = ({ show }) => {
  21. const transitionRef = useRef(null);
  22. return (
  23. <CSSTransition
  24. nodeRef={transitionRef}
  25. in={show}
  26. timeout={500}
  27. mountOnEnter
  28. unmountOnExit
  29. classNames="fade"
  30. >
  31. <div className={styles.header} ref={transitionRef}>
  32. <p>TerrAssumptions!</p>
  33. </div>
  34. </CSSTransition>
  35. );
  36. }
  37. const Footer = ({ show }) => {
  38. const transitionRef = useRef(null);
  39. return (
  40. <CSSTransition
  41. nodeRef={transitionRef}
  42. in={show}
  43. timeout={500}
  44. mountOnEnter
  45. unmountOnExit
  46. classNames="fade"
  47. >
  48. <div className={styles.footer} ref={transitionRef}>
  49. <ApiInfo />
  50. </div>
  51. </CSSTransition>
  52. );
  53. }
  54. const paramRouter = {
  55. join: dispatch.goToLobby,
  56. summary: gameId => dispatch.goToSummary(gameId, false),
  57. }
  58. const State = ({ show, children, setTransitioning }) => {
  59. const transitionRef = useRef(null);
  60. return (
  61. <CSSTransition
  62. nodeRef={transitionRef}
  63. in={show}
  64. timeout={500}
  65. mountOnEnter
  66. unmountOnExit
  67. classNames="fade"
  68. onEnter={() => setTransitioning(true)}
  69. onExited={() => setTransitioning(false)}
  70. >
  71. <div className={styles.state} ref={transitionRef}>
  72. {children}
  73. </div>
  74. </CSSTransition>
  75. );
  76. }
  77. export default () => {
  78. const [transitioning, setTransitioning] = useState(true);
  79. const gameState = useGameState();
  80. useEffect(() => {
  81. const url = new URL(window.location.href);
  82. for (let [param, value] of url.searchParams.entries()) {
  83. const route = paramRouter[param];
  84. if (route) {
  85. url.searchParams.delete(param);
  86. window.history.replaceState({}, document.title, url.href);
  87. route(value);
  88. break;
  89. }
  90. }
  91. }, []);
  92. const needsHF = needsHeaderFooter[gameState];
  93. return (
  94. <React.StrictMode>
  95. <div className={styles.page}>
  96. <Header show={needsHF} />
  97. <State show={gameState === PRE_GAME} setTransitioning={setTransitioning}>
  98. <HomePage />
  99. </State>
  100. <State show={gameState === PRE_ROUND} setTransitioning={setTransitioning}>
  101. <Lobby />
  102. </State>
  103. {!transitioning && gameState === IN_ROUND && <GamePanel />}
  104. <State show={gameState === POST_ROUND} setTransitioning={setTransitioning}>
  105. <RoundSummary />
  106. </State>
  107. <State show={gameState === POST_GAME} setTransitioning={setTransitioning}>
  108. <GameSummary />
  109. </State>
  110. <State show={gameState === ERROR}>
  111. <p>Application encountered unrecoverable error, please refresh the page.</p>
  112. </State>
  113. <Footer show={needsHF} />
  114. </div>
  115. </React.StrictMode>
  116. );
  117. };