|
|
@@ -0,0 +1,262 @@
|
|
|
+<template>
|
|
|
+ <v-menu offset-y v-model="isOpen">
|
|
|
+ <template #activator="{ on: { click }, attrs }">
|
|
|
+ <v-tooltip bottom>
|
|
|
+ <template #activator="{ on: on_tooltips , attrs: attrs_tooltips }">
|
|
|
+ <v-btn
|
|
|
+ icon
|
|
|
+ v-bind="[attrs, attrs_tooltips]"
|
|
|
+ color=""
|
|
|
+ v-on="on_tooltips"
|
|
|
+ @click="click"
|
|
|
+ >
|
|
|
+ <v-badge
|
|
|
+ color="orange"
|
|
|
+ offset-y="10"
|
|
|
+ :value="unreadNotification.length > 0"
|
|
|
+ :content="unreadNotification.length"
|
|
|
+ >
|
|
|
+ <v-icon class="ot_white--text" small>
|
|
|
+ fa-bell
|
|
|
+ </v-icon>
|
|
|
+ </v-badge>
|
|
|
+ </v-btn>
|
|
|
+ </template>
|
|
|
+ <span>{{ $t('notification') }}</span>
|
|
|
+ </v-tooltip>
|
|
|
+ </template>
|
|
|
+ <v-card scrollable max-width="400">
|
|
|
+ <v-card-title class="ot_header_menu text-body-2 font-weight-bold">
|
|
|
+ {{ $t('notification') }}
|
|
|
+ </v-card-title>
|
|
|
+ <v-card-text class="ma-0 pa-0 header-menu">
|
|
|
+ <v-list dense :subheader="true">
|
|
|
+ <template v-for="(notification, index) in notifications">
|
|
|
+ <v-list-item :key="index" :class="`${notification.notificationUsers.length === 0 ? 'unread' : ''}`">
|
|
|
+ <v-list-item-content>
|
|
|
+ <v-list-item-title class="list_item mt-2 mb-2" v-text="getMessage(notification)"/>
|
|
|
+ </v-list-item-content>
|
|
|
+ <v-list-item-icon v-if="notification.link" class="pt-4">
|
|
|
+ <v-icon @click="download(notification.link)">mdi-download</v-icon>
|
|
|
+ </v-list-item-icon>
|
|
|
+ </v-list-item>
|
|
|
+ <v-divider></v-divider>
|
|
|
+ </template>
|
|
|
+ </v-list>
|
|
|
+ <v-card v-intersect="update"></v-card>
|
|
|
+ <v-row
|
|
|
+ v-if="loading"
|
|
|
+ class="fill-height mt-3 mb-3"
|
|
|
+ align="center"
|
|
|
+ justify="center"
|
|
|
+ >
|
|
|
+ <v-progress-circular
|
|
|
+ indeterminate
|
|
|
+ color="grey lighten-1"
|
|
|
+ ></v-progress-circular>
|
|
|
+ </v-row>
|
|
|
+ </v-card-text>
|
|
|
+ <v-card-actions class="ma-0 pa-0">
|
|
|
+ <template>
|
|
|
+ <v-list-item
|
|
|
+ id="all_notifications"
|
|
|
+ :key="$t('all_notification')"
|
|
|
+ :href="notificationUrl"
|
|
|
+ router
|
|
|
+ >
|
|
|
+ <v-list-item-title class="text-body-2 ot_white--text" v-text="$t('all_notification')"/>
|
|
|
+ </v-list-item>
|
|
|
+ </template>
|
|
|
+ </v-card-actions>
|
|
|
+ </v-card>
|
|
|
+ </v-menu>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script lang="ts">
|
|
|
+import {computed, ComputedRef, defineComponent, onUnmounted, Ref, ref, useContext, useFetch, watch} from '@nuxtjs/composition-api'
|
|
|
+import {NOTIFICATION_TYPE, QUERY_TYPE} from "~/types/enums";
|
|
|
+import {Notification} from "~/models/Core/Notification";
|
|
|
+import {repositoryHelper} from "~/services/store/repository";
|
|
|
+import {ApiResponse, HydraMetadata} from "~/types/interfaces";
|
|
|
+import {queryHelper} from "~/services/store/query";
|
|
|
+import {NotificationUsers} from "~/models/Core/NotificationUsers";
|
|
|
+import {$accessProfile} from "~/services/profile/accessProfile";
|
|
|
+
|
|
|
+export default defineComponent({
|
|
|
+ setup: function () {
|
|
|
+ const {$dataProvider, $dataPersister, $config, store, app: { i18n }} = useContext()
|
|
|
+ const profileAccess = store.state.profile.access
|
|
|
+ $accessProfile.setStore(store)
|
|
|
+ const currentAccessId = $accessProfile.getCurrentAccessId()
|
|
|
+
|
|
|
+ const loading: Ref<Boolean> = ref(true)
|
|
|
+ const isOpen: Ref<Boolean> = ref(false)
|
|
|
+ const page: Ref<number> = ref(1)
|
|
|
+ const data: Ref<ApiResponse> = ref({} as ApiResponse)
|
|
|
+
|
|
|
+ /**
|
|
|
+ * On récupère les notifications via l'API qui seront stockées dans le store
|
|
|
+ */
|
|
|
+ const {fetch, fetchState} = useFetch(async () => {
|
|
|
+ data.value = await $dataProvider.invoke({
|
|
|
+ type: QUERY_TYPE.MODEL,
|
|
|
+ model: Notification,
|
|
|
+ listArgs: {
|
|
|
+ itemsPerPage: 10,
|
|
|
+ page: page.value
|
|
|
+ }
|
|
|
+ })
|
|
|
+ loading.value = false
|
|
|
+ })
|
|
|
+
|
|
|
+ /**
|
|
|
+ * On récupère les Notifications via le store
|
|
|
+ */
|
|
|
+ const notifications: ComputedRef = computed(() => {
|
|
|
+ const query = repositoryHelper.getRepository(Notification).with('message').orderBy('id', 'desc')
|
|
|
+ return queryHelper.getCollection(query)
|
|
|
+ })
|
|
|
+
|
|
|
+ /**
|
|
|
+ * on calcul le nombre de notification non lues
|
|
|
+ */
|
|
|
+ const unreadNotification: ComputedRef<Array<Notification>> = computed(() => {
|
|
|
+ return notifications.value.filter((notification: Notification) => {
|
|
|
+ return notification.notificationUsers.length === 0
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Les metadata dépendront de la dernière valeur du GET lancé
|
|
|
+ */
|
|
|
+ const metadata: ComputedRef<HydraMetadata> = computed(() => {
|
|
|
+ return data.value.metadata
|
|
|
+ })
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Lorsque l'utilisateur scroll on regarde la nextPage a charger et on le fait que si le pending du fetch est false
|
|
|
+ * (si on a fini de télécharger les éléments précédents)
|
|
|
+ */
|
|
|
+ const update = async () => {
|
|
|
+ if (!fetchState.pending && metadata.value?.nextPage && metadata.value.nextPage > 0) {
|
|
|
+ loading.value = true
|
|
|
+ page.value = metadata.value.nextPage
|
|
|
+ await fetch()
|
|
|
+ //Si des notifications n'avaient pas été marquées comme lues, on le fait immédiatement.
|
|
|
+ markNotificationsAsRead()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * On construit le message qui va devoir s'afficher pour une notification
|
|
|
+ * @param notification
|
|
|
+ */
|
|
|
+ const getMessage = (notification:Notification) => {
|
|
|
+ switch (notification.type){
|
|
|
+ case NOTIFICATION_TYPE.FILE :
|
|
|
+ return `${i18n.t('your_file')} ${notification.message?.fileName} ${i18n.t('is_ready_to_be_downloaded')}`
|
|
|
+ break;
|
|
|
+
|
|
|
+ case NOTIFICATION_TYPE.MESSAGE:
|
|
|
+ if(notification.message?.action)
|
|
|
+ return `${i18n.t('your_message')} ${notification.message?.fileName} ${i18n.t('is_ready_to_be')} ${notification.message.action}`
|
|
|
+
|
|
|
+ return `${i18n.t('your_message')} ${notification.message?.about ?? ''} ${i18n.t('has_been_sent')} `
|
|
|
+ break;
|
|
|
+
|
|
|
+ case NOTIFICATION_TYPE.SYSTEM :
|
|
|
+ if(notification.message?.about)
|
|
|
+ return `${i18n.t(notification.message.about)}`
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ return i18n.t(notification.name)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Dès l'ouverture du menu, on indique que les notifications non lues, le sont.
|
|
|
+ */
|
|
|
+ const unwatch = watch(isOpen, (newValue, oldValue) => {
|
|
|
+ if(newValue){
|
|
|
+ markNotificationsAsRead()
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ onUnmounted(() => {
|
|
|
+ unwatch()
|
|
|
+ })
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Marque les notification non lues comme lues
|
|
|
+ */
|
|
|
+ const markNotificationsAsRead = () => {
|
|
|
+ unreadNotification.value.map((notification:Notification)=>{
|
|
|
+ notification.notificationUsers = ['read']
|
|
|
+ repositoryHelper.persist(Notification, notification)
|
|
|
+ createNewNotificationUsers(notification)
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Créer une nouvelle notification users coté back.
|
|
|
+ * @param notification
|
|
|
+ */
|
|
|
+ const createNewNotificationUsers = (notification: Notification) =>{
|
|
|
+ const newNotificationUsers = repositoryHelper.persist(NotificationUsers, new NotificationUsers(
|
|
|
+ {
|
|
|
+ access:`/api/accesses/${currentAccessId}`,
|
|
|
+ notification:`/api/notifications/${notification.id}`,
|
|
|
+ isRead: true
|
|
|
+ }
|
|
|
+ )) as NotificationUsers
|
|
|
+
|
|
|
+ $dataPersister.invoke({
|
|
|
+ type: QUERY_TYPE.MODEL,
|
|
|
+ model: NotificationUsers,
|
|
|
+ idTemp: newNotificationUsers.id,
|
|
|
+ showProgress: false
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Download le lien
|
|
|
+ * @param link
|
|
|
+ */
|
|
|
+ const download = (link: string) => {
|
|
|
+ const url_parts: Array<string> = link.split('/api');
|
|
|
+ if(profileAccess.originalAccess)
|
|
|
+ url_parts[0] = `api/${profileAccess.originalAccess.id}/${currentAccessId}`
|
|
|
+ else
|
|
|
+ url_parts[0] = `api/${currentAccessId}`
|
|
|
+
|
|
|
+ window.open(`${$config.baseURL_Legacy}/${url_parts.join('')}`);
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ data,
|
|
|
+ getMessage,
|
|
|
+ notificationUrl: `${$config.baseURL_adminLegacy}/notifications/list/`,
|
|
|
+ loading,
|
|
|
+ notifications,
|
|
|
+ update,
|
|
|
+ unreadNotification,
|
|
|
+ isOpen,
|
|
|
+ download
|
|
|
+ }
|
|
|
+ }
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+ #all_notifications{
|
|
|
+ background: var(--v-ot_green-base, white);
|
|
|
+ color: white;
|
|
|
+ }
|
|
|
+ .list_item{
|
|
|
+ white-space: normal;
|
|
|
+ }
|
|
|
+ .unread{
|
|
|
+ background: #ecf0f5;
|
|
|
+ }
|
|
|
+</style>
|