Browse Source

review validation

Olivier Massot 1 year ago
parent
commit
6bf43d8225
2 changed files with 132 additions and 105 deletions
  1. 82 105
      components/Contact/Form.vue
  2. 50 0
      models/Maestro/ContactRequest.ts

+ 82 - 105
components/Contact/Form.vue

@@ -1,8 +1,10 @@
 <template>
   <LayoutContainer>
+    <div id="anchor" />
     <v-form
+      v-if="!contactRequestSent"
       ref="form"
-      v-model="valid"
+      v-model="isValid"
       lazy-validation
     >
       <v-container>
@@ -20,7 +22,7 @@
         <v-row>
           <v-col cols="12">
             <v-radio-group
-              v-model="gender"
+              v-model="contactRequest.gender"
               row
               mandatory
               inline
@@ -35,7 +37,7 @@
         <v-row>
           <v-col cols="12" md="6">
             <v-text-field
-              v-model="name"
+              v-model="contactRequest.name"
               :rules="[validateName]"
               label="Nom*"
               required
@@ -44,7 +46,7 @@
 
           <v-col cols="12" md="6">
             <v-text-field
-              v-model="surname"
+              v-model="contactRequest.surname"
               :rules="[validateSurname]"
               label="Prénom*"
               required
@@ -56,7 +58,7 @@
         <v-row>
           <v-col cols="12" md="6">
             <v-text-field
-              v-model="postalCode"
+              v-model="contactRequest.postalCode"
               label="Code postal*"
               :rules="[validatePostalCode]"
             />
@@ -64,7 +66,7 @@
 
           <v-col cols="12" md="6">
             <v-text-field
-              v-model="city"
+              v-model="contactRequest.city"
               label="Ville"
             />
           </v-col>
@@ -74,7 +76,7 @@
         <v-row>
           <v-col cols="12" md="6">
             <v-text-field
-              v-model="email"
+              v-model="contactRequest.email"
               :rules="[validateEmail]"
               label="Email*"
               required
@@ -84,7 +86,7 @@
 
           <v-col cols="12" md="6">
             <v-text-field
-              v-model="phone"
+              v-model="contactRequest.phone"
               :rules="[validatePhone]"
               label="Téléphone*"
               type="tel"
@@ -96,7 +98,7 @@
         <v-row>
           <v-col cols="12">
             <v-text-field
-              v-model="structureName"
+              v-model="contactRequest.structureName"
               :rules="[validateStructureName]"
               label="Nom de la structure*"
               required
@@ -112,9 +114,11 @@
         <v-row>
           <v-col cols="12" md="6">
             <v-select
-              v-model="requestType"
+              v-model="contactRequest.requestType"
               :items="requestTypes"
-              label="Votre demande concerne*"
+              item-value="id"
+              item-title="label"
+              label="Votre demande concerne *"
               outlined
               dense
             />
@@ -122,7 +126,7 @@
 
           <v-col cols="12" md="6">
             <v-text-field
-              v-model="concernedProduct"
+              v-model="contactRequest.concernedProduct"
               label="Le produit concerné"
               outlined
               dense
@@ -138,8 +142,8 @@
         <v-row>
           <v-col cols="12">
             <v-textarea
-              v-model="message"
-              :rules="[validateMessageLength]"
+              v-model="contactRequest.message"
+              :rules="[validateNonEmptyMessage, validateMessageLength]"
               label="Votre message*"
               required
               outlined
@@ -151,13 +155,13 @@
 
         <!-- Policy and  checkboxes -->
         <v-checkbox
-          v-model="privacyPolicy"
-          :rules="[(v) => !!v || 'You must accept the privacy policy']"
+          v-model="contactRequest.privacyPolicyAccepted"
+          :rules="[(v) => !!v || 'Vous devez accepter la politique de confidentialité']"
           label="J'ai pris connaissance de la politique de confidentialité et j'accepte le traitement de mes données personnelles par Opentalent."
         />
 
         <v-checkbox
-          v-model="newsletterSubscription"
+          v-model="contactRequest.newsletterSubscription"
           label="Je souhaite recevoir des communications d'Opentalent par email (promotions, informations logiciel…). Je pourrai me désinscrire à tout moment."
         />
 
@@ -168,7 +172,7 @@
         <v-row>
           <v-col cols="12">
             <v-btn
-              :disabled="!valid"
+              :disabled="!isValid"
               @click="submitForm"
             >
               Envoyer
@@ -178,58 +182,40 @@
       </v-container>
     </v-form>
 
-    <div v-if="submissionStatus">
-      {{ submissionStatus }}
+    <div v-else class="confirmation-message d-flex flex-row justify-center">
+      <v-card>
+        <v-icon icon="fas fa-check mr-1"/>
+        Votre demande de contact a bien été enregistrée, nous reviendrons vers vous dès que possible.
+      </v-card>
     </div>
-
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
-import { ContactFormData } from "~/types/interface";
 import VueHcaptcha from '@hcaptcha/vue3-hcaptcha';
+import ContactRequest from "~/models/Maestro/ContactRequest";
+import { useEntityManager } from "~/composables/data/useEntityManager";
+import { useRouter } from "vue-router";
 
 const route = useRoute();
-const defaultRequestType = route.query.request;
+const router = useRouter()
 const runtimeConfig = useRuntimeConfig()
+const { em } = useEntityManager()
 
-// --- Constants ---
-const requestTypes: Array<string> = [
-  "Demande d'information",
-  "Demande de devis",
-  "Demande de démonstration",
-  "Demande d'option supplémentaire",
-  "Autre",
-];
-
-
-// --- Refs ---
-const name: Ref<string | null> = ref(null);
-
-const surname: Ref<string | null> = ref(null);
-
-const email: Ref<string | null> = ref(null);
-
-const structureName: Ref<string | null> = ref(null);
-
-const message: Ref<string | null> = ref(null);
-
-const privacyPolicy: Ref<boolean> = ref(false);
-
-const gender: Ref<string | null> = ref(null);
-
-const postalCode: Ref<string | null> = ref(null);
-
-const city: Ref<string | null> = ref(null);
-
-const phone: Ref<string | null> = ref(null);
+const requestTypes: Array<{id: string, label: string}> = [
+  { id: "CONTACT_REQUEST_INFORMATION", label: "Demande d'information"},
+  { id: "CONTACT_REQUEST_ESTIMATE", label: "Demande de devis"},
+  { id: "CONTACT_REQUEST_DEMO", label: "Demande de démonstration"},
+  { id: "CONTACT_REQUEST_OPTION", label: "Demande d'option supplémentaire"},
+  { id: "CONTACT_REQUEST_OTHER", label: "Autre"}
+]
 
-const concernedProduct: Ref<string | null> = ref(null);
+const defaultRequestType = route.query.request ?? 'CONTACT_REQUEST_INFORMATION'
 
-const newsletterSubscription: Ref<boolean> = ref(false);
-
-const submissionStatus: Ref<string | null> = ref(null);
+//@ts-ignore
+const contactRequest: ContactRequest = reactive(em.newInstance(ContactRequest, { requestType: defaultRequestType }))
 
+const isValid: Ref<boolean> = ref(true)
 
 // --- Validation ---
 const validateName = (name: string | null) => !!name || "Le nom est obligatoire";
@@ -248,61 +234,39 @@ const validatePhone = (email: string | null) =>
 const validateStructureName = (structureName: string | null) =>
   !!structureName || "Le nom de la structure est requis";
 
+const validateNonEmptyMessage = (message: string | null) =>
+  (!!message && !(message.length > 0)) ||
+  "Le message ne peut pas être vide";
+
 const validateMessageLength = (message: string | null) =>
   (!!message && message.length <= 400) ||
   "Le message ne doit pas dépasser 400 caractères";
 
-// TODO: revoir la validation, ça devrait être géré directement dans le v-form
-const valid: ComputedRef<boolean> = computed(() => {
-  return (
-    validateName(name.value) === true &&
-    validateSurname(surname.value) === true &&
-    validatePostalCode(postalCode.value) === true &&
-    validateEmail(email.value) === true &&
-    validatePhone(phone.value) === true &&
-    validateStructureName(structureName.value) === true &&
-    validateMessageLength(message.value) === true &&
-    privacyPolicy.value === true
-  );
-});
-
-// --- Form data (voir si utile) ---
-const formData: ContactFormData = reactive({
-  gender: null,
-  postalCode: null,
-  city: "",
-  phone: null,
-  requestType: null,
-  concernedProduct: "",
-  newsletterSubscription,
-});
-
-const formRefs = {
-  ...toRefs(formData),
-  name,
-  surname,
-  email,
-  structureName,
-  message,
-  privacyPolicy,
-  valid,
-};
-
-// --- Methods ---
+const contactRequestSent: Ref<boolean> = ref(false);
+
+/**
+ * Submits the contact form.
+ *
+ * This function validates the form and sets the value of a variable to indicate whether the form submission was successful.
+ *
+ * @function
+ * @name submitForm
+ *
+ * @returns {void}
+ */
 const submitForm = () => {
-  if (valid.value) {
-    // Logique d'envoi du formulaire
-    // TODO: implémenter
-    submissionStatus.value = "Mail envoyé à contact@opentalent.fr";
-  } else {
-    console.log("Validation failed!");
-    submissionStatus.value = "";
+  if (!isValid.value) {
+    console.log("Validation failed!")
+    contactRequestSent.value = false
+    return
   }
-};
 
-const requestType: Ref<string | null> = ref(
-  defaultRequestType === "demo" ? "Demande de démonstration" : null
-);
+  // Défile vers le début de page pour afficher le message de confirmation
+  router.push({ path: '', hash: '#anchor' })
+
+  // TODO: implémenter
+  contactRequestSent.value = true;
+};
 </script>
 
 <style scoped lang="scss">
@@ -322,4 +286,17 @@ const requestType: Ref<string | null> = ref(
     margin-bottom: 1rem;
   }
 }
+
+.confirmation-message {
+  .v-card {
+    .v-icon {
+      color: green;
+    }
+
+    max-width: 1200px;
+    padding: 24px;
+    margin: 128px 0;
+    font-weight: 500;
+  }
+}
 </style>

+ 50 - 0
models/Maestro/ContactRequest.ts

@@ -0,0 +1,50 @@
+import ApiModel from "~/models/ApiModel";
+import {Uid, Str, Bool, Attr} from "pinia-orm/dist/decorators";
+
+/**
+ * Maestro Model : JobPosting
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/maestro/-/blob/master/src/Entity/JobPosting/JobPosting.php?ref_type=heads
+ */
+export default class ContactRequest extends ApiModel {
+  static entity = 'contact-request'
+
+  @Uid()
+  declare id: number
+
+  @Str(null)
+  declare name: string | null
+
+  @Str(null)
+  declare surname: string | null
+
+  @Str(null)
+  declare email: string | null
+
+  @Str(null)
+  declare structureName: string | null
+
+  @Str(null)
+  declare message: string | null
+
+  @Bool(false)
+  declare privacyPolicyAccepted: boolean
+
+  @Str(null)
+  declare gender: string | null
+
+  @Str(null)
+  declare postalCode: string | null
+
+  @Str(null)
+  declare city: string | null
+
+  @Str(null)
+  declare phone: string | null
+
+  @Str(null)
+  declare concernedProduct: string | null
+
+  @Bool(false)
+  declare newsletterSubscription: boolean
+}