MT#62260 Add Phonebook search bar

* Add a search field to search for contacts
by Name, Phone number or the property Shared.
Note, the name and phone search use the wild card
before and after the typed string.
* Move call button outside the 3 dots menus
for easier access.

Change-Id: I2c135d744a66c921a028dcece4a889b482ccd33f
master
Debora Crescenzo 3 months ago committed by Crescenzo Debora
parent 0340bd7e3c
commit 8b4f8b2e9b

@ -0,0 +1,162 @@
<template>
<div>
<div
class="row justify-center full-width q-gutter-x-sm"
>
<div
class="col-xs-12 col-md-2"
>
<q-select
v-model="filterType"
emit-value
map-options
dense
:options="filterTypeOptions"
:label="$t('Filter by')"
/>
</div>
<div
class="col-xs-12 col-md-2"
>
<q-select
v-if="filterType === 'shared'"
v-model="typedFilter"
:options="sharedFilterOptions"
dense
:disable="filterType === null"
:label="$t('Is shared?')"
@update:model-value="triggerFilter"
/>
<q-input
v-else
v-model="typedFilter"
type="text"
dense
:disable="filterType === null"
:label="$t('Type something')"
@keypress.enter="triggerFilter"
>
<template
#append
>
<q-btn
icon="search"
color="primary"
dense
flat
@click="triggerFilter"
/>
</template>
</q-input>
</div>
</div>
<div
class="row justify-center full-width q-gutter-x-sm"
>
<div
class="col-xs-12 col-md-4"
>
<q-chip
v-for="(filterItem, index) in filters"
:key="index"
:label="getFilterLabel(filterItem)"
:disable="false"
icon="filter_alt"
removable
dense
color="primary"
text-color="dark"
@remove="removeFilter(filterItem.name)"
/>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'CscSubscriberFilters',
emits: ['filter'],
data () {
return {
filterType: null,
typedFilter: '',
filters: []
}
},
computed: {
filterTypeOptions () {
return [
{
label: this.$t('Name'),
value: 'name'
},
{
label: this.$t('Number'),
value: 'number'
},
{
label: this.$t('Shared'),
value: 'shared'
}
]
},
sharedFilterOptions () {
return [
{ label: this.$t('Yes'), value: '1' },
{ label: this.$t('No'), value: '0' }
]
}
},
methods: {
triggerFilter () {
this.addFilter(this.filterType, this.typedFilter)
},
removeFilter (name) {
this.filters = this.filters.filter((item) => item.name !== name)
this.filter()
},
removeFilters () {
if (this.filters.length > 0) {
this.filters = []
this.filter()
}
},
addFilter (name, value) {
const valueTrimmed = value?.value || value.trim()
if (valueTrimmed) {
this.typedFilter = ''
this.filters = this.filters.filter((item) => item.name !== name)
const filter = {
name,
value: valueTrimmed
}
this.filters.push(filter)
this.filter()
}
},
filter () {
const params = {}
this.filters.forEach((filter) => {
params[filter.name] = filter.value
})
this.$emit('filter', params)
},
getFilterLabel (filterItem) {
const filterNameTranslation = {
name: this.$t('Name'),
number: this.$t('Number'),
shared: this.$t('Shared')
}
const filterNameTitle = filterNameTranslation[filterItem.name] || this.$t('Unknown name')
if (filterItem.name === 'shared') {
const yes = this.$t('Yes')
const no = this.$t('No')
return `${filterNameTitle}: ${filterItem.value === '1' ? yes : no}`
}
return `${filterNameTitle}: ${filterItem.value}`
}
}
}
</script>

@ -26,6 +26,38 @@
<csc-page
class="q-pa-lg"
>
<csc-list-actions
class="row justify-center q-mb-xs"
>
<template
#slot1
>
<csc-list-action-button
v-if="!showFilters"
icon="filter_alt"
color="primary"
:label="$t('Search Contact')"
data-cy="groups-filter-open"
@click="openSearchFilters"
/>
<csc-list-action-button
v-if="showFilters"
icon="clear"
color="negative"
:label="$t('Close')"
data-cy="groups-filter-close"
@click="closeFilters"
/>
</template>
</csc-list-actions>
<csc-subscriber-filters
v-if="showFilters"
ref="filters"
class="q-mb-md q-pa-md"
@filter="applyFilter"
/>
<q-table
v-model:pagination="pagination"
class="no-shadow"
@ -65,13 +97,8 @@
</template>
<template #body-cell-menu="{ row }">
<td>
<div class="q-gutter-x-sm">
<csc-more-menu>
<csc-popup-menu-item
icon="fas fa-phone-alt"
color="primary"
:label="$t('Call back')"
@click="homePageCall(row)"
/>
<csc-popup-menu-item
icon="fas fa-pen"
color="primary"
@ -87,6 +114,15 @@
@click="deleteRow(row)"
/>
</csc-more-menu>
<q-btn
icon="fas fa-phone-alt"
color="primary"
size="sm"
flat
:label="$t('Call back')"
@click="homePageCall(row)"
/>
</div>
</td>
</template>
</q-table>
@ -95,11 +131,14 @@
</template>
<script>
import CscListActionButton from 'components/CscListActionButton'
import CscListActions from 'components/CscListActions'
import CscMoreMenu from 'components/CscMoreMenu'
import CscPage from 'components/CscPage'
import CscPageSticky from 'components/CscPageSticky'
import CscPopupMenuItem from 'components/CscPopupMenuItem'
import CscSpinner from 'components/CscSpinner'
import CscSubscriberFilters from 'components/pages/SubscriberPhonebook/CscSubscriberFilters'
import { LIST_DEFAULT_ROWS } from 'src/api/common'
import { mapWaitingActions } from 'vue-wait'
import { mapGetters, mapState } from 'vuex'
@ -110,7 +149,10 @@ export default {
CscPage,
CscMoreMenu,
CscPopupMenuItem,
CscPageSticky
CscPageSticky,
CscListActionButton,
CscListActions,
CscSubscriberFilters
},
data () {
return {
@ -121,7 +163,9 @@ export default {
page: 1,
rowsPerPage: LIST_DEFAULT_ROWS,
rowsNumber: 0
}
},
filters: {},
showFilters: false
}
},
computed: {
@ -166,6 +210,9 @@ export default {
sortable: true
}
]
},
hasFilters () {
return Object.keys(this.filters).length > 0
}
},
async mounted () {
@ -233,6 +280,44 @@ export default {
},
openSeatTable () {
this.$router.push('/user/seats')
},
applyFilter (filters) {
this.filters = filters
// Add wildcards to make search more extensive
if (filters?.name) {
this.filters.name = `*${filters.name}*`
}
if (filters?.number) {
this.filters.number = `*${filters.number}*`
}
this.pagination.page = 1 // Reset to first page on filter change
this.$scrollTo(this.$parent.$el)
const payload = this.filters
payload.page = 1
payload.subscriber_id = this.getSubscriberId
this.loadSubscriberPhonebook(payload)
},
closeFilters () {
this.showFilters = false
this.resetFilters()
},
openSearchFilters () {
this.showFilters = true
},
resetFilters () {
if (this.hasFilters) {
this.filters = {}
this.loadSubscriberPhonebook({
page: this.pagination.page,
rows: this.pagination.rowsPerPage,
order_by: this.pagination.sortBy,
order_by_direction: this.pagination.descending ? 'desc' : 'asc',
subscriber_id: this.getSubscriberId
})
}
}
}
}

Loading…
Cancel
Save