NotificationsList.vue 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. <!-- Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/ -->
  2. <script setup lang="ts">
  3. import { computed, ref } from 'vue'
  4. import { useOnlineNotificationCount } from '#shared/entities/online-notification/composables/useOnlineNotificationCount.ts'
  5. import { useOnlineNotificationMarkAllAsSeenMutation } from '#shared/entities/online-notification/graphql/mutations/markAllAsSeen.api.ts'
  6. import { useOnlineNotificationsQuery } from '#shared/entities/online-notification/graphql/queries/onlineNotifications.api.ts'
  7. import type { OnlineNotification, Scalars } from '#shared/graphql/types.ts'
  8. import {
  9. QueryHandler,
  10. MutationHandler,
  11. } from '#shared/server/apollo/handler/index.ts'
  12. import { edgesToArray } from '#shared/utils/helpers.ts'
  13. import CommonLoader from '#mobile/components/CommonLoader/CommonLoader.vue'
  14. import { useHeader } from '#mobile/composables/useHeader.ts'
  15. import NotificationItem from '../components/NotificationItem.vue'
  16. const notificationsHandler = new QueryHandler(useOnlineNotificationsQuery())
  17. const loading = notificationsHandler.loading()
  18. const notificationsResult = notificationsHandler.result()
  19. let mutationTriggered = false
  20. useHeader({
  21. backUrl: '/',
  22. backAvoidHomeButton: true,
  23. refetch: computed(() => loading.value && notificationsResult.value != null),
  24. })
  25. const notifications = computed(
  26. () =>
  27. edgesToArray(
  28. notificationsResult.value?.onlineNotifications,
  29. ) as OnlineNotification[],
  30. )
  31. const seenNotification = (id: Scalars['ID']['output']) => {
  32. const seenNotificationMutation = new MutationHandler(
  33. useOnlineNotificationMarkAllAsSeenMutation({
  34. variables: { onlineNotificationIds: [id] },
  35. }),
  36. {
  37. errorNotificationMessage: __(
  38. 'The online notification could not be marked as seen.',
  39. ),
  40. },
  41. )
  42. mutationTriggered = true
  43. seenNotificationMutation.send()
  44. }
  45. const markingAsSeen = ref(false)
  46. const markAllRead = async () => {
  47. markingAsSeen.value = true
  48. const onlineNotificationIds = notifications.value
  49. .filter((elem) => !elem.seen)
  50. .map((elem) => elem.id)
  51. const mutation = new MutationHandler(
  52. useOnlineNotificationMarkAllAsSeenMutation({
  53. variables: { onlineNotificationIds },
  54. }),
  55. {
  56. errorNotificationMessage: __('Cannot set online notifications as seen'),
  57. },
  58. )
  59. mutationTriggered = true
  60. await mutation.send()
  61. markingAsSeen.value = false
  62. }
  63. const notificationRemoved = () => {
  64. mutationTriggered = true
  65. }
  66. // TODO: currently this triggered in some situtations a real subscription on the server: https://github.com/apollographql/apollo-client/issues/10117
  67. const { unseenCount, notificationsCountSubscription } =
  68. useOnlineNotificationCount()
  69. notificationsCountSubscription.watchOnResult(() => {
  70. notificationsHandler.refetch()
  71. if (!mutationTriggered) notificationsHandler.refetch()
  72. mutationTriggered = false
  73. })
  74. const haveUnread = computed(() => unseenCount.value > 0)
  75. </script>
  76. <template>
  77. <CommonLoader :loading="!notifications.length && loading">
  78. <div class="ltr:pl-3 ltr:pr-4 rtl:pl-4 rtl:pr-3">
  79. <NotificationItem
  80. v-for="notification of notifications"
  81. :key="notification.id"
  82. :item-id="notification.id"
  83. :type-name="notification.typeName"
  84. :object-name="notification.objectName"
  85. :seen="notification.seen"
  86. :created-at="notification.createdAt"
  87. :created-by="notification.createdBy"
  88. :meta-object="notification.metaObject"
  89. @remove="notificationRemoved"
  90. @seen="seenNotification"
  91. />
  92. <div v-if="!notifications.length" class="px-4 py-3 text-center text-base">
  93. {{ $t('No entries') }}
  94. </div>
  95. <!-- TODO: Add some better solution when mark as seen is running.
  96. Maybe disabled state that it can not be clicked twice or hidding the action completley. -->
  97. <div
  98. v-if="haveUnread"
  99. class="text-blue flex flex-1 cursor-pointer justify-center px-4 py-3 text-base"
  100. :class="{ 'text-red': markingAsSeen }"
  101. role="button"
  102. tabindex="0"
  103. @keydown.enter="markAllRead"
  104. @click="markAllRead"
  105. >
  106. {{ $t('Mark all as read') }}
  107. </div>
  108. </div>
  109. </CommonLoader>
  110. </template>