| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- <script>
- import { onMount } from 'svelte';
- import { authentication } from '../store.js';
- import { goto } from '$app/navigation';
- import { fade } from 'svelte/transition';
- let isAuthenticated = false;
- let isLoading = true;
- let showPassword = false;
- let isDisabled = false;
- $: authentication.subscribe((value) => {
- isAuthenticated = !!value;
- });
- onMount(() => {
- try {
- const storedAuth = localStorage.getItem('authentication');
- if (storedAuth) {
- authentication.set(JSON.parse(storedAuth));
- goto('/portfolio');
- }
- } catch (error) {
- console.error('Error parsing stored auth:', error);
- } finally {
- isLoading = false;
- }
- });
- async function submit(event) {
- event.preventDefault();
- isDisabled = true;
- const formData = new FormData(event.target);
- const username = formData.get('username');
- const password = formData.get('password');
- if (!username || !password) {
- alert('Please enter both username and password.');
- return;
- }
- const data = {
- username: username,
- password: password
- };
- try {
- const response = await fetch(import.meta.env.VITE_AUTH_HOST + '/api/authenticate', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify(data)
- });
- if (response.ok) {
- const result = await response.json();
- authentication.set(result);
- localStorage.setItem('authentication', JSON.stringify(result));
- await goto('/portfolio');
- } else {
- const error = await response.json();
- console.error('Login failed:', error);
- alert('Login failed: ' + error.message);
- }
- } catch (err) {
- console.error('Error during login:', err);
- alert('An error occurred. Please try again.');
- } finally {
- isDisabled = false;
- }
- }
- function navigateToRegister() {
- window.location.href = '/register';
- }
- function togglePasswordVisibility() {
- showPassword = !showPassword;
- }
- </script>
- <svelte:head>
- <title>Login</title>
- <meta name="description" content="Login page" />
- </svelte:head>
- <div in:fade class="flex justify-center items-center min-h-[70vh] px-4">
- {#if isLoading}
- <p class="text-gray-500 dark:text-gray-400">Loading...</p>
- {:else if !isAuthenticated}
- <div class="w-full max-w-sm bg-white dark:bg-gray-900 shadow-md rounded-xl p-6 space-y-6">
- <form on:submit={submit} class="space-y-4">
- <!-- Username -->
- <input
- type="text"
- name="username"
- placeholder="Username"
- class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-800 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
- />
- <!-- Password -->
- <div class="relative">
- <input
- type={showPassword ? 'text' : 'password'}
- name="password"
- placeholder="Password"
- class="w-full px-4 py-2 pr-10 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-800 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
- />
- <!-- Visibility toggle -->
- <span
- on:click={togglePasswordVisibility}
- class="absolute inset-y-0 right-3 flex items-center text-gray-500 dark:text-gray-400 cursor-pointer"
- >
- {#if showPassword}
- <!-- Eye Off Icon -->
- <svg
- xmlns="http://www.w3.org/2000/svg"
- class="h-5 w-5"
- fill="none"
- viewBox="0 0 24 24"
- stroke="currentColor"
- >
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- stroke-width="2"
- d="M13.875 18.825A10.05 10.05 0 0112 19c-5.523 0-10-4.03-10-9s4.477-9 10-9a9.96 9.96 0 014.586 1.055M15 12a3 3 0 11-6 0 3 3 0 016 0z"
- />
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- stroke-width="2"
- d="M2.458 12C3.732 15.943 7.46 19 12 19c1.5 0 2.91-.358 4.158-.99M19.742 16.018a9.97 9.97 0 002.258-4.018M15 12a3 3 0 00-3-3m0 0a3 3 0 01-3 3"
- />
- </svg>
- {:else}
- <!-- Eye Icon -->
- <svg
- xmlns="http://www.w3.org/2000/svg"
- class="h-5 w-5"
- fill="none"
- viewBox="0 0 24 24"
- stroke="currentColor"
- >
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- stroke-width="2"
- d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
- />
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- stroke-width="2"
- d="M2.458 12C3.732 15.943 7.46 19 12 19c4.54 0 8.268-3.057 9.542-7-1.274-3.943-5.002-7-9.542-7S3.732 8.057 2.458 12z"
- />
- </svg>
- {/if}
- </span>
- </div>
- <!-- Buttons -->
- <button
- type="submit"
- class="w-full bg-blue-500 hover:bg-blue-600 text-white py-2 rounded-lg transition flex justify-center items-center gap-2"
- disabled={isDisabled}
- >
- {#if isDisabled}
- <svg
- class="animate-spin h-5 w-5 text-white"
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 24 24"
- >
- <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-8v8H4z"></path>
- </svg>
- <span>Logging in...</span>
- {:else}
- <span>Login</span>
- {/if}
- </button>
- <button
- type="button"
- class="w-full bg-gray-300 hover:bg-gray-400 text-gray-800 py-2 rounded-lg transition"
- on:click={navigateToRegister}
- disabled={isDisabled}
- >
- Register
- </button>
- </form>
- </div>
- {/if}
- </div>
|