<template>
<div v-if="shouldRender" class="search_module" :class="mode">
<!-- Button shown when the menu is collapsed -->
<em
v-show="isAdvancedSearchWithLayoutCollapsed"
class="fas fa-search collapsed_search_button"
@click="switchToSearch"
/>
<div
v-show="!isAdvancedSearchWithLayoutCollapsed"
class="search_module_inner"
>
<!-- When results are displayed, user can come back to search selection -->
<BackTitleButton
v-show="showBackToSearch"
:title="$t('search_module.results_view.switch_back_to_search')"
style="margin-left: 10px"
@click="inputClick"
/>
<SMSelection
v-show="!showBackToSearch"
ref="selection"
:show-selected="willShowSelectedItems"
:results="isViewResults"
:visible="isSelectionView || isFormMode"
:suggestions="showSuggestions"
:fixed-input="isFormMode"
:back-arrow="showBackToResultsArrow"
@onQuery="(query) => (lastSearchedString = query)"
@inputClick="inputClick()"
>
<template #input-left>
<!-- User can switch back to existing results -->
<em
v-show="showBackToResultsArrow"
v-b-tooltip.hover.bottom
class="fas fa-arrow-left pt-1"
:title="$t('search_module.search_view.last_results_button_tooltip')"
@click="switchToResults"
/>
</template>
</SMSelection>
<div class="actions">
<!-- CLOSE BUTTON (X) -->
<em
v-if="!isFormMode"
v-show="hasSelection"
class="fas fa-times p-1"
aria-hidden="true"
@click="resetSearch"
/>
<!-- Preselection/History menu button -->
<em v-if="false" v-show="isFormMode" class="fas fa-history p-1" />
<em
v-if="false"
v-show="!isFormMode"
class="fas fa-history p-1"
@click="setView('history_menu')"
/>
<!-- Validate search button -->
<em class="fas fa-search p-1" @click="clickSearch" />
</div>
<SearchModuleHistoryMenu v-show="showHistoryMenu" />
</div>
<!-- FREE MODE -->
<!-- Advanced search button -->
<div
v-if="!isFormMode && !isViewResults"
class="search_bar__switch_mode_button_wrapper"
>
<b-button
squared
block
class="search_bar__switch_mode_button"
@click="() => $emit('clickFormModeButton')"
>
{{ $t('searchModule.buttons.advanced_search') }}
</b-button>
<slot name="search-validate-button-free" :vm="this">
<button
v-if="!isViewResults"
class="btn btn-block btn-primary mt-2 float-right"
@click="clickSearch"
>
<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>
</button>
</slot>
</div>
<!-- FORM MODE -->
<!-- Search form (Sidebar menu) -->
<SMForm
v-if="isFormMode"
v-show="shouldShowSearchForm"
ref="form"
:results="isViewResults"
:search-string="lastSearchedString"
:highlight-vehicles-tab="highlightVehiclesTab"
:highlight-drivers-tab="highlightDriversTab"
:highlight-circuits-tab="highlightCircuitsTab"
:tabs="computedFormTabs"
:reset-button="hasSelection"
@validate="clickSearch"
@reset="resetSearch"
>
<template #search-filters>
<slot name="search-filters" />
</template>
<template #date-picker="slotProps">
<slot name="date-picker" :form-actions="slotProps.formActions" />
</template>
<template #search-validate-button>
<slot
name="search-validate-button-form"
:click-search="() => clickSearch()"
:is-view-results="isViewResults"
/>
</template>
<div v-show="!isViewResults">
<slot name="form-bottom"> </slot>
</div>
</SMForm>
<!-- Free search button -->
<div
v-if="computedToggleFreesearch && isFormMode && !isViewResults"
v-show="!isAdvancedSearchWithLayoutCollapsed"
class="search_bar__switch_mode_button_wrapper"
>
<b-button
variant="outline-primary"
squared
block
class="search_bar__switch_mode_button"
@click="() => $emit('clickFreeModeButton')"
>
{{ $t('searchModule.buttons.free_search') }}
</b-button>
</div>
<!-- FREE/FORM MODE -->
<!-- Results slot -->
<div v-show="isViewResults" class="results">
<slot name="results" />
</div>
</div>
</template>
<script>
import SMSelection from './SMSelection.vue'
import SearchModuleHistoryMenu from './SMHistoryMenu.vue'
import SMForm from './SMForm.vue'
import Vue from 'vue'
import BackTitleButton from '@c/shared/BackTitleButton.vue'
/**
* Shared Form/Free search component used by Location, Alerts, Identification, etc
* @namespace components
* @category components
* @subcategory search-module
* @module SearchModule
**/
export default {
components: {
SMSelection,
SearchModuleHistoryMenu,
SMForm,
BackTitleButton,
},
inject: {
/**
* Allow to define search form tabs
*/
searchFormTabs: {
default: [],
},
},
props: {
value: {
type: Object,
default: () => null,
},
/**
* free: Renders the free mode (Saisie libre)
* advanced/form: Renders a form (Like GeoredV2)
* empty string: Renders free mode (only if menu is collapsed) (This was the initial POC for the input center on the top of the map)
* map: not implemented
*/
mode: {
type: String,
validator: (value) =>
['', 'advanced', 'form', 'free', 'map'].includes(value),
default: '',
},
highlightVehiclesTab: {
type: Boolean,
default: false,
},
highlightDriversTab: {
type: Boolean,
default: false,
},
highlightCircuitsTab: {
type: Boolean,
default: false,
},
formTabs: {
type: Array,
default: () => [],
},
canToggleFreesearch: {
type: Boolean,
default: true,
},
},
data() {
return {
lastSearchedString: '',
}
},
computed: {
view: {
get() {
return this.$store.state.search_module.view
},
set(v) {
this.$store.state.search_module.view = v
},
},
computedToggleFreesearch() {
return this.searchModuleCanToggleFreesearch !== null
? this.searchModuleCanToggleFreesearch
: this.canToggleFreesearch
},
computedFormTabs() {
return this.formTabs.length !== 0 ? this.formTabs : this.searchFormTabs
},
hasResults() {
return this.$store.getters['search_module/hasResults']
},
showBackToSearch() {
return this.isFormMode && this.isViewResults
},
showBackToResultsArrow() {
return (
this.isFormMode &&
!this.isViewResults &&
this.$store.getters['search_module/hasResults']
)
},
/**
* Only for location module
* @todo Improve/Remove/Attention
*/
isAdvancedSearchWithLayoutCollapsed() {
if (this.$store.state.app.layoutType === 'tlayout') {
return (
this.isFormMode && this.$store.getters['app/layout'].isMenuCollapsed
)
} else {
return false
}
},
shouldShowSearchForm() {
return !this.isAdvancedSearchWithLayoutCollapsed
},
shouldRender() {
if (this.mode === 'free') {
return true
}
if (this.isFormMode) {
return true
} else {
//@todo: Showing the search input in the middle-screen (on top of the map) will be deprecated in the near-future (maybe)
return (
this.$store.getters['app/layout'].isMenuCollapsed &&
this.$store.getters['app/layout'].willMenuCollapseCompletely
)
}
},
isViewResults() {
return this.isFormMode && this.view == 'results'
},
isFormMode() {
return ['form', 'advanced'].includes(this.mode)
},
willShowSelectedItems() {
return !this.isFormMode
},
showSuggestions() {
return !this.isFormMode
},
isSelectionView() {
return this.view === 'selection'
},
/**
* @warn Unused: Favorites/Last search selection/Most used search selection feature
*/
showHistoryMenu() {
return this.view === 'history_menu'
},
hasSelection() {
return this.$store.getters['search_module/hasSelection']
},
},
watch: {
hasResults() {
if (this.hasResults) {
this.switchToResults()
}
},
},
created() {
this.view = 'selection'
},
async mounted() {
await this.$store.dispatch('search_module/initialize')
},
methods: {
switchToResults(e) {
this.setView('results')
this.$store.dispatch('app/changeLayout', {
menu_full_collapse: false,
})
this.$emit('clickFormModeButton')
e && e.stopPropagation()
},
/**
* Switch back to search when the layout is collapsed
*/
switchToSearch(e) {
this.$log.debug('switchToSearch')
this.$store.dispatch('app/changeLayout', {
menu: true,
menu_collapsed: false,
menu_full_collapse: true,
sub_menu: false,
})
this.setViewSelection()
e && e.stopPropagation()
},
resetSearch() {
this.clearSelection()
this.$emit('clear')
this.switchToSearch()
},
inputClick() {
this.setViewSelection()
this.$emit('inputClick')
},
focusQueryInput() {
this.$refs.selection.focusInput()
},
clearSelection() {
this.$store.dispatch('search_module/clearSelection')
this.$store.dispatch('search_module/clearDateSelection')
this.$refs.selection.hideSuggestions()
},
setViewSelection() {
this.setView('selection')
this.$refs.selection.showSuggestions()
},
setView(view) {
this.view = view
this.$emit('viewChange', view)
},
clickSearch() {
if (!this.$store.getters['search_module/isValidSelection']) {
return
}
this.$emit('input', this.$store.getters['search_module/getSelection'])
this.$store.dispatch('search_module/validateSearch')
},
},
}
</script>
<style lang="scss" scoped>
.search_module {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.search_module.advanced {
position: initial;
}
.search_module_inner {
display: grid;
grid-template-columns: 1fr;
position: relative;
background-color: white;
width: inherit;
min-height: 44px;
}
.actions {
font-size: 25px;
padding: 0.1rem;
position: absolute;
width: fit-content;
//margin-top: 5px;
top: 0px;
right: 5px;
}
em {
color: var(--color-denim);
cursor: pointer;
font-size: 16px;
}
em:hover {
opacity: 0.9;
}
em.fa-times {
font-size: 24px;
position: relative;
top: 2px;
}
.btn {
background-color: var(--color-search-module-button);
color: #484848;
}
.btn.btn-primary {
color: #fff;
background-color: #007bff;
border-color: #007bff;
}
.search_bar__switch_mode_button {
max-width: 570px;
border: 0px;
outline: 0px;
box-shadow: none;
font: normal normal normal 12px/14px Open Sans;
letter-spacing: 0px;
}
.search_bar__switch_mode_button_wrapper {
max-width: 570px;
width: inherit;
position: relative;
z-index: 1000;
}
.collapsed_search_button {
color: var(--color-dark-blue);
font-size: 25px;
margin-top: 20px;
margin-bottom: 20px;
}
.results {
width: inherit;
}
</style>
Source