feat: move notification helper to store and add translation support
This commit is contained in:
parent
def270bd08
commit
7075ab83cb
|
@ -2,19 +2,19 @@
|
||||||
<div class="single-notification">
|
<div class="single-notification">
|
||||||
<div class="read-indicator" :class="{'read': notification.readAt !== null}" />
|
<div class="read-indicator" :class="{'read': notification.readAt !== null}" />
|
||||||
<user
|
<user
|
||||||
class="user"
|
|
||||||
v-if="notification.notification.doer"
|
v-if="notification.notification.doer"
|
||||||
|
class="user"
|
||||||
:user="notification.notification.doer"
|
:user="notification.notification.doer"
|
||||||
:show-username="false"
|
:show-username="false"
|
||||||
:avatar-size="16"
|
:avatar-size="16"
|
||||||
/>
|
/>
|
||||||
<div class="detail">
|
<div class="detail">
|
||||||
<div>
|
<div>
|
||||||
<span class="has-text-weight-bold mr-1" v-if="notification.notification.doer">
|
<span v-if="notification.notification.doer" class="has-text-weight-bold mr-1">
|
||||||
{{ getDisplayName(notification.notification.doer) }}
|
{{ getDisplayName(notification.notification.doer) }}
|
||||||
</span>
|
</span>
|
||||||
<BaseButton :to="to" @click="emit('markNotificationAsRead')">
|
<BaseButton :to="getNotificationRoute(notification)" @click="emit('markNotificationAsRead')">
|
||||||
{{ notificationText }}
|
{{ getNotificationTitle(notification, userInfo) }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</div>
|
||||||
<span class="created" v-tooltip="formatDateLong(notification.created)">
|
<span class="created" v-tooltip="formatDateLong(notification.created)">
|
||||||
|
@ -27,17 +27,18 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {computed} from 'vue'
|
import {computed} from 'vue'
|
||||||
|
|
||||||
import {useAuthStore} from '@/stores/auth'
|
import type {INotification} from '@/modelTypes/INotification'
|
||||||
|
|
||||||
import {NOTIFICATION_NAMES, type INotification} from '@/modelTypes/INotification'
|
|
||||||
import BaseButton from '@/components/base/BaseButton.vue'
|
import BaseButton from '@/components/base/BaseButton.vue'
|
||||||
import User from '@/components/misc/user.vue'
|
import User from '@/components/misc/user.vue'
|
||||||
|
|
||||||
|
import {useAuthStore} from '@/stores/auth'
|
||||||
|
|
||||||
import {formatDateLong, formatDateSince} from '@/helpers/time/formatDate'
|
import {formatDateLong, formatDateSince} from '@/helpers/time/formatDate'
|
||||||
import {getDisplayName} from '@/models/user'
|
import {getDisplayName} from '@/models/user'
|
||||||
import {getTextIdentifier} from '@/models/task'
|
import {getNotificationRoute, getNotificationTitle} from '@/services/notification'
|
||||||
|
|
||||||
const props = defineProps<{
|
defineProps<{
|
||||||
notification: INotification
|
notification: INotification
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
@ -47,67 +48,6 @@ const emit = defineEmits<{
|
||||||
|
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
const userInfo = computed(() => authStore.info)
|
const userInfo = computed(() => authStore.info)
|
||||||
|
|
||||||
const to = computed(() => {
|
|
||||||
const to = {
|
|
||||||
name: '',
|
|
||||||
params: {},
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (props.notification.name) {
|
|
||||||
case NOTIFICATION_NAMES.TASK_COMMENT:
|
|
||||||
case NOTIFICATION_NAMES.TASK_ASSIGNED:
|
|
||||||
to.name = 'task.detail'
|
|
||||||
to.params.id = props.notification.notification.task.id
|
|
||||||
break
|
|
||||||
case NOTIFICATION_NAMES.TASK_DELETED:
|
|
||||||
// Nothing
|
|
||||||
break
|
|
||||||
case NOTIFICATION_NAMES.LIST_CREATED:
|
|
||||||
to.name = 'task.index'
|
|
||||||
to.params.listId = props.notification.notification.list.id
|
|
||||||
break
|
|
||||||
case NOTIFICATION_NAMES.TEAM_MEMBER_ADDED:
|
|
||||||
to.name = 'teams.edit'
|
|
||||||
to.params.id = props.notification.notification.team.id
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
return to
|
|
||||||
})
|
|
||||||
|
|
||||||
const notificationText = computed(() => {
|
|
||||||
const notification = props.notification.notification
|
|
||||||
let who = ''
|
|
||||||
|
|
||||||
switch (props.notification.name) {
|
|
||||||
case NOTIFICATION_NAMES.TASK_COMMENT:
|
|
||||||
return `commented on ${getTextIdentifier(notification.task)}`
|
|
||||||
case NOTIFICATION_NAMES.TASK_ASSIGNED:
|
|
||||||
if (userInfo.value !== null && userInfo.value.id === notification.assignee.id) {
|
|
||||||
who = 'you'
|
|
||||||
} else {
|
|
||||||
who = `${getDisplayName(notification.assignee)}`
|
|
||||||
}
|
|
||||||
|
|
||||||
return `assigned ${who} to ${getTextIdentifier(notification.task)}`
|
|
||||||
case NOTIFICATION_NAMES.TASK_DELETED:
|
|
||||||
return `deleted ${getTextIdentifier(notification.task)}`
|
|
||||||
case NOTIFICATION_NAMES.LIST_CREATED:
|
|
||||||
return `created ${notification.list.title}`
|
|
||||||
case NOTIFICATION_NAMES.TEAM_MEMBER_ADDED:
|
|
||||||
if (userInfo.value !== null && userInfo.value.id === notification.member.id) {
|
|
||||||
who = 'you'
|
|
||||||
} else {
|
|
||||||
who = `${getDisplayName(notification.member)}`
|
|
||||||
}
|
|
||||||
|
|
||||||
return `added ${who} to the ${notification.team.name} team`
|
|
||||||
}
|
|
||||||
|
|
||||||
return ''
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|
|
@ -45,6 +45,8 @@ import type {INotification} from '@/modelTypes/INotification'
|
||||||
import NavbarTriggerButton from '@/components/home/NavbarTriggerButton.vue'
|
import NavbarTriggerButton from '@/components/home/NavbarTriggerButton.vue'
|
||||||
import NotificationItem from '@/components/notifications/NotificationItem.vue'
|
import NotificationItem from '@/components/notifications/NotificationItem.vue'
|
||||||
|
|
||||||
|
import {findIndexById} from '@/helpers/utils'
|
||||||
|
|
||||||
const NOTIFICATIONS_PULL_INTERVAL = 10000
|
const NOTIFICATIONS_PULL_INTERVAL = 10000
|
||||||
|
|
||||||
const allNotifications = ref<INotification[]>([])
|
const allNotifications = ref<INotification[]>([])
|
||||||
|
@ -90,11 +92,18 @@ async function loadNotifications() {
|
||||||
allNotifications.value = await notificationService.getAll()
|
allNotifications.value = await notificationService.getAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
async function markNotificationAsRead(index: number, notification: INotification) {
|
async function markNotificationAsRead(notification: INotification) {
|
||||||
allNotifications.value[index] = await notificationService.update({
|
const index = findIndexById(allNotifications.value, notification.id)
|
||||||
|
if (index === -1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
allNotifications.value[index] = {
|
||||||
...notification,
|
...notification,
|
||||||
read: true,
|
read: true,
|
||||||
})
|
}
|
||||||
|
|
||||||
|
await notificationService.update(allNotifications.value[index])
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -134,7 +143,6 @@ async function markNotificationAsRead(index: number, notification: INotification
|
||||||
.head {
|
.head {
|
||||||
font-family: $vikunja-font;
|
font-family: $vikunja-font;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
padding: .5rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification-item:last-child {
|
.notification-item:last-child {
|
||||||
|
|
|
@ -945,7 +945,26 @@
|
||||||
"notification": {
|
"notification": {
|
||||||
"title": "Notifications",
|
"title": "Notifications",
|
||||||
"none": "You don't have any notifications. Have a nice day!",
|
"none": "You don't have any notifications. Have a nice day!",
|
||||||
"explainer": "Notifications will appear here when actions on namespaces, lists or tasks you subscribed to happen."
|
"explainer": "Notifications will appear here when actions on namespaces, lists or tasks you subscribed to happen.",
|
||||||
|
"items": {
|
||||||
|
"taskComment": {
|
||||||
|
"message": "commented on {taskIdentifier}"
|
||||||
|
},
|
||||||
|
"taskAssigned": {
|
||||||
|
"message": "assigned {user} to {taskIdentifier}",
|
||||||
|
"userYou": "you"
|
||||||
|
},
|
||||||
|
"taskDeleted": {
|
||||||
|
"message": "deleted {taskIdentifier}"
|
||||||
|
},
|
||||||
|
"listCreated": {
|
||||||
|
"message": "created {listTitle}"
|
||||||
|
},
|
||||||
|
"teamMemberAdded": {
|
||||||
|
"message": "added ${user} to the {teamName} team",
|
||||||
|
"userYou": "you"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"quickActions": {
|
"quickActions": {
|
||||||
"commands": "Commands",
|
"commands": "Commands",
|
||||||
|
|
|
@ -1,6 +1,78 @@
|
||||||
import AbstractService from '@/services/abstractService'
|
import AbstractService from '@/services/abstractService'
|
||||||
import NotificationModel from '@/models/notification'
|
import NotificationModel from '@/models/notification'
|
||||||
import type {INotification} from '@/modelTypes/INotification'
|
import {NOTIFICATION_NAMES, type INotification} from '@/modelTypes/INotification'
|
||||||
|
import type {IUser} from '@/modelTypes/IUser'
|
||||||
|
import {getTextIdentifier} from '@/models/task'
|
||||||
|
import {getDisplayName} from '@/models/user'
|
||||||
|
import {i18n} from '@/i18n'
|
||||||
|
|
||||||
|
export function getNotificationTitle(notificationItem: INotification, user: IUser | null) {
|
||||||
|
const notification = notificationItem.notification
|
||||||
|
let who: string
|
||||||
|
|
||||||
|
switch (notificationItem.name) {
|
||||||
|
case NOTIFICATION_NAMES.TASK_COMMENT:
|
||||||
|
return i18n.global.t('notification.items.taskComment.message', { taskIdentifier: getTextIdentifier(notification.task)})
|
||||||
|
case NOTIFICATION_NAMES.TASK_ASSIGNED:
|
||||||
|
who = (user !== null && user.id === notification.assignee.id)
|
||||||
|
? i18n.global.t('notification.items.taskAssigned.userYou')
|
||||||
|
: `${getDisplayName(notification.assignee)}`
|
||||||
|
|
||||||
|
return i18n.global.t('notification.items.taskAssigned.message', {
|
||||||
|
user: who,
|
||||||
|
taskIdentifier: getTextIdentifier(notification.task),
|
||||||
|
})
|
||||||
|
case NOTIFICATION_NAMES.TASK_DELETED:
|
||||||
|
// TODO: add user to title
|
||||||
|
return i18n.global.t('notification.items.taskDeleted.message', {
|
||||||
|
taskIdentifier: getTextIdentifier(notification.task),
|
||||||
|
})
|
||||||
|
case NOTIFICATION_NAMES.LIST_CREATED:
|
||||||
|
return i18n.global.t('notification.items.listCreated.message', {
|
||||||
|
listTitle: notification.list.title,
|
||||||
|
})
|
||||||
|
|
||||||
|
case NOTIFICATION_NAMES.TEAM_MEMBER_ADDED:
|
||||||
|
who = (user !== null && user.id === notification.member.id)
|
||||||
|
? i18n.global.t('notification.items.teamMemberAdded.userYou')
|
||||||
|
: `${getDisplayName(notification.member)}`
|
||||||
|
|
||||||
|
return i18n.global.t('notification.items.teamMemberAdded.message', {
|
||||||
|
user: who,
|
||||||
|
teamName: notification.team.name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getNotificationRoute(notificationItem: INotification) {
|
||||||
|
const to = {
|
||||||
|
name: '',
|
||||||
|
params: {},
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (notificationItem.name) {
|
||||||
|
case NOTIFICATION_NAMES.TASK_COMMENT:
|
||||||
|
case NOTIFICATION_NAMES.TASK_ASSIGNED:
|
||||||
|
to.name = 'task.detail'
|
||||||
|
to.params.id = notificationItem.notification.task.id
|
||||||
|
break
|
||||||
|
case NOTIFICATION_NAMES.TASK_DELETED:
|
||||||
|
// Nothing
|
||||||
|
break
|
||||||
|
case NOTIFICATION_NAMES.LIST_CREATED:
|
||||||
|
to.name = 'task.index'
|
||||||
|
to.params.listId = notificationItem.notification.list.id
|
||||||
|
break
|
||||||
|
case NOTIFICATION_NAMES.TEAM_MEMBER_ADDED:
|
||||||
|
to.name = 'teams.edit'
|
||||||
|
to.params.id = notificationItem.notification.team.id
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
return to
|
||||||
|
}
|
||||||
|
|
||||||
export default class NotificationService extends AbstractService<INotification> {
|
export default class NotificationService extends AbstractService<INotification> {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
Reference in New Issue
Block a user