Prechádzať zdrojové kódy

add page new subdomain with validation

Olivier Massot 3 rokov pred
rodič
commit
6a1a867b0b

+ 26 - 35
components/Form/Parameters/SubdomainNew.vue

@@ -7,9 +7,11 @@
 
         <UiForm
           :id="id"
+          ref="form"
           :model="model"
           :query="query()"
-          :submitActions="submitActions">
+          :submitActions="submitActions"
+        >
           <template #form.input="{entry, updateRepository}">
             <v-container fluid class="container">
               <v-row>
@@ -24,11 +26,10 @@
                     label="subdomain"
                     :data="entry['subdomain']"
                     type="string"
-                    :rules="rules().subdomainRules"
-                    :error="subdomainError"
-                    :error-message="subdomainErrorMessage"
-                    @update="checkSubdomainHook($event, updateRepository)"
+                    :rules="rules()"
+                    @change="checkSubdomainHook($event); updateRepository(entry['subdomain'], 'subdomain')"
                   />
+                  <span v-if="entry['subdomain'] && subdomainAvailable">Ce sous-domaine est disponible</span>
                 </v-col>
 
               </v-row>
@@ -51,12 +52,12 @@
 </template>
 
 <script lang="ts">
-import {defineComponent, computed, useContext, useFetch} from '@nuxtjs/composition-api'
+import {defineComponent, computed, useContext, Ref, ref} from '@nuxtjs/composition-api'
 import { Repository as VuexRepository } from '@vuex-orm/core/dist/src/repository/Repository'
 import { Query, Model } from '@vuex-orm/core'
-import {QUERY_TYPE, SUBMIT_TYPE} from '~/types/enums'
+import {SUBMIT_TYPE} from '~/types/enums'
 import { repositoryHelper } from '~/services/store/repository'
-import {AnyJson, ApiResponse, MobytUserStatus} from "~/types/interfaces";
+import {AnyJson} from "~/types/interfaces";
 import {Subdomain} from "~/models/Organization/Subdomain";
 import {useValidator} from "~/composables/form/useValidator";
 
@@ -71,8 +72,10 @@ export default defineComponent({
     const {$dataProvider, app:{i18n}} = useContext()
     const repository: VuexRepository<Model> = repositoryHelper.getRepository(Subdomain)
     const query: Query = repository.query()
+    const subdomainAvailable: Ref<boolean | null> = ref(null)
+    const form = ref(null);
 
-    const { subdomainError, subdomainErrorMessage, checkSubdomainUnity } = useValidator($dataProvider, i18n).useHandleSubdomain()
+    const { checkSubdomainAvailability } = useValidator($dataProvider, i18n).useHandleSubdomain()
 
     const submitActions = computed(() => {
       let actions:AnyJson = {}
@@ -80,18 +83,11 @@ export default defineComponent({
       return actions
     })
 
-    // TODO: unity error message don't show up
-    // TODO: submit is not blocked even when subdomain is invalid
-    const checkSubdomainHook = async (subdomain: string, updateRepository: any) => {
-      const valid = (subdomain?.match(/^[\w\-]{2,60}$/) !== null)
-      console.log('valid: ' + valid)
-      if (!valid) {
-        return
-      }
-      await checkSubdomainUnity(subdomain)
-      console.log('unity error: ' + subdomainError.value + ' - ' + subdomainErrorMessage.value)
-      if (!subdomainError.value) {
-        updateRepository(subdomain, 'subdomain')
+    const checkSubdomainHook = async (subdomain: string | null) => {
+      subdomainAvailable.value = null
+      if (subdomain !== null && subdomain.match(/^[\w\-]{2,60}$/) !== null) {
+        subdomainAvailable.value = await checkSubdomainAvailability(subdomain);
+        (form.value as any).validate()
       }
     }
 
@@ -99,25 +95,20 @@ export default defineComponent({
     return {
       model: Subdomain,
       query: () => query,
-      rules: () => getRules(i18n),
-      panel: 0,
       submitActions,
-      subdomainError,
-      subdomainErrorMessage,
-      checkSubdomainHook
+      form,
+      checkSubdomainHook,
+      subdomainAvailable,
+      rules: () => [
+        (subdomain: string | null) => (subdomain !== null) || i18n.t('please_enter_a_value_for_the_subdomain'),
+        (subdomain: string | null) => (subdomain !== null && subdomain.length >= 2 && subdomain.length <=60) || i18n.t('subdomain_need_to_have_0_to_60_cars'),
+        (subdomain: string | null) => (subdomain !== null && subdomain.match(/^[\w\-]+$/) !== null) || i18n.t('subdomain_can_not_contain_spaces_or_special_cars'),
+        () => (subdomainAvailable.value === true) || i18n.t('this_subdomain_is_already_in_use')
+      ]
     }
   },
   beforeDestroy() {
     repositoryHelper.cleanRepository(Subdomain)
   }
 })
-
-function getRules (i18n: any) {
-  return {
-    subdomainRules: [
-      (subdomain: string) => (subdomain?.length <= 60 && subdomain?.length >= 2) || i18n.t('subdomain_need_to_have_0_to_60_cars'),
-      (subdomain: string) => subdomain?.match(/^[\w\-]+$/) !== null || i18n.t('subdomain_can_not_contain_spaces_or_special_cars'),
-    ]
-  }
-}
 </script>

+ 7 - 2
components/Ui/Form.vue

@@ -120,8 +120,12 @@ export default defineComponent({
       repositoryHelper.updateStoreFromField(props.model, entry.value, newValue, field)
     }
 
+    const validate = function () {
+      return form.value.validate()
+    }
+
     const submit = async (next: string|null = null) => {
-      if(form.value.validate()){
+      if(await validate()){
         markAsNotDirty()
 
         try {
@@ -202,7 +206,8 @@ export default defineComponent({
       quitForm,
       closeDialog,
       saveAndQuit,
-      actions
+      actions,
+      validate
     }
   }
 })

+ 16 - 15
components/Ui/Input/Text.vue

@@ -5,20 +5,21 @@ Champs de saisie de texte
 -->
 
 <template>
-    <v-text-field
-      autocomplete="off"
-      :value="data"
-      :label="$t(label_field)"
-      :rules="rules"
-      :disabled="readonly"
-      :type="type === 'password' ? (show ? 'text' : type) : type"
-      :error="error || !!violation"
-      :error-messages="errorMessage || violation ? $t(violation) : ''"
-      @change="onChange($event)"
-      v-mask="mask"
-      :append-icon="type === 'password' ? (show ? 'mdi-eye' : 'mdi-eye-off') : ''"
-      @click:append="show = !show"
-    />
+  <v-text-field
+    autocomplete="off"
+    :value="data"
+    :label="$t(label_field)"
+    :rules="rules"
+    :disabled="readonly"
+    :type="type === 'password' ? (show ? 'text' : type) : type"
+    :error="error || !!violation"
+    :error-messages="errorMessage || (violation ? $t(violation) : '')"
+    @change="onChange($event); $emit('change', $event)"
+    @input="$emit('input', $event, field)"
+    v-mask="mask"
+    :append-icon="type === 'password' ? (show ? 'mdi-eye' : 'mdi-eye-off') : ''"
+    @click:append="show = !show"
+  />
 </template>
 
 <script lang="ts">
@@ -93,7 +94,7 @@ export default defineComponent({
 })
 </script>
 
-<style>
+<style scoped>
   input:read-only{
     color: #666 !important;
   }

+ 4 - 17
composables/form/useValidator.ts

@@ -40,29 +40,16 @@ export function useValidator($dataProvider: DataProvider, i18n: VueI18n) {
   }
 
   function useHandleSubdomain() {
-    const subdomainError: Ref<boolean> = ref(false)
-    const subdomainErrorMessage: Ref<string> = ref('')
 
-    const checkSubdomainUnity = async (subdomain: string) => {
-      const response: ApiResponse = await $dataProvider.invoke({
+    const checkSubdomainAvailability = async (subdomain: string | null) => {
+      const response = await $dataProvider.invoke({
         type: QUERY_TYPE.DEFAULT,
         url: '/api/subdomains/?subdomain[]=' + subdomain
       })
-      if (typeof response !== 'undefined') {
-        // @ts-ignore
-        if (response.metadata.totalItems > 0) {
-          subdomainError.value = true
-          subdomainErrorMessage.value = i18n.t('this_subdomain_is_already_in_use') as string
-        }
-      } else {
-        subdomainError.value = true
-        subdomainErrorMessage.value = i18n.t('could_not_contact_server_please_try_again') as string
-      }
+      return typeof response !== 'undefined' && response.metadata.totalItems === 0
     }
     return {
-      checkSubdomainUnity,
-      subdomainError,
-      subdomainErrorMessage
+      checkSubdomainAvailability
     }
   }
 

+ 3 - 0
lang/content/parameters/fr-FR.js

@@ -11,6 +11,9 @@ export default (context, locale) => {
     pleaseEnterYourNewSubdomain: 'Veuillez saisir votre nouveau sous-domaine',
     subdomain_need_to_have_0_to_60_cars: 'Le sous-domaine doit comporter de 2 à 60 caractères',
     this_subdomain_is_already_in_use: 'Ce sous-domaine est déjà utilisé',
+    this_subdomain_is_available: 'Ce sous-domaine est disponible',
     subdomain_can_not_contain_spaces_or_special_cars: 'Le sous-domaine ne doit pas contenir d\'espaces ni de caractères spéciaux',
+    please_enter_a_value_for_the_subdomain: 'Veuillez saisir une valeur pour le sous-domaine',
+    please_wait_for_validation: 'Veuillez patienter, validation en cours',
   })
 }

+ 1 - 1
pages/parameters/subdomain/_id.vue

@@ -75,7 +75,7 @@ export default defineComponent({
       return queryHelper.getFlattenEntry(query.value, id)
     })
 
-    const submit = async (next: string|null = null) => {
+    const submit = async () => {
       await $dataPersister.invoke({
         type: QUERY_TYPE.MODEL,
         model: Subdomain,

+ 0 - 5
pages/parameters/subdomain/new.vue

@@ -14,9 +14,7 @@
 <script lang="ts">
 import {defineComponent, useContext} from '@nuxtjs/composition-api'
 import {useDataUtils} from "~/composables/data/useDataUtils";
-import {ResidenceArea} from "~/models/Billing/ResidenceArea";
 import {Subdomain} from "~/models/Organization/Subdomain";
-import {repositoryHelper} from "~/services/store/repository";
 
 export default defineComponent({
   name: 'NewFormParametersSubdomain',
@@ -34,9 +32,6 @@ export default defineComponent({
       loading,
       item
     }
-  },
-  beforeDestroy() {
-    repositoryHelper.cleanRepository(Subdomain)
   }
 })
 </script>