Forráskód Böngészése

V8-3858 restore header

Olivier Massot 3 éve
szülő
commit
c51dcb533d

+ 87 - 113
components/Layout/Header.vue

@@ -1,140 +1,114 @@
 <!--
-Header de l'application, contient entre autres le nom de l'organisation, l'accès à l'aide
-et aux préférences de l'utilisateur
+Header de l'application
+Contient entre autres le nom de l'organisation, l'accès à l'aide et aux préférences de l'utilisateur
 -->
 
 <template>
   <v-app-bar
-    clipped-left
-    elevate-on-scroll
-    dense
-    fixed
-    app
-    class="ot-green ot-white--text"
+      order="0"
+      density="compact"
+      class="bg-ot-green text-ot-white"
   >
-    <v-btn
-      v-if="displayedMiniVariant"
-      class="menu-btn d-none d-sm-none d-sm-none d-md-none d-lg-flex" icon @click.stop="displayedMiniMenu()"
-    >
-      <v-icon class="ot-white--text">
-        mdi-menu{{ `${properties.miniVariant ? '' : '-open'}` }}
-      </v-icon>
-    </v-btn>
-
-    <v-btn class="menu-btn d-sm-flex d-md-flex d-lg-none" icon @click.stop="displayedMenu()">
-      <v-icon class="ot-white--text">
-        mdi-menu
-      </v-icon>
-    </v-btn>
+    <template #prepend>
+      <v-app-bar-nav-icon
+          v-if="hasMenu('Main')"
+          :icon="isMenuOpened('Main') ? 'mdi:mdi-menu-open' : 'mdi:mdi-menu'"
+          class="text-ot-white"
+          @click="toggleMenu('Main')"
+      >
+      </v-app-bar-nav-icon>
+
+      <!--        :icon="isMenuOpened('Main') ? 'fas fa-angle-left' : 'fas fa-bars'"-->
+    </template>
 
     <v-toolbar-title v-text="title" />
 
     <v-spacer />
 
-    <LayoutHeaderUniversalCreationCreateButton v-if="showUniversalButton" />
-
-    <v-tooltip bottom>
-      <template #activator="{ on, attrs }">
-        <v-btn
-          icon
-          class="ml-2"
-          v-bind="attrs"
-          v-on="on"
-        >
-          <a class="no-decoration" :href="properties.homeUrl + '/'"><v-icon class="ot-white--text" small>fa-home</v-icon></a>
-        </v-btn>
-      </template>
-      <span>{{ $t('welcome') }}</span>
+<!--    <LayoutHeaderUniversalCreationCreateButton v-if="showUniversalButton" />-->
+
+    <v-tooltip text="$t('welcome')" bottom>
+      <v-btn
+        icon="far fa-home"
+        :href="homeUrl"
+        class="ml-2 text-ot-white"
+      ></v-btn>
     </v-tooltip>
 
-    <LayoutHeaderMenu :menu="webSiteMenu" />
+<!--    <LayoutHeaderMenu :menu="webSiteMenu" />-->
 
-    <LayoutHeaderMenu v-if="hasAccessesMenu" :menu="myAccessesMenu" />
+<!--    <LayoutHeaderMenu v-if="hasAccessesMenu" :menu="myAccessesMenu" />-->
 
-    <LayoutHeaderMenu v-if="hasFamilyMenu" :menu="myFamilyMenu" />
+<!--    <LayoutHeaderMenu v-if="hasFamilyMenu" :menu="myFamilyMenu" />-->
 
-    <LayoutHeaderNotification />
+<!--    <LayoutHeaderNotification />-->
 
-    <LayoutHeaderMenu v-if="hasConfigurationMenu" :menu="configurationMenu" />
+<!--    <LayoutHeaderMenu v-if="hasConfigurationMenu" :menu="configurationMenu" />-->
 
-    <LayoutHeaderMenu :menu="accountMenu"/>
+<!--    <LayoutHeaderMenu :menu="accountMenu"/>-->
 
-    <a class="text-body pa-3 ml-2 ot-dark_grey ot-white--text text-decoration-none" href="https://support.opentalent.fr/" target="_blank">
+    <a
+        href="https://support.opentalent.fr/"
+        class="text-body pa-3 ml-2 ot-dark-grey text-ot-white text-decoration-none"
+        target="_blank"
+    >
+      <!-- TODO: mettre le lien vers le support dans les .env ou dans la conf -->
       <span class="d-none d-sm-none d-md-flex">{{ $t('help_access') }}</span>
-      <v-icon class="d-sm-flex d-md-none" color="white">fas fa-question-circle</v-icon>
+      <v-icon icon="fas fa-question-circle" class="d-sm-flex d-md-none" color="white"></v-icon>
     </a>
   </v-app-bar>
 </template>
 
-<script lang="ts">
-import {
-  defineComponent, reactive, useContext, computed, ComputedRef, Ref, UnwrapRef
-} from '@nuxtjs/composition-api'
-import { $useMenu } from '~/composables/layout/menu'
-import { AnyJson } from '~/types/interfaces'
-
-export default defineComponent({
-  setup (_props, { emit }) {
-    const { store, $config,$ability } = useContext()
-
-    const properties:UnwrapRef<AnyJson> = reactive({
-      miniVariant: false,
-      openMenu: false,
-      homeUrl: $config.baseURL_adminLegacy
-    })
-
-    const displayedMiniVariant:ComputedRef<boolean> = computed(() => store.state.profile.access.hasLateralMenu)
-    const hasConfigurationMenu:ComputedRef<boolean> = computed(() => store.state.profile.access.hasConfigurationMenu)
-    const hasAccessesMenu:ComputedRef<boolean> = computed(() => store.state.profile.access.hasAccessesMenu)
-    const hasFamilyMenu:ComputedRef<boolean> = computed(() => store.state.profile.access.hasFamilyMenu)
-    const title:ComputedRef<string> = computed(() => store.state.profile.organization.name)
-
-    const webSiteMenu:Ref<any> = $useMenu.setupContext().useWebSiteMenuConstruct()
-    const myAccessesMenu:Ref<any> = $useMenu.setupContext().useMyAccessesMenuConstruct()
-    const myFamilyMenu:Ref<any> = $useMenu.setupContext().useMyFamilyMenuConstruct()
-    const configurationMenu:Ref<any> = $useMenu.setupContext().useConfigurationMenuConstruct()
-    const accountMenu:Ref<any> = $useMenu.setupContext().useAccountMenuConstruct()
-
-    const displayedMiniMenu = () => {
-      properties.miniVariant = !properties.miniVariant
-      emit('handle-open-mini-menu-click', properties.miniVariant)
-    }
-
-    const displayedMenu = () => {
-      properties.openMenu = !properties.openMenu
-      emit('handle-open-menu-click', properties.openMenu )
-    }
-
-    const showUniversalButton =
-        $ability.can('manage', 'users')
-      || $ability.can('manage', 'courses')
-      || $ability.can('manage', 'examens')
-      || $ability.can('manage', 'educationalprojects')
-      || $ability.can('manage', 'events')
-      || $ability.can('manage', 'emails')
-      || $ability.can('manage', 'mails')
-      || $ability.can('manage', 'texto')
-      || $ability.can('display', 'message_send_page')
-      || $ability.can('manage', 'equipments') ;
-
-    return {
-      properties,
-      displayedMiniVariant,
-      hasConfigurationMenu,
-      hasAccessesMenu,
-      hasFamilyMenu,
-      title,
-      displayedMiniMenu,
-      displayedMenu,
-      webSiteMenu,
-      myAccessesMenu,
-      myFamilyMenu,
-      configurationMenu,
-      accountMenu,
-      showUniversalButton
-    }
-  }
-})
+<script setup lang="ts">
+
+import {computed, ComputedRef, Ref} from "@vue/reactivity";
+import {useMenuBuilder} from "~/composables/layout/useMenuBuilder";
+import {useAbility} from "@casl/vue";
+import {usePageStore} from "~/store/page";
+import {useOrganizationProfileStore} from "~/store/profile/organization";
+import {useRuntimeConfig} from "#app";
+
+const organizationProfile = useOrganizationProfileStore()
+
+const title: ComputedRef<string> = computed(() => organizationProfile.name ?? 'Opentalent')
+
+const { buildAccountMenu, buildWebsiteListMenu, buildMyFamilyMenu, buildConfigurationMenu, buildMyAccessesMenu, hasMenu } = useMenuBuilder()
+
+const webSiteMenu: Ref<any> = buildWebsiteListMenu()
+const myAccessesMenu: Ref<any> = buildMyAccessesMenu()
+const myFamilyMenu: Ref<any> = buildMyFamilyMenu()
+const configurationMenu: Ref<any> = buildConfigurationMenu()
+const accountMenu: Ref<any> = buildAccountMenu()
+
+const pageState = usePageStore()
+
+const isMenuOpened = (name: string): boolean => {
+  return pageState.menusOpened[name]
+}
+
+const toggleMenu = (name: string) => {
+  console.log('toggle menu ' + name)
+  pageState.menusOpened[name] = !pageState.menusOpened[name]
+}
+
+
+const runtimeConfig = useRuntimeConfig()
+const homeUrl = runtimeConfig.baseUrlAdminLegacy
+
+const { can } = useAbility()
+
+const showUniversalButton =
+    can('manage', 'users')
+  || can('manage', 'courses')
+  || can('manage', 'examens')
+  || can('manage', 'educationalprojects')
+  || can('manage', 'events')
+  || can('manage', 'emails')
+  || can('manage', 'mails')
+  || can('manage', 'texto')
+  || can('display', 'message_send_page')
+  || can('manage', 'equipments') ;
+
 </script>
 
 <style scoped>

+ 9 - 23
components/Layout/MainMenu.vue

@@ -5,9 +5,10 @@ Prend en paramètre une liste de ItemMenu et les met en forme
 
 <template>
   <v-navigation-drawer
-    :mini-variant.sync="miniVariant"
-    v-model="open"
-    class="bg-ot-dark-grey text-ot-menu-color main-menu"
+      :model-value="true"
+      :rail="!opened"
+      :disable-resize-watcher="true"
+      class="bg-ot-dark-grey text-ot-menu-color main-menu"
   >
     <template #prepend>
       <slot name="title"></slot>
@@ -73,10 +74,10 @@ Prend en paramètre une liste de ItemMenu et les met en forme
 </template>
 
 <script setup lang="ts">
-import {onUnmounted, watch, WatchStopHandle} from "@vue/runtime-core";
-import {ref, toRefs} from "@vue/reactivity";
+import {computed} from "@vue/reactivity";
 import {MenuGroup, MenuItem} from "~/types/layout";
 import {MENU_LINK_TYPE} from "~/types/enum/layout";
+import {usePageStore} from "~/store/page";
 
 const props = defineProps({
   menu: {
@@ -86,35 +87,20 @@ const props = defineProps({
   miniVariant: {
     type: Boolean,
     required: true
-  },
-  openMenu: {
-    type: Boolean,
-    required: true
   }
 })
 
-const { openMenu } = toRefs(props)
-const open = ref(true)
-
+const { menusOpened } = usePageStore()
 
 // Par défaut si l'écran est trop petit au chargement de la page, le menu doit être fermé.
 if(process.client)
-  open.value = window.innerWidth >= 1264
+  menusOpened['Main'] = window.innerWidth >= 1264
 
-// TODO : ajouter une petite explication de ce qu'on fait dans ce watch
-const unwatch: WatchStopHandle = watch(openMenu, (newValue, oldValue) => {
-  if (newValue !== oldValue) {
-    open.value = true
-  }
-})
+const opened = computed(() => menusOpened['Main'])
 
 const isInternalLink = (menuItem: MenuItem | MenuGroup) => {
   return 'type' in menuItem && menuItem.type === MENU_LINK_TYPE.INTERNAL
 }
-
-onUnmounted(() => {
-  unwatch()
-})
 </script>
 
 <style scoped lang="scss">

+ 11 - 7
composables/layout/useMenuBuilder.ts

@@ -1,6 +1,6 @@
 import {Ref, ref} from "@vue/reactivity";
 import {useAccessProfileStore} from "~/store/profile/access";
-import {useRouter, useRuntimeConfig} from "#app";
+import {useRuntimeConfig} from "#app";
 import {useAbility} from "@casl/vue";
 import {useOrganizationProfileStore} from "~/store/profile/organization";
 import AbstractMenuBuilder from "~/services/menuBuilder/abstractMenuBuilder";
@@ -11,7 +11,8 @@ import MyAccessesMenuBuilder from "~/services/menuBuilder/myAccessesMenuBuilder"
 import MyFamilyMenuBuilder from "~/services/menuBuilder/myFamilyMenuBuilder";
 import WebsiteListMenuBuilder from "~/services/menuBuilder/websiteListMenuBuilder";
 import ParametersMenuBuilder from "~/services/menuBuilder/parametersMenuBuilder";
-import {useEach} from "#imports";
+import {MenuGroup} from "~/types/layout";
+import {usePageStore} from "~/store/page";
 
 /**
  * Renvoie certaines méthodes pour interagir avec les menus
@@ -45,6 +46,7 @@ export const useMenuBuilder = () => {
   const ability = useAbility()
   const organizationProfile = useOrganizationProfileStore()
   const accessProfile = useAccessProfileStore()
+  const pageState = usePageStore()
 
   /**
    * Construit un menu selon le builder passé en paramètre
@@ -52,21 +54,23 @@ export const useMenuBuilder = () => {
    *
    * @param menuBuilder
    */
-  const buildMenu = (menuBuilder: typeof AbstractMenuBuilder) => {
+  const buildMenu = (menuBuilder: typeof AbstractMenuBuilder): Ref<MenuGroup> => {
     // @ts-ignore
     const builder = new menuBuilder(runtimeConfig, ability, organizationProfile, accessProfile)
     const menu = builder.build()
 
-    // On enregistre l'état du menu dans le store
-    accessProfile.hasMenu[builder.name()] = menu.children.length > 0
+    // On enregistre l'état du menu dans le store de la page
+    if (menu !== null && menu.children.length > 0) {
+      pageState.menusOpened[builder.name()] = false
+      console.log('Menu ' + builder.name() + ' built (' + menu.children.length+ ' entries)')
+    }
 
-    console.log('Menu ' + builder.name() + ' built (' + menu.children.length + ' entries)')
     return ref(menu)
   }
 
   const hasMenu = (name: string): Ref<boolean> => {
     // TODO: revoir pour la réactivité
-    return accessProfile.hasMenu[name] ?? ref(false)
+    return ref(name in pageState.menusOpened)
   }
 
   /**

+ 5 - 17
layouts/default.vue

@@ -3,9 +3,10 @@
     <!-- The client only is used to show the loading picture -->
 <!--    <ClientOnly placeholder-tag="client-only-placeholder" placeholder=" " />-->
     <v-app>
-      <LayoutMainMenu v-if="displayMenu" :menu="menu" :mini-variant="properties.miniVariant" :openMenu="properties.openMenu" />
 
-<!--      <LayoutHeader @handle-open-menu-click="handleOpenMenu" @handle-open-mini-menu-click="handleOpenMiniMenu" />-->
+      <LayoutHeader menuOpened="menuOpened" />
+
+      <LayoutMainMenu v-if="displayMenu" :menu="menu" :opened="menuOpened" />
 
       <v-main class="ot-content-color">
 <!--        <LayoutSubheader />-->
@@ -24,27 +25,14 @@
 
 <script setup lang="ts">
 import {useMenuBuilder} from "~/composables/layout/useMenuBuilder";
-import {computed, reactive} from "@vue/reactivity";
+import {computed, ref} from "@vue/reactivity";
 
 const { buildMainMenu, hasMenu } = useMenuBuilder()
 
 const menu = buildMainMenu()
-
 const displayMenu = computed(() => hasMenu('Main'))
 
-const properties = reactive({
-  clipped: false,
-  miniVariant: false,
-  openMenu: true
-})
-
-const handleOpenMenu = (openMenu: boolean) => {
-  properties.openMenu = openMenu
-}
-
-const handleOpenMiniMenu = (miniVariant: boolean) => {
-  properties.miniVariant = miniVariant
-}
+const menuOpened = ref(true)
 </script>
 
 <style scoped>

+ 3 - 0
pages/poc/blank.vue

@@ -1,2 +1,5 @@
 <template>
 </template>
+
+<script setup lang="ts">
+</script>

+ 3 - 0
plugins/vuetify.ts

@@ -4,7 +4,9 @@ import * as directives from 'vuetify/directives'
 import 'vuetify/styles'
 import {defineNuxtPlugin} from "nuxt/app";
 import { aliases, fa } from 'vuetify/iconsets/fa'
+import { mdi } from 'vuetify/iconsets/mdi'
 import '@fortawesome/fontawesome-free/css/all.css'
+import '@mdi/font/css/materialdesignicons.css'
 
 export default defineNuxtPlugin(nuxtApp => {
     const vuetify = createVuetify({
@@ -43,6 +45,7 @@ export default defineNuxtPlugin(nuxtApp => {
             aliases,
             sets: {
                 fa,
+                mdi
             }
         },
     })

+ 3 - 2
store/page.ts

@@ -1,11 +1,12 @@
 import {Alert, pageState} from '~/types/interfaces'
 import {defineStore} from "pinia";
-import {FORM_FUNCTION, TYPE_ALERT} from "~/types/enum/enums";
+import {TYPE_ALERT} from "~/types/enum/enums";
 
 export const usePageStore = defineStore('page', {
   state: (): pageState => {
     return {
-      alerts: []
+      alerts: [],
+      menusOpened: {}
     }
   },
   actions: {

+ 0 - 1
store/profile/access.ts

@@ -33,7 +33,6 @@ export const useAccessProfileStore = defineStore('accessProfile', {
       isOther: false,
       isGuardian: false,
       isPayer: false,
-      hasMenu: [],
       multiAccesses: [],
       familyAccesses: [],
       originalAccess: null

+ 2 - 2
types/interfaces.d.ts

@@ -60,7 +60,8 @@ interface Alert {
 }
 
 interface pageState {
-  alerts: Array<Alert>
+  alerts: Array<Alert>,
+  menusOpened: Record<string, boolean>
 }
 
 interface ormState {
@@ -114,7 +115,6 @@ interface accessState extends baseAccessState {
   isOther: boolean | null
   isGuardian: boolean | null
   isPayer: boolean | null
-  hasMenu: Record<string, boolean>
   multiAccesses: Array<baseOrganizationState>
   familyAccesses: Array<baseAccessState>
   originalAccess: OrignalAccessState | null