<template>
<div
v-show="visible"
ref="root"
class="search_module_suggestions_search popOver"
:class="{ with_back_arrow: backArrow }"
>
<SearchModuleDatePicker
ref="datePicker"
:show-input="false"
@onDateSelection="onDateSelection"
/>
<slot name="input-left" />
<input
ref="input"
v-model="query"
type="text"
:placeholder="$t('searchModule.placeholder.filter')"
@click="onInputClick"
@keyup="queryKeyUp"
/>
<div v-show="autocomplete && query" ref="optionsList" class="options">
<div class="list-group">
<div
v-for="vehicle in suggestedVehicles"
:key="'vehicle_' + vehicle.id"
class="list-group-item list-group-item-action"
:class="{ selected: selected == vehicle.id }"
@click="selectItem($event, vehicle.id, 'vehicle')"
>
<img class="item_icon" src="./assets/truck.svg" />
<span
v-if="false"
class="iconify item_icon"
data-icon="mdi:dump-truck"
data-inline="false"
data-width="20"
data-height="20"
/>
{{ vehicle.name }}
</div>
<div
v-for="driver in suggestedDrivers"
:key="'driver_' + driver.id"
class="list-group-item list-group-item-action"
:class="{ selected: selected == driver.id }"
@click="selectItem($event, driver.id, 'driver')"
>
<span
class="iconify item_icon"
data-icon="mdi:account-hard-hat"
data-inline="false"
data-width="20"
data-height="20"
/>
{{ driver.name }}
</div>
<div
v-for="circuit in suggestedCircuits"
:key="circuit.id"
class="list-group-item list-group-item-action"
:class="{ selected: selected == circuit.id }"
@click="selectItem($event, circuit.id, 'circuit')"
>
<span
class="iconify item_icon"
data-icon="mdi:road-variant"
data-inline="false"
data-width="20"
data-height="20"
/>
{{ circuit.name }}
</div>
</div>
</div>
</div>
</template>
<script>
import SearchModuleDatePicker from './SMDatePicker.vue'
import { mapGetters } from 'vuex'
/**
* Floating window to show results (Floating search module feature)
*/
export default {
components: {
SearchModuleDatePicker,
},
inject: {
isSearchModuleDatePickerEnabled: {
default: () => () => true,
},
},
props: {
backArrow: {
type: Boolean,
default: false,
},
visible: {
type: Boolean,
default: true,
},
autocomplete: {
type: Boolean,
default: true,
},
},
data() {
return {
query: '',
selected: null,
}
},
computed: {
...mapGetters({
vehicles: 'search_module/getVehicles',
drivers: 'search_module/getDrivers',
circuits: 'search_module/getCircuits',
}),
suggestedVehicles() {
let ids = this.vehicles.map((v) => v.id)
return ids
.filter((id, index) => {
if (!(ids.indexOf(id) == index)) {
this.$log.debug(
'Skiping duplicate vehicle',
id,
this.vehicles.find((v) => v.id == id)
)
}
return ids.indexOf(id) == index
})
.map((id) => this.vehicles.find((v) => v.id == id))
.filter((item) =>
(item.name || '').toLowerCase().includes(this.query.toLowerCase())
)
},
suggestedDrivers() {
return this.drivers.filter((item) =>
(item.name || '').toLowerCase().includes(this.query.toLowerCase())
)
},
suggestedCircuits() {
return this.circuits.filter((item) =>
(item.name || '').toLowerCase().includes(this.query.toLowerCase())
)
},
},
watch: {
query() {
this.$emit('onQuery', this.query)
},
},
mounted() {
this.bindEscape()
},
methods: {
onDateSelection(ranges) {
this.$store.dispatch('search_module/clearDateSelection')
ranges.forEach((range) => {
this.selectItem(null, range, 'date_range')
})
},
queryKeyUp(e) {
if (!this.isSearchModuleDatePickerEnabled()) {
return
}
//Open automatically if the user writes '/'
if (this.query.indexOf('/') !== -1) {
this.$refs.datePicker.open(this.query.split('/').join('-'))
this.query = ''
return
}
if (e.key === 'Enter' && this.query.indexOf('-') !== -1) {
if (e.ctrlKey) {
//Select a single date period without datepicker if the date contains '-'
this.$log.debug('will set date using', this.query)
let range = this.$refs.datePicker.setFromString(this.query)
if (range.length === 2) {
this.onDateSelection(range)
} else {
return
}
} else {
//Open manually if the user writes the date with '-' and presses enter
this.$log.debug('will open date picker', this.query)
this.$refs.datePicker.open(this.query)
}
this.query = ''
}
},
onInputClick(e) {
this.$emit('inputClick')
e.stopPropagation()
},
bindEscape() {
if (!this.isSearchModuleDatePickerEnabled()) {
return
}
setTimeout(() => {
this.$refs.root &&
this.$refs.root.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
if (this.$refs.datePicker.visible) {
this.$refs.datePicker.cancel()
} else {
this.$emit('escape')
}
e.preventDefault()
e.stopPropagation()
}
})
}, 1000)
},
focusInput() {
this.$nextTick(() => {
this.$refs.input.focus()
})
},
selectItem(e, value, type) {
this.$store.dispatch('search_module/selectItem', { value, type })
e && e.stopPropagation()
e && e.preventDefault()
},
clearQuery() {
this.query = ''
},
},
}
</script>
<style lang="scss" scoped>
.search_module_suggestions_search input {
border: none;
padding-left: 8px;
background-color: transparent;
box-shadow: none;
outline: none;
}
.search_module_suggestions_search {
display: flex;
flex-direction: column;
}
.search_module_suggestions_search.with_back_arrow {
flex-direction: row;
}
.popOver {
padding: 10px;
width: auto;
top: 46px;
}
.popOver input {
width: 100%;
//margin-top: 5px;
font-size: 16px;
}
.options {
max-height: 150px;
overflow-y: scroll;
margin-top: 5px;
}
.options ul {
list-style-type: none;
text-align: left;
padding-left: 0;
}
.options ul li {
border-bottom: 1px solid lightgray;
padding: 10px;
cursor: pointer;
background: #f1f1f1;
}
.options ul li:first-child {
border-top: 2px solid #d6d6d6;
}
.options ul li:not(.selected):hover {
background: #8c8c8c;
color: #fff;
}
.options ul li.selected {
background: #8c8c8c;
color: #fff;
font-weight: 600;
}
.list-group-item {
cursor: pointer;
}
.item_icon {
color: var(--color-dark-blue);
max-width: 20px;
}
.list-group-item {
border: 0px;
}
</style>
Source