Skip to content

Commit

Permalink
Game setup implementation and question model simplification
Browse files Browse the repository at this point in the history
  • Loading branch information
david-vct committed Mar 30, 2024
1 parent f2fab13 commit ccb403c
Show file tree
Hide file tree
Showing 10 changed files with 92 additions and 67 deletions.
12 changes: 10 additions & 2 deletions src/pages/QuestionCreator/ChoiceQuestionCreator.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useState } from "react"
import { createQuestion } from "../../services/questions-store"
import { initializeEmptyQuestionFields, splitAndTrim } from "../../utils/utils"
import { QuestionType } from "../../utils/types"

export const ChoiceQuestionCreator = () => {
const [title, setTitle] = useState("")
Expand All @@ -10,14 +11,21 @@ export const ChoiceQuestionCreator = () => {

const createQuestionHandler = () => {
const question = {
type: QuestionType.CHOICE,
title,
choices: splitAndTrim(choices),
body: splitAndTrim(choices),
answers: splitAndTrim(answers),
tags: splitAndTrim(tags),
...initializeEmptyQuestionFields(),
}

createQuestion(question)
createQuestion(question).then((response) => {
if (!response.success) {
console.error(response.error)
} else {
console.log(response.data)
}
})
}

return (
Expand Down
12 changes: 10 additions & 2 deletions src/pages/QuestionCreator/CompleteQuestionCreator.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useState } from "react"
import { createQuestion } from "../../services/questions-store"
import { initializeEmptyQuestionFields, splitAndTrim } from "../../utils/utils"
import { QuestionType } from "../../utils/types"

export const CompleteQuestionCreator = () => {
const [title, setTitle] = useState("")
Expand All @@ -10,14 +11,21 @@ export const CompleteQuestionCreator = () => {

const createQuestionHandler = () => {
const question = {
type: QuestionType.COMPLETE,
title,
description,
body: [description],
answers: splitAndTrim(answers, ","),
tags: splitAndTrim(tags),
...initializeEmptyQuestionFields(),
}

createQuestion(question)
createQuestion(question).then((response) => {
if (!response.success) {
console.error(response.error)
} else {
console.log(response.data)
}
})
}

return (
Expand Down
11 changes: 10 additions & 1 deletion src/pages/QuestionCreator/SimpleQuestionCreator.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useState } from "react"
import { createQuestion } from "../../services/questions-store"
import { initializeEmptyQuestionFields, splitAndTrim } from "../../utils/utils"
import { QuestionType } from "../../utils/types"

export const SimpleQuestionCreator = () => {
const [title, setTitle] = useState("")
Expand All @@ -9,13 +10,21 @@ export const SimpleQuestionCreator = () => {

const createQuestionHandler = () => {
const question = {
type: QuestionType.SIMPLE,
title,
body: [],
answers: splitAndTrim(answers),
tags: splitAndTrim(tags),
...initializeEmptyQuestionFields(),
}

createQuestion(question)
createQuestion(question).then((response) => {
if (!response.success) {
console.error(response.error)
} else {
console.log(response.data)
}
})
}

return (
Expand Down
14 changes: 5 additions & 9 deletions src/pages/TestsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import { useState } from "react"
import { findQuestionById } from "../services/questions-store"
import { findQuestionByTags } from "../services/questions-store"

export const TestsPage = () => {
const [questionId, setQuestionId] = useState("")

function find() {
findQuestionById(questionId).then((response) => {
function action() {
findQuestionByTags(["histoire", "enigme"]).then((response) => {
if (response.success) {
console.log("Docs nb : " + response.data.length)
console.log(response.data)
} else {
console.error(response.error)
}
Expand All @@ -16,8 +13,7 @@ export const TestsPage = () => {

return (
<div>
<input placeholder="id" onChange={(e) => setQuestionId(e.target.value)} />
<button onClick={find}>Find</button>
<button onClick={action}>Action</button>
</div>
)
}
2 changes: 1 addition & 1 deletion src/pages/game/LobbyPlayers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const LobbyPlayers = (props: LobbyPlayersProps) => {
<h2>Joueurs</h2>
<ul>
{props.usernames.map((username) => (
<li>{username}</li>
<li key={username}>{username}</li>
))}
</ul>
</div>
Expand Down
23 changes: 20 additions & 3 deletions src/pages/game/LobbySettings.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,36 @@
import { useState } from "react"
import { startGame } from "../../services/games-store"
import { splitAndTrim } from "../../utils/utils"

type LobbySettingsProps = {
gameId: string
}

export const LobbySettings = (props: LobbySettingsProps) => {
const startGameHandler = async () => {
await startGame(props.gameId)
const [tags, setTags] = useState("")
const [nbQuestion, setNbQuestions] = useState(10)

const startGameHandler = () => {
startGame(props.gameId, splitAndTrim(tags), nbQuestion).then((response) => {
if (!response.success) {
console.error(response.error)
} else {
console.log(response.data)
}
})
}

const setNbQuestionsHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = parseInt(e.target.value)
if (!isNaN(value)) setNbQuestions(value)
}

return (
<div>
<h2>Parametres</h2>
<div>Game id : {props.gameId}</div>
<input placeholder="Themes" />
<input placeholder="Tags" onChange={(e) => setTags(e.target.value)} />
<input placeholder="Nombre de questions" type="number" value={nbQuestion} onChange={setNbQuestionsHandler} />
<button onClick={startGameHandler}>Commencer</button>
</div>
)
Expand Down
16 changes: 13 additions & 3 deletions src/services/games-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { getErrorStoreResponse, getSuccessStoreResponse, initializeEmptyGameData
import { findDataByQuery } from "./store"
import { Game, GameSchema, StoreResponse, UserInfo } from "../utils/types"
import { validateStoreResponseLength } from "./validation"
import { findQuestionByTags } from "./questions-store"

const gamesRef = collection(db, "games")

Expand Down Expand Up @@ -80,9 +81,18 @@ export async function existsGameById(id: string) {
* @param id
* @returns
*/
export async function startGame(id: string) {
// TODO: Add setup logic
const response = await updateGame(id, { ["isSetup"]: true })
export async function startGame(id: string, tags: string[], nbQuestions: number) {
const questionResponse = await findQuestionByTags(tags, nbQuestions)
if (!questionResponse.success) {
return questionResponse
}

const data = {
["isSetup"]: true,
["questions"]: questionResponse.data,
}

const response = await updateGame(id, data)
return response
}

Expand Down
4 changes: 2 additions & 2 deletions src/services/questions-store.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Query, addDoc, collection, documentId, limit, query, where } from "firebase/firestore"
import { db } from "../config/firebase"
import { Question, QuestionSchema, StoreResponse } from "../utils/types"
import { Question, QuestionData, QuestionSchema, StoreResponse } from "../utils/types"
import { isValideQuestion } from "./validation"
import { findDataByQuery } from "./store"
import { getErrorStoreResponse, getSuccessStoreResponse } from "../utils/utils"
Expand All @@ -25,7 +25,7 @@ export async function findQuestionById(questionId: string) {
return response
}

export async function createQuestion(question: Question) {
export async function createQuestion(question: QuestionData) {
if (!isValideQuestion(question)) {
return getErrorStoreResponse("Not valide question")
}
Expand Down
6 changes: 3 additions & 3 deletions src/services/validation.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Question, QuestionSchema, StoreResponse } from "../utils/types"
import { QuestionData, QuestionDataSchema, StoreResponse } from "../utils/types"

export function isValideQuestion(question: Question) {
const questionParsed = QuestionSchema.safeParse(question)
export function isValideQuestion(question: QuestionData) {
const questionParsed = QuestionDataSchema.safeParse(question)
if (!questionParsed.success) {
console.error(questionParsed.error)
}
Expand Down
59 changes: 18 additions & 41 deletions src/utils/types.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
import { z } from "zod"

// Questions Schemas
const QuestionBaseSchema = z.object({
/* Questions Types */

export enum QuestionType {
SIMPLE,
COMPLETE,
CHOICE,
IMAGE,
}

export const QuestionDataSchema = z.object({
title: z.string().min(1).max(100),
body: z.array(z.string()),
answers: z.array(z.string().trim()).min(1).max(10),
tags: z.array(z.string()),
type: z.nativeEnum(QuestionType),
rating: z.object({
like: z.number(),
dislike: z.number(),
Expand All @@ -11,57 +23,22 @@ const QuestionBaseSchema = z.object({
win: z.number(),
lose: z.number(),
}),
tags: z.array(z.string()),
})

export const SimpleQuestionSchema = QuestionBaseSchema.extend({
answers: z.array(z.string().trim()).min(1).max(10),
})

export const CompleteQuestionSchema = QuestionBaseSchema.extend({
description: z.string().min(1).max(250),
answers: z.array(z.string().trim()).min(1).max(10),
})

export const ChoiceQuestionSchema = QuestionBaseSchema.extend({
choices: z.array(z.string()).min(2).max(10),
answers: z.array(z.number().min(0).max(9)).min(1).max(10),
})

export const ImageQuestionSchema = QuestionBaseSchema.extend({
imageUrl: z.string().url().min(1),
answers: z.array(z.string().trim()).min(1).max(10),
export const QuestionSchema = QuestionDataSchema.extend({
id: z.string(),
})

export const QuestionSchema = z.union([
SimpleQuestionSchema,
CompleteQuestionSchema,
ChoiceQuestionSchema,
ImageQuestionSchema,
])

// Questions Types
export type SimpleQuestion = z.infer<typeof SimpleQuestionSchema>
export type CompleteQuestion = z.infer<typeof CompleteQuestionSchema>
export type ChoiceQuestion = z.infer<typeof ChoiceQuestionSchema>
export type ImageQuestion = z.infer<typeof ImageQuestionSchema>

export type QuestionData = z.infer<typeof QuestionDataSchema>
export type Question = z.infer<typeof QuestionSchema>

export enum QuestionType {
SIMPLE,
COMPLETE,
CHOICE,
IMAGE,
}

// Games types
export const GameDataSchema = z.object({
name: z.string().toUpperCase().length(4),
isSetup: z.boolean(),
users: z.record(z.string(), z.string()),
tags: z.array(z.string()),
questions: z.array(z.string()),
questions: z.array(QuestionSchema),
questionIndex: z.number(),
})

Expand Down

0 comments on commit ccb403c

Please sign in to comment.