浏览代码

Merge branch 'release/0.1.1'

Vincent GUFFON 4 年之前
父节点
当前提交
c7e3d74ead
共有 100 个文件被更改,包括 2149 次插入1433 次删除
  1. 2 10
      assets/css/global.scss
  2. 0 44
      components/Form/BottomSheetComponent.vue
  3. 0 115
      components/Form/FormComponent.vue
  4. 0 61
      components/Form/Input/CheckboxComponent.vue
  5. 0 82
      components/Form/Input/InputComponent.vue
  6. 0 89
      components/Form/Input/SelectComponent.vue
  7. 0 61
      components/Form/Input/TextComponent.vue
  8. 36 0
      components/Layout/BannerTop.vue
  9. 0 0
      components/Layout/Container.vue
  10. 6 6
      components/Layout/Header.vue
  11. 0 0
      components/Layout/HeaderMenu.vue
  12. 0 0
      components/Layout/Menu.vue
  13. 1 1
      components/Layout/Notification.vue
  14. 35 0
      components/Ui/Card.vue
  15. 11 16
      components/Ui/DataTable.vue
  16. 0 0
      components/Ui/ExpansionPanel.vue
  17. 228 0
      components/Ui/Form.vue
  18. 46 0
      components/Ui/Input/Checkbox.vue
  19. 17 27
      components/Ui/Input/DatePicker.vue
  20. 81 0
      components/Ui/Input/Enum.vue
  21. 65 0
      components/Ui/Input/Text.vue
  22. 69 0
      components/Ui/SubList.vue
  23. 1 1
      config/nuxtConfig/build.js
  24. 8 0
      config/nuxtConfig/env.js
  25. 4 4
      config/nuxtConfig/modules.js
  26. 5 2
      config/nuxtConfig/plugins.js
  27. 7 3
      layouts/default.vue
  28. 3 7
      models/Core/AddressPostal.ts
  29. 1 2
      models/Core/BankAccount.ts
  30. 1 2
      models/Core/ContactPoint.ts
  31. 1 2
      models/Core/Country.ts
  32. 3 10
      models/Model.ts
  33. 4 1
      models/Organization/Organization.ts
  34. 2 3
      models/Organization/OrganizationAddressPostal.ts
  35. 1 2
      models/Organization/OrganizationLicence.ts
  36. 1 2
      models/Organization/OrganizationNetwork.ts
  37. 1 0
      nuxt.config.js
  38. 11 5
      package.json
  39. 1 1
      pages/index.vue
  40. 1 0
      pages/login.vue
  41. 42 0
      pages/organization.vue
  42. 105 0
      pages/organization/address/_id.vue
  43. 0 469
      pages/organization/edit.vue
  44. 382 0
      pages/organization/index.vue
  45. 19 0
      plugins/Data/axios.js
  46. 12 0
      plugins/Data/dataPersister.ts
  47. 12 0
      plugins/Data/dataProvider.ts
  48. 0 20
      plugins/Queries/http.js
  49. 0 9
      plugins/Queries/rest.ts
  50. 8 0
      plugins/helpersInit.ts
  51. 20 0
      plugins/route.ts
  52. 48 0
      services/connection/connection.ts
  53. 61 0
      services/connection/constructUrl.ts
  54. 71 0
      services/dataPersister/dataPersister.ts
  55. 4 0
      services/dataPersister/hook/_import.ts
  56. 14 0
      services/dataPersister/hook/baseHook.ts
  57. 31 0
      services/dataPersister/hook/hook_example.ts
  58. 42 42
      services/dataProvider/dataProvider.ts
  59. 0 40
      services/dataProvider/enumDataProvider.ts
  60. 9 0
      services/dataProvider/provider/_import.ts
  61. 40 0
      services/dataProvider/provider/baseProvider.ts
  62. 20 0
      services/dataProvider/provider/defaultProvider.ts
  63. 39 0
      services/dataProvider/provider/enumProvider.ts
  64. 5 0
      services/dataProvider/provider/hook/_import.ts
  65. 14 0
      services/dataProvider/provider/hook/baseHook.ts
  66. 31 0
      services/dataProvider/provider/hook/hook_example.ts
  67. 29 0
      services/dataProvider/provider/modelProvider.ts
  68. 1 1
      services/profile/accessProfile.ts
  69. 1 1
      services/profile/organizationProfile.ts
  70. 0 29
      services/queries/rest.ts
  71. 5 3
      services/rights/abilitiesUtils.ts
  72. 1 1
      services/rights/roleUtils.ts
  73. 7 0
      services/serializer/denormalizer/_import.ts
  74. 12 0
      services/serializer/denormalizer/baseDenormalizer.ts
  75. 118 0
      services/serializer/denormalizer/hydra.ts
  76. 32 0
      services/serializer/denormalizer/yaml.ts
  77. 5 0
      services/serializer/normalizer/_import.ts
  78. 12 0
      services/serializer/normalizer/baseNormalizer.ts
  79. 14 0
      services/serializer/normalizer/model.ts
  80. 24 0
      services/serializer/serializer.ts
  81. 0 112
      services/utils/hydraParser.ts
  82. 1 1
      services/utils/objectProperties.ts
  83. 0 27
      services/utils/yamlParser.ts
  84. 23 0
      store/form.ts
  85. 6 1
      store/index.js
  86. 1 1
      store/profile/access.ts
  87. 1 1
      store/profile/organization.ts
  88. 7 1
      tsconfig.json
  89. 23 0
      types/enums.ts
  90. 128 0
      types/interfaces.d.ts
  91. 1 85
      types/types.d.ts
  92. 0 21
      use/form/useFormInputSetup.ts
  93. 8 2
      use/form/utils.ts
  94. 1 1
      use/layout/Menus/accessMenu.ts
  95. 1 1
      use/layout/Menus/accountMenu.ts
  96. 1 1
      use/layout/Menus/admin2iosMenu.ts
  97. 1 1
      use/layout/Menus/agendaMenu.ts
  98. 1 1
      use/layout/Menus/baseMenu.ts
  99. 1 1
      use/layout/Menus/billingMenu.ts
  100. 1 1
      use/layout/Menus/communicationMenu.ts

+ 2 - 10
assets/css/global.scss

@@ -10,18 +10,10 @@ header .v-toolbar__content{
 }
 
 .no-decoration{
-  text-decoration: none;
+  text-decoration: none !important;
+  color: inherit !important;
 }
 
 .margin-bottom-20{
   margin-bottom: 20px;
 }
-
-.form_main_title{
-  width: 100%;
-  .editBtn{
-    float: right;
-    margin-right: 20px;
-  }
-
-}

+ 0 - 44
components/Form/BottomSheetComponent.vue

@@ -1,44 +0,0 @@
-<template>
-  <div class="text-center">
-    <v-bottom-sheet
-      v-model="openSheet"
-      persistent
-    >
-      <v-sheet
-        class="text-center"
-      >
-        <slot></slot>
-
-        <v-btn
-          text
-          color="error"
-          @click="$emit('close-bottom-sheet', false)"
-        >
-          Fermer
-        </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>

+ 0 - 115
components/Form/FormComponent.vue

@@ -1,115 +0,0 @@
-<template>
-  <v-form
-    ref="form"
-    v-model="properties.valid"
-    lazy-validation
-  >
-    <slot name="form.input" v-bind="{entry}"></slot>
-<!--{{entry}}-->
-
-    <v-container fluid class="container">
-      <v-row>
-        <v-col cols="12" sm="12">
-          <v-btn v-if="!readOnly" class="mr-4 submitBtn ot_green ot_white--text" @click="submit">
-            Enregistrer
-          </v-btn>
-          <v-btn v-if="!readOnly" class="mr-4 submitBtn ot_danger ot_white--text" @click="submit">
-            Annuler
-          </v-btn>
-        </v-col>
-      </v-row>
-    </v-container>
-  </v-form>
-</template>
-
-<script lang="ts">
-  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<Model>,
-        required: true
-      },
-      id:{
-        type: Number,
-        required: true
-      },
-      query:{
-        type: Object as () => Query,
-        required: true
-      },
-    },
-    setup(props) {
-      const {repository, id, query} = toRefs(props)
-      const properties = reactive({
-        valid: false,
-        saveOk: false,
-        saveKo: false
-      })
-
-      const {store} = useContext();
-      const readOnly = computed(() => {
-        return 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 {
-        submit,
-        properties,
-        readOnly,
-        entry
-      }
-    },
-    // 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 {
-    right: 0;
-    margin-top: 20px;
-    margin-bottom: 20px;
-  }
-</style>

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

@@ -1,61 +0,0 @@
-<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>

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

@@ -1,82 +0,0 @@
-<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>

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

@@ -1,89 +0,0 @@
-<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>

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

@@ -1,61 +0,0 @@
-<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>

+ 36 - 0
components/Layout/BannerTop.vue

@@ -0,0 +1,36 @@
+<template>
+  <v-row justify="center" align="center" class="bannerTopForm">
+    <v-col cols="3" class="ot_dark_grey ot_white--text">
+      <slot name="bloc1"></slot>
+    </v-col>
+    <v-col cols="6" class="ot_white ot_grey--text">
+      <slot name="bloc2"></slot>
+    </v-col>
+    <v-col cols="3" class="ot_light_grey ot_grey--text">
+      <slot name="bloc3"></slot>
+    </v-col>
+  </v-row>
+</template>
+
+<script lang="ts">
+  import {defineComponent} from '@nuxtjs/composition-api'
+
+  export default defineComponent({
+    setup() {
+      return {
+      }
+    }
+  })
+</script>
+
+<style scoped>
+  .bannerTopForm{
+    min-height: 100px;
+    margin-top: 10px !important;
+    margin-bottom: 10px !important;
+  }
+  .bannerTopForm > .col{
+    min-height: 100px;
+    padding: 10px;
+  }
+</style>

+ 0 - 0
components/Layout/ContainerComponent.vue → components/Layout/Container.vue


+ 6 - 6
components/Layout/HeaderComponent.vue → components/Layout/Header.vue

@@ -33,17 +33,17 @@
       <NuxtLink to="/" class="no-decoration"><v-icon class="ot_white--text" small>fa-home</v-icon></NuxtLink>
     </v-btn>
 
-    <HeaderMenuComponent :menu="properties.webSiteMenu"></HeaderMenuComponent>
+    <LayoutHeaderMenu :menu="properties.webSiteMenu"></LayoutHeaderMenu>
 
-    <HeaderMenuComponent :menu="properties.myAccessesMenu" v-if="properties.hasAccessesMenu"></HeaderMenuComponent>
+    <LayoutHeaderMenu :menu="properties.myAccessesMenu" v-if="properties.hasAccessesMenu"></LayoutHeaderMenu>
 
-    <HeaderMenuComponent :menu="properties.myFamilyMenu" v-if="properties.hasFamilyMenu"></HeaderMenuComponent>
+    <LayoutHeaderMenu :menu="properties.myFamilyMenu" v-if="properties.hasFamilyMenu"></LayoutHeaderMenu>
 
-    <NotificationComponent></NotificationComponent>
+    <LayoutNotification></LayoutNotification>
 
-    <HeaderMenuComponent :menu="properties.configurationMenu" v-if="properties.hasConfigurationMenu"></HeaderMenuComponent>
+    <LayoutHeaderMenu :menu="properties.configurationMenu" v-if="properties.hasConfigurationMenu"></LayoutHeaderMenu>
 
-    <HeaderMenuComponent :menu="properties.accountMenu" :avatar="true"></HeaderMenuComponent>
+    <LayoutHeaderMenu :menu="properties.accountMenu" :avatar="true"></LayoutHeaderMenu>
 
     <a class="help ot_dark_grey ot_menu_color--text" href="https://support.opentalent.fr/" target="_blank">{{$t('help_access')}}</a>
 

+ 0 - 0
components/Layout/HeaderMenuComponent.vue → components/Layout/HeaderMenu.vue


+ 0 - 0
components/Layout/MenuComponent.vue → components/Layout/Menu.vue


+ 1 - 1
components/Layout/NotificationComponent.vue → components/Layout/Notification.vue

@@ -26,7 +26,7 @@
 <script lang="ts">
   import {$useMenu} from '@/use/layout/menu'
   import {defineComponent, reactive} from '@nuxtjs/composition-api'
-  import {AnyJson} from "~/types/types";
+  import {AnyJson} from "~/types/interfaces";
 
   export default defineComponent({
     setup() {

+ 35 - 0
components/Ui/Card.vue

@@ -0,0 +1,35 @@
+<template>
+  <v-card
+    elevation="2"
+    outlined
+    shaped
+    min-height="200"
+  >
+    <v-card-title>
+      <slot name="card.title"></slot>
+    </v-card-title>
+    <v-card-text>
+      <slot name="card.text"></slot>
+    </v-card-text>
+    <v-card-actions>
+      <v-spacer></v-spacer>
+      <slot name="card.action"></slot>
+    </v-card-actions>
+  </v-card>
+</template>
+
+<script lang="ts">
+  import {defineComponent} from '@nuxtjs/composition-api'
+
+  export default defineComponent({
+    props: {
+    },
+    setup(props) {
+      return {
+
+      }
+    }
+  })
+</script>
+<style scoped>
+</style>

+ 11 - 16
components/Form/DataTableComponent.vue → components/Ui/DataTable.vue

@@ -3,10 +3,6 @@
       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"
@@ -44,9 +40,10 @@
 <script lang="ts">
   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 {AnyJson} from "~/types/interfaces";
   import {useQueryHelper} from "~/use/store/useQuery";
+  import {QUERY_TYPE} from "~/types/enums";
+  import {Organization} from "~/models/Organization/Organization";
 
   export default defineComponent({
     props: {
@@ -85,24 +82,23 @@
       const entries = ref([] as Array<AnyJson>)
       const loading = ref(true)
 
-      const {store, $rest} = useContext()
+      const {$dataProvider} = useContext()
       const {fetch, fetchState} = useFetch(async ()=>{
-        await $dataProvider(store, $rest).getSubResourceCollection(
-          rootModel.value,
-          rootId.value,
-          model.value
-        )
+        await $dataProvider.invoke({
+          type: QUERY_TYPE.MODEL,
+          model: model.value,
+          root_model: rootModel.value,
+          root_id: rootId.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) )
@@ -113,8 +109,7 @@
         loading,
         headersWithItem,
         editItem,
-        itemId,
-        openSheet
+        itemId
       }
     }
   })

+ 0 - 0
components/Form/ExpansionPanelComponent.vue → components/Ui/ExpansionPanel.vue


+ 228 - 0
components/Ui/Form.vue

@@ -0,0 +1,228 @@
+<template>
+  <main>
+    <v-form
+      ref="form"
+      v-model="properties.valid"
+      lazy-validation
+      :readonly="readOnly"
+    >
+      <v-container fluid class="container btnActions">
+        <v-row>
+          <v-col cols="12" sm="12">
+            <slot name="form.button"></slot>
+            <v-btn v-if="!readOnly" class="mr-4 ot_green ot_white--text" @click="submit">
+              Enregistrer
+            </v-btn>
+          </v-col>
+        </v-row>
+      </v-container>
+
+      <slot name="form.input" v-bind="{entry,updateRepository}"></slot>
+
+      <v-container fluid class="container btnActions">
+        <v-row>
+          <v-col cols="12" sm="12">
+            <slot name="form.button"></slot>
+            <v-btn v-if="!readOnly" class="mr-4 ot_green ot_white--text" @click="submit">
+              Enregistrer
+            </v-btn>
+          </v-col>
+        </v-row>
+      </v-container>
+    </v-form>
+
+    <div class="text-center">
+      <v-dialog
+        v-model="dialog"
+        width="500"
+      >
+        <v-card>
+          <v-card-title class="text-h5 grey lighten-2">
+            Attention
+          </v-card-title>
+
+          <v-card-text>
+            <br>
+            <p>Vous souhaitez quitter ce formulaire sans avoir enregistré</p>
+          </v-card-text>
+
+          <v-divider></v-divider>
+
+          <v-card-actions>
+            <v-spacer></v-spacer>
+            <v-btn class="mr-4 submitBtn ot_danger ot_white--text" @click="closeDialogs">
+              Retour
+            </v-btn>
+            <v-btn class="mr-4 submitBtn ot_green ot_white--text" @click="goEvenUnsavedData">
+              Continuer
+            </v-btn>
+          </v-card-actions>
+        </v-card>
+      </v-dialog>
+    </div>
+  </main>
+</template>
+
+<script lang="ts">
+  import {defineComponent, reactive, useContext, computed, toRefs, onBeforeUnmount, onBeforeMount} from '@nuxtjs/composition-api'
+  import {useRepositoryHelper} from "~/use/store/useRepository";
+  import {useQueryHelper} from "~/use/store/useQuery";
+  import {Query} from "@vuex-orm/core";
+  import {QUERY_TYPE} from "~/types/enums";
+
+  export default defineComponent({
+    props: {
+      model: {
+        type: Function,
+        required: true
+      },
+      id: {
+        type: Number,
+        required: true
+      },
+      query: {
+        type: Object as () => Query,
+        required: true
+      },
+    },
+    setup: function (props) {
+      const {$dataPersister, store, app} = useContext()
+
+      const {id, query} = toRefs(props)
+      const repository = useRepositoryHelper.getRepository(props.model)
+      const properties = reactive({
+        valid: false,
+        saveOk: false,
+        saveKo: false
+      })
+
+      const readOnly = computed(() => {
+        return false
+      })
+
+      const entry = computed(() => {
+        return useQueryHelper.getFlattenEntry(query.value, id.value)
+      })
+
+      const handler = getEventHandler()
+
+      const updateRepository = (newValue: string, field: string) => {
+        addEventListener(handler)
+        store.commit('form/setDirty', true)
+        useRepositoryHelper.updateStoreFromField(repository, entry.value, newValue, field)
+      }
+
+      const dialog = computed(() => {
+        return store.state.form.showConfirmToLeave
+      })
+
+      const closeDialogs = () => {
+        store.commit('form/setShowConfirmToLeave', false)
+      }
+
+      const goEvenUnsavedData = () => {
+        store.commit('form/setDirty', false)
+        store.commit('form/setShowConfirmToLeave', false)
+
+        const entryCopy = query.value.first()
+        if (entryCopy && entryCopy.$getAttributes()['originalState']) {
+          useRepositoryHelper.updateStore(repository, entryCopy.$getAttributes()['originalState'])
+        }
+
+        if (app.router) {
+          app.router.push(store.state.form.goAfterLeave)
+        }
+      }
+
+      onBeforeMount(() => {
+        clearEventListener(handler)
+      })
+
+      onBeforeUnmount(() => {
+        clearEventListener(handler)
+      })
+
+      const submit = async () => {
+        try {
+          store.commit('form/setDirty', false)
+          clearEventListener(handler)
+
+          await $dataPersister.invoke({
+            type: QUERY_TYPE.MODEL,
+            model: props.model,
+            id: id.value
+          })
+        } catch (error) {
+          console.log('aie aie aie')
+        }
+      }
+
+      return {
+        submit,
+        updateRepository,
+        properties,
+        readOnly,
+        dialog,
+        entry,
+        goEvenUnsavedData,
+        closeDialogs,
+      }
+    },
+    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)
+      //     }
+      //   }
+      // }
+    }
+  })
+
+  function getEventHandler() {
+    return function (e: any) {
+      // Cancel the event
+      e.preventDefault();
+      // Chrome requires returnValue to be set
+      e.returnValue = '';
+    };
+  }
+
+  function addEventListener(handler: any) {
+    if (process.browser) {
+      window.addEventListener('beforeunload', handler);
+    }
+  }
+
+  function clearEventListener(handler: any) {
+    if (process.browser) {
+      window.removeEventListener('beforeunload', handler);
+    }
+  }
+
+</script>
+
+<style scoped>
+  .btnActions {
+    text-align: right;
+  }
+</style>

+ 46 - 0
components/Ui/Input/Checkbox.vue

@@ -0,0 +1,46 @@
+<template>
+  <v-container
+    class="px-0"
+    fluid
+  >
+    <v-checkbox
+      :value="data"
+      :label="$t(label_field)"
+      @change="$emit('update', $event, field)"
+      :disabled="readOnly"
+    ></v-checkbox>
+  </v-container>
+</template>
+
+<script lang="ts">
+  import {defineComponent} from '@nuxtjs/composition-api'
+
+  export default defineComponent({
+    props: {
+      field: {
+        type: String,
+        required: false
+      },
+      label: {
+        type: String,
+        required: false
+      },
+      data: {
+        type: Boolean,
+        required: false
+      },
+      readOnly: {
+        type: Boolean,
+        required: false
+      },
+    },
+    setup(props){
+      return {
+        label_field : props.label ?? props.field,
+      }
+    }
+  })
+</script>
+
+<style scoped>
+</style>

+ 17 - 27
components/Form/Input/DatePickerComponent.vue → components/Ui/Input/DatePicker.vue

@@ -28,46 +28,37 @@
 
 
 <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";
+  import {defineComponent, watch, ref, useContext, onUnmounted} from '@nuxtjs/composition-api'
 
   export default defineComponent({
     props: {
-      repository: {
-        type: Object as () => Repository<Model>,
-        required: true
-      },
-      entry:{
-        type: Object,
-        required: true
-      },
       field: {
         type: String,
-        required: true
+        required: false
       },
       label: {
         type: String,
         required: false
-      }
+      },
+      data: {
+        type: String,
+        required: false
+      },
+      readOnly: {
+        type: Boolean,
+        required: false
+      },
     },
-    setup(props){
-      const {label, field, repository } = props
-      const entry = toRef(props, 'entry')
-
+    setup(props, {emit}){
+      const {data, field} = props
       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 dateFormatted = ref($moment(data).format('DD/MM/YYYY'))
+      const dateParsed = ref($moment(data).format('YYYY-MM-DD'))
 
       const unwatch = watch(dateParsed, (newValue) => {
         dateFormatted.value = $moment(newValue).format('DD/MM/YYYY')
-        useRepositoryHelper.updateStoreFromField(repository, entry.value, newValue, field)
+        emit('update', newValue, field)
       })
 
       onUnmounted(()=>{
@@ -75,8 +66,7 @@
       })
 
       return {
-        label_field,
-        readOnly,
+        label_field : props.label ?? props.field,
         dateParsed,
         dateFormatted,
         dateOpen: false

+ 81 - 0
components/Ui/Input/Enum.vue

@@ -0,0 +1,81 @@
+<template>
+  <main>
+    <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="$emit('update', $event, field)"
+      :rules="rules"
+      :disabled="readOnly"
+    ></v-select>
+  </main>
+</template>
+
+<script lang="ts">
+  import {defineComponent, ref, useContext, useFetch} from '@nuxtjs/composition-api'
+  import {AnyJson} from "~/types/interfaces";
+  import {QUERY_TYPE} from "~/types/enums";
+
+  export default defineComponent({
+    props: {
+      enumType: {
+        type: String,
+        required: true
+      },
+      label:{
+        type: String,
+        required: false
+      },
+      field:{
+        type: String,
+        required: false
+      },
+      data: {
+        type: String,
+        required: false
+      },
+      readOnly: {
+        type: Boolean,
+        required: false
+      },
+      rules: {
+        type: Array,
+        required: false
+      }
+    },
+    setup(props, {emit}){
+      const label_field = props.label ?? props.field
+
+      const loading = ref(true)
+      const { enumType } = props
+      const {$dataProvider} = useContext()
+
+      const items: AnyJson = ref([])
+      const {fetch, fetchState} = useFetch(async () => {
+        items.value = await $dataProvider.invoke({
+          type: QUERY_TYPE.ENUM,
+          enumType: enumType
+        })
+        loading.value = false
+      })
+
+      return {
+        items,
+        label_field,
+        loading
+      }
+    }
+  })
+</script>
+
+<style scoped>
+</style>

+ 65 - 0
components/Ui/Input/Text.vue

@@ -0,0 +1,65 @@
+<template>
+    <v-text-field
+      :value="data"
+      :label="$t(label_field)"
+      @change="$emit('update', $event, field)"
+      :rules="rules"
+      :disabled="readOnly"
+      :type="type"
+      :error="error"
+      :error-messages="errorMessage"
+    >
+    </v-text-field>
+</template>
+
+<script lang="ts">
+  import {defineComponent} from '@nuxtjs/composition-api'
+
+  export default defineComponent({
+    props: {
+      label:{
+        type: String,
+        required: false
+      },
+      field:{
+        type: String,
+        required: false
+      },
+      type:{
+        type: String,
+        required: false
+      },
+      data: {
+        type: String,
+        required: false
+      },
+      readOnly: {
+        type: Boolean,
+        required: false
+      },
+      rules:{
+        type: Array,
+        required: false
+      },
+      error:{
+        type: Boolean,
+        required: false
+      },
+      errorMessage:{
+        type: String,
+        required: false
+      }
+    },
+    setup(props){
+      return {
+        label_field : props.label ?? props.field
+      }
+    }
+  })
+</script>
+
+<style>
+  input:read-only{
+    color: #666 !important;
+  }
+</style>

+ 69 - 0
components/Ui/SubList.vue

@@ -0,0 +1,69 @@
+<template>
+    <main>
+      <v-skeleton-loader
+        type="text"
+        v-if="loading"
+      ></v-skeleton-loader>
+      <div v-else>
+        <slot name="list.item" v-bind="{entries}"></slot>
+      </div>
+      <slot>
+      </slot>
+    </main>
+</template>
+
+<script lang="ts">
+  import {defineComponent, ref, useContext, useFetch, computed, toRefs, onUnmounted} from '@nuxtjs/composition-api'
+  import {Query} from "@vuex-orm/core";
+  import {AnyJson} from "~/types/interfaces";
+  import {useQueryHelper} from "~/use/store/useQuery";
+  import {QUERY_TYPE} from "~/types/enums";
+  import {Organization} from "~/models/Organization/Organization";
+
+  export default defineComponent({
+    props: {
+      rootModel:{
+        type: Function,
+        required: true
+      },
+      rootId:{
+        type: Number,
+        required: true
+      },
+      model:{
+        type: Function,
+        required: true
+      },
+      query:{
+        type: Object as () => Query,
+        required: true
+      }
+    },
+    setup(props) {
+      const {rootModel, rootId, model, query} = toRefs(props);
+      const entries = ref([] as Array<AnyJson>)
+      const loading = ref(true)
+
+      const {$dataProvider} = useContext()
+      const {fetch, fetchState} = useFetch(async ()=>{
+
+        await $dataProvider.invoke({
+          type: QUERY_TYPE.MODEL,
+          model: model.value,
+          root_model: rootModel.value,
+          root_id: rootId.value
+        })
+
+        entries.value = useQueryHelper.getEntries(query.value);
+        loading.value = false
+      })
+
+      // onUnmounted( useRepositoryHelper.cleanRepository(repository.value) )
+
+      return {
+        entries,
+        loading
+      }
+    }
+  })
+</script>

+ 1 - 1
config/nuxtConfig/build.js

@@ -4,7 +4,7 @@ export default {
   // Disable server-side rendering (https://go.nuxtjs.dev/ssr-mode)
   ssr: true,
 
-  // Auto import components (https://go.nuxtjs.dev/config-components)
+  // // Auto import components (https://go.nuxtjs.dev/config-components)
   components: true,
 
   // Build Configuration (https://go.nuxtjs.dev/config-build)

+ 8 - 0
config/nuxtConfig/env.js

@@ -12,12 +12,20 @@ export default {
     http: {
       browserBaseURL: process.env.NODE_ENV !== 'production' ? 'https://local.new.api.opentalent.fr' : 'https://local.new.api.opentalent.fr'
     },
+    axios: {
+      https: true,
+      browserBaseURL: process.env.NODE_ENV !== 'production' ? 'https://local.new.api.opentalent.fr' : 'https://local.new.api.opentalent.fr'
+    },
     baseURL_Legacy: process.env.NODE_ENV !== 'production' ? 'https://local.api.opentalent.fr' : 'https://local.api.opentalent.fr',
     baseURL_adminLegacy: process.env.NODE_ENV !== 'production' ? 'https://local.admin.opentalent.fr/#' : 'https://admin.opentalent.fr/#',
     baseURL_typo3: process.env.NODE_ENV !== 'production' ? `https://local.sub.opentalent.fr/###subDomain###` : `https://###subDomain###.opentalent.fr/#`,
   },
   privateRuntimeConfig: {
     http: {
+      https:true,
+      baseURL: process.env.NODE_ENV !== 'production' ? 'http://nginx_new' : 'https://local.api.opentalent.fr'
+    },
+    axios: {
       baseURL: process.env.NODE_ENV !== 'production' ? 'http://nginx_new' : 'https://local.api.opentalent.fr'
     },
     baseURL_Legacy: process.env.NODE_ENV !== 'production' ? 'http://nginx' : 'https://local.api.opentalent.fr'

+ 4 - 4
config/nuxtConfig/modules.js

@@ -1,17 +1,17 @@
 export default {
   // Modules for dev and build (recommended) (https://go.nuxtjs.dev/config-modules)
   buildModules: [
-    // https://go.nuxtjs.dev/typescript
+    // // https://go.nuxtjs.dev/typescript
     '@nuxt/typescript-build',
-    // https://go.nuxtjs.dev/vuetify
+    // // https://go.nuxtjs.dev/vuetify
     '@nuxtjs/vuetify',
     '@nuxtjs/moment',
-    '@nuxtjs/composition-api'
+    '@nuxtjs/composition-api/module'
   ],
 
   // Modules (https://go.nuxtjs.dev/config-modules)
   modules: [
-    '@nuxt/http',
+    '@nuxtjs/axios',
     'nuxt-i18n'
   ]
 }

+ 5 - 2
config/nuxtConfig/plugins.js

@@ -1,9 +1,12 @@
 export default {
   // Plugins to run before rendering page (https://go.nuxtjs.dev/config-plugins)
   plugins: [
+    '~/plugins/route',
+    '~/plugins/helpersInit',
     '~/plugins/Rights/ability',
     './plugins/Rights/casl.js',
-    '~/plugins/Queries/http',
-    '~/plugins/Queries/rest'
+    '~/plugins/Data/axios',
+    '~/plugins/Data/dataPersister',
+    '~/plugins/Data/dataProvider',
   ]
 }

+ 7 - 3
layouts/default.vue

@@ -5,9 +5,9 @@
 
     <v-app dark>
 
-      <MenuComponent  v-if="properties.displayedMenu" :miniVariant="properties.miniVariant"></MenuComponent>
+      <LayoutMenu  v-if="properties.displayedMenu" :miniVariant="properties.miniVariant"></LayoutMenu>
 
-      <HeaderComponent v-on:handle-open-menu-click="handleOpenMenu"></HeaderComponent>
+      <LayoutHeader v-on:handle-open-menu-click="handleOpenMenu"></LayoutHeader>
 
       <v-main class="ot_content_color">
           <nuxt/>
@@ -17,7 +17,7 @@
 </template>
 
 <script lang="ts">
-  import {defineComponent, reactive, ref, useContext, computed} from '@nuxtjs/composition-api'
+  import {defineComponent, reactive, useContext, computed} from '@nuxtjs/composition-api'
 
   export default defineComponent({
     name: 'defaultLayout',
@@ -34,11 +34,15 @@
         properties.miniVariant = miniVariant
       }
 
+
+
       return {
         properties,
         handleOpenMenu
       }
     },
+
+
     middleware: ['auth']
   })
 </script>

+ 3 - 7
models/Core/AddressPostal.ts

@@ -1,5 +1,4 @@
-import {Attr, Str, HasOne, Num} from '@vuex-orm/core'
-import {Model} from '@/models/Model'
+import {Attr, Str, HasOne, Num, Model} from '@vuex-orm/core'
 import {Country} from "~/models/Core/Country";
 
 export class AddressPostal extends Model{
@@ -8,11 +7,8 @@ export class AddressPostal extends Model{
   @Attr(null)
   id!: number | null
 
-  @Attr(null)
-  addressPostalId!: number | null
-
-  @HasOne(() => Country, 'countryId')
-  country!: Country | null
+  @HasOne(() => Country, 'id')
+  addressCountry!: Country | null
 
   @Str('', {nullable: true})
   addressCity!: string

+ 1 - 2
models/Core/BankAccount.ts

@@ -1,5 +1,4 @@
-import {Attr, Str, Bool, Num} from '@vuex-orm/core'
-import {Model} from '@/models/Model'
+import {Attr, Str, Bool, Model} from '@vuex-orm/core'
 
 export class BankAccount extends Model{
   static entity = 'bank_accounts'

+ 1 - 2
models/Core/ContactPoint.ts

@@ -1,5 +1,4 @@
-import {Attr, Str} from '@vuex-orm/core'
-import {Model} from '@/models/Model'
+import {Attr, Str, Model} from '@vuex-orm/core'
 
 export class ContactPoint extends Model{
   static entity = 'contact_points'

+ 1 - 2
models/Core/Country.ts

@@ -1,5 +1,4 @@
-import {Attr, Str} from '@vuex-orm/core'
-import {Model} from '@/models/Model'
+import {Attr, Str, Model} from '@vuex-orm/core'
 
 export class Country extends Model{
   static entity = 'countries'

+ 3 - 10
models/Model.ts

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

+ 4 - 1
models/Organization/Organization.ts

@@ -1,5 +1,5 @@
 import {Attr, Str, Bool, Num} from '@vuex-orm/core'
-import {Model} from '@/models/Model'
+import {Model} from "~/models/Model";
 
 export class Organization extends Model{
   static entity = 'organizations'
@@ -7,6 +7,9 @@ export class Organization extends Model{
   @Attr(null)
   id!: number | null
 
+  @Attr({})
+  originalState!: object | null
+
   @Str('', {nullable: true})
   name!: string
 

+ 2 - 3
models/Organization/OrganizationAddressPostal.ts

@@ -1,5 +1,4 @@
-import {Attr, Str, HasOne} from '@vuex-orm/core'
-import {Model} from '@/models/Model'
+import {Attr, Str, HasOne, Model} from '@vuex-orm/core'
 import {AddressPostal} from "~/models/Core/AddressPostal";
 
 export class OrganizationAddressPostal extends Model{
@@ -8,7 +7,7 @@ export class OrganizationAddressPostal extends Model{
   @Attr(null)
   id!: number | null
 
-  @HasOne(() => AddressPostal, 'addressPostalId')
+  @HasOne(() => AddressPostal, 'id')
   addressPostal!: AddressPostal | null
 
   @Str('PRINCIPAL', {nullable: false})

+ 1 - 2
models/Organization/OrganizationLicence.ts

@@ -1,5 +1,4 @@
-import {Attr, Str} from '@vuex-orm/core'
-import {Model} from '@/models/Model'
+import {Attr, Str, Model} from '@vuex-orm/core'
 
 export class OrganizationLicence extends Model{
   static entity = 'organization_licences'

+ 1 - 2
models/Organization/OrganizationNetwork.ts

@@ -1,5 +1,4 @@
-import {Attr, Str} from '@vuex-orm/core'
-import {Model} from '@/models/Model'
+import {Attr, Str, Model} from '@vuex-orm/core'
 
 export class OrganizationLicence extends Model{
   static entity = 'organization_licences'

+ 1 - 0
nuxt.config.js

@@ -17,3 +17,4 @@ export default {
   ...vuetify,
   ...moment,
 }
+

+ 11 - 5
package.json

@@ -15,18 +15,19 @@
   "dependencies": {
     "@casl/ability": "^5.1.0",
     "@casl/vue": "^1.2.1",
-    "@nuxt/http": "^0.6.1",
+    "@nuxt/components": "^2.1.8",
     "@nuxt/typescript-runtime": "^2.0.0",
-    "@nuxtjs/composition-api": "0.22.0",
+    "@nuxtjs/axios": "^5.13.1",
+    "@nuxtjs/composition-api": "0.24.2",
     "@types/lodash": "^4.14.168",
-    "@vuex-orm/core": "1.0.0-draft.9",
+    "@vuex-orm/core": "1.0.0-draft.14",
     "cookieparser": "^0.1.0",
     "core-js": "^3.6.5",
     "js-yaml": "^4.0.0",
     "lodash": "^4.17.20",
     "marked": "^1.2.7",
-    "nuxt": "^2.14.6",
-    "nuxt-i18n": "^6.18.0",
+    "nuxt": "2.15.6",
+    "nuxt-i18n": "6.27.0",
     "vue-i18n-composable": "^0.2.1",
     "yaml-import": "^2.0.0"
   },
@@ -44,10 +45,15 @@
     "babel-eslint": "^10.1.0",
     "babel-jest": "^26.5.0",
     "better-docs": "^2.3.2",
+    "css-loader": "^5.0.0",
     "eslint": "^7.10.0",
     "eslint-plugin-nuxt": "^1.0.0",
     "jest": "^26.5.0",
     "jsdoc": "^3.6.6",
+    "postcss": "^8.1.10",
+    "postcss-import": "^13.0.0",
+    "postcss-loader": "^4.1.0",
+    "postcss-url": "^10.1.1",
     "ts-jest": "^26.4.1",
     "vue-jest": "^3.0.4"
   }

+ 1 - 1
pages/index.vue

@@ -2,7 +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>
+      <NuxtLink to="organization">Organization</NuxtLink>
     </v-col>
   </v-row>
 </template>

+ 1 - 0
pages/login.vue

@@ -11,6 +11,7 @@
   import {defineComponent, useContext} from '@nuxtjs/composition-api'
 
   export default defineComponent({
+    name: 'login',
     setup() {
       return {
 

+ 42 - 0
pages/organization.vue

@@ -0,0 +1,42 @@
+<template>
+  <v-container fluid>
+    <LayoutBannerTop>
+      <template v-slot:bloc1>{{entry.name}}</template>
+      <template v-slot:bloc2>N°Siret : {{entry.siretNumber}}</template>
+      <template v-slot:bloc3>{{entry.description}}</template>
+    </LayoutBannerTop>
+    <NuxtChild />
+  </v-container>
+</template>
+
+
+<script lang="ts">
+  import {computed, defineComponent, useContext} from '@nuxtjs/composition-api'
+  import {QUERY_TYPE} from "~/types/enums";
+  import {Organization} from "~/models/Organization/Organization";
+  import {useQueryHelper} from "~/use/store/useQuery";
+  import {useRepositoryHelper} from "~/use/store/useRepository";
+
+  export default defineComponent({
+    name: 'organization',
+    setup() {
+      const {store} = useContext()
+      const repository = useRepositoryHelper.getRepository(Organization)
+      const query = computed(() => repository.query())
+      const entry = computed(() => {
+        return useQueryHelper.getEntry(query.value, store.state.profile.organization.id)
+      })
+      return {
+        entry
+      }
+    },
+    async asyncData({store, $dataProvider}) {
+      await $dataProvider.invoke({
+        type: QUERY_TYPE.MODEL,
+        model: Organization,
+        id: store.state.profile.organization.id
+      })
+    }
+  })
+
+</script>

+ 105 - 0
pages/organization/address/_id.vue

@@ -0,0 +1,105 @@
+<template>
+  <main>
+    <v-skeleton-loader
+      type="text"
+      v-if="loading"
+    ></v-skeleton-loader>
+    <LayoutContainer v-else>
+      <v-card class="margin-bottom-20">
+        <v-toolbar flat class="ot_light_grey toolbarForm" dark dense rounded>
+          <v-toolbar-title class="ot_dark_grey--text form_main_title">
+            <v-icon class="ot_white--text ot_green icon">fa-globe-europe</v-icon>
+            {{ $t('address_postal') }}
+          </v-toolbar-title>
+        </v-toolbar>
+
+        <UiForm :model="model" :id="id" :query="query()">
+          <template v-slot:form.input="{entry, updateRepository}">
+
+            <v-skeleton-loader
+              type="text"
+              v-if="loading"
+            ></v-skeleton-loader>
+            <v-container v-else fluid class="container">
+              <v-row>
+                <v-col cols="12" sm="6">
+                  <UiInputText field="addressPostal.streetAddress" label="streetAddress" :data="entry['addressPostal.streetAddress']" v-on:update="updateRepository"/>
+                </v-col>
+                <v-col cols="12" sm="6">
+                  <UiInputText field="addressPostal.streetAddressSecond" label="streetAddressSecond" :data="entry['addressPostal.streetAddressSecond']" v-on:update="updateRepository"/>
+                </v-col>
+                <v-col cols="12" sm="6">
+                  <UiInputText field="addressPostal.streetAddressThird" label="streetAddressThird" :data="entry['addressPostal.streetAddressThird']" v-on:update="updateRepository"/>
+                </v-col>
+                <v-col cols="12" sm="6">
+                  <UiInputText field="addressPostal.postalCode" label="postalCode" :data="entry['addressPostal.postalCode']" v-on:update="updateRepository"/>
+                </v-col>
+                <v-col cols="12" sm="6">
+                  <UiInputText field="addressPostal.addressCity" label="addressCity" :data="entry['addressPostal.addressCity']" v-on:update="updateRepository"/>
+                </v-col>
+              </v-row>
+            </v-container>
+
+          </template>
+
+          <template v-slot:form.button>
+            <NuxtLink :to="{ path: '/organization', query: { accordion: 'postal_address' }}" class="no-decoration">
+              <v-btn class="mr-4 ot_danger ot_white--text">
+                Retour
+              </v-btn>
+            </NuxtLink>
+          </template>
+        </UiForm>
+      </v-card>
+    </LayoutContainer>
+  </main>
+</template>
+
+
+<script lang="ts">
+  import {defineComponent, useContext, useFetch, ref, computed} from '@nuxtjs/composition-api'
+  import {OrganizationAddressPostal} from "~/models/Organization/OrganizationAddressPostal";
+  import {QUERY_TYPE} from "~/types/enums";
+  import {useRepositoryHelper} from "~/use/store/useRepository";
+
+  export default defineComponent({
+    name: 'organization_address',
+    setup() {
+      const {route, $dataProvider} = useContext()
+      const loading = ref(true)
+      const id = parseInt(route.value.params.id)
+
+      const repository = useRepositoryHelper.getRepository(OrganizationAddressPostal)
+      const query = computed(() => repository.with('addressPostal', (query) => {
+        query.with('addressCountry')
+      }))
+
+      useFetch(async () => {
+        await $dataProvider.invoke({
+          type: QUERY_TYPE.MODEL,
+          model: OrganizationAddressPostal,
+          id: id
+        })
+        loading.value = false
+      })
+
+      return {
+        model: OrganizationAddressPostal,
+        query: () => query,
+        id,
+        loading,
+        panel: 0
+      }
+    },
+  })
+</script>
+<style>
+  .toolbarForm .v-toolbar__content{
+    padding-left: 0px !important;
+  }
+  .toolbarForm .v-toolbar__title .v-icon{
+    height: 46px;
+    width: 46px;
+  }
+
+</style>

+ 0 - 469
pages/organization/edit.vue

@@ -1,469 +0,0 @@
-<template>
-  <ContainerComponent>
-    <template>
-      <v-card class="margin-bottom-20">
-        <v-toolbar flat class="ot_light_grey" dark>
-          <v-toolbar-title class="ot_dark_grey--text form_main_title">
-            Description de l'organisation
-            <v-btn @click="edit" v-if="readOnly" class="ot_green editBtn">
-              Modifier
-            </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 class="container sheetBottomContainer">
-                    <h2 class="sheet_bottom_title">Adresse postale</h2>
-                    <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 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 class="container sheetBottomContainer">
-                    <h2 class="sheet_bottom_title">Point de contact</h2>
-                    <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 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 class="container sheetBottomContainer">
-                    <h2 class="sheet_bottom_title">IBAN</h2>
-                    <FormComponent :repository="repositories.bankAccountRepository" :id="itemId" :query="queries.bankAccountQuery()">
-                      <template v-slot:form.input="{entry: bankAccountEntry }">
-                        <v-row>
-                          <v-col cols="12" sm="6">
-                            <InputComponent field="bankName" :repository="repositories.bankAccountRepository" :entry="bankAccountEntry" />
-                          </v-col>
-                          <v-col cols="12" sm="6">
-                            <InputComponent field="bic" :repository="repositories.bankAccountRepository" :entry="bankAccountEntry" />
-                          </v-col>
-                          <v-col cols="12" sm="6">
-                            <InputComponent field="iban" :repository="repositories.bankAccountRepository" :entry="bankAccountEntry" />
-                          </v-col>
-                          <v-col cols="12" sm="6">
-                            <InputComponent field="debitAddress" :repository="repositories.bankAccountRepository" :entry="bankAccountEntry" />
-                          </v-col>
-                          <v-col cols="12" sm="6">
-                            <InputComponent field="holder" :repository="repositories.bankAccountRepository" :entry="bankAccountEntry" />
-                          </v-col>
-                          <v-col cols="12" sm="6">
-                            <CheckboxComponent field="principal" :repository="repositories.bankAccountRepository" :entry="bankAccountEntry" />
-                          </v-col>
-                        </v-row>
-                      </template>
-                    </FormComponent>
-                  </v-container>
-                </template>
-              </DataTableComponent>
-            </v-col>
-          </v-row>
-        </v-container>
-      </ExpansionPanelComponent>
-
-    </v-expansion-panels>
-
-  </ContainerComponent>
-</template>
-
-<script lang="ts">
-  import {defineComponent, useContext, onUnmounted, computed} from '@nuxtjs/composition-api'
-  import {$dataProvider} from "~/services/dataProvider/dataProvider";
-  import {$organizationProfile} from "~/services/profile/organizationProfile";
-  import {Organization} from '@/models/Organization/Organization'
-  import {OrganizationAddressPostal} from "~/models/Organization/OrganizationAddressPostal";
-  import {ContactPoint} from "~/models/Core/ContactPoint";
-  import {BankAccount} from "~/models/Core/BankAccount";
-  import {useRepositoryHelper} from "~/use/store/useRepository";
-  import {Utils} from "~/use/form/utils";
-
-  export default defineComponent({
-    name: 'organization_edit',
-    setup() {
-      const {store, app:{i18n}} = useContext()
-      const organizationProfile = $organizationProfile(store)
-      const id = store.state.profile.organization.id;
-
-      const repositories = getRepositories()
-
-
-      const {siretError, siretErrorMessage, checkSiret} = Utils.useHandleSiret()
-      //onUnmounted( useRepositoryHelper.cleanRepository(repository) )
-
-      const readOnly = computed(() => {
-        return useRepositoryHelper.getReadOnly(repositories.organizationRepository)
-      })
-
-      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,
-        readOnly
-      }
-    },
-
-    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;
-  }
-  .sheet_bottom_title{
-    text-align: left;
-    border-bottom: 1px solid #1ead8d;
-    margin-bottom: 35px;
-  }
-  .sheetBottomContainer{
-    padding: 20px;
-    padding-top: 30px;
-  }
-</style>

+ 382 - 0
pages/organization/index.vue

@@ -0,0 +1,382 @@
+<template>
+  <LayoutContainer>
+
+    <UiForm :model="models.Organization" :id="id" :query="repositories.organizationRepository.query()">
+      <template v-slot:form.input="{entry, updateRepository}">
+
+        <v-expansion-panels v-model="panel" focusable accordion>
+
+          <!-- Description -->
+          <UiExpansionPanel :title="$t('description')" icon="fa-info">
+            <v-container fluid class="container">
+              <v-row>
+                <v-col cols="12" sm="6">
+                  <UiInputText field="name" :data="entry['name']"  v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputText field="acronym" :data="entry['acronym']"  v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputText field="siretNumber" :data="entry['siretNumber']"  v-on:update="checkSiretHook($event, 'siretNumber', updateRepository)"
+                                  :error="siretError"
+                                  :errorMessage="siretErrorMessage"
+                                  :rules="rules.siretRule"/>
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputText field="apeNumber" :data="entry['apeNumber']"  v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6" v-if="entry['legalStatus'] === 'ASSOCIATION_LAW_1901'">
+                  <UiInputText field="waldecNumber" :data="entry['waldecNumber']"  v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6" v-if="organizationProfile.isInsideNetwork()">
+                  <UiInputText :label="organizationProfile.isCmf() ? 'identifierCmf' : 'identifierFfec'" field="identifier" :data="entry['identifier']"  v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6" v-if="organizationProfile.isFfec()">
+                  <UiInputText field="ffecApproval" :data="entry['ffecApproval']"  v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputText field="description" :data="entry['description']"  v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputText field="logo" :data="entry['logo']"  v-on:update="updateRepository"/>
+                </v-col>
+
+                <!-- @todo: ajouter les if et transformer en select-->
+                <v-col cols="12" sm="6">
+                  <UiInputText field="typeOfPractices" :data="entry['typeOfPractices']"  v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputText field="otherPractice" :data="entry['otherPractice']"  v-on:update="updateRepository"/>
+                </v-col>
+
+              </v-row>
+            </v-container>
+          </UiExpansionPanel>
+
+          <!-- Adresses -->
+          <UiExpansionPanel :title="$t('address_postal')" icon="fa-globe-europe">
+            <v-container fluid class="container">
+              <v-row>
+                <v-col cols="12" sm="12">
+                  <UiSubList
+                    :query="repositories.addressRepository.with('addressPostal', (query) => {
+                      query.with('addressCountry')
+                    })"
+                    :rootModel="models.Organization"
+                    :rootId="id"
+                    :model="models.OrganizationAddressPostal"
+                  >
+                    <template v-slot:list.item="{entries}">
+                      <v-container fluid>
+                        <v-row dense>
+                            <v-col
+                              v-for="entry in entries"
+                              :key="entry.id"
+                              cols="3"
+                            >
+                              <UiCard>
+                                <template v-slot:card.title>{{$t(entry.type)}}</template>
+                                <template v-slot:card.text>
+                                  {{entry.addressPostal.streetAddress}} <br />
+                                  <span v-if="entry.addressPostal.streetAddressSecond">{{entry.addressPostal.streetAddressSecond}} <br /></span>
+                                  <span v-if="entry.addressPostal.streetAddressThird">{{entry.addressPostal.streetAddressThird}} <br /></span>
+                                  {{entry.addressPostal.postalCode}} {{entry.addressPostal.addressCity}}<br />
+                                  <span v-if="entry.addressPostal.addressCountry">{{entry.addressPostal.addressCountry.name}}</span>
+                                </template>
+                                <template v-slot:card.action>
+                                  <v-btn icon>
+                                    <NuxtLink :to="`/organization/address/${entry.id}`" class="no-decoration"><v-icon>mdi-pencil</v-icon></NuxtLink>
+                                  </v-btn>
+                                  <v-btn icon>
+                                    <v-icon>mdi-delete</v-icon>
+                                  </v-btn>
+                                </template>
+                              </UiCard>
+                            </v-col>
+                        </v-row>
+                      </v-container>
+                    </template>
+                  </UiSubList>
+                </v-col>
+              </v-row>
+            </v-container>
+          </UiExpansionPanel>
+
+          <!--  Point de Contact-->
+          <UiExpansionPanel :title="$t('contact_point')" icon="fa-phone">
+            <v-container class="container">
+              <v-row>
+                <v-col cols="12" sm="12">
+                  <UiDataTable
+                    :query="repositories.contactPointRepository.query()"
+                    :rootModel="models.Organization"
+                    :rootId="id"
+                    :model="models.ContactPoint"
+                    :headers="datatableHeaders.headersContactPoint"
+                  >
+                  </UiDataTable>
+                </v-col>
+              </v-row>
+            </v-container>
+          </UiExpansionPanel>
+
+          <!-- Informations légales -->
+          <UiExpansionPanel :title="$t('legalInformation')" icon="fa-gavel">
+            <v-container fluid class="container">
+              <v-row>
+                <v-col cols="12" sm="6">
+                  <UiInputDatePicker field="creationDate" :data="entry['creationDate']"  v-on:update="updateRepository"/>
+                </v-col>
+                <v-col cols="12" sm="6">
+                  <UiInputText field="prefectureName" :data="entry['prefectureName']"  v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputText field="prefectureNumber" :data="entry['prefectureNumber']"  v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputText field="tvaNumber" :data="entry['tvaNumber']"  v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputEnum field="legalStatus" :data="entry['legalStatus']"  enumType="organization_legal" v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6" v-if="!organizationProfile.isManagerProduct()">
+                  <UiInputEnum field="principalType" :data="entry['principalType']"  enumType="organization_principal_type" v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6" v-if="!organizationProfile.isFfec() && !organizationProfile.isManagerProduct() && !organizationProfile.isArtist()">
+                  <UiInputEnum field="schoolCategory" :data="entry['schoolCategory']"  enumType="organization_school_cat" v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6" v-if="organizationProfile.isFfec()">
+                  <UiInputEnum field="typeEstablishment" :data="entry['typeEstablishment']"  enumType="organization_type_establishment" v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6" v-if="entry.typeEstablishment === 'MULTIPLE'">
+                  <UiInputEnum field="typeEstablishmentDetail" :data="entry['typeEstablishmentDetail']"  enumType="organization_type_establishment_detail" v-on:update="updateRepository"/>
+                </v-col>
+
+              </v-row>
+            </v-container>
+          </UiExpansionPanel>
+
+          <!--  Agréments -->
+          <UiExpansionPanel :title="$t('agrements')" icon="fa-certificate">
+            <v-container class="container">
+              <v-row>
+                <v-col cols="12" sm="6">
+                  <UiInputText field="youngApproval" :data="entry['youngApproval']"  v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputText field="trainingApproval" :data="entry['trainingApproval']"  v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputText field="otherApproval" :data="entry['otherApproval']"  v-on:update="updateRepository"/>
+                </v-col>
+
+              </v-row>
+            </v-container>
+          </UiExpansionPanel>
+
+          <!-- Salariés -->
+          <UiExpansionPanel :title="$t('salary')" icon="fa-users">
+            <v-container class="container">
+              <v-row>
+                <v-col cols="12" sm="6">
+                  <UiInputText field="collectiveAgreement" :data="entry['collectiveAgreement']"  v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputEnum field="opca" :data="entry['opca']"  enumType="organization_opca" v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputText field="icomNumber" :data="entry['icomNumber']"  v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputText field="urssafNumber" :data="entry['urssafNumber']"  v-on:update="updateRepository"/>
+                </v-col>
+
+              </v-row>
+            </v-container>
+          </UiExpansionPanel>
+
+          <!-- Réseaux -->
+          <UiExpansionPanel v-if="organizationProfile.isInsideNetwork()" :title="$t('network')" icon="fa-share-alt">
+            <v-container class="container">
+              <v-row>
+                <v-col cols="12" sm="6" v-if="organizationProfile.isFfec()">
+                  <UiInputText field="budget" :data="entry['budget']"  v-on:update="updateRepository" type="number"/>
+                </v-col>
+
+                <v-col cols="12" sm="6" v-if="organizationProfile.isFfec()">
+                  <UiInputCheckbox field="isPedagogicIsPrincipalActivity" :data="entry['isPedagogicIsPrincipalActivity']"  v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6" v-if="organizationProfile.isFfec()">
+                  <UiInputText field="pedagogicBudget" :data="entry['pedagogicBudget']"  v-on:update="updateRepository" type="number"/>
+                </v-col>
+
+              </v-row>
+            </v-container>
+          </UiExpansionPanel>
+
+          <!-- Communication -->
+          <UiExpansionPanel :title="$t('communication')" icon="fa-rss">
+            <v-container class="container">
+              <v-row>
+                <v-col cols="12" sm="6">
+                  <UiInputText field="twitter" :data="entry['twitter']"  v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputText field="facebook" :data="entry['facebook']"  v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputText field="instagram" :data="entry['instagram']"  v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputCheckbox field="portailVisibility" :data="entry['portailVisibility']"  v-on:update="updateRepository"/>
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputText field="image" :data="entry['image']"  v-on:update="updateRepository"/>
+                </v-col>
+
+              </v-row>
+            </v-container>
+          </UiExpansionPanel>
+
+          <!-- IBAN -->
+          <UiExpansionPanel :title="$t('bank_account')" icon="fa-euro-sign">
+            <v-container class="container">
+              <v-row>
+                <v-col cols="12" sm="12">
+                  <UiDataTable
+                    :query="repositories.bankAccountRepository.query()"
+                    :rootModel="models.Organization"
+                    :rootId="id"
+                    :model="models.BankAccount"
+                    :headers="datatableHeaders.headersBankAccount"
+                  >
+                  </UiDataTable>
+                </v-col>
+              </v-row>
+            </v-container>
+          </UiExpansionPanel>
+
+        </v-expansion-panels>
+      </template>
+    </UiForm>
+  </LayoutContainer>
+</template>
+
+<script lang="ts">
+  import {defineComponent, useContext} from '@nuxtjs/composition-api'
+  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_parent',
+    setup() {
+      const {store, app: {i18n}, route} = useContext()
+      const organizationProfile = $organizationProfile(store)
+      const id = store.state.profile.organization.id;
+
+      const repositories = getRepositories()
+
+      const {siretError, siretErrorMessage, checkSiret} = Utils.useHandleSiret()
+      const checkSiretHook = async (siret:string, field:string, updateRepository:any) => {
+        await checkSiret(siret)
+        if(!siretError.value)
+          updateRepository(siret, field);
+      }
+
+      //onUnmounted( useRepositoryHelper.cleanRepository(repository) )
+
+      return {
+        repositories,
+        id,
+        organizationProfile,
+        models: {Organization, ContactPoint, BankAccount, OrganizationAddressPostal},
+        datatableHeaders: getDataTablesHeaders(i18n),
+        rules: getRules(i18n),
+        siretError,
+        siretErrorMessage,
+        checkSiretHook,
+        panel: route.value.query.accordion ? 0 : 0
+      }
+    },
+  })
+
+  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.getRepository(Organization),
+      contactPointRepository: useRepositoryHelper.getRepository(ContactPoint),
+      bankAccountRepository: useRepositoryHelper.getRepository(BankAccount),
+      addressRepository: useRepositoryHelper.getRepository(OrganizationAddressPostal)
+    }
+  }
+</script>
+
+<style scoped>
+  .v-icon.v-icon {
+    font-size: 14px;
+  }
+</style>

+ 19 - 0
plugins/Data/axios.js

@@ -0,0 +1,19 @@
+export default function ({ $axios, redirect, store }) {
+  $axios.onRequest(config => {
+    $axios.setHeader('x-accessid', `${store.state.profile.access.accessId}`)
+    $axios.setToken(`${store.state.profile.access.bearer}`, 'Bearer')
+  })
+
+  $axios.onResponse(response => {
+  })
+
+  $axios.onError((error) => {
+    // In case of unauthorized, redirect to a specific page
+    if (error.statusCode === 401) {
+      redirect('/login')
+    }
+    if (error.statusCode === 403) {
+      console.debug('forbidden');
+    }
+  })
+}

+ 12 - 0
plugins/Data/dataPersister.ts

@@ -0,0 +1,12 @@
+import {Plugin} from '@nuxt/types'
+import DataPersister from "~/services/dataPersister/dataPersister";
+
+const dataPersisterPlugin: Plugin = (ctx) => {
+  const dataPersister = new DataPersister();
+  dataPersister.initCtx(ctx)
+
+  //Déclare un nouvel accesseur de service via le context Nuxt
+  ctx.$dataPersister = dataPersister
+}
+
+export default dataPersisterPlugin

+ 12 - 0
plugins/Data/dataProvider.ts

@@ -0,0 +1,12 @@
+import {Plugin} from '@nuxt/types'
+import DataProvider from "~/services/dataProvider/dataProvider";
+
+const dataProviderPlugin: Plugin = (ctx) => {
+  const dataProvider = new DataProvider();
+  dataProvider.initCtx(ctx)
+
+  //Déclare un nouvel accesseur de service via le context Nuxt
+  ctx.$dataProvider = dataProvider
+}
+
+export default dataProviderPlugin

+ 0 - 20
plugins/Queries/http.js

@@ -1,20 +0,0 @@
-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) => {
-    // In case of unauthorized, redirect to a specific page
-    if (error.statusCode === 401) {
-      redirect('/login')
-    }
-    if (error.statusCode === 403) {
-      console.debug('forbidden');
-    }
-  })
-}

+ 0 - 9
plugins/Queries/rest.ts

@@ -1,9 +0,0 @@
-import {Plugin} from '@nuxt/types'
-import {$rest} from "~/services/queries/rest";
-
-const restPlugin: Plugin = (ctx) => {
-  //Déclare un nouvel accesseur de service via le context Nuxt
-  ctx.$rest = $rest(ctx.$http)
-}
-
-export default restPlugin

+ 8 - 0
plugins/helpersInit.ts

@@ -0,0 +1,8 @@
+import {Plugin} from '@nuxt/types'
+import {useRepositoryHelper} from "~/use/store/useRepository";
+
+const helpersInitPlugin: Plugin = (ctx) => {
+  useRepositoryHelper.setStore(ctx.store)
+}
+
+export default helpersInitPlugin

+ 20 - 0
plugins/route.ts

@@ -0,0 +1,20 @@
+import {Plugin} from '@nuxt/types'
+
+const routePlugin: Plugin = (ctx) => {
+  if(ctx.app.router){
+    ctx.app.router.beforeEach((to, from, next)=>{
+      if(ctx.store.state.form.dirty){
+        ctx.store.commit('form/setShowConfirmToLeave', true)
+        ctx.store.commit('form/setGoAfterLeave', to)
+      }else{
+        next()
+      }
+    })
+
+    ctx.app.router.afterEach(()=>{
+      ctx.store.commit('form/setDirty', false)
+    })
+  }
+}
+
+export default routePlugin

+ 48 - 0
services/connection/connection.ts

@@ -0,0 +1,48 @@
+import {DataPersisterArgs, DataProviderArgs} from "~/types/interfaces";
+import {HTTP_METHOD} from "~/types/enums";
+import {NuxtAxiosInstance} from "@nuxtjs/axios";
+import {AxiosRequestConfig} from "axios";
+
+class Connection{
+  static connector:NuxtAxiosInstance;
+
+  constructor() {
+  }
+
+  static initConnector(connector: NuxtAxiosInstance){
+    Connection.connector = connector
+  }
+
+  async invoke(method: HTTP_METHOD, url: string, args:DataProviderArgs|DataPersisterArgs): Promise<any>{
+    switch (method) {
+      case HTTP_METHOD.GET:
+        if(args.id)
+          return await this.getItem(url, args.id)
+        else
+          return await this.getCollection(url)
+    }
+    return null
+  }
+
+  private async getItem(url: string, id: number): Promise<any>{
+    const config:AxiosRequestConfig = {
+      url: `${url}/${id}`,
+      method: HTTP_METHOD.GET,
+    }
+    return await this.request(config)
+  }
+
+  private async getCollection(url: string): Promise<any>{
+    const config:AxiosRequestConfig = {
+      url: `${url}`,
+      method: HTTP_METHOD.GET,
+    }
+    return await this.request(config)
+  }
+
+  private async request(config:AxiosRequestConfig){
+    return await Connection.connector.$request(config)
+  }
+}
+
+export default Connection

+ 61 - 0
services/connection/constructUrl.ts

@@ -0,0 +1,61 @@
+import {UrlArgs} from "~/types/interfaces";
+import {QUERY_TYPE} from "~/types/enums";
+import {Context} from "@nuxt/types/app";
+import {Model} from "@vuex-orm/core";
+
+class ConstructUrl{
+  static ROOT = '/api/'
+
+  private ctx !: Context
+
+  constructor(ctx: Context) {
+    this.ctx = ctx
+  }
+
+  invoke(args:UrlArgs): string{
+    switch (args.type) {
+      case QUERY_TYPE.DEFAULT:
+        return this.getDefaultUrl(args.url)
+
+      case QUERY_TYPE.ENUM:
+        return this.getEnumUrl(args.enumType)
+
+      case QUERY_TYPE.MODEL:
+        return this.getModelUrl(args.model, args.root_model, args.root_id)
+
+      default:
+        throw new Error('url, model or enum must be defined');
+    }
+  }
+
+  private getDefaultUrl(url?: string){
+    if(typeof url === 'undefined')
+      throw new Error('url must be defined');
+    return String(ConstructUrl.ROOT + url).toString()
+  }
+
+  private getEnumUrl(enumType?: string){
+    if(typeof enumType === 'undefined')
+      throw new Error('enumType must be defined');
+    return String(ConstructUrl.ROOT + 'enum/' + enumType).toString()
+  }
+
+  private getModelUrl(model ?: typeof Model, rootModel ?: typeof Model, rootId ?: number){
+    if(typeof model === 'undefined')
+      throw new Error('model must be defined');
+    const repository = this.ctx.store.$repo(model);
+    const entity = repository.getModel().$entity();
+
+    if(typeof rootModel !== 'undefined'){
+      if(typeof rootId === 'undefined')
+        throw new Error('Root ID must be defined');
+
+      const rootUrl = this.getModelUrl(rootModel) as string
+      return String(`${rootUrl}/${rootId}/${entity}`).toString()
+    }
+
+    return String(ConstructUrl.ROOT  + entity).toString()
+  }
+}
+
+export default ConstructUrl

+ 71 - 0
services/dataPersister/dataPersister.ts

@@ -0,0 +1,71 @@
+import {hooks} from "~/services/dataPersister/hook/_import";
+import {DataPersisterArgs} from "~/types/interfaces";
+import {Context} from "@nuxt/types/app";
+import Connection from "~/services/connection/connection";
+import ConstructUrl from "~/services/connection/constructUrl";
+import {HTTP_METHOD} from "~/types/enums";
+
+class DataPersister{
+  private ctx !: Context;
+  private arguments!: DataPersisterArgs;
+
+  constructor() {
+    this.sort()
+  }
+
+  initCtx(ctx:Context){
+    Connection.initConnector(ctx.$axios)
+    this.ctx = ctx
+  }
+
+  async invoke(args:DataPersisterArgs): Promise<any>{
+    this.arguments = args
+    try{
+      this.preHook()
+
+      await this.serialization()
+
+      const url = this.constructUrl()
+
+      const response = await this.connection(url)
+    }catch(error){
+     throw new Error(error.message);
+    }
+  }
+
+  async preHook(){
+    for(const hook of hooks){
+      if(hook.support(this.arguments)){
+        await new hook().invoke(this.arguments);
+      }
+    }
+  }
+
+  serialization(){
+    console.log('serialization')
+  }
+
+  constructUrl(): string{
+    const constructUrl = new ConstructUrl(this.ctx);
+    return constructUrl.invoke(this.arguments)
+  }
+
+  connection(url: string): Promise<any>{
+    const connection = new Connection()
+    return connection.invoke(HTTP_METHOD.GET, url, this.arguments)
+  }
+
+  sort(){
+    hooks.sort(function(a, b) {
+      if (a.priority > b.priority) {
+        return 1;
+      }
+      if (a.priority < b.priority) {
+        return -1;
+      }
+      return 0;
+    });
+  }
+}
+
+export default DataPersister

+ 4 - 0
services/dataPersister/hook/_import.ts

@@ -0,0 +1,4 @@
+import Hook_example from "~/services/dataPersister/hook/hook_example";
+export const hooks = [
+  Hook_example
+]

+ 14 - 0
services/dataPersister/hook/baseHook.ts

@@ -0,0 +1,14 @@
+import {DataPersisterArgs} from "~/types/interfaces";
+
+class BaseHook{
+  static priority = 255
+
+  constructor() {
+  }
+
+  static support(args:DataPersisterArgs): boolean{
+    throw new Error('Need to be implement into static method')
+  }
+}
+
+export default BaseHook

+ 31 - 0
services/dataPersister/hook/hook_example.ts

@@ -0,0 +1,31 @@
+import {DataPersisterArgs, HookPersister} from "~/types/interfaces";
+import BaseHook from "~/services/dataPersister/hook/baseHook";
+
+class Hook_example extends BaseHook implements HookPersister{
+  static priority = 10
+
+  constructor() {
+    super()
+  }
+
+  async invoke(args: DataPersisterArgs): Promise<any>{
+    await timeoutPromise(3000)
+    console.log('Hook 1');
+    throw new Error('STOP!')
+  }
+
+  static support(args:DataPersisterArgs): boolean{
+    return args.hook === 'test'
+  }
+}
+
+export default Hook_example
+
+function timeoutPromise(interval:number) {
+  return new Promise((resolve, reject) => {
+    setTimeout(function(){
+      console.log('done')
+      resolve("done");
+    }, interval);
+  });
+};

+ 42 - 42
services/dataProvider/dataProvider.ts

@@ -1,60 +1,60 @@
-import {Store} from "vuex";
-import {Rest} from "~/services/queries/rest";
-import {Model} from "@/models/Model"
+import {AnyJson, DataProviderArgs} from "~/types/interfaces";
+import {DENORMALIZER_TYPE, HTTP_METHOD} from "~/types/enums";
+import {providers} from "~/services/dataProvider/provider/_import";
+import ConstructUrl from "~/services/connection/constructUrl";
+import Connection from "~/services/connection/connection";
+import Serializer from "~/services/serializer/serializer";
+import {Context} from "@nuxt/types/app";
 
 class DataProvider{
-  private store: Store<any>
-  private $rest: Rest
+  private ctx !: Context;
+  private arguments!: DataProviderArgs;
 
-  constructor(store:Store<any>, $rest: Rest) {
-    this.store = store
-    this.$rest = $rest
+  constructor() {
   }
 
-  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);
+  initCtx(ctx:Context){
+    Connection.initConnector(ctx.$axios)
+    this.ctx = ctx
   }
 
-  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);
-  }
+  async invoke(args:DataProviderArgs): Promise<any>{
+    this.arguments = args
+    try{
+      const url = this.constructUrl()
 
-  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 response = await this.connection(url)
 
-    const repository = this.store.$repo(model);
-    const entity = repository.getModel().$entity();
+      const deserializeResponse = await this.deserialization(response)
 
-    const response = await this.$rest.getCollection(`/api/${root_entity}/${root_id}/${entity}`)
-    if(response){
-      repository.insert(response)
-      return repository.all();
+      return await this.provide(deserializeResponse)
+    }catch(error){
+      throw new Error(error.message);
     }
-    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();
+  constructUrl(): string{
+    const constructUrl = new ConstructUrl(this.ctx);
+    return constructUrl.invoke(this.arguments)
+  }
+
+  connection(url: string): Promise<any>{
+    const connection = new Connection()
+    return connection.invoke(HTTP_METHOD.GET, url, this.arguments)
+  }
 
-    const repository = this.store.$repo(model);
-    const entity = repository.getModel().$entity();
+  provide(data: AnyJson): any{
+    for(const provider of providers){
+      if(provider.support(this.arguments)){
+         return new provider(this.ctx, this.arguments).invoke(data);
+      }
+    }
+  }
 
-    const response = await this.$rest.getItem(`/api/${root_entity}/${root_id}/${entity}`, id)
-    if(response)
-      repository.insert(response);
+  deserialization(data: AnyJson): AnyJson{
+    const serializer = new Serializer()
+    return serializer.denormalize(data, DENORMALIZER_TYPE.DEFAULT)
   }
 }
 
-export const $dataProvider = (store:Store<any>, $rest:Rest) => new DataProvider(store, $rest);
+export default DataProvider

+ 0 - 40
services/dataProvider/enumDataProvider.ts

@@ -1,40 +0,0 @@
-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);

+ 9 - 0
services/dataProvider/provider/_import.ts

@@ -0,0 +1,9 @@
+import ModelProvider from "~/services/dataProvider/provider/modelProvider";
+import EnumProvider from "~/services/dataProvider/provider/enumProvider";
+import DefaultProvider from "~/services/dataProvider/provider/defaultProvider";
+
+export const providers = [
+  DefaultProvider,
+  ModelProvider,
+  EnumProvider
+]

+ 40 - 0
services/dataProvider/provider/baseProvider.ts

@@ -0,0 +1,40 @@
+import {hooks} from "~/services/dataProvider/provider/hook/_import";
+import {DataProviderArgs} from "~/types/interfaces";
+import {Context} from "@nuxt/types/app";
+
+class BaseProvider{
+  protected arguments!: DataProviderArgs;
+  protected ctx!: Context;
+
+  constructor(ctx: Context, args: DataProviderArgs) {
+    this.arguments = args
+    this.ctx = ctx
+    this.sortHook()
+  }
+
+  static support(args:DataProviderArgs): boolean{
+    throw new Error('Need to be implement into static method')
+  }
+
+  async postHook(){
+    for(const hook of hooks){
+      if(hook.support(this.arguments)){
+        await new hook().invoke(this.arguments);
+      }
+    }
+  }
+
+  sortHook(){
+    hooks.sort(function(a, b) {
+      if (a.priority > b.priority) {
+        return 1;
+      }
+      if (a.priority < b.priority) {
+        return -1;
+      }
+      return 0;
+    });
+  }
+}
+
+export default BaseProvider

+ 20 - 0
services/dataProvider/provider/defaultProvider.ts

@@ -0,0 +1,20 @@
+import {AnyJson, DataProviderArgs, Provider} from "~/types/interfaces";
+import BaseProvider from "~/services/dataProvider/provider/baseProvider";
+import {QUERY_TYPE} from "~/types/enums";
+import {Context} from "@nuxt/types/app";
+
+class DefaultProvider extends BaseProvider implements Provider{
+  constructor(ctx: Context, args: DataProviderArgs) {
+    super(ctx, args);
+  }
+
+  async invoke(data: AnyJson): Promise<any>{
+    return data
+  }
+
+  static support(args:DataProviderArgs): boolean{
+    return args.type ===  QUERY_TYPE.DEFAULT
+  }
+}
+
+export default DefaultProvider

+ 39 - 0
services/dataProvider/provider/enumProvider.ts

@@ -0,0 +1,39 @@
+import {AnyJson, DataProviderArgs, EnumChoice, EnumChoices, Provider} from "~/types/interfaces";
+import BaseProvider from "~/services/dataProvider/provider/baseProvider";
+import {QUERY_TYPE} from "~/types/enums";
+import * as _ from "lodash";
+import {Context} from "@nuxt/types/app";
+
+class EnumProvider extends BaseProvider implements Provider{
+  constructor(ctx: Context, args: DataProviderArgs) {
+    super(ctx, args);
+  }
+
+  async invoke(data: AnyJson): Promise<any>{
+    const enums:EnumChoices = []
+    _.each(data['items'], (item, key) =>{
+      const entry:EnumChoice = {
+        value: key,
+        label: this.ctx.app.i18n.t(item) as string
+      };
+      enums.push(entry)
+    })
+    return this.sortEnum(enums)
+  }
+
+  private sortEnum(enums:EnumChoices){
+    return enums.sort( (a, b) => {
+      if (a.label > b.label)
+        return 1;
+      if (a.label < b.label)
+        return -1;
+      return 0;
+    });
+  }
+
+  static support(args:DataProviderArgs): boolean{
+    return args.type ===  QUERY_TYPE.ENUM
+  }
+}
+
+export default EnumProvider

+ 5 - 0
services/dataProvider/provider/hook/_import.ts

@@ -0,0 +1,5 @@
+import Hook_example from "~/services/dataProvider/provider/hook/hook_example";
+
+export const hooks = [
+  Hook_example
+]

+ 14 - 0
services/dataProvider/provider/hook/baseHook.ts

@@ -0,0 +1,14 @@
+import {DataProviderArgs} from "~/types/interfaces";
+
+class BaseHook{
+  static priority = 255
+
+  constructor() {
+  }
+
+  static support(args:DataProviderArgs): boolean{
+    throw new Error('Need to be implement into static method')
+  }
+}
+
+export default BaseHook

+ 31 - 0
services/dataProvider/provider/hook/hook_example.ts

@@ -0,0 +1,31 @@
+import {DataProviderArgs, HookProvider} from "~/types/interfaces";
+import BaseHook from "~/services/dataProvider/provider/hook/baseHook";
+
+class Hook_example extends BaseHook implements HookProvider{
+  static priority = 10
+
+  constructor() {
+    super()
+  }
+
+  async invoke(args: DataProviderArgs): Promise<any> {
+    await timeoutPromise(3000)
+    console.log('Hook 1');
+    throw new Error('STOP!')
+  }
+
+  static support(args:DataProviderArgs): boolean{
+    return args.hook === 'test'
+  }
+}
+
+export default Hook_example
+
+function timeoutPromise(interval:number) {
+  return new Promise((resolve, reject) => {
+    setTimeout(function(){
+      console.log('done')
+      resolve("done");
+    }, interval);
+  });
+};

+ 29 - 0
services/dataProvider/provider/modelProvider.ts

@@ -0,0 +1,29 @@
+import {AnyJson, DataProviderArgs, Provider} from "~/types/interfaces";
+import BaseProvider from "~/services/dataProvider/provider/baseProvider";
+import {QUERY_TYPE} from "~/types/enums";
+import {Context} from "@nuxt/types/app";
+import * as _ from "lodash";
+import {useRepositoryHelper} from "~/use/store/useRepository";
+
+class ModelProvider extends BaseProvider implements Provider{
+  constructor(ctx: Context, args: DataProviderArgs) {
+    super(ctx, args);
+  }
+
+  async invoke(data: AnyJson): Promise<any>{
+    if(typeof this.arguments.model === 'undefined')
+      throw new Error('model must be defined');
+
+    data['originalState'] = _.cloneDeep(data)
+    const repository = useRepositoryHelper.getRepository(this.arguments.model);
+    await useRepositoryHelper.updateStore(repository, data)
+
+    await this.postHook()
+  }
+
+  static support(args:DataProviderArgs): boolean{
+    return args.type === QUERY_TYPE.MODEL
+  }
+}
+
+export default ModelProvider

+ 1 - 1
services/profile/accessProfile.ts

@@ -1,4 +1,4 @@
-import {AbilitiesType, accessState, AccessStore, AnyJson} from "~/types/types";
+import {AbilitiesType, accessState, AccessStore, AnyJson} from "~/types/interfaces";
 import {Ability} from "@casl/ability";
 
 /**

+ 1 - 1
services/profile/organizationProfile.ts

@@ -1,4 +1,4 @@
-import {AnyJson, organizationState, OrganizationStore} from "~/types/types";
+import {AnyJson, organizationState, OrganizationStore} from "~/types/interfaces";
 
 /**
  * @category Services/profiles

+ 0 - 29
services/queries/rest.ts

@@ -1,29 +0,0 @@
-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)

+ 5 - 3
services/rights/abilitiesUtils.ts

@@ -1,10 +1,11 @@
 import {$accessProfile} from "@/services/profile/accessProfile"
 import {$organizationProfile} from "@/services/profile/organizationProfile"
 import {$roleUtils} from "~/services/rights/roleUtils";
-import {AbilitiesType, AnyJson, AnyStore} from "~/types/types";
+import {AbilitiesType, AnyJson, AnyStore} from "~/types/interfaces";
 import {Ability} from "@casl/ability";
-import {$yamlParser} from "~/services/utils/yamlParser";
 import * as _ from "lodash";
+import Serializer from "~/services/serializer/serializer";
+import {DENORMALIZER_TYPE} from "~/types/enums";
 
 /**
  * @category Services/droits
@@ -94,7 +95,8 @@ class AbilitiesUtils {
   getAbilitiesByConfig(configPath:string): Array<AbilitiesType> {
     let abilitiesByConfig: Array<AbilitiesType> = []
    try {
-      const doc = $yamlParser.parse(configPath);
+      const serializer = new Serializer()
+      const doc = serializer.denormalize({path: configPath}, DENORMALIZER_TYPE.YAML);
       const abilitiesAvailable = doc['abilities']
       const abilitiesFiltered = this.abilitiesAvailableFilter(abilitiesAvailable)
       abilitiesByConfig = this.transformAbilitiesConfigToAbility(abilitiesFiltered)

+ 1 - 1
services/rights/roleUtils.ts

@@ -1,4 +1,4 @@
-import {AbilitiesType, AnyJson} from "~/types/types";
+import {AbilitiesType, AnyJson} from "~/types/interfaces";
 import * as _ from "lodash";
 
 const roles_by_function = [

+ 7 - 0
services/serializer/denormalizer/_import.ts

@@ -0,0 +1,7 @@
+import Hydra from "~/services/serializer/denormalizer/hydra";
+import Yaml from "~/services/serializer/denormalizer/yaml";
+
+export const denormalizers = [
+  Yaml,
+  Hydra
+]

+ 12 - 0
services/serializer/denormalizer/baseDenormalizer.ts

@@ -0,0 +1,12 @@
+import {DENORMALIZER_TYPE} from "~/types/enums";
+
+class BaseDenormalizer{
+  constructor() {
+  }
+
+  static support(type: DENORMALIZER_TYPE): boolean {
+    throw new Error('Need to be implement into static method')
+  }
+}
+
+export default BaseDenormalizer

+ 118 - 0
services/serializer/denormalizer/hydra.ts

@@ -0,0 +1,118 @@
+import {AnyJson, Denormalizer} from "~/types/interfaces";
+import BaseDenormalizer from "~/services/serializer/denormalizer/baseDenormalizer";
+import {DENORMALIZER_TYPE} from "~/types/enums";
+
+/**
+ * @category Services/utils
+ * @class HydraParser
+ * Classe permettant d'assurer le parsing d'une réponse Hydra
+ */
+class Hydra extends BaseDenormalizer implements Denormalizer{
+  static support(type: DENORMALIZER_TYPE): boolean {
+    return type === DENORMALIZER_TYPE.DEFAULT
+  }
+
+  /**
+   * Parcours une réponse Hydra pour retourner son équivalent en Json
+   * @param {AnyJson} hydraData
+   * @return {AnyJson} réponse parsée
+   */
+  public denormalize(hydraData: AnyJson): AnyJson {
+    if (hydraData['hydra:member']) {
+      hydraData.totalCount = hydraData['hydra:totalItems'];
+      return this.parseCollection(hydraData);
+    } else {
+      return this.parseItem(hydraData);
+    }
+  }
+
+  /**
+   * Méthode de parsing appelé si on est dans un GET
+   * @param {AnyJson} hydraData
+   */
+  private parseItem(hydraData: AnyJson): AnyJson {
+    this.populateId(hydraData);
+
+    if (hydraData['hydra:previous']) {
+      let iriParts = hydraData['hydra:previous'].split('/');
+      hydraData.previous = iriParts[iriParts.length - 1];
+    }
+    if (hydraData['hydra:next']) {
+      let iriParts = hydraData['hydra:next'].split('/');
+      hydraData.next = iriParts[iriParts.length - 1];
+    }
+    if (hydraData['hydra:totalItems']) {
+      hydraData.totalItems = hydraData['hydra:totalItems'];
+    }
+    if (hydraData['hydra:itemPosition']) {
+      hydraData.itemPosition = hydraData['hydra:itemPosition'];
+    }
+    return hydraData;
+  }
+
+  /**
+   * Méthode de parsing appelé si on est dans un GET Collection
+   * @param {AnyJson} hydraData
+   */
+  private parseCollection(hydraData: AnyJson): AnyJson {
+    let collectionResponse = hydraData['hydra:member'];
+    collectionResponse.metadata = {};
+    collectionResponse.order = {};
+    collectionResponse.search = {};
+
+    // Put metadata in a property of the collection
+    for (const key in hydraData) {
+      const value = hydraData[key];
+      if ('hydra:member' !== key) {
+        collectionResponse.metadata[key] = value;
+      }
+    }
+
+    // Populate href property for all elements of the collection
+    for (const key in collectionResponse) {
+      const value = collectionResponse[key];
+      this.populateAllData(value);
+    }
+
+    if ('undefined' !== typeof (hydraData['hydra:search'])) {
+      let collectionSearch = hydraData['hydra:search']['hydra:mapping'];
+      for (const key in collectionSearch) {
+        const value = collectionSearch[key];
+        if (value['variable'].indexOf("filter[order]") === 0) {
+          collectionResponse.order[value['property']] = value;
+        } else if (value['variable'].indexOf("filter[where]") === 0) {
+          collectionResponse.search[value['property']] = value;
+        }
+      }
+    }
+    return collectionResponse;
+  }
+
+
+  /**
+   * Hydrate l'objet Json avec la valeur id correspondant à l'uri de l'objet
+   * @param {AnyJson} data
+   */
+  private populateId(data: AnyJson): void{
+    if (data['@id'] && data['@id'] instanceof String) {
+      var iriParts = data['@id'].split('/');
+      data.id = iriParts[iriParts.length - 1];
+    }
+  }
+
+  /**
+   * Hydrate l'objet JSON de façon récursive (afin de gérer les objet nested)
+   * @param {AnyJson} data
+   */
+  private populateAllData(data: AnyJson):void {
+    this.populateId(data);
+    for (const key in data) {
+      const value = data[key];
+      if (value instanceof Object) {
+        this.populateAllData(value);
+      }
+    }
+  }
+}
+
+export default Hydra

+ 32 - 0
services/serializer/denormalizer/yaml.ts

@@ -0,0 +1,32 @@
+import {AnyJson, Denormalizer} from "~/types/interfaces";
+import { read } from 'yaml-import';
+import BaseDenormalizer from "~/services/serializer/denormalizer/baseDenormalizer";
+import {DENORMALIZER_TYPE} from "~/types/enums";
+const yaml = require('js-yaml');
+
+/**
+ * @category Services/utils
+ * @class YamlParser
+ * Classe permettant d'assurer le parsing d'un fichier Yaml
+ */
+class Yaml extends BaseDenormalizer implements Denormalizer{
+  static support(type: DENORMALIZER_TYPE): boolean {
+    return type === DENORMALIZER_TYPE.YAML
+  }
+
+  /**
+   * Parse un fichier Yaml pour en retourner son équivalent en Json
+   * @param {AnyJson} data
+   * @return {AnyJson}
+   */
+  denormalize(data: AnyJson): AnyJson {
+    try {
+      return yaml.load(yaml.dump(read(data.path)));
+    }catch (e) {
+      console.debug(e);
+      return {}
+    }
+  }
+}
+
+export default Yaml

+ 5 - 0
services/serializer/normalizer/_import.ts

@@ -0,0 +1,5 @@
+import Model from "~/services/serializer/normalizer/model";
+
+export const normalizers = [
+  Model
+]

+ 12 - 0
services/serializer/normalizer/baseNormalizer.ts

@@ -0,0 +1,12 @@
+import {QUERY_TYPE} from "~/types/enums";
+
+class BaseNormalizer{
+  constructor() {
+  }
+
+  static support(type: QUERY_TYPE): boolean {
+    throw new Error('Need to be implement into static method')
+  }
+}
+
+export default BaseNormalizer

+ 14 - 0
services/serializer/normalizer/model.ts

@@ -0,0 +1,14 @@
+import BaseNormalizer from "~/services/serializer/normalizer/baseNormalizer";
+import {DataPersisterArgs, Normalizer} from "~/types/interfaces";
+import {QUERY_TYPE} from "~/types/enums";
+
+class Model extends BaseNormalizer implements Normalizer{
+  static support(type: QUERY_TYPE): boolean {
+    return type === QUERY_TYPE.MODEL
+  }
+
+  normalize(args:DataPersisterArgs): any {
+    console.log(args)
+  }
+}
+export default Model

+ 24 - 0
services/serializer/serializer.ts

@@ -0,0 +1,24 @@
+import {AnyJson, DataPersisterArgs} from "~/types/interfaces";
+import {denormalizers} from "~/services/serializer/denormalizer/_import";
+import {normalizers} from "~/services/serializer/normalizer/_import";
+import {DENORMALIZER_TYPE} from "~/types/enums";
+
+class Serializer {
+  public normalize(args:DataPersisterArgs){
+    for(const normalizer of normalizers){
+      if(normalizer.support(args.type)){
+        return new normalizer().normalize(args);
+      }
+    }
+  }
+
+  public denormalize(data: AnyJson, type: DENORMALIZER_TYPE): any {
+    for(const denormalizer of denormalizers){
+      if(denormalizer.support(type)){
+        return new denormalizer().denormalize(data);
+      }
+    }
+  }
+}
+
+export default Serializer

+ 0 - 112
services/utils/hydraParser.ts

@@ -1,112 +0,0 @@
-import {AnyJson} from "~/types/types";
-
-/**
- * @category Services/utils
- * @class HydraParser
- * Classe permettant d'assurer le parsing d'une réponse Hydra
- */
-class HydraParser {
-  /**
-   * Parcours une réponse Hydra pour retourner son équivalent en Json
-   * @param {AnyJson} hydraData
-   * @return {AnyJson} réponse parsée
-   */
-  parse(hydraData: AnyJson): AnyJson {
-    if (hydraData['hydra:member']) {
-      hydraData.totalCount = hydraData['hydra:totalItems'];
-      return this.parseCollection(hydraData);
-    } else {
-      return this.parseItem(hydraData);
-    }
-  }
-
-  /**
-   * Méthode de parsing appelé si on est dans un GET
-   * @param {AnyJson} hydraData
-   */
-  parseItem(hydraData: AnyJson): AnyJson {
-    this.populateId(hydraData);
-
-    if (hydraData['hydra:previous']) {
-      let iriParts = hydraData['hydra:previous'].split('/');
-      hydraData.previous = iriParts[iriParts.length - 1];
-    }
-    if (hydraData['hydra:next']) {
-      let iriParts = hydraData['hydra:next'].split('/');
-      hydraData.next = iriParts[iriParts.length - 1];
-    }
-    if (hydraData['hydra:totalItems']) {
-      hydraData.totalItems = hydraData['hydra:totalItems'];
-    }
-    if (hydraData['hydra:itemPosition']) {
-      hydraData.itemPosition = hydraData['hydra:itemPosition'];
-    }
-    return hydraData;
-  }
-
-  /**
-   * Méthode de parsing appelé si on est dans un GET Collection
-   * @param {AnyJson} hydraData
-   */
-  parseCollection(hydraData: AnyJson): AnyJson {
-    let collectionResponse = hydraData['hydra:member'];
-    collectionResponse.metadata = {};
-    collectionResponse.order = {};
-    collectionResponse.search = {};
-
-    // Put metadata in a property of the collection
-    for (const key in hydraData) {
-      const value = hydraData[key];
-      if ('hydra:member' !== key) {
-        collectionResponse.metadata[key] = value;
-      }
-    }
-
-    // Populate href property for all elements of the collection
-    for (const key in collectionResponse) {
-      const value = collectionResponse[key];
-      this.populateAllData(value);
-    }
-
-    if ('undefined' !== typeof (hydraData['hydra:search'])) {
-      let collectionSearch = hydraData['hydra:search']['hydra:mapping'];
-      for (const key in collectionSearch) {
-        const value = collectionSearch[key];
-        if (value['variable'].indexOf("filter[order]") === 0) {
-          collectionResponse.order[value['property']] = value;
-        } else if (value['variable'].indexOf("filter[where]") === 0) {
-          collectionResponse.search[value['property']] = value;
-        }
-      }
-    }
-    return collectionResponse;
-  }
-
-
-  /**
-   * Hydrate l'objet Json avec la valeur id correspondant à l'uri de l'objet
-   * @param {AnyJson} data
-   */
-  populateId(data: AnyJson): void{
-    if (data['@id'] && data['@id'] instanceof String) {
-      var iriParts = data['@id'].split('/');
-      data.id = iriParts[iriParts.length - 1];
-    }
-  }
-
-  /**
-   * Hydrate l'objet JSON de façon récursive (afin de gérer les objet nested)
-   * @param {AnyJson} data
-   */
-  populateAllData(data: AnyJson):void {
-    this.populateId(data);
-    for (const key in data) {
-      const value = data[key];
-      if (value instanceof Object) {
-        this.populateAllData(value);
-      }
-    }
-  }
-}
-
-export const $hydraParser = new HydraParser()

+ 1 - 1
services/utils/objectProperties.ts

@@ -3,7 +3,7 @@
  * @class ObjectProperties
  * Classe aidant à manipuler des Objets
  */
-import {AnyJson} from "~/types/types";
+import {AnyJson} from "~/types/interfaces";
 
 class ObjectProperties {
   /**

+ 0 - 27
services/utils/yamlParser.ts

@@ -1,27 +0,0 @@
-import {AnyJson} from "~/types/types";
-import { read } from 'yaml-import';
-const yaml = require('js-yaml');
-
-/**
- * @category Services/utils
- * @class YamlParser
- * Classe permettant d'assurer le parsing d'un fichier Yaml
- */
-class YamlParser {
-
-  /**
-   * Parse un fichier Yaml pour en retourner son équivalent en Json
-   * @param {string} inPath
-   * @return {AnyJson}
-   */
-  parse(inPath: string): AnyJson {
-    try {
-      return yaml.load(yaml.dump(read(inPath)));
-    }catch (e) {
-      console.debug(e);
-      return {}
-    }
-  }
-}
-
-export const $yamlParser = new YamlParser()

+ 23 - 0
store/form.ts

@@ -0,0 +1,23 @@
+import {formState} from "~/types/interfaces";
+
+export const state = () => ({
+  dirty: false,
+  showConfirmToLeave: false,
+  goAfterLeave: null,
+})
+
+export const mutations = {
+  setDirty(state:formState, dirty:boolean){
+    state.dirty = dirty
+  },
+  setShowConfirmToLeave(state:formState, showConfirmToLeave:boolean){
+    state.showConfirmToLeave = showConfirmToLeave
+  },
+  setGoAfterLeave(state:formState, goAfterLeave:string){
+    state.goAfterLeave = goAfterLeave
+  },
+}
+
+export const actions = {
+
+}

+ 6 - 1
store/index.js

@@ -1,4 +1,5 @@
 import VuexORM from '@vuex-orm/core'
+import {QUERY_TYPE} from "~/types/enums";
 
 const cookieparser = process.server ? require('cookieparser') : undefined
 
@@ -53,7 +54,11 @@ export const actions = {
    * @return {Promise<void>}
    */
   async updateProfile({dispatch, state}) {
-    const my_profile = await this.$http.$get(`/api/my_profile/${state.profile.access.accessId}`)
+    const my_profile = await this.app.context.$dataProvider.invoke({
+      type: QUERY_TYPE.DEFAULT,
+      url: 'my_profile',
+      id: state.profile.access.accessId
+    })
     dispatch('profile/access/setProfile', my_profile)
   },
 }

+ 1 - 1
store/profile/access.ts

@@ -1,5 +1,5 @@
 import {$roleUtils} from '~/services/rights/roleUtils'
-import {AbilitiesType, accessState} from "~/types/types";
+import {AbilitiesType, accessState} from "~/types/interfaces";
 
 export const state = () => ({
   bearer: null,

+ 1 - 1
store/profile/organization.ts

@@ -1,4 +1,4 @@
-import {organizationState} from "~/types/types";
+import {organizationState} from "~/types/interfaces";
 import * as _ from "lodash";
 
 export const state = () => ({

+ 7 - 1
tsconfig.json

@@ -8,6 +8,12 @@
       "ESNext.AsyncIterable",
       "DOM"
     ],
+    "preserveConstEnums": true,
+    "typeRoots": [
+      "./types/types.d.ts",
+      "./types/interfaces.d.ts",
+      "./types/enums.d.ts"
+    ],
     "esModuleInterop": true,
     "allowJs": true,
     "sourceMap": true,
@@ -26,7 +32,7 @@
     "types": [
       "@types/node",
       "@nuxt/types",
-      "@nuxt/http",
+      "@nuxtjs/axios",
       "@nuxtjs/vuetify",
       "@nuxtjs/moment",
       "nuxt-i18n"

+ 23 - 0
types/enums.ts

@@ -0,0 +1,23 @@
+export const enum HTTP_METHOD {
+  POST = 'POST',
+  PUT = 'PUT',
+  GET = 'GET',
+  DELETE = 'DELETE'
+}
+
+export const enum DENORMALIZER_TYPE {
+  DEFAULT,
+  YAML
+}
+
+export const enum QUERY_TYPE {
+  DEFAULT,
+  MODEL,
+  ENUM
+}
+
+export const enum ABILITIES {
+  DISPLAY = 'diplay',
+  READ = 'read',
+  MANAGE = 'manage'
+}

+ 128 - 0
types/interfaces.d.ts

@@ -0,0 +1,128 @@
+import {Model} from "@vuex-orm/core";
+import {Ability} from "@casl/ability";
+import DataPersister from "~/services/dataPersister/dataPersister";
+import DataProvider from "~/services/dataProvider/dataProvider";
+import {Store} from "vuex";
+import {ABILITIES, QUERY_TYPE} from "~/types/enums";
+
+/**
+ * Upgrade du @nuxt/types pour TypeScript
+ */
+declare module '@nuxt/types' {
+  interface Context {
+    $ability(): Ability,
+    $dataPersister: DataPersister,
+    $dataProvider: DataProvider,
+  }
+}
+
+interface ItemMenu {
+  title: string,
+  icon?: string,
+  to?: string,
+  children?: ItemsMenu,
+  isExternalLink?: boolean,
+}
+interface ItemsMenu extends Array<ItemMenu> {}
+
+interface AbilitiesType {
+  action: ABILITIES,
+
+  subject: string,
+  /** an array of fields to which user has (or not) access */
+  fields?: string[]
+  /** an object of conditions which restricts the rule scope */
+  conditions?: any
+  /** indicates whether rule allows or forbids something */
+  inverted?: boolean
+  /** message which explains why rule is forbidden */
+  reason?: string
+}
+
+interface formState {
+  dirty: boolean,
+  showConfirmToLeave: boolean,
+  goAfterLeave: string
+}
+
+interface accessState {
+  bearer: string,
+  accessId: number,
+  name: string,
+  givenName: string,
+  roles: Array<string>,
+  abilities: Array<AbilitiesType>,
+  isAdminAccess: boolean,
+  isAdmin: boolean,
+  isAdministratifManager: boolean,
+  isPedagogicManager: boolean,
+  isFinancialManager: boolean,
+  isCaMember: boolean,
+  isStudent: boolean,
+  isTeacher: boolean,
+  isMember: boolean,
+  isOther: boolean,
+  hasLateralMenu: boolean,
+  hasConfigurationMenu: boolean,
+  hasAccessesMenu: boolean,
+  hasFamilyMenu: boolean
+}
+interface AccessStore extends Store<{profile:{access:accessState}}> {}
+
+interface organizationState {
+  id: number,
+  name: string,
+  product?: string,
+  modules?: Array<string>,
+  hasChildren?: boolean,
+  networks: Array<string>,
+  website?: string,
+  subDomain?: string,
+  parents: Array<organizationState>,
+}
+interface OrganizationStore extends Store<{profile:{organization:organizationState}}> {}
+
+interface AnyJson extends Record<string, any> {}
+interface AnyStore extends Store<any> {}
+
+interface EnumChoice {
+  value: string,
+  label: string
+}
+interface EnumChoices extends Array<EnumChoice> {}
+
+interface UrlArgs {
+  readonly type: QUERY_TYPE,
+  readonly url?:string,
+  readonly enumType?:string,
+  readonly model?: typeof Model,
+  readonly root_model?: typeof Model,
+  readonly id?:any,
+  readonly root_id?:number
+}
+
+interface DataPersisterArgs extends UrlArgs{
+  readonly hook?:string
+}
+
+interface HookPersister{
+  invoke(args:DataPersisterArgs): Promise<any>,
+}
+
+interface DataProviderArgs extends UrlArgs{
+  readonly hook?:string
+}
+
+interface HookProvider{
+  invoke(args:DataProviderArgs): Promise<any>,
+}
+interface Provider{
+  invoke(data: AnyJson): Promise<any>,
+}
+interface Denormalizer{
+  denormalize(data:any): any,
+}
+interface Normalizer{
+  normalize(args:DataPersisterArgs): any,
+}
+

+ 1 - 85
types/types.d.ts

@@ -1,86 +1,2 @@
-import {
-  Store
-} from "vuex";
-import {Ability} from "@casl/ability";
-import {Rest} from "~/services/queries/rest";
-
-/**
- * Upgrade du @nuxt/types pour TypeScript
- */
-declare module '@nuxt/types' {
-  interface Context {
-    $ability(): Ability,
-    $rest: Rest
-  }
-}
-
-interface ItemMenu {
-  title: string,
-  icon?: string,
-  to?: string,
-  children?: ItemsMenu,
-  isExternalLink?: boolean,
-}
-interface ItemsMenu extends Array<ItemMenu> {}
-
-interface AbilitiesType {
-  action: 'display' | 'read' | 'manage',
-  subject: string,
-  /** an array of fields to which user has (or not) access */
-  fields?: string[]
-  /** an object of conditions which restricts the rule scope */
-  conditions?: any
-  /** indicates whether rule allows or forbids something */
-  inverted?: boolean
-  /** message which explains why rule is forbidden */
-  reason?: string
-}
-
-interface accessState {
-  bearer: string,
-  accessId: number,
-  name: string,
-  givenName: string,
-  roles: Array<string>,
-  abilities: Array<AbilitiesType>,
-  isAdminAccess: boolean,
-  isAdmin: boolean,
-  isAdministratifManager: boolean,
-  isPedagogicManager: boolean,
-  isFinancialManager: boolean,
-  isCaMember: boolean,
-  isStudent: boolean,
-  isTeacher: boolean,
-  isMember: boolean,
-  isOther: boolean,
-  hasLateralMenu: boolean,
-  hasConfigurationMenu: boolean,
-  hasAccessesMenu: boolean,
-  hasFamilyMenu: boolean
-}
-interface AccessStore extends Store<{profile:{access:accessState}}> {}
-
-interface organizationState {
-  id: number,
-  name: string,
-  product?: string,
-  modules?: Array<string>,
-  hasChildren?: boolean,
-  networks: Array<string>,
-  website?: string,
-  subDomain?: string,
-  parents: Array<organizationState>,
-}
-interface OrganizationStore extends Store<{profile:{organization:organizationState}}> {}
-
-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";
+import {Query, Repository, Model} from "@vuex-orm/core";
 export type RepositoryOrQuery<R extends Repository = Repository, Q extends Query = Query> = R | Q;

+ 0 - 21
use/form/useFormInputSetup.ts

@@ -1,21 +0,0 @@
-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)

+ 8 - 2
use/form/utils.ts

@@ -1,13 +1,19 @@
 import {ref, useContext} from "@nuxtjs/composition-api";
+import {QUERY_TYPE} from "~/types/enums";
 
 export class Utils{
   public static useHandleSiret(){
-    const {app:{i18n}, $rest} = useContext()
+    const {app:{i18n}, $dataProvider} = useContext()
     const siretError = ref(false)
     const siretErrorMessage = ref('')
 
     const checkSiret = async (siret:string) => {
-      const response = await $rest.getItem(`/api/siret-checking`, siret)
+      const response = await $dataProvider.invoke({
+        type: QUERY_TYPE.DEFAULT,
+        url: 'siret-checking',
+        id: siret
+      })
+
       if(response){
         siretError.value = !response.isCorrect
         siretErrorMessage.value = response.isCorrect ? '' : i18n.t('siret_error') as string

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

@@ -1,4 +1,4 @@
-import {ItemMenu, ItemsMenu} from "~/types/types";
+import {ItemMenu, ItemsMenu} from "~/types/interfaces";
 import {$organizationProfile} from "~/services/profile/organizationProfile";
 import BaseMenu from "~/use/layout/Menus/baseMenu";
 

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

@@ -1,4 +1,4 @@
-import {ItemMenu, ItemsMenu} from "~/types/types";
+import {ItemMenu, ItemsMenu} from "~/types/interfaces";
 import BaseMenu from "~/use/layout/Menus/baseMenu";
 
 class AccountMenu extends BaseMenu{

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

@@ -1,4 +1,4 @@
-import {ItemMenu, ItemsMenu} from "~/types/types";
+import {ItemMenu, ItemsMenu} from "~/types/interfaces";
 import BaseMenu from "~/use/layout/Menus/baseMenu";
 
 class Admin2iosMenu extends BaseMenu{

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

@@ -1,4 +1,4 @@
-import {ItemMenu, ItemsMenu} from "~/types/types";
+import {ItemMenu, ItemsMenu} from "~/types/interfaces";
 import BaseMenu from "~/use/layout/Menus/baseMenu";
 
 class AgendaMenu extends BaseMenu{

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

@@ -1,4 +1,4 @@
-import {ItemMenu} from "~/types/types";
+import {ItemMenu} from "~/types/interfaces";
 
 class BaseMenu{
   protected $config:any;

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

@@ -1,4 +1,4 @@
-import {ItemMenu, ItemsMenu} from "~/types/types";
+import {ItemMenu, ItemsMenu} from "~/types/interfaces";
 import BaseMenu from "~/use/layout/Menus/baseMenu";
 
 class BillingMenu extends BaseMenu{

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

@@ -1,4 +1,4 @@
-import {ItemMenu, ItemsMenu} from "~/types/types";
+import {ItemMenu, ItemsMenu} from "~/types/interfaces";
 import BaseMenu from "~/use/layout/Menus/baseMenu";
 
 class CommunicationMenu extends BaseMenu{

部分文件因为文件数量过多而无法显示