Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Single player game mechanic implementation #14

Merged
merged 3 commits into from
Mar 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 17 additions & 15 deletions src/pages/QuestionCreator/ChoiceQuestionCreator.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,39 @@
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("")
const [choices, setChoices] = useState("")
const [answers, setAnswers] = useState("")
const [tags, setTags] = useState("")

const createQuestionHandler = () => {
const question = {
type: QuestionType.CHOICE,
title,
choices: splitAndTrim(choices, ","),
answers: splitAndTrim(answers, ","),
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 (
<div>
<input
placeholder="Question"
onChange={(e) => setTitle(e.target.value)}
/>
<input
placeholder="Description"
onChange={(e) => setChoices(e.target.value)}
/>
<input
placeholder="Réponses"
onChange={(e) => setAnswers(e.target.value)}
/>
<input placeholder="Question" onChange={(e) => setTitle(e.target.value)} />
<input placeholder="Choix" onChange={(e) => setChoices(e.target.value)} />
<input placeholder="Réponses" onChange={(e) => setAnswers(e.target.value)} />
<input placeholder="Tags" onChange={(e) => setTags(e.target.value)} />
<button onClick={createQuestionHandler}>Créer</button>
</div>
)
Expand Down
30 changes: 16 additions & 14 deletions src/pages/QuestionCreator/CompleteQuestionCreator.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,39 @@
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("")
const [description, setDescription] = useState("")
const [answers, setAnswers] = useState("")
const [tags, setTags] = useState("")

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 (
<div>
<input
placeholder="Question"
onChange={(e) => setTitle(e.target.value)}
/>
<input
placeholder="Description"
onChange={(e) => setDescription(e.target.value)}
/>
<input
placeholder="Réponses"
onChange={(e) => setAnswers(e.target.value)}
/>
<input placeholder="Question" onChange={(e) => setTitle(e.target.value)} />
<input placeholder="Description" onChange={(e) => setDescription(e.target.value)} />
<input placeholder="Réponses" onChange={(e) => setAnswers(e.target.value)} />
<input placeholder="Tags" onChange={(e) => setTags(e.target.value)} />
<button onClick={createQuestionHandler}>Créer</button>
</div>
)
Expand Down
26 changes: 16 additions & 10 deletions src/pages/QuestionCreator/SimpleQuestionCreator.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,37 @@
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("")
const [answers, setAnswers] = useState("")
const [tags, setTags] = useState("")

const createQuestionHandler = () => {
const question = {
type: QuestionType.SIMPLE,
title,
answers: splitAndTrim(answers, ","),
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 (
<div>
<input
placeholder="Question"
onChange={(e) => setTitle(e.target.value)}
/>
<input
placeholder="Réponses"
onChange={(e) => setAnswers(e.target.value)}
/>
<input placeholder="Question" onChange={(e) => setTitle(e.target.value)} />
<input placeholder="Réponses" onChange={(e) => setAnswers(e.target.value)} />
<input placeholder="Tags" onChange={(e) => setTags(e.target.value)} />
<button onClick={createQuestionHandler}>Créer</button>
</div>
)
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>
)
}
68 changes: 51 additions & 17 deletions src/pages/game/GameController.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,28 @@ import { LobbySettings } from "./LobbySettings"
import { LobbyPlayers } from "./LobbyPlayers"
import { useNavigate, useParams } from "react-router-dom"
import { useEffect, useState } from "react"
import { addPlayerToGame, listenGame } from "../../services/games-store"
import { addPlayerToGame, listenGame, updateGameUserAnswers } from "../../services/games-store"
import { getSnapshotData } from "../../services/store"
import { Game, GameSchema, StoreResponse } from "../../utils/types"
import { Game, GameSchema, GameState, Question, StoreResponse } from "../../utils/types"
import { GameQuestion } from "./GameQuestion"
import { getUserInfo } from "../../services/authentication"
import { isEqual } from "lodash"
import { GameReview } from "./GameReview"

export const GameController = () => {
const [isSetup, setIsSetup] = useState(false)
const [gameState, setGameState] = useState(GameState.WAITING)
const [questionIndex, setQuestionIndex] = useState(0)
const [usernames, setUsernames] = useState([] as string[])
const [usernames, setUsernames] = useState({})
const [questions, setQuestions] = useState([] as Question[])
const [answers, setAnswers] = useState({} as Record<string, string>)
const [game, setGame] = useState({} as Game)

const { gameId } = useParams()
const navigate = useNavigate()

console.log("Rendering app")

// Listen to game changes, called once
// Game state contoller
useEffect(() => {
if (gameId === undefined) {
console.error("Undefined game id")
Expand All @@ -31,6 +35,7 @@ export const GameController = () => {
// Add user to game
addPlayerToGame(gameId, getUserInfo())

// TODO: Handle stop listening game
listenGame(gameId, (snapshot) => {
console.log("Snapshot listener")
const response: StoreResponse<Game> = getSnapshotData(snapshot, GameSchema)
Expand All @@ -50,23 +55,48 @@ export const GameController = () => {
// Get this game
const game = response.data.shift()!

// Set game as state
setGame(game)

// Update users if needed
if (!isEqual(usernames, game.users)) {
setUsernames(Object.values(game.users))
}

// Control game state
if (isSetup !== game.isSetup) {
setIsSetup(game.isSetup)
}

// Set next question
if (questionIndex !== game.questionIndex) {
setQuestionIndex(game.questionIndex)
// Start the game play
if (game.isSetup) {
setQuestions(game.questions)
setGameState(GameState.PLAYING)
}
})
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])

// Game play controller
const handleAnswer = (answer: string) => {
// Add answer to answers
answers[questions[questionIndex].id] = answer
setAnswers(answers)

// Next question
if (questionIndex < questions.length - 1) {
setQuestionIndex(questionIndex + 1)
}

// Reviwing state
else {
// TODO: reviwing state
updateGameUserAnswers(game.id, getUserInfo().id, answers).then((response) => {
if (!response.success) {
console.error(response.error)
navigate("/error/")
} else {
setGameState(GameState.REVIEWING)
}
})
}
}

if (gameId === undefined) {
console.error("Undefined game id")
navigate("/error/")
Expand All @@ -76,14 +106,18 @@ export const GameController = () => {
return (
<div>
<Navbar />
{isSetup ? (
<GameQuestion />
) : (
{gameState === GameState.WAITING ? (
<div>
<h1>Nouvelle partie</h1>
<LobbySettings gameId={gameId} />
<LobbyPlayers gameId={gameId} usernames={usernames} />
<LobbyPlayers usernames={usernames} />
</div>
) : gameState === GameState.PLAYING ? (
<GameQuestion question={questions[questionIndex]} sendAnswer={handleAnswer} />
) : gameState === GameState.REVIEWING ? (
<GameReview game={game} />
) : (
<div>Jeu fini</div>
)}
</div>
)
Expand Down
15 changes: 14 additions & 1 deletion src/pages/game/GameQuestion.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
export const GameQuestion = () => {
import { useState } from "react"
import { Question } from "../../utils/types"

type GameQuestionPorps = {
question: Question
sendAnswer: (answer: string) => void
}

export const GameQuestion = (props: GameQuestionPorps) => {
const [answer, setAnswer] = useState("")

return (
<div>
<h2>Partie!</h2>
<div>{JSON.stringify(props.question)}</div>
<input placeholder="Réponse" onChange={(e) => setAnswer(e.target.value)} />
<button onClick={() => props.sendAnswer(answer)}>Repondre</button>
</div>
)
}
14 changes: 14 additions & 0 deletions src/pages/game/GameReview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Game } from "../../utils/types"

type GameReviewProps = {
game: Game
}

export const GameReview = (props: GameReviewProps) => {
return (
<div>
<h2>Question Review</h2>
<div>{JSON.stringify(props.game.users)}</div>
</div>
)
}
12 changes: 7 additions & 5 deletions src/pages/game/LobbyPlayers.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { GameUser } from "../../utils/types"

type LobbyPlayersProps = {
gameId: string
usernames: string[]
usernames: Record<string, GameUser>
}

export const LobbyPlayers = (props: LobbyPlayersProps) => {
const userIds = Object.keys(props.usernames)

return (
<div>
<h2>Joueurs</h2>
<div>Game id : {props.gameId}</div>
<ul>
{props.usernames.map((username) => (
<li>{username}</li>
{userIds.map((id) => (
<li key={id}>{props.usernames[id].name}</li>
))}
</ul>
</div>
Expand Down
Loading
Loading