Compare commits
9
Commits
38afd41ca0
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cf2557896 | ||
|
|
ba8db120b4 | ||
|
|
a8809ace9b | ||
|
|
aed5c675d3 | ||
|
|
fe14660601 | ||
|
|
b652447121 | ||
|
|
23c738d218 | ||
|
|
add6a061bf | ||
|
|
dcaf98e612 |
@@ -29,11 +29,4 @@ h1, h2, h3, h4, h5, h6 {
|
|||||||
|
|
||||||
.button-primary {
|
.button-primary {
|
||||||
@apply border-primary-GoldTinsel bg-primary-GoldTinsel-dark text-primary-SantaSuitBlack font-bold mx-auto px-6 hover:bg-primary-GoldTinsel-light
|
@apply border-primary-GoldTinsel bg-primary-GoldTinsel-dark text-primary-SantaSuitBlack font-bold mx-auto px-6 hover:bg-primary-GoldTinsel-light
|
||||||
}
|
|
||||||
|
|
||||||
.movie-poster {
|
|
||||||
@apply rounded-md mx-2 w-[60rem]
|
|
||||||
/* aspect-ratio: auto; */
|
|
||||||
/* width: 100%; */
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -13,6 +13,17 @@ export const handle: Handle = async ({ event, resolve }) => {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.url.pathname.startsWith('/admin')) {
|
||||||
|
const current_user = await authenticateUser(event);
|
||||||
|
if (!current_user) {
|
||||||
|
throw redirect(302, '/login');
|
||||||
|
}
|
||||||
|
if (!current_user.is_admin) {
|
||||||
|
throw redirect(302, '/');
|
||||||
|
}
|
||||||
|
event.locals.user = current_user;
|
||||||
|
}
|
||||||
|
|
||||||
const response = await resolve(event);
|
const response = await resolve(event);
|
||||||
return response;
|
return response;
|
||||||
};
|
};
|
||||||
@@ -1,32 +1,53 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
let { id, title, description, points }: Cliche = $props();
|
import type { Cliche } from '$lib/types';
|
||||||
|
let {
|
||||||
|
cardData,
|
||||||
|
onCardChecked,
|
||||||
|
isBonus = false
|
||||||
|
}: { cardData: Cliche; onCardChecked: any; isBonus?: boolean } = $props();
|
||||||
|
|
||||||
type Cliche = {
|
let isCardChecked: boolean = $state(false);
|
||||||
id: number;
|
let isSelectedAtStart: boolean = $state(false);
|
||||||
title: string;
|
|
||||||
description: string;
|
function toggleCardChecked() {
|
||||||
points: number;
|
isCardChecked = !isCardChecked;
|
||||||
};
|
onCardChecked(cardData, isCardChecked, isBonus);
|
||||||
|
}
|
||||||
|
console.log('isBonus', isBonus);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card" id="card">
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<input class="left-0 top-0" type="checkbox" name="" id="card-{id}" />
|
<div>
|
||||||
<input type="checkbox" class="peer hidden" name="cardDetails-{id}" id="cardDetails-{id}" />
|
<input
|
||||||
<label for="cardDetails-{id}">{title}</label>
|
type="checkbox"
|
||||||
<!-- <button class="text-center text-xl font-semibold">{title}</button> -->
|
name=""
|
||||||
|
id="card-{cardData.id}"
|
||||||
|
onchange={toggleCardChecked}
|
||||||
|
class="appearance-none h-6 w-6 rounded-lg border-2 border-primary-FestiveRed-dark checked:bg-primary-FestiveRed-dark checked:border-primary-FestiveRed-dark cursor-pointer transition-all duration-200 ease-in-out"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
class="peer hidden"
|
||||||
|
name="cardDetails-{cardData.id}"
|
||||||
|
id="cardDetails-{cardData.id}"
|
||||||
|
/>
|
||||||
|
<label for="cardDetails-{cardData.id}">{cardData.title}</label>
|
||||||
|
|
||||||
<div class="hidden flex-col gap-4 peer-checked:flex">
|
<div class="hidden flex-col gap-4 peer-checked:flex">
|
||||||
<!-- <img src="https://placehold.co/150x200" class="mx-auto" alt="Descriptive" /> -->
|
<!-- <img src="https://placehold.co/150x200" class="mx-auto" alt="Descriptive" /> -->
|
||||||
<p>{description}</p>
|
<p>{cardData.description}</p>
|
||||||
<p>Points: {points}</p>
|
<p>Pisteet: {cardData.point_value}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="postcss">
|
<style lang="postcss">
|
||||||
.card {
|
.card {
|
||||||
@apply mx-auto my-6 flex max-w-sm flex-col gap-4 rounded-xl border-2 border-primary-FestiveRed-dark p-6 text-center;
|
@apply mx-auto w-full max-w-sm gap-4 rounded-xl border-2 border-primary-FestiveRed-dark p-4 text-center;
|
||||||
}
|
}
|
||||||
.card input {
|
.card input {
|
||||||
@apply absolute left-0 top-0 m-0 appearance-none rounded-lg p-0 accent-black;
|
@apply absolute left-0 top-0 m-0 appearance-none rounded-lg p-0 accent-black;
|
||||||
|
|||||||
@@ -1,73 +1,37 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import type { Cliche } from '$lib/types';
|
||||||
import Card from './Card.svelte';
|
import Card from './Card.svelte';
|
||||||
|
|
||||||
type Cliche = {
|
const cards: Cliche[] = $props();
|
||||||
id: number;
|
let selected_cliches: Cliche[] = $state([]);
|
||||||
title: string;
|
|
||||||
description: string;
|
|
||||||
points: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
const cards: Cliche[] = [
|
function handleChildData(card: Cliche) {
|
||||||
{
|
for (let i = 0; i < selected_cliches.length; i++) {
|
||||||
id: 1,
|
if (selected_cliches[i].id == card.id) {
|
||||||
title: 'Punainen villakangastakki',
|
selected_cliches.splice(i, 1);
|
||||||
description: 'Päähenkilöllä on aina kirkkaanpunainen, täydellisesti istuva talvitakki.',
|
return;
|
||||||
points: 1
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
title: 'Keskeytetty suudelma',
|
|
||||||
description: 'Juuri, kun romanttinen hetki on käsillä, jokin keskeyttää ensisuudelman.',
|
|
||||||
points: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
title: 'Miespääosa yh',
|
|
||||||
description:
|
|
||||||
'Miespäähenkilö on yksinhuoltaja, joka tasapainoilee uran ja lapsenhoidon välillä.',
|
|
||||||
points: 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
title: 'Leskimies',
|
|
||||||
description: 'Päähenkilö on menettänyt puolisonsa ja yrittää nyt toipua elämässään.',
|
|
||||||
points: 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
title: 'Jouluoksennus',
|
|
||||||
description:
|
|
||||||
'Koti, työpaikka tai jokin muu koristeltu liioitellusti jouluteemalla, ilman mitään hillittyä tyylitajua.',
|
|
||||||
points: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 6,
|
|
||||||
title: 'Evergreen',
|
|
||||||
description:
|
|
||||||
"Tarinan kylä tai kaupunki on idyllinen paikka, nimeltään jotain jouluista, kuten 'Evergreen' tai 'Snowville'.",
|
|
||||||
points: 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 7,
|
|
||||||
title: 'Yritys pulassa',
|
|
||||||
description: 'Päähenkilön yritys on konkurssin partaalla tai vaarassa tulla ostetuksi.',
|
|
||||||
points: 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 8,
|
|
||||||
title: 'Naispääosa pitkä blondi',
|
|
||||||
description: 'Naispääosalla pitkät blondit hiukset.',
|
|
||||||
points: 1
|
|
||||||
}
|
}
|
||||||
];
|
selected_cliches = [...selected_cliches, card];
|
||||||
let selected_cliches: Cliche[] = [];
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<form action="">
|
<form action="">
|
||||||
{#each cards as card}
|
<div class="space-y-2 lg:grid lg:grid-cols-2">
|
||||||
<Card id={card.id} title={card.title} description={card.description} points={card.points} />
|
{#each cards as card}
|
||||||
{/each}
|
<Card cardData={card} onCardChecked={handleChildData} />
|
||||||
<button class="button button-primary mx-auto">Valitse kortit</button>
|
{/each}
|
||||||
|
</div>
|
||||||
|
<p>Kortteja valittu: {selected_cliches.length} / 5</p>
|
||||||
|
{#if selected_cliches.length == 5}
|
||||||
|
<button class="button button-primary mx-auto">Valitse kortit</button>
|
||||||
|
{:else}
|
||||||
|
<button class="button button-disabled mx-auto" disabled>Korjaa valintaa</button>
|
||||||
|
{/if}
|
||||||
</form>
|
</form>
|
||||||
<div></div>
|
|
||||||
|
<style lang="postcss">
|
||||||
|
button {
|
||||||
|
@apply mx-auto mt-6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
class="input-text"
|
class="input-text"
|
||||||
required
|
required
|
||||||
minlength="3"
|
minlength="3"
|
||||||
value="admin"
|
placeholder="käyttäjätunnus"
|
||||||
/>
|
/>
|
||||||
<label for="password">Salasana</label>
|
<label for="password">Salasana</label>
|
||||||
<input
|
<input
|
||||||
@@ -24,8 +24,8 @@
|
|||||||
id="password"
|
id="password"
|
||||||
class="input-text"
|
class="input-text"
|
||||||
required
|
required
|
||||||
value="password"
|
|
||||||
minlength="5"
|
minlength="5"
|
||||||
|
placeholder="salasana"
|
||||||
/>
|
/>
|
||||||
<hr class="my-4 border-0" />
|
<hr class="my-4 border-0" />
|
||||||
<button type="submit" class="button button-primary">Sisään</button>
|
<button type="submit" class="button button-primary">Sisään</button>
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
<script>
|
<script>
|
||||||
let data = $props();
|
let data = $props();
|
||||||
const movie = data.data.movie;
|
const movie = data;
|
||||||
let actors = movie.actors.join(', ');
|
let actors = movie.actors.join(', ');
|
||||||
const imdb_link = `https://www.imdb.com/title/${movie.imdb_id}/`;
|
const imdb_link = `https://www.imdb.com/title/${movie.imdb_id}/`;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h2 class="mb-4 text-center text-xl font-semibold">{movie.name}</h2>
|
<h2 class="mb-4 text-center text-xl font-semibold">{movie.name}</h2>
|
||||||
<div class="mx-auto flex gap-2 px-3">
|
<div class="max-w-1/2 mx-auto flex flex-col gap-4 px-3 lg:flex-row">
|
||||||
<div class="movie-poster">
|
<div class="mx-auto">
|
||||||
<img class="rounded-2xl" src={movie.poster_url} alt="Poster" />
|
<img class="rounded-2xl" src={movie.poster_url} alt="Poster" />
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-8">
|
<div class="space-y-8">
|
||||||
|
|||||||
@@ -6,4 +6,24 @@ export function decodeUSerCookie(userCookie: string) {
|
|||||||
const decodedCookie = decodeURIComponent(userCookie);
|
const decodedCookie = decodeURIComponent(userCookie);
|
||||||
const parsedCookie = JSON.parse(decodedCookie);
|
const parsedCookie = JSON.parse(decodedCookie);
|
||||||
return parsedCookie;
|
return parsedCookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getNextMovie() {
|
||||||
|
const get_next_movie_url = `${api_url}/movie/next`;
|
||||||
|
return fetch(get_next_movie_url)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
const year = new Date(data.release_date).getFullYear();
|
||||||
|
data.release_date = `${year}`;
|
||||||
|
return data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCards() {
|
||||||
|
const get_cards_url = `${api_url}/card`;
|
||||||
|
return fetch(get_cards_url)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
return data;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
export type movie = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
imdb_id: string;
|
||||||
|
actors: Array<string>;
|
||||||
|
plot: string;
|
||||||
|
poster_url: string;
|
||||||
|
release_date: string;
|
||||||
|
showtime: string;
|
||||||
|
is_watched: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Cliche = {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
point_value: number;
|
||||||
|
};
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
<div class="flex min-h-[100dvh] flex-col">
|
<div class="flex min-h-[100dvh] flex-col">
|
||||||
<Header user={data.user} />
|
<Header user={data.user} />
|
||||||
<main class="container mx-auto max-w-4xl flex-grow overflow-hidden">
|
<main class="container mx-auto max-w-4xl flex-grow">
|
||||||
{@render children()}
|
{@render children()}
|
||||||
</main>
|
</main>
|
||||||
<Footer />
|
<Footer />
|
||||||
|
|||||||
@@ -1,30 +1,9 @@
|
|||||||
import type { PageServerLoad } from "./$types";
|
import type { PageServerLoad } from "./$types";
|
||||||
import { api_url } from "$lib";
|
import { getNextMovie } from "$lib";
|
||||||
|
|
||||||
type movie = {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
imdb_id: string;
|
|
||||||
actors: Array<string>;
|
|
||||||
plot: string;
|
|
||||||
poster_url: string;
|
|
||||||
release_date: string;
|
|
||||||
showtime: string;
|
|
||||||
is_watched: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const load: PageServerLoad = async (event) => {
|
export const load: PageServerLoad = async (event) => {
|
||||||
|
|
||||||
|
const data = await getNextMovie();
|
||||||
|
|
||||||
const get_next_movie_url = `${api_url}/movie/next`;
|
|
||||||
const response = await fetch(get_next_movie_url);
|
|
||||||
const data: movie = await response.json();
|
|
||||||
|
|
||||||
|
|
||||||
const year = new Date(data.release_date).getFullYear();
|
|
||||||
data.release_date = `${year}`;
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
movie: data,
|
movie: data,
|
||||||
|
|||||||
@@ -2,5 +2,3 @@
|
|||||||
import MovieDetails from '$lib/components/MovieDetails.svelte';
|
import MovieDetails from '$lib/components/MovieDetails.svelte';
|
||||||
let data = $props();
|
let data = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<MovieDetails {...data} />
|
|
||||||
|
|||||||
@@ -0,0 +1,192 @@
|
|||||||
|
import { error } from '@sveltejs/kit';
|
||||||
|
import type { Actions, PageServerLoad } from './$types';
|
||||||
|
|
||||||
|
const api_url = import.meta.env.VITE_API_URL;
|
||||||
|
|
||||||
|
interface Movie {
|
||||||
|
name: string;
|
||||||
|
imdb_id: string;
|
||||||
|
showtime: string;
|
||||||
|
plot: string;
|
||||||
|
actors: string[];
|
||||||
|
release_date: string;
|
||||||
|
poster_url: string;
|
||||||
|
id: string;
|
||||||
|
created_at: string;
|
||||||
|
modified_at: string;
|
||||||
|
is_watched: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const load: PageServerLoad = async ({ fetch }) => {
|
||||||
|
try {
|
||||||
|
const [usersRes, moviesRes, cardsRes] = await Promise.all([
|
||||||
|
fetch(`${api_url}/user`),
|
||||||
|
fetch(`${api_url}/movie`),
|
||||||
|
fetch(`${api_url}/card`)
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!usersRes.ok) throw error(usersRes.status, 'Failed to load users');
|
||||||
|
if (!moviesRes.ok) throw error(moviesRes.status, 'Failed to load movies');
|
||||||
|
if (!cardsRes.ok) throw error(cardsRes.status, 'Failed to load cards');
|
||||||
|
|
||||||
|
const users = await usersRes.json();
|
||||||
|
const movies: Movie[] = await moviesRes.json();
|
||||||
|
const cards = await cardsRes.json();
|
||||||
|
|
||||||
|
return {
|
||||||
|
users,
|
||||||
|
movies,
|
||||||
|
cards
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading data:', error);
|
||||||
|
return {
|
||||||
|
users: [],
|
||||||
|
movies: [],
|
||||||
|
cards: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const actions: Actions = {
|
||||||
|
addUser: async ({ request }) => {
|
||||||
|
const data = await request.formData();
|
||||||
|
const username = data.get('username');
|
||||||
|
const password = data.get('password');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${api_url}/admin/user`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
username,
|
||||||
|
password
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { success: true };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error adding user:', error);
|
||||||
|
return { success: false, message: 'Failed to add user' };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteUser: async ({ request }) => {
|
||||||
|
const data = await request.formData();
|
||||||
|
const userId = data.get('userId');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${api_url}/admin/user?user_id=${userId}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { success: true };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error deleting user:', error);
|
||||||
|
return { success: false, message: 'Failed to delete user' };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addMovie: async ({ request }) => {
|
||||||
|
const data = await request.formData();
|
||||||
|
const movieData = {
|
||||||
|
imdb_id: data.get('imdb_id'),
|
||||||
|
showtime: data.get('showtime'),
|
||||||
|
plot: data.get('plot')
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${api_url}/admin/movie`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(movieData)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { success: true };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error adding movie:', error);
|
||||||
|
return { success: false, message: 'Failed to add movie' };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setMovieWatched: async ({ request, fetch }) => {
|
||||||
|
const formData = await request.formData();
|
||||||
|
const movieId = formData.get('movieId');
|
||||||
|
|
||||||
|
const response = await fetch(`${api_url}/admin/movie/${movieId}`, {
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ is_watched: true })
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw error(response.status, 'Failed to update movie status');
|
||||||
|
}
|
||||||
|
|
||||||
|
return { success: true };
|
||||||
|
},
|
||||||
|
|
||||||
|
addCard: async ({ request, fetch }) => {
|
||||||
|
const data = await request.formData();
|
||||||
|
const cardData = {
|
||||||
|
title: data.get('title'),
|
||||||
|
description: data.get('description'),
|
||||||
|
point_value: Number(data.get('point_value'))
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${api_url}/admin/card`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(cardData)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { success: true };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error adding card:', error);
|
||||||
|
return { success: false, message: 'Failed to add card' };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteCard: async ({ request, fetch }) => {
|
||||||
|
const formData = await request.formData();
|
||||||
|
const cardId = formData.get('cardId');
|
||||||
|
|
||||||
|
const response = await fetch(`${api_url}/admin/card/${cardId}`, {
|
||||||
|
method: 'DELETE'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw error(response.status, 'Failed to delete card');
|
||||||
|
}
|
||||||
|
|
||||||
|
return { success: true };
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,322 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { enhance } from '$app/forms';
|
||||||
|
let activeTab = 'users';
|
||||||
|
|
||||||
|
export let data;
|
||||||
|
const { users, movies, cards } = data;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="admin-panel">
|
||||||
|
<nav class="tabs">
|
||||||
|
<button
|
||||||
|
class:active={activeTab === 'users'}
|
||||||
|
on:click={() => activeTab = 'users'}>Users</button>
|
||||||
|
<button
|
||||||
|
class:active={activeTab === 'movies'}
|
||||||
|
on:click={() => activeTab = 'movies'}>Movies</button>
|
||||||
|
<button
|
||||||
|
class:active={activeTab === 'cards'}
|
||||||
|
on:click={() => activeTab = 'cards'}>Cards</button>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="tab-content">
|
||||||
|
{#if activeTab === 'users'}
|
||||||
|
<div class="section">
|
||||||
|
<h2>Existing Users</h2>
|
||||||
|
<div class="table-container">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Username</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{#each users as user}
|
||||||
|
<tr>
|
||||||
|
<td>{user.username}</td>
|
||||||
|
<td>
|
||||||
|
<form method="POST" action="?/deleteUser" use:enhance>
|
||||||
|
<input type="hidden" name="userId" value={user.id}>
|
||||||
|
<button type="submit" class="danger small">Delete</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Add User</h2>
|
||||||
|
<form method="POST" action="?/addUser" use:enhance>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="username">Username:</label>
|
||||||
|
<input type="text" id="username" name="username" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="password">Password:</label>
|
||||||
|
<input type="password" id="password" name="password" required>
|
||||||
|
</div>
|
||||||
|
<button type="submit">Add User</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if activeTab === 'movies'}
|
||||||
|
<div class="section">
|
||||||
|
<h2>Existing Movies</h2>
|
||||||
|
<div class="table-container">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Plot</th>
|
||||||
|
<th>IMDB</th>
|
||||||
|
<th>Showtime</th>
|
||||||
|
<th>Watched</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{#each movies as movie}
|
||||||
|
<tr>
|
||||||
|
<td>{movie.name}</td>
|
||||||
|
<td>{movie.plot}</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://www.imdb.com/title/{movie.imdb_id}" target="_blank" rel="noopener noreferrer">
|
||||||
|
View on IMDB
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>{new Date(movie.showtime).toLocaleDateString()}</td>
|
||||||
|
<td>{movie.is_watched ? 'Yes' : 'No'}</td>
|
||||||
|
<td>
|
||||||
|
{#if !movie.is_watched}
|
||||||
|
<form method="POST" action="?/setMovieWatched" use:enhance>
|
||||||
|
<input type="hidden" name="movieId" value={movie.id}>
|
||||||
|
<button type="submit" class="small">Mark Watched</button>
|
||||||
|
</form>
|
||||||
|
{/if}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Add Movie</h2>
|
||||||
|
<form method="POST" action="?/addMovie" use:enhance>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="imdb_id">IMDB ID:</label>
|
||||||
|
<input type="text" id="imdb_id" name="imdb_id" placeholder="tt1234567" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="showtime">Showtime:</label>
|
||||||
|
<input type="date" id="showtime" name="showtime" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="plot">Plot:</label>
|
||||||
|
<textarea id="plot" name="plot" rows="3" required></textarea>
|
||||||
|
</div>
|
||||||
|
<button type="submit">Add Movie</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if activeTab === 'cards'}
|
||||||
|
<div class="section">
|
||||||
|
<h2>Existing Cards</h2>
|
||||||
|
<div class="table-container">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Title</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Points</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{#each cards as card}
|
||||||
|
<tr>
|
||||||
|
<td>{card.title}</td>
|
||||||
|
<td>{card.description}</td>
|
||||||
|
<td>{card.point_value}</td>
|
||||||
|
<td>
|
||||||
|
<form method="POST" action="?/deleteCard" use:enhance>
|
||||||
|
<input type="hidden" name="cardId" value={card.id}>
|
||||||
|
<button type="submit" class="danger small">Delete</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Add Card</h2>
|
||||||
|
<form method="POST" action="?/addCard" use:enhance>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="title">Title:</label>
|
||||||
|
<input type="text" id="title" name="title" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="description">Description:</label>
|
||||||
|
<textarea id="description" name="description" rows="3" required></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="point_value">Points:</label>
|
||||||
|
<input type="number" id="point_value" name="point_value" min="1" required>
|
||||||
|
</div>
|
||||||
|
<button type="submit">Add Card</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.admin-panel {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 2rem auto;
|
||||||
|
padding: 1rem;
|
||||||
|
background-color: #1a472a; /* Dark Christmas green */
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 1rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
border-bottom: 1px solid #2c6842;
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs button {
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 1rem;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs button:hover {
|
||||||
|
background: #2c6842;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs button.active {
|
||||||
|
background: #c41e3a; /* Christmas red for active tab */
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section {
|
||||||
|
background: #234332; /* Slightly lighter green for sections */
|
||||||
|
padding: 2rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin-top: 2rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
input, textarea {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.5rem;
|
||||||
|
border: 1px solid #2c6842;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 1rem;
|
||||||
|
background: #1a472a;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus, textarea:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #c41e3a;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
height: 100px;
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
background: #c41e3a; /* Christmas red for buttons */
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 1rem;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background: #a01830;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.danger {
|
||||||
|
background: #dc3545;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.danger:hover {
|
||||||
|
background: #c82333;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.small {
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-container {
|
||||||
|
overflow-x: auto;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
background: #1a472a;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
th, td {
|
||||||
|
padding: 0.75rem;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid #2c6842;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
background-color: #2c6842;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:hover {
|
||||||
|
background-color: #2c6842;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a placeholder style for better visibility */
|
||||||
|
input::placeholder, textarea::placeholder {
|
||||||
|
color: rgba(255, 255, 255, 0.6);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,7 +1,107 @@
|
|||||||
import type { PageServerLoad } from "./$types";
|
import type { PageServerLoad, Actions } from "./$types";
|
||||||
|
import { getNextMovie, getCards } from "$lib";
|
||||||
|
import { redirect } from "@sveltejs/kit";
|
||||||
|
import type { Cliche } from "$lib/types";
|
||||||
|
|
||||||
|
const api_url = import.meta.env.VITE_API_URL
|
||||||
|
|
||||||
export const load: PageServerLoad = async (event) => {
|
export const load: PageServerLoad = async (event) => {
|
||||||
return {
|
const cards = await getCards();
|
||||||
user: event.locals.user
|
const movies = await getNextMovie();
|
||||||
|
const selected_cliches = {
|
||||||
|
baseCards: JSON.parse(event.cookies.get('selected_cliches') ?? '[]'),
|
||||||
|
bonusCards: JSON.parse(event.cookies.get('selected_bonus_cliches') ?? '[]')
|
||||||
};
|
};
|
||||||
};
|
return {
|
||||||
|
movie: movies,
|
||||||
|
cards: cards,
|
||||||
|
user: event.locals.user,
|
||||||
|
selected_cliches: selected_cliches
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const actions: Actions = {
|
||||||
|
/**
|
||||||
|
* Starts a new game. Sets the selected cliche and bonus cliche cookies for the user.
|
||||||
|
* @param {RequestEvent} event - The request event.
|
||||||
|
* @param {Cookie | undefined} cookies - The cookies object.
|
||||||
|
* @returns {Promise<void>} - The response object.
|
||||||
|
*/
|
||||||
|
startGame: async ({ request, cookies }) => {
|
||||||
|
const formData = await request.formData();
|
||||||
|
const selected_cliches = formData.get('selected_cliches')?.toString() ?? '[]';
|
||||||
|
const selected_bonus_cliches = formData.get('selected_bonus_cliches')?.toString() ?? '[]';
|
||||||
|
|
||||||
|
cookies.set('selected_cliches', selected_cliches, {
|
||||||
|
path: '/',
|
||||||
|
sameSite: 'strict',
|
||||||
|
secure: false,
|
||||||
|
maxAge: 60 * 60 * 24
|
||||||
|
});
|
||||||
|
cookies.set('selected_bonus_cliches', selected_bonus_cliches, {
|
||||||
|
path: '/',
|
||||||
|
sameSite: 'strict',
|
||||||
|
secure: false,
|
||||||
|
maxAge: 60 * 60 * 24
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* End game action. Calculates the total score for the user and sends it to the
|
||||||
|
* server to be saved. Redirects to the game over page.
|
||||||
|
* @param {RequestEvent} event - The request event.
|
||||||
|
* @param {Cookie | undefined} cookies - The cookies object.
|
||||||
|
* @returns {Promise<Response>} - The response object.
|
||||||
|
*/
|
||||||
|
endGame: async ({ request, cookies }) => {
|
||||||
|
const formData = await request.formData();
|
||||||
|
console.log(formData);
|
||||||
|
|
||||||
|
const movieId = formData.get('movieId');
|
||||||
|
const userId = formData.get('userId');
|
||||||
|
|
||||||
|
const resultCards = JSON.parse(formData.get('result_cards')?.toString() ?? '[]');
|
||||||
|
const resultBonusCards = JSON.parse(formData.get('result_bonus_cards')?.toString() ?? '[]');
|
||||||
|
const selectedBonusCards = JSON.parse(cookies.get('selected_bonus_cliches') ?? '[]');
|
||||||
|
|
||||||
|
let totalScore: number = 0;
|
||||||
|
|
||||||
|
for (let i = 0; i < resultCards.length; i++) {
|
||||||
|
console.log('resultCards[i].point_value', resultCards[i].point_value);
|
||||||
|
totalScore += resultCards[i].point_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < selectedBonusCards.length; i++) {
|
||||||
|
if (resultBonusCards.some((card: Cliche) => card.id === selectedBonusCards[i].id)) {
|
||||||
|
totalScore += selectedBonusCards[i].point_value*2;
|
||||||
|
} else {
|
||||||
|
totalScore -= selectedBonusCards[i].point_value*2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(`${api_url}/score`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
user_id: userId,
|
||||||
|
movie_id: movieId,
|
||||||
|
score: totalScore
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('response', await response);
|
||||||
|
// console.log(baseCards, bonusCards);
|
||||||
|
// cookies.delete('selected_cliches', {
|
||||||
|
// path: '/',
|
||||||
|
// sameSite: 'strict',
|
||||||
|
// secure: false,
|
||||||
|
// });
|
||||||
|
// cookies.delete('selected_bonus_cliches', {
|
||||||
|
// path: '/',
|
||||||
|
// sameSite: 'strict',
|
||||||
|
// secure: false,
|
||||||
|
// });
|
||||||
|
throw redirect(302, `/gameroom/${totalScore}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,156 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import MovieDetails from '$lib/components/MovieDetails.svelte';
|
||||||
|
import Card from '$lib/components/Card.svelte';
|
||||||
|
import type { Cliche } from '$lib/types';
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
|
import { enhance } from '$app/forms';
|
||||||
|
|
||||||
let { data }: { data: PageData } = $props();
|
let { data }: { data: PageData } = $props();
|
||||||
|
let roundNumber: number = $state(1);
|
||||||
|
const cards: Cliche[] = data.cards;
|
||||||
|
let selected_cliches: Cliche[] = $state([]);
|
||||||
|
let selected_bonus_cliches: Cliche[] = $state([]);
|
||||||
|
let result_cards: Cliche[] = $state([]);
|
||||||
|
let result_bonus_cards: Cliche[] = $state([]);
|
||||||
|
|
||||||
|
function onCardChecked(card: Cliche) {
|
||||||
|
for (let i = 0; i < selected_cliches.length; i++) {
|
||||||
|
if (selected_cliches[i].id == card.id) {
|
||||||
|
selected_cliches.splice(i, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selected_cliches = [...selected_cliches, card];
|
||||||
|
}
|
||||||
|
|
||||||
|
function onBonusCardChecked(card: Cliche) {
|
||||||
|
for (let i = 0; i < selected_bonus_cliches.length; i++) {
|
||||||
|
if (selected_bonus_cliches[i].id == card.id) {
|
||||||
|
selected_bonus_cliches.splice(i, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selected_bonus_cliches = [...selected_bonus_cliches, card];
|
||||||
|
}
|
||||||
|
|
||||||
|
function setResult(cliche: Cliche, isCardChecked: boolean, isBonus: boolean) {
|
||||||
|
if (isCardChecked) {
|
||||||
|
if (isBonus) {
|
||||||
|
result_bonus_cards = [...result_bonus_cards, cliche];
|
||||||
|
} else {
|
||||||
|
result_cards = [...result_cards, cliche];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isBonus) {
|
||||||
|
result_bonus_cards = result_bonus_cards.filter((card) => card.id != cliche.id);
|
||||||
|
} else {
|
||||||
|
result_cards = result_cards.filter((card) => card.id != cliche.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$inspect(result_bonus_cards);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<h1>gameroom</h1>
|
<div class="space-y-8">
|
||||||
|
<input type="checkbox" checked name="moviedetails" id="moviedetails" class="peer hidden" />
|
||||||
|
<div class="flex justify-center border-2 border-primary-FestiveRed-dark">
|
||||||
|
<label for="moviedetails" class="cursor-pointer text-xl font-semibold">Elokuva</label>
|
||||||
|
</div>
|
||||||
|
<div class="hidden peer-checked:flex">
|
||||||
|
<MovieDetails {...data.movie} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-8 justify-center space-y-4">
|
||||||
|
{#if roundNumber == 1 && data.selected_cliches.baseCards.length == 0}
|
||||||
|
<h2 class="text-center text-xl font-semibold">Valitse kortit</h2>
|
||||||
|
<div class="flex flex-col space-y-4 lg:grid lg:grid-cols-2">
|
||||||
|
{#each cards as card}
|
||||||
|
<Card cardData={card} {onCardChecked} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
<p>Kortteja valittu: {selected_cliches.length} / 5</p>
|
||||||
|
|
||||||
|
{#if selected_cliches.length == 5}
|
||||||
|
<button onclick={() => roundNumber++} class="button button-primary mx-auto"
|
||||||
|
>Valitse kortit</button
|
||||||
|
>
|
||||||
|
{:else}
|
||||||
|
<button class="button button-disabled mx-auto" disabled>Korjaa valintaa</button>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if roundNumber == 2 && data.selected_cliches.baseCards.length == 0}
|
||||||
|
<h2 class="text-center text-xl font-semibold">Bonus kortit</h2>
|
||||||
|
<div class="flex flex-col space-y-4 lg:grid lg:grid-cols-2">
|
||||||
|
{#each cards as card}
|
||||||
|
{#if !selected_cliches.some((c) => c.id === card.id)}
|
||||||
|
<!-- <p>Kortti {card.title} valittu</p> -->
|
||||||
|
<Card cardData={card} onCardChecked={onBonusCardChecked} />
|
||||||
|
<!-- {:else} -->
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
<p>Kortteja valittu: {selected_bonus_cliches.length} / 3</p>
|
||||||
|
|
||||||
|
{#if selected_bonus_cliches.length < 4}
|
||||||
|
<!-- <button onclick={() => roundNumber++} class="button button-primary mx-auto"
|
||||||
|
>Aloita peli</button
|
||||||
|
> -->
|
||||||
|
<form action="?/startGame" method="post" use:enhance>
|
||||||
|
<input type="hidden" name="selected_cliches" value={JSON.stringify(selected_cliches)} />
|
||||||
|
<input
|
||||||
|
type="hidden"
|
||||||
|
name="selected_bonus_cliches"
|
||||||
|
value={JSON.stringify(selected_bonus_cliches)}
|
||||||
|
/>
|
||||||
|
<button type="submit" class="button button-primary mx-auto">Aloita peli</button>
|
||||||
|
</form>
|
||||||
|
{:else}
|
||||||
|
<button class="button button-disabled mx-auto" disabled>Korjaa valintaa</button>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if data.selected_cliches.baseCards.length > 0}
|
||||||
|
<p class="text-center text-xl font-semibold">Peli alkaa</p>
|
||||||
|
<form action="?/endGame" method="post" use:enhance>
|
||||||
|
<div>
|
||||||
|
<p class="text-center">Valitut kortit</p>
|
||||||
|
{#each data.selected_cliches.baseCards as cliche}
|
||||||
|
<Card cardData={cliche} onCardChecked={setResult} isBonus={false} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p class="text-center">Valitut bonus kortit</p>
|
||||||
|
{#each data.selected_cliches.bonusCards as cliche}
|
||||||
|
<Card cardData={cliche} onCardChecked={setResult} isBonus={true} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
<input type="hidden" name="userId" id="userId" value={data.user.id} />
|
||||||
|
<input type="hidden" name="movieId" id="movieId" value={data.movie.id} />
|
||||||
|
<input
|
||||||
|
type="hidden"
|
||||||
|
name="result_cards"
|
||||||
|
id="result_cards"
|
||||||
|
value={JSON.stringify(result_cards)}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="hidden"
|
||||||
|
name="result_bonus_cards"
|
||||||
|
id="result_bonus_cards"
|
||||||
|
value={JSON.stringify(result_bonus_cards)}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="hidden"
|
||||||
|
name="bonusCards"
|
||||||
|
id="bonusCards"
|
||||||
|
value={JSON.stringify(data.selected_cliches.bonusCards)}
|
||||||
|
/>
|
||||||
|
<button type="submit" class="button button-primary mx-auto">Lopeta</button>
|
||||||
|
</form>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { PageData } from './$types';
|
||||||
|
|
||||||
|
export let data: PageData;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex flex-col items-center space-y-4">
|
||||||
|
<h1 class="text-2xl font-semibold">Game Over!</h1>
|
||||||
|
<p class="text-md">Peli on päättynyt!</p>
|
||||||
|
<p class="text-md">Sait</p>
|
||||||
|
<p class="rounded-xl border-2 p-4 text-xl font-semibold">{data.score}</p>
|
||||||
|
<p class="text-md">pistettä!</p>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export function load({ params }) {
|
||||||
|
return {
|
||||||
|
score: params.score
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -6,5 +6,15 @@ export const load: PageServerLoad = async (event) => {
|
|||||||
sameSite: 'strict',
|
sameSite: 'strict',
|
||||||
secure: false,
|
secure: false,
|
||||||
});
|
});
|
||||||
|
event.cookies.delete('selected_cliches', {
|
||||||
|
path: '/',
|
||||||
|
sameSite: 'strict',
|
||||||
|
secure: false,
|
||||||
|
});
|
||||||
|
event.cookies.delete('selected_bonus_cliches', {
|
||||||
|
path: '/',
|
||||||
|
sameSite: 'strict',
|
||||||
|
secure: false,
|
||||||
|
});
|
||||||
throw redirect(302, '/login');
|
throw redirect(302, '/login');
|
||||||
};
|
};
|
||||||
Reference in New Issue
Block a user