ソースを参照

refactor edition / creation pages with new Form components

Olivier Massot 2 年 前
コミット
8618f7937e

+ 0 - 41
components/Layout/Parameters/CycleEditForm.vue

@@ -1,41 +0,0 @@
-<template>
-    <UiForm
-        ref="form"
-        :model="Cycle"
-        :entity="cycle"
-        :submitActions="submitActions"
-    >
-      <UiInputText field="label" v-model="cycle.label" :rules="rules()" />
-    </UiForm>
-</template>
-
-<script setup lang="ts">
-import Cycle from "~/models/Education/Cycle";
-import {AnyJson} from "~/types/data";
-import {SUBMIT_TYPE} from "~/types/enum/enums";
-
-const props = defineProps({
-  cycle: {
-    type: Object as () => Cycle,
-    required: true
-  }
-})
-
-const i18n = useI18n()
-
-const goBackRoute = { path: `/parameters`, query: { tab: 'teaching' } }
-
-const submitActions = computed(() => {
-  let actions: AnyJson = {}
-  actions[SUBMIT_TYPE.SAVE_AND_BACK] = goBackRoute
-  return actions
-})
-
-const rules = () => [
-  (label: string | null) => (label !== null && label.length > 0) || i18n.t('please_enter_a_value'),
-]
-</script>
-
-<style scoped lang="scss">
-
-</style>

+ 1 - 1
components/Ui/Button/Submit.vue

@@ -22,7 +22,7 @@
       <template #activator="{ on, attrs }">
         <v-toolbar-title v-on="on">
           <v-icon class="pl-3 pr-3">
-            {{ dropDirection === 'top' ? 'fa-caret-up' : 'fa-caret-down'}}
+            {{ dropDirection === 'top' ? 'fa fa-caret-up' : 'fa fa-caret-down'}}
           </v-icon>
         </v-toolbar-title>
       </template>

+ 7 - 3
components/Ui/Form.vue

@@ -84,14 +84,13 @@ de quitter si des données ont été modifiées.
 import {computed, ComputedRef, ref, Ref} from "@vue/reactivity";
 import {FORM_FUNCTION, SUBMIT_TYPE, TYPE_ALERT} from "~/types/enum/enums";
 import { useFormStore } from "~/stores/form";
-import {Route} from "@intlify/vue-router-bridge";
+import {Route, RouteLocationRaw} from "@intlify/vue-router-bridge";
 import {useEntityManager} from "~/composables/data/useEntityManager";
 import ApiModel from "~/models/ApiModel";
 import {usePageStore} from "~/stores/page";
-import {watch} from "@vue/runtime-core";
+import {PropType, watch} from "@vue/runtime-core";
 import {AnyJson} from "~/types/data";
 import * as _ from 'lodash-es'
-import {Bool} from "pinia-orm/dist/decorators";
 import {useRefreshProfile} from "~/composables/data/useRefreshProfile";
 
 const props = defineProps({
@@ -116,6 +115,11 @@ const props = defineProps({
     type: Function,
     required: false
   },
+  goBackRoute: {
+    type: Object as PropType<RouteLocationRaw>,
+    required: false,
+    default: null
+  },
   /**
    * Types de soumission disponibles (enregistrer / enregistrer et quitter)
    */

+ 89 - 0
components/Ui/Form/Creation.vue

@@ -0,0 +1,89 @@
+<template>
+  <UiForm
+      :model="model"
+      :entity="entity"
+      :submitActions="submitActions"
+  >
+    <template #form.button>
+      <v-btn v-if="goBackRoute" class="theme-neutral mr-3" @click="quit">
+        {{ $t('cancel') }}
+      </v-btn>
+    </template>
+
+    <slot v-bind="{model, entity}"/>
+  </UiForm>
+</template>
+
+<script setup lang="ts">
+
+import {PropType} from "@vue/runtime-core";
+import {RouteLocationRaw} from "@intlify/vue-router-bridge";
+import ApiModel from "~/models/ApiModel";
+import {AnyJson} from "~/types/data";
+import {SUBMIT_TYPE} from "~/types/enum/enums";
+import {useEntityManager} from "~/composables/data/useEntityManager";
+
+const props = defineProps({
+  /**
+   * Classe de l'ApiModel (ex: Organization, Notification, ...)
+   */
+  model: {
+    type: Function as any as () => typeof ApiModel,
+    required: true
+  },
+  /**
+   * Route de retour
+   */
+  goBackRoute: {
+    type: Object as PropType<RouteLocationRaw>,
+    required: false,
+    default: null
+  },
+  /**
+   * La validation est en cours
+   */
+  validationPending: {
+    type: Boolean,
+    required: false,
+    default: false
+  },
+  /**
+   * Faut-il rafraichir le profil à la soumission du formulaire?
+   */
+  refreshProfile: {
+    type: Boolean,
+    required: false,
+    default: false
+  }
+})
+
+const router = useRouter()
+const { em } = useEntityManager()
+
+//@ts-ignore Pour une raison que j'ignore, le type Ref<ApiModel> met en erreur la prop entity de UiForm...
+const entity: ApiModel = reactive(em.newInstance(props.model))
+
+const submitActions = computed(() => {
+  let actions: AnyJson = {}
+
+  if (props.goBackRoute !== null) {
+    actions[SUBMIT_TYPE.SAVE_AND_BACK] = props.goBackRoute
+  } else {
+    actions[SUBMIT_TYPE.SAVE] = null
+  }
+  return actions
+})
+
+const quit = () => {
+  if (!props.goBackRoute) {
+    throw Error('no go back route defined')
+  }
+
+  router.push(props.goBackRoute)
+}
+
+</script>
+
+<style scoped lang="scss">
+
+</style>

+ 115 - 0
components/Ui/Form/Edition.vue

@@ -0,0 +1,115 @@
+<template>
+  <UiLoadingPanel v-if="pending" />
+  <UiForm
+      v-else
+      :model="model"
+      :entity="entity"
+      :submitActions="submitActions"
+  >
+    <template #form.button>
+      <v-btn v-if="goBackRoute" class="theme-neutral mr-3" @click="quit">
+        {{ $t('cancel') }}
+      </v-btn>
+    </template>
+
+    <slot v-bind="{model, entity}"/>
+  </UiForm>
+</template>
+
+<script setup lang="ts">
+
+import {PropType} from "@vue/runtime-core";
+import {RouteLocationRaw} from "@intlify/vue-router-bridge";
+import ApiModel from "~/models/ApiModel";
+import {AnyJson} from "~/types/data";
+import {SUBMIT_TYPE} from "~/types/enum/enums";
+import {useEntityManager} from "~/composables/data/useEntityManager";
+import {ref} from "vue/dist/vue";
+import {useRoute} from "vue-router";
+import ResidenceArea from "~/models/Billing/ResidenceArea";
+import {useEntityFetch} from "~/composables/data/useEntityFetch";
+
+const props = defineProps({
+  /**
+   * Classe de l'ApiModel (ex: Organization, Notification, ...)
+   */
+  model: {
+    type: Function as any as () => typeof ApiModel,
+    required: true
+  },
+  /**
+   * Id de l'objet
+   * Si non renseigné, le component essaiera de l'extraire de la route actuelle
+   */
+  id: {
+    type: Number,
+    required: false,
+    default: null
+  },
+  /**
+   * Route de retour
+   */
+  goBackRoute: {
+    type: Object as PropType<RouteLocationRaw>,
+    required: false,
+    default: null
+  },
+  /**
+   * La validation est en cours
+   */
+  validationPending: {
+    type: Boolean,
+    required: false,
+    default: false
+  },
+  /**
+   * Faut-il rafraichir le profil à la soumission du formulaire?
+   */
+  refreshProfile: {
+    type: Boolean,
+    required: false,
+    default: false
+  }
+})
+
+const { fetch } = useEntityFetch()
+const route = useRoute()
+const router = useRouter()
+
+const entityId = computed(() => {
+  if (props.id !== null) {
+    return props.id
+  }
+
+  return parseInt(route.params.id as string)
+})
+
+const { data: entity, pending } = fetch(
+    props.model,
+    entityId.value
+)
+
+const submitActions = computed(() => {
+  let actions: AnyJson = {}
+
+  if (props.goBackRoute !== null) {
+    actions[SUBMIT_TYPE.SAVE_AND_BACK] = props.goBackRoute
+  } else {
+    actions[SUBMIT_TYPE.SAVE] = null
+  }
+  return actions
+})
+
+const quit = () => {
+  if (!props.goBackRoute) {
+    throw Error('no go back route defined')
+  }
+
+  router.push(props.goBackRoute)
+}
+
+</script>
+
+<style scoped lang="scss">
+
+</style>

+ 24 - 22
pages/parameters/cycles/[id].vue

@@ -1,30 +1,32 @@
 <template>
-  <main>
-    <LayoutContainer>
-      <UiLoadingPanel v-if="pending" />
-      <div v-else>
-        <LayoutParametersCycleEditForm :cycle="cycle" />
-      </div>
-    </LayoutContainer>
-  </main>
+  <LayoutContainer>
+    <div>
+      <h2>{{ $t('cycle') }}</h2>
+      <UiFormEdition
+          :model="Cycle"
+          :go-back-route="goBackRoute"
+      >
+        <template v-slot="{ entity }">
+          <UiInputText
+              field="label"
+              v-model="entity.label"
+              :rules="rules()"
+          />
+        </template>
+      </UiFormEdition>
+    </div>
+  </LayoutContainer>
 </template>
-
 <script setup lang="ts">
-import {useEntityFetch} from "~/composables/data/useEntityFetch";
+import {RouteLocationPathRaw} from 'vue-router'
+import { useI18n } from 'vue-i18n'
 import Cycle from "~/models/Education/Cycle";
 
-const { fetch } = useEntityFetch()
-const route = useRoute()
-
-if (!route.params.id || isNaN(route.params.id as any)) {
-  throw new Error('no id found')
-}
+const i18n = useI18n()
 
-const id: number = parseInt(route.params.id as string)
+const goBackRoute = { path: `/parameters`, query: { tab: 'teaching' } }
 
-const { data: cycle, pending } = fetch(Cycle, id)
+const rules = () => [
+  (label: string | null) => (label !== null && label.length > 0) || i18n.t('please_enter_a_value'),
+]
 </script>
-
-<style scoped lang="scss">
-
-</style>

+ 13 - 43
pages/parameters/education_timings/[id].vue

@@ -1,63 +1,33 @@
 <template>
   <LayoutContainer>
-    <UiLoadingPanel v-if="pending" />
-    <div v-else>
+    <div>
       <h2>{{ $t('educationTiming') }}</h2>
-      <UiForm
-        ref="form"
+      <UiFormEdition
         :model="EducationTiming"
-        :entity="educationTiming"
-        :submitActions="submitActions"
+        :go-back-route="goBackRoute"
       >
-        <UiInputNumber
-          field="educationTiming"
-          v-model="educationTiming.timing"
-          :rules="rules()"
-        />
-      </UiForm>
-      <v-btn class="mr-12" @click="quit">
-        {{ $t('back') }}
-      </v-btn>
+        <template v-slot="{ entity }">
+          <UiInputNumber
+            field="educationTiming"
+            v-model="entity.timing"
+            :rules="rules()"
+          />
+        </template>
+      </UiFormEdition>
     </div>
   </LayoutContainer>
 </template>
 <script setup lang="ts">
-import {ref, computed, ComputedRef} from 'vue'
-import { useEntityFetch } from '~/composables/data/useEntityFetch'
 import EducationTiming from '~/models/Education/EducationTiming'
-import {RouteLocationPathRaw, useRoute, useRouter} from 'vue-router'
+import {RouteLocationPathRaw} from 'vue-router'
 import { useI18n } from 'vue-i18n'
-import { AnyJson } from '~/types/data'
-import { SUBMIT_TYPE } from '~/types/enum/enums'
-import {Ref} from "@vue/reactivity";
 
 const i18n = useI18n()
-const { fetch } = useEntityFetch()
-const route = useRoute()
-const router = useRouter()
-
-const educationTimingId: Ref<number> = ref(parseInt(route.params.id as string))
 
 const goBackRoute: RouteLocationPathRaw = { path: `/parameters`, query: { tab: 'educationTimings' } }
 
-const submitActions = computed(() => {
-  let actions: AnyJson = {}
-  actions[SUBMIT_TYPE.SAVE_AND_BACK] = goBackRoute
-  return actions
-})
-
-const { data: educationTiming, pending } = fetch(
-  EducationTiming,
-  educationTimingId.value
-)
-
 const rules = () => [
   (timing: string | null) =>
-    (timing !== null && timing.length > 0) || i18n.t('please_enter_a_value'),
+    (timing !== null && parseInt(timing) > 0) || i18n.t('please_enter_a_value'),
 ]
-
-const quit = () => {
-  router.push(goBackRoute)
-}
-
 </script>

+ 19 - 41
pages/parameters/education_timings/new.vue

@@ -2,63 +2,41 @@
   <LayoutContainer>
     <div>
       <h2>{{ $t("new_education_timing")}}</h2>
-      <UiForm
-        ref="form"
+      <UiFormCreation
         :model="EducationTiming"
-        :entity="educationTiming"
-        :submitActions="submitActions"
+        :go-back-route="goBackRoute"
       >
-        <v-container :fluid="true" class="container">
-          <v-row>
-            <v-col cols="12" sm="6"> </v-col>
-          </v-row>
-          <v-row>
-            <v-col cols="12" sm="6">
-              <UiInputNumber
-                v-model="educationTiming.timing"
-                field="new_education_timings"
-                :rules="rules()"
-              />
-            </v-col>
-          </v-row>
-        </v-container>
-      </UiForm>
-      <v-btn class="mr-12" @click="quit">
-        {{ $t('back') }}
-      </v-btn>
+        <template v-slot="{ entity }">
+          <v-container :fluid="true" class="container">
+            <v-row>
+              <v-col cols="12" sm="6"> </v-col>
+            </v-row>
+            <v-row>
+              <v-col cols="12" sm="6">
+                <UiInputNumber
+                  v-model="entity.timing"
+                  field="new_education_timings"
+                  :rules="rules()"
+                />
+              </v-col>
+            </v-row>
+          </v-container>
+        </template>
+      </UiFormCreation>
     </div>
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
-import { computed } from 'vue'
-import { AnyJson } from '~/types/data'
-import { SUBMIT_TYPE } from '~/types/enum/enums'
 import EducationTiming from '~/models/Education/EducationTiming'
 import { useI18n } from 'vue-i18n'
-import { useEntityManager } from '~/composables/data/useEntityManager'
 
 const i18n = useI18n()
-const router = useRouter()
-const { em } = useEntityManager()
-
-//@ts-ignore
-let educationTiming: EducationTiming = reactive(em.newInstance(EducationTiming))
 
 const goBackRoute = { path: `/parameters`, query: { tab: 'educationTimings' } }
 
-const submitActions = computed(() => {
-  let actions: AnyJson = {}
-  actions[SUBMIT_TYPE.SAVE_AND_BACK] = goBackRoute
-  return actions
-})
-
 const rules = () => [
   (timing: number | null ) =>
     (timing !== null && timing > 0) || i18n.t('please_enter_a_value'),
 ]
-
-const quit = () => {
-  router.push(goBackRoute)
-}
 </script>

+ 12 - 38
pages/parameters/residence_areas/[id].vue

@@ -1,62 +1,36 @@
 <template>
   <LayoutContainer>
-    <UiLoadingPanel v-if="pending" />
-    <div v-else>
-      <h2>Editer la zone de résidence</h2>
-      <UiForm
-        ref="form"
+    <div>
+      <h2>Éditer la zone de résidence</h2>
+      <UiFormEdition
         :model="ResidenceArea"
-        :entity="residence_areas"
-        :submitActions="submitActions"
+        :go-back-route="goBackRoute"
       >
-        <UiInputText
-          field="label"
-          v-model="residence_areas.label"
-          :rules="rules()"
-        />
-      </UiForm>
+        <template v-slot="{ entity }">
+          <UiInputText
+            field="label"
+            v-model="entity.label"
+            :rules="rules()"
+          />
+        </template>
+      </UiFormEdition>
     </div>
-    <v-btn class="mr-12" @click="quit">
-      {{ $t('back') }}
-    </v-btn>
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
-import { ref } from 'vue'
 import { useEntityFetch } from '~/composables/data/useEntityFetch'
 import ResidenceArea from '~/models/Billing/ResidenceArea'
-import { useRoute } from 'vue-router'
 import { useI18n } from 'vue-i18n'
-import { AnyJson } from '~/types/data'
-import { SUBMIT_TYPE } from '~/types/enum/enums'
 
 const i18n = useI18n()
 const { fetch } = useEntityFetch()
 const router = useRouter()
-const route = useRoute()
-
-const residenceId = ref(parseInt(route.params.id as string))
 
 const goBackRoute = { path: `/parameters`, query: { tab: 'residenceAreas' } }
 
-const submitActions = computed(() => {
-  let actions: AnyJson = {}
-  actions[SUBMIT_TYPE.SAVE_AND_BACK] = goBackRoute
-  return actions
-})
-
-const { data: residence_areas, pending } = fetch(
-  ResidenceArea,
-  residenceId.value
-)
-
 const rules = () => [
   (label: string | null) =>
     (label !== null && label.length > 0) || i18n.t('please_enter_a_value'),
 ]
-
-const quit = () => {
-  router.push(goBackRoute)
-}
 </script>

+ 18 - 43
pages/parameters/residence_areas/new.vue

@@ -1,65 +1,40 @@
 <template>
   <LayoutContainer>
-    <UiLoadingPanel v-if="pending" />
-    <div v-else>
+    <div>
       <h2>{{ $t('create_a_new_residence_area') }}</h2>
-      <UiForm
-        ref="form"
+      <UiFormCreation
         :model="ResidenceArea"
-        :entity="residence_areas"
-        :submitActions="submitActions"
+        :go-back-route="goBackRoute"
       >
-        <v-container :fluid="true" class="container">
-          <v-row>
-            <v-col cols="12" sm="6">
-              <UiInputText
-                v-model="residence_areas.label"
-                field="label"
-                type="string"
-                :rules="rules()"
-              />
-            </v-col>
-          </v-row>
-        </v-container>
-      </UiForm>
-      <v-btn class="mr-12" @click="quit">
-        {{ $t('back') }}
-      </v-btn>
+        <template v-slot="{ entity }">
+          <v-container :fluid="true" class="container">
+            <v-row>
+              <v-col cols="12" sm="6">
+                <UiInputText
+                  v-model="entity.label"
+                  field="label"
+                  type="string"
+                  :rules="rules()"
+                />
+              </v-col>
+            </v-row>
+          </v-container>
+        </template>
+      </UiFormCreation>
     </div>
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
-import { ref, onMounted, computed } from 'vue'
-import { Ref } from '@vue/reactivity'
-import { useEntityFetch } from '~/composables/data/useEntityFetch'
-import { AnyJson } from '~/types/data'
-import { SUBMIT_TYPE } from '~/types/enum/enums'
 import ResidenceArea from '~/models/Billing/ResidenceArea'
 import { useI18n } from 'vue-i18n'
-import { useEntityManager } from '~/composables/data/useEntityManager'
 
 const i18n = useI18n()
-const router = useRouter()
-const { em } = useEntityManager()
-
-//@ts-ignore
-const residence_areas: Ref<ResidenceArea> = reactive(em.newInstance(ResidenceArea))
 
 const goBackRoute = { path: `/parameters`, query: { tab: 'residenceAreas' } }
 
-const submitActions = computed(() => {
-  let actions: AnyJson = {}
-  actions[SUBMIT_TYPE.SAVE_AND_BACK] = goBackRoute
-  return actions
-})
-
 const rules = () => [
   (label: string | null) =>
     (label !== null && label.length > 0) || i18n.t('please_enter_a_value'),
 ]
-
-const quit = () => {
-  router.push(goBackRoute)
-}
 </script>

+ 1 - 1
types/enum/enums.ts

@@ -72,6 +72,6 @@ export const enum ALERT_STATE_COTISATION {
 
 export const enum SUBMIT_TYPE {
   SAVE = 'save',
-  SAVE_AND_BACK= 'save_and_back'
+  SAVE_AND_BACK = 'save_and_back'
 }