diff --git a/src/routes/kahootclone/host/+page.svelte b/src/routes/kahootclone/host/+page.svelte new file mode 100644 index 0000000..6f7a3df --- /dev/null +++ b/src/routes/kahootclone/host/+page.svelte @@ -0,0 +1,29 @@ + + +
+
+ {#if Status.v == "lobby"} + + {:else if Status.v == "started"} + + {/if} +
+
diff --git a/src/routes/kahootclone/host/components/DuringGame/PeopleAwnsered.svelte b/src/routes/kahootclone/host/components/DuringGame/PeopleAwnsered.svelte new file mode 100644 index 0000000..5c02b48 --- /dev/null +++ b/src/routes/kahootclone/host/components/DuringGame/PeopleAwnsered.svelte @@ -0,0 +1,13 @@ + + +
+

{PeopleAwnseredQ.v} out of {Totalplayers.v} have answered the question

+
+
+
+
diff --git a/src/routes/kahootclone/host/components/DuringGame/awnseringQuetions/Awnsers.svelte b/src/routes/kahootclone/host/components/DuringGame/awnseringQuetions/Awnsers.svelte new file mode 100644 index 0000000..0911124 --- /dev/null +++ b/src/routes/kahootclone/host/components/DuringGame/awnseringQuetions/Awnsers.svelte @@ -0,0 +1,24 @@ + + +
+ {#each CurrentQuestionDetails.v.answers as answer, index} +
+ + +
+ {/each} +
diff --git a/src/routes/kahootclone/host/components/DuringGame/awnseringQuetions/ProgressBar.svelte b/src/routes/kahootclone/host/components/DuringGame/awnseringQuetions/ProgressBar.svelte new file mode 100644 index 0000000..34cb551 --- /dev/null +++ b/src/routes/kahootclone/host/components/DuringGame/awnseringQuetions/ProgressBar.svelte @@ -0,0 +1,13 @@ + + +
+

Question {currentQuestion.v + 1} of {totalQuetions.v}

+
+
+
+
diff --git a/src/routes/kahootclone/host/components/DuringGame/awnseringQuetions/display.svelte b/src/routes/kahootclone/host/components/DuringGame/awnseringQuetions/display.svelte new file mode 100644 index 0000000..5643130 --- /dev/null +++ b/src/routes/kahootclone/host/components/DuringGame/awnseringQuetions/display.svelte @@ -0,0 +1,11 @@ + + + + + + + diff --git a/src/routes/kahootclone/host/components/DuringGame/awnseringQuetions/text/Quetion.svelte b/src/routes/kahootclone/host/components/DuringGame/awnseringQuetions/text/Quetion.svelte new file mode 100644 index 0000000..8ba9f89 --- /dev/null +++ b/src/routes/kahootclone/host/components/DuringGame/awnseringQuetions/text/Quetion.svelte @@ -0,0 +1,24 @@ + + +

+ Q{currentQuestion.v + 1}. {CurrentQuestionDetails.v.question} +

+{#if CurrentQuestionDetails.v.media != null} +
+ {#if CurrentQuestionDetails.v.media.match(/\.(mp4|webm|ogg|mov|avi|mkv)$/i)} +
+{/if} diff --git a/src/routes/kahootclone/host/components/DuringGame/display.svelte b/src/routes/kahootclone/host/components/DuringGame/display.svelte new file mode 100644 index 0000000..92a5995 --- /dev/null +++ b/src/routes/kahootclone/host/components/DuringGame/display.svelte @@ -0,0 +1,10 @@ + + +

HOSTING

+ + + \ No newline at end of file diff --git a/src/routes/kahootclone/host/components/DuringGame/timeLeft.svelte b/src/routes/kahootclone/host/components/DuringGame/timeLeft.svelte new file mode 100644 index 0000000..147daaa --- /dev/null +++ b/src/routes/kahootclone/host/components/DuringGame/timeLeft.svelte @@ -0,0 +1,15 @@ + + +{#if TotalTimeLeft.v != null} +
+

{timeLeft.v}sec out of {TotalTimeLeft.v}secs is left

+
+
+
+
+{/if} diff --git a/src/routes/kahootclone/host/components/lobby/PlayersGUI/playerBadge.svelte b/src/routes/kahootclone/host/components/lobby/PlayersGUI/playerBadge.svelte new file mode 100644 index 0000000..ced3664 --- /dev/null +++ b/src/routes/kahootclone/host/components/lobby/PlayersGUI/playerBadge.svelte @@ -0,0 +1,6 @@ + + +{playerName} diff --git a/src/routes/kahootclone/host/components/lobby/PlayersGUI/players.svelte b/src/routes/kahootclone/host/components/lobby/PlayersGUI/players.svelte new file mode 100644 index 0000000..de8b651 --- /dev/null +++ b/src/routes/kahootclone/host/components/lobby/PlayersGUI/players.svelte @@ -0,0 +1,12 @@ + + +

Players Joined:

+

(Total Players: {players.v.length})

+
+ {#each players.v as playerName} + + {/each} +
diff --git a/src/routes/kahootclone/host/components/lobby/buttons/startGame.svelte b/src/routes/kahootclone/host/components/lobby/buttons/startGame.svelte new file mode 100644 index 0000000..4c6e8ac --- /dev/null +++ b/src/routes/kahootclone/host/components/lobby/buttons/startGame.svelte @@ -0,0 +1,12 @@ + + + diff --git a/src/routes/kahootclone/host/components/lobby/display.svelte b/src/routes/kahootclone/host/components/lobby/display.svelte new file mode 100644 index 0000000..495fee0 --- /dev/null +++ b/src/routes/kahootclone/host/components/lobby/display.svelte @@ -0,0 +1,15 @@ + + +

HOSTING

+

Game Pin:

+

+ {gamePin.v} +

+ + diff --git a/src/routes/kahootclone/host/logic/GameOver.js b/src/routes/kahootclone/host/logic/GameOver.js new file mode 100644 index 0000000..f0275b0 --- /dev/null +++ b/src/routes/kahootclone/host/logic/GameOver.js @@ -0,0 +1,7 @@ +import { supabase } from "$lib/supabase.js"; + +export async function GameOver(GamePin) { + await supabase.from("games").update({ status: `completed` }).eq("gamepin", GamePin); + + window.location.replace("/kahootclone/results?gamepin=" + GamePin + "&playerID=host-null"); +} diff --git a/src/routes/kahootclone/host/logic/GetCurrentPlayers.js b/src/routes/kahootclone/host/logic/GetCurrentPlayers.js new file mode 100644 index 0000000..5761345 --- /dev/null +++ b/src/routes/kahootclone/host/logic/GetCurrentPlayers.js @@ -0,0 +1,17 @@ +import { supabase } from "$lib/supabase.js"; +import toast from "svelte-5-french-toast"; +import { players } from "./HostsData.svelte.js"; + +export async function GetCurrentPlayers(gamePin) { + const { data, error } = await supabase + .from("players") + .select("playername") + .eq("gameid", Number(gamePin)); + + if (error) { + toast.error("Error fetching players: " + error.message); + return; + } + + players.v = data ? data.map((player) => player.playername) : []; +} diff --git a/src/routes/kahootclone/host/logic/HostsData.svelte.js b/src/routes/kahootclone/host/logic/HostsData.svelte.js new file mode 100644 index 0000000..32a0c5a --- /dev/null +++ b/src/routes/kahootclone/host/logic/HostsData.svelte.js @@ -0,0 +1,15 @@ +export let players = $state({ v: [] }); +export let Status = $state({ v: "lobby" }); +export let questions = { v: {} }; + +export let currentQuestion = $state({ v: 0 }); +export let totalQuetions = $state({ v: 3 }); +export let PeopleAwnseredQ = $state({ v: 0 }); +export let Totalplayers = $state({ v: 3 }); + +export let CurrentQuestionDetails = $state({ v: {} }); + +export let gamePin = $state({ v: "" }); + +export let timeLeft = $state({ v: 0 }); +export let TotalTimeLeft = $state({ v: 0 }); \ No newline at end of file diff --git a/src/routes/kahootclone/host/logic/UpdatePlayersList.js b/src/routes/kahootclone/host/logic/UpdatePlayersList.js new file mode 100644 index 0000000..757ca4b --- /dev/null +++ b/src/routes/kahootclone/host/logic/UpdatePlayersList.js @@ -0,0 +1,26 @@ +import { supabase } from "$lib/supabase.js"; +import { players } from "./HostsData.svelte.js"; + +export let LobbyConnection; + +function onNewPlayer(Newplayers) { + players.v.push(Newplayers.playername); +} + +export async function AutoUpdatePlayersList(gamePin) { + LobbyConnection = supabase + .channel("players-realtime") + .on( + "postgres_changes", + { + event: "INSERT", + schema: "public", + table: "players", + filter: `gameid=eq.${gamePin}`, + }, + (payload) => { + onNewPlayer(payload.new); + }, + ) + .subscribe(); +} diff --git a/src/routes/kahootclone/host/logic/WaitForAwnser.js b/src/routes/kahootclone/host/logic/WaitForAwnser.js new file mode 100644 index 0000000..f640f66 --- /dev/null +++ b/src/routes/kahootclone/host/logic/WaitForAwnser.js @@ -0,0 +1,85 @@ +import { supabase } from "$lib/supabase.js"; +import { onNewPlayerAwnsered } from "./onNewPlayerAwnsered.js"; +import { + currentQuestion, + questions, + CurrentQuestionDetails, + TotalTimeLeft, + timeLeft, + PeopleAwnseredQ, + totalQuetions, +} from "./HostsData.svelte.js"; +import { GameOver } from "./GameOver.js"; + +let WaitingForAwnserConection; +let TimeLimitInterval; + +export async function WaitForAwnser(questionid, gamePin) { + if (questionid != 0) { + await supabase.removeChannel(WaitingForAwnserConection); + clearInterval(TimeLimitInterval); + } + + await supabase + .from("games") + .update({ status: `question-${currentQuestion.v}` }) + .eq("gamepin", gamePin); + + WaitingForAwnserConection = supabase + .channel("answeredby-realtime") + .on( + "postgres_changes", + { + event: "INSERT", + schema: "public", + table: "answeredby", + filter: `questionid=eq.${questions.v[questionid].id}`, + }, + (payload) => { + onNewPlayerAwnsered(gamePin); + }, + ) + .subscribe(); + + const { data: questionsData } = await supabase + .from("questions") + .select("*") + .eq("gameid", Number(gamePin)) + .order("id", { ascending: true }); + + const { data: answers } = await supabase + .from("answers") + .select("content") + .eq("questionid", Number(questionsData[currentQuestion.v].id)) + .order("id", { ascending: true }); + + CurrentQuestionDetails.v = { + question: questionsData[currentQuestion.v].questionstext, + correctAnswer: questionsData[currentQuestion.v].correctanswer, + answers: answers.map((answer) => answer.content), + questionid: questionsData[currentQuestion.v].id, + media: questionsData[currentQuestion.v].media || null, + timeLimit: questionsData[currentQuestion.v].timelimit, + }; + + TotalTimeLeft.v = CurrentQuestionDetails.v.timeLimit; + timeLeft.v = CurrentQuestionDetails.v.timeLimit; + + if (TotalTimeLeft.v != null) { + TimeLimitInterval = setInterval(() => { + if (timeLeft.v > 0) { + timeLeft.v--; + } else { + supabase.removeChannel(WaitingForAwnserConection); + currentQuestion.v++; + if (currentQuestion.v == totalQuetions.v) { + //GameOver(gamePin); + return; + } + PeopleAwnseredQ.v = 0; + + WaitForAwnser(currentQuestion.v, gamePin); + } + }, 1000); + } +} diff --git a/src/routes/kahootclone/host/logic/onNewPlayerAwnsered.js b/src/routes/kahootclone/host/logic/onNewPlayerAwnsered.js new file mode 100644 index 0000000..8c1176d --- /dev/null +++ b/src/routes/kahootclone/host/logic/onNewPlayerAwnsered.js @@ -0,0 +1,23 @@ +import { + Totalplayers, + PeopleAwnseredQ, + currentQuestion, + totalQuetions, +} from "./HostsData.svelte.js"; +import { GameOver } from "./GameOver.js"; +import { WaitForAwnser } from "./WaitForAwnser.js"; + +export async function onNewPlayerAwnsered(GamePin) { + PeopleAwnseredQ.v++; + + if (PeopleAwnseredQ.v == Totalplayers.v) { + currentQuestion.v++; + if (currentQuestion.v == totalQuetions.v) { + GameOver(GamePin); + return; + } + PeopleAwnseredQ.v = 0; + + WaitForAwnser(currentQuestion.v, GamePin); + } +} diff --git a/src/routes/kahootclone/host/logic/startGame.js b/src/routes/kahootclone/host/logic/startGame.js new file mode 100644 index 0000000..a54e163 --- /dev/null +++ b/src/routes/kahootclone/host/logic/startGame.js @@ -0,0 +1,38 @@ +import { supabase } from "$lib/supabase.js"; +import { LobbyConnection } from "./UpdatePlayersList.js"; +import { questions, Status, Totalplayers, totalQuetions, players } from "./HostsData.svelte.js"; +import { WaitForAwnser } from "./WaitForAwnser.js"; +import toast from "svelte-5-french-toast"; + +export async function startGame(gamePin) { + if (players.v.length == 0) { + toast.error("you need at least 1 person to start the game!"); + return; + + + } + + await supabase.removeChannel(LobbyConnection); + + Status.v = "started"; + + const { data } = await supabase + .from("questions") + .select("*") + .eq("gameid", Number(gamePin)) + .order("id", { ascending: true }); + + questions.v = data; + + totalQuetions.v = data.length; + + const { data: playersData } = await supabase + .from("players") + .select("id") + .eq("gameid", Number(gamePin)) + .order("id", { ascending: true }); + + Totalplayers.v = playersData.length; + + WaitForAwnser(0, gamePin); +}