Source

components/shared/AlertsLayer.vue

<template>
  <div v-show="isLayerVisible" class="alerts_layer" @click="clearMessage()">
    <div
      v-for="item in messages"
      :key="item.id"
      :class="getAlertClassname(item.type)"
      role="alert"
    >
      <strong v-text="$te(item.title) ? $t(item.title) : item.title" />
      <p v-html="getMessageText(item)" />
      <button
        type="button"
        class="close"
        aria-label="Close"
        @click="dismissMessage($event, item.id)"
      >
        <span aria-hidden="true">&times;</span>
      </button>
    </div>
  </div>
</template>
<script>
import api from '../../api'
import { mapGetters } from 'vuex'
import Vue from 'vue'
/**
 * @namespace components
 * @category components
 * @subcategory shared
 * @module AlertsLayer
 **/
export default {
  mixins: [Vue.$mixins.authMixin],
  data() {
    return {
      isLayerVisible: false,
    }
  },
  computed: {
    ...mapGetters({
      messages: 'alert/alerts',
    }),
  },
  watch: {
    messages(messages) {
      if (messages.length > 0) {
        //If login view: message should contains "Login" or "Auth" as part of the title
        if (
          this.$route.name === 'login_screen' &&
          !messages.find(
            (m) =>
              !!['auth', 'login'].find((str) =>
                m.title.toLowerCase().includes(str)
              )
          )
        ) {
          this.clearMessage()
          this.isLayerVisible = false
        } else {
          //For any other route, show messages right away
          this.isLayerVisible = true
        }
      } else {
        this.isLayerVisible = false
      }
    },
  },
  created() {
    api.bus.$on('403', () => {
      if (!this.messages.find((v) => v.title === '403')) {
        this.$store.dispatch('alert/addAlert', {
          type: 'warning',
          title: '403',
          text: 'alerts.NOT_ENOUGH_RIGHTS',
        })
      }
    })
    api.bus.$on('401', () => {
      if (
        !this.messages.find((v) => v.title === '401') &&
        this.$route.name !== 'login_screen'
      ) {
        this.$store.dispatch('alert/addAlert', {
          type: 'warning',
          title: 'session.token_expired_message_title',
          text: 'session.token_expired_message_contents',
        })
        this.logoutFromApplication()

        //A session expired event can left some loader hanging around
        setTimeout(() => {
          this.$loader.hide()
        }, 1000)
      }
    })

    this.dismissInterval = setInterval(() => {
      let lastMessage = this.messages[this.messages.length - 1]

      if (lastMessage && lastMessage.dismissible) {
        this.countDownChanged(lastMessage)
        if (lastMessage.dismissCountDown <= 0) {
          this.clearMessage()
        }
      }
    }, 1000)
    /*
          :dismissible="item.dismissible"
      @dismissed="clearMessage"
      @dismiss-count-down="countDownChanged(item)"
      */
  },
  destroyed() {
    window.clearInterval(this.dismissInterval)
  },
  methods: {
    countDownChanged(item) {
      if (item.dismissCountDown === undefined) {
        item.dismissCountDown = item.dismissSecs || 5
      }
      item.dismissCountDown--
    },
    getMessageText(item) {
      return this.$t(item.text, item.params || {})
    },
    dismissMessage(e, id) {
      e && e.stopPropagation()
      this.$store.dispatch('alert/removeAlert', id)
    },
    getAlertClassname(type) {
      return `alert alert-${type} alert-dismissible fade show`
    },
    /**
     * @todo Clear all messages if multiple
     */
    clearMessage() {
      if (this.messages.length > 0) {
        this.dismissMessage(null, this.messages[this.messages.length - 1].id)
      }
    },
  },
}
</script>
<style lang="scss" scoped>
.alerts_layer {
  position: absolute;
  left: 0px;
  top: 0px;
  width: calc(100vw);
  height: calc(100vh);
  z-index: 9999999999;
  background-color: rgba(255, 255, 255, 0.5);
}
</style>