WIP: Working homepage with Login and logout
This commit is contained in:
4
src/app.d.ts
vendored
4
src/app.d.ts
vendored
@@ -46,7 +46,3 @@ export type WebSocketMessage = {
|
|||||||
type: string;
|
type: string;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,40 +1,40 @@
|
|||||||
import { db } from '$lib/server/db';
|
import { db } from '$lib/server/db';
|
||||||
import { sessionsTable, usersTable } from '$lib/server/db/schema';
|
import { sessionsTable } from '$lib/server/db/schema';
|
||||||
import { eq } from 'drizzle-orm';
|
import { eq } from 'drizzle-orm';
|
||||||
import { redirect, type Handle } from '@sveltejs/kit';
|
import { redirect, type Handle } from '@sveltejs/kit';
|
||||||
|
|
||||||
export const handle: Handle = async ({ event, resolve }) => {
|
export const handle: Handle = async ({ event, resolve }) => {
|
||||||
const sessionId = event.cookies.get('session_id');
|
const sessionId = event.cookies.get('session_id');
|
||||||
let user = {
|
let user = {
|
||||||
isLoggedIn: false,
|
isLoggedIn: false,
|
||||||
email: "",
|
email: "",
|
||||||
username: ""
|
username: ""
|
||||||
};
|
};
|
||||||
|
|
||||||
if (sessionId) {
|
if (sessionId) {
|
||||||
const session = await db.query.sessionsTable.findFirst({
|
const session = await db.query.sessionsTable.findFirst({
|
||||||
with: {
|
with: {
|
||||||
user: true
|
user: true
|
||||||
},
|
},
|
||||||
where: eq(sessionsTable.id, sessionId)
|
where: eq(sessionsTable.id, sessionId)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (session && session.user && session.user.email) {
|
if (session && session.user && session.user.email) {
|
||||||
user = {
|
user = {
|
||||||
isLoggedIn: true,
|
isLoggedIn: true,
|
||||||
email: session.user.email,
|
email: session.user.email,
|
||||||
username: session.user.username || "Unknown username"
|
username: session.user.username || "Unknown username"
|
||||||
};
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.url.pathname.startsWith("/private") && !user.isLoggedIn) {
|
|
||||||
redirect(307, "/error");
|
|
||||||
} else if (event.url.pathname.startsWith("/api") && !user.isLoggedIn) {
|
|
||||||
return new Response(null, { status: 401 });
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
event.locals.user = user;
|
if (event.url.pathname.startsWith("/private") && !user.isLoggedIn) {
|
||||||
const response = await resolve(event);
|
redirect(307, "/error");
|
||||||
return response;
|
} else if (event.url.pathname.startsWith("/api") && !user.isLoggedIn) {
|
||||||
}
|
return new Response(null, { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
event.locals.user = user;
|
||||||
|
const response = await resolve(event);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import favicon from '$lib/assets/favicon.svg';
|
import favicon from '$lib/assets/favicon.svg';
|
||||||
import "../app.css";
|
import '../app.css';
|
||||||
let { children } = $props();
|
let { children } = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -9,3 +9,12 @@
|
|||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
{@render children?.()}
|
{@render children?.()}
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<footer class="bg-white py-6">
|
||||||
|
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<p class="text-center text-gray-500 text-sm">
|
||||||
|
© 2025 Pablu. All rights reserved.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|||||||
@@ -1,46 +1,8 @@
|
|||||||
import { db } from "$lib/server/db";
|
|
||||||
import { sessionsTable, usersTable } from "$lib/server/db/schema";
|
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import { redirect, type Actions } from "@sveltejs/kit";
|
|
||||||
import type { PageServerLoad } from "./$types";
|
import type { PageServerLoad } from "./$types";
|
||||||
|
|
||||||
|
|
||||||
export const load: PageServerLoad = async ({ locals }) => {
|
export const load: PageServerLoad = async ({ locals }) => {
|
||||||
let allUsers = null;
|
return {
|
||||||
if (locals.user.isLoggedIn) {
|
user: locals.user,
|
||||||
allUsers = await db.select().from(usersTable);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
user: locals.user,
|
|
||||||
users: allUsers ?? []
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const actions = {
|
|
||||||
logout: async ({ locals, cookies }) => {
|
|
||||||
const sessionId = cookies.get('session_id');
|
|
||||||
|
|
||||||
if (!sessionId) {
|
|
||||||
redirect(307, "/error")
|
|
||||||
}
|
|
||||||
|
|
||||||
await db.delete(sessionsTable).where(eq(sessionsTable.id, sessionId))
|
|
||||||
|
|
||||||
cookies.delete('session_id', { path: "/" });
|
|
||||||
locals.user.isLoggedIn = false;
|
|
||||||
locals.user.email = null;
|
|
||||||
locals.user.username = null;
|
|
||||||
|
|
||||||
return { success: true };
|
|
||||||
},
|
|
||||||
deleteUsers: async ({ locals, fetch }) => {
|
|
||||||
await fetch("/api/deleteUsers");
|
|
||||||
|
|
||||||
locals.user.isLoggedIn = false;
|
|
||||||
locals.user.email = null;
|
|
||||||
locals.user.username = null;
|
|
||||||
|
|
||||||
return { success: true }
|
|
||||||
}
|
|
||||||
} satisfies Actions;
|
|
||||||
@@ -2,64 +2,158 @@
|
|||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import type { PageProps } from './$types';
|
import type { PageProps } from './$types';
|
||||||
|
|
||||||
let { data, form }: PageProps = $props();
|
let lobbyCode = $state('');
|
||||||
|
let isLoggingIn = $state(false);
|
||||||
|
let loginError = $state('');
|
||||||
|
|
||||||
|
let { data }: PageProps = $props();
|
||||||
|
let user = $state(data.user);
|
||||||
|
|
||||||
|
|
||||||
|
// Example login function (would connect to a real auth service)
|
||||||
|
function handleLogin() {
|
||||||
|
isLoggingIn = true;
|
||||||
|
loginError = '';
|
||||||
|
|
||||||
|
goto('/login');
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleLogout() {
|
||||||
|
user.isLoggedIn = false;
|
||||||
|
user.username = null;
|
||||||
|
user.email = null;
|
||||||
|
|
||||||
|
goto("/logout");
|
||||||
|
}
|
||||||
|
|
||||||
|
function createLobby() {
|
||||||
|
goto('/lobby/create');
|
||||||
|
}
|
||||||
|
|
||||||
|
function joinLobby() {
|
||||||
|
if (lobbyCode.trim()) {
|
||||||
|
goto(`/lobby/${lobbyCode}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<h1>Welcome to SvelteKit</h1>
|
<div class="min-h-screen bg-white flex flex-col">
|
||||||
<p>Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the documentation</p>
|
<!-- Header -->
|
||||||
|
<header class="bg-white shadow-sm py-4">
|
||||||
|
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 flex justify-between items-center">
|
||||||
|
<h1 class="text-2xl font-bold text-indigo-600">Hitstar</h1>
|
||||||
|
|
||||||
<!-- <div>
|
{#if user.isLoggedIn}
|
||||||
<label>Email: <input type="text" bind:value={email} /></label>
|
<div class="flex items-center">
|
||||||
<label>Username: <input type="text" bind:value={username} /></label>
|
<span class="mr-4 text-gray-700">Welcome, {user.username}</span>
|
||||||
</div> -->
|
<button
|
||||||
|
class="px-4 py-2 rounded-md text-gray-600 hover:text-gray-900 hover:bg-gray-100 transition-colors"
|
||||||
|
onclick={handleLogout}
|
||||||
|
>
|
||||||
|
Log Out
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
{#if form?.success}
|
<!-- Main Content -->
|
||||||
<p>Successfully logged out</p>
|
<main class="flex-1 flex flex-col items-center justify-center px-4">
|
||||||
{/if}
|
<div class="w-full max-w-md">
|
||||||
|
<!-- Hero -->
|
||||||
|
<div class="text-center mb-12">
|
||||||
|
<h2 class="text-4xl font-bold text-gray-800 mb-4">Test Your Music Knowledge</h2>
|
||||||
|
<p class="text-xl text-gray-600">Place songs on a timeline in the correct order.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
{#if !data.user.isLoggedIn}
|
{#if !user.isLoggedIn}
|
||||||
<button onclick={async () => await goto('/login')}> Login </button>
|
<!-- Login Section -->
|
||||||
{:else}
|
<div class="bg-white rounded-lg shadow-md p-8 mb-6">
|
||||||
<h2>Hello {data.user.username}</h2>
|
<h3 class="text-xl font-semibold text-gray-800 mb-6">Sign In to Play</h3>
|
||||||
<form method="POST" action="?/logout">
|
|
||||||
<button type="submit">Logout</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<form method="POST" action="?/deleteUsers">
|
{#if loginError}
|
||||||
<button type="submit">Delete all Users</button>
|
<div class="bg-red-50 text-red-700 p-3 rounded-md mb-4 text-sm">
|
||||||
</form>
|
{loginError}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<button type="submit" onclick={async () => await goto("/lobby/create")}>Create Lobby</button>
|
<button
|
||||||
{/if}
|
class="w-full py-3 px-4 bg-indigo-600 hover:bg-indigo-700 text-white font-medium rounded-md transition-colors flex justify-center items-center"
|
||||||
<!--
|
onclick={handleLogin}
|
||||||
<button
|
disabled={isLoggingIn}
|
||||||
onclick={async () => {
|
>
|
||||||
const response = await fetch('/api/createUser', {
|
{#if isLoggingIn}
|
||||||
method: 'POST',
|
<svg
|
||||||
body: JSON.stringify({
|
class="animate-spin -ml-1 mr-2 h-4 w-4 text-white"
|
||||||
email: email,
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
username: username
|
fill="none"
|
||||||
}),
|
viewBox="0 0 24 24"
|
||||||
headers: {
|
>
|
||||||
'Content-Type': 'application/json'
|
<circle
|
||||||
}
|
class="opacity-25"
|
||||||
});
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="10"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="4"
|
||||||
|
></circle>
|
||||||
|
<path
|
||||||
|
class="opacity-75"
|
||||||
|
fill="currentColor"
|
||||||
|
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
Logging in...
|
||||||
|
{:else}
|
||||||
|
Login to Play
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<!-- Game Options -->
|
||||||
|
<div class="bg-white rounded-lg shadow-md p-8 space-y-6">
|
||||||
|
<h3 class="text-xl font-semibold text-gray-800 mb-6">Ready to Play?</h3>
|
||||||
|
|
||||||
console.log(response.status);
|
<button
|
||||||
|
class="w-full py-3 px-4 bg-indigo-600 hover:bg-indigo-700 text-white font-medium rounded-md transition-colors flex items-center justify-center"
|
||||||
|
onclick={createLobby}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="h-5 w-5 mr-2"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M12 6v6m0 0v6m0-6h6m-6 0H6"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
Create New Lobby
|
||||||
|
</button>
|
||||||
|
|
||||||
if (response.ok) {
|
<div class="relative mt-4">
|
||||||
const newUser: Array<any> = await response.json();
|
<div class="flex rounded-md shadow-sm">
|
||||||
users.push(...newUser);
|
<input
|
||||||
} else {
|
type="text"
|
||||||
console.log(`Encountered Error ${response.status}`);
|
bind:value={lobbyCode}
|
||||||
}
|
placeholder="Enter lobby code"
|
||||||
}}>Create User</button
|
class="flex-1 min-w-0 block w-full px-3 py-3 rounded-none rounded-l-md border border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500"
|
||||||
> -->
|
/>
|
||||||
|
<button
|
||||||
<ul>
|
class="inline-flex items-center px-4 py-2 border border-l-0 border-gray-300 rounded-r-md bg-indigo-600 hover:bg-indigo-700 text-white font-medium"
|
||||||
{#each data.users as user (user.email)}
|
onclick={joinLobby}
|
||||||
<li>
|
disabled={!lobbyCode.trim()}
|
||||||
{user.username} = {user.email}
|
>
|
||||||
</li>
|
Join Lobby
|
||||||
{/each}
|
</button>
|
||||||
</ul>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
import { generateRandomString } from "$lib/server/auth/spotify";
|
|
||||||
import type { states } from "$lib/server/db/schema";
|
|
||||||
import { redirect } from "@sveltejs/kit";
|
import { redirect } from "@sveltejs/kit";
|
||||||
import type { PageServerLoad } from "./$types";
|
import type { PageServerLoad } from "./$types";
|
||||||
import { setContext } from "svelte";
|
|
||||||
|
|
||||||
|
|
||||||
export const load: PageServerLoad = async ({locals, fetch}) => {
|
export const load: PageServerLoad = async ({locals, fetch}) => {
|
||||||
const response = await fetch("/api/createLobby", {
|
const response = await fetch("/api/createLobby", {
|
||||||
@@ -19,4 +15,4 @@ export const load: PageServerLoad = async ({locals, fetch}) => {
|
|||||||
const lobby = await response.json();
|
const lobby = await response.json();
|
||||||
|
|
||||||
redirect(307, `/lobby/${lobby.id}`);
|
redirect(307, `/lobby/${lobby.id}`);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user