Add notifications overview (#414)
Co-authored-by: kolaente <k@knt.li> Reviewed-on: https://kolaente.dev/vikunja/frontend/pulls/414 Co-authored-by: konrad <konrad@kola-entertainments.de> Co-committed-by: konrad <konrad@kola-entertainments.de>
This commit is contained in:
@ -37,6 +37,7 @@
|
||||
|
||||
<div class="navbar-end">
|
||||
<update/>
|
||||
<notifications/>
|
||||
<div class="user">
|
||||
<img :src="userAvatar" alt="" class="avatar"/>
|
||||
<dropdown class="is-right">
|
||||
@ -86,10 +87,12 @@ import Rights from '@/models/rights.json'
|
||||
import Update from '@/components/home/update'
|
||||
import ListSettingsDropdown from '@/components/list/list-settings-dropdown'
|
||||
import Dropdown from '@/components/misc/dropdown'
|
||||
import Notifications from '@/components/notifications/notifications'
|
||||
|
||||
export default {
|
||||
name: 'topNavigation',
|
||||
components: {
|
||||
Notifications,
|
||||
Dropdown,
|
||||
ListSettingsDropdown,
|
||||
Update,
|
||||
|
135
src/components/notifications/notifications.vue
Normal file
135
src/components/notifications/notifications.vue
Normal file
@ -0,0 +1,135 @@
|
||||
<template>
|
||||
<div class="notifications">
|
||||
<a @click.stop="showNotifications = !showNotifications" class="trigger">
|
||||
<span class="unread-indicator" v-if="unreadNotifications > 0"></span>
|
||||
<icon icon="bell"/>
|
||||
</a>
|
||||
|
||||
<transition name="fade">
|
||||
<div class="notifications-list" v-if="showNotifications" ref="popup">
|
||||
<span class="head">Notifications</span>
|
||||
<div
|
||||
v-for="(n, index) in notifications"
|
||||
:key="n.id"
|
||||
class="single-notification"
|
||||
>
|
||||
<div class="read-indicator" :class="{'read': n.readAt !== null}"></div>
|
||||
<user
|
||||
:user="n.notification.doer"
|
||||
:show-username="true"
|
||||
:avatar-size="16"
|
||||
v-if="n.notification.doer"/>
|
||||
<span class="detail">
|
||||
<a @click="() => to(n, index)()">
|
||||
{{ n.toText(userInfo) }}
|
||||
</a>
|
||||
<span class="created" v-tooltip="formatDate(n.created)">
|
||||
{{ formatDateSince(n.created) }}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<p class="nothing" v-if="notifications.length === 0">
|
||||
You don't have any notifications. Have a nice day!<br/>
|
||||
<span class="explainer">
|
||||
Notifications will appear here when actions on namespaces, lists or tasks you subscribed to happen.
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import NotificationService from '@/services/notification'
|
||||
import User from '@/components/misc/user'
|
||||
import names from '@/models/notificationNames.json'
|
||||
import {closeWhenClickedOutside} from '@/helpers/closeWhenClickedOutside'
|
||||
import {mapState} from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'notifications',
|
||||
components: {User},
|
||||
data() {
|
||||
return {
|
||||
notificationService: NotificationService,
|
||||
notifications: [],
|
||||
showNotifications: false,
|
||||
interval: null,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.notificationService = new NotificationService()
|
||||
},
|
||||
mounted() {
|
||||
this.loadNotifications()
|
||||
document.addEventListener('click', this.hidePopup)
|
||||
this.interval = setInterval(this.loadNotifications, 10000)
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener('click', this.hidePopup)
|
||||
clearInterval(this.interval)
|
||||
},
|
||||
computed: {
|
||||
unreadNotifications() {
|
||||
return this.notifications.filter(n => n.readAt === null).length
|
||||
},
|
||||
...mapState({
|
||||
userInfo: state => state.auth.info,
|
||||
}),
|
||||
},
|
||||
methods: {
|
||||
hidePopup(e) {
|
||||
if (this.showNotifications) {
|
||||
closeWhenClickedOutside(e, this.$refs.popup, () => this.showNotifications = false)
|
||||
}
|
||||
},
|
||||
loadNotifications() {
|
||||
this.notificationService.getAll()
|
||||
.then(r => {
|
||||
this.$set(this, 'notifications', r)
|
||||
})
|
||||
.catch(e => {
|
||||
this.error(e, this)
|
||||
})
|
||||
},
|
||||
to(n, index) {
|
||||
const to = {
|
||||
name: '',
|
||||
params: {},
|
||||
}
|
||||
|
||||
switch (n.name) {
|
||||
case names.TASK_COMMENT:
|
||||
case names.TASK_ASSIGNED:
|
||||
to.name = 'task.detail'
|
||||
to.params.id = n.notification.task.id
|
||||
break
|
||||
case names.TASK_DELETED:
|
||||
// Nothing
|
||||
break
|
||||
case names.LIST_CREATED:
|
||||
to.name = 'task.index'
|
||||
to.params.listId = n.notification.list.id
|
||||
break
|
||||
case names.TEAM_MEMBER_ADDED:
|
||||
to.name = 'teams.edit'
|
||||
to.params.id = n.notification.team.id
|
||||
break
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (to.name !== '') {
|
||||
this.$router.push(to)
|
||||
}
|
||||
|
||||
n.read = true
|
||||
this.notificationService.update(n)
|
||||
.then(r => {
|
||||
this.$set(this.notifications, index, r)
|
||||
})
|
||||
.catch(e => this.error(e, this))
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
@ -1,10 +1,7 @@
|
||||
<template>
|
||||
<div class="heading">
|
||||
<h1 class="title task-id" v-if="task.identifier === ''">
|
||||
#{{ task.index }}
|
||||
</h1>
|
||||
<h1 class="title task-id" v-else>
|
||||
{{ task.identifier }}
|
||||
<h1 class="title task-id">
|
||||
{{ task.getTextIdentifier() }}
|
||||
</h1>
|
||||
<div class="is-done" v-if="task.done">Done</div>
|
||||
<h1
|
||||
|
Reference in New Issue
Block a user