🚸 Refreshed admin-screen and qr-endpoint!
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
<script lang="ts">
|
||||
<script lang='ts'>
|
||||
import { socket } from '$lib/socket';
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import { browser } from '$app/env';
|
||||
import tippy from 'sveltejs-tippy';
|
||||
|
||||
export let game_pin: string;
|
||||
|
||||
@@ -10,7 +11,8 @@
|
||||
|
||||
let hcaptcha = {
|
||||
execute: async (_a, _b) => ({ response: '' }),
|
||||
render: (_a, _b) => {}
|
||||
render: (_a, _b) => {
|
||||
}
|
||||
};
|
||||
let hcaptchaWidgetID;
|
||||
|
||||
@@ -31,7 +33,8 @@
|
||||
if (browser) {
|
||||
hcaptcha = {
|
||||
execute: async () => ({ response: '' }),
|
||||
render: () => {}
|
||||
render: () => {
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
@@ -50,46 +53,50 @@
|
||||
});
|
||||
};
|
||||
socket.on('game_not_found', () => {
|
||||
game_pin = '';
|
||||
alert('Game not found');
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<script src="https://js.hcaptcha.com/1/api.js?render=explicit" async defer></script>
|
||||
<script src='https://js.hcaptcha.com/1/api.js?render=explicit' async defer></script>
|
||||
</svelte:head>
|
||||
|
||||
{#if game_pin === '' || game_pin.length <= 7}
|
||||
<div class="flex flex-col justify-center align-center w-screen h-screen">
|
||||
<div class='flex flex-col justify-center align-center w-screen h-screen'>
|
||||
<form
|
||||
on:submit|preventDefault={() => {}}
|
||||
class="flex-col flex justify-center align-center mx-auto"
|
||||
class='flex-col flex justify-center align-center mx-auto'
|
||||
>
|
||||
<h1 class="text-lg text-center">Game Pin</h1>
|
||||
<h1 class='text-lg text-center'>Game Pin</h1>
|
||||
<input
|
||||
class="border border-amber-800 self-center text-center"
|
||||
class='border border-amber-800 self-center text-center text-black'
|
||||
bind:value={game_pin}
|
||||
maxlength="8"
|
||||
maxlength='8'
|
||||
/>
|
||||
<!-- use:tippy={{content: "Please enter the game pin", sticky: true, placement: 'top'}}-->
|
||||
|
||||
<br />
|
||||
<button
|
||||
class="bg-amber-800 hover:bg-amber-700 text-white font-bold py-2 px-4 rounded"
|
||||
type="submit"
|
||||
class='bg-amber-800 hover:bg-amber-700 text-white font-bold py-2 px-4 rounded disabled:opacity-50 disabled:cursor-not-allowed mt-2'
|
||||
type='submit'
|
||||
disabled={game_pin.length <= 7}
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex flex-col justify-center align-center w-screen h-screen">
|
||||
<div class='flex flex-col justify-center align-center w-screen h-screen'>
|
||||
<form
|
||||
on:submit|preventDefault={setUsername}
|
||||
class="flex-col flex justify-center align-center mx-auto"
|
||||
class='flex-col flex justify-center align-center mx-auto'
|
||||
>
|
||||
<h1 class="text-lg text-center">Username</h1>
|
||||
<input class="border border-amber-800" bind:value={username} />
|
||||
<h1 class='text-lg text-center'>Username</h1>
|
||||
<input class='border border-amber-800 text-black text-center' bind:value={username} />
|
||||
<button
|
||||
class="bg-amber-800 hover:bg-amber-700 text-white font-bold py-2 px-4 rounded disabled:cursor-not-allowed disabled:opacity-50"
|
||||
type="submit"
|
||||
class='bg-amber-800 hover:bg-amber-700 text-white font-bold py-2 px-4 rounded disabled:cursor-not-allowed disabled:opacity-50 mt-2'
|
||||
type='submit'
|
||||
disabled={username.length <= 3}
|
||||
>
|
||||
Submit
|
||||
@@ -98,9 +105,9 @@
|
||||
</div>
|
||||
{/if}
|
||||
<div
|
||||
id="hcaptcha"
|
||||
class="h-captcha"
|
||||
id='hcaptcha'
|
||||
class='h-captcha'
|
||||
data-sitekey={hcaptchaSitekey}
|
||||
data-size="invisible"
|
||||
data-theme="dark"
|
||||
data-size='invisible'
|
||||
data-theme='dark'
|
||||
/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
if (session.authenticated) {
|
||||
return {
|
||||
status: 302,
|
||||
redirect: '/'
|
||||
redirect: '/overview'
|
||||
};
|
||||
}
|
||||
return {};
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
if (session.authenticated) {
|
||||
return {
|
||||
status: 302,
|
||||
redirect: '/'
|
||||
redirect: '/overview'
|
||||
};
|
||||
}
|
||||
return {};
|
||||
|
||||
@@ -8,10 +8,15 @@
|
||||
}
|
||||
const token = url.searchParams.get('token');
|
||||
const pin = url.searchParams.get('pin');
|
||||
let auto_connect = url.searchParams.get('connect') !== null;
|
||||
if (token === null || pin === null) {
|
||||
auto_connect = false;
|
||||
}
|
||||
return {
|
||||
props: {
|
||||
game_pin: pin === null ? '' : pin,
|
||||
game_token: token === null ? '' : token
|
||||
game_token: token === null ? '' : token,
|
||||
auto_connect: auto_connect
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -28,6 +33,7 @@
|
||||
// game_pin: '66190765'
|
||||
// };
|
||||
export let game_pin: string;
|
||||
export let auto_connect: boolean;
|
||||
export let game_token: string;
|
||||
console.log(game_pin, game_token);
|
||||
let success = false;
|
||||
@@ -45,6 +51,9 @@
|
||||
game_id: game_token
|
||||
});
|
||||
};
|
||||
if (auto_connect) {
|
||||
connect();
|
||||
}
|
||||
socket.on('registered_as_admin', (data) => {
|
||||
console.log('registered_as_admin', data['game']);
|
||||
quiz_data = JSON.parse(data['game']);
|
||||
@@ -104,8 +113,11 @@
|
||||
<p class='text-red-700'>{errorMessage}</p>
|
||||
{/if}
|
||||
{:else if !game_started}
|
||||
<img src='/api/v1/utils/qr/{quiz_data.game_pin}' class='block mx-auto w-1/6' />
|
||||
<p class='text-3xl text-center'>Pin: {quiz_data.game_pin}</p>
|
||||
<ul>
|
||||
{#if players.length > 0}
|
||||
|
||||
{#each players as player}
|
||||
<li>
|
||||
<span>{player.username} </span>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<script context="module" lang="ts">
|
||||
<script context='module' lang='ts'>
|
||||
export async function load({ session }) {
|
||||
if (!session.authenticated) {
|
||||
return {
|
||||
@@ -13,3 +13,124 @@
|
||||
};
|
||||
}
|
||||
</script>
|
||||
<script lang='ts'>
|
||||
import type { QuizData } from '../app';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
|
||||
const getData = async (): Promise<Array<QuizData>> => {
|
||||
const res = await fetch('/api/v1/quiz/list');
|
||||
const data = await res.json();
|
||||
return data;
|
||||
};
|
||||
|
||||
const formatDate = (date: string): string => {
|
||||
const dt = DateTime.fromISO(date);
|
||||
return dt.toLocaleString(DateTime.DATETIME_MED);
|
||||
};
|
||||
|
||||
const startGame = async (id: string): Promise<void> => {
|
||||
console.log('start game', id);
|
||||
const res = await fetch(`/api/v1/quiz/start/${id}`, {
|
||||
method: 'POST'
|
||||
// headers: {
|
||||
// 'Content-Type': 'application/json'
|
||||
// }
|
||||
});
|
||||
if (res.status !== 200) {
|
||||
throw new Error('Failed to start game');
|
||||
}
|
||||
const data = await res.json();
|
||||
window.location.replace(`/admin?token=${data.game_id}&pin=${data.game_pin}&connect=1`);
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
{#await getData()}
|
||||
<p>Loading...</p>
|
||||
|
||||
{:then quizzes}
|
||||
|
||||
<div class='flex flex-col w-fit'>
|
||||
<div class='overflow-x-auto sm:-mx-8 lg:-mx-8'>
|
||||
<div class='inline-block py-2 min-w-full sm:px-6 lg:px-8'>
|
||||
<div class='overflow-hidden shadow-md sm:rounded-lg'>
|
||||
<table class='min-w-full'>
|
||||
<thead class='bg-gray-50 dark:bg-gray-700'>
|
||||
<tr>
|
||||
<th
|
||||
scope='col'
|
||||
class='py-3 px-6 text-xs font-medium tracking-wider text-left text-gray-700 uppercase dark:text-gray-400'
|
||||
>
|
||||
Title
|
||||
</th>
|
||||
<th
|
||||
scope='col'
|
||||
class='py-3 px-6 text-xs font-medium tracking-wider text-left text-gray-700 uppercase dark:text-gray-400'
|
||||
>
|
||||
Created at
|
||||
</th>
|
||||
<th
|
||||
scope='col'
|
||||
class='py-3 px-6 text-xs font-medium tracking-wider text-left text-gray-700 uppercase dark:text-gray-400'
|
||||
>
|
||||
Question count
|
||||
</th>
|
||||
<th
|
||||
scope='col'
|
||||
class='py-3 px-6 text-xs font-medium tracking-wider text-left text-gray-700 uppercase dark:text-gray-400'
|
||||
>
|
||||
Play
|
||||
</th>
|
||||
<th
|
||||
scope='col'
|
||||
class='py-3 px-6 text-xs font-medium tracking-wider text-left text-gray-700 uppercase dark:text-gray-400'
|
||||
>
|
||||
Edit
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- Product 1 -->
|
||||
{#each quizzes as quiz}
|
||||
|
||||
<tr class='bg-white border-b dark:bg-gray-800 dark:border-gray-700'>
|
||||
<td
|
||||
class='py-4 px-6 text-sm font-medium text-gray-900 whitespace-nowrap dark:text-white'
|
||||
>
|
||||
{quiz.title}
|
||||
</td>
|
||||
<td
|
||||
class='py-4 px-6 text-sm text-gray-500 whitespace-nowrap dark:text-gray-400'
|
||||
>
|
||||
{formatDate(quiz.created_at)}
|
||||
</td>
|
||||
<td
|
||||
class='py-4 px-6 text-sm text-gray-500 whitespace-nowrap dark:text-gray-400'
|
||||
>
|
||||
{quiz.questions.length}
|
||||
</td>
|
||||
<td
|
||||
class='py-4 px-6 text-sm text-gray-500 whitespace-nowrap dark:text-gray-400'
|
||||
>
|
||||
<button on:click={() => {startGame(quiz.id)}} class='border border-green-600'>
|
||||
Start
|
||||
</button>
|
||||
</td>
|
||||
<td
|
||||
class='py-4 px-6 text-sm text-gray-500 whitespace-nowrap dark:text-gray-400'
|
||||
>
|
||||
<a href='/edit/{quiz.id}'>Edit</a>
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{:catch err}
|
||||
<p>{err}</p>
|
||||
{/await}
|
||||
|
||||
Reference in New Issue
Block a user