app/actions/create-game.ts (41 lines of code) (raw):
/**
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use server';
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} from 'firebase-admin/firestore';
import {GameSettingsSchema} from '@/app/types';
import {validateTokens} from '@/app/lib/server-token-validator';
export async function createGameAction({gameSettings, tokens}: {gameSettings: GameSettings, tokens: Tokens}): Promise<{gameId: string}> {
const authUser = await validateTokens(tokens);
// Parse request (throw an error if not correct)
const {timePerQuestion, timePerAnswer, questionAdvancement} = GameSettingsSchema.parse(gameSettings);
const querySnapshot = await questionsRef.get();
const validQuestionsArray = querySnapshot.docs.reduce((agg: Question[], doc: QueryDocumentSnapshot) => {
let question = doc.data();
try {
question = QuestionSchema.parse(question);
return [...agg, question];
} catch (error) {
console.warn(`WARNING: The question "${question?.prompt}" [Firestore ID: ${doc.id}] has an issue and will not be added to the game.`);
return agg;
}
}, []);
// convert array to object for Firebase
const questions = {...validQuestionsArray};
// create game with server endpoint
const leader = {
displayName: generateName(authUser.uid),
uid: authUser.uid,
};
const newGame: Game = {
questions,
leader,
players: {},
state: gameStates.NOT_STARTED,
currentQuestionIndex: 0,
timePerQuestion: timePerQuestion + 1, // add one for padding between questions
timePerAnswer: timePerAnswer + 1, // add one for padding between questions
questionAdvancement,
currentStateStartTime: {seconds: 0},
};
const gameRef = await gamesRef.add(newGame);
if (gameRef.id) return {gameId: gameRef.id};
throw new Error('no gameId returned in the response');
}