feat: auth store, router guard and login page

This commit is contained in:
Martin 2026-03-20 01:11:20 +01:00
parent 26e3efed81
commit 19aca0e5fc
3 changed files with 104 additions and 2 deletions

View File

@ -1,4 +1,5 @@
import { createRouter, createWebHistory } from 'vue-router' import { createRouter, createWebHistory } from 'vue-router'
import { useAuthStore } from '../stores/auth'
const router = createRouter({ const router = createRouter({
history: createWebHistory(), history: createWebHistory(),
@ -9,4 +10,11 @@ const router = createRouter({
], ],
}) })
router.beforeEach((to) => {
if (to.meta.public) return true
const auth = useAuthStore()
if (!auth.isAuthenticated) return '/login'
return true
})
export default router export default router

View File

@ -0,0 +1,30 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { authApi } from '../api'
export const useAuthStore = defineStore('auth', () => {
const token = ref<string | null>(localStorage.getItem('token'))
const expiresAt = ref<string | null>(localStorage.getItem('expiresAt'))
const isAuthenticated = computed(() => {
if (!token.value || !expiresAt.value) return false
return Date.now() < Date.parse(expiresAt.value)
})
async function login(username: string, password: string): Promise<void> {
const response = await authApi.login({ username, password })
token.value = response.token ?? null
expiresAt.value = response.expiresAt ?? null
if (token.value) localStorage.setItem('token', token.value)
if (expiresAt.value) localStorage.setItem('expiresAt', expiresAt.value)
}
function logout() {
token.value = null
expiresAt.value = null
localStorage.removeItem('token')
localStorage.removeItem('expiresAt')
}
return { token, isAuthenticated, login, logout }
})

View File

@ -1 +1,65 @@
<template><div>Login</div></template> <script setup lang="ts">
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { useAuthStore } from '../stores/auth'
const router = useRouter()
const auth = useAuthStore()
const username = ref('')
const password = ref('')
const error = ref('')
const loading = ref(false)
async function submit() {
error.value = ''
loading.value = true
try {
await auth.login(username.value, password.value)
router.push('/')
} catch {
error.value = 'Nesprávné přihlašovací údaje.'
} finally {
loading.value = false
}
}
</script>
<template>
<v-container class="fill-height" fluid>
<v-row align="center" justify="center">
<v-col cols="12" sm="8" md="4">
<v-card>
<v-card-title class="text-h5 pa-6">Finance Tracker</v-card-title>
<v-card-text>
<v-alert v-if="error" type="error" class="mb-4">{{ error }}</v-alert>
<v-text-field
v-model="username"
label="Uživatelské jméno"
prepend-inner-icon="mdi-account"
@keyup.enter="submit"
/>
<v-text-field
v-model="password"
label="Heslo"
type="password"
prepend-inner-icon="mdi-lock"
@keyup.enter="submit"
/>
</v-card-text>
<v-card-actions class="pa-6 pt-0">
<v-btn
block
color="primary"
size="large"
:loading="loading"
@click="submit"
>
Přihlásit se
</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</v-container>
</template>