Browse Source

Implement recent game display

Kirk Trombley 3 years ago
parent
commit
5af5794570

+ 2 - 0
client/src/components/screens/HomePage/HomePage.jsx

@@ -4,6 +4,7 @@ import { dispatch } from "../../../domain/gameStore";
 import DelayedButton from "../../util/DelayedButton";
 import GameCreationForm from "../../util/GameCreationForm";
 import styles from "./HomePage.module.css";
+import RecentGames from "./RecentGames";
 import useHasSavedInfo from "./useHasSavedInfo";
 
 export const Rejoin = forwardRef((_, ref) => (
@@ -37,6 +38,7 @@ const HomePage = () => {
         <Rejoin ref={transitionRef} />
       </CSSTransition>
       <GameCreationForm afterCreate={gameId => dispatch.goToLobby(gameId)} />
+      <RecentGames />
     </div>
   );
 };

+ 39 - 3
client/src/components/screens/HomePage/HomePage.module.css

@@ -1,9 +1,11 @@
 .page {
+  box-sizing: border-box;
   width: 100%;
   height: 100%;
+  padding-top: 20%;
   display: flex;
   flex-flow: column nowrap;
-  justify-content: center;
+  justify-content: space-between;
   align-items: center;
 }
 
@@ -12,11 +14,45 @@
 }
 
 .rejoinSection {
-  top: 20%;
+  top: 10%;
   position: absolute;
-  flex: 1;
   display: flex;
   flex-flow: column nowrap;
   justify-content: flex-end;
   align-items: center;
 }
+
+.recentSection {
+  margin-bottom: 2em;
+  display: flex;
+  flex-flow: column nowrap;
+  justify-content: flex-start;
+  align-items: stretch;
+  width: 24em;
+}
+
+.recentTitle {
+  width: 100%;
+  padding-bottom: 0.5em;
+}
+
+.recentItem {
+  width: 100%;
+  margin-bottom: 0.5em;
+  display: inline-flex;
+  justify-content: space-between;
+}
+
+.recentPlayerInfo {
+  max-width: 50%;
+  display: inline-flex;
+  justify-content: flex-end;
+}
+
+.recentPlayerName {
+  margin-right: 0.125em;
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  text-align: right;
+}

+ 44 - 0
client/src/components/screens/HomePage/RecentGames.jsx

@@ -0,0 +1,44 @@
+import ms from "pretty-ms";
+import { dispatch } from "../../../domain/gameStore";
+import { useRecentGameInfo } from "../../../hooks/useGameInfo";
+import styles from "./HomePage.module.css";
+
+const RecentGames = () => {
+  const recent = useRecentGameInfo();
+
+  if (!recent || recent.length === 0) {
+    return <></>;
+  }
+
+  return (
+    <div className={styles.recentSection}>
+      <div className={styles.recentTitle}>Recent Games:</div>
+      {recent.map(({ gameId, gameMode, rounds, timer, player, numPlayers }) => (
+        <button
+          key={gameId}
+          type="button"
+          className={styles.recentItem}
+          onClick={() => dispatch.goToLobby(gameId)}
+        >
+          <div>
+            {gameMode
+              .split("_")
+              .map(part => part[0].toUpperCase() + part.slice(1).toLowerCase())
+              .join(" ")}
+            ,&nbsp;
+            {rounds} round(s),&nbsp;
+            {ms(timer * 1000)}
+          </div>
+          <div className={styles.recentPlayerInfo}>
+            <div className={styles.recentPlayerName}>
+              {player ?? "(no players)"}
+            </div>
+            {numPlayers > 1 ? `+${numPlayers - 1}` : ""}
+          </div>
+        </button>
+      ))}
+    </div>
+  );
+};
+
+export default RecentGames;

+ 20 - 0
client/src/domain/apiMethods.js

@@ -92,6 +92,26 @@ export const getPlayers = async gameId => {
   return players;
 };
 
+export const getRecentGameInfo = async () => {
+  const res = await fetch(`${API_BASE}/recent`);
+  if (!res.ok) {
+    throw Error(res.statusText);
+  }
+  const { recentGames } = await res.json();
+  return Promise.all(
+    recentGames.slice(0, 5).map(async gameId => {
+      const config = await getGameConfig(gameId);
+      const players = await getPlayers(gameId);
+      return {
+        gameId,
+        ...config,
+        player: players?.[0]?.name,
+        numPlayers: players?.length ?? 0,
+      };
+    })
+  );
+};
+
 export const getLinkedGame = async gameId => {
   const res = await fetch(`${API_BASE}/game/${gameId}/linked`);
   if (!res.ok) {

+ 3 - 0
client/src/hooks/useGameInfo.jsx

@@ -5,6 +5,7 @@ import {
   getGameCoords,
   getPlayers,
   getLinkedGame,
+  getRecentGameInfo,
 } from "../domain/apiMethods";
 import { useGameId } from "../domain/gameStore";
 
@@ -52,3 +53,5 @@ const useAutoRefresh = apiCall => {
 export const usePlayers = () => useAutoRefresh(getPlayers);
 
 export const useLinkedGame = () => useAutoRefresh(getLinkedGame);
+
+export const useRecentGameInfo = () => useAutoRefresh(getRecentGameInfo);