Bläddra i källkod

restore breadcrumb and rewrite profiles stores to use composition

Olivier Massot 3 år sedan
förälder
incheckning
dcace64ad3

+ 1 - 4
components/Layout/Header.vue

@@ -17,8 +17,6 @@ Contient entre autres le nom de l'organisation, l'accès à l'aide et aux préf
           @click="toggleMainMenu"
       >
       </v-app-bar-nav-icon>
-
-      <!--        :icon="isMenuOpened('Main') ? 'fas fa-angle-left' : 'fas fa-bars'"-->
     </template>
 
     <v-toolbar-title v-text="title" />
@@ -53,7 +51,7 @@ Contient entre autres le nom de l'organisation, l'accès à l'aide et aux préf
 
     <a
         href="https://support.opentalent.fr/"
-        class="text-body pa-3 ml-2 ot-dark-grey text-ot-white text-decoration-none"
+        class="text-body pa-3 ml-2 bg-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 -->
@@ -68,7 +66,6 @@ Contient entre autres le nom de l'organisation, l'accès à l'aide et aux préf
 import {computed, ComputedRef} from "@vue/reactivity";
 import {useMenu} from "~/composables/layout/useMenu";
 import {useAbility} from "@casl/vue";
-import {usePageStore} from "~/store/page";
 import {useOrganizationProfileStore} from "~/store/profile/organization";
 import {useRuntimeConfig} from "#app";
 

+ 0 - 2
components/Layout/Header/Menu.vue

@@ -23,7 +23,6 @@ header principal (configuration, paramètres du compte...)
             activator="parent"
             location="start"
             @update:modelValue="onStateUpdated"
-            style="top: 48px;"
         >
           <v-card>
             <v-card-title class="ot-header-menu text-body-2 font-weight-bold">
@@ -94,7 +93,6 @@ const displayMenu = computed(() => hasMenu(props.name))
 const isOpened = () => isMenuOpened(props.name)
 
 const onStateUpdated = (e: any) => {
-  console.log(props.name, menu.value.label)
   setMenuState(props.name, e)
 }
 

+ 10 - 26
components/Layout/SubHeader/ActivityYear.vue

@@ -18,37 +18,21 @@
 </template>
 
 <script lang="ts">
-import { defineComponent, useContext } from '@nuxtjs/composition-api'
-import { useMyProfile } from '~/composables/data/useMyProfile'
-import { $organizationProfile } from '~/services/profile/organizationProfile'
-import {useForm} from "~/composables/form/useForm";
 
-export default defineComponent({
-  setup () {
-    const { store, $dataPersister } = useContext()
-    const { updateMyProfile, setActivityYear, activityYear } = useMyProfile($dataPersister, store)
-    const { markAsNotDirty } = useForm(store)
+import {useOrganizationProfileStore} from "~/store/profile/organization";
 
-    const organizationProfile = $organizationProfile(store)
+const organizationProfile = useOrganizationProfileStore()
 
-    const yearPlusOne:boolean = !organizationProfile.isManagerProduct()
-    const label:string = organizationProfile.isSchool() ? 'schooling_year' : organizationProfile.isArtist() ? 'season_year' : 'cotisation_year'
+const yearPlusOne: boolean = !organizationProfile.isManagerProduct()
+const label: string = organizationProfile.isSchool() ? 'schooling_year' : organizationProfile.isArtist() ? 'season_year' : 'cotisation_year'
 
-    const updateActivityYear = async (newDate:number) => {
-      markAsNotDirty()
-      setActivityYear(newDate)
-      await updateMyProfile()
-      window.location.reload()
-    }
+const updateActivityYear = async (newDate:number) => {
+  markAsNotDirty()
+  setActivityYear(newDate)
+  await updateMyProfile()
+  window.location.reload()
+}
 
-    return {
-      activityYear,
-      label,
-      yearPlusOne,
-      updateActivityYear
-    }
-  }
-})
 </script>
 
 <style lang="scss">

+ 35 - 36
components/Layout/SubHeader/Breadcrumbs.vue

@@ -4,45 +4,44 @@
   />
 </template>
 
-<script lang="ts">
-import { defineComponent, computed, useContext, useRouter, ComputedRef } from '@nuxtjs/composition-api'
-import { AnyJson } from '~/types/interfaces'
-
-export default defineComponent({
-  setup () {
-    const { route, $config, app: { i18n } } = useContext()
-    const $router = useRouter()
-    const homeUrl: string = $config.baseURL_adminLegacy
-
-    const items: ComputedRef<Array<AnyJson>> = computed(() => {
-      const crumbs:Array<AnyJson> = []
-      crumbs.push({
-        text: i18n.t('welcome'),
-        href: homeUrl
-      })
+<script setup lang="ts">
+import {useRouter, useRuntimeConfig} from "#app";
+import {computed, ComputedRef} from "@vue/reactivity";
+import {AnyJson} from "~/types/data";
+import {useI18n} from "vue-i18n";
+import Url from "~/services/utils/url";
 
-      const fullPath:string = route.value.path
-      const params:Array<string> = fullPath.startsWith('/') ? fullPath.substring(1).split('/') : fullPath.split('/')
-      let path:string = ''
-      params.forEach((param) => {
-        path = `${path}/${param}`
-        const match = $router.match(path)
-        if (match.name !== null) {
-          crumbs.push({
-            text: !parseInt(param, 10) ? i18n.t(param + '_breadcrumbs') : i18n.t('item'),
-            nuxt: true,
-            'exact-path': true,
-            to: path
-          })
-        }
-      })
+const runtimeConfig = useRuntimeConfig()
+const i18n = useI18n()
+const router = useRouter()
+
+const items: ComputedRef<Array<AnyJson>> = computed(() => {
+  const crumbs:Array<AnyJson> = []
+
+  crumbs.push({
+    title: i18n.t('welcome'),
+    href: runtimeConfig.baseUrlAdminLegacy
+  })
+
+  const pathPart: Array<string> = Url.split(router.currentRoute.value.path)
 
-      return crumbs
-    })
+  let path: string = ''
 
-    return {
-      items
+  pathPart.forEach((part) => {
+    path = `${path}/${part}`
+
+    const match = router.resolve(path)
+
+    if (match.name !== null) {
+      crumbs.push({
+        title: !parseInt(part, 10) ? i18n.t(part + '_breadcrumbs') : i18n.t('item'),
+        exact: true,
+        to: path
+      })
     }
-  }
+  })
+
+  console.log(crumbs)
+  return crumbs
 })
 </script>

+ 19 - 20
components/Layout/Subheader.vue

@@ -6,9 +6,8 @@ Contient entre autres le breadcrumb, les commandes de changement d'année et les
 <template>
   <main>
     <v-card
-      class="d-md-flex ot-light_grey text-body-2"
+      class="d-md-flex bg-ot-light-grey text-body-2"
       flat
-      tile
     >
       <LayoutSubHeaderBreadcrumbs class="mr-auto d-sm-none d-md-flex d-none d-sm-flex" />
 
@@ -18,32 +17,32 @@ Contient entre autres le breadcrumb, les commandes de changement d'année et les
         tile
       >
         <LayoutSubHeaderActivityYear v-if="!showDateTimeRange" class="activity-year" />
-        <div v-if="hasMenuOrIsTeacher" class="d-sm-none d-md-flex d-none d-sm-flex">
-          <LayoutSubHeaderDataTiming v-if="!showDateTimeRange" class="data-timing ml-2" />
-          <LayoutSubHeaderDataTimingRange class="data-timing-range ml-n1" @showDateTimeRange="showDateTimeRange=$event" />
-          <LayoutSubHeaderPersonnalizedList class="personalized-list ml-2" />
-        </div>
+
+<!--        <div v-if="hasMenuOrIsTeacher" class="d-sm-none d-md-flex d-none d-sm-flex">-->
+<!--          <LayoutSubHeaderDataTiming v-if="!showDateTimeRange" class="data-timing ml-2" />-->
+<!--          <LayoutSubHeaderDataTimingRange class="data-timing-range ml-n1" @showDateTimeRange="showDateTimeRange=$event" />-->
+<!--          <LayoutSubHeaderPersonnalizedList class="personalized-list ml-2" />-->
+<!--        </div>-->
       </v-card>
     </v-card>
   </main>
 </template>
 
-<script lang="ts">
-import {defineComponent, ref, Ref, useContext} from '@nuxtjs/composition-api'
-import {UseAccess} from "~/composables/utils/useAccess";
+<script setup lang="ts">
+
+    import {useAccessProfileStore} from "~/store/profile/access";
+    import {computed, ComputedRef, ref, Ref} from "@vue/reactivity";
+    import {useMenu} from "~/composables/layout/useMenu";
+
+    const accessProfile = useAccessProfileStore()
+    const { hasMenu } = useMenu()
+
+    const hasMenuOrIsTeacher: ComputedRef<boolean> = computed(
+        () => hasMenu('Main') || (accessProfile.isTeacher ?? false)
+    )
 
-export default defineComponent({
-  setup () {
-    const {store} = useContext()
-    const {hasMenuOrIsTeacher} = UseAccess(store)
     const showDateTimeRange: Ref<boolean> = ref(false)
 
-    return {
-      showDateTimeRange,
-      hasMenuOrIsTeacher
-    }
-  }
-})
 </script>
 
 <style scoped>

+ 2 - 1
layouts/default.vue

@@ -9,7 +9,8 @@
       <LayoutMainMenu />
 
       <v-main class="ot-content-color">
-<!--        <LayoutSubheader />-->
+
+      <LayoutSubheader />
 
 <!--        <LayoutAlertbar class="mt-1"></LayoutAlertbar>-->
 

+ 1 - 1
package.json

@@ -6,7 +6,7 @@
     "node": ">=18.0.0"
   },
   "scripts": {
-    "dev": "nuxt dev",
+    "dev": "rm -rf /tmp/nitro && nuxt dev",
     "dev:local": "yarn dev --dotenv .env.local",
     "dev:preprod": "yarn dev --dotenv .env.preprod",
     "dev:prod": "yarn dev --dotenv .env.prod",

+ 0 - 141
services/profile/accessProfile.ts

@@ -1,141 +0,0 @@
-import {AbilitiesType, accessState} from "~/types/interfaces";
-import {useAccessProfileStore} from "~/store/profile/access";
-import {MongoAbility} from "@casl/ability/dist/types/Ability";
-import {AnyJson} from "~/types/enum/data";
-
-/**
- * L'AccessProfile permet de manipuler l'AccessState l'Access qui peuvent
- * être nécessaires pour l'affichage de chacune des pages de l'application
- * (ex: rôles, habilités, ...etc)
- */
-export class AccessProfile {
-  private accessProfile!: accessState
-
-  private $ability: MongoAbility = {} as MongoAbility
-
-  /**
-   * Set le store
-   */
-  public setPinia () {
-    this.accessProfile = useAccessProfileStore()
-  }
-
-  /**
-   * Permet de setter le service d'abilités
-   * @param ability
-   */
-  public setAbility(ability: MongoAbility){
-    this.$ability = ability
-  }
-
-  /**
-   * Est-ce que l'utilisateur possède le rôle donné?
-   *
-   * @param {Array<string>} roles Rôles à tester
-   * @return {boolean}
-   */
-  hasRole (roles: Array<string>|null): boolean {
-    if (roles === null) {
-      return true
-    }
-
-    let hasRole = false
-    roles.map((r) => {
-      if (this.accessProfile.roles.includes(r)) {
-        hasRole = true
-      }
-    })
-    return hasRole
-  }
-
-  /**
-   * Est-ce que l'utilisateur possède l'abilité
-   * @param {Array<AbilitiesType>} abilities abilités à tester
-   * @return {boolean}
-   */
-  hasAbility(abilities:Array<AbilitiesType>|null): boolean{
-    if(abilities === null)
-      return true;
-
-    let hasAbility= false;
-    abilities.map((ability) => {
-      if (this.$ability.can(ability.action, ability.subject))
-        hasAbility = true;
-    });
-    return hasAbility;
-  }
-
-  /**
-   * Retourne vrai si l'utilisateur connecté possède l'un des profiles passés en paramètre
-   * @param {Array<string>} profiles : profiles à tester
-   * @return {boolean}
-   */
-  hasProfile(profiles: Array<string>|null): boolean{
-    if (null === profiles)
-      return true;
-
-    let hasProfile = false;
-    profiles.map(async (profile) => {
-      if (this.testProfile(profile))
-        hasProfile = true;
-    });
-    return hasProfile;
-  }
-
-  /**
-   * Factory pour tester le profil d'un utilisateur
-   * @param {string} profile : profile à tester
-   * @return {boolean}
-   */
-  testProfile(profile:string): boolean{
-    const factory: {[key: string]: boolean|null} = {
-      'admin': this.accessProfile.isAdmin,
-      'administratifManager': this.accessProfile.isAdministratifManager,
-      'pedagogicManager': this.accessProfile.isPedagogicManager,
-      'financialManager': this.accessProfile.isFinancialManager,
-      'caMember': this.accessProfile.isCaMember,
-      'student': this.accessProfile.isStudent,
-      'teacher': this.accessProfile.isTeacher,
-      'member': this.accessProfile.isMember,
-      'other': this.accessProfile.isOther,
-      'guardian': this.accessProfile.isGuardian,
-      'payor': this.accessProfile.isPayer,
-    }
-
-    if(profile in factory)
-      return factory[profile] ?? false
-    else return false
-  }
-
-  /**
-   * Est-ce que l'utilisateur possède un compte administrateur
-   * @return {boolean}
-   */
-  isAdminAccount(): boolean{
-    return this.accessProfile.isAdminAccess ?? false
-  }
-
-  /**
-   * Retourne l'id de la session en cours
-   * @return {boolean}
-   */
-  getCurrentAccessId(): number{
-    return this.accessProfile.switchId ?? (this.accessProfile.id ?? 0)
-  }
-
-  /**
-   * Factory
-   *
-   * @return {AnyJson} retourne les fonction rendues publiques
-   */
-  handler (): AnyJson {
-    return {
-      hasRole: this.hasRole.bind(this),
-      hasAbility: this.hasAbility.bind(this),
-      hasProfile: this.hasProfile.bind(this),
-      isAdminAccount: this.isAdminAccount.bind(this)
-    }
-  }
-}
-
-export const $accessProfile = new AccessProfile()

+ 0 - 182
services/profile/organizationProfile.ts

@@ -1,182 +0,0 @@
-import { organizationState } from '~/types/interfaces'
-import {useOrganizationProfileStore} from "~/store/profile/organization";
-import {AnyJson} from "~/types/enum/data";
-/**
- * L'OrganizationProfile permet de manipuler l'OrganizationState auquel
- * l'access courant est connecté et qui peuvent  être nécessaires pour l'affichage
- * de chacune des pages de l'application
- * (ex: modules, produit, ...etc)
- */
-class OrganizationProfile {
-  private organizationProfile: organizationState
-
-  /**
-   * @constructor
-   */
-  constructor () {
-    this.organizationProfile = useOrganizationProfileStore()
-  }
-
-  /**
-   * Est-ce que l'organisation possède le module donné
-   *
-   * @param {Array<string>} modules Modules à tester
-   * @return {boolean}
-   */
-  hasModule (modules: Array<string>): boolean {
-    let hasModule = false
-    modules.map((module) => {
-      if (this.organizationProfile.modules && this.organizationProfile.modules.includes(module)) { hasModule = true }
-    })
-    return hasModule
-  }
-
-  /**
-   * L'organization fait-elle partie d'un réseau ?
-   *
-   * @return {boolean}
-   */
-  isInsideNetwork (): boolean {
-    return this.isCmf() || this.isFfec()
-  }
-
-  /**
-   * L'organization fait-elle partie du réseau CMF?
-   *
-   * @return {boolean}
-   */
-  isCmf (): boolean {
-    return this.organizationProfile.networks.filter((network: string) => {
-      return network === process.env.cmf_network
-    }).length > 0
-  }
-
-  /**
-   * L'organization fait-elle partie du réseau FFEC?
-   *
-   * @return {boolean}
-   */
-  isFfec (): boolean {
-    return this.organizationProfile.networks.filter((network: string) => {
-      return network === process.env.ffec_network
-    }).length > 0
-  }
-
-  /**
-   * L'organization possède t'elle un produit premium
-   * @return {boolean}
-   */
-  isArtistProduct (): boolean {
-    return this.organizationProfile.product === process.env.artist_product
-  }
-
-  /**
-   * L'organization possède t'elle un produit artiste premium
-   * @return {boolean}
-   */
-  isArtistPremiumProduct (): boolean {
-    return this.organizationProfile.product === process.env.artist_premium_product
-  }
-
-  /**
-   * L'organization possède-t-elle un produit school?
-   *
-   * @return {boolean}
-   */
-  isSchoolProduct (): boolean {
-    return this.organizationProfile.product === process.env.school_product
-  }
-
-  /**
-   * L'organization possède-t-elle un produit school-premium?
-   *
-   * @return {boolean}
-   */
-  isSchoolPremiumProduct (): boolean {
-    return this.organizationProfile.product === process.env.school_premium_product
-  }
-
-  /**
-   * L'organization possède-t-elle un produit school ou school-premium
-   * @return {boolean}
-   */
-  isSchool (): boolean {
-    return this.isSchoolProduct() || this.isSchoolPremiumProduct()
-  }
-
-  /**
-   * L'organization possède t'elle un produit artiste ou artiste premium
-   * @return {boolean}
-   */
-  isArtist (): boolean {
-    return this.isArtistProduct() || this.isArtistPremiumProduct()
-  }
-
-  /**
-   * L'organization possède t'elle un produit manager
-   * @return {boolean}
-   */
-  isManagerProduct (): boolean {
-    return this.organizationProfile.product === process.env.manager_product
-  }
-
-  /**
-   * L'organization possède t-elle des enfants
-   * @return {boolean|null}
-   */
-  hasChildren (): any {
-    return this.organizationProfile.hasChildren
-  }
-
-  /**
-   * L'organization peut elle afficher la lister des adhérents avec leurs coordonnées
-   * @return {boolean|null}
-   */
-  isShowAdherentList():any{
-    return this.organizationProfile.showAdherentList;
-  }
-
-  /**
-   * L'organization est elle une association ?
-   * @return {boolean|null}
-   */
-  isAssociation():any{
-    return this.organizationProfile.legalStatus === 'ASSOCIATION_LAW_1901';
-  }
-
-  /**
-   * L'organization est-elle la CMF ?
-   *
-   * @return {boolean}
-   */
-  isCMFCentralService(): boolean {
-    if(process.env.CMF_ID)
-      return this.organizationProfile.id == parseInt(process.env.CMF_ID)
-    return false
-  }
-
-  getWebsite(): string | null {
-    return this.organizationProfile.website ?? null
-  }
-
-  /**
-   * Factory
-   *
-   * @return {AnyJson} retourne les fonction rendues publiques
-   */
-  handler (): AnyJson {
-    return {
-      hasModule: this.hasModule.bind(this),
-      isSchool: this.isSchool.bind(this),
-      isArtist: this.isArtist.bind(this),
-      isManagerProduct: this.isManagerProduct.bind(this),
-      isOrganizationWithChildren: this.hasChildren.bind(this),
-      isAssociation: this.isAssociation.bind(this),
-      isShowAdherentList: this.isShowAdherentList.bind(this),
-      isCmf: this.isCmf.bind(this),
-      getWebsite: this.getWebsite.bind(this),
-    }
-  }
-}
-
-export const $organizationProfile = () => new OrganizationProfile()

+ 13 - 0
services/utils/url.ts

@@ -63,6 +63,19 @@ class Url {
 
     return parseInt(id)
   }
+
+  /**
+   * Découpe une URI au niveau des '/'
+   * Utilisé entre autres pour le breadcrumb
+   *
+   * @param uri
+   */
+  public static split(uri: string) {
+    if (uri.startsWith('/')) {
+      uri = uri.substring(1)
+    }
+    return uri.split('/')
+  }
 }
 
 export default Url

+ 272 - 121
store/profile/access.ts

@@ -1,132 +1,283 @@
 import { defineStore } from 'pinia'
 import {$roleUtils} from "~/services/rights/roleUtils";
-import {accessState, baseAccessState, baseOrganizationState, OrignalAccessState} from "~/types/interfaces";
+import {
+  AbilitiesType,
+  baseAccessState,
+  baseOrganizationState,
+  OrignalAccessState
+} from "~/types/interfaces";
 import {useOrganizationProfileStore} from "~/store/profile/organization";
 
 import {MyProfile} from "~/models/Access/MyProfile";
 import {useRepo} from "pinia-orm";
+import {computed, ref, Ref} from "@vue/reactivity";
+import {useEach} from "#imports";
+import {useAbility} from "@casl/vue";
 
-export const useAccessProfileStore = defineStore('accessProfile', {
-  state: (): accessState => {
-    return {
-      bearer: null,
-      id: null,
-      switchId: null,
-      name: null,
-      givenName: null,
-      gender: null,
-      avatarId: null,
-      activityYear: null,
-      historical: [],
-      roles: [],
-      abilities: [],
-      isAdminAccess: false,
-      isSuperAdminAccess: false,
-      isAdmin: false,
-      isAdministratifManager: false,
-      isPedagogicManager: false,
-      isFinancialManager: false,
-      isCaMember: false,
-      isStudent: false,
-      isTeacher: false,
-      isMember: false,
-      isOther: false,
-      isGuardian: false,
-      isPayer: false,
-      multiAccesses: [],
-      familyAccesses: [],
-      originalAccess: null
-    }
-  },
-  actions: {
-    setProfile(profile: any) {
-      const roles: Array<string> = Object.values(profile.roles)
-
-      this.name = profile.name
-      this.givenName = profile.givenName
-      this.gender = profile.gender
-      this.avatarId = profile.avatarId
-      this.activityYear = profile.activityYear
-      this.historical = profile.historical
-      this.isAdminAccess = profile.isAdminAccess
-
-      this.isAdmin = $roleUtils.isA('ADMIN', roles)
-      this.isAdministratifManager = $roleUtils.isA('ADMINISTRATIF_MANAGER', roles)
-      this.isPedagogicManager = $roleUtils.isA('PEDAGOGICS_MANAGER', roles)
-      this.isFinancialManager = $roleUtils.isA('FINANCIAL_MANAGER', roles)
-      this.isCaMember = $roleUtils.isA('CA', roles)
-      this.isStudent = $roleUtils.isA('STUDENT', roles)
-      this.isTeacher = $roleUtils.isA('TEACHER', roles)
-      this.isMember = $roleUtils.isA('MEMBER', roles)
-      this.isOther = $roleUtils.isA('OTHER', roles)
-      this.isGuardian = profile.isGuardian
-      this.isPayer = profile.isPayor
-      this.roles = $roleUtils.filterFunctionRoles(roles)
-
-      // Time to add the original Access (switch User case)
-      this.originalAccess = profile.originalAccess
-
-      // Time to set Multi Accesses
-      this.setMultiAccesses(profile.multiAccesses)
-
-      // Time to set Family Accesses
-      this.setFamilyAccesses(profile.familyAccesses)
-
-      // Time to set Organization Profile
-      const organizationProfileStore = useOrganizationProfileStore()
-      organizationProfileStore.setProfile(profile.organization)
-
-      useRepo(MyProfile).save(profile)
-    },
-    refreshProfile(profile: any) {
-      this.name = profile.name
-      this.givenName = profile.givenName
-      this.gender = profile.gender
-      this.avatarId = profile.avatarId
-      this.activityYear = profile.activityYear
-
-      const organizationProfileStore = useOrganizationProfileStore()
-      organizationProfileStore.refreshProfile(profile.organization)
-    },
-    setMultiAccesses(organizations: any) {
-      useEach(organizations, (organization: baseOrganizationState) => {
-        const o: baseOrganizationState = {
-          id: organization.id,
-          name: organization.name
-        }
-        this.multiAccesses.push(o)
-      })
-    },
-    setFamilyAccesses(accesses: any) {
-      useEach(accesses, (access: baseAccessState) => {
-        const a: baseAccessState = {
-          id: access.id,
-          name: access.name,
-          givenName: access.givenName,
-          gender: access.gender,
-          avatarId: access.avatarId
-        }
-        this.familyAccesses.push(a)
+export const useAccessProfileStore = defineStore('accessProfile', () => {
+
+  // State
+  const bearer = ref(null)
+  const id = ref(null)
+  const switchId = ref(null)
+  const name = ref(null)
+  const givenName = ref(null)
+  const gender = ref(null)
+  const avatarId = ref(null)
+  const activityYear = ref(null)
+  const historical = ref([])
+  const roles: Ref<Array<string>> = ref([])
+  const abilities = ref([])
+  const isAdminAccess = ref(false)
+  const isSuperAdminAccess = ref(false)
+  const isAdmin = ref(false)
+  const isAdministratifManager = ref(false)
+  const isPedagogicManager = ref(false)
+  const isFinancialManager = ref(false)
+  const isCaMember = ref(false)
+  const isStudent = ref(false)
+  const isTeacher = ref(false)
+  const isMember = ref(false)
+  const isOther = ref(false)
+  const isGuardian = ref(false)
+  const isPayer = ref(false)
+  const multiAccesses: Ref<Array<baseOrganizationState>> = ref([])
+  const familyAccesses: Ref<Array<baseAccessState>> = ref([])
+  const originalAccess = ref(null)
+
+  // Getters
+  /**
+   * Est-ce que l'utilisateur possède un compte administrateur
+   * @return {boolean}
+   */
+  const isAdminAccount = computed((): boolean => {
+    return isAdminAccess.value ?? false
+  })
+
+  /**
+   * Retourne l'id de la session en cours
+   * @return {boolean}
+   */
+  const currentAccessId = computed((): number => {
+    return switchId.value ?? (id.value ?? 0)
+  })
+
+
+  // Actions
+  const setMultiAccesses = (organizations: any) => {
+    useEach(organizations, (organization: baseOrganizationState) => {
+      multiAccesses.value.push({
+        id: organization.id,
+        name: organization.name
       })
-    },
-    setOriginalAccess(access: any) {
-      if (access) {
-        const organization: baseOrganizationState = {
-          id: access.organization.id,
-          name: access.organization.name
-        }
-
-        const originalAccess: OrignalAccessState = {
-          id: access.id,
-          name: access.name,
-          givenName: access.givenName,
-          gender: access.gender,
-          isSuperAdminAccess: access.isSuperAdminAccess,
-          avatarId: access.avatarId,
-          organization: organization
-        }
-        this.setOriginalAccess(originalAccess)
+    })
+  }
+
+  const setFamilyAccesses = (accesses: any) => {
+    useEach(accesses, (access: baseAccessState) => {
+      const a: baseAccessState = {
+        id: access.id,
+        name: access.name,
+        givenName: access.givenName,
+        gender: access.gender,
+        avatarId: access.avatarId
       }
-    },
+      familyAccesses.value.push(a)
+    })
+  }
+
+  const setProfile = (profile: any) => {
+    const profileRoles: Array<string> = Object.values(profile.roles)
+
+    name.value = profile.name
+    givenName.value = profile.givenName
+    gender.value = profile.gender
+    avatarId.value = profile.avatarId
+    activityYear.value = profile.activityYear
+    historical.value = profile.historical
+    isAdminAccess.value = profile.isAdminAccess
+
+    isAdmin.value = $roleUtils.isA('ADMIN', profileRoles)
+    isAdministratifManager.value = $roleUtils.isA('ADMINISTRATIF_MANAGER', profileRoles)
+    isPedagogicManager.value = $roleUtils.isA('PEDAGOGICS_MANAGER', profileRoles)
+    isFinancialManager.value = $roleUtils.isA('FINANCIAL_MANAGER', profileRoles)
+    isCaMember.value = $roleUtils.isA('CA', profileRoles)
+    isStudent.value = $roleUtils.isA('STUDENT', profileRoles)
+    isTeacher.value = $roleUtils.isA('TEACHER', profileRoles)
+    isMember.value = $roleUtils.isA('MEMBER', profileRoles)
+    isOther.value = $roleUtils.isA('OTHER', profileRoles)
+    isGuardian.value = profile.isGuardian
+    isPayer.value = profile.isPayor
+    roles.value = $roleUtils.filterFunctionRoles(profileRoles)
+
+    // Time to add the original Access (switch User case)
+    originalAccess.value = profile.originalAccess
+
+    // Time to set Multi Accesses
+    setMultiAccesses(profile.multiAccesses)
+
+    // Time to set Family Accesses
+    setFamilyAccesses(profile.familyAccesses)
+
+    // Time to set Organization Profile
+    const organizationProfileStore = useOrganizationProfileStore()
+    organizationProfileStore.setProfile(profile.organization)
+
+    useRepo(MyProfile).save(profile)
+  }
+
+  const refreshProfile = (profile: any) => {
+    name.value = profile.name
+    givenName.value = profile.givenName
+    gender.value = profile.gender
+    avatarId.value = profile.avatarId
+    activityYear.value = profile.activityYear
+
+    const organizationProfileStore = useOrganizationProfileStore()
+    organizationProfileStore.refreshProfile(profile.organization)
+  }
+
+  const setOriginalAccess = (access: any) => {
+    if (access) {
+      const organization: baseOrganizationState = {
+        id: access.organization.id,
+        name: access.organization.name
+      }
+
+      const originalAccess: OrignalAccessState = {
+        id: access.id,
+        name: access.name,
+        givenName: access.givenName,
+        gender: access.gender,
+        isSuperAdminAccess: access.isSuperAdminAccess,
+        avatarId: access.avatarId,
+        organization: organization
+      }
+      setOriginalAccess(originalAccess)
+    }
+  }
+
+  /**
+   * Teste le profil d'un utilisateur
+   *
+   * @param {string} profile : profile à tester
+   * @return {boolean}
+   */
+  const testProfile = (profile:string): boolean => {
+    const factory: {[key: string]: boolean|null} = {
+      'admin': isAdmin.value,
+      'administratifManager': isAdministratifManager.value,
+      'pedagogicManager': isPedagogicManager.value,
+      'financialManager': isFinancialManager.value,
+      'caMember': isCaMember.value,
+      'student': isStudent.value,
+      'teacher': isTeacher.value,
+      'member': isMember.value,
+      'other': isOther.value,
+      'guardian': isGuardian.value,
+      'payor': isPayer.value,
+    }
+
+    if (!(profile in factory)) {
+      return false
+    }
+    return factory[profile] ?? false
+  }
+
+  /**
+   * Retourne vrai si l'utilisateur connecté possède l'un des profils passés en paramètre
+   *
+   * @param {Array<string>} profiles Profils à tester
+   * @return {boolean}
+   */
+  const hasProfile = (profiles: Array<string>|null): boolean => {
+    if (null === profiles)
+      return true;
+
+    let hasProfile = false;
+    profiles.map(async (profile) => {
+      if (testProfile(profile))
+        hasProfile = true;
+    });
+    return hasProfile;
+  }
+
+  const { can } = useAbility()
+
+  /**
+   * Est-ce que l'utilisateur possède l'habilité
+   *
+   * @param {Array<AbilitiesType>} abilities Habilités à tester
+   * @return {boolean}
+   */
+  const hasAbility = (abilities: Array<AbilitiesType>|null): boolean => {
+    if(abilities === null)
+      return true;
+
+    let hasAbility= false;
+    abilities.map((ability) => {
+      if (can(ability.action, ability.subject))
+        hasAbility = true;
+    });
+    return hasAbility;
+  }
+
+  /**
+   * Est-ce que l'utilisateur possède le ou les rôles donnés ?
+   *
+   * @param {Array<string>} roles Rôles à tester
+   * @return {boolean}
+   */
+  const hasRole = computed((rolesToTest: Array<string>|null): boolean => {
+    if (rolesToTest === null) {
+      return true
+    }
+
+    rolesToTest.map((r) => {
+      if (roles.value.includes(r)) {
+        return true
+      }
+    })
+    return false
+  })
+
+  return {
+    bearer,
+    id,
+    switchId,
+    name,
+    givenName,
+    gender,
+    avatarId,
+    activityYear,
+    historical,
+    roles,
+    abilities,
+    isAdminAccess,
+    isSuperAdminAccess,
+    isAdmin,
+    isAdministratifManager,
+    isPedagogicManager,
+    isFinancialManager,
+    isCaMember,
+    isStudent,
+    isTeacher,
+    isMember,
+    isOther,
+    isGuardian,
+    isPayer,
+    multiAccesses,
+    familyAccesses,
+    originalAccess,
+    isAdminAccount,
+    currentAccessId,
+    setMultiAccesses,
+    setFamilyAccesses,
+    setProfile,
+    refreshProfile,
+    setOriginalAccess,
+    hasProfile,
+    hasAbility,
+    hasRole,
   }
 })

+ 215 - 46
store/profile/organization.ts

@@ -1,51 +1,220 @@
-import { baseOrganizationState, organizationState } from '~/types/interfaces'
+import { baseOrganizationState } from '~/types/interfaces'
 import { defineStore } from "pinia";
+import {computed, Ref} from "@vue/reactivity";
+import {useEach} from "#imports";
 
-export const useOrganizationProfileStore = defineStore('organizationProfile', {
-  state: (): organizationState => {
-        return {
-          id: null,
-          parametersId: null,
-          name: null,
-          product: null,
-          currentActivityYear: null,
-          modules: [],
-          hasChildren: false,
-          legalStatus: null,
-          showAdherentList: false,
-          networks: [],
-          website: null,
-          parents: []
-        }
-  },
-  actions : {
-    setProfile (profile: any) {
-      this.id = profile.id
-      this.parametersId = profile.parametersId
-      this.name = profile.name
-      this.product = profile.product
-      this.currentActivityYear = profile.currentYear
-      this.website = profile.website
-      this.modules = profile.modules
-      this.hasChildren = profile.hasChildren
-      this.legalStatus = profile.legalStatus
-      this.showAdherentList = profile.showAdherentList
-      this.networks = profile.networks
-
-      useEach(profile.parents, (parent) => {
-        const p: baseOrganizationState = {
-          id: parent.id,
-          name: parent.name,
-          website: parent.website
-        }
-        this.parents.push(p)
+export const useOrganizationProfileStore = defineStore('organizationProfile', () => {
+
+  // State
+  const id = ref(null)
+  const parametersId = ref(null)
+  const name = ref(null)
+  const product = ref(null)
+  const currentActivityYear = ref(null)
+  const modules = ref([])
+  const hasChildren = ref(false)
+  const legalStatus = ref(null)
+  const showAdherentList = ref(false)
+  const networks = ref([])
+  const website = ref(null)
+  const parents: Ref<Array<baseOrganizationState>> = ref([])
+
+  // Getters
+  /**
+   * Est-ce que l'organisation possède le module donné
+   *
+   * @param {Array<string>} modules Modules à tester
+   * @return {boolean}
+   */
+  const hasModule = computed((): boolean => {
+    let hasModule = false
+    modules.value.map((module) => {
+      if (modules && modules.value.includes(module)) {
+        hasModule = true
+      }
+    })
+    return hasModule
+  })
+
+  /**
+   * L'organization fait-elle partie du réseau CMF?
+   *
+   * @return {boolean}
+   */
+  const isCmf = computed( (): boolean => {
+    return networks.value.filter((network: string) => {
+      return network === process.env.cmf_network
+    }).length > 0
+  })
+
+  /**
+   * L'organization fait-elle partie du réseau FFEC?
+   *
+   * @return {boolean}
+   */
+  const isFfec = computed( (): boolean => {
+    return networks.value.filter((network: string) => {
+      return network === process.env.ffec_network
+    }).length > 0
+  })
+
+  /**
+   * L'organization fait-elle partie d'un réseau ?
+   *
+   * @return {boolean}
+   */
+  const isInsideNetwork = computed( (): boolean => {
+    return isCmf.value || isFfec.value
+  })
+
+  /**
+   * L'organization possède t'elle un produit premium
+   * @return {boolean}
+   */
+  const isArtistProduct = computed( (): boolean => {
+    return product.value === process.env.artist_product
+  })
+
+  /**
+   * L'organization possède t'elle un produit artiste premium
+   * @return {boolean}
+   */
+  const isArtistPremiumProduct = computed( (): boolean => {
+    return product.value === process.env.artist_premium_product
+  })
+
+  /**
+   * L'organization possède-t-elle un produit artiste ou artiste premium
+   * @return {boolean}
+   */
+  const isArtist = computed( (): boolean => {
+    return isArtistProduct.value || isArtistPremiumProduct.value
+  })
+
+  /**
+   * L'organization possède-t-elle un produit school?
+   *
+   * @return {boolean}
+   */
+  const isSchoolProduct = computed( (): boolean => {
+    return product.value === process.env.school_product
+  })
+
+  /**
+   * L'organization possède-t-elle un produit school-premium?
+   *
+   * @return {boolean}
+   */
+  const isSchoolPremiumProduct = computed( (): boolean => {
+    return product.value === process.env.school_premium_product
+  })
+
+  /**
+   * L'organization possède-t-elle un produit school ou school-premium
+   * @return {boolean}
+   */
+  const isSchool = computed( (): boolean => {
+    return isSchoolProduct.value || isSchoolPremiumProduct.value
+  })
+
+  /**
+   * L'organization possède t'elle un produit manager
+   * @return {boolean}
+   */
+  const isManagerProduct = computed( (): boolean => {
+    return product.value === process.env.manager_product
+  })
+
+  /**
+   * L'organization peut-elle afficher la lister des adhérents avec leurs coordonnées
+   * @return {boolean|null}
+   */
+  const isShowAdherentList = computed(():any => {
+    return showAdherentList.value;
+  })
+
+  /**
+   * L'organization est elle une association ?
+   * @return {boolean|null}
+   */
+  const isAssociation = computed(():any => {
+    return legalStatus.value === 'ASSOCIATION_LAW_1901';
+  })
+
+  /**
+   * L'organization est-elle la CMF ?
+   *
+   * @return {boolean}
+   */
+  const isCMFCentralService = computed((): boolean => {
+    if(process.env.CMF_ID)
+      return id.value === parseInt(process.env.CMF_ID)
+    return false
+  })
+
+  const getWebsite = computed((): string | null => {
+    return website.value ?? null
+  })
+
+
+  // Actions
+  const setProfile = (profile: any) => {
+    id.value = profile.id
+    parametersId.value = profile.parametersId
+    name.value = profile.name
+    product.value = profile.product
+    currentActivityYear.value = profile.currentYear
+    website.value = profile.website
+    modules.value = profile.modules
+    hasChildren.value = profile.hasChildren
+    legalStatus.value = profile.legalStatus
+    showAdherentList.value = profile.showAdherentList
+    networks.value = profile.networks
+
+    useEach(profile.parents, (parent) => {
+      parents.value.push({
+        id: parent.id,
+        name: parent.name,
+        website: parent.website
       })
-    },
-    refreshProfile (profile: any) {
-      this.name = profile.name
-      this.currentActivityYear = profile.currentYear
-      this.website = profile.website
-      this.legalStatus = profile.legalStatus
-    }
+    })
+  }
+
+  const refreshProfile = (profile: any) => {
+    name.value = profile.name
+    currentActivityYear.value = profile.currentYear
+    website.value = profile.website
+    legalStatus.value = profile.legalStatus
+  }
+
+  return {
+    id,
+    parametersId,
+    name,
+    product,
+    currentActivityYear,
+    modules,
+    hasChildren,
+    legalStatus,
+    showAdherentList,
+    networks,
+    website,
+    parents,
+    hasModule,
+    isCmf,
+    isFfec,
+    isInsideNetwork,
+    isArtistProduct,
+    isArtistPremiumProduct,
+    isArtist,
+    isSchoolPremiumProduct,
+    isSchoolProduct,
+    isSchool,
+    isManagerProduct,
+    isShowAdherentList,
+    isAssociation,
+    getWebsite,
+    setProfile,
+    refreshProfile
   }
 })