implemented notification component and logic

This commit is contained in:
Sockenklaus
2021-10-21 01:24:46 +02:00
parent 5017be6d42
commit 7e5ab9b445
6 changed files with 129 additions and 26 deletions

View File

@@ -1,15 +1,24 @@
<template> <template>
<v-app> <v-app>
<v-main> <v-main>
<div class="container shadow p-3 text-center"> <Notification />
<router-view></router-view> <div class="container shadow p-3 text-center">
</div> <nav class="nav justify-content-center border-bottom mb-4 pb-2">
</v-main> <a href="" class="nav-link">Logout</a>
</v-app> <router-link class="nav-link" to="/">Home</router-link>
<router-link to="Login" class="nav-link">Login</router-link>
</nav>
<router-view></router-view>
</div>
</v-main>
</v-app>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import Notification from '@/components/Notification.vue';
</script> </script>
<style> <style>
@@ -18,6 +27,5 @@
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
color: #2c3e50; color: #2c3e50;
margin-top: 60px;
} }
</style> </style>

View File

@@ -0,0 +1,41 @@
<template>
<div class="toast-container position-absolute top-0 start-50 mt-3 translate-middle-x">
<transition-group name="fade">
<div v-for="(note, index) in notifications" :key="index" data-bs-delay="2000" data-bs-autohide="true" class="show fade toast border-0 text-white" :class="toastClasses(note.type)" role="alert" aria-live="assertive" aria-atomic="true">
<div class="d-flex">
<div class="toast-body">
{{note.text}}
</div>
<button type="button" @click="destroyAlert(index)" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast"></button>
</div>
</div>
</transition-group>
</div>
</template>
<script setup lang="ts">
import { useNotifications } from '@/stores/notifications'
import { storeToRefs } from 'pinia'
const notes = useNotifications()
const { notifications } = storeToRefs(notes)
function destroyAlert(index : number) {
notes.removeAlert(index)
}
function toastClasses(type : string){
return {
'bg-danger': type === 'danger',
'bg-success' : type === 'success',
'bg-warning' : type === 'warning'
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,20 @@
import { defineStore, acceptHMRUpdate } from 'pinia'
export const useNotifications = defineStore('notifications', {
state: () => {
return {
/**@type {{type: string, text: string}[]} */
notifications: new Array<{type: string, text: string}>()
}
},
actions: {
removeAlert(index : number) : void {
this.notifications.splice(index, 1)
}
}
})
if(import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useNotifications, import.meta.hot))
}

View File

@@ -1,5 +1,22 @@
import { defineStore } from 'pinia' import { defineStore, storeToRefs } from 'pinia'
import axios, {AxiosResponse, AxiosError} from 'axios' import axios, {AxiosResponse, AxiosError} from 'axios'
import { useNotifications } from './notifications'
type AuthSuccResult = {
notification: {
type: string,
text: string
}
user: string,
role: string
}
type AuthErrResult = {
notification: {
text: string,
type: string
}
}
export const useUser = defineStore('userStore', { export const useUser = defineStore('userStore', {
state: () => { state: () => {
@@ -12,27 +29,37 @@ export const useUser = defineStore('userStore', {
actions: { actions: {
async login(username: string, password: string) : Promise<boolean> { async login(username: string, password: string) : Promise<boolean> {
const { notifications } = storeToRefs(useNotifications())
try { try {
const response: AxiosResponse<{ const response = await axios.post<AuthSuccResult>('http://localhost:3333/api/v1/login', {
user: string,
role: string,
Message: string
}> = await axios.post('http://localhost:3333/api/v1/login', {
username: username, username: username,
password: password password: password
}) })
console.log(response.data)
this.isLoggedIn = true this.isLoggedIn = true
this.user = response.data.user this.user = response.data.user
this.role = response.data.role this.role = response.data.role
notifications.value.push({
type: response.data.notification.type,
text: response.data.notification.text,
})
return true return true
} catch(err) { } catch(err : unknown) {
if (axios.isAxiosError(err)){ if (axios.isAxiosError(err) && err.response && err.response.data){
console.log(err.response)
const data = err.response.data as AuthErrResult
const note = {
type: data.notification.type,
text: data.notification.text
}
notifications.value.push(note)
} }
return false return false
} }

View File

@@ -1,6 +1,6 @@
<template lang="pug"> <template lang="pug">
p {{ state }} //- p {{ state }}
MonthPicker(:selectedMonth="selectedMonth" :selectedYear="selectedYear" @getMonth="selectedMonth = $event" @getYear="selectedYear = $event") MonthPicker(:selectedMonth="selectedMonth" :selectedYear="selectedYear" @getMonth="selectedMonth = $event" @getYear="selectedYear = $event")

View File

@@ -1,4 +1,7 @@
<template> <template>
<br />
<img src="/src/assets/logo.png"> <img src="/src/assets/logo.png">
<form class="m-auto"> <form class="m-auto">
<h1 class="h3 mb-3">Bitte einloggen</h1> <h1 class="h3 mb-3">Bitte einloggen</h1>
@@ -24,22 +27,26 @@
<script setup lang="ts"> <script setup lang="ts">
import { useUser } from '@/stores/user' import { useUser } from '@/stores/user'
import { onMounted, reactive } from 'vue' import { useNotifications } from '@/stores/notifications'
import { reactive } from 'vue'
import { storeToRefs } from 'pinia'
import { useRouter } from 'vue-router'
const userStore = useUser() const userStore = useUser()
const noteStore = useNotifications()
const router = useRouter()
const input = reactive({ const input = reactive({
username: '', username: '',
password: '' password: ''
}) })
onMounted(() => {
})
async function onClick() { async function onClick() {
userStore.login(input.username, input.password) if(await userStore.login(input.username, input.password)) {
router.push({name: 'Home'})
}
} }