Source

components/shared/SearchModule/SMForm.vue

<template>
  <div class="search_module__form">
    <nav v-if="tabs.length === 0" class="nav nav-pills flex-row">
      <a
        v-if="isFixedTabEnabled('vehicle')"
        class="w-25 p-0 pt-2 pb-1 flex-fill text-center nav-link"
        :class="{
          active: tabName === 'vehicle',
          highlight: highlightVehiclesTab,
        }"
        @click="clickTab('vehicle')"
        >{{ $t('common.Véhicule') }}</a
      >
      <a
        v-if="isFixedTabEnabled('driver')"
        class="w-25 p-0 pt-2 pb-1 flex-fill text-center nav-link"
        :class="{
          active: tabName === 'driver',
          highlight: highlightDriversTab,
        }"
        @click="clickTab('driver')"
        >{{ $t('common.Chauffeur') }}</a
      >
      <a
        v-if="isFixedTabEnabled('circuit')"
        class="w-25 p-0 pt-2 pb-1 flex-fill text-center nav-link"
        :class="{
          active: tabName === 'circuit',
          highlight: highlightCircuitsTab,
        }"
        @click="clickTab('circuit')"
        >{{ $t('common.Circuit') }}</a
      >
    </nav>

    <nav
      v-if="
        filteredTabs.length > 0 &&
        !(filteredTabs.length === 1 && filteredTabs[0] === 'disabled')
      "
      v-show="!results || (showDynamicTabsOnResultView && !!results)"
      class="nav nav-pills flex-row"
    >
      <a
        v-for="tab in filteredTabs"
        :key="tab.value"
        class="w-25 p-0 pt-2 pb-1 flex-fill text-center nav-link"
        :class="{
          active: tabName === tab.value,
          highlight: highlightCircuitsTab,
        }"
        @click="clickTab(tab.value)"
        >{{ tab.label }}</a
      >
    </nav>

    <div v-show="shouldShowList('vehicle')" class="list scrollbar">
      <b-spinner
        v-if="!isInitialLoadingComplete.vehicles"
        class="loader"
        variant="info"
        style="width: 3rem; height: 3rem"
      />

      <SMFormTree type="vehicle" :search-string="searchString" />
    </div>
    <div v-show="shouldShowList('driver')" class="list scrollbar">
      <b-spinner
        v-if="!isInitialLoadingComplete.drivers"
        class="loader"
        variant="info"
        style="width: 3rem; height: 3rem"
      />

      <SMFormTree type="driver" :search-string="searchString" />
    </div>
    <div v-show="shouldShowList('circuit')" class="list scrollbar">
      <b-spinner
        v-if="!isInitialLoadingComplete.circuits"
        class="loader"
        variant="info"
        style="width: 3rem; height: 3rem"
      />

      <SMFormTree type="circuit" :search-string="searchString" />
    </div>

    <div
      v-if="isSearchModuleDatePickerEnabled()"
      v-show="!results"
      class="date-picker-wrapper"
    >
      <slot name="date-picker" :form-actions="formActions">
        <SMDatePicker
          ref="datePicker"
          @clear="onDateClear"
          @onDateSelection="onDateSelection"
        />
      </slot>
    </div>

    <div v-if="!!$slots['search-filters']" v-show="!results">
      <div v-show="showCustomFilters">
        <slot name="search-filters" />
      </div>
      <p
        class="custom_filters_toggle_text"
        @click="() => (showCustomFilters = !showCustomFilters)"
      >
        <span v-show="showCustomFilters">{{
          $t('search_module.extra_filters.not_collapsed_title')
        }}</span>
        <span v-show="!showCustomFilters">{{
          $t('search_module.extra_filters.collapsed_title')
        }}</span>
        <em
          class="fas"
          :class="showCustomFilters ? 'fa-angle-up' : 'fa-angle-down'"
        />
      </p>
    </div>

    <slot> </slot>

    <div class="row m-0 p-0">
      <div class="col-md-12 m-0 form_buttons">
        <b-button
          v-if="!results"
          v-show="resetButton"
          class="btn btn-block btn-light mt-2"
          size="sm"
          @click="reset"
        >
          {{ $t('buttons.cancel_alternative') }}
        </b-button>

        <slot name="search-validate-button">
          <b-button
            v-if="!results"
            variant="primary"
            class="btn btn-block btn-primary mt-2"
            size="sm"
            @click="validate"
          >
            <span v-show="!$store.state.search_module.isSearchInProgress">
              {{ $t('common.Valider') }}
            </span>
            <span v-show="$store.state.search_module.isSearchInProgress">
              <b-spinner
                class="loader"
                variant="info"
                style="
                  width: 1rem;
                  height: 1rem;
                  margin: 0 auto;
                  display: block;
                "
              />
            </span>
          </b-button>
        </slot>
      </div>
    </div>
  </div>
</template>
<script>
import { mapGetters } from 'vuex'

import SMDatePicker from './SMDatePicker.vue'
import SMFormTree from './SMFormTree.vue'

/**
 * @todo Remove fixed tabs (use prop tabs instead)
 */
export default {
  components: {
    SMFormTree,
    SMDatePicker,
  },
  inject: {
    /**
     * @todo Remove fixed tabs
     */
    showDynamicTabsOnResultView: {
      default: false,
    },
    /**
     * Hides date picker (right validation)
     */
    isSearchModuleDatePickerEnabled: {
      default: () => () => true,
    },
    /**
     * Allow us to hide some tabs (rights validations)
     * Note: To define tabs, use "searchFormTabs" in SearchModule.vue instead
     */
    blacklistedSearchModuleFormTabs: {
      default: () => [],
    },
    showCustomFiltersByDefault: {
      default: true,
    },
  },
  props: {
    searchString: {
      type: String,
      default: '',
    },
    /*
     * True if SearchModule.view equals 'results'
     */
    results: {
      type: Boolean,
      default: false,
    },
    highlightVehiclesTab: {
      type: Boolean,
      default: false,
    },
    highlightDriversTab: {
      type: Boolean,
      default: false,
    },
    highlightCircuitsTab: {
      type: Boolean,
      default: false,
    },
    tabs: {
      type: Array,
      default: () => [],
    },
    resetButton: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      tabName: '',
      showCustomFilters: this.showCustomFiltersByDefault,
    }
  },
  computed: {
    ...mapGetters({
      vehicleCategories: 'search_module/getVehicleCategories',
      isInitialLoadingComplete: 'search_module/isInitialLoadingComplete',
    }),
    filteredTabs() {
      return this.tabs.filter((tabItem) => {
        return !this.blacklistedSearchModuleFormTabs.includes(tabItem.value)
      })
    },
    formActions() {
      return {
        onDateClear: () => this.onDateClear,
        onDateSelection: (ranges) => this.onDateSelection(ranges),
      }
    },
  },
  mounted() {
    if (
      this.tabs.length > 0 &&
      !(this.tabs.length === 1 && this.tabs[0] === 'disabled')
    ) {
      this.clickTab(this.tabs[0].value || this.tabs[0])
    }

    //@todo: Refactor once fixed tabs are gone
    if (this.tabs.length === 0) {
      let type = ['vehicle', 'driver', 'circuit'].find(
        (type) => !this.blacklistedSearchModuleFormTabs.includes(type)
      )
      if (type) {
        this.clickTab(type)
      }
    }
  },
  methods: {
    /**
     * Blacklisted tabs will be skip (rights validations)
     */
    isFixedTabEnabled(name) {
      return !this.blacklistedSearchModuleFormTabs.includes(name)
    },
    reset() {
      this.$emit('reset')
    },
    shouldShowList(name) {
      return this.tabName == name && !this.results
    },
    validate() {
      this.$emit('validate')
    },
    //Clearing the date picker in the form modules removes all the selected date-ranges
    onDateClear() {
      this.$store.dispatch('search_module/clearDateSelection')
    },
    onDateSelection(ranges) {
      this.onDateClear()
      ranges.forEach((range) => {
        this.selectItem(null, range, 'date_range')
      })
    },
    selectItem(e, value, type) {
      this.$store.dispatch('search_module/selectItem', { value, type })
      e && e.stopPropagation()
      e && e.preventDefault()
    },
    clickTab(name) {
      this.tabName = name
      this.$store.dispatch('search_module/activeSearchFormTabName', name)
    },
  },
}
</script>
<style lang="scss">
.search_module__form {
  padding: 5px;
  background-color: white;
  width: inherit;
}
.search_module__form .nav {
  background-color: white;
}
.search_module__form .nav-pills {
  cursor: pointer;
}
.search_module__form .nav-pills .nav-link {
  color: var(--color-denim) !important;
  cursor: pointer;
  margin: 0px 3px;
}
.search_module__form .nav-pills .nav-link.active,
.search_module__form .nav-pills .show > .nav-link {
  border-bottom: 4px solid var(--color-denim);
  border-radius: 0;
}
.search_module__form .nav-pills .nav-link.active {
  background-color: transparent;
}
.search_module__form .nav-pills .nav-link.highlight {
  background-color: #0a71ac17;
}
.search_module__form a {
  color: #495057;
}
.search_module__form .loader {
  margin: 0 auto;
  display: block;
  margin-top: 10px;
}
.search_module__form .category,
.search_module__form .vehicle {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
.category_icon {
  color: #808080a1;
}

.search_module__form .category span {
  font-size: 14px;
}
.search_module__form .list {
  min-height: 250px;
  max-height: 250px;
  overflow-y: auto;
  scrollbar-color: white;
  scrollbar-width: thin;
  padding: 20px 10px;
  margin-bottom: 30px;
}
.custom_filters_toggle_text {
  padding-top: 20px;
  font: normal normal normal 12px/14px Open Sans;
  letter-spacing: 0px;
  color: var(--color-tundora);
  cursor: pointer;
  display: flex;
  justify-content: center;
  em {
    margin-left: 5px;
    font-size: 14px;
  }
}
.form_buttons {
  display: flex;
  flex-direction: row;
  justify-content: flex-end;
  column-gap: 10px;
  button {
    max-width: 87px;
    font: normal normal bold 14px/21px Open Sans;
    letter-spacing: 0px;
    color: #484848;
  }
  button.btn-primary {
    font: normal normal bold 14px/21px Open Sans;
    letter-spacing: 0px;
    color: #ffffff;
  }
}
</style>