mattwr18 3f30d93726 refactor: update notifications to return count
- still working on getting the counter to be reactive when markAsRead,
  subscribeToMore are triggered
2020-04-20 15:05:06 +02:00

145 lines
3.8 KiB
Vue

<template>
<nuxt-link v-if="!notificationsCount" class="notifications-menu" :to="{ name: 'notifications' }">
<base-button icon="bell" ghost circle />
</nuxt-link>
<dropdown v-else class="notifications-menu" offset="8" :placement="placement">
<template #default="{ toggleMenu }">
<base-button @click="toggleMenu" ghost circle>
<counter-icon icon="bell" :count="notificationsCount" danger />
</base-button>
</template>
<template slot="popover">
<div class="notifications-menu-popover">
<notification-list :notifications="unreadNotifications" @markAsRead="markAsRead" />
</div>
<div class="notifications-link-container">
<nuxt-link :to="{ name: 'notifications' }">
{{
notificationsCount > 25
? $t('notifications.manyNotifications', { notificationsCount })
: $t('notifications.pageLink')
}}
</nuxt-link>
</div>
</template>
</dropdown>
</template>
<script>
import { mapGetters } from 'vuex'
import unionBy from 'lodash/unionBy'
import { notificationQuery, markAsReadMutation, notificationAdded } from '~/graphql/User'
import CounterIcon from '~/components/_new/generic/CounterIcon/CounterIcon'
import Dropdown from '~/components/Dropdown'
import NotificationList from '../NotificationList/NotificationList'
export default {
name: 'NotificationMenu',
components: {
CounterIcon,
Dropdown,
NotificationList,
},
data() {
return {
unreadNotifications: [],
notificationsCount: null,
}
},
props: {
placement: { type: String },
},
methods: {
async markAsRead(notificationSourceId) {
const variables = { id: notificationSourceId }
try {
await this.$apollo.mutate({
mutation: markAsReadMutation(this.$i18n),
variables,
update: () => {
this.notificationsCount--
},
})
} catch (err) {
this.$toast.error(err.message)
}
},
},
computed: {
...mapGetters({
user: 'auth/user',
}),
},
apollo: {
notifications: {
query() {
return notificationQuery(this.$i18n)
},
variables() {
return {
read: false,
orderBy: 'updatedAt_desc',
first: 25,
}
},
update({ notifications }) {
this.unreadNotifications = notifications.notifications
this.notificationsCount = notifications.notificationsCount
},
subscribeToMore: {
document: notificationAdded(),
variables() {
return {
userId: this.user.id,
}
},
updateQuery: (previousResult, { subscriptionData }) => {
const {
data: { notificationAdded: newNotification },
} = subscriptionData
return {
notificationsCount:
previousResult.notificationsCount - newNotification.notificationsCount,
unreadNotifications: unionBy(
[newNotification.notifications],
previousResult.notifications.notifications,
(notification) => notification.id,
).sort((a, b) => new Date(b.updatedAt) - new Date(a.updatedAt)),
}
},
},
error(error) {
this.$toast.error(error.message)
},
},
},
}
</script>
<style lang="scss">
.notifications-menu {
flex-shrink: 0;
display: flex;
align-items: center;
.base-button {
overflow: visible;
}
}
.notifications-menu-popover {
max-width: 500px;
margin-bottom: $size-height-base;
}
.notifications-link-container {
background-color: $background-color-softer-active;
text-align: center;
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: $size-height-base;
padding: $space-x-small;
}
</style>