desker/apps/web/src/routes/login/+page.svelte

84 lines
3.2 KiB
Svelte

<script lang="ts">
import { token, user, logout } from "$lib/stores/auth";
import { goto } from "$app/navigation";
import { page } from "$app/stores";
import { apiFetch } from "$lib/api/client";
let email = "";
let password = "";
let error = "";
async function handleLogin() {
try {
const data: any = await apiFetch("/auth/login", {
method: "POST",
body: JSON.stringify({ email, password }),
});
token.set(data.access_token);
user.set(data.user);
const redirect = $page.url.searchParams.get("redirect") || "/dashboard";
goto(redirect);
} catch (e: any) {
if (e.message?.includes('401')) {
error = "Invalid credentials";
} else {
error = "Failed to connect to server";
}
}
}
function handleLogout() {
logout();
goto("/login");
}
</script>
<div class="flex items-center justify-center min-h-screen bg-gray-100 p-4">
<div class="p-8 bg-white rounded shadow-md w-full max-w-md">
{#if $token}
<div class="text-center">
<h1 class="text-2xl font-bold mb-6">User Profile</h1>
<div class="bg-blue-50 p-4 rounded-lg mb-6 text-left">
<p class="text-sm text-gray-500 uppercase font-bold mb-1">Email</p>
<p class="text-lg mb-4">{$user?.email}</p>
<p class="text-sm text-gray-500 uppercase font-bold mb-1">Role</p>
<p class="text-lg mb-4 capitalize">{$user?.role}</p>
<p class="text-sm text-gray-500 uppercase font-bold mb-1">Organization ID</p>
<p class="text-xs font-mono text-gray-600">{$user?.organizationId}</p>
</div>
<div class="flex gap-4">
<a href="/dashboard" class="flex-1 bg-gray-100 text-gray-700 p-2 rounded hover:bg-gray-200 text-center font-semibold">Dashboard</a>
<button on:click={handleLogout} class="flex-1 bg-red-600 text-white p-2 rounded hover:bg-red-700 font-semibold">Sign Out</button>
</div>
</div>
{:else}
<h1 class="text-2xl font-bold mb-6 text-center">Login</h1>
{#if error}
<div class="bg-red-50 text-red-600 p-3 rounded mb-4 text-center text-sm">
{error}
</div>
{/if}
<form on:submit|preventDefault={handleLogin} class="space-y-4">
<div>
<label class="block text-gray-700 text-sm font-bold mb-1" for="email">Email Address</label>
<input id="email" type="email" bind:value={email} class="w-full p-2 border rounded focus:ring-2 focus:ring-blue-500 outline-none" placeholder="name@example.com" required />
</div>
<div>
<label class="block text-gray-700 text-sm font-bold mb-1" for="password">Password</label>
<input id="password" type="password" bind:value={password} class="w-full p-2 border rounded focus:ring-2 focus:ring-blue-500 outline-none" placeholder="••••••••" required />
</div>
<button type="submit" class="w-full bg-blue-600 text-white p-2 rounded hover:bg-blue-700 font-semibold transition-colors">Sign In</button>
</form>
<div class="mt-6 text-center text-sm text-gray-500">
<p>Use seeded credentials:</p>
<p class="font-mono mt-1">admin@example.com / admin123</p>
</div>
{/if}
</div>
</div>