Kaynağa Gözat

first form page

Vincent GUFFON 4 yıl önce
ebeveyn
işleme
d699c336fe
62 değiştirilmiş dosya ile 1941 ekleme ve 680 silme
  1. 2 1
      assets/css/global.scss
  2. 0 1
      assets/css/import.scss
  3. 0 25
      components/Actions/EditButtonComponent.vue
  4. 45 0
      components/Form/BottomSheetComponent.vue
  5. 90 29
      components/Form/DataTableComponent.vue
  6. 13 5
      components/Form/ExpansionPanelComponent.vue
  7. 85 58
      components/Form/FormComponent.vue
  8. 61 0
      components/Form/Input/CheckboxComponent.vue
  9. 89 0
      components/Form/Input/DatePickerComponent.vue
  10. 82 0
      components/Form/Input/InputComponent.vue
  11. 89 0
      components/Form/Input/SelectComponent.vue
  12. 61 0
      components/Form/Input/TextComponent.vue
  13. 0 69
      components/Form/InputComponent.vue
  14. 26 0
      components/Layout/ContainerComponent.vue
  15. 5 1
      components/Layout/HeaderComponent.vue
  16. 0 44
      components/List/ListComponent.vue
  17. 0 27
      components/Utils/AlertComponent.vue
  18. 1 0
      config/nuxtConfig/env.js
  19. 1 0
      config/nuxtConfig/modules.js
  20. 7 0
      config/nuxtConfig/moment.js
  21. 0 1
      config/nuxtConfig/plugins.js
  22. 61 0
      lang/enum/fr-FR.js
  23. 67 0
      lang/field/fr-FR.js
  24. 7 2
      lang/fr-FR.js
  25. 7 0
      lang/rulesAndErrors/fr-FR.js
  26. 0 2
      layouts/default.vue
  27. 0 12
      models/Access/Access.ts
  28. 40 0
      models/Core/AddressPostal.ts
  29. 27 0
      models/Core/BankAccount.ts
  30. 21 0
      models/Core/ContactPoint.ts
  31. 12 0
      models/Core/Country.ts
  32. 13 0
      models/Model.ts
  33. 99 2
      models/Organization/Organization.ts
  34. 16 0
      models/Organization/OrganizationAddressPostal.ts
  35. 21 0
      models/Organization/OrganizationLicence.ts
  36. 21 0
      models/Organization/OrganizationNetwork.ts
  37. 0 17
      models/Person/Person.ts
  38. 0 14
      models/Person/PersonActivity.ts
  39. 3 1
      nuxt.config.js
  40. 4 3
      package.json
  41. 0 83
      pages/accesses/_id.vue
  42. 0 38
      pages/accesses/list.vue
  43. 1 0
      pages/index.vue
  44. 444 7
      pages/organization/edit.vue
  45. 1 1
      plugins/Queries/http.js
  46. 3 25
      plugins/Queries/rest.ts
  47. 3 27
      plugins/Rights/ability.ts
  48. 0 4
      plugins/Syncfusion/grid.js
  49. 60 0
      services/dataProvider/dataProvider.ts
  50. 40 0
      services/dataProvider/enumDataProvider.ts
  51. 21 2
      services/profile/organizationProfile.ts
  52. 29 0
      services/queries/rest.ts
  53. 30 1
      services/rights/abilitiesUtils.ts
  54. 3 0
      services/utils/objectProperties.ts
  55. 1 0
      tsconfig.json
  56. 15 3
      types/types.d.ts
  57. 21 0
      use/form/useFormInputSetup.ts
  58. 26 0
      use/form/utils.ts
  59. 1 1
      use/layout/Menus/configurationMenu.ts
  60. 34 0
      use/store/useQuery.ts
  61. 45 0
      use/store/useRepository.ts
  62. 87 174
      yarn.lock

+ 2 - 1
assets/css/global.scss

@@ -13,5 +13,6 @@ header .v-toolbar__content{
   text-decoration: none;
 }
 
-.dropdown_header{
+.margin-bottom-20{
+  margin-bottom: 20px;
 }

+ 0 - 1
assets/css/import.scss

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

+ 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 - 29
components/Form/DataTableComponent.vue

@@ -1,32 +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 {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:{
@@ -34,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>

+ 5 - 1
components/Layout/HeaderComponent.vue

@@ -25,8 +25,12 @@
       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>
-      <a class="no-decoration" :href="properties.homeUrl + '/'"><v-icon class="ot_white--text" small>fa-home</v-icon></a>
+      <NuxtLink to="/" class="no-decoration"><v-icon class="ot_white--text" small>fa-home</v-icon></NuxtLink>
     </v-btn>
 
     <HeaderMenuComponent :menu="properties.webSiteMenu"></HeaderMenuComponent>

+ 0 - 44
components/List/ListComponent.vue

@@ -1,44 +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 scoped>
-</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 - 0
config/nuxtConfig/env.js

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

+ 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/Syncfusion/grid',
     '~/plugins/Rights/ability',
     './plugins/Rights/casl.js',
     '~/plugins/Queries/http',

+ 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),
   }
 }

+ 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",
+  })
+}

+ 0 - 2
layouts/default.vue

@@ -10,9 +10,7 @@
       <HeaderComponent v-on:handle-open-menu-click="handleOpenMenu"></HeaderComponent>
 
       <v-main class="ot_content_color">
-        <v-container>
           <nuxt/>
-        </v-container>
       </v-main>
     </v-app>
   </main>

+ 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 - 83
pages/accesses/_id.vue

@@ -1,83 +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'
-
-  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>

+ 1 - 0
pages/index.vue

@@ -2,6 +2,7 @@
   <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>

+ 444 - 7
pages/organization/edit.vue

@@ -1,15 +1,452 @@
 <template>
-    <main>
-      Fiche de l'organisation
-    </main>
+  <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>
-    export default {
-        name: "edit"
+<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/Syncfusion/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);

+ 21 - 2
services/profile/organizationProfile.ts

@@ -30,6 +30,14 @@ class OrganizationProfile{
     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}
@@ -41,6 +49,17 @@ class OrganizationProfile{
     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;
+  }
+
   /**
    * L'organization possède t'elle un produit school ou school premium
    * @return {boolean}
@@ -99,7 +118,7 @@ class OrganizationProfile{
 
   /**
    * L'organization possède t'elledes enfants
-   * @return {boolean}
+   * @return {boolean|null}
    */
   isOrganizationWithChildren():any{
     return this.organizationProfile.hasChildren;
@@ -116,7 +135,7 @@ class OrganizationProfile{
       isArtist: this.isArtist.bind(this),
       isManagerProduct: this.isManagerProduct.bind(this),
       isOrganizationWithChildren: this.isOrganizationWithChildren.bind(this),
-      isCmf: this.isCmf.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 } } }

+ 1 - 0
tsconfig.json

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

+ 15 - 3
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,7 +10,7 @@ interface ItemsMenu extends Array<ItemMenu> {}
 declare module '@nuxt/types' {
   interface Context {
     $ability(): Ability,
-    $rest: AnyJson
+    $rest: Rest
   }
 }
 
@@ -19,6 +21,7 @@ interface ItemMenu {
   children?: ItemsMenu,
   isExternalLink?: boolean,
 }
+interface ItemsMenu extends Array<ItemMenu> {}
 
 interface AbilitiesType {
   action: 'display' | 'read' | 'manage',
@@ -72,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
+    }
+  }
+}

+ 1 - 1
use/layout/Menus/configurationMenu.ts

@@ -27,7 +27,7 @@ class ConfigurationMenu extends BaseMenu{
     }
 
     if (this.$ability().can('display', 'parameters_page')) {
-      children.push(this.constructMenu('parameters', undefined,'/main/edit/parameters/' + this.$store.state.profile.organization.id, true))
+      children.push(this.constructMenu('parameters', undefined,'/configuration/parameters'))
     }
 
     if (this.$ability().can('display', 'place_page')) {

+ 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()

+ 87 - 174
yarn.lock

@@ -1680,13 +1680,16 @@
     webpack-node-externals "^2.5.2"
     webpackbar "^4.0.0"
 
-"@nuxtjs/composition-api@0.19":
-  version "0.19.0"
-  resolved "https://registry.yarnpkg.com/@nuxtjs/composition-api/-/composition-api-0.19.0.tgz#06ed97e70e4c5522bad151aa1890d85afb252b49"
-  integrity sha512-eej0MNm2KE4BSzAq+iZ2NrL8abDBfZoFrbBHV/GxuOVOQce2aKOEVZ3HB7UgEvdJywKmhM1/RajkGNG+YvT4CA==
+"@nuxtjs/composition-api@0.22.0":
+  version "0.22.0"
+  resolved "https://registry.yarnpkg.com/@nuxtjs/composition-api/-/composition-api-0.22.0.tgz#4ce65673dd08ef3d864ff35556e311224f16ffa2"
+  integrity sha512-FnrnYkCog3/N5T13vFcKKn0wu0Ifsh64OgS4e0PFESe+ON0AheXBYfPhpR7jxAAGBaFmz/8OMD4+LKYaQhxT9w==
   dependencies:
-    "@vue/composition-api" "1.0.0-rc.1"
+    "@vue/composition-api" "1.0.0-rc.3"
     defu "^3.2.2"
+    estree-walker "^2.0.2"
+    magic-string "^0.25.7"
+    ufo "^0.6.9"
     upath "^2.0.1"
 
 "@nuxtjs/eslint-config-typescript@^3.0.0":
@@ -1720,6 +1723,16 @@
     consola "^2.11.3"
     eslint-loader "^4.0.2"
 
+"@nuxtjs/moment@^1.6.1":
+  version "1.6.1"
+  resolved "https://registry.yarnpkg.com/@nuxtjs/moment/-/moment-1.6.1.tgz#a4e98a861c9d21e34f983046143f4c9bb92bdb7c"
+  integrity sha512-Mo2/3NQB0XryMQuNCTVnAclrDvt9I9sr6dwVm56KhYCoiWTKgQ78tDV9tmrxw7lahw1IBwyPGhw+3pwkM4phAA==
+  dependencies:
+    moment "^2.25.3"
+    moment-locales-webpack-plugin "^1.2.0"
+    moment-timezone "^0.5.28"
+    moment-timezone-data-webpack-plugin "^1.3.0"
+
 "@nuxtjs/proxy@^2.0.1":
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/@nuxtjs/proxy/-/proxy-2.1.0.tgz#fa7715a11d237fa1273503c4e9e137dd1bf5575b"
@@ -1761,165 +1774,6 @@
   dependencies:
     "@sinonjs/commons" "^1.7.0"
 
-"@syncfusion/ej2-base@~18.4.30", "@syncfusion/ej2-base@~18.4.31":
-  version "18.4.31"
-  resolved "https://registry.yarnpkg.com/@syncfusion/ej2-base/-/ej2-base-18.4.31.tgz#90a9202aa2aa93a9c4985226efba32f654fad09b"
-  integrity sha512-WT4SAqqk+igTs4jK6h8hylFd1VZWhuactRHSvVqdf1b3XHqG64BSyEEnMpQO3VynAkd66nNdnyUuaMPIIyCtdA==
-  dependencies:
-    "@syncfusion/ej2-icons" "~18.4.30"
-
-"@syncfusion/ej2-buttons@~18.4.30":
-  version "18.4.30"
-  resolved "https://registry.yarnpkg.com/@syncfusion/ej2-buttons/-/ej2-buttons-18.4.30.tgz#f7c5e26c31e53a50ab98cd881d8fe617b82d059f"
-  integrity sha512-rcsemtNOobwtmbsunYrpKDVFoBJ2R+M6tyhA+wWn0d/2CEgcJGaOvUCLIVECBKQTtIcqhOyxN5R6/VZDPHKVvQ==
-  dependencies:
-    "@syncfusion/ej2-base" "~18.4.30"
-
-"@syncfusion/ej2-calendars@~18.4.31":
-  version "18.4.31"
-  resolved "https://registry.yarnpkg.com/@syncfusion/ej2-calendars/-/ej2-calendars-18.4.31.tgz#7a3fe6b9300011be9d0b7eb595082c846438f7b5"
-  integrity sha512-6H7qmk27CW2zQfmUkV35Q/Imv9JMk8t19tUQLWi0nV7rBmwnomhywZ3fHeJ7EKNJojrW0vo3LMF74I0hUXFvUg==
-  dependencies:
-    "@syncfusion/ej2-base" "~18.4.31"
-    "@syncfusion/ej2-buttons" "~18.4.30"
-    "@syncfusion/ej2-inputs" "~18.4.31"
-    "@syncfusion/ej2-lists" "~18.4.30"
-    "@syncfusion/ej2-popups" "~18.4.30"
-
-"@syncfusion/ej2-compression@~18.4.30":
-  version "18.4.30"
-  resolved "https://registry.yarnpkg.com/@syncfusion/ej2-compression/-/ej2-compression-18.4.30.tgz#54dc91314cacdc90dcdbbc2914dfbca3ec5182d5"
-  integrity sha512-W9W/8XQRbs+23vnDSdeNGzU+pJovDESYKTtyLTgtXfqUat7BpZTCrEtnW7u+jC2RoLVPMjlHW06oB7yW6mC5Ag==
-  dependencies:
-    "@syncfusion/ej2-file-utils" "~18.4.30"
-
-"@syncfusion/ej2-data@~18.4.30":
-  version "18.4.30"
-  resolved "https://registry.yarnpkg.com/@syncfusion/ej2-data/-/ej2-data-18.4.30.tgz#f0314a90f47385486a5ae77e02ef1e630c5eb1ab"
-  integrity sha512-HQyB4yEAffuj394VZyUayfvyOzDL/IaNWQs2r6qXD2pZvAvWYq/NdK4PvfWNWFN9lO21IXUVK6TyH2F800ciJg==
-  dependencies:
-    "@syncfusion/ej2-base" "~18.4.30"
-
-"@syncfusion/ej2-dropdowns@~18.4.31":
-  version "18.4.31"
-  resolved "https://registry.yarnpkg.com/@syncfusion/ej2-dropdowns/-/ej2-dropdowns-18.4.31.tgz#1a59dec8b897a63a9f8dbcb8f68bcf73411f98dd"
-  integrity sha512-/gvrbv2UmG5mLkTM/ZSqCg36ufcQ/A+vS/uC4Gw5Tne+49r9jYpz/PyAcDdRn046ybs7YZy/bNR1CHM9iHewEw==
-  dependencies:
-    "@syncfusion/ej2-base" "~18.4.31"
-    "@syncfusion/ej2-data" "~18.4.30"
-    "@syncfusion/ej2-inputs" "~18.4.31"
-    "@syncfusion/ej2-lists" "~18.4.30"
-    "@syncfusion/ej2-navigations" "~18.4.31"
-    "@syncfusion/ej2-popups" "~18.4.30"
-
-"@syncfusion/ej2-excel-export@~18.4.30":
-  version "18.4.30"
-  resolved "https://registry.yarnpkg.com/@syncfusion/ej2-excel-export/-/ej2-excel-export-18.4.30.tgz#a85cef0ba6b31aca64f5e21e8a8ba045e0686c48"
-  integrity sha512-IQos0nS29h7iHxA/5Y61Y2ZwUK/SLiDWufmTfat/oqqhE/ggiZEyOxIDLhE6adpX3rUBaYqrrzXS5SMJd+y20Q==
-  dependencies:
-    "@syncfusion/ej2-base" "~18.4.30"
-    "@syncfusion/ej2-compression" "~18.4.30"
-
-"@syncfusion/ej2-file-utils@~18.4.30":
-  version "18.4.30"
-  resolved "https://registry.yarnpkg.com/@syncfusion/ej2-file-utils/-/ej2-file-utils-18.4.30.tgz#2b468d641be524a7a045e13c31f9fbc4d02ba206"
-  integrity sha512-Iwqx3D6fbAN+remo0zgGf2tzHEM4qgAlPQhLyMFB3PgiREeksbJrnoA8DvZBo2DmMbDnZZrgd0hWRyHNKV9nFQ==
-
-"@syncfusion/ej2-grids@18.4.31":
-  version "18.4.31"
-  resolved "https://registry.yarnpkg.com/@syncfusion/ej2-grids/-/ej2-grids-18.4.31.tgz#ba920f0b5f33ac4e7f552095546760226ad19d92"
-  integrity sha512-sF3+V5qsDTetYMs2ZVm/ETeGAP0iweGBnDntNFaEs01LswKmHIe9w86Qx9aD7eWVt0m59scuRs0d+Johm7vw2Q==
-  dependencies:
-    "@syncfusion/ej2-base" "~18.4.31"
-    "@syncfusion/ej2-buttons" "~18.4.30"
-    "@syncfusion/ej2-calendars" "~18.4.31"
-    "@syncfusion/ej2-compression" "~18.4.30"
-    "@syncfusion/ej2-data" "~18.4.30"
-    "@syncfusion/ej2-dropdowns" "~18.4.31"
-    "@syncfusion/ej2-excel-export" "~18.4.30"
-    "@syncfusion/ej2-file-utils" "~18.4.30"
-    "@syncfusion/ej2-inputs" "~18.4.31"
-    "@syncfusion/ej2-lists" "~18.4.30"
-    "@syncfusion/ej2-navigations" "~18.4.31"
-    "@syncfusion/ej2-pdf-export" "~18.4.30"
-    "@syncfusion/ej2-popups" "~18.4.30"
-    "@syncfusion/ej2-splitbuttons" "~18.4.31"
-
-"@syncfusion/ej2-icons@~18.4.30":
-  version "18.4.30"
-  resolved "https://registry.yarnpkg.com/@syncfusion/ej2-icons/-/ej2-icons-18.4.30.tgz#658f517a8163f0614453f9d420d0af03601ab9ee"
-  integrity sha512-kUSNE0xglgwXdIsfXFpa4so9hLRUkvxEsSbZIZhhrJrc7Z8Y3Y7O8HUM9+rIJzY6cLG8KWy+A8tBO9qVADujfQ==
-
-"@syncfusion/ej2-inputs@~18.4.31":
-  version "18.4.31"
-  resolved "https://registry.yarnpkg.com/@syncfusion/ej2-inputs/-/ej2-inputs-18.4.31.tgz#cc536c781979a9a73c82be52f1e49fd553b5c224"
-  integrity sha512-I61oUtvrFb572yTrN3cdf99MU3i4Z1eOXqfBJrsyKc9kMGKYGXmqECJK6Zvu0+Z2gvHq8og0EbgO8WzGlNccug==
-  dependencies:
-    "@syncfusion/ej2-base" "~18.4.31"
-    "@syncfusion/ej2-buttons" "~18.4.30"
-    "@syncfusion/ej2-popups" "~18.4.30"
-    "@syncfusion/ej2-splitbuttons" "~18.4.31"
-
-"@syncfusion/ej2-lists@~18.4.30":
-  version "18.4.30"
-  resolved "https://registry.yarnpkg.com/@syncfusion/ej2-lists/-/ej2-lists-18.4.30.tgz#8b0352b502a8de9a6af1101b9711a91db4a2cf54"
-  integrity sha512-y9K33QyxHw9k/CcjtJUlgsegHyBQjkJcG+Q/+kWICTkn9PtgjZbhG8ipmgHMV59WAy4v8G4eOR1Aw2APZlPMLw==
-  dependencies:
-    "@syncfusion/ej2-base" "~18.4.30"
-    "@syncfusion/ej2-buttons" "~18.4.30"
-    "@syncfusion/ej2-data" "~18.4.30"
-
-"@syncfusion/ej2-navigations@~18.4.31":
-  version "18.4.31"
-  resolved "https://registry.yarnpkg.com/@syncfusion/ej2-navigations/-/ej2-navigations-18.4.31.tgz#984c8d1e6bddbbfcf0145dc83bb8533ed402fe5c"
-  integrity sha512-jq1BsnsH8wX7KkPeSscU+mdA/1KmRZho8Ks8lny+K15pvIOuRsehtqLGBXi8Fav46MIXIFz9TZ7Vrhpo/PyzDA==
-  dependencies:
-    "@syncfusion/ej2-base" "~18.4.31"
-    "@syncfusion/ej2-buttons" "~18.4.30"
-    "@syncfusion/ej2-data" "~18.4.30"
-    "@syncfusion/ej2-inputs" "~18.4.31"
-    "@syncfusion/ej2-lists" "~18.4.30"
-    "@syncfusion/ej2-popups" "~18.4.30"
-
-"@syncfusion/ej2-pdf-export@~18.4.30":
-  version "18.4.30"
-  resolved "https://registry.yarnpkg.com/@syncfusion/ej2-pdf-export/-/ej2-pdf-export-18.4.30.tgz#764a30365e95090a6b5aab6619f10afc86764b1c"
-  integrity sha512-rDltaJtGcF0lPOK4ZbKt6pLW2GvLeGwKYvUfxcHajOTsv7XxwfWVZsKIAws2MLqwZ8ZRZnAXfLzJTmgtjmdt9A==
-  dependencies:
-    "@syncfusion/ej2-compression" "~18.4.30"
-
-"@syncfusion/ej2-popups@~18.4.30":
-  version "18.4.30"
-  resolved "https://registry.yarnpkg.com/@syncfusion/ej2-popups/-/ej2-popups-18.4.30.tgz#4a13399500660d07462c0c743d2066ec0e046261"
-  integrity sha512-APNzfUuWkM5lywV6/+/DYQGePMj/JhoAlrYI9OO8GNSMZj8xtSnWSkybUVLJyIgPQfh5B3YP7TsV1bjTC6fhXg==
-  dependencies:
-    "@syncfusion/ej2-base" "~18.4.30"
-    "@syncfusion/ej2-buttons" "~18.4.30"
-
-"@syncfusion/ej2-splitbuttons@~18.4.31":
-  version "18.4.31"
-  resolved "https://registry.yarnpkg.com/@syncfusion/ej2-splitbuttons/-/ej2-splitbuttons-18.4.31.tgz#ba02fda03f664f099e7ac16d3c5672d05108c30d"
-  integrity sha512-GJ/eaWCCNZlWoTXWO4u9Nax6e0pgGObowJ2kk+E8l6PfYXSp3w99ze7pwmRXxSaSWXwBL1jxY4j4GD6ewoyNNg==
-  dependencies:
-    "@syncfusion/ej2-base" "~18.4.31"
-    "@syncfusion/ej2-popups" "~18.4.30"
-
-"@syncfusion/ej2-vue-base@~18.4.30":
-  version "18.4.30"
-  resolved "https://registry.yarnpkg.com/@syncfusion/ej2-vue-base/-/ej2-vue-base-18.4.30.tgz#9df8e102ce8ed5054acb1044a792512334492b48"
-  integrity sha512-FHFwF5RECj1mtjmFjIpRpxljI9zGThbexcDOg31ZRQ0WzuohZR7uyrsp50PcLLgnTqvQQv4F1ctpCI7RwXYAjw==
-  dependencies:
-    "@syncfusion/ej2-base" "~18.4.30"
-
-"@syncfusion/ej2-vue-grids@^18.4.30":
-  version "18.4.31"
-  resolved "https://registry.yarnpkg.com/@syncfusion/ej2-vue-grids/-/ej2-vue-grids-18.4.31.tgz#ce6cd13282c5be9b8161eec57678759ef945470e"
-  integrity sha512-O1D8r3r/a6XNGrzXm8elMX7IsqCJwcasCPz+Jv0VFX+WKKcPi1JtyIIeE6xS/etmqV2544NotKJk01EQsmdq5A==
-  dependencies:
-    "@syncfusion/ej2-base" "~18.4.31"
-    "@syncfusion/ej2-grids" "18.4.31"
-    "@syncfusion/ej2-vue-base" "~18.4.30"
-
 "@types/anymatch@*":
   version "1.3.1"
   resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a"
@@ -2537,12 +2391,12 @@
   optionalDependencies:
     prettier "^1.18.2"
 
-"@vue/composition-api@1.0.0-rc.1":
-  version "1.0.0-rc.1"
-  resolved "https://registry.yarnpkg.com/@vue/composition-api/-/composition-api-1.0.0-rc.1.tgz#d5286bbaffcd1987e56d5e3a9f26bfb6023e7c41"
-  integrity sha512-6I5LkfA+VvVOLZufRugzQ5sWKQH81/Cr9gRLidDSeUmjRPolEEWgG4MAnWtBR5zgP5qbRMwZJ4IEYtKhnadMQQ==
+"@vue/composition-api@1.0.0-rc.3":
+  version "1.0.0-rc.3"
+  resolved "https://registry.yarnpkg.com/@vue/composition-api/-/composition-api-1.0.0-rc.3.tgz#5174632fdda888f4f04bbaa5263cf01e34ba3fc2"
+  integrity sha512-/N/yCgIeFwAdsChML1RAke7YT5v/LYnPOyrz2zU+fE6xx2MpZfWn+DD2wCf3Vre659AvuXA8zzKLlRaFzW75XQ==
   dependencies:
-    tslib "^2.0.3"
+    tslib "^2.1.0"
 
 "@vue/test-utils@^1.1.0":
   version "1.1.1"
@@ -2553,10 +2407,10 @@
     lodash "^4.17.15"
     pretty "^2.0.0"
 
-"@vuex-orm/core@1.0.0-draft.8":
-  version "1.0.0-draft.8"
-  resolved "https://registry.yarnpkg.com/@vuex-orm/core/-/core-1.0.0-draft.8.tgz#3122ca7aff6f651a26e29de850f76404ad2686a6"
-  integrity sha512-pGfuHK+53Qh5S5Y5Pko5NhQPYJapO1V87KIeHQAX8twbcxPJUgZw6HTRVLUogrJ7WHtKcv6XbpPQgvE29UOE2Q==
+"@vuex-orm/core@1.0.0-draft.9":
+  version "1.0.0-draft.9"
+  resolved "https://registry.yarnpkg.com/@vuex-orm/core/-/core-1.0.0-draft.9.tgz#a0c7bbeecdf32aef9d841553d1a100305ecae542"
+  integrity sha512-23X0Yc8UFYnVk+Obq0Eho3nArMpPux38oDmMwXGbivCKIfm8FUI2QloZbp8gKpHBRyTCg9cQO1fP2LXN+YvlrQ==
   dependencies:
     "@types/uuid" "^8.0.0"
     normalizr "^3.6.1"
@@ -5385,6 +5239,11 @@ estraverse@^5.1.0, estraverse@^5.2.0:
   resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880"
   integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==
 
+estree-walker@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
+  integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
+
 esutils@^2.0.2:
   version "2.0.3"
   resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
@@ -7761,6 +7620,11 @@ lodash.clonedeep@^4.5.0:
   resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
   integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
 
+lodash.difference@^4.5.0:
+  version "4.5.0"
+  resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c"
+  integrity sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=
+
 lodash.get@^4.4.2:
   version "4.4.2"
   resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
@@ -7872,6 +7736,13 @@ lru-cache@^6.0.0:
   dependencies:
     yallist "^4.0.0"
 
+magic-string@^0.25.7:
+  version "0.25.7"
+  resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051"
+  integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==
+  dependencies:
+    sourcemap-codec "^1.4.4"
+
 make-dir@^1.0.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"
@@ -8196,6 +8067,33 @@ mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@~0.5.1:
   dependencies:
     minimist "^1.2.5"
 
+moment-locales-webpack-plugin@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/moment-locales-webpack-plugin/-/moment-locales-webpack-plugin-1.2.0.tgz#9af83876a44053706b868ceece5119584d10d7aa"
+  integrity sha512-QAi5v0OlPUP7GXviKMtxnpBAo8WmTHrUNN7iciAhNOEAd9evCOvuN0g1N7ThIg3q11GLCkjY1zQ2saRcf/43nQ==
+  dependencies:
+    lodash.difference "^4.5.0"
+
+moment-timezone-data-webpack-plugin@^1.3.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/moment-timezone-data-webpack-plugin/-/moment-timezone-data-webpack-plugin-1.4.0.tgz#78ff6af8055a98fcda8f7452d905e21d98f0b6af"
+  integrity sha512-tBCIpTT0FARkMoNW+wT67r4d/Yavr3e3iyLsM+rGdYlrsp6LkCI0WoKLGtI4yoNWMBh3AATs+4fLnVyjx6/Afg==
+  dependencies:
+    find-cache-dir "^3.0.0"
+    make-dir "^3.0.0"
+
+moment-timezone@^0.5.28:
+  version "0.5.33"
+  resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.33.tgz#b252fd6bb57f341c9b59a5ab61a8e51a73bbd22c"
+  integrity sha512-PTc2vcT8K9J5/9rDEPe5czSIKgLoGsH8UNpA4qZTVw0Vd/Uz19geE9abbIOQKaAQFcnQ3v5YEXrbSc5BpshH+w==
+  dependencies:
+    moment ">= 2.9.0"
+
+"moment@>= 2.9.0", moment@^2.25.3:
+  version "2.29.1"
+  resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
+  integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
+
 move-concurrently@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
@@ -10874,6 +10772,11 @@ source-map@^0.7.3:
   resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
   integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
 
+sourcemap-codec@^1.4.4:
+  version "1.4.8"
+  resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
+  integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
+
 spdx-correct@^3.0.0:
   version "3.1.1"
   resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9"
@@ -11549,7 +11452,7 @@ tslib@^2.0.1:
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.3.tgz#8e0741ac45fc0c226e58a17bfc3e64b9bc6ca61c"
   integrity sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==
 
-tslib@^2.0.3:
+tslib@^2.0.3, tslib@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
   integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
@@ -11652,6 +11555,11 @@ uc.micro@^1.0.1, uc.micro@^1.0.5:
   resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac"
   integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==
 
+ufo@^0.6.9:
+  version "0.6.9"
+  resolved "https://registry.yarnpkg.com/ufo/-/ufo-0.6.9.tgz#9f1f830d11ec059e957149002cbd1d34b3ddeab0"
+  integrity sha512-+Yr0CwPqrug7Svt6zZRhx+WcxGZaOws0JlWB+NHKCp+BOnds9jHFFyTYeigpRWGRDZDf1LiBKl2x5WbWhGhBVQ==
+
 uglify-js@^2.6.1:
   version "2.8.29"
   resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd"
@@ -11977,6 +11885,11 @@ vue-hot-reload-api@^2.3.0:
   resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz#532955cc1eb208a3d990b3a9f9a70574657e08f2"
   integrity sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==
 
+vue-i18n-composable@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/vue-i18n-composable/-/vue-i18n-composable-0.2.1.tgz#51c67f6b2aba23b8585643d9b7db376c6d5872d7"
+  integrity sha512-Z7hqOWeHQMgadV6IBX6yLtsl775QJ7fjBdsj+/QgwpDqB1XpiKm/TDxt5cJihsUlkUyddwh1O3vBMka6WkPYxQ==
+
 vue-i18n@^8.18.1:
   version "8.22.3"
   resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-8.22.3.tgz#4ac0fdc3e71d4fe188938c40a9ffca32cde60732"