App.jsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. import { useEffect, useRef, useState, StrictMode } 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 {
  11. ERROR,
  12. IN_ROUND,
  13. POST_GAME,
  14. POST_ROUND,
  15. PRE_GAME,
  16. PRE_ROUND,
  17. } from "./domain/constants";
  18. import { dispatch, useGameState } from "./domain/gameStore";
  19. import Loading from "./components/util/Loading";
  20. const needsHeaderFooter = {
  21. [PRE_GAME]: true,
  22. [PRE_ROUND]: true,
  23. [IN_ROUND]: false,
  24. [POST_ROUND]: false,
  25. [POST_GAME]: false,
  26. [ERROR]: true,
  27. };
  28. export const Header = ({ show }) => {
  29. const transitionRef = useRef(null);
  30. return (
  31. <CSSTransition
  32. nodeRef={transitionRef}
  33. in={show}
  34. timeout={500}
  35. mountOnEnter
  36. unmountOnExit
  37. classNames="fade"
  38. >
  39. <div className={styles.header} ref={transitionRef}>
  40. <p>TerrAssumptions!</p>
  41. </div>
  42. </CSSTransition>
  43. );
  44. };
  45. export const Footer = ({ show }) => {
  46. const transitionRef = useRef(null);
  47. return (
  48. <CSSTransition
  49. nodeRef={transitionRef}
  50. in={show}
  51. timeout={500}
  52. mountOnEnter
  53. unmountOnExit
  54. classNames="fade"
  55. >
  56. <div className={styles.footer} ref={transitionRef}>
  57. <ApiInfo />
  58. </div>
  59. </CSSTransition>
  60. );
  61. };
  62. export const paramRouter = {
  63. join: dispatch.goToLobby,
  64. summary: gameId => dispatch.goToSummary(gameId, false),
  65. };
  66. export const State = ({ show, children, setTransitioning }) => {
  67. const transitionRef = useRef(null);
  68. return (
  69. <CSSTransition
  70. nodeRef={transitionRef}
  71. in={show}
  72. timeout={500}
  73. mountOnEnter
  74. unmountOnExit
  75. classNames="fade"
  76. onEnter={() => setTransitioning(true)}
  77. onExited={() => setTransitioning(false)}
  78. >
  79. <div className={styles.state} ref={transitionRef}>
  80. {children}
  81. </div>
  82. </CSSTransition>
  83. );
  84. };
  85. const App = () => {
  86. const [loading, setLoading] = useState(true);
  87. const [transitioning, setTransitioning] = useState(true);
  88. const gameState = useGameState();
  89. useEffect(() => {
  90. const url = new URL(window.location.href);
  91. // eslint-disable-next-line no-restricted-syntax
  92. for (const [param, value] of url.searchParams.entries()) {
  93. const route = paramRouter[param];
  94. if (route) {
  95. url.searchParams.delete(param);
  96. window.history.replaceState({}, document.title, url.href);
  97. route(value);
  98. break;
  99. }
  100. }
  101. setLoading(false);
  102. }, []);
  103. const needsHF = needsHeaderFooter[gameState];
  104. return (
  105. <StrictMode>
  106. <div className={styles.page}>
  107. <Header show={needsHF} />
  108. <State show={loading} setTransitioning={setTransitioning}>
  109. <div className={styles.loading}>
  110. <Loading />
  111. </div>
  112. </State>
  113. <State
  114. show={!loading && gameState === PRE_GAME}
  115. setTransitioning={setTransitioning}
  116. >
  117. <HomePage />
  118. </State>
  119. <State
  120. show={gameState === PRE_ROUND}
  121. setTransitioning={setTransitioning}
  122. >
  123. <Lobby />
  124. </State>
  125. {!transitioning && gameState === IN_ROUND && <GamePanel />}
  126. <State
  127. show={gameState === POST_ROUND}
  128. setTransitioning={setTransitioning}
  129. >
  130. <RoundSummary />
  131. </State>
  132. <State
  133. show={gameState === POST_GAME}
  134. setTransitioning={setTransitioning}
  135. >
  136. <GameSummary />
  137. </State>
  138. <State show={gameState === ERROR}>
  139. <p>
  140. Application encountered unrecoverable error, please refresh the
  141. page.
  142. </p>
  143. </State>
  144. <Footer show={needsHF} />
  145. </div>
  146. </StrictMode>
  147. );
  148. };
  149. export default App;