Merge branch 'main' of https://github.com/RezHackXYZ/KahootClone
This commit is contained in:
commit
caff3cef7c
4 changed files with 327 additions and 0 deletions
109
src/routes/hostgame/[gamePin]/+page.svelte
Normal file
109
src/routes/hostgame/[gamePin]/+page.svelte
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
<script>
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import { supabase } from '$lib/supabase';
|
||||||
|
|
||||||
|
export let data;
|
||||||
|
const gamePin = data.gamePin;
|
||||||
|
|
||||||
|
let totalQuetions = 3;
|
||||||
|
let currentQuestion = 0;
|
||||||
|
|
||||||
|
let PeopleAwnseredQ = 2;
|
||||||
|
let Totalplayers = 3;
|
||||||
|
|
||||||
|
let questions = [];
|
||||||
|
|
||||||
|
async function NewUpdate(question) {
|
||||||
|
if (question[currentQuestion].playersCompelted == Totalplayers) {
|
||||||
|
currentQuestion++;
|
||||||
|
|
||||||
|
if (currentQuestion > questions.length) {
|
||||||
|
await supabase
|
||||||
|
.from('games')
|
||||||
|
.update({ gameStatus: `completed` })
|
||||||
|
.eq('gamePIN', Number(data.gamePin));
|
||||||
|
goto(`/results/${gamePin}`);
|
||||||
|
} else {
|
||||||
|
await supabase
|
||||||
|
.from('games')
|
||||||
|
.update({ gameStatus: `${currentQuestion}` })
|
||||||
|
.eq('gamePIN', Number(data.gamePin));
|
||||||
|
}
|
||||||
|
|
||||||
|
PeopleAwnseredQ = 0;
|
||||||
|
} else {
|
||||||
|
PeopleAwnseredQ = question[currentQuestion].playersCompelted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
const channel = supabase
|
||||||
|
.channel(`game-${gamePin}`)
|
||||||
|
.on(
|
||||||
|
'postgres_changes',
|
||||||
|
{
|
||||||
|
event: 'UPDATE',
|
||||||
|
schema: 'public',
|
||||||
|
table: 'games',
|
||||||
|
filter: `gamePIN=eq.${gamePin}`
|
||||||
|
},
|
||||||
|
(payload) => {
|
||||||
|
if (payload.new.questions != questions) {
|
||||||
|
questions = payload.new.questions;
|
||||||
|
currentQuestion = Number(payload.new.gameStatus);
|
||||||
|
NewUpdate(questions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.subscribe();
|
||||||
|
|
||||||
|
const { data, error } = await supabase
|
||||||
|
.from('games')
|
||||||
|
.select('players')
|
||||||
|
.eq('gamePIN', Number(gamePin))
|
||||||
|
.single();
|
||||||
|
|
||||||
|
Totalplayers = data.players.length;
|
||||||
|
|
||||||
|
const { data: data2, error: error2 } = await supabase
|
||||||
|
.from('games')
|
||||||
|
.select('questions')
|
||||||
|
.eq('gamePIN', Number(gamePin))
|
||||||
|
.single();
|
||||||
|
|
||||||
|
questions = data2.questions;
|
||||||
|
totalQuetions = questions.length;
|
||||||
|
|
||||||
|
currentQuestion = 0;
|
||||||
|
await supabase
|
||||||
|
.from('games')
|
||||||
|
.update({ gameStatus: currentQuestion.toString() })
|
||||||
|
.eq('gamePIN', Number(gamePin));
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="bg-grey-900 flex h-full items-center justify-center">
|
||||||
|
<div
|
||||||
|
class="flex max-w-[700px] flex-col items-center justify-center gap-1 rounded-lg bg-gray-900 p-8 shadow-lg"
|
||||||
|
>
|
||||||
|
<h1 class="m-[0] text-7xl">HOSTING</h1>
|
||||||
|
<div class="mt-1 mb-3 flex w-full flex-col rounded-2xl border-2 border-green-400 p-2">
|
||||||
|
<h3>Question {currentQuestion + 1} of {totalQuetions} is beeing awnsered</h3>
|
||||||
|
<div class="flex-1 rounded-full border-2 border-gray-600">
|
||||||
|
<div
|
||||||
|
class="h-4 rounded-full bg-green-600 transition-all duration-700"
|
||||||
|
style="width: {(currentQuestion / totalQuetions) * 100}%;"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-1 mb-3 flex w-full flex-col rounded-2xl border-2 border-green-400 p-2">
|
||||||
|
<h3>{PeopleAwnseredQ} out of {Totalplayers} have awnsered the quetion</h3>
|
||||||
|
<div class="flex-1 rounded-full border-2 border-gray-600">
|
||||||
|
<div
|
||||||
|
class="h-4 rounded-full bg-green-600 transition-all duration-700"
|
||||||
|
style="width: {(PeopleAwnseredQ / Totalplayers) * 100}%;"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
142
src/routes/play/[gamePin]/+page.svelte
Normal file
142
src/routes/play/[gamePin]/+page.svelte
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
<script>
|
||||||
|
import { supabase } from '$lib/supabase';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
export let data;
|
||||||
|
const gamePin = data.gamePin;
|
||||||
|
import { page } from '$app/stores';
|
||||||
|
const name = $page.state?.name;
|
||||||
|
|
||||||
|
let question = [];
|
||||||
|
let Selected = null;
|
||||||
|
let currentQuestion = 0;
|
||||||
|
let isWait = true;
|
||||||
|
let gameStatus = '';
|
||||||
|
let players = [];
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
const channel = supabase
|
||||||
|
.channel(`game-${gamePin}`)
|
||||||
|
.on(
|
||||||
|
'postgres_changes',
|
||||||
|
{
|
||||||
|
event: 'UPDATE',
|
||||||
|
schema: 'public',
|
||||||
|
table: 'games',
|
||||||
|
filter: `gamePIN=eq.${gamePin}`
|
||||||
|
},
|
||||||
|
(payload) => {
|
||||||
|
if (payload.new.gameStatus != gameStatus) {
|
||||||
|
if (payload.new.questions == 'completed') {
|
||||||
|
goto(`/results/${gamePin}`, {
|
||||||
|
state: {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
gameStatus = payload.new.gameStatus;
|
||||||
|
isWait = false;
|
||||||
|
Selected = null;
|
||||||
|
currentQuestion = Number(gameStatus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.subscribe();
|
||||||
|
|
||||||
|
const { data, error } = await supabase
|
||||||
|
.from('games')
|
||||||
|
.select('questions')
|
||||||
|
.eq('gamePIN', Number(gamePin))
|
||||||
|
.single();
|
||||||
|
|
||||||
|
if (!error && data) {
|
||||||
|
question = data.questions || [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function SubmitAnswer() {
|
||||||
|
isWait = true;
|
||||||
|
|
||||||
|
const { data, error } = await supabase
|
||||||
|
.from('games')
|
||||||
|
.select('players')
|
||||||
|
.eq('gamePIN', Number(gamePin))
|
||||||
|
.single();
|
||||||
|
players = data.players;
|
||||||
|
|
||||||
|
if (question[currentQuestion].correctAnswer == Selected) {
|
||||||
|
players.forEach((player) => {
|
||||||
|
if (player.name == name) {
|
||||||
|
player.score += 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await supabase.from('games').update({ players: players }).eq('gamePIN', Number(gamePin));
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data: data2 } = await supabase
|
||||||
|
.from('games')
|
||||||
|
.select('questions')
|
||||||
|
.eq('gamePIN', Number(gamePin))
|
||||||
|
.single();
|
||||||
|
|
||||||
|
question = data2.questions;
|
||||||
|
|
||||||
|
question[currentQuestion].playersCompelted++;
|
||||||
|
console.log('Players Completed:', question[currentQuestion].playersCompelted);
|
||||||
|
|
||||||
|
await supabase.from('games').update({ questions: question }).eq('gamePIN', Number(gamePin));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="bg-grey-900 flex h-full items-center justify-center">
|
||||||
|
<div
|
||||||
|
class="flex max-w-[700px] flex-col items-center justify-center gap-1 rounded-lg bg-gray-900 p-8 shadow-lg"
|
||||||
|
>
|
||||||
|
<div class="mb-5 flex w-full items-center justify-center gap-3">
|
||||||
|
<h3>Question {currentQuestion + 1} of {question.length}</h3>
|
||||||
|
<div class="flex-1 rounded-full border-2 border-gray-600">
|
||||||
|
<div
|
||||||
|
class="h-4 rounded-full bg-green-600 transition-all duration-700"
|
||||||
|
style="width: {(currentQuestion / question.length) * 100}%;"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{#if isWait != true}
|
||||||
|
<h1 class="m-[0] text-center text-5xl">
|
||||||
|
Q{currentQuestion + 1}. {question[currentQuestion].name}
|
||||||
|
</h1>
|
||||||
|
<div class="mt-5 grid grid-cols-2 gap-5 gap-x-3">
|
||||||
|
{#each question[currentQuestion].answers as answer, index}
|
||||||
|
<div class="flex">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
id="O{index}"
|
||||||
|
name="question"
|
||||||
|
class="peer sr-only"
|
||||||
|
value={index}
|
||||||
|
bind:group={Selected}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
class="w-full cursor-pointer rounded-lg border-3 border-gray-600 bg-gray-600 pt-1 pr-2 pb-1 pl-2 text-center text-3xl transition-all peer-checked:border-blue-600 peer-checked:bg-blue-600 hover:border-blue-600"
|
||||||
|
for="O{index}">{answer}</label
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{#if Selected != null}
|
||||||
|
<button
|
||||||
|
class="mt-4 cursor-pointer gap-0 rounded-lg bg-green-700 p-2 text-3xl transition-all hover:scale-110 hover:-rotate-10"
|
||||||
|
onclick={SubmitAnswer}
|
||||||
|
>submit answer
|
||||||
|
</button>
|
||||||
|
{:else}
|
||||||
|
<button
|
||||||
|
class="mt-4 cursor-pointer gap-0 rounded-lg bg-gray-700 p-2 text-3xl transition-all hover:scale-110"
|
||||||
|
>select an answer to submit!
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
{:else}<h1 class="m-[0] text-center text-5xl">
|
||||||
|
Please wait for everyone else to answer the question.
|
||||||
|
</h1>{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
5
src/routes/results/[gamePin]/+page.js
Normal file
5
src/routes/results/[gamePin]/+page.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export function load({ params }) {
|
||||||
|
return {
|
||||||
|
gamePin: params.gamePin
|
||||||
|
};
|
||||||
|
}
|
71
src/routes/results/[gamePin]/+page.svelte
Normal file
71
src/routes/results/[gamePin]/+page.svelte
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
<script>
|
||||||
|
import { supabase } from '$lib/supabase';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
export let data;
|
||||||
|
const gamePin = data.gamePin;
|
||||||
|
import { page } from '$app/stores';
|
||||||
|
let name = '';
|
||||||
|
name = $page.state?.name;
|
||||||
|
|
||||||
|
let players = [];
|
||||||
|
onMount(async () => {
|
||||||
|
const { data } = await supabase
|
||||||
|
.from('games')
|
||||||
|
.select('players')
|
||||||
|
.eq('gamePIN', Number(gamePin))
|
||||||
|
.single();
|
||||||
|
|
||||||
|
players = data.players;
|
||||||
|
|
||||||
|
players.sort((a, b) => b.score - a.score);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="bg-grey-900 flex h-full items-center justify-center">
|
||||||
|
<div
|
||||||
|
class="flex max-w-[700px] flex-col items-center justify-center gap-1 rounded-lg bg-gray-900 p-8 shadow-lg"
|
||||||
|
>
|
||||||
|
<h1 class="mb-3 text-7xl font-bold text-white">Leaderboard</h1>
|
||||||
|
|
||||||
|
{#if players}
|
||||||
|
{#each players as player, i}
|
||||||
|
{#if name == player.name}
|
||||||
|
<div class="flex w-full items-center justify-between rounded-lg bg-green-950 p-2">
|
||||||
|
<div class="mr-2 flex h-6 w-6 items-center justify-center rounded-full bg-gray-500">
|
||||||
|
{i + 1}
|
||||||
|
</div>
|
||||||
|
<div class="w-20 text-white">{player.name}</div>
|
||||||
|
<div class="flex-1 rounded-full border-2 border-gray-600">
|
||||||
|
<div
|
||||||
|
class="flex h-6 items-center justify-center rounded-full bg-green-600 transition-all duration-700"
|
||||||
|
style="width: {(player.score / players[0].score) * 100}%;"
|
||||||
|
>
|
||||||
|
<div>{player.score} points</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{:else}<div class="flex w-full items-center justify-between rounded-lg bg-gray-800 p-2">
|
||||||
|
<div class="mr-2 flex h-6 w-6 items-center justify-center rounded-full bg-gray-500">
|
||||||
|
{i + 1}
|
||||||
|
</div>
|
||||||
|
<div class="w-20 text-white">{player.name}</div>
|
||||||
|
<div class="flex-1 rounded-full border-2 border-gray-600">
|
||||||
|
<div
|
||||||
|
class="flex h-6 items-center justify-center rounded-full bg-green-600 transition-all duration-700"
|
||||||
|
style="width: {(player.score / players[0].score) * 100}%;"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
<div class="flex w-17 justify-end">{player.score} points</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="mt-4 cursor-pointer rounded-full bg-green-700 p-2 transition-all hover:scale-110 hover:-rotate-10"
|
||||||
|
on:click={joinGame}
|
||||||
|
>
|
||||||
|
Go back to the home page!
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
Loading…
Add table
Add a link
Reference in a new issue