diff --git a/web/admin-gui/src/assets/base.css b/web/admin-gui/src/assets/base.css index dcce1a6..64cdbbb 100644 --- a/web/admin-gui/src/assets/base.css +++ b/web/admin-gui/src/assets/base.css @@ -6,7 +6,11 @@ --semibold-weight: 600; --bold-weight: 700; - --radius: 10px; + --radius: 15px; + + --font-body: 16px; + --font-small: 14px; + --font-verysmall: 12px; --primary: #2CD358; --primary-dark: #00BA2A; @@ -15,6 +19,7 @@ --secondary-dark: #BA0094; --secondary-light: #E88DCA; --neutral-dark: #121212; + --neutral-medium: #707070; --neutral-light: #aaaaaa; } @@ -24,8 +29,11 @@ body { h1 { font-family: 'Frank Ruhl Libre', serif; + font-size: 40px; } - +h2 { font-size: 32px; } +h3 { font-size: 24px; } +h4 { font-size: 18px; } h2, h3, h4, h5, h6 { font-family: 'Nunito', sans-serif; } @@ -37,33 +45,53 @@ h2, h3, h4, h5, h6 { color: var(--neutral-dark); } -.label-input { +.label-input, +.label-input-error { display: flex; flex-direction: column; } -.label-input label { - font-weight: var(--medium-weight); +.label-input label, +.label-input-error label { + font-size: var(--font-body); + font-weight: var(--semibold-weight); } -.label-input input { - height: 32px; - padding: 0 8px; +.label-input p, +.label-input-error p { + color: var(--neutral-medium); + font-size: var(--font-body); + font-weight: var(--medium-weight); + margin: 0; +} + +.label-input input, +.label-input-error input { + padding: 3px 16px; + font-size: var(--font-body); border: solid 1.25px var(--neutral-light); border-radius: var(--radius); } +.label-input-error input { + border: solid 1.75px red; +} + +.label-input-error p { + color: red; +} + .button-primary { border-radius: var(--radius); border: none; - height: 32px; + padding: 3px 16px; + font-size: var(--font-body); + font-weight: var(--medium-weight); background-color: var(--primary); - font-weight: var(--medium-weight); - cursor: pointer; } diff --git a/web/admin-gui/src/router/index.ts b/web/admin-gui/src/router/index.ts index 3feda3c..cacb985 100644 --- a/web/admin-gui/src/router/index.ts +++ b/web/admin-gui/src/router/index.ts @@ -1,27 +1,43 @@ -import { createRouter, createWebHistory } from 'vue-router' +import { createRouter, createWebHistory, type NavigationGuard } from 'vue-router' import Home from '@/views/Home.vue' import Debug from '@/views/Debug.vue' import Login from '@/views/Login.vue' +import { useAuthStore } from '@/stores/AuthStore' const router = createRouter({ - history: createWebHistory(import.meta.env.BASE_URL), - routes: [ - { - path: '/', - name: 'login', - component: Login - }, - { - path: '/debug', - name: 'debug', - component: Debug - }, - { - path: '/home', - name: 'home', - component: Home - }, - ] + history: createWebHistory(import.meta.env.BASE_URL), + routes: [ + { + path: '/', + name: 'login', + component: Login, + }, + { + path: '/debug', + name: 'debug', + component: Debug + }, + { + path: '/home', + name: 'home', + component: Home + }, + ] +}) + +router.beforeEach(async (to, from) => { + const isTokenValid = useAuthStore().isValid() + if (to.name === 'login') { + if (isTokenValid) return { + name: 'home' + } + } else { + if (!isTokenValid) { + return { + name: 'login', + } + } + } }) export default router diff --git a/web/admin-gui/src/stores/AuthStore.ts b/web/admin-gui/src/stores/AuthStore.ts index 387723d..3071fc9 100644 --- a/web/admin-gui/src/stores/AuthStore.ts +++ b/web/admin-gui/src/stores/AuthStore.ts @@ -1,5 +1,7 @@ +import { getCookie } from "@/utils/cookies"; import { defineStore } from "pinia"; import { ref } from "vue"; +import { useErrorsStore } from "./ErrorsStore"; export interface jwtFormat { code: number, @@ -8,8 +10,38 @@ export interface jwtFormat { } export const useAuthStore = defineStore("AuthStore", () => { - const expire = ref("") - const token = ref("") + const expire = ref("") + const token = ref("") + + function isSet(): boolean { + return token.value !== undefined && token.value !== "" + } + + function isExpired(): boolean { + const tokenDate = new Date(expire.value) + const currentDate = new Date() - return { expire, token } + if (currentDate.getTime() > tokenDate.getTime()) { + useErrorsStore().sessionExpired = true + return true + } + return false + } + + function isValid(): boolean { + return isSet() && !isExpired() + } + + function initStore(): void { + const JWTtoken = getCookie('JWTtoken') + const JWTexpire = getCookie('JWTexpire') + if (JWTtoken !== "" && JWTexpire !== "") { + token.value = JWTtoken + expire.value = JWTexpire + } + } + + initStore() + + return { expire, token, isValid } }) \ No newline at end of file diff --git a/web/admin-gui/src/stores/ErrorsStore.ts b/web/admin-gui/src/stores/ErrorsStore.ts new file mode 100644 index 0000000..b72f392 --- /dev/null +++ b/web/admin-gui/src/stores/ErrorsStore.ts @@ -0,0 +1,14 @@ +import { defineStore } from "pinia"; +import { ref, type Ref } from "vue"; + +interface storeErrors { + sessionExpired: boolean +} + +export const useErrorsStore = defineStore("ErrorsStore", () => { + const errors: Ref = ref({ + sessionExpired: false + }) + + return errors +}) \ No newline at end of file diff --git a/web/admin-gui/src/utils/cookies.ts b/web/admin-gui/src/utils/cookies.ts new file mode 100644 index 0000000..08ffbd8 --- /dev/null +++ b/web/admin-gui/src/utils/cookies.ts @@ -0,0 +1,13 @@ +export interface cookie { + key: string, + value: string, + expire: string +} + +export function setCookie(cookieData: cookie): void { + document.cookie = `${cookieData.key}=${cookieData.value}; SameSite=Strict; Expires=${cookieData.expire};Secure` +} + +export function getCookie(cookieName: string): string { + return document.cookie.match('(^|;)\\s*' + cookieName + '\\s*=\\s*([^;]+)')?.pop() || '' +} \ No newline at end of file diff --git a/web/admin-gui/src/views/Login.vue b/web/admin-gui/src/views/Login.vue index b9f0929..67c508a 100644 --- a/web/admin-gui/src/views/Login.vue +++ b/web/admin-gui/src/views/Login.vue @@ -1,22 +1,48 @@