Browse Source

add alert bars

Olivier Massot 3 years ago
parent
commit
355816adea

+ 33 - 0
components/Layout/AlertBar.vue

@@ -0,0 +1,33 @@
+<!--
+Alert bars
+
+Contient les différentes barres d'alertes qui s'affichent dans certains cas
+-->
+
+<template>
+  <main>
+    <client-only>
+      <LayoutAlertBarEnv />
+    </client-only>
+
+    <LayoutAlertBarSwitchUser />
+
+    <client-only>
+      <LayoutAlertBarCotisation v-if="organizationProfile.isCmf && can('manage', 'cotisation')" />
+    </client-only>
+
+    <LayoutAlertBarSwitchYear />
+    <LayoutAlertBarSuperAdmin />
+  </main>
+</template>
+
+<script setup lang="ts">
+  import {useOrganizationProfileStore} from "~/stores/organizationProfile";
+  import {useAbility} from "@casl/vue";
+
+  const organizationProfile = useOrganizationProfileStore()
+  const { can } = useAbility()
+</script>
+
+<style scoped>
+</style>

+ 149 - 0
components/Layout/AlertBar/Cotisation.vue

@@ -0,0 +1,149 @@
+<!--
+Cotisation bar
+
+Barre d'alerte qui s'affiche pour donner l'état de la cotisation
+-->
+
+<template>
+  <main>
+    <!-- TODO : fonctionnement à valider -->
+    <UiSystemBar v-if="showCotisationAccess" background-color="ot-info" text-color="ot-white">
+      <template #bar.text>
+        <a @click="goOn('AFFILIATION')">
+          <v-icon small>fas fa-info-circle</v-icon>
+          {{$t('cotisation_access')}}
+        </a>
+      </template>
+    </UiSystemBar>
+
+    <UiSystemBar v-else-if="showUploadInvoice" background-color="ot-info" text-color="ot-white">
+      <template #bar.text>
+        <a @click="goOn('INVOICE')">
+          <v-icon small>fas fa-info-circle</v-icon>
+          {{$t('upload_cotisation_invoice')}}
+        </a>
+      </template>
+    </UiSystemBar>
+
+    <UiSystemBar v-else-if="showRenewInsurance" background-color="ot-info" text-color="ot-white">
+      <template #bar.text>
+        <a @click="goOn('INSURANCE')">
+          <v-icon small>fas fa-info-circle</v-icon>
+          {{$t('renew_insurance_cmf')}}
+        </a>
+      </template>
+    </UiSystemBar>
+
+    <UiSystemBar v-else-if="showInsuranceSubscription" background-color="ot-info" text-color="ot-white">
+      <template #bar.text>
+        <a @click="goOn('ADVERTISINGINSURANCE')">
+          <v-icon small>fas fa-info-circle</v-icon>
+          {{$t('insurance_cmf_subscription')}}
+        </a>
+      </template>
+    </UiSystemBar>
+  </main>
+</template>
+
+<script setup lang="ts">
+import {useOrganizationProfileStore} from "~/stores/organizationProfile";
+import {Ref} from "vue";
+import Url from "~/services/utils/url";
+import {ALERT_STATE_COTISATION} from "~/types/enum/enums";
+import {useAsyncData} from "#app";
+import {useEntityFetch} from "~/composables/data/useEntityFetch";
+import {Cotisation} from "~/models/Organization/Cotisation";
+
+const { fetch } = useEntityFetch()
+
+const organizationProfile = useOrganizationProfileStore()
+
+const runtimeConfig = useRuntimeConfig()
+const baseLegacyUrl: string = runtimeConfig.baseUrlAdminLegacy
+
+const cotisationYear: Ref<number | null> = ref(null)
+const showCotisationAccess: Ref<Boolean> = ref(false)
+const showUploadInvoice: Ref<Boolean> = ref(false)
+const showRenewInsurance: Ref<Boolean> = ref(false)
+const showInsuranceSubscription: Ref<Boolean> = ref(false)
+
+/**
+ * On récupère l'état des cotisations via l'API
+ */
+useAsyncData(async () => {
+  if (!organizationProfile.id) {
+    throw new Error('missing organization id')
+  }
+  const { data: cotisation } = await fetch(Cotisation, organizationProfile.id)
+
+  if (cotisation.value !== null) {
+    cotisationYear.value = cotisation.value.cotisationYear
+    handleShow(cotisation.value.alertState)
+  }
+})
+
+/**
+ * Suivant l'état de l'alerte on affiche tel ou tel message
+ * @param alertState
+ */
+const handleShow = (alertState: ALERT_STATE_COTISATION) =>{
+  switch(alertState){
+    case ALERT_STATE_COTISATION.AFFILIATION :
+      showCotisationAccess.value = true
+      break;
+    case ALERT_STATE_COTISATION.INVOICE :
+      showUploadInvoice.value = true
+      break;
+    case ALERT_STATE_COTISATION.INSURANCE :
+      showRenewInsurance.value = true
+      break;
+    case ALERT_STATE_COTISATION.ADVERTISINGINSURANCE :
+      showInsuranceSubscription.value = true
+      break;
+  }
+}
+
+/**
+ * Suivant le bandeau, une action différente est réalisée
+ * @param type
+ */
+const goOn = (type: ALERT_STATE_COTISATION) => {
+  switch(type){
+    case ALERT_STATE_COTISATION.AFFILIATION :
+      if (!organizationProfile.id) {
+        throw new Error('missing organization id')
+      }
+      window.location.href = Url.join(baseLegacyUrl, '/cotisation/cotisation_steps', organizationProfile.id, 'steps/1')
+      break;
+    case ALERT_STATE_COTISATION.INVOICE :
+      if (!cotisationYear.value) {
+        throw new Error('no cotisation year defined')
+      }
+      window.open(
+          Url.join(baseLegacyUrl, 'cotisation/invoice', cotisationYear.value),
+          '_blank'
+      )
+      break;
+    case ALERT_STATE_COTISATION.INSURANCE :
+      window.location.href = Url.join(baseLegacyUrl, 'cotisation/insuranceedit')
+      break;
+    case ALERT_STATE_COTISATION.ADVERTISINGINSURANCE :
+      window.open(
+          'https://www.cmf-musique.org/services/assurances/assurance-de-groupe/',
+          '_blank'
+      )
+      break;
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.v-system-bar {
+  font-size: 14px;
+}
+
+.v-icon {
+  height: 20px;
+  margin: 0 6px;
+}
+</style>

+ 30 - 0
components/Layout/AlertBar/Env.vue

@@ -0,0 +1,30 @@
+<!--
+Env bar
+
+Barre d'alerte qui s'affiche lorsque l'utilisateur n'est pas dans un environnement de production
+-->
+
+<template>
+  <UiSystemBar v-if="show" background-color="ot-warning" text-color="ot-white">
+    <template #bar.text>
+      <v-icon small>fas fa-exclamation-triangle</v-icon>
+      {{ $t('not_production_environment', { env }) }}
+    </template>
+  </UiSystemBar>
+</template>
+
+<script setup lang="ts">
+  const env = process.env.NODE_ENV
+  const show = env !== 'production'
+</script>
+
+<style scoped lang="scss">
+.v-system-bar {
+  font-size: 14px;
+}
+
+.v-icon {
+  height: 20px;
+  margin: 0 6px;
+}
+</style>

+ 59 - 0
components/Layout/AlertBar/SuperAdmin.vue

@@ -0,0 +1,59 @@
+<!--
+Super Admin bar
+
+Barre d'alerte qui s'affiche lorsque l'utilisateur est un super admin en mode switch
+-->
+
+<template>
+  <!-- TODO : fonctionnement à valider -->
+  <UiSystemBar v-if="show" color="ot-danger">
+    <template #bar.text>
+      <v-icon small>
+        fas fa-exclamation-triangle
+      </v-icon>
+
+      <span>{{ $t('super_admin_switch_account') }}</span>
+
+      <a v-if="url" :href="url" class="text-ot-black text-decoration-none">
+        <strong>{{ $t('click_here') }}</strong>
+      </a>
+    </template>
+  </UiSystemBar>
+</template>
+
+<script setup lang="ts">
+  import {useAccessProfileStore} from "~/stores/accessProfile";
+  import Url from "~/services/utils/url";
+  import {ComputedRef} from "@vue/reactivity";
+
+  const runtimeConfig = useRuntimeConfig()
+
+  const baseLegacyUrl: string = runtimeConfig.baseUrlAdminLegacy
+
+  const accessProfile = useAccessProfileStore()
+
+  const show: ComputedRef<boolean> = computed(() =>
+      accessProfile.originalAccess !== null && accessProfile.originalAccess.isSuperAdminAccess
+  )
+
+  const url: ComputedRef<string> = computed(() => {
+    const orgId = accessProfile.originalAccess ? accessProfile.originalAccess.organization.id : null
+    const originalAccessId = accessProfile.originalAccess ? accessProfile.originalAccess.id : null
+
+    if (show && orgId && originalAccessId) {
+      return Url.join(baseLegacyUrl, 'switch_user', orgId, originalAccessId, 'exit')
+    }
+    return ''
+  })
+</script>
+
+<style scoped lang="scss">
+.v-system-bar {
+  font-size: 14px;
+}
+
+.v-icon {
+  height: 20px;
+  margin: 0 6px;
+}
+</style>

+ 39 - 0
components/Layout/AlertBar/SwitchUser.vue

@@ -0,0 +1,39 @@
+<!--
+Switch user
+
+Barre qui s'affiche lorsque l'utilisateur possède un compte multi user
+-->
+
+<template>
+  <!-- TODO : fonctionnement à valider -->
+  <UiSystemBar v-if="show" color="ot-info">
+    <template #bar.text>
+      <v-icon small icon="fas fa-info-circle" />
+      <span v-html="$t('multi_account_alert', { fullname })" />
+      <v-icon class="ml-1" small icon="fa fa-users" />
+      {{$t('multi_account_alert_next')}}
+    </template>
+  </UiSystemBar>
+</template>
+
+<script setup lang="ts">
+  import {useAccessProfileStore} from "~/stores/accessProfile";
+  import {useMenu} from "~/composables/layout/useMenu";
+
+  const accessProfile = useAccessProfileStore()
+  const { hasMenu } = useMenu()
+
+  const show = hasMenu('Family')
+  const fullname = `${accessProfile.givenName} ${accessProfile.name}`
+</script>
+
+<style scoped lang="scss">
+.v-system-bar {
+  font-size: 14px;
+}
+
+.v-icon {
+  height: 20px;
+  margin: 0 6px;
+}
+</style>

+ 63 - 0
components/Layout/AlertBar/SwitchYear.vue

@@ -0,0 +1,63 @@
+<!--
+Switch year bar
+
+Barre d'alerte qui s'affiche lorsque l'utilisateur n'est pas sur l'année courante.
+-->
+
+<template>
+  <!-- TODO : fonctionnement à valider -->
+  <UiSystemBar v-if="show" color="ot-warning">
+    <template #bar.text>
+      {{$t('not_current_year')}}
+
+      <a @click="resetYear">
+        <strong class="text-ot-black">
+          {{$t('not_current_year_reset')}}
+        </strong>
+      </a>
+    </template>
+  </UiSystemBar>
+</template>
+
+<script setup lang="ts">
+  import {useAccessProfileStore} from "~/stores/accessProfile";
+  import {useOrganizationProfileStore} from "~/stores/organizationProfile";
+  import {ComputedRef} from "@vue/reactivity";
+  import {useFormStore} from "~/stores/form";
+
+  const accessProfile = useAccessProfileStore()
+  const organizationProfile = useOrganizationProfileStore()
+  const { setDirty } = useFormStore()
+
+  const show: ComputedRef<boolean> = computed(() => {
+    return (
+        accessProfile.historical.past || accessProfile.historical.future ||
+        (accessProfile.historical.dateStart && accessProfile.historical.dateStart.length > 0) ||
+        (accessProfile.historical.dateEnd && accessProfile.historical.dateEnd.length > 0) ||
+        accessProfile.activityYear !== organizationProfile.currentActivityYear
+    )
+  })
+
+  const resetYear = async () => {
+    accessProfile.setHistorical(false, true, false)
+
+    if (organizationProfile.currentActivityYear) {
+      accessProfile.activityYear = organizationProfile.currentActivityYear
+    }
+
+    setDirty(false)
+
+    window.location.reload()
+  }
+</script>
+
+<style scoped lang="scss">
+.v-system-bar {
+  font-size: 14px;
+}
+
+.v-icon {
+  height: 20px;
+  margin: 0 6px;
+}
+</style>

+ 0 - 1
components/Layout/Dialog.vue

@@ -5,7 +5,6 @@
     persistent
     max-width="800"
     :content-class="contentClass"
-    @update:modelValue="console.log($event); $emit($event)"
   >
     <v-card class="d-flex flex-row">
       <div class="dialog-type flex-column justify-center d-none d-sm-flex">

+ 0 - 3
components/Layout/Header/Notification.vue

@@ -120,14 +120,11 @@ const { fetchCollection } = useEntityFetch()
 
 let { data: collection, pending, refresh } = await fetchCollection(Notification)
 
-
-
 /**
  * On récupère les Notifications via le store
  */
 const notifications: ComputedRef = computed(() => {
   // TODO: revoir pour reprendre le order by et tout
-  console.log(collection.value?.items[0].id)
   return collection.value !== null ? collection.value.items : []
 })
 

+ 1 - 1
layouts/default.vue

@@ -12,7 +12,7 @@
 
         <LayoutSubheader />
 
-<!--        <LayoutAlertbar class="mt-1"></LayoutAlertbar>-->
+        <LayoutAlertBar class="mt-1" />
 
         <!-- Page will be rendered here-->
         <slot />

+ 20 - 0
models/Organization/Cotisation.ts

@@ -0,0 +1,20 @@
+import ApiResource from "~/models/ApiResource";
+import {Num, Str, Uid} from "pinia-orm/dist/decorators";
+
+/**
+ * Ap2i ApiResource : Cotisation
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/ApiResources/Cotisation/Cotisation.php
+ */
+export class Cotisation extends ApiResource {
+    static entity = 'cotisations'
+
+    @Uid()
+    declare id: number | string | null
+
+    @Str(null)
+    declare alertState: string | null
+
+    @Num(null)
+    declare cotisationYear: number | null
+}

+ 4 - 4
services/utils/url.ts

@@ -8,10 +8,10 @@ class Url {
    * @param tails
    * @private
    */
-  public static join (base: string, ...tails: string[]): string {
-    let url = base
-    tails.forEach((tail: string) => {
-      url = url.replace(/^|\/$/g, '') + '/' + tail.replace(/^\/?|$/g, '')
+  public static join (base: string|number, ...tails: Array<string|number>): string {
+    let url = String(base)
+    tails.forEach((tail: string|number) => {
+      url = url.replace(/^|\/$/g, '') + '/' + String(tail).replace(/^\/?|$/g, '')
     })
     return url
   }