Compare commits

..
4 Commits
Author SHA1 Message Date
Esa Kataja fdbc7a2b23 Add message when login failed 2025-05-10 13:37:25 +03:00
Esa Kataja 524e9fab7e Add example env config 2025-05-10 13:36:44 +03:00
Esa Kataja 6e06161939 chore: update Nuxt compatibility date to May 2025 2025-05-10 13:04:40 +03:00
Esa Kataja a87cc4018c Add login functionality 2025-05-10 13:04:30 +03:00
4 changed files with 95 additions and 7 deletions
+1
View File
@@ -0,0 +1 @@
API_BASE=http://your-server-ip-or-domain:8000
+60 -3
View File
@@ -1,10 +1,67 @@
<script setup lang="ts">
import { onMounted } from 'vue'
import { useState, useRuntimeConfig } from '#imports'
// Using Nuxt's useState composable instead of Vue's ref
const config = useRuntimeConfig()
const apiBase = config.public.apiBase
const user = useState('user', () => ({}))
const isLoggedIn = useState('isLoggedIn', () => false)
onMounted(() => {
// Checking if code is running in browser environment before accessing localStorage
if (process.client) {
try {
const userData = JSON.parse(localStorage.getItem('user') || '{}')
user.value = userData
if (Object.keys(userData).length > 0) {
isLoggedIn.value = true
}
} catch (error) {
console.error('Error accessing localStorage:', error)
}
}
})
const logout = () => {
if (process.client) {
try {
localStorage.removeItem('user')
isLoggedIn.value = false
user.value = {}
} catch (error) {
console.error('Error during logout:', error)
}
}
}
</script>
<template> <template>
<header class="p-4 shadow-md flex justify-between bg-slate-100"> <header class="p-4 shadow-md flex justify-between bg-slate-100">
<h1><NuxtLink to="/">Eurovision 2025</NuxtLink></h1> <h1><NuxtLink to="/">Eurovision 2025</NuxtLink></h1>
<nav> <nav>
<ul class="flex gap-4"> <ul class="flex items-center gap-4">
<li><NuxtLink to="/profile">Profile</NuxtLink></li> <li v-if="isLoggedIn" class="flex items-center gap-2">
<li><NuxtLink to="/login">Login</NuxtLink></li> <NuxtLink to="/profile">
<NuxtImg
v-if="'avatar_id' in user"
:src="`${apiBase}/static/avatars/${user.avatar_id}.webp`"
class="w-4 h-4 rounded-full object-cover"
:alt="user.username"
/></NuxtLink>
</li>
<li v-if="!isLoggedIn">
<NuxtLink to="/login" class="flex items-center gap-1">
<Icon name="qlementine-icons:log-in-16" class="w-5 h-5" />
</NuxtLink>
</li>
<li v-if="isLoggedIn">
<button @click="logout" class="flex items-center gap-1">
<Icon name="qlementine-icons:log-out-16" class="w-5 h-5" />
</button>
</li>
</ul> </ul>
</nav> </nav>
</header> </header>
+1 -1
View File
@@ -2,7 +2,7 @@ import tailwindcss from "@tailwindcss/vite";
// https://nuxt.com/docs/api/configuration/nuxt-config // https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({ export default defineNuxtConfig({
compatibilityDate: '2024-11-01', compatibilityDate: '2025-05-10',
devtools: { enabled: true }, devtools: { enabled: true },
modules: [ modules: [
+32 -2
View File
@@ -3,9 +3,36 @@ definePageMeta({
layout: 'login' layout: 'login'
}) })
const login = () => { const errorMessage = ref('')
console.log('login')
const login = async () => {
// Clear any previous error messages
errorMessage.value = ''
const payload = {
username: document.getElementById('username')?.value,
password: document.getElementById('password')?.value
}
const config = useRuntimeConfig()
const apiBase = config.public.apiBase
const api_url = `${apiBase}/auth/token`
try {
const { data: user } = await useFetch(api_url, {
method: 'POST',
body: payload
})
if (!user.value) {
errorMessage.value = 'Kirjautuminen epäonnistui. Tarkista käyttäjätunnus ja salasana.'
return
}
localStorage.setItem('user', JSON.stringify(user.value))
navigateTo('/') navigateTo('/')
} catch (error) {
errorMessage.value = 'Kirjautuminen epäonnistui. Palvelimeen ei saada yhteyttä.'
}
} }
</script> </script>
@@ -14,6 +41,9 @@ const login = () => {
<div class="flex flex-col gap-4 m-6 bg-slate-300 rounded-2xl p-6 shadow-md text-sm"> <div class="flex flex-col gap-4 m-6 bg-slate-300 rounded-2xl p-6 shadow-md text-sm">
<h1 class="text-center font-bold text-lg">Kirjaudu</h1> <h1 class="text-center font-bold text-lg">Kirjaudu</h1>
<form @submit.prevent="login" class=""> <form @submit.prevent="login" class="">
<div v-if="errorMessage" class="error-message p-2 my-2 bg-red-100 text-red-700 rounded border border-red-300">
{{ errorMessage }}
</div>
<label>Käyttäjätunnus <label>Käyttäjätunnus
<input class="textfield" type="text" id="username" placeholder="Käyttäjätunnus" /> <input class="textfield" type="text" id="username" placeholder="Käyttäjätunnus" />
</label> </label>