made the loby working using the newer rDB and makeing everything to bbe better manageable by using folders and more components!

This commit is contained in:
RezHackXYZ 2025-05-17 13:57:02 +05:30
parent 2b9b5c3b39
commit d3e0f3406e
No known key found for this signature in database
37 changed files with 417 additions and 159 deletions

View file

@ -1,7 +1,7 @@
{
"useTabs": true,
"singleQuote": false,
"trailingComma": "all",
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
"overrides": [

View file

@ -11,6 +11,8 @@
"gamepin",
"hostgame",
"kahoot",
"kahootclone",
"Newplayers",
"playername",
"questionid",
"questionstext",

View file

@ -33,6 +33,11 @@
int QuestionID FK
string content
}
ANSWEREDBY {
int ID PK
int QuestionID FK
string NameOfAnswerer
}
PLAYERS {
int ID PK
int GameID FK
@ -40,6 +45,9 @@
}
GAMES ||--o{ QUESTIONS : contains
QUESTIONS ||--o{ ANSWERS : has
GAMES ||--o{ PLAYERS : participated_by
QUESTIONS ||--o{ ANSWERS : has_answers
QUESTIONS ||--o{ ANSWEREDBY : has_answeredby
GAMES ||--o{ PLAYERS : has_players
```

View file

@ -3,9 +3,10 @@
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"moduleResolution": "bundler"
"moduleResolution": "bundler","target": "es2015",
"module": "es2015",
"types": ["svelte"]
},
"exclude": [
"node_modules"
]
"include": ["src/**/*"],
"exclude": ["node_modules/*"],
}

View file

@ -15,9 +15,7 @@
"@sveltejs/adapter-auto": "^4.0.0",
"@sveltejs/kit": "^2.16.0",
"@sveltejs/vite-plugin-svelte": "^5.0.0",
"@tailwindcss/postcss": "^4.1.6",
"@tailwindcss/vite": "^4.0.0",
"autoprefixer": "^10.4.21",
"eslint-config-prettier": "^10.0.1",
"prettier": "^3.4.2",
"prettier-plugin-svelte": "^3.3.3",
@ -25,8 +23,5 @@
"svelte": "^5.0.0",
"tailwindcss": "^4.0.0",
"vite": "^6.0.0"
},
"dependencies": {
"@supabase/supabase-js": "^2.49.4"
}
}

1
src/app.css Normal file
View file

@ -0,0 +1 @@
@import 'tailwindcss';

View file

@ -1,12 +1,12 @@
<!doctype html>
<html lang="en" style="height: 100%; margin: 0">
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover" style="height: 100%; margin: 0">
<div style="display: contents; height: 100%">%sveltekit.body%</div>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>

View file

@ -1,13 +1,6 @@
<script>
import '../app.css';
let { children } = $props();
</script>
<div class="h-full text-white">{@render children()}</div>
<style>
@import 'tailwindcss';
:root {
background-color: black;
}
</style>
{@render children()}

View file

@ -1,18 +1,2 @@
<div class="bg-grey-900 flex h-full items-center justify-center">
<div class="flex flex-col items-center justify-center gap-1 rounded-lg bg-gray-900 p-8 shadow-lg">
<h1 class="m-[0] text-6xl">DaKahootClone</h1>
<p class="m-[0] mb-2 text-lg text-gray-400">The best ever kahoot clone.</p>
<a href="./join">
<button
class="cursor-pointer rounded-full bg-green-700 p-2 transition-all hover:scale-110 hover:-rotate-10"
>Join a game</button
></a
>
<a href="./create">
<button
class="cursor-pointer rounded-full bg-blue-700 p-2 transition-all hover:scale-110 hover:-rotate-10"
>Create and Host a game</button
>
</a>
</div>
</div>
<h1>Welcome to SvelteKit</h1>
<p>Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the documentation</p>

View file

@ -1,46 +1,18 @@
<script>
import { onMount } from 'svelte';
import { page } from '$app/stores';
import { supabase } from '$lib/supabase';
import { goto } from '$app/navigation';
import PlayingDisplay from "./components/DuringGame/display.svelte";
import LobbyDisplay from "./components/lobby/display.svelte";
import { Status } from "./logic/HostsData.svelte.js";
import { AutoUpdatePlayersList } from "./logic/UpdatePlayersList.js";
import { GetCurrentPlayers } from "./logic/GetCurrentPlayers.js";
import { onMount } from "svelte";
export let data;
const gamePin = data.gamePin;
let players = [];
// Subscribe to realtime changes in players
function subscribeToPlayers() {
const channel = supabase
.channel(`game-${gamePin}`)
.on(
'postgres_changes',
{
event: 'UPDATE',
schema: 'public',
table: 'games',
filter: `gamePIN=eq.${gamePin}`
},
(payload) => {
players = payload.new.players || [];
}
)
.subscribe();
}
onMount(async () => {
const { data: gameData } = await supabase
.from('games')
.select('players')
.eq('gamePIN', Number(gamePin))
.maybeSingle();
if (gameData?.players) {
players = gameData.players;
}
subscribeToPlayers();
onMount(() => {
GetCurrentPlayers(gamePin);
AutoUpdatePlayersList(gamePin);
});
</script>
@ -48,35 +20,10 @@
<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-9xl">HOSTING</h1>
<h1 class="m-[0] text-7xl">Game Pin:</h1>
<h1 class="m-[0] rounded-2xl bg-gray-700 pt-1.5 pr-2 pb-0 pl-2 font-mono text-5xl">
{gamePin}
</h1>
<h1 class="m-[0] mt-10 text-6xl">Players Joined:</h1>
<h1 class="m-[0] text-4xl text-gray-400">(Total Players: {players.length})</h1>
<div class="mt-2 flex flex-wrap justify-center gap-2">
{#each players as player}
<span class="m-[0] rounded-xl bg-gray-700 pt-1 pr-2 pb-0 pl-2 font-mono text-3xl"
>{player.name}</span
>
{/each}
</div>
<button
class="mt-5 cursor-pointer rounded-2xl bg-green-700 p-2 text-4xl transition-all hover:scale-110 hover:-rotate-10"
on:click={async () => {
if (players.length > 0) {
if (confirm('Are you sure you want to start the game?')) {
await supabase
.from('games')
.update({ gameStatus: 'started' })
.eq('gamePIN', Number(data.gamePin));
goto(`/hostgame/${gamePin}`);
}
} else {
alert('You need at least one player to start the game.');
}
}}>Start the game</button
>
{#if Status.v == "lobby"}
<LobbyDisplay {gamePin} />
{:else if Status.v == "started"}
<PlayingDisplay />
{/if}
</div>
</div>

View file

@ -0,0 +1,13 @@
<script>
import { PeopleAwnseredQ, Totalplayers } from "./../../logic/HostsData.svelte.js";
</script>
<div class="mt-1 mb-3 flex w-full flex-col rounded-2xl border-2 border-green-400 p-2">
<h3>{PeopleAwnseredQ.v} out of {Totalplayers.v} 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-500"
style="width: {(PeopleAwnseredQ.v / Totalplayers.v) * 100}%;"
></div>
</div>
</div>

View file

@ -0,0 +1,13 @@
<script>
import { currentQuestion, totalQuetions } from "./../../logic/HostsData.svelte.js";
</script>
<div class="mt-1 mb-3 flex w-full flex-col rounded-2xl border-2 border-green-400 p-2">
<h3>Question {currentQuestion.v + 1} of {totalQuetions.v} 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-500"
style="width: {(currentQuestion.v + 1 / totalQuetions.v) * 100}%;"
></div>
</div>
</div>

View file

@ -0,0 +1,9 @@
<script>
import PeopleAwnsered from "./PeopleAwnsered.svelte";
import QuetionsAwnsred from "./QuetionsAwnsred.svelte";
</script>
<h1 class="m-[0] text-7xl">HOSTING</h1>
<QuetionsAwnsred />
<PeopleAwnsered />

View file

@ -0,0 +1,6 @@
<script>
let props = $props();
let playerName = props.playerName;
</script>
<span class="m-[0] rounded-xl bg-gray-700 pt-1 pr-2 pb-0 pl-2 font-mono text-3xl">{playerName}</span>

View file

@ -0,0 +1,12 @@
<script>
import { players } from "../../../logic/HostsData.svelte.js";
import PlayerBadge from "./playerBadge.svelte";
</script>
<h1 class="m-[0] mt-10 text-6xl">Players Joined:</h1>
<h1 class="m-[0] text-4xl text-gray-400">(Total Players: {players.v.length})</h1>
<div class="mt-2 flex flex-wrap justify-center gap-2">
{#each players.v as playerName}
<PlayerBadge {playerName} />
{/each}
</div>

View file

@ -0,0 +1,12 @@
<script>
import { startGame } from "../../../logic/startGame.js";
let props = $props();
</script>
<button
class="mt-5 cursor-pointer rounded-2xl bg-green-700 p-2 text-4xl transition-all hover:scale-110 hover:-rotate-10"
onclick={() => {
startGame(props.gamePin);
}}>Start the game</button
>

View file

@ -0,0 +1,15 @@
<script>
import StartGame from "./buttons/startGame.svelte";
import Players from "./PlayersGUI/players.svelte";
let props = $props();
let gamePin = props.gamePin;
</script>
<h1 class="m-[0] text-9xl">HOSTING</h1>
<h1 class="m-[0] text-7xl">Game Pin:</h1>
<h1 class="m-[0] rounded-2xl bg-gray-700 pt-1.5 pr-2 pb-0 pl-2 font-mono text-5xl">
{gamePin}
</h1>
<Players />
<StartGame {gamePin} />

View file

@ -0,0 +1,18 @@
import { supabase } from "$lib/supabase.js";
import { players } from "./HostsData.svelte.js";
export async function GetCurrentPlayers(gamePin) {
const { data, error } = await supabase
.from("players")
.select("playername")
.eq("gameid", Number(gamePin));
console.log("Current players data:", JSON.stringify(data));
if (error) {
console.error("Error fetching players:", error);
return;
}
players.v = data ? data.map(player => player.playername) : [];
}

View file

@ -0,0 +1,9 @@
export let players = $state({ v: [] });
export let Status = $state({ v: "lobby" });
export let questions = $state({ v: [] });
export let CurrentQuestion = $state({ v: -1 });
export let currentQuestion = $state({ v: 0 });
export let totalQuetions = $state({ v: 3 });
export let PeopleAwnseredQ = $state({ v: 0 });
export let Totalplayers = $state({ v: 3 });

View file

@ -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();
}

View file

@ -0,0 +1,25 @@
import { supabase } from "$lib/supabase.js";
import { LobbyConnection } from "./UpdatePlayersList.js";
import { questions, Status, CurrentQuestion, currentQuestion } from "./HostsData.svelte.js";
export async function startGame(gamePin) {
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;
CurrentQuestion.v = 0;
await supabase
.from("games")
.update({ status: `question-${currentQuestion.v}` })
.eq("gamepin", gamePin);
}

View file

@ -1,13 +1,15 @@
<script>
import { joinGame } from './logic/joinGame.js';
import { Checking } from './logic/JoinGameData.svelte.js';
import { joinGame } from "./logic/joinGame.js";
import { Checking } from "./logic/JoinGameData.svelte.js";
let pin;
let name;
</script>
<div class="bg-grey-900 flex h-full items-center justify-center">
<div class="flex flex-col items-center justify-center gap-1 rounded-lg bg-gray-900 p-7 shadow-lg">
<div
class="flex flex-col items-center justify-center gap-1 rounded-lg bg-gray-900 p-7 shadow-lg"
>
<h1 class="m-[0] mb-3 text-5xl">Join a game here</h1>
<input
@ -33,9 +35,9 @@
class="mt-2 cursor-pointer rounded-full bg-green-700 p-2 transition-all hover:scale-110 hover:-rotate-10"
on:click={() => {
if (!pin || !name) {
alert('Please fill in the game pin and your name.');
alert("Please fill in the game pin and your name.");
} else {
joinGame();
joinGame(pin, name);
}
}}
>

View file

@ -1,20 +1,22 @@
import { goto } from '$app/navigation';
import { addPlayer } from './InsertPlayerInDB.js';
import { validateGamePin } from './validateGamePin.js';
import { Checking} from "./JoinGameData.svelte.js"
import { goto } from "$app/navigation";
import { addPlayer } from "./InsertPlayerInDB.js";
import { validateGamePin } from "./validateGamePin.js";
import { Checking } from "./JoinGameData.svelte.js";
export async function joinGame(pin, name) {
Checking.v = true;
if (!(await validateGamePin())) {
alert('Invalid game pin. Please try again.');
if (!(await validateGamePin(pin))) {
alert("Invalid game pin. Please try again.");
Checking.v = false;
return;
}
addPlayer(name, pin);
goto('/play/' + pin, {
state: { name }
Checking.v = false;
goto("/play/" + pin, {
state: { name },
});
}

View file

@ -0,0 +1,29 @@
<script>
import PlayingDisplay from "./components/DuringGame/display.svelte";
import LobbyDisplay from "./components/lobby/display.svelte";
import { Status } from "./logic/HostsData.svelte.js";
import { AutoUpdatePlayersList } from "./logic/UpdatePlayersList.js";
import { GetCurrentPlayers } from "./logic/GetCurrentPlayers.js";
import { onMount } from "svelte";
export let data;
const gamePin = data.gamePin;
onMount(() => {
GetCurrentPlayers(gamePin);
AutoUpdatePlayersList(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"
>
{#if Status.v == "lobby"}
<LobbyDisplay {gamePin} />
{:else if Status.v == "started"}
<PlayingDisplay />
{/if}
</div>
</div>

View file

@ -0,0 +1,13 @@
<script>
import { PeopleAwnseredQ, Totalplayers } from "./../../logic/HostsData.svelte.js";
</script>
<div class="mt-1 mb-3 flex w-full flex-col rounded-2xl border-2 border-green-400 p-2">
<h3>{PeopleAwnseredQ.v} out of {Totalplayers.v} 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-500"
style="width: {(PeopleAwnseredQ.v / Totalplayers.v) * 100}%;"
></div>
</div>
</div>

View file

@ -0,0 +1,13 @@
<script>
import { currentQuestion, totalQuetions } from "./../../logic/HostsData.svelte.js";
</script>
<div class="mt-1 mb-3 flex w-full flex-col rounded-2xl border-2 border-green-400 p-2">
<h3>Question {currentQuestion.v + 1} of {totalQuetions.v} 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-500"
style="width: {(currentQuestion.v + 1 / totalQuetions.v) * 100}%;"
></div>
</div>
</div>

View file

@ -0,0 +1,9 @@
<script>
import PeopleAwnsered from "./PeopleAwnsered.svelte";
import QuetionsAwnsred from "./QuetionsAwnsred.svelte";
</script>
<h1 class="m-[0] text-7xl">HOSTING</h1>
<QuetionsAwnsred />
<PeopleAwnsered />

View file

@ -0,0 +1,6 @@
<script>
let props = $props();
let playerName = props.playerName;
</script>
<span class="m-[0] rounded-xl bg-gray-700 pt-1 pr-2 pb-0 pl-2 font-mono text-3xl">{playerName}</span>

View file

@ -0,0 +1,12 @@
<script>
import { players } from "../../../logic/HostsData.svelte.js";
import PlayerBadge from "./playerBadge.svelte";
</script>
<h1 class="m-[0] mt-10 text-6xl">Players Joined:</h1>
<h1 class="m-[0] text-4xl text-gray-400">(Total Players: {players.v.length})</h1>
<div class="mt-2 flex flex-wrap justify-center gap-2">
{#each players.v as playerName}
<PlayerBadge {playerName} />
{/each}
</div>

View file

@ -0,0 +1,13 @@
<script>
import Players from "./PlayersGUI/players.svelte";
let props = $props();
let gamePin = props.gamePin;
</script>
<h1 class="m-[0] text-9xl">HOSTING</h1>
<h1 class="m-[0] text-7xl">Game Pin:</h1>
<h1 class="m-[0] rounded-2xl bg-gray-700 pt-1.5 pr-2 pb-0 pl-2 font-mono text-5xl">
{gamePin}
</h1>
<Players />

View file

@ -0,0 +1,18 @@
import { supabase } from "$lib/supabase.js";
import { players } from "./HostsData.svelte.js";
export async function GetCurrentPlayers(gamePin) {
const { data, error } = await supabase
.from("players")
.select("playername")
.eq("gameid", Number(gamePin));
console.log("Current players data:", JSON.stringify(data));
if (error) {
console.error("Error fetching players:", error);
return;
}
players.v = data ? data.map(player => player.playername) : [];
}

View file

@ -0,0 +1,9 @@
export let players = $state({ v: [] });
export let Status = $state({ v: "lobby" });
export let questions = $state({ v: [] });
export let CurrentQuestion = $state({ v: -1 });
export let currentQuestion = $state({ v: 0 });
export let totalQuetions = $state({ v: 3 });
export let PeopleAwnseredQ = $state({ v: 0 });
export let Totalplayers = $state({ v: 3 });

View file

@ -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();
}

View file

@ -0,0 +1,25 @@
import { supabase } from "$lib/supabase.js";
import { LobbyConnection } from "./UpdatePlayersList.js";
import { questions, Status, CurrentQuestion, currentQuestion } from "./HostsData.svelte.js";
export async function startGame(gamePin) {
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;
CurrentQuestion.v = 0;
await supabase
.from("games")
.update({ status: `question-${currentQuestion.v}` })
.eq("gamepin", gamePin);
}

View file

@ -7,14 +7,6 @@ const config = {
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
// See https://svelte.dev/docs/kit/adapters for more information about adapters.
adapter: adapter()
}
};