Browse Source

Merge branch 'release/0.1.0'

Vincent GUFFON 4 years ago
parent
commit
02cdc243ab
98 changed files with 3259 additions and 1392 deletions
  1. 18 0
      assets/css/global.scss
  2. 0 1
      assets/css/import.scss
  3. 1 0
      assets/css/variables.scss
  4. 0 25
      components/Actions/EditButtonComponent.vue
  5. 45 0
      components/Form/BottomSheetComponent.vue
  6. 90 30
      components/Form/DataTableComponent.vue
  7. 13 5
      components/Form/ExpansionPanelComponent.vue
  8. 85 58
      components/Form/FormComponent.vue
  9. 61 0
      components/Form/Input/CheckboxComponent.vue
  10. 89 0
      components/Form/Input/DatePickerComponent.vue
  11. 82 0
      components/Form/Input/InputComponent.vue
  12. 89 0
      components/Form/Input/SelectComponent.vue
  13. 61 0
      components/Form/Input/TextComponent.vue
  14. 0 69
      components/Form/InputComponent.vue
  15. 26 0
      components/Layout/ContainerComponent.vue
  16. 61 11
      components/Layout/HeaderComponent.vue
  17. 71 0
      components/Layout/HeaderMenuComponent.vue
  18. 23 20
      components/Layout/MenuComponent.vue
  19. 48 0
      components/Layout/NotificationComponent.vue
  20. 0 50
      components/List/ListComponent.vue
  21. 0 27
      components/Utils/AlertComponent.vue
  22. 1 1
      config/abilities/pages/addressBook.yaml
  23. 0 36
      config/abilities/pages/admin2ios.yaml
  24. 103 0
      config/abilities/pages/parameters.yaml
  25. 2 0
      config/nuxtConfig/env.js
  26. 1 0
      config/nuxtConfig/head.js
  27. 1 0
      config/nuxtConfig/modules.js
  28. 7 0
      config/nuxtConfig/moment.js
  29. 0 1
      config/nuxtConfig/plugins.js
  30. 3 0
      config/nuxtConfig/vuetify.js
  31. 0 24
      data/accessesData.js
  32. 0 26
      data/personActivitiesData.js
  33. 61 0
      lang/enum/fr-FR.js
  34. 67 0
      lang/field/fr-FR.js
  35. 7 2
      lang/fr-FR.js
  36. 16 0
      lang/layout/fr-FR.js
  37. 7 0
      lang/rulesAndErrors/fr-FR.js
  38. 16 8
      layouts/default.vue
  39. 1 0
      layouts/login.vue
  40. 0 12
      models/Access/Access.ts
  41. 40 0
      models/Core/AddressPostal.ts
  42. 27 0
      models/Core/BankAccount.ts
  43. 21 0
      models/Core/ContactPoint.ts
  44. 12 0
      models/Core/Country.ts
  45. 13 0
      models/Model.ts
  46. 99 2
      models/Organization/Organization.ts
  47. 16 0
      models/Organization/OrganizationAddressPostal.ts
  48. 21 0
      models/Organization/OrganizationLicence.ts
  49. 21 0
      models/Organization/OrganizationNetwork.ts
  50. 0 17
      models/Person/Person.ts
  51. 0 14
      models/Person/PersonActivity.ts
  52. 3 1
      nuxt.config.js
  53. 4 3
      package.json
  54. 0 84
      pages/accesses/_id.vue
  55. 0 38
      pages/accesses/list.vue
  56. 3 1
      pages/index.vue
  57. 452 0
      pages/organization/edit.vue
  58. 1 1
      plugins/Queries/http.js
  59. 3 25
      plugins/Queries/rest.ts
  60. 3 27
      plugins/Rights/ability.ts
  61. 0 4
      plugins/grid.js
  62. 60 0
      services/dataProvider/dataProvider.ts
  63. 40 0
      services/dataProvider/enumDataProvider.ts
  64. 44 13
      services/profile/organizationProfile.ts
  65. 29 0
      services/queries/rest.ts
  66. 30 1
      services/rights/abilitiesUtils.ts
  67. 3 0
      services/utils/objectProperties.ts
  68. 17 1
      store/profile/access.ts
  69. 13 1
      store/profile/organization.ts
  70. 5 5
      test/use/layout/menu.spec.js
  71. 1 0
      tsconfig.json
  72. 23 5
      types/types.d.ts
  73. 21 0
      use/form/useFormInputSetup.ts
  74. 26 0
      use/form/utils.ts
  75. 8 8
      use/layout/Menus/accessMenu.ts
  76. 29 0
      use/layout/Menus/accountMenu.ts
  77. 54 0
      use/layout/Menus/admin2iosMenu.ts
  78. 4 4
      use/layout/Menus/agendaMenu.ts
  79. 2 2
      use/layout/Menus/baseMenu.ts
  80. 10 10
      use/layout/Menus/billingMenu.ts
  81. 5 5
      use/layout/Menus/communicationMenu.ts
  82. 73 0
      use/layout/Menus/configurationMenu.ts
  83. 94 0
      use/layout/Menus/cotisationsMenu.ts
  84. 2 2
      use/layout/Menus/donorsMenu.ts
  85. 8 8
      use/layout/Menus/educationalMenu.ts
  86. 2 2
      use/layout/Menus/equipmentMenu.ts
  87. 2 2
      use/layout/Menus/medalsMenu.ts
  88. 29 0
      use/layout/Menus/myAccessesMenu.ts
  89. 29 0
      use/layout/Menus/myFamilyMenu.ts
  90. 5 5
      use/layout/Menus/statsMenu.ts
  91. 19 7
      use/layout/Menus/websiteMenu.ts
  92. 138 0
      use/layout/menu.ts
  93. 34 0
      use/store/useQuery.ts
  94. 45 0
      use/store/useRepository.ts
  95. 0 78
      use/template/Menus/admin2iosMenu.ts
  96. 0 94
      use/template/Menus/cotisationsMenu.ts
  97. 0 87
      use/template/menu.ts
  98. 460 429
      yarn.lock

+ 18 - 0
assets/css/global.scss

@@ -0,0 +1,18 @@
+header .v-toolbar__content{
+  padding-right: 0px;
+}
+
+.e-grid .e-gridheader {
+  position: -webkit-sticky;
+  position: sticky;
+  top: 58px; /* The height of top nav menu. */
+  z-index: 1;
+}
+
+.no-decoration{
+  text-decoration: none;
+}
+
+.margin-bottom-20{
+  margin-bottom: 20px;
+}

+ 0 - 1
assets/css/import.scss

@@ -1 +0,0 @@
-@import "~/node_modules/@syncfusion/ej2-base/styles/material.css";

+ 1 - 0
assets/css/variables.scss

@@ -2,3 +2,4 @@
 //
 // The variables you want to modify
 // $font-size-root: 20px;
+$btn-text-transform: none;

+ 0 - 25
components/Actions/EditButtonComponent.vue

@@ -1,25 +0,0 @@
-<template>
-  <main>
-      <NuxtLink to="">Editer</NuxtLink>
-  </main>
-</template>
-
-<script lang="ts">
-  import {defineComponent} from '@nuxtjs/composition-api'
-
-  /**
-   * @component
-   */
-  export default defineComponent({
-    setup() {
-
-      return {
-
-      }
-    },
-  })
-</script>
-
-<style scoped>
-
-</style>

+ 45 - 0
components/Form/BottomSheetComponent.vue

@@ -0,0 +1,45 @@
+<template>
+  <div class="text-center">
+    <v-bottom-sheet
+      v-model="openSheet"
+      persistent
+    >
+      <v-sheet
+        class="text-center"
+      >
+        <slot></slot>
+
+        <v-btn
+          class="mt-6"
+          text
+          color="error"
+          @click="$emit('close-bottom-sheet', false)"
+        >
+          close
+        </v-btn>
+      </v-sheet>
+    </v-bottom-sheet>
+  </div>
+</template>
+
+
+<script>
+  import {defineComponent} from '@nuxtjs/composition-api'
+
+  export default defineComponent({
+    name: "BottomSheetComponent",
+    props:{
+      openSheet:{
+        type:Boolean,
+        required: true
+      }
+    },
+    setup: function () {
+
+    }
+  })
+</script>
+
+<style scoped>
+
+</style>

+ 90 - 30
components/Form/DataTableComponent.vue

@@ -1,33 +1,69 @@
 <template>
-  <v-col
-    cols="12"
-    sm="12"
-  >
-    <v-data-table
-      :headers="headers"
-      :items="entries"
-      :options.sync="options"
-      :server-items-length="totalEntries"
-      :loading="loading"
-      class="elevation-1"
-    ></v-data-table>
-  </v-col>
+    <v-col
+      cols="12"
+      sm="12"
+    >
+      <BottomSheetComponent :openSheet="openSheet" v-on:close-bottom-sheet="openSheet=$event">
+          <slot name="sheet.content" v-bind="{itemId}"></slot>
+      </BottomSheetComponent>
+
+      <v-data-table
+        :headers="headersWithItem"
+        :items="entries"
+        :server-items-length="totalEntries"
+        :loading="loading"
+        class="elevation-1"
+      >
+
+        <template v-for="header in headersWithItem" v-slot:[header.item]="props">
+          <slot :name="header.item" v-bind="props">
+            {{props.item[header.value]}}
+          </slot>
+        </template>
+
+        <template v-slot:item.actions="{ item }">
+          <v-icon
+            small
+            class="mr-2"
+            @click="editItem(item)"
+          >
+            mdi-pencil
+          </v-icon>
+          <v-icon
+            small
+            @click="deleteItem(item)"
+          >
+            mdi-delete
+          </v-icon>
+        </template>
+
+      </v-data-table>
+    </v-col>
 </template>
 
 <script lang="ts">
-  import {defineComponent, ref, useContext, useFetch} from '@nuxtjs/composition-api'
-  import {Collection, Model, Repository} from "@vuex-orm/core";
-  import personActivitiesData from '@/data/personActivitiesData'
+  import {defineComponent, ref, useContext, useFetch, computed, toRefs, onUnmounted} from '@nuxtjs/composition-api'
+  import {Query} from "@vuex-orm/core";
+  import {$dataProvider} from "~/services/dataProvider/dataProvider";
   import {AnyJson} from "~/types/types";
+  import {useQueryHelper} from "~/use/store/useQuery";
 
   export default defineComponent({
     props: {
-      repository:{
-        type: Object as () => Repository,
+      rootModel:{
+        type: Function,
         required: true
       },
-      uri:{
-        type: String,
+      rootId:{
+        type: Number,
+        required: true
+      },
+      model:{
+        type: Function,
+        required: true
+      },
+      query:{
+        type: Object as () => Query,
         required: true
       },
       headers:{
@@ -35,26 +71,50 @@
         required: true
       }
     },
-    setup({repository, uri}) {
+    setup(props) {
+      const {rootModel, rootId, model, headers, query} = toRefs(props);
+
+      const headersWithItem = computed(()=>{
+        return headers.value.map((header:any)=>{
+          header['item'] = 'item.' + header.value
+          return header
+        })
+      })
+
       const totalEntries = ref(0)
-      const entries = ref([] as Collection<Model>)
+      const entries = ref([] as Array<AnyJson>)
       const loading = ref(true)
-      const options = ref({})
-
-      const {$http} = useContext()
 
+      const {store, $rest} = useContext()
       const {fetch, fetchState} = useFetch(async ()=>{
-        const collection:AnyJson = await $http.$get(`https://local.new.api.opentalent.fr/api/${uri}`)
-        repository.insert(collection['hydra:member']);
-        entries.value = repository.all()
-        totalEntries.value = parseInt(collection['hydra:totalItems'])
+        await $dataProvider(store, $rest).getSubResourceCollection(
+          rootModel.value,
+          rootId.value,
+          model.value
+        )
+        entries.value = useQueryHelper.getFlattenEntries(query.value);
+        totalEntries.value = entries.value.length
         loading.value = false
       })
+
+      const openSheet = ref(false);
+      const itemId = ref(0);
+
+      const editItem = (item: AnyJson) => {
+        itemId.value=item.id;
+        openSheet.value = true;
+      }
+
+      // onUnmounted( useRepositoryHelper.cleanRepository(repository.value) )
+
       return {
         entries,
         totalEntries,
         loading,
-        options
+        headersWithItem,
+        editItem,
+        itemId,
+        openSheet
       }
     }
   })

+ 13 - 5
components/Form/ExpansionPanelComponent.vue

@@ -1,12 +1,11 @@
 <template>
      <v-expansion-panel>
-       <v-expansion-panel-header class="light_grey">
+       <v-expansion-panel-header class="ot_light_grey">
+         <v-icon class="ot_white--text ot_green icon">{{icon}}</v-icon>
          {{title}}
        </v-expansion-panel-header>
        <v-expansion-panel-content>
-         <v-row>
-           <slot></slot>
-         </v-row>
+        <slot></slot>
        </v-expansion-panel-content>
      </v-expansion-panel>
  </template>
@@ -17,6 +16,10 @@
         title:{
           type: String,
           required: true
+        },
+        icon:{
+          type: String,
+          required: false
         }
       },
 
@@ -26,5 +29,10 @@
 </script>
 
 <style scoped>
-
+  .icon{
+    width: 30px;
+    height: 30px;
+    padding: 10px;
+    flex: none;
+  }
 </style>

+ 85 - 58
components/Form/FormComponent.vue

@@ -1,78 +1,105 @@
 <template>
-  <main>
-    <v-form
-      ref="form"
-      v-model="valid"
-      lazy-validation
-    >
-      <v-row>
-        <slot></slot>
-      </v-row>
-
-      <v-btn
-        class="mr-4 submitBtn"
-        @click="submit"
-      >
-        submit
-      </v-btn>
-    </v-form>
-
-   <AlertComponent type="success" v-if="saveOk">Sauvegarde Effectuée</AlertComponent>
-   <AlertComponent type="error" v-if="saveKo">Sauvegarde Echouée</AlertComponent>
-  </main>
+  <v-form
+    ref="form"
+    v-model="properties.valid"
+    lazy-validation
+  >
+    <slot name="form.input" v-bind="{entry}"></slot>
+<!--{{entry}}-->
+    <v-btn v-if="!readOnly" class="mr-4 submitBtn ot_green ot_white--text" @click="submit">
+      Enregistrer
+    </v-btn>
+  </v-form>
 </template>
 
 <script lang="ts">
-  import {defineComponent, ref, toRef} from '@nuxtjs/composition-api'
-  import {Repository} from "@vuex-orm/core";
+  import {defineComponent, reactive, useContext, computed, toRefs} from '@nuxtjs/composition-api'
   import Vue from 'vue'
+  import {useRepositoryHelper} from "~/use/store/useRepository";
+  import {useQueryHelper} from "~/use/store/useQuery";
+  import {Query, Repository} from "@vuex-orm/core";
+  import {Model} from "~/models/Model";
+
   export type VForm = Vue & { validate: () => boolean }
 
   export default defineComponent({
     props: {
-      // repository:{
-      //   type: Object as () => Repository,
-      //   required: true
-      // }
+      repository: {
+        type: Object as () => Repository<Model>,
+        required: true
+      },
+      id:{
+        type: Number,
+        required: true
+      },
+      query:{
+        type: Object as () => Query,
+        required: true
+      },
     },
-    setup(){
-      const valid = true
-      const saveOk = ref(false)
-      const saveKo = ref(false)
+    setup(props) {
+      const {repository, id, query} = toRefs(props)
+      const properties = reactive({
+        valid: false,
+        saveOk: false,
+        saveKo: false
+      })
+
+      const {store} = useContext();
+      const readOnly = computed(() => {
+        useRepositoryHelper.getReadOnly(repository.value)
+      })
+
+      const entry = computed(() => {
+          return useQueryHelper.getFlattenEntry(query.value, id.value)
+      })
+
+      const submit = () => {
+        useRepositoryHelper.setReadOnly(repository.value, true)
+        console.log(useQueryHelper.getJsonEntry(query.value, id.value))
+      }
+
       return {
-        valid,
-        saveOk,
-        saveKo
+        submit,
+        properties,
+        readOnly,
+        entry
       }
     },
-    methods:{
-      async submit(){
-      //   const form:VForm = this.$refs.form;
-      //   if(form.validate()){
-      //     const model = await this.repository.find(parseInt(this.$route.params.id));
-      //     if(model){
-      //       const playload = model.$toJson();
-      //
-      //       this.$http.$put(`https://local.new.api.opentalent.fr/api/${model.$entity}/${this.$route.params.id}`, playload)
-      //         .then(()=>{
-      //           this.saveOk=true
-      //         }, () =>{
-      //           this.saveKo=true
-      //         })
-      //
-      //       setTimeout(()=>{
-      //         this.saveOk=false
-      //         this.saveKo=false
-      //       },2000)
-      //     }
-      //   }
-      }
-    }
+    // methods:{
+    //   async submit(){
+    //
+    //     console.log()
+    //
+    //
+    //     const form:VForm = this.$refs.form;
+    //     if(form.validate()){
+    //       const model = await this.repository.find(parseInt(this.$route.params.id));
+    //       if(model){
+    //         const playload = model.$toJson();
+    //
+    //         this.$http.$put(`https://local.new.api.opentalent.fr/api/${model.$entity}/${this.$route.params.id}`, playload)
+    //           .then(()=>{
+    //             this.saveOk=true
+    //           }, () =>{
+    //             this.saveKo=true
+    //           })
+    //
+    //         setTimeout(()=>{
+    //           this.saveOk=false
+    //           this.saveKo=false
+    //         },2000)
+    //       }
+    //     }
+    //   }
+    // }
   })
 </script>
 
 <style scoped>
-  .submitBtn{
+  .submitBtn {
+    right: 0;
     margin-top: 20px;
+    margin-bottom: 20px;
   }
 </style>

+ 61 - 0
components/Form/Input/CheckboxComponent.vue

@@ -0,0 +1,61 @@
+<template>
+  <v-container
+    class="px-0"
+    fluid
+  >
+    <v-checkbox
+      :value="data"
+      :label="$t(label_field)"
+      @change="update"
+      :disabled="readOnly"
+    ></v-checkbox>
+  </v-container>
+</template>
+
+<script lang="ts">
+  import {computed, defineComponent, toRef} from '@nuxtjs/composition-api'
+  import {useRepositoryHelper} from "~/use/store/useRepository";
+  import {Repository} from "@vuex-orm/core";
+  import {Model} from "~/models/Model";
+
+  export default defineComponent({
+    props: {
+      repository: {
+        type: Object as () => Repository<Model>,
+        required: true
+      },
+      entry:{
+        type: Object,
+        required: true
+      },
+      field: {
+        type: String,
+        required: true
+      },
+      label: {
+        type: String,
+        required: false
+      }
+    },
+    setup(props){
+      const {label, field, repository } = props
+      const entry = toRef(props, 'entry')
+
+      const label_field = label ?? field;
+
+      const data = computed(() => entry.value[field])
+      const update = (newValue:string) => useRepositoryHelper.updateStoreFromField(repository, entry.value, newValue, field)
+      const readOnly = computed(() => useRepositoryHelper.getReadOnly(repository))
+
+      return {
+        label_field,
+        readOnly,
+        data,
+        update
+      }
+    }
+  })
+</script>
+
+<style scoped>
+</style>

+ 89 - 0
components/Form/Input/DatePickerComponent.vue

@@ -0,0 +1,89 @@
+<template>
+  <v-menu
+    v-model="dateOpen"
+    :close-on-content-click="false"
+    :nudge-right="40"
+    transition="scale-transition"
+    offset-y
+    min-width="auto"
+  >
+    <template v-slot:activator="{ on, attrs }">
+      <v-text-field
+        v-model="dateFormatted"
+        :label="$t(label_field)"
+        prepend-icon="mdi-calendar"
+        :disabled="readOnly"
+        v-bind="attrs"
+        v-on="on"
+      ></v-text-field>
+    </template>
+    <v-date-picker
+      v-model="dateParsed"
+      @input="dateOpen = false"
+      locale="fr"
+      color="ot_green lighten-1"
+    ></v-date-picker>
+  </v-menu>
+</template>
+
+
+<script lang="ts">
+  import {defineComponent, watch, ref, useContext, onUnmounted, computed, toRef} from '@nuxtjs/composition-api'
+  import {useRepositoryHelper} from "~/use/store/useRepository";
+  import {Repository} from "@vuex-orm/core";
+  import {Model} from "~/models/Model";
+
+  export default defineComponent({
+    props: {
+      repository: {
+        type: Object as () => Repository<Model>,
+        required: true
+      },
+      entry:{
+        type: Object,
+        required: true
+      },
+      field: {
+        type: String,
+        required: true
+      },
+      label: {
+        type: String,
+        required: false
+      }
+    },
+    setup(props){
+      const {label, field, repository } = props
+      const entry = toRef(props, 'entry')
+
+      const {$moment} = useContext()
+      const label_field = label ?? field;
+
+      const data = computed(() => entry.value[field])
+      const readOnly = computed(() => useRepositoryHelper.getReadOnly(repository))
+
+      const dateFormatted = ref($moment(data.value).format('DD/MM/YYYY'))
+      const dateParsed = ref($moment(data.value).format('YYYY-MM-DD'))
+
+      const unwatch = watch(dateParsed, (newValue) => {
+        dateFormatted.value = $moment(newValue).format('DD/MM/YYYY')
+        useRepositoryHelper.updateStoreFromField(repository, entry.value, newValue, field)
+      })
+
+      onUnmounted(()=>{
+        unwatch()
+      })
+
+      return {
+        label_field,
+        readOnly,
+        dateParsed,
+        dateFormatted,
+        dateOpen: false
+      }
+    }
+  })
+</script>
+
+<style scoped>
+</style>

+ 82 - 0
components/Form/Input/InputComponent.vue

@@ -0,0 +1,82 @@
+<template>
+    <v-text-field
+      :value="data"
+      :label="$t(label_field)"
+      @change="update"
+      :rules="rules"
+      :disabled="readOnly"
+      :type="type"
+      :error="error"
+      :error-messages="errorMessage"
+    >
+    </v-text-field>
+</template>
+
+<script lang="ts">
+  import {computed, defineComponent, toRef, ref} from '@nuxtjs/composition-api'
+  import {useRepositoryHelper} from "~/use/store/useRepository";
+  import {Repository} from "@vuex-orm/core";
+  import {Model} from "~/models/Model";
+
+  export default defineComponent({
+    props: {
+      repository:{
+        type: Object as () => Repository<Model>,
+        required: true
+      },
+      entry:{
+        type: Object,
+        required: true
+      },
+      field:{
+        type: String,
+        required: true
+      },
+      label:{
+        type: String,
+        required: false
+      },
+      type:{
+        type: String,
+        required: false
+      },
+      rules:{
+        type: Array,
+        required: false
+      },
+      error:{
+        type: Boolean,
+        required: false
+      },
+      errorMessage:{
+        type: String,
+        required: false
+      }
+    },
+    setup(props, {emit}){
+      const {label, field, repository } = props
+      const entry = toRef(props, 'entry')
+      const label_field = label ? label : field;
+
+      const data = computed(() => entry.value[field])
+      const update = (newValue:string) => {
+        useRepositoryHelper.updateStoreFromField(repository, entry.value, newValue, field)
+        emit('update', newValue)
+      }
+      const readOnly = computed(() => useRepositoryHelper.getReadOnly(repository))
+
+      return {
+        label_field,
+        data,
+        update,
+        readOnly
+      }
+    }
+  })
+</script>
+
+<style>
+  input:read-only{
+    color: #666 !important;
+  }
+</style>

+ 89 - 0
components/Form/Input/SelectComponent.vue

@@ -0,0 +1,89 @@
+<template>
+  <div>
+    <v-skeleton-loader
+      v-if="loading"
+      type="list-item"
+      loading
+    ></v-skeleton-loader>
+
+    <v-select
+      v-if="!loading"
+      :label="$t(label_field)"
+      :value="data"
+      :items="items"
+      item-text="label"
+      item-value="value"
+      @change="update"
+      :rules="rules"
+      :disabled="readOnly"
+    ></v-select>
+  </div>
+</template>
+
+<script lang="ts">
+  import {computed, defineComponent, ref, toRef, useContext, useFetch} from '@nuxtjs/composition-api'
+  import {$enumDataProvider} from "~/services/dataProvider/enumDataProvider";
+  import {AnyJson} from "~/types/types";
+  import {useRepositoryHelper} from "~/use/store/useRepository";
+  import {Repository} from "@vuex-orm/core";
+  import {Model} from "~/models/Model";
+
+  export default defineComponent({
+    props: {
+      repository: {
+        type: Object as () => Repository<Model>,
+        required: true
+      },
+      entry:{
+        type: Object,
+        required: true
+      },
+      field: {
+        type: String,
+        required: true
+      },
+      label: {
+        type: String,
+        required: false
+      },
+      enumType: {
+        type: String,
+        required: true
+      },
+      rules: {
+        type: Array,
+        required: false
+      }
+    },
+    setup(props){
+      const {label, field, repository, enumType } = props
+      const entry = toRef(props, 'entry')
+
+      const {$rest, app: {i18n}} = useContext()
+      const label_field = label ?? field;
+
+      const data = computed(() => entry.value[field])
+      const update = (newValue:string) => useRepositoryHelper.updateStoreFromField(repository, entry.value, newValue, field)
+      const readOnly = computed(() => useRepositoryHelper.getReadOnly(repository))
+
+      const loading = ref(true)
+      const items: AnyJson = ref([])
+      const {fetch, fetchState} = useFetch(async () => {
+        items.value = await $enumDataProvider($rest, i18n).get(enumType)
+        loading.value = false
+      })
+
+      return {
+        data,
+        update,
+        items,
+        loading,
+        label_field,
+        readOnly
+      }
+    }
+  })
+</script>
+
+<style scoped>
+</style>

+ 61 - 0
components/Form/Input/TextComponent.vue

@@ -0,0 +1,61 @@
+<template>
+  <v-textarea
+    :value="data"
+    :label="$t(label_field)"
+    @change="update"
+    :rules="rules"
+    :disabled="readOnly"
+  ></v-textarea>
+</template>
+
+<script lang="ts">
+  import {computed, defineComponent, toRef} from '@nuxtjs/composition-api'
+  import {useRepositoryHelper} from "~/use/store/useRepository";
+  import {Repository} from "@vuex-orm/core";
+  import {Model} from "~/models/Model";
+
+  export default defineComponent({
+    props: {
+      repository: {
+        type: Object as () => Repository<Model>,
+        required: true
+      },
+      entry:{
+        type: Object,
+        required: true
+      },
+      field: {
+        type: String,
+        required: true
+      },
+      label: {
+        type: String,
+        required: false
+      },
+      rules: {
+        type: Array,
+        required: false
+      }
+    },
+    setup(props){
+      const {label, field, repository } = props
+      const entry = toRef(props, 'entry')
+
+      const label_field = label ?? field;
+
+      const data = computed(() => entry.value[field])
+      const update = (newValue:string) => useRepositoryHelper.updateStoreFromField(repository, entry.value, newValue, field)
+      const readOnly = computed(() => useRepositoryHelper.getReadOnly(repository))
+
+      return {
+        label_field,
+        data,
+        readOnly,
+        update
+      }
+    }
+  })
+</script>
+
+<style scoped>
+</style>

+ 0 - 69
components/Form/InputComponent.vue

@@ -1,69 +0,0 @@
-<template>
-  <v-col
-    cols="12"
-    sm="6"
-  >
-    <v-text-field
-      v-model="data[field]"
-      @change="update()"
-      color="purple darken-2"
-      :rules="rules"
-      required
-    ></v-text-field>
-  </v-col>
-</template>
-
-<script lang="ts">
-  import {unref, defineComponent, ref, useFetch, watch, onUnmounted, useContext} from '@nuxtjs/composition-api'
-  import {Query} from "@vuex-orm/core";
-  import {$objectProperties} from "~/services/utils/objectProperties";
-  import {AnyJson} from "~/types/types";
-
-  export default defineComponent({
-    props: {
-      query:{
-        type: Object as () => Query,
-        required: true
-      },
-      field:{
-        type: String,
-        required: true
-      },
-      rules:{
-        type: Array,
-        required: false
-      }
-    },
-    setup({query, field}){
-      const data = ref({})
-      const {route} = useContext();
-
-      const { fetch, fetchState } = useFetch(async () => {
-        const entry = await query.find(parseInt(route.value.params.id));
-        data.value = $objectProperties.cloneAndFlatten(entry as AnyJson);
-      })
-
-      const update = () => {
-        query.update($objectProperties.cloneAndNest(unref(data)))
-      }
-
-      /* const unwatch = watch(
-        () => root.$store.state.entities.people.data,
-        (state, prevState) => {
-         unref(data)[field] = state
-        }
-      )
-      onUnmounted(() => {
-        unwatch()
-      }) */
-
-      return {
-        data,
-        update
-      }
-    }
-  })
-</script>
-
-<style scoped>
-</style>

+ 26 - 0
components/Layout/ContainerComponent.vue

@@ -0,0 +1,26 @@
+<template>
+  <v-container fluid class="container">
+    <v-row justify="center" align="center">
+      <v-col cols="12" sm="12" md="12">
+        <slot></slot>
+      </v-col>
+    </v-row>
+  </v-container>
+</template>
+
+<script lang="ts">
+  import {defineComponent, reactive} from '@nuxtjs/composition-api'
+
+  export default defineComponent({
+    setup() {
+      return {
+      }
+    }
+  })
+</script>
+
+<style scoped>
+  .container{
+    padding: 30px;
+  }
+</style>

+ 61 - 11
components/Layout/HeaderComponent.vue

@@ -1,46 +1,96 @@
 <template>
   <v-app-bar
-    :clipped-left="properties.clipped"
+    clipped-left
+    elevate-on-scroll
+    dense
     fixed
     app
     class="ot_green ot_white--text"
   >
     <v-btn
+      v-if="properties.displayedMiniVariant"
       class="menu-btn"
       icon
-      @click.stop="properties.miniVariant = !properties.miniVariant"
+      @click.stop="displayedMenu()"
     >
       <v-icon class="ot_white--text">mdi-menu{{ `${properties.miniVariant ? '' : '-open'}` }}</v-icon>
     </v-btn>
 
-    <v-toolbar-title v-text="properties.title" />
+    <v-toolbar-title v-text="properties.title"/>
 
-    <v-spacer />
+    <v-spacer/>
+
+    <v-btn
+      elevation="2"
+      color="ot_warning ot_white--text"
+    >{{$t('create')}}</v-btn>
+
+<!--    <v-btn icon>-->
+<!--      <a class="no-decoration" :href="properties.homeUrl + '/'"><v-icon class="ot_white&#45;&#45;text" small>fa-home</v-icon></a>-->
+<!--    </v-btn>-->
+
+    <v-btn icon>
+      <NuxtLink to="/" class="no-decoration"><v-icon class="ot_white--text" small>fa-home</v-icon></NuxtLink>
+    </v-btn>
+
+    <HeaderMenuComponent :menu="properties.webSiteMenu"></HeaderMenuComponent>
+
+    <HeaderMenuComponent :menu="properties.myAccessesMenu" v-if="properties.hasAccessesMenu"></HeaderMenuComponent>
+
+    <HeaderMenuComponent :menu="properties.myFamilyMenu" v-if="properties.hasFamilyMenu"></HeaderMenuComponent>
+
+    <NotificationComponent></NotificationComponent>
+
+    <HeaderMenuComponent :menu="properties.configurationMenu" v-if="properties.hasConfigurationMenu"></HeaderMenuComponent>
+
+    <HeaderMenuComponent :menu="properties.accountMenu" :avatar="true"></HeaderMenuComponent>
+
+    <a class="help ot_dark_grey ot_menu_color--text" href="https://support.opentalent.fr/" target="_blank">{{$t('help_access')}}</a>
 
   </v-app-bar>
 </template>
 
 <script lang="ts">
   import {defineComponent, reactive, useContext} from '@nuxtjs/composition-api'
+  import {$useMenu} from "~/use/layout/menu";
 
   export default defineComponent({
-    setup() {
-      const {store} = useContext();
+    setup(props, {emit}) {
+      const {store, $config} = useContext();
 
       const properties = reactive({
-        clipped: true,
-        fixed: true,
         miniVariant: false,
-        title: store.state.profile.organization.name
+        displayedMiniVariant: store.state.profile.access.hasLateralMenu,
+        hasConfigurationMenu: store.state.profile.access.hasConfigurationMenu,
+        hasAccessesMenu: store.state.profile.access.hasAccessesMenu,
+        hasFamilyMenu: store.state.profile.access.hasFamilyMenu,
+        title: store.state.profile.organization.name,
+        homeUrl : $config.baseURL_adminLegacy,
+        webSiteMenu: $useMenu.setUpContext().useWebSiteMenuConstruct(),
+        myAccessesMenu : $useMenu.setUpContext().useMyAccessesMenuConstruct(),
+        myFamilyMenu : $useMenu.setUpContext().useMyFamilyMenuConstruct(),
+        configurationMenu: $useMenu.setUpContext().useConfigurationMenuConstruct(),
+        accountMenu : $useMenu.setUpContext().useAccountMenuConstruct()
       })
 
+      const displayedMenu = () => {
+        properties.miniVariant = !properties.miniVariant
+        emit('handle-open-menu-click', properties.miniVariant)
+      }
+
       return {
-        properties
+        properties,
+        displayedMenu
       }
     }
   })
 </script>
 
 <style scoped>
-
+  .help {
+    padding: 14px;
+    padding-bottom: 13px;
+    font-size: 14px;
+    text-decoration: none;
+  }
 </style>

+ 71 - 0
components/Layout/HeaderMenuComponent.vue

@@ -0,0 +1,71 @@
+<template>
+  <v-menu offset-y left max-height="300">
+    <template v-slot:activator="{ on, attrs }">
+      <v-avatar v-if="avatar"
+             size="30"
+             v-bind="attrs"
+             v-on="on"
+      >
+        <img
+          src="https://cdn.vuetifyjs.com/images/john.jpg"
+          alt="John"
+        >
+      </v-avatar>
+      <v-btn v-else
+             icon
+             v-bind="attrs"
+             v-on="on"
+             color=""
+      >
+        <v-icon class="ot_white--text" small>{{menu.icon}}</v-icon>
+      </v-btn>
+    </template>
+    <v-list dense :subheader="true">
+      <v-list-item dense class="ot_light_grey">
+        <v-list-item-title v-text="$t(menu.title)"></v-list-item-title>
+      </v-list-item>
+      <template v-for="(item, index) in menu.children">
+        <v-list-item
+          :key="item.title"
+          :href="item.isExternalLink ? item.to : undefined"
+          :to="!item.isExternalLink ? item.to : undefined"
+          router
+          exact
+        >
+          <v-list-item-title v-text="$t(item.title)"></v-list-item-title>
+        </v-list-item>
+        <v-divider
+          v-if="index < menu.length - 1"
+          :key="index"
+        ></v-divider>
+      </template>
+
+    </v-list>
+  </v-menu>
+</template>
+
+<script lang="ts">
+  import {defineComponent} from '@nuxtjs/composition-api'
+
+  export default defineComponent({
+    props: {
+      menu: {
+        type: Object,
+        required: true
+      },
+      avatar: {
+        type: Boolean,
+        required: false
+      }
+    },
+
+    setup() {
+      return {
+      }
+    }
+  })
+</script>
+
+<style scoped>
+
+</style>

+ 23 - 20
components/Layout/MenuComponent.vue

@@ -1,13 +1,13 @@
 <template>
   <v-navigation-drawer
-    :mini-variant="miniVariant"
-    :clipped="clipped"
+    :mini-variant.sync="miniVariant"
+    clipped
     class="ot_dark_grey ot_menu_color--text"
     fixed
     app
   >
     <v-list>
-      <div v-for="(item, i) in menu" :key="i">
+      <div v-for="(item, i) in properties.menu" :key="i">
         <v-list-item
           v-if="!item.children"
           :href="item.isExternalLink ? item.to : undefined"
@@ -16,7 +16,7 @@
           exact
         >
           <v-list-item-action>
-            <v-icon class="ot_menu_color--text">{{ item.icon }}</v-icon>
+            <v-icon class="ot_menu_color--text" small>{{ item.icon }}</v-icon>
           </v-list-item-action>
           <v-list-item-content>
             <v-list-item-title class="ot_menu_color--text" v-text="$t(item.title)"/>
@@ -30,7 +30,7 @@
         >
           <template v-slot:activator>
             <v-list-item-action>
-              <v-icon class="ot_menu_color--text">{{ item.icon }}</v-icon>
+              <v-icon class="ot_menu_color--text" small>{{ item.icon }}</v-icon>
             </v-list-item-action>
             <v-list-item-content>
               <v-list-item-title class="ot_menu_color--text" v-text="$t(item.title)"/>
@@ -46,7 +46,7 @@
             exact
           >
             <v-list-item-action>
-              <v-icon class="ot_menu_color--text">{{ child.icon }}</v-icon>
+              <v-icon class="ot_menu_color--text" small>{{ child.icon }}</v-icon>
             </v-list-item-action>
             <v-list-item-content>
               <v-list-item-title class="ot_menu_color--text" v-text="$t(child.title)"/>
@@ -61,26 +61,23 @@
 </template>
 
 <script lang="ts">
-  import {$useMenu} from '@/use/template/menu'
-  import {defineComponent} from '@nuxtjs/composition-api'
-  import {AnyJson} from "~/types/types";
+  import {$useMenu} from '@/use/layout/menu'
+  import {defineComponent, reactive} from '@nuxtjs/composition-api'
 
   export default defineComponent({
     props: {
       miniVariant: {
         type: Boolean,
         required: true
-      },
-      clipped: {
-        type: Boolean,
-        required: true
       }
     },
     setup() {
-      const menu: AnyJson = $useMenu.setUpContext().useLateralMenuConstruct()
+      const properties = reactive({
+        menu: $useMenu.setUpContext().useLateralMenuConstruct()
+      })
 
       return {
-        menu
+        properties
       }
     }
   })
@@ -90,22 +87,28 @@
   .v-list-item__action, .v-list-group__header__prepend-icon {
     margin-right: 10px !important;
   }
+
   .v-application--is-ltr .v-list-group--no-action > .v-list-group__items > .v-list-item {
     padding-left: 30px;
   }
-  .v-list-item__title{
+
+  .v-list-item__title {
     font-size: 14px;
   }
-  .v-icon.v-icon{
-    font-size: 16px;
-  }
-  .v-list-item{
+
+  .v-list-item {
     min-height: 10px !important;
   }
+
   .v-list-item__action {
     margin: 10px 0;
   }
+
   .v-list-item__content {
     padding: 8px 0;
   }
+
+  .home_menu {
+    font-size: 23px;
+  }
 </style>

+ 48 - 0
components/Layout/NotificationComponent.vue

@@ -0,0 +1,48 @@
+<template>
+  <v-menu offset-y>
+    <template v-slot:activator="{ on, attrs }">
+      <v-btn icon
+             v-bind="attrs"
+             v-on="on"
+      >
+        <v-icon class="ot_white--text" small>fa-bell</v-icon>
+      </v-btn>
+    </template>
+    <v-list dense>
+      <template v-for="(item, index) in properties.menu">
+        <v-list-item :key="item.title">
+          <v-list-item-title v-text="$t(item.title)"></v-list-item-title>
+        </v-list-item>
+        <v-divider
+          v-if="index < properties.menu.length - 1"
+          :key="index"
+        ></v-divider>
+      </template>
+
+    </v-list>
+  </v-menu>
+</template>
+
+<script lang="ts">
+  import {$useMenu} from '@/use/layout/menu'
+  import {defineComponent, reactive} from '@nuxtjs/composition-api'
+  import {AnyJson} from "~/types/types";
+
+  export default defineComponent({
+    setup() {
+      const menu: AnyJson = $useMenu.setUpContext().useConfigurationMenuConstruct()
+
+      const properties = reactive({
+        menu: menu
+      })
+
+      return {
+        properties
+      }
+    }
+  })
+</script>
+
+<style scoped>
+
+</style>

+ 0 - 50
components/List/ListComponent.vue

@@ -1,50 +0,0 @@
-<template>
-  <main>
-    <ejs-grid :dataSource="data" :allowPaging="true" :pageSettings='pageSettings' :enableHeaderFocus="true">
-      <e-columns>
-        <slot></slot>
-      </e-columns>
-    </ejs-grid>
-  </main>
-</template>
-
-<script lang="ts">
-  import {defineComponent, ref, useFetch} from '@nuxtjs/composition-api'
-  import { Page } from "@syncfusion/ej2-vue-grids";
-  import {Query,Collection, Model} from "@vuex-orm/core";
-
-  export default defineComponent({
-    props: {
-      query:{
-        type: Object as () => Query,
-        required: true
-      }
-    },
-    setup({query}){
-      const pageSettings = { pageSize: 30 }
-      const data = ref([] as Collection<Model>)
-
-      const { fetch, fetchState } = useFetch(async () => {
-        const collection = await query.get();
-        data.value = collection
-      })
-
-      return{
-        pageSettings,
-        data
-      }
-    },
-    provide: {
-      grid: [Page]
-    }
-  })
-</script>
-
-<style>
-  .e-grid .e-gridheader {
-    position: -webkit-sticky;
-    position: sticky;
-    top: 58px; /* The height of top nav menu. */
-    z-index: 1;
-  }
-</style>

+ 0 - 27
components/Utils/AlertComponent.vue

@@ -1,27 +0,0 @@
-<template>
-  <v-alert :type="type" class="position">
-    <slot></slot>
-  </v-alert>
-</template>
-
-<script lang="ts">
-  import {defineComponent, ref} from "@nuxtjs/composition-api";
-
-  export default defineComponent({
-    props: {
-      type:{
-        type: String,
-        required: true
-      }
-    }
-  })
-</script>
-
-<style scoped>
-  .position{
-    position: fixed;
-    width: 300px;
-    bottom: 0;
-    right: 0;
-  }
-</style>

+ 1 - 1
config/abilities/pages/addressBook.yaml

@@ -2,7 +2,7 @@
     action: 'display'
     services:
       access :
-        - {function: hasAbility, parameters: [{action: 'read', subject: 'user'}]}
+        - {function: hasAbility, parameters: [{action: 'read', subject: 'users'}]}
       organization  :
         - {function: hasModule, parameters: ['Users']}
 

+ 0 - 36
config/abilities/pages/admin2ios.yaml

@@ -22,42 +22,6 @@
       organization  :
         - {function: hasModule, parameters: ['CorePremium']}
 
-  actions_lead_page:
-    action: 'display'
-    services:
-      organization  :
-        - {function: hasModule, parameters: ['Admin2IOS']}
-
-  renewall_list_page:
-    action: 'display'
-    services:
-      organization  :
-        - {function: hasModule, parameters: ['Admin2IOS']}
-
-  settlements_page:
-    action: 'display'
-    services:
-      organization  :
-        - {function: hasModule, parameters: ['Admin2IOS']}
-
-  pendings_settlements_page:
-    action: 'display'
-    services:
-      organization  :
-        - {function: hasModule, parameters: ['Admin2IOS']}
-
-  outages_notice_page:
-    action: 'display'
-    services:
-      organization  :
-        - {function: hasModule, parameters: ['Admin2IOS']}
-
-  degraded_page:
-    action: 'display'
-    services:
-      organization  :
-        - {function: hasModule, parameters: ['Admin2IOS']}
-
   dgv_page:
     action: 'display'
     services:

+ 103 - 0
config/abilities/pages/parameters.yaml

@@ -0,0 +1,103 @@
+  organization_page:
+    action: 'display'
+    services:
+      access:
+        - {function: hasAbility, parameters: [{action: 'read', subject: 'organization'}]}
+      organization:
+        - {function: hasModule, parameters: ['GeneralConfig']}
+
+  cmf_licence_page:
+    action: 'display'
+    services:
+      access:
+        - {function: hasAbility, parameters: [{action: 'read', subject: 'organization'}]}
+      organization:
+        - {function: hasModule, parameters: ['GeneralConfig']}
+        - {function: isCmf}
+
+  parameters_page:
+    action: 'display'
+    services:
+      access:
+        - {function: hasAbility, parameters: [{action: 'read', subject: 'general-config'}]}
+      organization:
+        - {function: hasModule, parameters: ['GeneralConfig']}
+
+  place_page:
+    action: 'display'
+    services:
+      access:
+        - {function: hasAbility, parameters: [{action: 'read', subject: 'place'}]}
+      organization:
+        - {function: hasModule, parameters: ['GeneralConfig']}
+
+  education_page:
+    action: 'display'
+    services:
+      access:
+        - {function: hasAbility, parameters: [{action: 'read', subject: 'pedagogics-administration'}]}
+      organization:
+        - {function: hasModule, parameters: ['PedagogicsAdministation']}
+
+  tag_page:
+    action: 'display'
+    services:
+      access:
+        - {function: hasAbility, parameters: [{action: 'manage', subject: 'tagg'}]}
+      organization:
+        - {function: hasModule, parameters: ['TaggAdvanced']}
+
+  activities_page:
+    action: 'display'
+    services:
+      access:
+        - {function: hasAbility, parameters: [{action: 'read', subject: 'activity'}]}
+      organization:
+        - {function: hasModule, parameters: ['GeneralConfig']}
+
+  billing_settings_page:
+    action: 'display'
+    services:
+      access:
+        - {function: hasAbility, parameters: [{action: 'read', subject: 'billings-administration'}]}
+      organization:
+        - {function: hasModule, parameters: ['BillingAdministration']}
+
+  online_registration_settings_page:
+    action: 'display'
+    services:
+      access:
+        - {function: hasAbility, parameters: [{action: 'read', subject: 'onlineregistration-administration'}]}
+      organization:
+        - {function: hasModule, parameters: ['IEL']}
+        - {function: isSchool}
+
+  transition_next_year_page:
+    action: 'display'
+    services:
+      access:
+        - {function: hasAbility, parameters: [{action: 'manage', subject: 'pedagogics-administration'}]}
+      organization:
+        - {function: hasModule, parameters: ['PedagogicsAdministation']}
+
+  course_duplication_page:
+    action: 'display'
+    services:
+      access:
+        - {function: hasAbility, parameters: [{action: 'manage', subject: 'pedagogics-administration'}]}
+      organization:
+        - {function: hasModule, parameters: ['PedagogicsAdministation']}
+
+  import_page:
+    action: 'display'
+    services:
+      access:
+        - function: hasAbility
+          parameters:
+            - {action: 'manage', subject: 'user'}
+            - {action: 'manage', subject: 'equipments'}
+      organization:
+        - function: hasModule
+          parameters:
+            - 'Users'
+            - 'Equipments'

+ 2 - 0
config/nuxtConfig/env.js

@@ -5,6 +5,8 @@ export default {
     artist_product: 'artist',
     artist_premium_product: 'artist-premium',
     manager_product: 'manager',
+    cmf_network: 'CMF',
+    ffec_network: 'FFEC',
   },
   publicRuntimeConfig: {
     http: {

+ 1 - 0
config/nuxtConfig/head.js

@@ -16,6 +16,7 @@ export default {
   // Global CSS (https://go.nuxtjs.dev/config-css)
   css: [
     '@/assets/css/import.scss',
+    '@/assets/css/global.scss',
     '@fortawesome/fontawesome-free/css/all.css'
   ]
 }

+ 1 - 0
config/nuxtConfig/modules.js

@@ -5,6 +5,7 @@ export default {
     '@nuxt/typescript-build',
     // https://go.nuxtjs.dev/vuetify
     '@nuxtjs/vuetify',
+    '@nuxtjs/moment',
     '@nuxtjs/composition-api'
   ],
 

+ 7 - 0
config/nuxtConfig/moment.js

@@ -0,0 +1,7 @@
+export default {
+  moment: {
+    defaultLocale: 'fr',
+    locales: ['fr'],
+    timezone: true
+  }
+}

+ 0 - 1
config/nuxtConfig/plugins.js

@@ -1,7 +1,6 @@
 export default {
   // Plugins to run before rendering page (https://go.nuxtjs.dev/config-plugins)
   plugins: [
-    '~/plugins/grid',
     '~/plugins/Rights/ability',
     './plugins/Rights/casl.js',
     '~/plugins/Queries/http',

+ 3 - 0
config/nuxtConfig/vuetify.js

@@ -7,6 +7,8 @@ export default {
       iconfont: 'fa' || 'mdi',
     },
     customVariables: ['~/assets/css/variables.scss'],
+    customProperties: true,
+    treeShake: true,
     theme: {
       dark: false,
       themes: {
@@ -31,6 +33,7 @@ export default {
           ot_warning: '#f39c12',
           ot_info: '#3c8dbc',
           ot_menu_color: '#b8c7ce',
+          ot_content_color: '#ecf0f4',
           ot_white: '#ffffff'
         },
       }

+ 0 - 24
data/accessesData.js

@@ -1,24 +0,0 @@
-export default async function accessesData() {
-  return {
-    "@context": "\/api\/contexts\/Access",
-    "@id": "\/api\/accesses\/64",
-    "@type": "Access",
-    "id": 64,
-    "person": {
-      "@type": "Person",
-      "@id": "_:771",
-      "id": 552581,
-      "username": "",
-      "roles": [
-        "ROLE_USER"
-      ],
-      "name": "BLONDAZ PIEDIGROS",
-      "givenName": "Sylvie",
-      "__isInitialized__": true
-    },
-    "personActivity": [
-      "\/api\/person_activities\/58",
-      "\/api\/person_activities\/59"
-    ]
-  }
-}

+ 0 - 26
data/personActivitiesData.js

@@ -1,26 +0,0 @@
-export default async function personActivitiesData(){
-  return {
-    "@context": "\/api\/contexts\/PersonActivity",
-    "@id": "\/api\/accesses\/64\/person_activities",
-    "@type": "hydra:Collection",
-    "hydra:member": [
-      {
-        "@id": "\/api\/person_activities\/58",
-        "@type": "PersonActivity",
-        "id": 58,
-        "complementSpeciality": "Trompette",
-        "startDate": "1977-09-01T00:00:00+00:00",
-        "access": "\/api\/accesses\/64"
-      },
-      {
-        "@id": "\/api\/person_activities\/59",
-        "@type": "PersonActivity",
-        "id": 59,
-        "complementSpeciality": "Guitare",
-        "startDate": "2015-09-02T00:00:00+00:00",
-        "access": "\/api\/accesses\/64"
-      }
-    ],
-    "hydra:totalItems": 2
-  }
-}

+ 61 - 0
lang/enum/fr-FR.js

@@ -0,0 +1,61 @@
+export default (context, locale) => {
+  return ({
+    LOCAL_AUTHORITY: 'Collectivité territoriale (Mairie, SIVOM, SIVU, EPIC, …)',
+    ASSOCIATION_LAW_1901: 'Association loi 1901 ou assimilée (Droit local, ...)',
+    COMMERCIAL_SOCIETY: 'Entreprise commerciale (SARL, SAS, EURL, Autoentrepreneur, …)',
+    ARTISTIC_EDUCATION_ONLY: "Enseignement artistique seul",
+    ARTISTIC_PRACTICE_EDUCATION: "Pratique et enseignement artistique",
+    ARTISTIC_PRACTICE_ONLY: "Pratique artistique seule",
+    DELEGATION: "Délégation",
+    DEPARTEMENTAL_FEDERATION: "Fédération départementale",
+    GROUPMENT: "Groupement",
+    LOCAL_FEDERATION: "Fédération locale",
+    MUSIC_OPENTALENT: "Opentalent",
+    NATIONAL_FEDERATION: "Fédération nationale",
+    REGIONAL_FEDERATION: "Fédération régionale",
+    CESMD: "CESMD Centre d'études supérieures de musique et de danse",
+    CNSMD: "CNSMD Conservatoire national supérieur de musique",
+    CRC: "CRC Conservatoire à rayonnement communal",
+    CRD: "CRD Conservatoire à rayonnement départemental",
+    CRI: "CRI Conservatoire à rayonnement intercommunal",
+    CRR: "CRR Conservatoire à rayonnement régional",
+    EENC: "EENC Établissement d'enseignement artistique non classé",
+    EMP: "EMP Ecole de musique privée",
+    MULTIPLE: "Multiple",
+    UNIQUE: "Unique",
+    MAIN_BUILDING: "Etablissement principal",
+    SECONDARY_SCHOOL: "Etablissement secondaire",
+    ACTALIANS: "Actalians",
+    AFDAS: "Afdas",
+    AGEFOS: "Agefos",
+    AGEFOS_PME: "Agefos pme",
+    ANFA: "Anfa",
+    ANFH: "Anfh",
+    APCMA: "Apcma",
+    CNFPT: "Cnfpt",
+    CONSTRUCTYS: "Constructys",
+    FAF_TT: "Faf-tt",
+    FAFIEC: "Fafiec",
+    FAFIH: "Fafih",
+    FAFSEA: "Fafsea",
+    FIF_PL: "Fif pl",
+    FONGECIF: "Fongecif",
+    FORCO: "Forco",
+    INTERGROS: "Intergros",
+    OPCA3_PLUS: "Opca3+",
+    OPCAIM: "Opcaim",
+    OPCALIA: "Opcalia",
+    OPCALIM: "Opcalim",
+    OPCA_BAIA: "Opca baia",
+    OPCA_DEFI: "Opca defi",
+    OPCA_TRANSPORTS: "Opca transports",
+    UNIFAF: "Unifaf",
+    UNIFORMATION: "Uniformation",
+    VIVEA: "Vivea",
+    ADDRESS_PRACTICE: "Adresse de pratique",
+    ADDRESS_HEAD_OFFICE: "Adresse du siège social",
+    ADDRESS_CONTACT: "Adresse de contact",
+    ADDRESS_BILL: "Adresse de facturation",
+    ADDRESS_OTHER: "Autre adresse",
+  })
+}

+ 67 - 0
lang/field/fr-FR.js

@@ -0,0 +1,67 @@
+export default (context, locale) => {
+  return ({
+    legalInformation: 'Informations légales',
+    agrements: 'Agréments',
+    salary: 'Salariés',
+    network: 'Informations réseau',
+    communication: 'Communication',
+    legalStatus: "Statut juridique",
+    siretNumber: "N° SIRET",
+    apeNumber: "Code APE",
+    waldecNumber: "RNA (ancien Waldec)",
+    identifierCmf: "Matricule CMF",
+    identifierFfec: "Matricule FFEC",
+    ffecApproval: "N° agrément FFEC",
+    description: "Description",
+    typeOfPractices: "Type de pratiques",
+    otherPractice: "Autres ensembles (préciser)",
+    principalType: "Type principal",
+    contact_point: "Point de contact",
+    name: "Nom",
+    acronym: "Sigle",
+    creationDate: "Date de création",
+    prefectureName: "Préfecture ou sous-préfecture",
+    prefectureNumber: "Numéro de déclaration",
+    declarationDate: "Date de déclaration",
+    tvaNumber: "TVA Intracommunautaire",
+    schoolCategory: "Catégorie d'école",
+    typeEstablishment: "Type d'établissement",
+    typeEstablishmentDetail: "Détails du type",
+    youngApproval: "Jeunesse-éducation populaire",
+    trainingApproval: "Organisme de formation",
+    otherApproval: "Si autre, lesquels",
+    collectiveAgreement: "Nom de la convention collective",
+    opca: "Nom de l'OPCA",
+    icomNumber: "N° ICOM",
+    urssafNumber: "N° URSSAF",
+    email: "E-mail",
+    telphone: "Téléphone",
+    mobilPhone: "Portable",
+    actions: "Actions",
+    twitter: "Lien Twitter",
+    facebook: "Lien Facebook",
+    instagram: "Lien Instagram",
+    image: "Image",
+    portailVisibility: "Répertorier la structure dans l'annuaire du portail Opentalent",
+    pedagogicBudget: "Budget pédagogique",
+    budget: "Montant du dernier budget réalisé",
+    isPedagogicIsPrincipalActivity: "L'activité principale de la stucture est « la pédagogie des arts du cirque »",
+    bank_account: "IBAN",
+    bankName: "Nom de la banque",
+    bic: "Code BIC",
+    iban: "IBAN",
+    holder: "Titulaire du compte",
+    debitAddress: "Domiciliation",
+    principal: "Principal",
+    address_postal: "Adresses postales",
+    address: "Adresse",
+    address_postal_type: "Nature",
+    addressOwner: "Chez",
+    streetAddress: "Adresses",
+    streetAddressSecond: "Adresses suite",
+    streetAddressThird: "Adresses suite 2",
+    postalCode: "Code postal",
+    addressCity: "Ville",
+    country: "Pays",
+  })
+}

+ 7 - 2
lang/fr-FR.js

@@ -1,8 +1,13 @@
 import layout from '@/lang/layout/fr-FR'
-
+import enums from '@/lang/enum/fr-FR'
+import fields from '@/lang/field/fr-FR'
+import rulesAndErrors from '@/lang/rulesAndErrors/fr-FR'
 export default (context, locale) => {
 
   return {
-    ...layout()
+    ...layout(context, locale),
+    ...enums(context, locale),
+    ...fields(context, locale),
+    ...rulesAndErrors(context, locale),
   }
 }

+ 16 - 0
lang/layout/fr-FR.js

@@ -71,5 +71,21 @@ export default (context, locale) => {
     tree_menu: 'Gestion de l\'arbre',
     website: 'Site internet',
     advanced_modification: 'Modifications avancées',
+    simple_modification: 'Modifications simplifiées',
+    create: 'Créer',
+    help_access: 'Accès aide',
+    configuration: 'Configuration',
+    organization_page: 'Fiche de la structure',
+    cmf_licence_generate: 'Générer la licence CMF de la structure',
+    parameters: 'Préférences',
+    place: 'Lieux',
+    education: 'Enseignements',
+    tag: 'Tags',
+    activities: 'Sections',
+    billing_settings: 'Facturation',
+    online_registration_settings: 'Pré-inscription(s) en ligne',
+    transition_next_year: 'Passage à l\'année suivante',
+    course_duplication: 'Dupliquer les cours hebdomadaires',
+    import: 'Importer',
   })
 }

+ 7 - 0
lang/rulesAndErrors/fr-FR.js

@@ -0,0 +1,7 @@
+export default (context, locale) => {
+  return ({
+    required: 'Ce champs est obligatoire',
+    name_length_rule: "La taille du nom doit être de moins de 128 caractères",
+    siret_error: "N° de siret non valide",
+  })
+}

+ 16 - 8
layouts/default.vue

@@ -4,31 +4,39 @@
     </client-only>
 
     <v-app dark>
-      <MenuComponent :miniVariant="properties.miniVariant" :clipped="properties.clipped"></MenuComponent>
 
-      <HeaderComponent></HeaderComponent>
+      <MenuComponent  v-if="properties.displayedMenu" :miniVariant="properties.miniVariant"></MenuComponent>
 
-      <v-main class="ot_super_light_grey">
-        <v-container>
+      <HeaderComponent v-on:handle-open-menu-click="handleOpenMenu"></HeaderComponent>
+
+      <v-main class="ot_content_color">
           <nuxt/>
-        </v-container>
       </v-main>
     </v-app>
   </main>
 </template>
 
 <script lang="ts">
-  import {defineComponent, reactive, useContext} from '@nuxtjs/composition-api'
+  import {defineComponent, reactive, ref, useContext, computed} from '@nuxtjs/composition-api'
 
   export default defineComponent({
+    name: 'defaultLayout',
     setup() {
+      const {store} = useContext()
+
       const properties = reactive({
-        clipped: true,
+        clipped: false,
         miniVariant: false,
+        displayedMenu:  store.state.profile.access.hasLateralMenu
       })
 
+      const handleOpenMenu = (miniVariant:boolean) => {
+        properties.miniVariant = miniVariant
+      }
+
       return {
-        properties
+        properties,
+        handleOpenMenu
       }
     },
     middleware: ['auth']

+ 1 - 0
layouts/login.vue

@@ -10,6 +10,7 @@
 
 <script>
   export default {
+    name: 'loginLayout',
     data () {
       return {
 

+ 0 - 12
models/Access/Access.ts

@@ -1,12 +0,0 @@
-import {Model, Attr, HasOne} from '@vuex-orm/core'
-import {Person} from '@/models/Person/Person'
-
-export class Access extends Model{
-  static entity = 'accesses'
-
-  @Attr(null)
-  id!: number | null
-
-  @HasOne(() => Person, 'accessId')
-  person!: Person | null
-}

+ 40 - 0
models/Core/AddressPostal.ts

@@ -0,0 +1,40 @@
+import {Attr, Str, HasOne, Num} from '@vuex-orm/core'
+import {Model} from '@/models/Model'
+import {Country} from "~/models/Core/Country";
+
+export class AddressPostal extends Model{
+  static entity = 'address_postals'
+
+  @Attr(null)
+  id!: number | null
+
+  @Attr(null)
+  addressPostalId!: number | null
+
+  @HasOne(() => Country, 'countryId')
+  country!: Country | null
+
+  @Str('', {nullable: true})
+  addressCity!: string
+
+  @Str('', {nullable: true})
+  addressOwner!: string
+
+  @Str('', {nullable: true})
+  postalCode!: string
+
+  @Str('', {nullable: true})
+  streetAddress!: string
+
+  @Str('', {nullable: true})
+  streetAddressSecond!: string
+
+  @Str('', {nullable: true})
+  streetAddressThird!: string
+
+  @Num(0, {nullable: true})
+  latitude!: number
+
+  @Num(0, {nullable: true})
+  longitude!: number
+}

+ 27 - 0
models/Core/BankAccount.ts

@@ -0,0 +1,27 @@
+import {Attr, Str, Bool, Num} from '@vuex-orm/core'
+import {Model} from '@/models/Model'
+
+export class BankAccount extends Model{
+  static entity = 'bank_accounts'
+
+  @Attr(null)
+  id!: number | null
+
+  @Str('', {nullable: true})
+  bankName!: string
+
+  @Str('', {nullable: true})
+  bic!: string
+
+  @Str('', {nullable: true})
+  iban!: string
+
+  @Str('', {nullable: true})
+  debitAddress!: string
+
+  @Str('', {nullable: true})
+  holder!: string
+
+  @Bool(false, {nullable: false})
+  principal!: boolean
+}

+ 21 - 0
models/Core/ContactPoint.ts

@@ -0,0 +1,21 @@
+import {Attr, Str} from '@vuex-orm/core'
+import {Model} from '@/models/Model'
+
+export class ContactPoint extends Model{
+  static entity = 'contact_points'
+
+  @Attr(null)
+  id!: number | null
+
+  @Str('', {nullable: true})
+  email!: string
+
+  @Str('', {nullable: true})
+  telphone!: string
+
+  @Str('', {nullable: true})
+  mobilPhone!: string
+
+  @Str('', {nullable: true})
+  faxNumber!: string
+}

+ 12 - 0
models/Core/Country.ts

@@ -0,0 +1,12 @@
+import {Attr, Str} from '@vuex-orm/core'
+import {Model} from '@/models/Model'
+
+export class Country extends Model{
+  static entity = 'countries'
+
+  @Attr(null)
+  id!: number | null
+
+  @Str('')
+  name!: string
+}

+ 13 - 0
models/Model.ts

@@ -0,0 +1,13 @@
+import {Model as BaseModel} from "@vuex-orm/core";
+
+export class Model extends BaseModel{
+  readonly:boolean = true;
+
+  setReadOnly(readOnly: boolean): void{
+    this.readonly = readOnly;
+  }
+
+  getReadOnly():boolean{
+    return this.readonly;
+  }
+}

+ 99 - 2
models/Organization/Organization.ts

@@ -1,4 +1,5 @@
-import {Model, Attr, Str} from '@vuex-orm/core'
+import {Attr, Str, Bool, Num} from '@vuex-orm/core'
+import {Model} from '@/models/Model'
 
 export class Organization extends Model{
   static entity = 'organizations'
@@ -6,12 +7,108 @@ export class Organization extends Model{
   @Attr(null)
   id!: number | null
 
-  @Str('', {nullable: false})
+  @Str('', {nullable: true})
   name!: string
 
+  @Str('', {nullable: true})
+  acronym!: string
+
+  @Str('', {nullable: true})
+  siretNumber!: string
+
+  @Str('', {nullable: true})
+  apeNumber!: string
+
+  @Str('', {nullable: true})
+  waldecNumber!: string
+
+  @Str('', {nullable: true})
+  identifier!: string
+
+  @Str('', {nullable: true})
+  ffecApproval!: string
+
+  @Str('', {nullable: true})
+  description!: string
+
+  @Str('', {nullable: true})
+  otherPractice!: string
+
   @Str('', {nullable: true})
   legalStatus!: string
 
   @Str('', {nullable: true})
   principalType!: string
+
+  @Str('', {nullable: true})
+  youngApproval!: string
+
+  @Str('', {nullable: true})
+  trainingApproval!: string
+
+  @Str('', {nullable: true})
+  otherApproval!: string
+
+  @Str('', {nullable: true})
+  collectiveAgreement!: string
+
+  @Str('', {nullable: true})
+  opca!: string
+
+  @Str('', {nullable: true})
+  icomNumber!: string
+
+  @Str('', {nullable: true})
+  urssafNumber!: string
+
+  @Str('', {nullable: true})
+  twitter!: string
+
+  @Str('', {nullable: true})
+  facebook!: string
+
+  @Str('', {nullable: true})
+  instagram!: string
+
+  @Bool(true, {nullable: false})
+  portailVisibility!: boolean
+
+  @Str('', {nullable: true})
+  image!: string
+
+  @Str('', {nullable: true})
+  creationDate!: string
+
+  @Str('', {nullable: true})
+  prefectureName!: string
+
+  @Str('', {nullable: true})
+  prefectureNumber!: string
+
+  @Str('', {nullable: true})
+  declarationDate!: string
+
+  @Str('', {nullable: true})
+  tvaNumber!: string
+
+  @Str('', {nullable: true})
+  schoolCategory!: string
+
+  @Str('', {nullable: true})
+  typeEstablishment!: string
+
+  @Str('', {nullable: true})
+  typeEstablishmentDetail!: string
+
+  @Bool(false, {nullable: false})
+  isPerformanceContractor!: boolean
+
+  @Num(0, {nullable: true})
+  budget!: number
+
+  @Bool(false, {nullable: false})
+  isPedagogicIsPrincipalActivity!: boolean
+
+  @Num(0, {nullable: true})
+  pedagogicBudget!: number
 }

+ 16 - 0
models/Organization/OrganizationAddressPostal.ts

@@ -0,0 +1,16 @@
+import {Attr, Str, HasOne} from '@vuex-orm/core'
+import {Model} from '@/models/Model'
+import {AddressPostal} from "~/models/Core/AddressPostal";
+
+export class OrganizationAddressPostal extends Model{
+  static entity = 'organization_address_postals'
+
+  @Attr(null)
+  id!: number | null
+
+  @HasOne(() => AddressPostal, 'addressPostalId')
+  addressPostal!: AddressPostal | null
+
+  @Str('PRINCIPAL', {nullable: false})
+  type!: string
+}

+ 21 - 0
models/Organization/OrganizationLicence.ts

@@ -0,0 +1,21 @@
+import {Attr, Str} from '@vuex-orm/core'
+import {Model} from '@/models/Model'
+
+export class OrganizationLicence extends Model{
+  static entity = 'organization_licences'
+
+  @Attr(null)
+  id!: number | null
+
+  @Str('', {nullable: false})
+  licensee!: string
+
+  @Str('', {nullable: true})
+  licenceNumber!: string
+
+  @Str('', {nullable: true})
+  categorie!: string
+
+  @Str('', {nullable: true})
+  validityDate!: string
+}

+ 21 - 0
models/Organization/OrganizationNetwork.ts

@@ -0,0 +1,21 @@
+import {Attr, Str} from '@vuex-orm/core'
+import {Model} from '@/models/Model'
+
+export class OrganizationLicence extends Model{
+  static entity = 'organization_licences'
+
+  @Attr(null)
+  id!: number | null
+
+  @Str('', {nullable: false})
+  licensee!: string
+
+  @Str('', {nullable: true})
+  licenceNumber!: string
+
+  @Str('', {nullable: true})
+  categorie!: string
+
+  @Str('', {nullable: true})
+  validityDate!: string
+}

+ 0 - 17
models/Person/Person.ts

@@ -1,17 +0,0 @@
-import {Model, Attr, Str} from '@vuex-orm/core'
-
-export class Person extends Model{
-  static entity = 'people'
-
-  @Attr(null)
-  id!: number | null
-
-  @Attr(null)
-  accessId!: number | null
-
-  @Str('', {nullable: false})
-  name!: string
-
-  @Str('', {nullable: true})
-  givenName!: string
-}

+ 0 - 14
models/Person/PersonActivity.ts

@@ -1,14 +0,0 @@
-import {Model, Attr, Str} from '@vuex-orm/core'
-
-export class PersonActivity extends Model{
-  static entity = 'person_activities'
-
-  @Attr(null)
-  id!: number | null
-
-  @Str('', {nullable: true})
-  startDate!: string
-
-  @Str('', {nullable: true})
-  complementSpeciality!: string
-}

+ 3 - 1
nuxt.config.js

@@ -5,6 +5,7 @@ import modules from './config/nuxtConfig/modules'
 import plugins from './config/nuxtConfig/plugins'
 import i18n from './config/nuxtConfig/i18n'
 import vuetify from './config/nuxtConfig/vuetify'
+import moment from './config/nuxtConfig/moment'
 
 export default {
   ...build,
@@ -13,5 +14,6 @@ export default {
   ...modules,
   ...plugins,
   ...i18n,
-  ...vuetify
+  ...vuetify,
+  ...moment,
 }

+ 4 - 3
package.json

@@ -17,10 +17,9 @@
     "@casl/vue": "^1.2.1",
     "@nuxt/http": "^0.6.1",
     "@nuxt/typescript-runtime": "^2.0.0",
-    "@nuxtjs/composition-api": "0.19",
-    "@syncfusion/ej2-vue-grids": "^18.4.30",
+    "@nuxtjs/composition-api": "0.22.0",
     "@types/lodash": "^4.14.168",
-    "@vuex-orm/core": "1.0.0-draft.8",
+    "@vuex-orm/core": "1.0.0-draft.9",
     "cookieparser": "^0.1.0",
     "core-js": "^3.6.5",
     "js-yaml": "^4.0.0",
@@ -28,6 +27,7 @@
     "marked": "^1.2.7",
     "nuxt": "^2.14.6",
     "nuxt-i18n": "^6.18.0",
+    "vue-i18n-composable": "^0.2.1",
     "yaml-import": "^2.0.0"
   },
   "devDependencies": {
@@ -37,6 +37,7 @@
     "@nuxtjs/eslint-config": "^3.1.0",
     "@nuxtjs/eslint-config-typescript": "^3.0.0",
     "@nuxtjs/eslint-module": "^2.0.0",
+    "@nuxtjs/moment": "^1.6.1",
     "@nuxtjs/vuetify": "1.11.3",
     "@vue/test-utils": "^1.1.0",
     "babel-core": "7.0.0-bridge.0",

+ 0 - 84
pages/accesses/_id.vue

@@ -1,84 +0,0 @@
-<template>
-  <v-row justify="center" align="center">
-    <v-col cols="12" sm="8" md="8">
-
-        <FormComponent>
-
-          <v-expansion-panels v-model="panel" focusable>
-
-            <ExpansionPanelComponent title="Informations générales">
-              <InputComponent :query="accessesQuery" field="person.name" :rules="nameRule" />
-              <InputComponent :query="accessesQuery" field="person.givenName" />
-            </ExpansionPanelComponent>
-
-            <ExpansionPanelComponent title="Activités">
-              <DataTableComponent :repository="personActivitiesRepository" :uri="personActivitiesUri" :headers="personActivitiesHearders"></DataTableComponent>
-            </ExpansionPanelComponent>
-
-          </v-expansion-panels>
-
-        </FormComponent>
-
-    </v-col>
-  </v-row>
-</template>
-
-
-<script lang="ts">
-  import {defineComponent, useContext} from '@nuxtjs/composition-api'
-  import {Access} from '@/models/Access/Access'
-  import {Person} from '@/models/Person/Person'
-  import {PersonActivity} from '@/models/Person/PersonActivity'
-  import accessesData from '@/data/accessesData'
-
-  export default defineComponent({
-    setup() {
-      const {store, route} = useContext();
-      const panel = 0
-      const accessesRepository = store.$repo(Access)
-      const accessesQuery = accessesRepository.with('person')
-      const personActivitiesRepository = store.$repo(PersonActivity)
-
-      const personActivitiesUri = `${accessesRepository.getModel().$entity}/${route.value.params.id}/${personActivitiesRepository.getModel().$entity}`
-      const personActivitiesHearders = [
-        {
-          text: 'Activité',
-          align: 'start',
-          sortable: false,
-          value: 'complementSpeciality',
-        },
-        { text: 'Date de début',
-          value: 'startDate'
-        }
-      ]
-
-      const nameRule = [
-        (nameValue:string) => (nameValue || '').length <= 128 || `A maximum of 128 characters is allowed`
-      ]
-
-      return {
-        accessesQuery,
-        personActivitiesRepository,
-        personActivitiesUri,
-        personActivitiesHearders,
-        panel,
-        nameRule
-      }
-    },
-
-    async asyncData({store, $rest, params}){
-      const repository = store.$repo(Access);
-      const entity = repository.getModel().$entity;
-      const access = await $rest.getItem(`/api/${entity}`, params.id)
-      // const accesses = await accessesData()
-      repository.insert(access);
-    },
-
-    async beforeRouteLeave (to, from, next) {
-      const flushAccess =  await this.$store.$repo(Access).flush();
-      const flushPerson =  await this.$store.$repo(Person).flush();
-      const flushPersonActivity =  await this.$store.$repo(PersonActivity).flush();
-      next();
-    }
-  })
-</script>

+ 0 - 38
pages/accesses/list.vue

@@ -1,38 +0,0 @@
-<template>
-  <main>
-    <NuxtLink to="/accesses/7351">Exemple fiche</NuxtLink>
-    <ListComponent :query="accessesQuery">
-      <e-column field='id' headerText='id'></e-column>
-      <e-column field='person.name' headerText='Nom'></e-column>
-      <e-column field='person.givenName' headerText='Prénom'></e-column>
-    </ListComponent>
-  </main>
-</template>
-
-
-<script lang="ts">
-  import {defineComponent, ref, useContext, useAsync} from '@nuxtjs/composition-api'
-  import {Access} from '@/models/Access/Access'
-
-  export default defineComponent({
-    setup() {
-      const { store } = useContext()
-      const accessesQuery = ref(store.$repo(Access).with('person'))
-
-      return {
-        accessesQuery
-      }
-    },
-    async asyncData({store, $rest}){
-      const repository = store.$repo(Access);
-      const entity = repository.getModel().$entity;
-
-      const accesses = await $rest.getCollection(`/api/${entity}`)
-      repository.insert(accesses);
-    }
-  })
-</script>
-
-<style>
- @import "~/node_modules/@syncfusion/ej2-vue-grids/styles/material.css";
-</style>

+ 3 - 1
pages/index.vue

@@ -2,15 +2,17 @@
   <v-row justify="center" align="center">
     <v-col cols="12" sm="12" md="12">
       <h3>Bienvenue !</h3>
+      <NuxtLink to="organization/edit">Organization</NuxtLink>
     </v-col>
   </v-row>
 </template>
 
 
 <script lang="ts">
-  import {defineComponent, useContext} from '@nuxtjs/composition-api'
+  import {defineComponent} from '@nuxtjs/composition-api'
 
   export default defineComponent({
+    name: 'index',
     setup() {
       return {
 

+ 452 - 0
pages/organization/edit.vue

@@ -0,0 +1,452 @@
+<template>
+  <ContainerComponent>
+    <template>
+      <v-card class="margin-bottom-20">
+        <v-toolbar flat class="ot_light_grey" dark>
+          <v-toolbar-title class="ot_dark_grey--text">
+            Description de l'organisation
+            <v-btn @click="edit" class="ot_green editBtn">
+              <v-icon class="ot_white--text" small>fa-pencil-alt</v-icon>
+            </v-btn>
+          </v-toolbar-title>
+        </v-toolbar>
+
+        <FormComponent :repository="repositories.organizationRepository" :id="id" :query="repositories.organizationRepository.query()">
+          <template v-slot:form.input="{entry}">
+            <v-tabs vertical>
+              <v-tab><v-icon left>fa-info</v-icon>{{$t('description')}}</v-tab>
+              <v-tab><v-icon left>fa-gavel</v-icon>{{$t('legalInformation')}}</v-tab>
+              <v-tab><v-icon left>fa-certificate</v-icon>{{$t('agrements')}}</v-tab>
+              <v-tab><v-icon left>fa-users</v-icon>{{$t('salary')}}</v-tab>
+              <v-tab v-if="organizationProfile.isInsideNetwork()"><v-icon left>fa-share-alt</v-icon>{{$t('network')}}</v-tab>
+              <v-tab><v-icon left>fa-rss</v-icon>{{$t('communication')}}</v-tab>
+
+              <v-tab-item>
+                <v-container fluid class="container">
+                  <v-row>
+                    <v-col cols="12" sm="6">
+                      <InputComponent field="name" :repository="repositories.organizationRepository" :entry="entry" :rules="rules.nameRules" />
+                    </v-col>
+
+                    <v-col cols="12" sm="6">
+                      <InputComponent field="acronym" :repository="repositories.organizationRepository" :entry="entry" />
+                    </v-col>
+                    <v-col cols="12" sm="6">
+                      <InputComponent
+                        field="siretNumber"
+                        :repository="repositories.organizationRepository"
+                        :entry="entry"
+                        v-on:update="checkSiret"
+                        :error="siretError"
+                        :errorMessage="siretErrorMessage"
+                        :rules="rules.siretRule"
+                      />
+                    </v-col>
+                    <v-col cols="12" sm="6">
+                      <InputComponent field="apeNumber" :repository="repositories.organizationRepository" :entry="entry" />
+                    </v-col>
+                    <v-col cols="12" sm="6" v-if="entry['legalStatus'] === 'ASSOCIATION_LAW_1901'" >
+                      <InputComponent field="waldecNumber" :repository="repositories.organizationRepository" :entry="entry"  />
+                    </v-col>
+                    <v-col cols="12" sm="6" v-if="organizationProfile.isInsideNetwork()" >
+                      <InputComponent field="identifier" :repository="repositories.organizationRepository" :entry="entry"
+                                      :label="organizationProfile.isCmf() ? 'identifierCmf' : 'identifierFfec'" />
+                    </v-col>
+                    <v-col cols="12" sm="6" v-if="organizationProfile.isFfec()" >
+                      <InputComponent field="ffecApproval" :repository="repositories.organizationRepository" :entry="entry" />
+                    </v-col>
+                    <v-col cols="12" sm="6">
+                      <InputComponent field="description" :repository="repositories.organizationRepository" :entry="entry"  />
+                    </v-col>
+                    <v-col cols="12" sm="6">
+                      <InputComponent field="logo" :repository="repositories.organizationRepository" :entry="entry"  />
+                    </v-col>
+
+                    <!-- @todo: ajouter les if et transformer en select-->
+                    <v-col cols="12" sm="6">
+                      <InputComponent field="typeOfPractices" :repository="repositories.organizationRepository" :entry="entry"  />
+                    </v-col>
+                    <v-col cols="12" sm="6">
+                      <InputComponent field="otherPractice" :repository="repositories.organizationRepository" :entry="entry"  />
+                    </v-col>
+                  </v-row>
+                </v-container>
+              </v-tab-item>
+
+              <v-tab-item>
+                <v-container fluid class="container">
+                  <v-row>
+                    <v-col cols="12" sm="6">
+                      <DatePickerComponent field="creationDate" :repository="repositories.organizationRepository" :entry="entry"  />
+                    </v-col>
+                    <v-col cols="12" sm="6">
+                      <InputComponent field="prefectureName" :repository="repositories.organizationRepository" :entry="entry"  />
+                    </v-col>
+                    <v-col cols="12" sm="6">
+                      <InputComponent field="prefectureNumber" :repository="repositories.organizationRepository" :entry="entry"  />
+                    </v-col>
+                    <v-col cols="12" sm="6">
+                      <InputComponent field="tvaNumber" :repository="repositories.organizationRepository" :entry="entry"  />
+                    </v-col>
+                    <v-col cols="12" sm="6">
+                      <SelectComponent field="legalStatus" :repository="repositories.organizationRepository" :entry="entry"  enumType="organization_legal" />
+                    </v-col>
+                    <v-col cols="12" sm="6" v-if="!organizationProfile.isManagerProduct()" >
+                      <SelectComponent field="principalType" :repository="repositories.organizationRepository"
+                                       :entry="entry"  enumType="organization_principal_type"
+                      />
+                    </v-col>
+                    <v-col cols="12" sm="6" v-if="!organizationProfile.isFfec() && !organizationProfile.isManagerProduct() && !organizationProfile.isArtist()">
+                      <SelectComponent field="schoolCategory" :repository="repositories.organizationRepository" :entry="entry"  enumType="organization_school_cat" />
+                    </v-col>
+                    <v-col cols="12" sm="6" v-if="organizationProfile.isFfec()" >
+                      <SelectComponent field="typeEstablishment" :repository="repositories.organizationRepository" :entry="entry" enumType="organization_type_establishment"/>
+                    </v-col>
+                    <v-col cols="12" sm="6" v-if="entry.typeEstablishment === 'MULTIPLE'" >
+                      <SelectComponent field="typeEstablishmentDetail" :repository="repositories.organizationRepository" :entry="entry"  enumType="organization_type_establishment_detail"/>
+                    </v-col>
+                  </v-row>
+                </v-container>
+              </v-tab-item>
+
+              <v-tab-item>
+                <v-container fluid class="container">
+                  <v-row>
+                    <v-col cols="12" sm="6">
+                      <InputComponent field="youngApproval" :repository="repositories.organizationRepository" :entry="entry"  />
+                    </v-col>
+                    <v-col cols="12" sm="6">
+                      <InputComponent field="trainingApproval" :repository="repositories.organizationRepository" :entry="entry"  />
+                    </v-col>
+                    <v-col cols="12" sm="6">
+                      <InputComponent field="otherApproval" :repository="repositories.organizationRepository" :entry="entry" />
+                    </v-col>
+                  </v-row>
+                </v-container>
+              </v-tab-item>
+
+              <v-tab-item>
+                <v-container fluid class="container">
+                  <v-row>
+                    <v-col cols="12" sm="6">
+                      <InputComponent field="collectiveAgreement" :repository="repositories.organizationRepository" :entry="entry"  />
+                    </v-col>
+                    <v-col cols="12" sm="6">
+                      <SelectComponent field="opca" :repository="repositories.organizationRepository" :entry="entry"  enumType="organization_opca" />
+                    </v-col>
+                    <v-col cols="12" sm="6">
+                      <InputComponent field="icomNumber" :repository="repositories.organizationRepository" :entry="entry"  />
+                    </v-col>
+                    <v-col cols="12" sm="6">
+                      <InputComponent field="urssafNumber" :repository="repositories.organizationRepository" :entry="entry" />
+                    </v-col>
+                  </v-row>
+                </v-container>
+              </v-tab-item>
+
+              <v-tab-item  v-if="organizationProfile.isInsideNetwork()">
+                <v-container fluid class="container">
+                  <v-row>
+                    <v-col cols="12" sm="6"  v-if="organizationProfile.isFfec()" >
+                      <InputComponent field="budget" :repository="repositories.organizationRepository" :entry="entry"  type="number" />
+                    </v-col>
+                    <v-col cols="12" sm="6" v-if="organizationProfile.isFfec()" >
+                      <CheckboxComponent field="isPedagogicIsPrincipalActivity" :repository="repositories.organizationRepository" :entry="entry"  />
+                    </v-col>
+                    <v-col cols="12" sm="6" v-if="organizationProfile.isFfec()" >
+                      <InputComponent field="pedagogicBudget" :repository="repositories.organizationRepository" :entry="entry"  type="number"/>
+                    </v-col>
+                  </v-row>
+                </v-container>
+              </v-tab-item>
+
+              <v-tab-item>
+                <v-container fluid class="container">
+                  <v-row>
+                    <v-col cols="12" sm="6">
+                      <InputComponent field="twitter" :repository="repositories.organizationRepository" :entry="entry"  />
+                    </v-col>
+                    <v-col cols="12" sm="6">
+                      <InputComponent field="facebook" :repository="repositories.organizationRepository" :entry="entry" />
+                    </v-col>
+                    <v-col cols="12" sm="6">
+                      <InputComponent field="instagram" :repository="repositories.organizationRepository" :entry="entry" />
+                    </v-col>
+                    <v-col cols="12" sm="6">
+                      <CheckboxComponent field="portailVisibility" :repository="repositories.organizationRepository" :entry="entry" />
+                    </v-col>
+                    <v-col cols="12" sm="6">
+                      <InputComponent field="image" :repository="repositories.organizationRepository" :entry="entry" />
+                    </v-col>
+                  </v-row>
+                </v-container>
+              </v-tab-item>
+
+            </v-tabs>
+          </template>
+        </FormComponent>
+      </v-card>
+    </template>
+
+
+    <v-expansion-panels v-model="panel" focusable>
+
+      <!-- Adresses -->
+      <ExpansionPanelComponent :title="$t('address_postal')"  icon="fa-globe-europe">
+        <v-container fluid class="container">
+          <v-row>
+            <v-col cols="12" sm="12">
+              <DataTableComponent
+                :query="repositories.addressRepository.with('addressPostal')"
+                :rootModel="models.Organization"
+                :rootId="id"
+                :model="models.OrganizationAddressPostal"
+                :headers="datatableHeaders.headersAddressPostal"
+              >
+                <template v-slot:item.type="{item}">
+                  {{$t(item.type)}}
+                </template>
+                <template v-slot:item.address="{item}">
+                  {{item['addressPostal.streetAddress']}}
+                  {{item['addressPostal.postalCode']}}
+                  {{item['addressPostal.addressCity']}}
+                </template>
+
+                <template v-slot:sheet.content="{itemId}">
+                  <v-container fluid class="container">
+                    <FormComponent :repository="repositories.addressRepository" :id="itemId" :query="queries.addressQuery()">
+                      <template v-slot:form.input="{entry: addressEntry }">
+                        <v-row>
+                          <v-col cols="12" sm="6">
+                            <SelectComponent field="type" label="address_postal_type" :repository="repositories.addressRepository" :entry="addressEntry" enumType="address_postal_organization" />
+                          </v-col>
+                          <v-col cols="12" sm="6">
+                            <InputComponent field="addressPostal.addressOwner" label="addressOwner" :repository="repositories.addressRepository" :entry="addressEntry" />
+                          </v-col>
+                          <v-col cols="12" sm="6">
+                            <InputComponent field="addressPostal.streetAddress" label="streetAddress" :repository="repositories.addressRepository" :entry="addressEntry" />
+                          </v-col>
+                          <v-col cols="12" sm="6">
+                            <InputComponent field="addressPostal.streetAddressSecond" label="streetAddressSecond" :repository="repositories.addressRepository" :entry="addressEntry" />
+                          </v-col>
+                          <v-col cols="12" sm="6">
+                            <InputComponent field="addressPostal.streetAddressThird" label="streetAddressThird" :repository="repositories.addressRepository" :entry="addressEntry" />
+                          </v-col>
+                          <v-col cols="12" sm="6">
+                            <InputComponent field="addressPostal.postalCode" label="postalCode" :repository="repositories.addressRepository" :entry="addressEntry" />
+                          </v-col>
+                          <v-col cols="12" sm="6">
+                            <InputComponent field="addressPostal.addressCity" label="addressCity" :repository="repositories.addressRepository" :entry="addressEntry" />
+                          </v-col>
+                          <v-col cols="12" sm="6">
+                            <InputComponent field="addressPostal.country" label="country" :repository="repositories.addressRepository" :entry="addressEntry" />
+                          </v-col>
+                        </v-row>
+                      </template>
+                    </FormComponent>
+                  </v-container>
+                </template>
+              </DataTableComponent>
+            </v-col>
+          </v-row>
+        </v-container>
+      </ExpansionPanelComponent>
+
+      <!--  Point de Contact-->
+      <ExpansionPanelComponent :title="$t('contact_point')"  icon="fa-phone">
+        <v-container fluid class="container">
+          <v-row>
+            <v-col cols="12" sm="12">
+              <DataTableComponent
+                :query="repositories.contactPointRepository.query()"
+                :rootModel="models.Organization"
+                :rootId="id"
+                :model="models.ContactPoint"
+                :headers="datatableHeaders.headersContactPoint"
+              >
+                <template v-slot:sheet.content="{itemId }">
+                  <v-container fluid class="container">
+                    <FormComponent :repository="repositories.contactPointRepository" :query="queries.contactPointQuery()" :id="itemId">
+                      <template v-slot:form.input="{entry: contactPointEntry }">
+                        <v-row>
+                          <v-col cols="12" sm="6">
+                            <InputComponent field="email" :repository="repositories.contactPointRepository" :entry="contactPointEntry" />
+                          </v-col>
+                          <v-col cols="12" sm="6">
+                            <InputComponent field="telphone" :repository="repositories.contactPointRepository" :entry="contactPointEntry" />
+                          </v-col>
+                          <v-col cols="12" sm="6">
+                            <InputComponent field="mobilPhone" :repository="repositories.contactPointRepository" :entry="contactPointEntry" />
+                          </v-col>
+                          <v-col cols="12" sm="6">
+                            <InputComponent field="faxNumber" :repository="repositories.contactPointRepository" :entry="contactPointEntry" />
+                          </v-col>
+                        </v-row>
+                      </template>
+                    </FormComponent>
+                  </v-container>
+                </template>
+              </DataTableComponent>
+            </v-col>
+          </v-row>
+        </v-container>
+      </ExpansionPanelComponent>
+
+      <!-- IBAN -->
+      <ExpansionPanelComponent :title="$t('bank_account')"  icon="fa-euro-sign">
+        <v-container fluid class="container">
+          <v-row>
+            <v-col cols="12" sm="12">
+              <DataTableComponent
+                :query="repositories.bankAccountRepository.query()"
+                :rootModel="models.Organization"
+                :rootId="id"
+                :model="models.BankAccount"
+                :headers="datatableHeaders.headersBankAccount"
+              >
+                <template v-slot:sheet.content="{itemId}">
+                  <v-container fluid class="container">
+                    <FormComponent :repository="repositories.bankAccountRepository" :id="itemId" :query="queries.bankAccountQuery()">
+                      <template v-slot:form.input="{entry: bankAccountEntry }">
+                        <v-row>
+                          <v-col cols="12" sm="6">
+                            <InputComponent field="bankName" :repository="repositories.bankAccountRepository" :entry="bankAccountEntry" />
+                          </v-col>
+                          <v-col cols="12" sm="6">
+                            <InputComponent field="bic" :repository="repositories.bankAccountRepository" :entry="bankAccountEntry" />
+                          </v-col>
+                          <v-col cols="12" sm="6">
+                            <InputComponent field="iban" :repository="repositories.bankAccountRepository" :entry="bankAccountEntry" />
+                          </v-col>
+                          <v-col cols="12" sm="6">
+                            <InputComponent field="debitAddress" :repository="repositories.bankAccountRepository" :entry="bankAccountEntry" />
+                          </v-col>
+                          <v-col cols="12" sm="6">
+                            <InputComponent field="holder" :repository="repositories.bankAccountRepository" :entry="bankAccountEntry" />
+                          </v-col>
+                          <v-col cols="12" sm="6">
+                            <CheckboxComponent field="principal" :repository="repositories.bankAccountRepository" :entry="bankAccountEntry" />
+                          </v-col>
+                        </v-row>
+                      </template>
+                    </FormComponent>
+                  </v-container>
+                </template>
+              </DataTableComponent>
+            </v-col>
+          </v-row>
+        </v-container>
+      </ExpansionPanelComponent>
+
+    </v-expansion-panels>
+
+  </ContainerComponent>
+</template>
+
+<script lang="ts">
+  import {defineComponent, useContext, onUnmounted, computed} from '@nuxtjs/composition-api'
+  import {$dataProvider} from "~/services/dataProvider/dataProvider";
+  import {$organizationProfile} from "~/services/profile/organizationProfile";
+  import {Organization} from '@/models/Organization/Organization'
+  import {OrganizationAddressPostal} from "~/models/Organization/OrganizationAddressPostal";
+  import {ContactPoint} from "~/models/Core/ContactPoint";
+  import {BankAccount} from "~/models/Core/BankAccount";
+  import {useRepositoryHelper} from "~/use/store/useRepository";
+  import {Utils} from "~/use/form/utils";
+
+  export default defineComponent({
+    name: 'organization_edit',
+    setup() {
+      const {store, app:{i18n}} = useContext()
+      const organizationProfile = $organizationProfile(store)
+      const id = store.state.profile.organization.id;
+
+      const repositories = getRepositories()
+
+
+      const {siretError, siretErrorMessage, checkSiret} = Utils.useHandleSiret()
+      //onUnmounted( useRepositoryHelper.cleanRepository(repository) )
+
+      return {
+        repositories,
+        queries: getQueries(),
+        id,
+        organizationProfile,
+        models: {Organization, ContactPoint, BankAccount, OrganizationAddressPostal},
+        edit: useRepositoryHelper.editRepository(repositories.organizationRepository),
+        datatableHeaders: getDataTablesHeaders(i18n),
+        rules: getRules(i18n),
+        siretError,
+        siretErrorMessage,
+        checkSiret,
+        panel:null,
+      }
+    },
+
+    async asyncData({store, $rest}){
+      await $dataProvider(store, $rest).getItem(Organization, store.state.profile.organization.id)
+    }
+  })
+
+  function getRules(i18n: any){
+    return {
+      nameRules : [
+        (nameValue:string) => !!nameValue || i18n.t('required'),
+        (nameValue:string) => (nameValue || '').length <= 128 || i18n.t('name_length_rule')
+      ],
+      siretRule : [
+        (siretValue:string) => /^([0-9]{9}|[0-9]{14})$/.test(siretValue) || i18n.t('siret_error')
+      ]
+    }
+  }
+
+  function getDataTablesHeaders(i18n: any) {
+    return {
+      headersContactPoint: [
+        {text: i18n.t('email'), value: 'email'},
+        {text: i18n.t('telphone'), value: 'telphone'},
+        {text: i18n.t('mobilPhone'), value: 'mobilPhone'},
+        {text: i18n.t('actions'), value: 'actions', sortable: false},
+      ],
+      headersBankAccount: [
+        {text: i18n.t('bankName'), value: 'bankName'},
+        {text: i18n.t('iban'), value: 'iban'},
+        {text: i18n.t('bic'), value: 'bic'},
+        {text: i18n.t('actions'), value: 'actions', sortable: false},
+      ],
+      headersAddressPostal: [
+        {text: i18n.t('address_postal_type'), value: 'type'},
+        {text: i18n.t('address'), value: 'address'},
+        {text: i18n.t('actions'), value: 'actions', sortable: false},
+      ]
+    }
+  }
+
+  function getRepositories() {
+    return {
+      organizationRepository: useRepositoryHelper.initRepository(Organization),
+      contactPointRepository: useRepositoryHelper.initRepository(ContactPoint, false),
+      bankAccountRepository: useRepositoryHelper.initRepository(BankAccount, false),
+      addressRepository: useRepositoryHelper.initRepository(OrganizationAddressPostal, false)
+    }
+  }
+
+  function getQueries() {
+    return {
+      organizationQuery: () => getRepositories().organizationRepository.query(),
+      contactPointQuery: () => getRepositories().contactPointRepository.query(),
+      bankAccountQuery: () => getRepositories().bankAccountRepository.query(),
+      addressQuery: () => getRepositories().addressRepository.with('addressPostal')
+    }
+  }
+</script>
+
+<style scoped>
+  .v-tab{
+    justify-content: left;
+    font-size: 12px;
+  }
+  .v-icon.v-icon{
+    font-size: 14px;
+  }
+</style>

+ 1 - 1
plugins/Queries/http.js

@@ -1,11 +1,11 @@
 export default function ({ $http, redirect, store }) {
-
   $http.onRequest(config => {
     config.headers.set('Authorization', `Bearer ${store.state.profile.access.bearer}`)
     config.headers.set('x-accessid', `${store.state.profile.access.accessId}`)
   })
 
   $http.onResponse(async (request, options, response) => {
+
   })
 
   $http.onError((error) => {

+ 3 - 25
plugins/Queries/rest.ts

@@ -1,31 +1,9 @@
 import {Plugin} from '@nuxt/types'
-import  {$hydraParser} from '../../services/utils/hydraParser'
+import {$rest} from "~/services/queries/rest";
 
 const restPlugin: Plugin = (ctx) => {
-
-  const getCollection = async (uri: string) => {
-    const responseQuery = await ctx.$http.get(`${uri}`);
-    return await queries(responseQuery);
-  }
-
-  const getItem = async (uri: string, id: number) => {
-    const query = await ctx.$http.get(`${uri}/${id}`);
-    return await queries(query);
-  }
-
-  const queries = async (responseQuery: any) => {
-    try {
-      let response = await responseQuery.json();
-      return $hydraParser.parse(response);
-    } catch (err) {
-      console.log(err)
-    }
-  }
-
-  ctx.$rest = {
-    'getCollection': getCollection,
-    'getItem': getItem
-  }
+  //Déclare un nouvel accesseur de service via le context Nuxt
+  ctx.$rest = $rest(ctx.$http)
 }
 
 export default restPlugin

+ 3 - 27
plugins/Rights/ability.ts

@@ -1,37 +1,13 @@
 import { Plugin } from '@nuxt/types'
-import { Ability } from '@casl/ability'
-import { $abilitiesUtils } from "~/services/rights/abilitiesUtils";
+import {Ability} from "@casl/ability";
+import {$abilitiesUtils} from "~/services/rights/abilitiesUtils";
 
 /**
  * Au moment de la phase D'init de Nuxt...
  * @param ctx
  */
 const abilityPlugin: Plugin = (ctx) => {
-  //Nécessaire pour que l'update des abilité soit correct après la phase SSR
-  ability.update(ctx.store.state.profile.access.abilities);
-
-  /**
-   * Au moment où l'on effectue un SetProfile via le store Organization, il faut aller récupérer
-   * les différentes abilitées que l'utilisateur peut effectuer. (Tout cela se passe en SSR)
-   */
-  const unsubscribe = ctx.store.subscribeAction({
-    after: (action, state) => {
-      switch (action.type) {
-        case 'profile/organization/setProfile':
-          //On récupère les abilités
-          const abilitiesUtils = $abilitiesUtils(ctx.store, ability)
-          const abilities = abilitiesUtils.getAbilities();
-
-          //On les store puis on update le service ability pour le mettre à jour.
-          ctx.store.commit('profile/access/setAbilities', abilities)
-          ability.update(abilities);
-          //Unsubscribe pour éviter les memory leaks
-          unsubscribe()
-          break;
-      }
-    }
-  })
-
+  $abilitiesUtils(ctx.store, ability).setAbilities()
   //Déclare un nouvel accesseur de service via le context Nuxt
   ctx.$ability = () => {return ability}
 }

+ 0 - 4
plugins/grid.js

@@ -1,4 +0,0 @@
-import Vue from 'vue'
-import { GridPlugin } from '@syncfusion/ej2-vue-grids';
-
-Vue.use(GridPlugin);

+ 60 - 0
services/dataProvider/dataProvider.ts

@@ -0,0 +1,60 @@
+import {Store} from "vuex";
+import {Rest} from "~/services/queries/rest";
+import {Model} from "@/models/Model"
+
+class DataProvider{
+  private store: Store<any>
+  private $rest: Rest
+
+  constructor(store:Store<any>, $rest: Rest) {
+    this.store = store
+    this.$rest = $rest
+  }
+
+  public async getItem(model: typeof Model, id: number){
+    const repository = this.store.$repo(model);
+    const entity = repository.getModel().$entity();
+
+    const response = await this.$rest.getItem(`/api/${entity}`, id)
+    if(response)
+      repository.insert(response);
+  }
+
+  public async getCollection(model: typeof Model){
+    const repository = this.store.$repo(model);
+    const entity = repository.getModel().$entity();
+
+    const response = await this.$rest.getCollection(`/api/${entity}`)
+    if(response)
+      repository.insert(response);
+  }
+
+  public async getSubResourceCollection(root_model: typeof Model, root_id: number, model: typeof Model){
+    const root_repository = this.store.$repo(root_model);
+    const root_entity = root_repository.getModel().$entity();
+
+    const repository = this.store.$repo(model);
+    const entity = repository.getModel().$entity();
+
+    const response = await this.$rest.getCollection(`/api/${root_entity}/${root_id}/${entity}`)
+    if(response){
+      repository.insert(response)
+      return repository.all();
+    }
+    return [];
+  }
+
+  public async getSubResourceItem(root_model: typeof Model, root_id: number, model: typeof Model, id: number) {
+    const root_repository = this.store.$repo(root_model);
+    const root_entity = root_repository.getModel().$entity();
+
+    const repository = this.store.$repo(model);
+    const entity = repository.getModel().$entity();
+
+    const response = await this.$rest.getItem(`/api/${root_entity}/${root_id}/${entity}`, id)
+    if(response)
+      repository.insert(response);
+  }
+}
+
+export const $dataProvider = (store:Store<any>, $rest:Rest) => new DataProvider(store, $rest);

+ 40 - 0
services/dataProvider/enumDataProvider.ts

@@ -0,0 +1,40 @@
+import {EnumChoice, EnumChoices} from "~/types/types";
+import * as _ from "lodash";
+import {Rest} from "~/services/queries/rest";
+
+class EnumDataProvider{
+  private $rest: Rest
+  private i18n:any
+
+  constructor($rest: Rest, i18n:any) {
+    this.$rest = $rest
+    this.i18n = i18n
+  }
+
+  public async get(type: string){
+    const enums:EnumChoices = []
+    const response = await this.$rest.getCollection(`/api/enum/${type}`)
+    if(response){
+      _.each(response['items'], (item, key) =>{
+        const entry:EnumChoice = {
+          value: key,
+          label: this.i18n.t(item)
+        };
+        enums.push(entry)
+      })
+    }
+    return this.sortEnum(enums)
+  }
+
+  public sortEnum(enums:EnumChoices){
+    return enums.sort( (a, b) => {
+      if (a.label > b.label)
+        return 1;
+      if (a.label < b.label)
+        return -1;
+      return 0;
+    });
+  }
+}
+
+export const $enumDataProvider = ($rest:Rest, i18n:any) => new EnumDataProvider($rest,i18n);

+ 44 - 13
services/profile/organizationProfile.ts

@@ -21,13 +21,43 @@ class OrganizationProfile{
    * @param {Array<string>} modules Modules à tester
    * @return {boolean}
    */
-  hasModule(modules:Array<string>) {
+  hasModule(modules:Array<string>):boolean {
     let hasModule = false;
     modules.map((module) => {
       if (this.organizationProfile.modules && this.organizationProfile.modules.indexOf(module) > -1)
-        hasModule = true;
+        hasModule = true
     });
-    return hasModule;
+    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 {
+    const networks = this.organizationProfile.networks.filter( (network:string) => {
+      return network == process.env.cmf_network
+    });
+    return networks.length > 0;
+  }
+
+  /**
+   * L'organization fait-elle partie du réseau FFEC ?
+   * @return {boolean}
+   */
+  isFfec():boolean {
+    const networks = this.organizationProfile.networks.filter( (network:string) => {
+      return network == process.env.ffec_network
+    });
+    return networks.length > 0;
   }
 
   /**
@@ -35,7 +65,7 @@ class OrganizationProfile{
    * @return {boolean}
    */
   isSchool():boolean {
-    return this.isSchoolProduct() || this.isSchoolPremiumProduct();
+    return this.isSchoolProduct() || this.isSchoolPremiumProduct()
   }
 
   /**
@@ -43,14 +73,14 @@ class OrganizationProfile{
    * @return {boolean}
    */
   isArtist():boolean {
-    return this.isArtistProduct() || this.isArtistPremiumProduct();
+    return this.isArtistProduct() || this.isArtistPremiumProduct()
   }
 
   /**
    * L'organization possède t'elle un produit school
    * @return {boolean}
    */
-  isSchoolProduct() {
+  isSchoolProduct():boolean {
     return this.organizationProfile.product === process.env.school_product
   }
 
@@ -58,7 +88,7 @@ class OrganizationProfile{
    * L'organization possède t'elle un produit school premium
    * @return {boolean}
    */
-  isSchoolPremiumProduct() {
+  isSchoolPremiumProduct():boolean {
     return this.organizationProfile.product === process.env.school_premium_product
   }
 
@@ -66,7 +96,7 @@ class OrganizationProfile{
    * L'organization possède t'elle un produit premium
    * @return {boolean}
    */
-  isArtistProduct() {
+  isArtistProduct():boolean {
     return this.organizationProfile.product === process.env.artist_product
   }
 
@@ -74,7 +104,7 @@ class OrganizationProfile{
    * L'organization possède t'elle un produit artiste premium
    * @return {boolean}
    */
-  isArtistPremiumProduct() {
+  isArtistPremiumProduct():boolean {
     return this.organizationProfile.product === process.env.artist_premium_product
   }
 
@@ -82,15 +112,15 @@ class OrganizationProfile{
    * L'organization possède t'elle un produit manager
    * @return {boolean}
    */
-  isManagerProduct() {
+  isManagerProduct():boolean {
     return this.organizationProfile.product === process.env.manager_product
   }
 
   /**
    * L'organization possède t'elledes enfants
-   * @return {boolean}
+   * @return {boolean|null}
    */
-  isOrganizationWithChildren(){
+  isOrganizationWithChildren():any{
     return this.organizationProfile.hasChildren;
   }
 
@@ -104,7 +134,8 @@ class OrganizationProfile{
       isSchool: this.isSchool.bind(this),
       isArtist: this.isArtist.bind(this),
       isManagerProduct: this.isManagerProduct.bind(this),
-      isOrganizationWithChildren: this.isOrganizationWithChildren.bind(this)
+      isOrganizationWithChildren: this.isOrganizationWithChildren.bind(this),
+      isCmf: this.isCmf.bind(this)
     }
   }
 }

+ 29 - 0
services/queries/rest.ts

@@ -0,0 +1,29 @@
+import  {$hydraParser} from '../../services/utils/hydraParser'
+import {NuxtHTTPInstance} from "@nuxt/http";
+
+export class Rest{
+  private $http: NuxtHTTPInstance
+
+  constructor($http: NuxtHTTPInstance) {
+    this.$http = $http
+  }
+  public getCollection = async (uri: string) => {
+    const responseQuery = await this.$http.get(`${uri}`);
+    return await this.queries(responseQuery);
+  }
+
+  public getItem = async (uri: string, key: number|string) => {
+    const query = await this.$http.get(`${uri}/${key}`);
+    return await this.queries(query);
+  }
+
+  private queries = async (responseQuery: any) => {
+    try {
+      let response = await responseQuery.json();
+      return $hydraParser.parse(response);
+    } catch (err) {
+      console.log(err)
+    }
+  }
+}
+export const $rest = ($http: NuxtHTTPInstance) => new Rest($http)

+ 30 - 1
services/rights/abilitiesUtils.ts

@@ -1,7 +1,7 @@
 import {$accessProfile} from "@/services/profile/accessProfile"
 import {$organizationProfile} from "@/services/profile/organizationProfile"
 import {$roleUtils} from "~/services/rights/roleUtils";
-import {AbilitiesType, AccessStore, AnyJson, AnyStore} from "~/types/types";
+import {AbilitiesType, AnyJson, AnyStore} from "~/types/types";
 import {Ability} from "@casl/ability";
 import {$yamlParser} from "~/services/utils/yamlParser";
 import * as _ from "lodash";
@@ -34,6 +34,35 @@ class AbilitiesUtils {
     }
   }
 
+  /**
+   * Set les abilities de l'utilisateur à chaque fois qu'on update son profile
+   */
+  setAbilities(){
+    //Nécessaire pour que l'update des abilité soit correct après la phase SSR
+    this.$ability.update(this.$store.state.profile.access.abilities);
+
+    /**
+     * Au moment où l'on effectue un SetProfile via le store Organization, il faut aller récupérer
+     * les différentes abilitées que l'utilisateur peut effectuer. (Tout cela se passe en SSR)
+     */
+    const unsubscribe = this.$store.subscribeAction({
+      after: (action, state) => {
+        switch (action.type) {
+          case 'profile/organization/setProfile':
+            //On récupère les abilités
+            const abilities = this.getAbilities();
+
+            //On les store puis on update le service ability pour le mettre à jour.
+            this.$store.commit('profile/access/setAbilities', abilities)
+            this.$ability.update(abilities);
+            //Unsubscribe pour éviter les memory leaks
+            unsubscribe()
+            break;
+        }
+      }
+    })
+  }
+
   /**
    * Récupération de l'ensemble des abilities quelles soient par Roles ou par Config.
    * @return {Array<AbilitiesType>}

+ 3 - 0
services/utils/objectProperties.ts

@@ -7,6 +7,9 @@ import {AnyJson} from "~/types/types";
 
 class ObjectProperties {
   /**
+   * What do you think about an option on find method to flatten the response, and an other one on update to nest the data before updating ?
+      Example :
+
    * Flatten un objet nested en un objet avec un seul niveau avec des noms de propriétés transformées comme cela 'foo.bar'
    * L'objet passé en paramètre reste inchangé car il est cloné
    * @example  cloneAndFlatten({ a: 1, b: { c: 2 }, d: { e: 3, f: { g: 4, h: 5 } }, i: { j: 6 } }, ['i']) => { a: 1, 'b.c': 2, 'd.e': 3, 'd.f.g': 4, 'd.f.h': 5, i: { j: 6 } } }

+ 17 - 1
store/profile/access.ts

@@ -16,7 +16,11 @@ export const state = () => ({
   isStudent: false,
   isTeacher: false,
   isMember: false,
-  isOther: false
+  isOther: false,
+  hasLateralMenu: true,
+  hasConfigurationMenu: true,
+  hasAccessesMenu: true,
+  hasFamilyMenu: true
 })
 
 export const mutations = {
@@ -67,6 +71,18 @@ export const mutations = {
   },
   setIsOther(state:accessState, isRole:boolean){
     state.isOther = isRole
+  },
+  setHasLateralMenu(state:accessState, hasLateralMenu:boolean){
+    state.hasLateralMenu = hasLateralMenu
+  },
+  setHasConfigurationMenu(state:accessState, hasConfigurationMenu:boolean){
+    state.hasConfigurationMenu = hasConfigurationMenu
+  },
+  setHasAccessesMenu(state:accessState, hasAccessesMenu:boolean){
+    state.hasAccessesMenu = hasAccessesMenu
+  },
+  setHasFamilyMenu(state:accessState, hasFamilyMenu:boolean){
+    state.hasFamilyMenu = hasFamilyMenu
   }
 }
 

+ 13 - 1
store/profile/organization.ts

@@ -2,16 +2,21 @@ import {organizationState} from "~/types/types";
 import * as _ from "lodash";
 
 export const state = () => ({
+  id: null,
   name: '',
   product: '',
   modules: [],
   hasChildren: false,
+  networks: [],
   website: '',
   subDomain: '',
   parents: []
 })
 
 export const mutations = {
+  setId(state:organizationState, id:number){
+    state.id = id
+  },
   setName(state:organizationState, name:string){
     state.name = name
   },
@@ -24,6 +29,9 @@ export const mutations = {
   setHasChildren(state:organizationState, hasChildren:boolean) {
     state.hasChildren = hasChildren
   },
+  setNetworks(state:organizationState, networks:Array<string>) {
+    state.networks = networks
+  },
   setParents(state:organizationState, parents:Array<organizationState>) {
     state.parents = parents
   },
@@ -40,19 +48,23 @@ export const mutations = {
 
 export const actions = {
   setProfile(context:any, profile:any){
+    context.commit('setId', profile.id)
     context.commit('setName', profile.name)
     context.commit('setProduct', profile.product)
     context.commit('setWebsite', profile.website)
     context.commit('setSubDomain', profile.subDomain)
     context.commit('setModules', profile.modules)
     context.commit('setHasChildren', profile.hasChildren)
+    context.commit('setNetworks', profile.networks)
 
     _.each(profile.parents, parent => {
       const p:organizationState = {
+        id: parent.id,
         name: parent.name,
         website: parent.website,
         subDomain: parent.subDomain,
-        parents: []
+        parents: [],
+        networks: [],
       }
       context.commit('addParent', p)
     });

+ 5 - 5
test/use/template/menu.spec.js → test/use/layout/menu.spec.js

@@ -1,20 +1,20 @@
-import BaseMenu from "~/use/template/Menus/baseMenu";
+import BaseMenu from "~/use/layout/Menus/baseMenu";
 
 test('test constructMenu', () => {
-  const menuWithoutChildren = new BaseMenu({'baseURL_adminLegacy': 'base_url'}).constructMenu('icon', 'children', '/url', false)
+  const menuWithoutChildren = new BaseMenu({'baseURL_adminLegacy': 'base_url'}).constructMenu('children',  'icon', '/url', false)
   expect(menuWithoutChildren).toStrictEqual({
-    "icon": "icon",
     "title": "children",
+    "icon": "icon",
     "to": "/url",
     "isExternalLink": false
   });
 
-  const menuWithChildren = new BaseMenu({'baseURL_adminLegacy': 'base_url'}).constructMenu('icon', 'parent', undefined, undefined, [menuWithoutChildren])
+  const menuWithChildren = new BaseMenu({'baseURL_adminLegacy': 'base_url'}).constructMenu('parent', 'icon', undefined, undefined, [menuWithoutChildren])
   expect(menuWithChildren).toStrictEqual({
     "children": [
       {
-        "icon": "icon",
         "title": "children",
+        "icon": "icon",
         "to": "/url",
         "isExternalLink": false
       }

+ 1 - 0
tsconfig.json

@@ -28,6 +28,7 @@
       "@nuxt/types",
       "@nuxt/http",
       "@nuxtjs/vuetify",
+      "@nuxtjs/moment",
       "nuxt-i18n"
     ]
   },

+ 23 - 5
types/types.d.ts

@@ -1,6 +1,8 @@
-import {Store} from "vuex";
+import {
+  Store
+} from "vuex";
 import {Ability} from "@casl/ability";
-interface ItemsMenu extends Array<ItemMenu> {}
+import {Rest} from "~/services/queries/rest";
 
 /**
  * Upgrade du @nuxt/types pour TypeScript
@@ -8,17 +10,18 @@ interface ItemsMenu extends Array<ItemMenu> {}
 declare module '@nuxt/types' {
   interface Context {
     $ability(): Ability,
-    $rest: AnyJson
+    $rest: Rest
   }
 }
 
 interface ItemMenu {
-  icon: string,
   title: string,
+  icon?: string,
   to?: string,
   children?: ItemsMenu,
   isExternalLink?: boolean,
 }
+interface ItemsMenu extends Array<ItemMenu> {}
 
 interface AbilitiesType {
   action: 'display' | 'read' | 'manage',
@@ -49,15 +52,21 @@ interface accessState {
   isStudent: boolean,
   isTeacher: boolean,
   isMember: boolean,
-  isOther: boolean
+  isOther: boolean,
+  hasLateralMenu: boolean,
+  hasConfigurationMenu: boolean,
+  hasAccessesMenu: boolean,
+  hasFamilyMenu: boolean
 }
 interface AccessStore extends Store<{profile:{access:accessState}}> {}
 
 interface organizationState {
+  id: number,
   name: string,
   product?: string,
   modules?: Array<string>,
   hasChildren?: boolean,
+  networks: Array<string>,
   website?: string,
   subDomain?: string,
   parents: Array<organizationState>,
@@ -66,3 +75,12 @@ interface OrganizationStore extends Store<{profile:{organization:organizationSta
 
 interface AnyJson extends Record<string, any> {}
 interface AnyStore extends Store<any> {}
+
+interface EnumChoice {
+  value: string,
+  label: string
+}
+interface EnumChoices extends Array<EnumChoice> {}
+
+import {Query, Repository} from "@vuex-orm/core";
+export type RepositoryOrQuery<R extends Repository = Repository, Q extends Query = Query> = R | Q;

+ 21 - 0
use/form/useFormInputSetup.ts

@@ -0,0 +1,21 @@
+import {ref, useContext, computed} from '@nuxtjs/composition-api'
+import {$objectProperties} from "~/services/utils/objectProperties";
+import {AnyJson} from "~/types/types";
+import {ModelsOrRepositories} from "@vuex-orm/core";
+
+class useFormInputSetup{
+  public getData(repository: ModelsOrRepositories, id:number, field:string){
+    const entry = $objectProperties.cloneAndFlatten(repository.find(id) as AnyJson);
+    const data = ref(entry[field])
+
+    const readOnly = false;
+
+    return {
+      data,
+      entry,
+      readOnly
+    }
+  }
+}
+
+export const useFormInputSetupGetData = (repository: ModelsOrRepositories, id:number, field:string) => new useFormInputSetup().getData(repository, id, field)

+ 26 - 0
use/form/utils.ts

@@ -0,0 +1,26 @@
+import {ref, useContext} from "@nuxtjs/composition-api";
+
+export class Utils{
+  public static useHandleSiret(){
+    const {app:{i18n}, $rest} = useContext()
+    const siretError = ref(false)
+    const siretErrorMessage = ref('')
+
+    const checkSiret = async (siret:string) => {
+      const response = await $rest.getItem(`/api/siret-checking`, siret)
+      if(response){
+        siretError.value = !response.isCorrect
+        siretErrorMessage.value = response.isCorrect ? '' : i18n.t('siret_error') as string
+      }else{
+        siretError.value = false
+        siretErrorMessage.value = ''
+      }
+    }
+
+    return {
+      siretError,
+      siretErrorMessage,
+      checkSiret
+    }
+  }
+}

+ 8 - 8
use/template/Menus/accessMenu.ts → use/layout/Menus/accessMenu.ts

@@ -1,6 +1,6 @@
 import {ItemMenu, ItemsMenu} from "~/types/types";
 import {$organizationProfile} from "~/services/profile/organizationProfile";
-import BaseMenu from "~/use/template/Menus/baseMenu";
+import BaseMenu from "~/use/layout/Menus/baseMenu";
 
 class AccessMenu extends BaseMenu{
   private $ability:any;
@@ -22,33 +22,33 @@ class AccessMenu extends BaseMenu{
     if (this.$ability().can('display', 'accesses_page')) {
       const organization = $organizationProfile(this.$store)
       let to = organization.isSchool() ? `/students/list/` : `/adherent/list/`
-      children.push(this.constructMenu('fa-user', 'person', to, true))
+      children.push(this.constructMenu('person', 'fa-user',  to, true))
     }
 
     if (this.$ability().can('display', 'student_registration_page')) {
-      children.push(this.constructMenu('fa-users', 'family_view', '/student_registration/new', true))
+      children.push(this.constructMenu('family_view', 'fa-users', '/student_registration/new', true))
     }
 
     if (this.$ability().can('display', 'education_student_next_year_page')) {
-      children.push(this.constructMenu('fa-list-alt', 'education_student_next_year', '/education_student_next_year/list/', true))
+      children.push(this.constructMenu('education_student_next_year', 'fa-list-alt', '/education_student_next_year/list/', true))
     }
 
     if (this.$ability().can('display', 'commissions_page')) {
-      children.push(this.constructMenu('fa-street-view', 'commissions', '/commissions/list/', true))
+      children.push(this.constructMenu('commissions', 'fa-street-view', '/commissions/list/', true))
     }
 
     if (this.$ability().can('display', 'network_children_page')) {
-      children.push(this.constructMenu('fa-sitemap', 'network', 'networks/list/', true))
+      children.push(this.constructMenu('network', 'fa-sitemap', 'networks/list/', true))
     }
 
     if (this.$ability().can('display', 'network_parents_page')) {
-      children.push(this.constructMenu('fa-sitemap', 'my_network', '/network_artist_schools/list/', true))
+      children.push(this.constructMenu('my_network', 'fa-sitemap', '/network_artist_schools/list/', true))
     }
 
     if(children.length === 1){
       return children[0];
     }
-    return children.length > 0 ? this.constructMenu('fa-address-book', 'address_book', undefined, undefined, children) : null;
+    return children.length > 0 ? this.constructMenu('address_book', 'fa-address-book', undefined, undefined, children) : null;
   }
 }
 

+ 29 - 0
use/layout/Menus/accountMenu.ts

@@ -0,0 +1,29 @@
+import {ItemMenu, ItemsMenu} from "~/types/types";
+import BaseMenu from "~/use/layout/Menus/baseMenu";
+
+class AccountMenu extends BaseMenu{
+  private $ability:any;
+  private $store:any;
+
+  constructor($config:any, $ability:any, $store: any) {
+    super($config)
+    this.$ability = $ability
+    this.$store = $store
+  }
+
+  /**
+   * Construit le menu Header Configuration ou null si aucune page accessible
+   * @return {ItemMenu | null}
+   */
+  getHeaderMenu():ItemMenu | null {
+    const children:ItemsMenu = [];
+
+    if (this.$ability().can('display', 'organization_page')) {
+      children.push(this.constructMenu('organization_page', undefined,'/organization/edit'))
+    }
+
+    return children.length > 0 ? this.constructMenu('configuration', 'fa-user', undefined, undefined, children) : null;
+  }
+}
+
+export const getAccountMenu = ($config:any, $ability:any, $store:any) => new AccountMenu($config, $ability, $store).getHeaderMenu()

+ 54 - 0
use/layout/Menus/admin2iosMenu.ts

@@ -0,0 +1,54 @@
+import {ItemMenu, ItemsMenu} from "~/types/types";
+import BaseMenu from "~/use/layout/Menus/baseMenu";
+
+class Admin2iosMenu extends BaseMenu{
+  private $ability:any;
+
+  constructor($config:any, $ability:any) {
+    super($config)
+    this.$ability = $ability
+  }
+
+  /**
+   * Construit le menu Administration 2ios ou null si aucune page accessible
+   * @return {ItemMenu | null}
+   */
+  getMenu():ItemMenu | null {
+    const children:ItemsMenu = [];
+
+    if (this.$ability().can('display', 'all_accesses_page')) {
+      children.push(this.constructMenu('all_accesses', 'fa-users',  '/all_accesses/list/', true))
+    }
+
+    if (this.$ability().can('display', 'all_organizations_page')) {
+      children.push(this.constructMenu('all_organizations', 'fa-building',  '/organization_params/list/', true))
+    }
+
+    if (this.$ability().can('display', 'tips_page')) {
+      children.push(this.constructMenu('tips', 'fa-info-circle',  '/tips/list/', true))
+    }
+
+    if (this.$ability().can('display', 'dgv_page')) {
+      children.push(this.constructMenu('dgv', 'fa-house-damage',  '/admin2ios/dgv', true))
+    }
+
+    if (this.$ability().can('display', 'cmf_cotisation_page')) {
+      children.push(this.constructMenu('cmf_cotisation', 'fa-info-circle',  '/admin2ios/cotisationcmf', true))
+    }
+
+    if (this.$ability().can('display', 'right_page')) {
+      children.push(this.constructMenu('right_menu', 'fa-balance-scale-right',  '/admin2ios/right', true))
+    }
+
+    if (this.$ability().can('display', 'tree_page')) {
+      children.push(this.constructMenu('tree_menu', 'fa-sitemap',  '/admin2ios/tree', true))
+    }
+
+    if(children.length === 1){
+      return children[0];
+    }
+    return children.length > 0 ? this.constructMenu('admin2ios', 'fa-sitemap', undefined, undefined, children) : null;
+  }
+}
+
+export const getAdmin2iosMenu = ($config:any, $ability:any) => new Admin2iosMenu($config, $ability).getMenu()

+ 4 - 4
use/template/Menus/agendaMenu.ts → use/layout/Menus/agendaMenu.ts

@@ -1,5 +1,5 @@
 import {ItemMenu, ItemsMenu} from "~/types/types";
-import BaseMenu from "~/use/template/Menus/baseMenu";
+import BaseMenu from "~/use/layout/Menus/baseMenu";
 
 class AgendaMenu extends BaseMenu{
   private $ability:any;
@@ -17,17 +17,17 @@ class AgendaMenu extends BaseMenu{
     const children:ItemsMenu = [];
 
     if (this.$ability().can('display', 'agenda_page')) {
-      children.push(this.constructMenu('fa-calendar-alt', 'schedule', '/calendar', true))
+      children.push(this.constructMenu('schedule', 'fa-calendar-alt',  '/calendar', true))
     }
 
     if (this.$ability().can('display', 'attendance_page')) {
-      children.push(this.constructMenu('fa-calendar-check', 'attendances', '/attendances/list/', true))
+      children.push(this.constructMenu('attendances', 'fa-calendar-check',  '/attendances/list/', true))
     }
 
     if(children.length === 1){
       return children[0];
     }
-    return children.length > 0 ? this.constructMenu('fa-calendar-alt', 'schedule', undefined, undefined, children) : null;
+    return children.length > 0 ? this.constructMenu('schedule', 'fa-calendar-alt',  undefined, undefined, children) : null;
   }
 }
 

+ 2 - 2
use/template/Menus/baseMenu.ts → use/layout/Menus/baseMenu.ts

@@ -17,10 +17,10 @@ class BaseMenu{
    * @param {boolean} isExternalLink est-ce un lien renvoyant vers l'extérieur?
    * @return {ItemMenu}
    */
-  constructMenu(icon: string, title: string, link?: string, isOldLink?: boolean, children?: Array<ItemMenu>, isExternalLink?: boolean): ItemMenu{
+  constructMenu(title: string, icon?: string, link?: string, isOldLink?: boolean, children?: Array<ItemMenu>, isExternalLink?: boolean): ItemMenu{
     return children ? {
-      icon: icon,
       title: title,
+      icon: icon,
       children: children,
     } : {
       icon: icon,

+ 10 - 10
use/template/Menus/billingMenu.ts → use/layout/Menus/billingMenu.ts

@@ -1,5 +1,5 @@
 import {ItemMenu, ItemsMenu} from "~/types/types";
-import BaseMenu from "~/use/template/Menus/baseMenu";
+import BaseMenu from "~/use/layout/Menus/baseMenu";
 
 class BillingMenu extends BaseMenu{
   private $ability:any;
@@ -17,41 +17,41 @@ class BillingMenu extends BaseMenu{
     const children:ItemsMenu = [];
 
     if (this.$ability().can('display', 'billing_product_page')) {
-      children.push(this.constructMenu('fa-cube', 'billing_product', '/intangibles/list/', true))
+      children.push(this.constructMenu('billing_product', 'fa-cube',  '/intangibles/list/', true))
     }
 
     if (this.$ability().can('display', 'billing_products_by_student_page')) {
-      children.push(this.constructMenu('fa-cubes', 'billing_products_by_student', '/access_intangibles/list/', true))
+      children.push(this.constructMenu('billing_products_by_student', 'fa-cubes',  '/access_intangibles/list/', true))
     }
 
     if (this.$ability().can('display', 'billing_edition_page')) {
-      children.push(this.constructMenu('fa-copy', 'billing_edition', '/billing_edition', true))
+      children.push(this.constructMenu('billing_edition', 'fa-copy',  '/billing_edition', true))
     }
 
     if (this.$ability().can('display', 'billing_accounting_page')) {
-      children.push(this.constructMenu('fa-file-alt', 'billing_accounting', '/bill_accountings/list/', true))
+      children.push(this.constructMenu('billing_accounting', 'fa-file-alt',  '/bill_accountings/list/', true))
     }
 
     if (this.$ability().can('display', 'billing_payment_list_page')) {
-      children.push(this.constructMenu('fa-credit-card', 'billing_payment_list', '/bill_payments_list/list/', true))
+      children.push(this.constructMenu('billing_payment_list', 'fa-credit-card',  '/bill_payments_list/list/', true))
     }
 
     if (this.$ability().can('display', 'pes_page')) {
-      children.push(this.constructMenu('fa-align-justify', 'pes_export', '/pes/list/', true))
+      children.push(this.constructMenu('pes_export', 'fa-align-justify',  '/pes/list/', true))
     }
 
     if (this.$ability().can('display', 'berger_levrault_page')) {
-      children.push(this.constructMenu('fa-align-justify', 'berger_levrault_export', '/berger_levraults/list/', true))
+      children.push(this.constructMenu('berger_levrault_export', 'fa-align-justify',  '/berger_levraults/list/', true))
     }
 
     if (this.$ability().can('display', 'jvs_page')) {
-      children.push(this.constructMenu('fa-align-justify', 'jvs_export', '/jvs/list/', true))
+      children.push(this.constructMenu('jvs_export', 'fa-align-justify',  '/jvs/list/', true))
     }
 
     if(children.length === 1){
       return children[0];
     }
-    return children.length > 0 ? this.constructMenu('fa-euro-sign', 'billing', undefined, undefined, children) : null;
+    return children.length > 0 ? this.constructMenu('billing', 'fa-euro-sign',  undefined, undefined, children) : null;
   }
 }
 

+ 5 - 5
use/template/Menus/communicationMenu.ts → use/layout/Menus/communicationMenu.ts

@@ -1,5 +1,5 @@
 import {ItemMenu, ItemsMenu} from "~/types/types";
-import BaseMenu from "~/use/template/Menus/baseMenu";
+import BaseMenu from "~/use/layout/Menus/baseMenu";
 
 class CommunicationMenu extends BaseMenu{
   private $ability:any;
@@ -17,21 +17,21 @@ class CommunicationMenu extends BaseMenu{
     const children:ItemsMenu = [];
 
     if (this.$ability().can('display', 'inbox_page')) {
-      children.push(this.constructMenu('fa-inbox', 'inbox', '/messages/list/', true))
+      children.push(this.constructMenu('inbox', 'fa-inbox',  '/messages/list/', true))
     }
 
     if (this.$ability().can('display', 'message_send_page')) {
-      children.push(this.constructMenu('fa-paper-plane', 'message_send', '/messagessends/list/', true))
+      children.push(this.constructMenu('message_send', 'fa-paper-plane',  '/messagessends/list/', true))
     }
 
     if (this.$ability().can('display', 'message_templates_page')) {
-      children.push(this.constructMenu('fa-edit', 'message_templates', '/templates/list/', true))
+      children.push(this.constructMenu('message_templates', 'fa-edit',  '/templates/list/', true))
     }
 
     if(children.length === 1){
       return children[0];
     }
-    return children.length > 0 ? this.constructMenu('fa-comments', 'communication', undefined, undefined, children) : null;
+    return children.length > 0 ? this.constructMenu('communication', 'fa-comments',  undefined, undefined, children) : null;
   }
 }
 

+ 73 - 0
use/layout/Menus/configurationMenu.ts

@@ -0,0 +1,73 @@
+import {ItemMenu, ItemsMenu} from "~/types/types";
+import BaseMenu from "~/use/layout/Menus/baseMenu";
+
+class ConfigurationMenu extends BaseMenu{
+  private $ability:any;
+  private $store:any;
+
+  constructor($config:any, $ability:any, $store: any) {
+    super($config)
+    this.$ability = $ability
+    this.$store = $store
+  }
+
+  /**
+   * Construit le menu Header Configuration ou null si aucune page accessible
+   * @return {ItemMenu | null}
+   */
+  getHeaderMenu():ItemMenu | null {
+    const children:ItemsMenu = [];
+
+    if (this.$ability().can('display', 'organization_page')) {
+      children.push(this.constructMenu('organization_page', undefined,'/organization/edit'))
+    }
+
+    if (this.$ability().can('display', 'cmf_licence_page')) {
+      children.push(this.constructMenu('cmf_licence_generate', undefined,'/attendances/list/', true))
+    }
+
+    if (this.$ability().can('display', 'parameters_page')) {
+      children.push(this.constructMenu('parameters', undefined,'/configuration/parameters'))
+    }
+
+    if (this.$ability().can('display', 'place_page')) {
+      children.push(this.constructMenu('place', undefined,'/places/list/', true))
+    }
+
+    if (this.$ability().can('display', 'education_page')) {
+      children.push(this.constructMenu('education', undefined,'/educations/list/', true))
+    }
+
+    if (this.$ability().can('display', 'tag_page')) {
+      children.push(this.constructMenu('tag', undefined,'/taggs/list/', true))
+    }
+
+    if (this.$ability().can('display', 'activities_page')) {
+      children.push(this.constructMenu('activities', undefined,'/activities/list/', true))
+    }
+
+    if (this.$ability().can('display', 'billing_settings_page')) {
+      children.push(this.constructMenu('billing_settings', undefined,'/billing_settings/' + this.$store.state.profile.organization.id, true))
+    }
+
+    if (this.$ability().can('display', 'online_registration_settings_page')) {
+      children.push(this.constructMenu('online_registration_settings', undefined,'/online_registration_settings/' + this.$store.state.profile.organization.id, true))
+    }
+
+    if (this.$ability().can('display', 'transition_next_year_page')) {
+      children.push(this.constructMenu('transition_next_year', undefined,'/attendances/list/', true))
+    }
+
+    if (this.$ability().can('display', 'course_duplication_page')) {
+      children.push(this.constructMenu('course_duplication', undefined,'/duplicate_courses/', true))
+    }
+
+    if (this.$ability().can('display', 'import_page')) {
+      children.push(this.constructMenu('import', undefined,'/import/all/', true))
+    }
+
+    return children.length > 0 ? this.constructMenu('configuration', 'fa-cogs', undefined, undefined, children) : null;
+  }
+}
+
+export const getConfigurationMenu = ($config:any, $ability:any, $store:any) => new ConfigurationMenu($config, $ability, $store).getHeaderMenu()

+ 94 - 0
use/layout/Menus/cotisationsMenu.ts

@@ -0,0 +1,94 @@
+import {ItemMenu, ItemsMenu} from "~/types/types";
+import BaseMenu from "~/use/layout/Menus/baseMenu";
+
+class CotisationsMenu extends BaseMenu{
+  private $ability:any;
+
+  constructor($config:any, $ability:any) {
+    super($config)
+    this.$ability = $ability
+  }
+
+  /**
+   * Construit le menu Cotisations ou null si aucune page accessible
+   * @return {ItemMenu | null}
+   */
+  getMenu():ItemMenu | null {
+    const children:ItemsMenu = [];
+
+    if (this.$ability().can('display', 'rate_cotisation_page')) {
+      children.push(this.constructMenu('rate_cotisation', 'fa-euro-sign',  '/cotisation/rate', true))
+    }
+
+    if (this.$ability().can('display', 'parameters_cotisation_page')) {
+      children.push(this.constructMenu('parameters_cotisation', 'fa-euro-sign',  '/cotisation/parameter', true))
+    }
+
+    if (this.$ability().can('display', 'send_cotisation_page')) {
+      children.push(this.constructMenu('send_cotisation', 'fa-euro-sign',  '/cotisation/send', true))
+    }
+
+    if (this.$ability().can('display', 'state_cotisation_page')) {
+      children.push(this.constructMenu('state_cotisation', 'fa-euro-sign',  '/cotisation/state', true))
+    }
+
+    if (this.$ability().can('display', 'pay_cotisation_page')) {
+      children.push(this.constructMenu('pay_cotisation', 'fa-euro-sign',  '/cotisation/pay', true))
+    }
+
+    if (this.$ability().can('display', 'check_cotisation_page')) {
+      children.push(this.constructMenu('check_cotisation', 'fa-euro-sign',  '/cotisation/check', true))
+    }
+
+    if (this.$ability().can('display', 'ledger_cotisation_page')) {
+      children.push(this.constructMenu('ledger_cotisation', 'fa-euro-sign',  '/cotisation/ledger', true))
+    }
+
+    if (this.$ability().can('display', 'magazine_cotisation_page')) {
+      children.push(this.constructMenu('magazine_cotisation', 'fa-euro-sign',  '/cotisation/magazine', true))
+    }
+
+    if (this.$ability().can('display', 'ventilated_cotisation_page')) {
+      children.push(this.constructMenu('ventilated_cotisation', 'fa-euro-sign',  '/cotisation/ventilated', true))
+    }
+
+    if (this.$ability().can('display', 'pay_erase_cotisation_page')) {
+      children.push(this.constructMenu('pay_erase_cotisation', 'fa-euro-sign',  '/cotisation/payerase', true))
+    }
+
+    if (this.$ability().can('display', 'resume_cotisation_page')) {
+      children.push(this.constructMenu('resume_cotisation', 'fa-euro-sign',  '/cotisation/resume', true))
+    }
+
+    if (this.$ability().can('display', 'history_cotisation_page')) {
+      children.push(this.constructMenu('history_cotisation', 'fa-euro-sign',  '/cotisation/history', true))
+    }
+
+    if (this.$ability().can('display', 'call_cotisation_page')) {
+      children.push(this.constructMenu('call_cotisation', 'fa-euro-sign',  '/cotisation/call', true))
+    }
+
+    if (this.$ability().can('display', 'history_struture_cotisation_page')) {
+      children.push(this.constructMenu('history_struture_cotisation', 'fa-euro-sign',  '/cotisation/historystructure', true))
+    }
+
+    if (this.$ability().can('display', 'insurance_cotisation_page')) {
+      children.push(this.constructMenu('insurance_cotisation', 'fa-euro-sign',  '/cotisation/insurance', true))
+    }
+
+    if (this.$ability().can('display', 'resume_all_cotisation_page')) {
+      children.push(this.constructMenu('resume_all_cotisation', 'fa-euro-sign',  '/cotisation/resumeall', true))
+    }
+
+    if (this.$ability().can('display', 'resume_pay_cotisation_page')) {
+      children.push(this.constructMenu('resume_pay_cotisation', 'fa-euro-sign',  '/cotisation/resumepay', true))
+    }
+
+    if(children.length === 1){
+      return children[0];
+    }
+    return children.length > 0 ? this.constructMenu('cotisations', 'fa-money-bill',  undefined, undefined, children) : null;
+  }
+}
+
+export const getCotisationsMenu = ($config:any, $ability:any) => new CotisationsMenu($config, $ability).getMenu()

+ 2 - 2
use/template/Menus/donorsMenu.ts → use/layout/Menus/donorsMenu.ts

@@ -1,5 +1,5 @@
 import {ItemMenu, ItemsMenu} from "~/types/types";
-import BaseMenu from "~/use/template/Menus/baseMenu";
+import BaseMenu from "~/use/layout/Menus/baseMenu";
 
 class DonorsMenu extends BaseMenu{
   private $ability:any;
@@ -15,7 +15,7 @@ class DonorsMenu extends BaseMenu{
    */
   getMenu():ItemMenu | null {
     if (this.$ability().can('display', 'donors_page')) {
-      return this.constructMenu('far fa-handshake', 'donors', '/donors/list/', true)
+      return this.constructMenu('donors', 'far fa-handshake',  '/donors/list/', true)
     }
     return null;
   }

+ 8 - 8
use/template/Menus/educationalMenu.ts → use/layout/Menus/educationalMenu.ts

@@ -1,5 +1,5 @@
 import {ItemMenu, ItemsMenu} from "~/types/types";
-import BaseMenu from "~/use/template/Menus/baseMenu";
+import BaseMenu from "~/use/layout/Menus/baseMenu";
 
 class EducationalMenu extends BaseMenu{
   private $ability:any;
@@ -17,33 +17,33 @@ class EducationalMenu extends BaseMenu{
     const children:ItemsMenu = [];
 
     if (this.$ability().can('display', 'criteria_notations_page')) {
-      children.push(this.constructMenu('fa-bars', 'criteria_notations', '/criteria_notations/list/', true))
+      children.push(this.constructMenu('criteria_notations', 'fa-bars',  '/criteria_notations/list/', true))
     }
 
     if (this.$ability().can('display', 'seizure_period_page')) {
-      children.push(this.constructMenu('fa-calendar-alt', 'seizure_period', '/education_teachers/list/', true))
+      children.push(this.constructMenu('seizure_period', 'fa-calendar-alt',  '/education_teachers/list/', true))
     }
 
     if (this.$ability().can('display', 'test_seizure_page')) {
-      children.push(this.constructMenu('fa-pencil-alt', 'test_seizure', '/education_input/list/', true))
+      children.push(this.constructMenu('test_seizure', 'fa-pencil-alt',  '/education_input/list/', true))
     }
 
     if (this.$ability().can('display', 'test_validation_page')) {
-      children.push(this.constructMenu('fa-check', 'test_validation', '/education_notations/list/', true))
+      children.push(this.constructMenu('test_validation', 'fa-check',  '/education_notations/list/', true))
     }
 
     if (this.$ability().can('display', 'examen_results_page')) {
-      children.push(this.constructMenu('fa-graduation-cap', 'examen_results', '/examen_convocations/list/', true))
+      children.push(this.constructMenu('examen_results', 'fa-graduation-cap',  '/examen_convocations/list/', true))
     }
 
     if (this.$ability().can('display', 'education_by_student_validation_page')) {
-      children.push(this.constructMenu('fa-check-square', 'education_by_student_validation', '/education_by_student/list/', true))
+      children.push(this.constructMenu('education_by_student_validation', 'fa-check-square',  '/education_by_student/list/', true))
     }
 
     if(children.length === 1){
       return children[0];
     }
-    return children.length > 0 ? this.constructMenu('fa-graduation-cap', 'education_state', undefined, undefined, children) : null;
+    return children.length > 0 ? this.constructMenu('education_state', 'fa-graduation-cap',  undefined, undefined, children) : null;
   }
 }
 

+ 2 - 2
use/template/Menus/equipmentMenu.ts → use/layout/Menus/equipmentMenu.ts

@@ -1,5 +1,5 @@
 import {ItemMenu} from "~/types/types";
-import BaseMenu from "~/use/template/Menus/baseMenu";
+import BaseMenu from "~/use/layout/Menus/baseMenu";
 
 class EquipmentMenu extends BaseMenu{
   private $ability:any;
@@ -15,7 +15,7 @@ class EquipmentMenu extends BaseMenu{
    */
   getMenu():ItemMenu | null {
     if (this.$ability().can('display', 'equipment_page')) {
-      return this.constructMenu('fa-cube', 'equipment', '/equipment/list', true)
+      return this.constructMenu('equipment', 'fa-cube',  '/equipment/list', true)
     }
     return null;
   }

+ 2 - 2
use/template/Menus/medalsMenu.ts → use/layout/Menus/medalsMenu.ts

@@ -1,5 +1,5 @@
 import {ItemMenu, ItemsMenu} from "~/types/types";
-import BaseMenu from "~/use/template/Menus/baseMenu";
+import BaseMenu from "~/use/layout/Menus/baseMenu";
 
 class MedalsMenu extends BaseMenu{
   private $ability:any;
@@ -15,7 +15,7 @@ class MedalsMenu extends BaseMenu{
    */
   getMenu():ItemMenu | null {
     if (this.$ability().can('display', 'medals_page')) {
-      return this.constructMenu('fa-trophy', 'medals', '/medals/list/', true)
+      return this.constructMenu('medals', 'fa-trophy',  '/medals/list/', true)
     }
     return null;
   }

+ 29 - 0
use/layout/Menus/myAccessesMenu.ts

@@ -0,0 +1,29 @@
+import {ItemMenu, ItemsMenu} from "~/types/types";
+import BaseMenu from "~/use/layout/Menus/baseMenu";
+
+class MyAccessesMenu extends BaseMenu{
+  private $ability:any;
+  private $store:any;
+
+  constructor($config:any, $ability:any, $store: any) {
+    super($config)
+    this.$ability = $ability
+    this.$store = $store
+  }
+
+  /**
+   * Construit le menu Header Configuration ou null si aucune page accessible
+   * @return {ItemMenu | null}
+   */
+  getHeaderMenu():ItemMenu | null {
+    const children:ItemsMenu = [];
+
+    if (this.$ability().can('display', 'organization_page')) {
+      children.push(this.constructMenu('organization_page', undefined,'/organization/edit'))
+    }
+
+    return children.length > 0 ? this.constructMenu('configuration', 'fa-building', undefined, undefined, children) : null;
+  }
+}
+
+export const getMyAccessesMenu = ($config:any, $ability:any, $store:any) => new MyAccessesMenu($config, $ability, $store).getHeaderMenu()

+ 29 - 0
use/layout/Menus/myFamilyMenu.ts

@@ -0,0 +1,29 @@
+import {ItemMenu, ItemsMenu} from "~/types/types";
+import BaseMenu from "~/use/layout/Menus/baseMenu";
+
+class MyFamilyMenu extends BaseMenu{
+  private $ability:any;
+  private $store:any;
+
+  constructor($config:any, $ability:any, $store: any) {
+    super($config)
+    this.$ability = $ability
+    this.$store = $store
+  }
+
+  /**
+   * Construit le menu Header Configuration ou null si aucune page accessible
+   * @return {ItemMenu | null}
+   */
+  getHeaderMenu():ItemMenu | null {
+    const children:ItemsMenu = [];
+
+    if (this.$ability().can('display', 'organization_page')) {
+      children.push(this.constructMenu('organization_page', undefined,'/organization/edit'))
+    }
+
+    return children.length > 0 ? this.constructMenu('configuration', 'fa-users', undefined, undefined, children) : null;
+  }
+}
+
+export const getMyFamilyMenu = ($config:any, $ability:any, $store:any) => new MyFamilyMenu($config, $ability, $store).getHeaderMenu()

+ 5 - 5
use/template/Menus/statsMenu.ts → use/layout/Menus/statsMenu.ts

@@ -1,5 +1,5 @@
 import {ItemMenu, ItemsMenu} from "~/types/types";
-import BaseMenu from "~/use/template/Menus/baseMenu";
+import BaseMenu from "~/use/layout/Menus/baseMenu";
 
 class StatsMenu extends BaseMenu{
   private $ability:any;
@@ -17,21 +17,21 @@ class StatsMenu extends BaseMenu{
     const children:ItemsMenu = [];
 
     if (this.$ability().can('display', 'report_activity_page')) {
-      children.push(this.constructMenu('fa-chart-bar', 'report_activity', '/report_activity', true))
+      children.push(this.constructMenu('report_activity', 'fa-chart-bar',  '/report_activity', true))
     }
 
     if (this.$ability().can('display', 'fede_stats_page')) {
-      children.push(this.constructMenu('fa-chart-bar', 'fede_stats', '/statistic/membersfedeonly', true))
+      children.push(this.constructMenu('fede_stats', 'fa-chart-bar',  '/statistic/membersfedeonly', true))
     }
 
     if (this.$ability().can('display', 'structure_stats_page')) {
-      children.push(this.constructMenu('fa-chart-bar', 'structure_stats', '/statistic/membersfedeassos', true))
+      children.push(this.constructMenu('structure_stats', 'fa-chart-bar',  '/statistic/membersfedeassos', true))
     }
 
     if(children.length === 1){
       return children[0];
     }
-    return children.length > 0 ? this.constructMenu('fa-chart-bar', 'stats', undefined, undefined, children) : null;
+    return children.length > 0 ? this.constructMenu('stats', 'fa-chart-bar',  undefined, undefined, children) : null;
   }
 }
 

+ 19 - 7
use/template/Menus/websiteMenu.ts → use/layout/Menus/websiteMenu.ts

@@ -1,5 +1,5 @@
 import {ItemMenu, ItemsMenu, organizationState} from "~/types/types";
-import BaseMenu from "~/use/template/Menus/baseMenu";
+import BaseMenu from "~/use/layout/Menus/baseMenu";
 import *  as _ from "lodash"
 
 class WebsiteMenu extends BaseMenu{
@@ -19,16 +19,28 @@ class WebsiteMenu extends BaseMenu{
   getMenu():ItemMenu | null {
     const children:ItemsMenu = [];
 
-    children.push(this.constructMenu('fa-globe-europe', this.$store.state.profile.organization.name, this.getWebsite(this.$store.state.profile.organization), false, undefined, true))
-
-    if(!this.$store.state.profile.organization.website && this.$store.state.profile.access.isAdminAccess)
+    if(!this.$store.state.profile.organization.website && this.$store.state.profile.access.isAdminAccess){
+      children.push(this.constructMenu('fa-globe-europe', 'simple_modification', this.getWebsite(this.$store.state.profile.organization), false, undefined, true))
       children.push(this.constructMenu('fa-globe-europe', 'advanced_modification', this.getWebsite(this.$store.state.profile.organization) + '/typo3', false, undefined, true))
+    }
+
+    return children.length > 0 ? this.constructMenu('fa-globe-europe', 'website', undefined, undefined, children) : null;
+  }
+
+  /**
+   * Construit le menu Header des Sites internet ou null si aucune page accessible
+   * @return {ItemMenu | null}
+   */
+  getHeaderMenu():ItemMenu | null {
+    const children:ItemsMenu = [];
+
+    children.push(this.constructMenu(this.$store.state.profile.organization.name, undefined, this.getWebsite(this.$store.state.profile.organization), false, undefined, true))
 
     _.each(this.$store.state.profile.organization.parents, parent => {
-      children.push(this.constructMenu('fa-globe-europe', parent.name, this.getWebsite(parent), false, undefined, true))
+      children.push(this.constructMenu(parent.name, undefined, this.getWebsite(parent), false))
     })
 
-    return children.length > 0 ? this.constructMenu('fa-globe-europe', 'website', undefined, undefined, children) : null;
+    return children.length > 0 ? this.constructMenu('website', 'fa-globe-europe',  undefined, undefined, children) : null;
   }
 
   getWebsite(organization:organizationState):string{
@@ -36,4 +48,4 @@ class WebsiteMenu extends BaseMenu{
   }
 }
 
-export const getWebsiteMenu = ($config:any, $ability:any, $store:any) => new WebsiteMenu($config, $ability, $store).getMenu()
+export const getWebsiteMenu = ($config:any, $ability:any, $store:any) => new WebsiteMenu($config, $ability, $store)

+ 138 - 0
use/layout/menu.ts

@@ -0,0 +1,138 @@
+import {ref, useContext} from "@nuxtjs/composition-api";
+import {ItemMenu, ItemsMenu} from "~/types/types";
+import {getAccessMenu} from "~/use/layout/Menus/accessMenu";
+import {getAgendaMenu} from "~/use/layout/Menus/agendaMenu";
+import {getEquipmentMenu} from "~/use/layout/Menus/equipmentMenu";
+import {getEducationalMenu} from "~/use/layout/Menus/educationalMenu";
+import {getBillingMenu} from "~/use/layout/Menus/billingMenu";
+import {getCommunicationMenu} from "~/use/layout/Menus/communicationMenu";
+import {getDonorsMenu} from "~/use/layout/Menus/donorsMenu";
+import {getMedalsMenu} from "~/use/layout/Menus/medalsMenu";
+import {getStatsMenu} from "~/use/layout/Menus/statsMenu";
+import {getCotisationsMenu} from "~/use/layout/Menus/cotisationsMenu";
+import {getAdmin2iosMenu} from "~/use/layout/Menus/admin2iosMenu";
+import {getWebsiteMenu} from "~/use/layout/Menus/websiteMenu";
+import {getConfigurationMenu} from "~/use/layout/Menus/configurationMenu";
+import {getMyFamilyMenu} from "~/use/layout/Menus/myFamilyMenu";
+import {getMyAccessesMenu} from "~/use/layout/Menus/myAccessesMenu";
+import {getAccountMenu} from "~/use/layout/Menus/accountMenu";
+
+/**
+ * @category Use/template
+ * @class Menu
+ * Use Classe pour la construction du Menu
+ */
+class Menu{
+  private $ability:any;
+  private $config:any;
+  private $store:any;
+
+  /**
+   * @constructor
+   * Initialisation des services issues du context
+   */
+  constructor() {
+  }
+
+  setUpContext(){
+    const {$ability, $config, store} = useContext();
+    this.$ability = $ability;
+    this.$config = $config;
+    this.$store = store;
+    return this;
+  }
+
+  /**
+   * Construit le menu et mets à jour le state du profile d'access
+   */
+  useLateralMenuConstruct(){
+    let menu:ItemsMenu = []
+
+    const accessMenu = getAccessMenu(this.$config,this.$ability,this.$store)
+    if(accessMenu) menu.push(accessMenu)
+
+    const agendaMenu = getAgendaMenu(this.$config,this.$ability)
+    if(agendaMenu) menu.push(agendaMenu)
+
+    const equipmentMenu = getEquipmentMenu(this.$config,this.$ability)
+    if(equipmentMenu) menu.push(equipmentMenu)
+
+    const educationalMenu = getEducationalMenu(this.$config,this.$ability)
+    if(educationalMenu) menu.push(educationalMenu)
+
+    const billingMenu = getBillingMenu(this.$config,this.$ability)
+    if(billingMenu) menu.push(billingMenu)
+
+    const communicationMenu = getCommunicationMenu(this.$config,this.$ability)
+    if(communicationMenu) menu.push(communicationMenu)
+
+    const donorsMenu = getDonorsMenu(this.$config,this.$ability)
+    if(donorsMenu) menu.push(donorsMenu)
+
+    const medalsMenu = getMedalsMenu(this.$config,this.$ability)
+    if(medalsMenu) menu.push(medalsMenu)
+
+    const websiteMenu = getWebsiteMenu(this.$config,this.$ability,this.$store).getMenu()
+    if(websiteMenu) menu.push(websiteMenu)
+
+    const cotisationsMenu = getCotisationsMenu(this.$config,this.$ability)
+    if(cotisationsMenu) menu.push(cotisationsMenu)
+
+    const statsMenu = getStatsMenu(this.$config,this.$ability)
+    if(statsMenu) menu.push(statsMenu)
+
+    const admin2iosMenu = getAdmin2iosMenu(this.$config,this.$ability)
+    if(admin2iosMenu) menu.push(admin2iosMenu)
+
+    //Si l'utilisateur possède au moins un menu alors le menu latéral sera accessible
+    this.$store.commit('profile/access/setHasLateralMenu', menu.length > 0)
+
+    return ref(menu)
+  }
+
+  /**
+   * Construit le menu configuration et mets à jour le state du profile d'access
+   */
+  useConfigurationMenuConstruct() {
+    const menu = getConfigurationMenu(this.$config,this.$ability,this.$store);
+    //Si l'utilisateur possède au moins un menu alors le menu configuration sera accessible
+    this.$store.commit('profile/access/setHasConfigurationMenu', menu != null)
+    return ref(menu)
+  }
+
+  /**
+   * Construit le menu Mon Compte
+   */
+  useAccountMenuConstruct() {
+    return ref(getAccountMenu(this.$config,this.$ability,this.$store))
+  }
+
+  /**
+   * Construit le menu Mes structure et mets à jour le state du profile d'access
+   */
+  useMyAccessesMenuConstruct() {
+    const menu = getMyAccessesMenu(this.$config,this.$ability,this.$store);
+    //Si l'utilisateur possède au moins un menu alors le menu mes structures sera accessible
+    this.$store.commit('profile/access/setHasAccessesMenu', menu != null)
+    return ref(menu)
+  }
+
+  /**
+   * Construit le menu Changement d'utilisateur et mets à jour le state du profile d'access
+   */
+  useMyFamilyMenuConstruct() {
+    const menu = getMyFamilyMenu(this.$config,this.$ability,this.$store);
+    //Si l'utilisateur possède au moins un menu alors le menu changement d'utilisateur sera accessible
+    this.$store.commit('profile/access/setHasFamilyMenu', menu != null)
+    return ref(menu)
+  }
+
+  /**
+   * Construit le menu site internet du header
+   */
+  useWebSiteMenuConstruct() {
+    return ref(getWebsiteMenu(this.$config,this.$ability,this.$store).getHeaderMenu())
+  }
+}
+
+export const $useMenu = new Menu()

+ 34 - 0
use/store/useQuery.ts

@@ -0,0 +1,34 @@
+import {Query} from "@vuex-orm/core";
+import {$objectProperties} from "~/services/utils/objectProperties";
+import {AnyJson} from "~/types/types";
+import {Collection, Item} from "@vuex-orm/core/dist/src/data/Data";
+
+class useQuery{
+  public getEntry(query: Query, id:number): Item{
+    return query.find(id);
+  }
+
+  public getEntries(query: Query):Collection{
+    return query.get()
+  }
+
+  public getFlattenEntry(query: Query, id:number): AnyJson{
+    return $objectProperties.cloneAndFlatten(this.getEntry(query, id) as AnyJson);
+  }
+
+  public getFlattenEntries(query: Query): Array<AnyJson>{
+    const entries = this.getEntries(query)
+    return entries.map((entry:AnyJson) => {
+      return $objectProperties.cloneAndFlatten(entry)
+    })
+  }
+
+  public getJsonEntry(query: Query, id:number): AnyJson{
+    const entry = this.getEntry(query, id);
+    if(entry)
+      return entry.$toJson();
+    return {}
+  }
+}
+
+export const useQueryHelper = new useQuery()

+ 45 - 0
use/store/useRepository.ts

@@ -0,0 +1,45 @@
+import {useContext} from '@nuxtjs/composition-api'
+import {Repository} from "@vuex-orm/core";
+import {$objectProperties} from "~/services/utils/objectProperties";
+import {Model} from '@/models/Model'
+import {AnyJson} from "~/types/types";
+
+class useRepository{
+  public getRepository(model: typeof Model): Repository<Model>{
+    const {store} = useContext()
+    return store.$repo(model)
+  }
+
+  public initRepository(model: typeof Model, readOnly:boolean = true): Repository<Model>{
+    const repository = this.getRepository(model)
+    this.setReadOnly(repository, readOnly)
+    return repository
+  }
+
+  public setReadOnly(repository: Repository<Model>, readOnly:boolean): void{
+    repository.getModel().setReadOnly(readOnly)
+  }
+
+  public getReadOnly(repository: Repository<Model>): boolean{
+    return repository.getModel().getReadOnly()
+  }
+
+  public editRepository(repository: Repository<Model>){
+    return () => {
+      this.setReadOnly(repository, false)
+    }
+  }
+
+  public updateStoreFromField(repository: Repository, entry:AnyJson, value:any, field:string): void{
+    entry[field] = value
+    repository.update($objectProperties.cloneAndNest(entry))
+  }
+
+  public cleanRepository(repository: Repository){
+    return () => {
+      repository.flush()
+    }
+  }
+}
+
+export const useRepositoryHelper = new useRepository()

+ 0 - 78
use/template/Menus/admin2iosMenu.ts

@@ -1,78 +0,0 @@
-import {ItemMenu, ItemsMenu} from "~/types/types";
-import BaseMenu from "~/use/template/Menus/baseMenu";
-
-class Admin2iosMenu extends BaseMenu{
-  private $ability:any;
-
-  constructor($config:any, $ability:any) {
-    super($config)
-    this.$ability = $ability
-  }
-
-  /**
-   * Construit le menu Administration 2ios ou null si aucune page accessible
-   * @return {ItemMenu | null}
-   */
-  getMenu():ItemMenu | null {
-    const children:ItemsMenu = [];
-
-    if (this.$ability().can('display', 'all_accesses_page')) {
-      children.push(this.constructMenu('fa-users', 'all_accesses', '/all_accesses/list/', true))
-    }
-
-    if (this.$ability().can('display', 'all_organizations_page')) {
-      children.push(this.constructMenu('fa-building', 'all_organizations', '/organization_params/list/', true))
-    }
-
-    if (this.$ability().can('display', 'tips_page')) {
-      children.push(this.constructMenu('fa-info-circle', 'tips', '/tips/list/', true))
-    }
-
-    if (this.$ability().can('display', 'actions_lead_page')) {
-      children.push(this.constructMenu('fa-comments-dollar', 'actions_lead', '/admin2ios/actions_lead', true))
-    }
-
-    if (this.$ability().can('display', 'renewall_list_page')) {
-      children.push(this.constructMenu('fa-sync', 'renewall_list', '/admin2ios/renewalllist', true))
-    }
-
-    if (this.$ability().can('display', 'settlements_page')) {
-      children.push(this.constructMenu('fa-euro-sign', 'settlements', '/admin2ios/settlements', true))
-    }
-
-    if (this.$ability().can('display', 'pendings_settlements_page')) {
-      children.push(this.constructMenu('fa-euro-sign', 'pendings_settlements', '/admin2ios/pendings_settlements', true))
-    }
-
-    if (this.$ability().can('display', 'outages_notice_page')) {
-      children.push(this.constructMenu('fa-cut', 'outages_notice', '/admin2ios/outagesnotice', true))
-    }
-
-    if (this.$ability().can('display', 'degraded_page')) {
-      children.push(this.constructMenu('fa-users', 'degraded', '/admin2ios/degraded', true))
-    }
-
-    if (this.$ability().can('display', 'dgv_page')) {
-      children.push(this.constructMenu('fa-house-damage', 'dgv', '/admin2ios/dgv', true))
-    }
-
-    if (this.$ability().can('display', 'cmf_cotisation_page')) {
-      children.push(this.constructMenu('fa-info-circle', 'cmf_cotisation', '/admin2ios/cotisationcmf', true))
-    }
-
-    if (this.$ability().can('display', 'right_page')) {
-      children.push(this.constructMenu('fa-balance-scale-right', 'right_menu', '/admin2ios/right', true))
-    }
-
-    if (this.$ability().can('display', 'tree_page')) {
-      children.push(this.constructMenu('fa-sitemap', 'tree_menu', '/admin2ios/tree', true))
-    }
-
-    if(children.length === 1){
-      return children[0];
-    }
-    return children.length > 0 ? this.constructMenu('fa-sitemap', 'admin2ios', undefined, undefined, children) : null;
-  }
-}
-
-export const getAdmin2iosMenu = ($config:any, $ability:any) => new Admin2iosMenu($config, $ability).getMenu()

+ 0 - 94
use/template/Menus/cotisationsMenu.ts

@@ -1,94 +0,0 @@
-import {ItemMenu, ItemsMenu} from "~/types/types";
-import BaseMenu from "~/use/template/Menus/baseMenu";
-
-class CotisationsMenu extends BaseMenu{
-  private $ability:any;
-
-  constructor($config:any, $ability:any) {
-    super($config)
-    this.$ability = $ability
-  }
-
-  /**
-   * Construit le menu Cotisations ou null si aucune page accessible
-   * @return {ItemMenu | null}
-   */
-  getMenu():ItemMenu | null {
-    const children:ItemsMenu = [];
-
-    if (this.$ability().can('display', 'rate_cotisation_page')) {
-      children.push(this.constructMenu('fa-euro-sign', 'rate_cotisation', '/cotisation/rate', true))
-    }
-
-    if (this.$ability().can('display', 'parameters_cotisation_page')) {
-      children.push(this.constructMenu('fa-euro-sign', 'parameters_cotisation', '/cotisation/parameter', true))
-    }
-
-    if (this.$ability().can('display', 'send_cotisation_page')) {
-      children.push(this.constructMenu('fa-euro-sign', 'send_cotisation', '/cotisation/send', true))
-    }
-
-    if (this.$ability().can('display', 'state_cotisation_page')) {
-      children.push(this.constructMenu('fa-euro-sign', 'state_cotisation', '/cotisation/state', true))
-    }
-
-    if (this.$ability().can('display', 'pay_cotisation_page')) {
-      children.push(this.constructMenu('fa-euro-sign', 'pay_cotisation', '/cotisation/pay', true))
-    }
-
-    if (this.$ability().can('display', 'check_cotisation_page')) {
-      children.push(this.constructMenu('fa-euro-sign', 'check_cotisation', '/cotisation/check', true))
-    }
-
-    if (this.$ability().can('display', 'ledger_cotisation_page')) {
-      children.push(this.constructMenu('fa-euro-sign', 'ledger_cotisation', '/cotisation/ledger', true))
-    }
-
-    if (this.$ability().can('display', 'magazine_cotisation_page')) {
-      children.push(this.constructMenu('fa-euro-sign', 'magazine_cotisation', '/cotisation/magazine', true))
-    }
-
-    if (this.$ability().can('display', 'ventilated_cotisation_page')) {
-      children.push(this.constructMenu('fa-euro-sign', 'ventilated_cotisation', '/cotisation/ventilated', true))
-    }
-
-    if (this.$ability().can('display', 'pay_erase_cotisation_page')) {
-      children.push(this.constructMenu('fa-euro-sign', 'pay_erase_cotisation', '/cotisation/payerase', true))
-    }
-
-    if (this.$ability().can('display', 'resume_cotisation_page')) {
-      children.push(this.constructMenu('fa-euro-sign', 'resume_cotisation', '/cotisation/resume', true))
-    }
-
-    if (this.$ability().can('display', 'history_cotisation_page')) {
-      children.push(this.constructMenu('fa-euro-sign', 'history_cotisation', '/cotisation/history', true))
-    }
-
-    if (this.$ability().can('display', 'call_cotisation_page')) {
-      children.push(this.constructMenu('fa-euro-sign', 'call_cotisation', '/cotisation/call', true))
-    }
-
-    if (this.$ability().can('display', 'history_struture_cotisation_page')) {
-      children.push(this.constructMenu('fa-euro-sign', 'history_struture_cotisation', '/cotisation/historystructure', true))
-    }
-
-    if (this.$ability().can('display', 'insurance_cotisation_page')) {
-      children.push(this.constructMenu('fa-euro-sign', 'insurance_cotisation', '/cotisation/insurance', true))
-    }
-
-    if (this.$ability().can('display', 'resume_all_cotisation_page')) {
-      children.push(this.constructMenu('fa-euro-sign', 'resume_all_cotisation', '/cotisation/resumeall', true))
-    }
-
-    if (this.$ability().can('display', 'resume_pay_cotisation_page')) {
-      children.push(this.constructMenu('fa-euro-sign', 'resume_pay_cotisation', '/cotisation/resumepay', true))
-    }
-
-    if(children.length === 1){
-      return children[0];
-    }
-    return children.length > 0 ? this.constructMenu('fa-money-bill', 'cotisations', undefined, undefined, children) : null;
-  }
-}
-
-export const getCotisationsMenu = ($config:any, $ability:any) => new CotisationsMenu($config, $ability).getMenu()

+ 0 - 87
use/template/menu.ts

@@ -1,87 +0,0 @@
-import {ref, useContext} from "@nuxtjs/composition-api";
-import {ItemsMenu} from "~/types/types";
-import {getAccessMenu} from "~/use/template/Menus/accessMenu";
-import {getAgendaMenu} from "~/use/template/Menus/agendaMenu";
-import {getEquipmentMenu} from "~/use/template/Menus/equipmentMenu";
-import {getEducationalMenu} from "~/use/template/Menus/educationalMenu";
-import {getBillingMenu} from "~/use/template/Menus/billingMenu";
-import {getCommunicationMenu} from "~/use/template/Menus/communicationMenu";
-import {getDonorsMenu} from "~/use/template/Menus/donorsMenu";
-import {getMedalsMenu} from "~/use/template/Menus/medalsMenu";
-import {getStatsMenu} from "~/use/template/Menus/statsMenu";
-import {getCotisationsMenu} from "~/use/template/Menus/cotisationsMenu";
-import {getAdmin2iosMenu} from "~/use/template/Menus/admin2iosMenu";
-import {getWebsiteMenu} from "~/use/template/Menus/websiteMenu";
-
-/**
- * @category Use/template
- * @class Menu
- * Use Classe pour la construction du Menu
- */
-class Menu{
-  private $ability:any;
-  private $config:any;
-  private $store:any;
-
-  /**
-   * @constructor
-   * Initialisation des services issues du context
-   */
-  constructor() {
-  }
-
-  setUpContext(){
-    const {$ability, $config, store} = useContext();
-    this.$ability = $ability;
-    this.$config = $config;
-    this.$store = store;
-    return this;
-  }
-
-  /**
-   * Construit le menu
-   */
-  useLateralMenuConstruct(){
-    let menu:ItemsMenu = []
-
-    const accessMenu = getAccessMenu(this.$config,this.$ability,this.$store)
-    if(accessMenu) menu.push(accessMenu)
-
-    const agendaMenu = getAgendaMenu(this.$config,this.$ability)
-    if(agendaMenu) menu.push(agendaMenu)
-
-    const equipmentMenu = getEquipmentMenu(this.$config,this.$ability)
-    if(equipmentMenu) menu.push(equipmentMenu)
-
-    const educationalMenu = getEducationalMenu(this.$config,this.$ability)
-    if(educationalMenu) menu.push(educationalMenu)
-
-    const billingMenu = getBillingMenu(this.$config,this.$ability)
-    if(billingMenu) menu.push(billingMenu)
-
-    const communicationMenu = getCommunicationMenu(this.$config,this.$ability)
-    if(communicationMenu) menu.push(communicationMenu)
-
-    const donorsMenu = getDonorsMenu(this.$config,this.$ability)
-    if(donorsMenu) menu.push(donorsMenu)
-
-    const medalsMenu = getMedalsMenu(this.$config,this.$ability)
-    if(medalsMenu) menu.push(medalsMenu)
-
-    const websiteMenu = getWebsiteMenu(this.$config,this.$ability,this.$store)
-    if(websiteMenu) menu.push(websiteMenu)
-
-    const cotisationsMenu = getCotisationsMenu(this.$config,this.$ability)
-    if(cotisationsMenu) menu.push(cotisationsMenu)
-
-    const statsMenu = getStatsMenu(this.$config,this.$ability)
-    if(statsMenu) menu.push(statsMenu)
-
-    const admin2iosMenu = getAdmin2iosMenu(this.$config,this.$ability)
-    if(admin2iosMenu) menu.push(admin2iosMenu)
-
-    return ref(menu)
-  }
-}
-
-export const $useMenu = new Menu()

File diff suppressed because it is too large
+ 460 - 429
yarn.lock


Some files were not shown because too many files changed in this diff