| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- <template>
- <div>
- <div id="anchor" />
- <v-form
- v-if="!contactRequestSent"
- ref="form"
- validate-on="submit lazy"
- @submit.prevent="submit"
- >
- <v-container>
- <v-row>
- <v-col cols="12" md="6">
- <v-text-field
- v-model="email"
- :rules="[validateEmail]"
- :label="$t('contact_email')"
- required
- type="email"
- />
- </v-col>
- <v-col cols="12" md="6">
- <v-text-field
- v-model="name"
- :label="$t('contact_name')"
- required
- />
- </v-col>
- </v-row>
- <v-row>
- <v-col cols="12">
- <v-textarea
- v-model="message"
- :rules="[validateNonEmptyMessage]"
- :label="$t('contact_message')"
- required
- maxlength="400"
- />
- </v-col>
- </v-row>
- <v-row>
- <v-col cols="12" class="captcha-container">
- <AltchaValidation v-if="!appStore.altchaPayload"/>
- <v-card v-else class="pa-2">Captcha already verified</v-card>
- <v-checkbox
- v-model="honeyPotChecked"
- :rules="[validateCaptcha]"
- class="hidden-ctrl"
- />
- </v-col>
- </v-row>
- <!-- Submit Button -->
- <div class="d-flex flex-row justify-center">
- <v-btn
- type="submit"
- variant="outlined"
- :height="54"
- :width="180"
- class="submit-btn"
- >
- {{ $t('contact_submit') }}
- </v-btn>
- </div>
- <div v-if="errorMsg" class="error">
- {{ errorMsg }}
- </div>
- </v-container>
- </v-form>
- <div v-else class="confirmation-message d-flex flex-row justify-center">
- <v-card>
- <v-icon icon="fas fa-check mr-1" />
- {{ $t('contact_confirmation') }}
- </v-card>
- </div>
- </div>
- </template>
- <script setup lang="ts">
- import type { Ref } from '@vue/reactivity'
- const appStore = useAppStore()
- const form: Ref<HTMLElement | null> = ref(null)
- const contactRequestSent: Ref<boolean> = ref(false)
- const errorMsg: Ref<string | null> = ref(null)
- const i18n = useI18n()
- const email: Ref<string | null> = ref(null)
- const name: Ref<string | null> = ref(null)
- const message: Ref<string | null> = ref(null)
- // Honeypot checkbox (if checked: it's probably a bot)
- const honeyPotChecked: Ref<boolean> = ref(false)
- const validateEmail = (email: string | null) =>
- (!!email && /.+@.+\..+/.test(email)) || i18n.t("email_must_be_valid")
- const validateNonEmptyMessage = (message: string | null) =>
- (!!message && message.length > 10) || i18n.t("message_must_be_valid")
- const validateCaptcha = () =>
- !honeyPotChecked.value && appStore.altchaPayload !== null || i18n.t("captcha_must_be_validated")
- /**
- * 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
- *
- * @returns {void}
- */
- const submit = async (): Promise<void> => {
- const { valid } = await form.value!.validate()
- if (!valid) {
- contactRequestSent.value = false
- return
- }
- const url = 'https://api.ogene.fr/api/contact';
- const headers = {
- 'Content-Type': 'application/ld+json'
- };
- const body = {
- "email": email.value,
- "name": name.value ?? '-',
- "message": message.value,
- "altchaPayload": appStore.altchaPayload
- };
- try {
- const response = await fetch(url, {
- method: 'POST',
- headers: headers,
- body: JSON.stringify(body)
- });
- if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
- }
- await response.json();
- } catch (error) {
- console.error('There was a problem with the fetch operation: ', error);
- }
- contactRequestSent.value = true
- errorMsg.value = null
- }
- </script>
- <style scoped lang="scss">
- .captcha-container {
- display: flex;
- flex-direction: column;
- align-items: center;
- margin: 24px 0;
- :deep(altcha-widget) {
- min-width: 280px;
- @media (max-width: 600px) {
- .altcha {
- margin: 0 auto;
- }
- }
- }
- }
- .confirmation-message .v-card {
- padding: 14px;
- }
- .hidden-ctrl {
- :deep(.v-input__control) {
- display: none;
- }
- }
- </style>
|