|
|
@@ -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>
|