MainMenu.vue 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. <!--
  2. Menu principal de l'application
  3. Prend en paramètre une liste de ItemMenu et les met en forme
  4. -->
  5. <template>
  6. <v-navigation-drawer
  7. v-model="displayMenu"
  8. :rail="isRail"
  9. :disable-resize-watcher="true"
  10. class="theme-secondary main-menu"
  11. >
  12. <div
  13. v-if="organizationProfile.isArtist && (accessProfile.isCaMember || accessProfile.isAdmin)"
  14. class="btn_trial"
  15. :class="{['btn_mini'] : isRail}"
  16. @click="trialAction()"
  17. ><v-icon icon="fa fa-ticket" /> <span v-if="!isRail">{{btnLabel}}</span></div>
  18. <template #prepend>
  19. <slot name="title"></slot>
  20. </template>
  21. <v-list open-strategy="single" active-class="active" class="left-menu">
  22. <!-- TODO: que se passe-t-il si le menu ne comprend qu'un seul MenuItem? -->
  23. <div v-for="(item, i) in items" :key="i">
  24. <!-- Cas 1 : l'item n'a pas d'enfants, c'est un lien (ou le menu est en mode réduit) -->
  25. <v-list-item
  26. v-if="!item.children || isRail"
  27. :title="$t(item.label)"
  28. :prepend-icon="item.icon.name"
  29. :href="!isInternalLink(item) ? item.to : undefined"
  30. :to="isInternalLink(item) ? item.to : undefined"
  31. :target="item.target"
  32. exact
  33. height="48px"
  34. class="menu-item"
  35. />
  36. <!-- Cas 2 : l'item a des enfants, c'est un groupe -->
  37. <v-list-group
  38. v-else
  39. expand-icon="fas fa-angle-down"
  40. collapse-icon="fas fa-angle-up"
  41. >
  42. <template #activator="{ props }">
  43. <v-list-item
  44. v-bind="props"
  45. :prepend-icon="item.icon.name"
  46. :title="$t(item.label)"
  47. class="theme-secondary menu-item"
  48. height="48px"
  49. />
  50. </template>
  51. <v-list-item
  52. v-for="child in item.children"
  53. :key="$t(child.label)"
  54. :title="$t(child.label)"
  55. :prepend-icon="child.icon.name"
  56. :href="!isInternalLink(child) ? child.to : undefined"
  57. :to="isInternalLink(child) ? child.to : undefined"
  58. exact
  59. height="38px"
  60. class="theme-secondary-alt"
  61. />
  62. </v-list-group>
  63. </div>
  64. </v-list>
  65. <template #append>
  66. <slot name="foot"></slot>
  67. </template>
  68. </v-navigation-drawer>
  69. <DialogTrialAllReadyDid
  70. :show="showDialog"
  71. @closeDialog = "showDialog = false"
  72. />
  73. </template>
  74. <script setup lang="ts">
  75. import { useMenu } from '~/composables/layout/useMenu'
  76. import { computed } from '@vue/reactivity'
  77. import { useDisplay } from 'vuetify'
  78. import type { MenuGroup, MenuItem } from '~/types/layout'
  79. import UrlUtils from "~/services/utils/urlUtils";
  80. import {useAp2iRequestService} from "~/composables/data/useAp2iRequestService";
  81. const runtimeConfig = useRuntimeConfig()
  82. const i18n = useI18n()
  83. const organizationProfile = useOrganizationProfileStore()
  84. const accessProfile = useAccessProfileStore()
  85. const { getMenu, hasMenu, isInternalLink, setMenuState, isMenuOpened } = useMenu()
  86. const { apiRequestService } = useAp2iRequestService()
  87. const { mdAndUp, lgAndUp } = useDisplay()
  88. const showDialog: Ref<boolean> = ref(false)
  89. const menu = getMenu('Main')
  90. // En vue lg+, on affiche toujours le menu
  91. const displayMenu = computed(() => {
  92. return menu !== null && hasMenu('Main') && (lgAndUp.value || isOpened.value)
  93. })
  94. const isOpened = computed(() => isMenuOpened('Main'))
  95. const items: Array<MenuGroup | MenuItem> = getItems(menu)
  96. // En vue md+, fermer le menu le passe simplement en mode rail
  97. // Sinon, le fermer le masque complètement
  98. const isRail = computed(() => {
  99. return (
  100. menu !== null &&
  101. mdAndUp.value &&
  102. !isOpened.value &&
  103. !items.some((item) => item.expanded)
  104. )
  105. })
  106. const btnLabel = computed(() => {
  107. return organizationProfile.principalType === 'ARTISTIC_PRACTICE_ONLY' ? i18n.t('try_premium') : i18n.t('discover_offer')
  108. })
  109. const unwatch = watch(lgAndUp, (newValue, oldValue) => {
  110. // Par défaut si l'écran est trop petit au chargement de la page, le menu doit rester fermé.
  111. if (process.client && menu !== null) {
  112. setMenuState('Main', lgAndUp.value)
  113. }
  114. })
  115. onUnmounted(() => {
  116. unwatch()
  117. })
  118. /**
  119. * Lorsque l'on appuie sur le bouton pour démarrer l'essai / découvrir les offres
  120. */
  121. const trialAction = async () => {
  122. if(organizationProfile.principalType === 'ARTISTIC_PRACTICE_ONLY'){
  123. try{
  124. const apiV1BaseURL = runtimeConfig.baseUrlLegacy || runtimeConfig.public.baseUrlLegacy
  125. await apiRequestService.get(
  126. UrlUtils.join(apiV1BaseURL, '/api/trial/is_available')
  127. )
  128. const v1BaseURL = runtimeConfig.baseUrlAdminLegacy || runtimeConfig.public.baseUrlAdminLegacy
  129. await navigateTo(UrlUtils.join(v1BaseURL, '#', 'trial'), {
  130. external: true
  131. })
  132. }catch(error){
  133. showDialog.value = true
  134. }
  135. }else{
  136. await navigateTo('/subscription')
  137. }
  138. }
  139. /**
  140. * Récupère les menuItem disponibles
  141. * @param menu
  142. */
  143. function getItems(menu: MenuGroup|MenuItem|null) : Array<MenuGroup | MenuItem>{
  144. let items: Array<MenuGroup | MenuItem>
  145. if (menu === null) {
  146. items = []
  147. } else if (menu.hasOwnProperty('children')) {
  148. items = (menu as MenuGroup).children ?? []
  149. } else {
  150. items = [menu]
  151. }
  152. return items;
  153. }
  154. </script>
  155. <style scoped lang="scss">
  156. .v-list-item {
  157. min-height: 10px !important;
  158. }
  159. :deep(.v-list-item-title),
  160. :deep(.v-icon) {
  161. font-size: 14px;
  162. color: rgb(var(--v-theme-on-secondary));
  163. }
  164. .v-list-item__prepend {
  165. margin: 10px 0;
  166. margin-right: 10px !important;
  167. }
  168. .v-application--is-ltr .v-list-group--no-action > .v-list-group__header {
  169. margin-left: 0;
  170. padding-left: 0;
  171. }
  172. .v-application--is-ltr
  173. .v-list-group--no-action
  174. > .v-list-group__items
  175. > .v-list-item {
  176. padding-left: 30px;
  177. }
  178. .v-list-item__content {
  179. padding: 8px 0;
  180. }
  181. .v-list-group__items .v-list-item {
  182. padding-inline-start: 30px !important;
  183. }
  184. .v-list-group--no-action > .v-list-group__header,
  185. .v-list-item {
  186. border-left: 3px solid rgb(var(--v-theme-secondary));
  187. height: 48px;
  188. }
  189. .v-list-item:hover,
  190. .v-list-item.active,
  191. :deep(.v-list-group__items .v-list-item) {
  192. border-left: 3px solid rgb(var(--v-theme-primary));
  193. background-color: rgb(var(--v-theme-secondary-alt)) !important;
  194. color: rgb(var(--v-theme-on-secondary-alt)) !important;
  195. }
  196. :deep(.v-list-group__items .v-list-item-title) {
  197. color: rgb(var(--v-theme-on-secondary-alt));
  198. }
  199. :deep(.v-list-group__items .v-icon) {
  200. color: rgb(var(--v-theme-on-secondary-alt));
  201. }
  202. :deep(.v-list-item .v-icon) {
  203. margin-right: 10px;
  204. }
  205. :deep(.menu-item .fa) {
  206. text-align: center;
  207. }
  208. .btn_trial{
  209. background-color: rgb(var(--v-theme-x-create-btn));
  210. border-radius: 5px;
  211. border: 1px solid #fff;
  212. margin-left: 15px;
  213. margin-right: 15px;
  214. font-size: 12px;
  215. text-align: center;
  216. color:#000;
  217. margin-top: 5px;
  218. padding: 5px;
  219. padding-left: 10px;
  220. padding-right: 10px;
  221. cursor: pointer;
  222. .v-icon{
  223. font-size: 15px;
  224. color:#000;
  225. padding-right: 5px;
  226. }
  227. }
  228. .btn_mini{
  229. font-size: 17px;
  230. margin-left: 7px;
  231. margin-right: 7px;
  232. padding: 0px;
  233. .v-icon{
  234. padding-right: 0px;
  235. }
  236. }
  237. </style>