Vincent 10 mesi fa
parent
commit
5ba92662f6

+ 59 - 0
components/Dialog/Trial/AllReadyDid.vue

@@ -0,0 +1,59 @@
+<template>
+  <LazyLayoutDialog :show="show" theme="warning">
+    <template #dialogType>{{ $t('important') }}</template>
+    <template #dialogTitle>{{ $t('trial_all_ready_did') }}</template>
+    <template #dialogText>
+      <v-card-text class="text">
+        <p>Au cours des 6 derniers mois, vous avez bénéficié d’un essai gratuit de 30 jours du logiciel Opentalent Artist Premium.</p>
+        <p>Pour continuer à explorer toutes les fonctionnalités de notre solution et optimiser la gestion de votre structure, nous vous invitons à souscrire à l’une de nos offres adaptées à vos besoins.</p>
+        <p>Si toutefois vous souhaitez une réactivation exceptionnelle de l’essai, n’hésitez pas à contacter notre équipe Opentalent. 
Nous serons ravis d’évaluer votre demande et de vous accompagner dans vos projets.</p>
+      </v-card-text>
+    </template>
+    <template #dialogBtn>
+      <v-btn class="mr-4 submitBtn theme-neutral-strong" @click="closeDialog">
+        {{ $t('cancel') }}
+      </v-btn>
+      <v-btn class="mr-4 submitBtn theme-warning" @click="contactOpentalent">
+        {{ $t('opentalent_contact') }}
+      </v-btn>
+    </template>
+  </LazyLayoutDialog>
+</template>
+
+<script setup lang="ts">
+
+import UrlUtils from "~/services/utils/urlUtils";
+
+const props = defineProps({
+  show: {
+    type: Boolean,
+    required: false,
+    default: false,
+  },
+})
+const emit = defineEmits(['closeDialog'])
+
+const closeDialog = () => {
+  emit('closeDialog')
+}
+
+const contactOpentalent = async () => {
+  emit('closeDialog')
+
+  await navigateTo('https://logiciels.opentalent.fr/nous-contacter', {
+    open: {
+      target: '_blank',
+    },
+    external: true
+  })
+}
+</script>
+
+<style scoped lang="scss">
+  .text{
+    font-size: 13px;
+    p{
+      margin-bottom: 10px;
+    }
+  }
+</style>

+ 8 - 0
components/Layout/Dialog.vue

@@ -14,6 +14,7 @@
         "
       >
         <h3 class="d-flex">
+          <v-icon icon="fa-solid fa-bullhorn" />
           <slot name="dialogType" />
         </h3>
       </div>
@@ -83,6 +84,13 @@ const _show = computed(() => props.show) as boolean
     writing-mode: vertical-lr;
     transform: rotate(-180deg);
   }
+
+  .v-icon{
+    font-size: 25px;
+    transform: rotate(90deg);
+    padding-right: 20px;
+    padding-bottom: 10px;
+  }
 }
 
 .dialog-container {

+ 100 - 13
components/Layout/MainMenu.vue

@@ -10,6 +10,13 @@ Prend en paramètre une liste de ItemMenu et les met en forme
     :disable-resize-watcher="true"
     class="theme-secondary main-menu"
   >
+    <div
+      v-if="organizationProfile.isArtist && (accessProfile.isCaMember || accessProfile.isAdmin)"
+      class="btn_trial"
+      :class="{['btn_mini'] : isRail}"
+      @click="trialAction()"
+    ><v-icon icon="fa fa-ticket" /> <span v-if="!isRail">{{btnLabel}}</span></div>
+
     <template #prepend>
       <slot name="title"></slot>
     </template>
@@ -65,6 +72,11 @@ Prend en paramètre une liste de ItemMenu et les met en forme
       <slot name="foot"></slot>
     </template>
   </v-navigation-drawer>
+
+  <DialogTrialAllReadyDid
+    :show="showDialog"
+    @closeDialog = "showDialog = false"
+  />
 </template>
 
 <script setup lang="ts">
@@ -72,30 +84,30 @@ import { useMenu } from '~/composables/layout/useMenu'
 import { computed } from '@vue/reactivity'
 import { useDisplay } from 'vuetify'
 import type { MenuGroup, MenuItem } from '~/types/layout'
+import UrlUtils from "~/services/utils/urlUtils";
+import {useAp2iRequestService} from "~/composables/data/useAp2iRequestService";
 
-const { getMenu, hasMenu, isInternalLink, setMenuState, isMenuOpened } =
-  useMenu()
+const runtimeConfig = useRuntimeConfig()
+const i18n = useI18n()
+const organizationProfile = useOrganizationProfileStore()
+const accessProfile = useAccessProfileStore()
+const { getMenu, hasMenu, isInternalLink, setMenuState, isMenuOpened } = useMenu()
+const { apiRequestService } = useAp2iRequestService()
 
 const { mdAndUp, lgAndUp } = useDisplay()
 
+const showDialog: Ref<boolean> = ref(false)
 const menu = getMenu('Main')
 
-const isOpened = computed(() => isMenuOpened('Main'))
-
-let items: Array<MenuGroup | MenuItem>
-if (menu === null) {
-  items = []
-} else if (menu.hasOwnProperty('children')) {
-  items = (menu as MenuGroup).children ?? []
-} else {
-  items = [menu]
-}
-
 // En vue lg+, on affiche toujours le menu
 const displayMenu = computed(() => {
   return menu !== null && hasMenu('Main') && (lgAndUp.value || isOpened.value)
 })
 
+const isOpened = computed(() => isMenuOpened('Main'))
+
+const items: Array<MenuGroup | MenuItem> = getItems(menu)
+
 // En vue md+, fermer le menu le passe simplement en mode rail
 // Sinon, le fermer le masque complètement
 const isRail = computed(() => {
@@ -107,6 +119,10 @@ const isRail = computed(() => {
   )
 })
 
+const btnLabel = computed(() => {
+  return organizationProfile.principalType === 'ARTISTIC_PRACTICE_ONLY' ? i18n.t('try_premium') : i18n.t('discover_offer')
+})
+
 const unwatch = watch(lgAndUp, (newValue, oldValue) => {
   // Par défaut si l'écran est trop petit au chargement de la page, le menu doit rester fermé.
   if (process.client && menu !== null) {
@@ -117,6 +133,46 @@ const unwatch = watch(lgAndUp, (newValue, oldValue) => {
 onUnmounted(() => {
   unwatch()
 })
+
+/**
+ * Lorsque l'on appuie sur le bouton pour démarrer l'essai / découvrir les offres
+ */
+const trialAction = async () => {
+  if(organizationProfile.principalType === 'ARTISTIC_PRACTICE_ONLY'){
+    const apiV1BaseURL = runtimeConfig.baseUrlLegacy || runtimeConfig.public.baseUrlLegacy
+    try{
+      await apiRequestService.get(
+        UrlUtils.join(apiV1BaseURL,  '/api/trial/is_available')
+      )
+
+      const v1BaseURL = runtimeConfig.baseUrlAdminLegacy || runtimeConfig.public.baseUrlAdminLegacy
+      await navigateTo(UrlUtils.join(v1BaseURL, '#', 'trial'), {
+        external: true
+      })
+    }catch(error){
+      showDialog.value = true
+    }
+  }else{
+    await navigateTo('/subscription')
+  }
+}
+
+/**
+ * Récupère les menuItem disponibles
+ * @param menu
+ */
+function getItems(menu: MenuGroup|MenuItem|null) : Array<MenuGroup | MenuItem>{
+  let items: Array<MenuGroup | MenuItem>
+
+  if (menu === null) {
+    items = []
+  } else if (menu.hasOwnProperty('children')) {
+    items = (menu as MenuGroup).children ?? []
+  } else {
+    items = [menu]
+  }
+  return items;
+}
 </script>
 
 <style scoped lang="scss">
@@ -183,4 +239,35 @@ onUnmounted(() => {
 :deep(.menu-item .fa) {
   text-align: center;
 }
+
+.btn_trial{
+  background-color: rgb(var(--v-theme-x-create-btn));
+  border-radius: 5px;
+  border: 1px solid #fff;
+  margin-left: 15px;
+  margin-right: 15px;
+  font-size: 12px;
+  text-align: center;
+  color:#000;
+  margin-top: 5px;
+  padding: 5px;
+  padding-left: 10px;
+  padding-right: 10px;
+  cursor: pointer;
+  .v-icon{
+    font-size: 15px;
+    color:#000;
+    padding-right: 5px;
+  }
+}
+
+.btn_mini{
+  font-size: 17px;
+  margin-left: 7px;
+  margin-right: 7px;
+  padding: 0px;
+  .v-icon{
+    padding-right: 0px;
+  }
+}
 </style>

+ 5 - 0
lang/fr.json

@@ -1,4 +1,9 @@
 {
+  "important": "Important",
+  "trial_all_ready_did": "Vous avez déjà bénéficié d’un essai gratuit !",
+  "opentalent_contact": "Contacter Opentalent",
+  "discover_offer": "Découvrir toutes les offres",
+  "try_premium": "Essayer Opentalent Artist Premium gratuitement pendant 30J",
   "opentalent_options": "Les options Opentalent",
   "opentalent_offer": "Les offres Opentalent",
   "service_detail": "Détails des services",

+ 3 - 0
models/Organization/OrganizationProfile.ts

@@ -41,4 +41,7 @@ export default class OrganizationProfile extends ApiResource {
 
   @Num(null)
   declare parametersId: null
+
+  @Str(null)
+  declare principalType: string
 }

+ 3 - 0
stores/organizationProfile.ts

@@ -23,6 +23,7 @@ export const useOrganizationProfileStore = defineStore(
     const modules: Ref<Array<string>> = ref([])
     const hasChildren: Ref<boolean | null> = ref(false)
     const legalStatus: Ref<string | null> = ref(null)
+    const principalType: Ref<string | null> = ref(null)
     const showAdherentList: Ref<boolean | null> = ref(false)
     const networks: Ref<Array<string>> = ref([])
     const website: Ref<string | null> = ref(null)
@@ -178,6 +179,7 @@ export const useOrganizationProfileStore = defineStore(
       modules.value = Array.from(profile.modules)
       hasChildren.value = profile.hasChildren
       legalStatus.value = profile.legalStatus
+      principalType.value = profile.principalType
       showAdherentList.value = profile.showAdherentList
       networks.value = Array.from(profile.networks)
 
@@ -206,6 +208,7 @@ export const useOrganizationProfileStore = defineStore(
       modules,
       hasChildren,
       legalStatus,
+      principalType,
       showAdherentList,
       networks,
       website,

+ 1 - 0
types/interfaces.d.ts

@@ -129,6 +129,7 @@ interface organizationState extends BaseOrganizationProfile {
   isSchool: boolean
   showAdherentList?: boolean | null
   legalStatus?: string | null
+  principalType?: string | null
   networks: Array<string>
   parents: Array<BaseOrganizationProfile>