Covivo/mobicoop

View on GitHub
client/src/MobicoopBundle/Resources/assets/js/components/contact/ContactForm.vue

Summary

Maintainability
Test Coverage
<template>
  <v-container fluid>
    <v-row
      justify="center"
    >
      <v-col
        cols="12"
        sm="8"
        md="6"
      >
        <v-snackbar
          v-model="snackbar"
          :color="(alert.type === 'error')?'error':'success'"
          top
        >
          <!--Use of span and v-html to handle multiple lines errors if needed-->
          <span v-html="alert.message" />
          <v-btn
            color="white"
            text
            @click="snackbar = false"
          >
            <v-icon>mdi-close-circle-outline</v-icon>
          </v-btn>
        </v-snackbar>
        <v-form
          id="formContact"
          ref="form"
          v-model="valid"
          lazy-validation
        >
          <v-container>
            <v-row>
              <v-col
                cols="12"
              >
                <v-text-field
                  id="familyName"
                  v-model="form.familyName"
                  :label="$t('lastName.placeholder')+` *`"
                  :aria-label="$t('lastName.placeholder')"
                  name="familyName"
                  required
                  :rules="form.familyNameRules"
                  aria-required="true"
                />
              </v-col>

              <v-col
                cols="12"
              >
                <v-text-field
                  id="givenName"
                  v-model="form.givenName"
                  :label="$t('firstName.placeholder')+` *`"
                  :aria-label="$t('firstName.placeholder')"
                  name="givenName"
                  required
                  :rules="form.givenNameRules"
                  aria-required="true"
                />
              </v-col>

              <v-col
                cols="12"
              >
                <v-text-field
                  id="email"
                  v-model="form.email"
                  :rules="form.emailRules"
                  :aria-label="$t('email.placeholder')"
                  :label="$t('email.placeholder') + ` *`"
                  name="email"
                  aria-required="true"
                />
              </v-col>

              <v-col
                cols="12"
              >
                <v-select
                  id="demand"
                  v-model="form.demand"
                  :items="demandItems"
                  :rules="form.demandRules"
                  :aria-label="$t('demand.placeholder')"
                  :label="$t('demand.placeholder') + ` *`"
                  name="demand"
                  required
                  aria-required="true"
                />
              </v-col>
              <v-col
                cols="12"
              >
                <v-textarea
                  id="message"
                  v-model="form.message"
                  :rules="form.messageRules"
                  :aria-label="$t('message.label')"
                  :label="$t('message.label') + ` *`"
                  name="message"
                  :hint="this.$t('message.hint')"
                  required
                  aria-required="true"
                />
              </v-col>
              <!-- Honey pot -->
              <!-- use of HTML input to have access to required attribute -->
              <!-- use of website name is arbitrary and can be changed -->
              <v-col
                cols="12"
                class="noney"
              >
                <label for="website">{{ $t('website.label') }}</label>
                <input
                  id="website"
                  v-model="form.website"
                  type="text"
                  name="website"
                  :aria-label="$t('website.label')"
                  :placeholder="$t('website.placeholder')"
                  tabindex="-1"
                  aria-required="true"
                  required
                >
              </v-col>
              <!-- /Honey pot -->
            </v-row>

            <v-btn
              :disabled="!valid || loading"
              :loading="loading"
              color="primary"
              rounded
              @click="validate"
            >
              {{ $t('buttons.send.label') }}
            </v-btn>

            <v-row
              class="mt-5"
            >
              <v-col cols="12">
                <p class="text-left">
                  {{ $t('dataPolicy.text') }}
                  <a
                    :href="$t('dataPolicy.route')"
                    target="_blank"
                    :aria-label="$t('dataPolicy.linkAria')"
                  >{{ $t('dataPolicy.link') }}</a>.
                </p>
              </v-col>
            </v-row>
          </v-container>
        </v-form>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
import maxios from "@utils/maxios";
import { merge } from "lodash";
import {messages_en, messages_fr, messages_eu, messages_nl} from "@translations/components/contact/ContactForm/";
import {messages_client_en, messages_client_fr, messages_client_eu, messages_client_nl} from "@clientTranslations/components/contact/ContactForm/";

let MessagesMergedEn = merge(messages_en, messages_client_en);
let MessagesMergedNl = merge(messages_nl, messages_client_nl);
let MessagesMergedFr = merge(messages_fr, messages_client_fr);
let MessagesMergedEu = merge(messages_eu, messages_client_eu);

export default {
  i18n: {
    messages: {
      'en': MessagesMergedEn,
      'nl': MessagesMergedNl,
      'fr': MessagesMergedFr,
      'eu': MessagesMergedEu
    },
  },
  props: {
    user: {
      type: Object,
      default: null
    }
  },
  data () {
    return {
      contactTypes: null,
      snackbar: false,
      loading: false,
      valid: false,
      form:{
        email: this.user && this.user.email ? this.user.email : null,
        emailRules: [
          v => !!v || this.$t("email.errors.required"),
          v => /.+@.+/.test(v) || this.$t("email.errors.valid")
        ],
        familyName: this.user && this.user.familyName ? this.user.familyName : null,
        familyNameRules: [
          v => !!v || this.$t("lastName.errors.required"),
        ],
        givenName: this.user && this.user.givenName ? this.user.givenName : null,
        givenNameRules: [
          v => !!v || this.$t("firstName.errors.required"),
        ],
        demand: null,
        demandRules: [
          v => !!v || this.$t("demand.errors.required"),
        ],
        message: null,
        messageRules: [
          v => !!v || this.$t("message.errors.required"),
        ],
        website: "", // honey pot data
      },
      // You need to use values corrresponding to your potential .env settings in CONTACT_TYPES
      // By default, contact type is used
      alert: {
        type: "success",
        message: ""
      }
    }
  },
  computed: {
    demandItems(){
      let contactItems = [];
      if(null !== this.contactTypes){
        for (let [key, value] of Object.entries(this.contactTypes)) {
          contactItems.push({text:this.$t('demand.items.'+value.demand), value:value.demand});
        }
      }
      return contactItems;
    }
  },
  mounted(){
    this.getContactItems();
  },
  methods: {
    validate() {
      const self = this;
      this.resetAlert();
      if (this.$refs.form.validate()) {
        this.loading = true;
        maxios.post(this.$t('buttons.send.route'), {
          email: this.form.email,
          givenName: this.form.givenName,
          familyName: this.form.familyName,
          demand: this.form.demand,
          message: this.form.message,
          website: this.form.website // honey pot data
        })
          .then(function (response) {
            // console.log(response.data);
            if (response.data && response.data.message) {
              self.alert = {
                type: "success",
                message: self.$t(response.data.message)
              };
              window.location.href="/";
            }
          })
          .catch(function (error) {
            console.error(error.response);
            let messages = "";
            if (error.response.data && error.response.data.errors) {
              error.response.data.errors.forEach(error => {
                messages += self.$t(error) + "<br>"
              });
            } else if (error.response.data && error.response.data.message) {
              messages = self.$t(error.response.data.message);
            }
            self.alert = {
              type: "error",
              message: messages
            };
          }).finally(function () {
            self.loading = false;
            if (self.alert.message.length > 0) {
              self.snackbar = true;
            }
          })
      }
    },
    resetAlert() {
      this.alert = {
        type: "success",
        message: ""
      }
    },
    getContactItems(){
      maxios.post(this.$t('getContactItemsUri'))
        .then(response => {
          // console.log(response.data);
          this.contactTypes = response.data;
        })
        .catch(function (error) {
          console.error(error);
        });
    }
  }
}
</script>

<style lang="scss" scoped>

  /* Honey pot */
  /* no display none / opacity 0 or visibility hidden to avoid bot from checking it */
  .noney {
    position: absolute;
    top: -1500px;
    left: 0;
  }

</style>