now people can join and leave the game
This commit is contained in:
parent
bf582efc46
commit
f83f50d9b2
12 changed files with 408 additions and 22 deletions
|
@ -1 +0,0 @@
|
|||
// place files you want to import through the `$lib` alias in this folder.
|
6
src/lib/supabase.js
Normal file
6
src/lib/supabase.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
import { createClient } from '@supabase/supabase-js';
|
||||
|
||||
export const supabase = createClient(
|
||||
import.meta.env.VITE_SUPABASE_URL,
|
||||
import.meta.env.VITE_SUPABASE_ANON_KEY
|
||||
);
|
|
@ -1,27 +1,37 @@
|
|||
<script>
|
||||
let questions = $state([
|
||||
import { supabase } from '$lib/supabase';
|
||||
import { goto } from '$app/navigation';
|
||||
let questions = [
|
||||
{
|
||||
name: '',
|
||||
answers: ['', '', '', ''],
|
||||
correctAnswer: undefined
|
||||
}
|
||||
]);
|
||||
];
|
||||
|
||||
function startGame() {
|
||||
if (questions.some((question) => question.name === '')) {
|
||||
alert('Please fill in the question for each question.');
|
||||
return;
|
||||
}
|
||||
if (questions.some((question) => question.answers.some((answer) => answer === ''))) {
|
||||
alert('Please fill in each of the options for each question.');
|
||||
return;
|
||||
}
|
||||
if (questions.some((question) => question.correctAnswer === undefined)) {
|
||||
alert('Please select a correct answer for each question.');
|
||||
async function startGame() {
|
||||
if (questions.some((q) => q.name === '')) return alert('Please fill all questions');
|
||||
if (questions.some((q) => q.answers.some((a) => a === ''))) return alert('Fill all options');
|
||||
if (questions.some((q) => q.correctAnswer === undefined))
|
||||
return alert('Select correct answers');
|
||||
|
||||
const gamePin = Math.floor(Math.random() * 1000000)
|
||||
.toString()
|
||||
.padStart(6, '0');
|
||||
|
||||
const { error } = await supabase.from('games').insert({
|
||||
gamePIN: gamePin,
|
||||
gameStatus: 'lobby',
|
||||
questions: questions,
|
||||
players: []
|
||||
});
|
||||
|
||||
if (error) {
|
||||
alert('Failed to create game: ' + error.message + '\n\nPlease try again.');
|
||||
return;
|
||||
}
|
||||
|
||||
alert('Game started!');
|
||||
goto('/host/' + gamePin);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
6
src/routes/host/[gamePin]/+page.js
Normal file
6
src/routes/host/[gamePin]/+page.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
// Example of what your +page.js or +page.server.js might need
|
||||
export function load({ params }) {
|
||||
return {
|
||||
gamePin: params.gamePin
|
||||
};
|
||||
}
|
78
src/routes/host/[gamePin]/+page.svelte
Normal file
78
src/routes/host/[gamePin]/+page.svelte
Normal file
|
@ -0,0 +1,78 @@
|
|||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { page } from '$app/stores';
|
||||
import { supabase } from '$lib/supabase';
|
||||
|
||||
export let data;
|
||||
const gamePin = data.gamePin;
|
||||
const name = $page.state?.name;
|
||||
|
||||
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();
|
||||
});
|
||||
</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-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={() => {
|
||||
if (players.length > 0) {
|
||||
if (confirm('Are you sure you want to start the game?')) {
|
||||
// Logic to start the game
|
||||
alert('Game started!'); // Replace with actual game start logic
|
||||
}
|
||||
} else {
|
||||
alert('You need at least one player to start the game.');
|
||||
}
|
||||
}}>Start the game</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
|
@ -1,19 +1,72 @@
|
|||
<script>
|
||||
import { goto } from '$app/navigation';
|
||||
import { supabase } from '$lib/supabase';
|
||||
|
||||
let pin;
|
||||
let name;
|
||||
let Checking = false;
|
||||
|
||||
async function validateGamePin() {
|
||||
const { data, error } = await supabase
|
||||
.from('games')
|
||||
.select('gamePIN')
|
||||
.eq('gamePIN', Number(pin))
|
||||
.maybeSingle();
|
||||
|
||||
// Return true if valid
|
||||
return data !== null && !error;
|
||||
}
|
||||
|
||||
async function joinGame() {
|
||||
if (!pin || !name) {
|
||||
alert('Please fill in the game pin and your name.');
|
||||
return;
|
||||
}
|
||||
|
||||
Checking = true;
|
||||
|
||||
const isValid = await validateGamePin();
|
||||
if (!isValid) {
|
||||
alert('Invalid game pin. Please try again.');
|
||||
Checking = false;
|
||||
return;
|
||||
}
|
||||
|
||||
goto('/play/' + pin, {
|
||||
state: {
|
||||
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-8 shadow-lg">
|
||||
<h1 class="m-[0] mb-3 text-5xl">Join a game here</h1>
|
||||
<input placeholder="Enter game pin" class="rounded-lg bg-gray-800 p-2 text-center text-white" />
|
||||
|
||||
<input
|
||||
placeholder="Enter game pin"
|
||||
class="rounded-lg bg-gray-800 p-2 text-center text-white"
|
||||
bind:value={pin}
|
||||
/>
|
||||
|
||||
<input
|
||||
placeholder="Enter your name"
|
||||
bind:value={name}
|
||||
class="rounded-lg bg-gray-800 p-2 text-center text-white"
|
||||
/>
|
||||
<button
|
||||
class="cursor-pointer rounded-full bg-green-700 p-2 transition-all hover:scale-110 hover:-rotate-10"
|
||||
>Join the game</button
|
||||
>
|
||||
|
||||
{#if !Checking}
|
||||
<button
|
||||
class="mt-4 cursor-pointer rounded-full bg-green-700 p-2 transition-all hover:scale-110 hover:-rotate-10"
|
||||
on:click={joinGame}
|
||||
>
|
||||
Join game
|
||||
</button>
|
||||
{:else}<button
|
||||
class="mt-4 cursor-pointer rounded-full bg-gray-700 p-2 transition-all hover:scale-110 hover:-rotate-10"
|
||||
>
|
||||
Checking if pin is valid...
|
||||
</button>{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
6
src/routes/play/[gamePin]/+page.js
Normal file
6
src/routes/play/[gamePin]/+page.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
// Example of what your +page.js or +page.server.js might need
|
||||
export function load({ params }) {
|
||||
return {
|
||||
gamePin: params.gamePin
|
||||
};
|
||||
}
|
87
src/routes/play/[gamePin]/+page.svelte
Normal file
87
src/routes/play/[gamePin]/+page.svelte
Normal file
|
@ -0,0 +1,87 @@
|
|||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { page } from '$app/stores';
|
||||
import { supabase } from '$lib/supabase';
|
||||
|
||||
export let data;
|
||||
const gamePin = data.gamePin;
|
||||
const name = $page.state?.name;
|
||||
|
||||
let players = [];
|
||||
|
||||
async function addPlayer() {
|
||||
const { data: gameData, error } = await supabase
|
||||
.from('games')
|
||||
.select('players')
|
||||
.eq('gamePIN', Number(gamePin))
|
||||
.maybeSingle();
|
||||
|
||||
let updatedPlayers = gameData.players || [];
|
||||
|
||||
const alreadyExists = updatedPlayers.some((p) => p.name === name);
|
||||
if (!alreadyExists) {
|
||||
updatedPlayers.push({ name: name, score: 0 });
|
||||
|
||||
const { error: updateError } = await supabase
|
||||
.from('games')
|
||||
.update({ players: updatedPlayers })
|
||||
.eq('gamePIN', Number(gamePin));
|
||||
}
|
||||
}
|
||||
|
||||
// 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 () => {
|
||||
await addPlayer();
|
||||
|
||||
const { data: gameData } = await supabase
|
||||
.from('games')
|
||||
.select('players')
|
||||
.eq('gamePIN', Number(gamePin))
|
||||
.maybeSingle();
|
||||
|
||||
if (gameData?.players) {
|
||||
players = gameData.players;
|
||||
}
|
||||
|
||||
subscribeToPlayers();
|
||||
});
|
||||
</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-9xl">PLAYING</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>
|
||||
</div>
|
||||
</div>
|
Loading…
Add table
Add a link
Reference in a new issue