Refactor and implemented full game logic

This commit is contained in:
Florian Sylvain
2023-03-08 14:48:05 +01:00
parent 8bce6af70c
commit 3a4f723c85
5 changed files with 184 additions and 70 deletions
-1
View File
@@ -11,7 +11,6 @@
"type-check": "vue-tsc --noEmit" "type-check": "vue-tsc --noEmit"
}, },
"dependencies": { "dependencies": {
"pinia": "^2.0.32",
"vue": "^3.2.47", "vue": "^3.2.47",
"vue-router": "^4.1.6" "vue-router": "^4.1.6"
}, },
-5
View File
@@ -1,5 +0,0 @@
<script setup lang="ts"></script>
<template></template>
<style scoped></style>
+103
View File
@@ -0,0 +1,103 @@
<script setup lang="ts">
import { onMounted, Ref, ref } from "vue"
interface AuthorData {
author: {
id: number
fullname: string
created_at: string
updated_at: string
}
}
interface Painting {
id: number
name: string
image_url: string
link: string
musuemId: number
PaintingAuthor: AuthorData[]
}
const emits = defineEmits(["win", "lose"])
const props = defineProps<{ disabled: boolean }>()
const paintings: Ref<Painting[]> = ref([])
const winningPainting: Ref<Painting> = ref({} as Painting)
function fetchRandomPainting(): Promise<{ paintings: Painting[] }> {
return new Promise((resolve, reject) => {
fetch(`${__APP_ENV__.API_ADDRESS}/paintings/random/4`)
.then((response) => response.json())
.then((data) => resolve(data))
.catch((error) => reject(error))
})
}
async function initPaintings(): Promise<void> {
const fetchedData = await fetchRandomPainting()
paintings.value = fetchedData.paintings
}
function setWinningPainting(): void {
const randomIndex = Math.floor(Math.random() * paintings.value.length)
winningPainting.value = paintings.value[randomIndex]
}
function authorClickHandler(auhtorId: number): void {
if (auhtorId === winningPainting.value.PaintingAuthor[0].author.id) {
emits("win")
} else {
emits("lose")
}
}
async function initGame(): Promise<void> {
await initPaintings()
setWinningPainting()
}
onMounted(async () => {
await initGame()
})
</script>
<template>
<div class="container">
<img :src="winningPainting?.image_url" />
<div class="choices">
<button
v-for="painting of paintings"
@click="() => authorClickHandler(painting.PaintingAuthor[0].author.id)"
type="button"
:disabled="disabled"
>
{{ painting.PaintingAuthor[0].author.fullname }}
</button>
</div>
</div>
</template>
<style scoped>
.container {
display: flex;
flex-direction: column;
gap: 16px;
justify-content: center;
align-items: center;
width: 100%;
}
.container img {
max-width: 100%;
max-height: 400px;
}
.choices {
display: grid;
grid-template: repeat(2, 1fr) / repeat(2, 1fr);
grid-gap: 8px;
width: 100%;
}
</style>
-3
View File
@@ -1,3 +0,0 @@
import { defineStore } from "pinia"
export const useStore = defineStore("store", () => {})
+80 -60
View File
@@ -1,81 +1,101 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, Ref, ref } from "vue" import { onMounted, Ref, ref } from "vue"
import Quizz from "../components/Quizz.vue"
interface AuthorData { const gameMessage = ref("choisissez une réponse")
author: { const gameProgression = ref(1)
id: number const gameProgressionMax = 10
fullname: string const gameScore = ref(0)
created_at: string const gameShouldGoNext = ref(false)
updated_at: string
} function gameHandler(callback: () => void): void {
if (gameShouldGoNext.value) return
gameShouldGoNext.value = true
callback()
} }
interface Painting { function winHandler(): void {
id: number gameMessage.value = "Bonne réponse !"
name: string gameScore.value += 1
image_url: string
link: string
musuemId: number
PaintingAuthor: AuthorData[]
} }
const paintings: Ref<Painting[]> = ref([]) function loseHandler(): void {
const winningPainting: Ref<Painting> = ref({} as Painting) gameMessage.value = "Mauvaise réponse"
const gameMessage = ref("")
function fetchRandomPainting(): Promise<{ paintings: Painting[] }> {
return new Promise((resolve, reject) => {
fetch(`${__APP_ENV__.API_ADDRESS}/paintings/random/4`)
.then((response) => response.json())
.then((data) => resolve(data))
.catch((error) => reject(error))
})
} }
async function initPaintings(): Promise<void> { function nextGame(): void {
const fetchedData = await fetchRandomPainting() if (!gameShouldGoNext.value) return
paintings.value = fetchedData.paintings gameShouldGoNext.value = false
gameMessage.value = "choisissez une réponse"
gameProgression.value += 1
} }
function setWinningPainting(): void { function resetGame(): void {
const randomIndex = Math.floor(Math.random() * paintings.value.length) gameMessage.value = "choisissez une réponse"
winningPainting.value = paintings.value[randomIndex] gameProgression.value = 1
gameScore.value = 0
} }
function authorClickHandler(auhtorId: number): void {
if (auhtorId === winningPainting.value.PaintingAuthor[0].author.id) {
gameMessage.value = "Correct!"
} else {
gameMessage.value = "Wrong!"
}
}
async function initGame(): Promise<void> {
await initPaintings()
setWinningPainting()
gameMessage.value = "What is the author of this painting?"
}
onMounted(async () => {
await initGame()
})
</script> </script>
<template> <template>
<img :src="winningPainting?.image_url" /> <div class="container">
<button <template v-if="gameProgression < gameProgressionMax">
v-for="painting of paintings" <p>Quiz ({{ gameProgression }}/{{ gameProgressionMax }})</p>
@click="() => authorClickHandler(painting.PaintingAuthor[0].author.id)" <h2>Qui a peint cette oeuvre ?</h2>
type="button"
> <Quizz
{{ painting.PaintingAuthor[0].author.fullname }} @win="() => gameHandler(winHandler)"
</button> @lose="() => gameHandler(loseHandler)"
:key="gameProgression"
:disabled="gameShouldGoNext"
></Quizz>
<div class="quizz-footer">
<p>{{ gameMessage }}</p> <p>{{ gameMessage }}</p>
<button type="button" @click="initGame">Next</button> <button type="button" @click="nextGame" :disabled="!gameShouldGoNext">
suivant
</button>
</div>
</template>
<div class="game-over" v-else>
<p>Vous avez {{ gameScore }}/{{ gameProgressionMax }} bonnes réponses !</p>
<button type="button" @click="resetGame">rejouer</button>
</div>
</div>
</template> </template>
<style scoped> <style scoped>
img { .container {
width: 200px; display: flex;
flex-direction: column;
gap: 16px;
width: 100%;
max-width: 350px;
}
.container > p,
.container > h2 {
margin: 0;
}
.container > p {
text-align: center;
}
.quizz-footer {
display: flex;
justify-content: space-between;
align-items: center;
}
.game-over {
display: flex;
flex-direction: column;
gap: 16px;
justify-content: center;
align-items: center;
} }
</style> </style>