Ver Fonte

V8-7031

Vincent há 10 meses atrás
pai
commit
1d5cff3fb1

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

@@ -22,8 +22,6 @@
 
 <script setup lang="ts">
 
-import UrlUtils from "~/services/utils/urlUtils";
-
 const props = defineProps({
   show: {
     type: Boolean,

+ 70 - 0
components/Dialog/Trial/StopConfirmation.vue

@@ -0,0 +1,70 @@
+<template>
+  <LazyLayoutDialog :show="show" theme="danger">
+    <template #dialogType>{{ $t('important') }}</template>
+    <template #dialogTitle>Vous souhaitez arrêter votre période d’essai Opentalent Artist Premium ? </template>
+    <template #dialogText>
+      <v-card-text class="text">
+        <p>En choisissant d’arrêter, votre compte reviendra automatiquement à la version précédente, sans perte de vos données essentielles. </p>
+        <p><strong>Que se passe-t-il si vous arrêtez votre période d’essai ?</strong></p>
+        <ul>
+          <li>Les fonctionnalités premium de l’essai ne seront plus accessibles.</li>
+          <li>Vous conserverez toutes les informations et configurations que vous avez ajoutées pendant l’essai.</li>
+          <li>Vous pourrez toujours gérer vos activités grâce aux fonctionnalités de la version de base.</li>
+        </ul>
+        <p>Si vous souhaitez continuer à profiter des avantages complets d’Opentalent Artist, vous pouvez souscrire à une licence à tout moment.</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-danger" @click="contactOpentalent">
+        Arr$eter l'essai
+      </v-btn>
+    </template>
+  </LazyLayoutDialog>
+</template>
+
+<script setup lang="ts">
+
+import UrlUtils from "~/services/utils/urlUtils";
+import {useApiLegacyRequestService} from "~/composables/data/useApiLegacyRequestService";
+
+const props = defineProps({
+  show: {
+    type: Boolean,
+    required: false,
+    default: false,
+  },
+})
+const runtimeConfig = useRuntimeConfig()
+const { apiRequestService } = useApiLegacyRequestService()
+
+const emit = defineEmits(['closeDialog'])
+
+const closeDialog = () => {
+  emit('closeDialog')
+}
+
+const contactOpentalent = async () => {
+  await apiRequestService.post('/trial/stop')
+  const v1BaseURL = runtimeConfig.baseUrlAdminLegacy || runtimeConfig.public.baseUrlAdminLegacy
+  await navigateTo(UrlUtils.join(v1BaseURL, '#', 'dashboard'), {
+    external: true
+  })
+}
+</script>
+
+<style scoped lang="scss">
+  .text{
+    font-size: 13px;
+    p{
+      margin-bottom: 10px;
+    }
+
+    ul{
+      padding-left: 20px;
+      margin-bottom: 10px;
+    }
+  }
+</style>

+ 3 - 6
components/Layout/MainMenu.vue

@@ -89,14 +89,14 @@ 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";
+import {useApiLegacyRequestService} from "~/composables/data/useApiLegacyRequestService";
 
 const runtimeConfig = useRuntimeConfig()
 const i18n = useI18n()
 const organizationProfile = useOrganizationProfileStore()
 const accessProfile = useAccessProfileStore()
 const { getMenu, hasMenu, isInternalLink, setMenuState, isMenuOpened } = useMenu()
-const { apiRequestService } = useAp2iRequestService()
+const { apiRequestService } = useApiLegacyRequestService()
 
 const { mdAndUp, lgAndUp } = useDisplay()
 
@@ -153,10 +153,7 @@ const trialAction = async () => {
     })
   }else if(organizationProfile.principalType === 'ARTISTIC_PRACTICE_ONLY'){
     try{
-      const apiV1BaseURL = runtimeConfig.baseUrlLegacy || runtimeConfig.public.baseUrlLegacy
-      await apiRequestService.get(
-        UrlUtils.join(apiV1BaseURL,  '/api/trial/is_available')
-      )
+      await apiRequestService.get('/trial/is_available')
       await navigateTo(UrlUtils.join(v1BaseURL, '#', 'trial'), {
         external: true
       })

+ 113 - 0
composables/data/useApiLegacyRequestService.ts

@@ -0,0 +1,113 @@
+import type { Ref } from 'vue'
+import type { FetchContext, FetchOptions } from 'ofetch'
+import { TYPE_ALERT } from '~/types/enum/enums'
+import ApiRequestService from '~/services/data/apiRequestService'
+import { usePageStore } from '~/stores/page'
+import UnauthorizedError from '~/services/error/UnauthorizedError'
+import { useAccessProfileStore } from '~/stores/accessProfile'
+import UrlUtils from "~/services/utils/urlUtils";
+
+/**
+ * Retourne une instance de ApiRequestService configurée pour interroger l'api legacy
+ *
+ * @see https://github.com/unjs/ohmyfetch/blob/main/README.md#%EF%B8%8F-create-fetch-with-default-options
+ */
+let apiRequestServiceClass: null | ApiRequestService = null
+export const useApiLegacyRequestService = () => {
+  const runtimeConfig = useRuntimeConfig()
+
+  const baseURL = UrlUtils.join(runtimeConfig.baseUrlLegacy || runtimeConfig.public.baseUrlLegacy, 'api')
+
+  const pending: Ref<boolean> = ref(false)
+
+  /**
+   * Peuple les headers avant l'envoi de la requête
+   *
+   * @param request
+   * @param options
+   */
+  const onRequest = function ({ request, options }: FetchContext) {
+    // @ts-expect-error options is not aware of noXaccessId
+    if (options && options.noXaccessId) {
+      return
+    }
+
+    const accessProfileStore = useAccessProfileStore()
+
+    const headers = new Headers(options.headers)
+
+    headers.set('X-Accessid', String(accessProfileStore.id))
+    headers.set('Authorization', 'BEARER ' + accessProfileStore.bearer)
+    if (accessProfileStore.switchId) {
+      headers.set('X-Switch-Access', String(accessProfileStore.switchId))
+    }
+    options.headers = headers
+
+    pending.value = true
+  }
+
+  const onRequestError = function (_: FetchContext) {
+    pending.value = false
+  }
+
+  /**
+   * Server responded
+   */
+  const onResponse = function (_: FetchContext) {
+    pending.value = false
+  }
+
+  /**
+   * Gère les erreurs retournées par l'api
+   *
+   * @param request
+   * @param response
+   * @param error
+   */
+  const onResponseError = function ({ response, error }: FetchContext) {
+    pending.value = false
+
+    if (response && response.status === 401) {
+      throw new UnauthorizedError('Api - Unauthorized')
+    } else if (response && response.status === 403) {
+      console.error('! Request error: Forbidden')
+      usePageStore().addAlert(TYPE_ALERT.ALERT, ['forbidden'])
+    } else if (
+      response &&
+      (response.status === 400 || response.status >= 404)
+    ) {
+      // @see https://developer.mozilla.org/fr/docs/Web/HTTP/Status
+      let errorMsg
+      if (error) {
+        errorMsg = error.message
+      } else if (response._data && response._data.detail) {
+        errorMsg = response._data.detail
+      } else if (response.statusText) {
+        errorMsg = response.statusText
+      } else {
+        errorMsg = 'An error occured'
+      }
+
+      console.error('! Request error: ' + errorMsg)
+      usePageStore().addAlert(TYPE_ALERT.ALERT, [errorMsg])
+    }
+  }
+
+  const config: FetchOptions = {
+    baseURL,
+    onRequest,
+    onRequestError,
+    onResponse,
+    onResponseError,
+  }
+
+  // Avoid memory leak
+  if (apiRequestServiceClass === null) {
+    // Utilise la fonction `create` d'ohmyfetch pour générer un fetcher dédié à l'interrogation de Ap2i
+    const fetcher = $fetch.create(config)
+
+    apiRequestServiceClass = new ApiRequestService(fetcher)
+  }
+
+  return { apiRequestService: apiRequestServiceClass, pending }
+}

+ 35 - 12
pages/subscription.vue

@@ -118,6 +118,7 @@ Page 'Mon abonnement'
                 </template>
                 <template #card.action>
                   <v-btn
+                    v-if="!organizationProfile.isArtistProduct"
                     class="theme-artist btn"
                     href="https://logiciels.opentalent.fr/opentalent-artist"
                     target="_blank"
@@ -159,7 +160,7 @@ Page 'Mon abonnement'
                           Souscrire à l'offre <i class="fa-solid fa-greater-than small"></i>
                         </v-btn>
                       </v-col>
-                      <v-col cols="12">
+                      <v-col cols="12" v-if="!organizationProfile.isArtistPremiumProduct" >
                         <v-btn
                           class="theme-artist btn"
                           href="https://logiciels.opentalent.fr/opentalent-artist"
@@ -168,6 +169,14 @@ Page 'Mon abonnement'
                           En savoir plus <i class="fa-solid fa-greater-than small"></i>
                         </v-btn>
                       </v-col>
+                      <v-col cols="12" v-if="organizationProfile.isTrialActive && (accessProfileStore.isAdmin || accessProfileStore.isCaMember)">
+                        <v-btn
+                          class="stop_btn"
+                          @click="stopTrial"
+                        >
+                          Arrêter l'essai
+                        </v-btn>
+                      </v-col>
                       <v-col cols="12">
                           <span class="special_conditions">
                           *Convient aux petites écoles sans besoins spécifiques de gestion pédagogique, de facturation, etc.
@@ -194,6 +203,7 @@ Page 'Mon abonnement'
                     <v-row>
                       <v-col cols="12">
                         <v-btn
+                          v-if="!organizationProfile.isSchool"
                           class="theme-school btn"
                           href="https://logiciels.opentalent.fr/opentalent-school"
                           target="_blank"
@@ -271,8 +281,13 @@ Page 'Mon abonnement'
   </LayoutContainer>
 
   <DialogTrialAllReadyDid
-    :show="showDialog"
-    @closeDialog = "showDialog = false"
+    :show="showDialogTrialAllReadyDid"
+    @closeDialog = "showDialogTrialAllReadyDid = false"
+  />
+
+  <DialogTrialStopConfirmation
+    :show="showDialogTrialStopConfirmation"
+    @closeDialog = "showDialogTrialStopConfirmation = false"
   />
 </template>
 
@@ -286,7 +301,7 @@ import {useEntityFetch} from '~/composables/data/useEntityFetch'
 import DolibarrAccount from '~/models/Organization/DolibarrAccount'
 import MobytUserStatus from '~/models/Organization/MobytUserStatus'
 import UrlUtils from "~/services/utils/urlUtils";
-import {useAp2iRequestService} from "~/composables/data/useAp2iRequestService";
+import {useApiLegacyRequestService} from "~/composables/data/useApiLegacyRequestService";
 
 //meta
 definePageMeta({
@@ -299,10 +314,11 @@ const runtimeConfig = useRuntimeConfig()
 const {mdAndUp, md} = useDisplay()
 const {fetch} = useEntityFetch()
 const i18n = useI18n()
-const { apiRequestService } = useAp2iRequestService()
+const { apiRequestService } = useApiLegacyRequestService()
 
 //Init ref
-const showDialog: Ref<boolean> = ref(false)
+const showDialogTrialAllReadyDid: Ref<boolean> = ref(false)
+const showDialogTrialStopConfirmation: Ref<boolean> = ref(false)
 const openedPanels: Ref<Array<string>> = initPanel()
 const organizationProfile = getOrganizationProfile()
 const accessProfileStore = useAccessProfileStore()
@@ -408,17 +424,13 @@ function getMobytInformations(): Record<Ref<MobytUserStatus | null>, Ref<boolean
  */
 async function startTrial(){
   try{
-    const apiV1BaseURL = runtimeConfig.baseUrlLegacy || runtimeConfig.public.baseUrlLegacy
-    await apiRequestService.get(
-      UrlUtils.join(apiV1BaseURL,  '/api/trial/is_available')
-    )
-
+    await apiRequestService.get('/trial/is_available')
     const v1BaseURL = runtimeConfig.baseUrlAdminLegacy || runtimeConfig.public.baseUrlAdminLegacy
     await navigateTo(UrlUtils.join(v1BaseURL, '#', 'trial'), {
       external: true
     })
   }catch(error){
-    showDialog.value = true
+    showDialogTrialAllReadyDid.value = true
   }
 }
 
@@ -431,6 +443,13 @@ async function subscription(){
     external: true
   })
 }
+
+/**
+ * Action lorsque l'on souhaite stopper l'essai
+ */
+function stopTrial(){
+  showDialogTrialStopConfirmation.value = true
+}
 </script>
 
 
@@ -493,4 +512,8 @@ async function subscription(){
     margin-top: 0px;
   }
 }
+
+.stop_btn{
+  color: rgb(var(--v-theme-danger));
+}
 </style>