Skip to content

Commit

Permalink
Feature/remove navbar (#110)
Browse files Browse the repository at this point in the history
* remove navbar

* use question time instead of total time

* feat: allow manual advancement

* create useCallback to remove redundant code
  • Loading branch information
LukeSchlangen authored Oct 4, 2023
1 parent fb4a05f commit 1294317
Show file tree
Hide file tree
Showing 15 changed files with 160 additions and 127 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,10 @@
'use client';

import GameList from '@/app/components/game-list';
import Navbar from '@/app/components/navbar';

export default function Home() {
return (
<div>
<Navbar />
<GameList />
<br />
</div>
Expand Down
2 changes: 0 additions & 2 deletions app-dev/party-game/app/(authenticated-pages)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import '@/app/globals.css';
import Image from 'next/image';
import useFirebaseAuthentication from '@/app/hooks/use-firebase-authentication';
import BigSignInButton from '@/app/components/big-sign-in-button';
import Navbar from '@/app/components/navbar';

export default function RootLayout({
children,
Expand All @@ -38,7 +37,6 @@ export default function RootLayout({
</>
) : (
<>
<Navbar />
<center className='pt-20'>
<div className='h-20'>
<Image
Expand Down
2 changes: 0 additions & 2 deletions app-dev/party-game/app/(authenticated-pages)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

import useActiveGameList from '@/app/hooks/use-active-game-list';
import {useRouter} from 'next/navigation';
import Navbar from '@/app/components/navbar';
import {useEffect} from 'react';

export default function Home() {
Expand All @@ -34,7 +33,6 @@ export default function Home() {

return (
<div>
<Navbar />
<center className="p-8">
Waiting for a game.
</center>
Expand Down
2 changes: 0 additions & 2 deletions app-dev/party-game/app/(unauthenticated-pages)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
* limitations under the License.
*/

import Navbar from '@/app/components/navbar';
import '@/app/globals.css';

export const metadata = {
Expand All @@ -29,7 +28,6 @@ export default function RootLayout({
}) {
return (
<>
<Navbar />
<main className="mt-5 mx-auto max-w-2xl underline hover:decoration-[var(--google-cloud-blue)]">
{children}
</main>
Expand Down
9 changes: 4 additions & 5 deletions app-dev/party-game/app/actions/create-game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import {gamesRef, questionsRef} from '@/app/lib/firebase-server-initialization';
import {generateName} from '@/app/lib/name-generator';
import {Game, GameSettings, Question, QuestionSchema, Tokens, gameStates} from '@/app/types';
import {QueryDocumentSnapshot, Timestamp} from 'firebase-admin/firestore';
import {QueryDocumentSnapshot} from 'firebase-admin/firestore';
import {GameSettingsSchema} from '@/app/types';
import {validateTokens} from '@/app/lib/server-token-validator';

Expand Down Expand Up @@ -51,17 +51,16 @@ export async function createGameAction({gameSettings, tokens}: {gameSettings: Ga
uid: authUser.uid,
};

const startTime = Timestamp.now();

const newGame: Game= {
const newGame: Game = {
questions,
leader,
players: {},
state: gameStates.NOT_STARTED,
currentQuestionIndex: 0,
startTime,
timePerQuestion: timePerQuestion + 1, // add one for padding between questions
timePerAnswer: timePerAnswer + 1, // add one for padding between questions
questionAdvancement: 'AUTOMATIC',
currentStateStartTime: {seconds: 0},
};

const gameRef = await gamesRef.add(newGame);
Expand Down
4 changes: 2 additions & 2 deletions app-dev/party-game/app/actions/delete-game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
'use server';

import {gamesRef} from '@/app/lib/firebase-server-initialization';
import {GameIdSchema, Tokens} from '@/app/types';
import {GameIdSchema, GameSchema, Tokens} from '@/app/types';
import {validateTokens} from '@/app/lib/server-token-validator';

export async function deleteGameAction({gameId, tokens}: {gameId: string, tokens: Tokens}) {
Expand All @@ -28,7 +28,7 @@ export async function deleteGameAction({gameId, tokens}: {gameId: string, tokens

const gameRef = await gamesRef.doc(gameId);
const gameDoc = await gameRef.get();
const game = gameDoc.data();
const game = GameSchema.parse(gameDoc.data());

if (game.leader.uid !== authUser.uid) {
// Respond with JSON indicating no game was found
Expand Down
4 changes: 2 additions & 2 deletions app-dev/party-game/app/actions/join-game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

import {gamesRef} from '@/app/lib/firebase-server-initialization';
import {generateName} from '@/app/lib/name-generator';
import {GameIdSchema, Tokens} from '@/app/types';
import {GameIdSchema, GameSchema, Tokens} from '@/app/types';
import {validateTokens} from '@/app/lib/server-token-validator';

export async function joinGameAction({gameId, tokens}: {gameId: string, tokens: Tokens}) {
Expand All @@ -29,7 +29,7 @@ export async function joinGameAction({gameId, tokens}: {gameId: string, tokens:

const gameRef = await gamesRef.doc(gameId);
const gameDoc = await gameRef.get();
const game = gameDoc.data();
const game = GameSchema.parse(gameDoc.data());
const playerIdList = Object.keys(game.players);
if (playerIdList.includes(authUser.uid)) return;
if (game.leader.uid === authUser.uid) {
Expand Down
83 changes: 58 additions & 25 deletions app-dev/party-game/app/actions/nudge-game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,44 +17,77 @@
'use server';

import {gamesRef} from '@/app/lib/firebase-server-initialization';
import {GameIdSchema, Tokens, gameStates} from '@/app/types';
import {Timestamp} from 'firebase-admin/firestore';
import {GameIdSchema, GameSchema, GameStateUpdate, GameStateUpdateSchema, Tokens, gameStates} from '@/app/types';
import {FieldValue} from 'firebase-admin/firestore';
import {validateTokens} from '@/app/lib/server-token-validator';

export async function nudgeGameAction({gameId, tokens}: {gameId: string, tokens: Tokens}) {
await validateTokens(tokens);
export async function nudgeGameAction({gameId, desiredState, tokens}: { gameId: string, desiredState: GameStateUpdate, tokens: Tokens }) {
const authUser = await validateTokens(tokens);

// Validate request
// Will throw an error if not a string
GameIdSchema.parse(gameId);
GameStateUpdateSchema.parse(desiredState);

const gameRef = await gamesRef.doc(gameId);
const gameDoc = await gameRef.get();
const game = gameDoc.data();
const game = GameSchema.parse(gameDoc.data());

// force the game state to move to where the game should be

const timeElapsedInMillis = Timestamp.now().toMillis() - game.startTime.seconds * 1000;
const timeElapsed = timeElapsedInMillis / 1000;
const timePerQuestionAndAnswer = game.timePerQuestion + game.timePerAnswer;
if (game.leader.uid !== authUser.uid) {
// Respond with JSON indicating no game was found
throw new Error('Only the leader of this game may advance this game.');
}

const totalNumberOfQuestions = Object.keys(game.questions).length;
const finalQuestionIndex = totalNumberOfQuestions - 1;
const correctQuestionIndex = Math.floor(timeElapsed / timePerQuestionAndAnswer);
if (correctQuestionIndex > finalQuestionIndex) {
await gameRef.update({
state: gameStates.GAME_OVER,
currentQuestionIndex: finalQuestionIndex,
});
return;
}

const timeThisQuestionStarted = correctQuestionIndex * timePerQuestionAndAnswer;
const shouldBeAcceptingAnswers = timeElapsed - timeThisQuestionStarted < game.timePerQuestion;
const correctState = shouldBeAcceptingAnswers ? gameStates.AWAITING_PLAYER_ANSWERS : gameStates.SHOWING_CORRECT_ANSWERS;
const nextQuestionIndex = game.currentQuestionIndex + 1;

const {NOT_STARTED, AWAITING_PLAYER_ANSWERS, GAME_OVER, SHOWING_CORRECT_ANSWERS} = gameStates;

await gameRef.update({
state: correctState,
currentQuestionIndex: correctQuestionIndex,
});
// if the game is already in the desired state, no further action required
if (game.state === desiredState.state && game.currentQuestionIndex === desiredState.currentQuestionIndex) {
throw new Error('Desired state is same as current state. No changes to be made.');
}

switch (game.state) {
case GAME_OVER:
throw new Error('The game is over. No game progression is allowed.');
case NOT_STARTED:
if (desiredState.state === AWAITING_PLAYER_ANSWERS && desiredState.currentQuestionIndex === 0) {
await gameRef.update({
state: AWAITING_PLAYER_ANSWERS,
currentQuestionIndex: 0,
currentStateStartTime: FieldValue.serverTimestamp(),
});
return;
}
throw new Error('The only allowed game progression when NOT_STARTED is to AWAITING_PLAYER_ANSWERS');
case SHOWING_CORRECT_ANSWERS:
if (desiredState.currentQuestionIndex === nextQuestionIndex) {
if (game.currentQuestionIndex === finalQuestionIndex) {
await gameRef.update({
state: GAME_OVER,
currentStateStartTime: FieldValue.serverTimestamp(),
});
return;
}
await gameRef.update({
state: AWAITING_PLAYER_ANSWERS,
currentQuestionIndex: nextQuestionIndex,
currentStateStartTime: FieldValue.serverTimestamp(),
});
return;
}
throw new Error('The only allowed game progression when SHOWING_CORRECT_ANSWERS is to AWAITING_PLAYER_ANSWERS on the next question');
case AWAITING_PLAYER_ANSWERS:
if (desiredState.state === SHOWING_CORRECT_ANSWERS && desiredState.currentQuestionIndex === game.currentQuestionIndex) {
await gameRef.update({
state: SHOWING_CORRECT_ANSWERS,
currentStateStartTime: FieldValue.serverTimestamp(),
});
return;
}
throw new Error('The only allowed game progression when AWAITING_PLAYER_ANSWERS is to SHOWING_CORRECT_ANSWERS');
}
}
44 changes: 0 additions & 44 deletions app-dev/party-game/app/actions/start-game.ts

This file was deleted.

4 changes: 2 additions & 2 deletions app-dev/party-game/app/actions/update-answer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
'use server';

import {gamesRef} from '@/app/lib/firebase-server-initialization';
import {GameIdSchema, Tokens, gameStates} from '@/app/types';
import {GameIdSchema, GameSchema, Tokens, gameStates} from '@/app/types';
import {z} from 'zod';
import {validateTokens} from '@/app/lib/server-token-validator';

Expand All @@ -29,7 +29,7 @@ export async function updateAnswerAction({gameId, answerSelection, tokens}: {gam

const gameRef = await gamesRef.doc(gameId);
const gameDoc = await gameRef.get();
const game = gameDoc.data();
const game = GameSchema.parse(gameDoc.data());

if (game.state !== gameStates.AWAITING_PLAYER_ANSWERS) {
return new Error(`Answering is not allowed during ${game.state}.`);
Expand Down
Loading

0 comments on commit 1294317

Please sign in to comment.