Skip to content

Commit f5bea4c

Browse files
authored
Merge pull request #330 from IFRCGo/WN-412
Improve users filter UX and search handling
2 parents 4954069 + 5e5ec63 commit f5bea4c

3 files changed

Lines changed: 91 additions & 23 deletions

File tree

resources/assets/js/pages/content/selectSociety.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
v-model="selectedSoc"
55
class="w-100 v-select-custom"
66
:options="listOfSocieties"
7-
label="name" :disabled="listOfSocieties.length === 0"
7+
label="name" :disabled="disabled || listOfSocieties.length === 0"
88
:placeholder="$t('content.whatnow.no_soc')">
99
<template slot="option" slot-scope="option">
1010
<div class="ml-2 rtl-mr-2 dropdown-option">
@@ -23,7 +23,7 @@ import { mapGetters } from 'vuex'
2323
import * as permissionsList from '../../store/permissions'
2424
2525
export default {
26-
props: ['selected', 'staynull', 'dontfilter', 'countryCode'],
26+
props: ['selected', 'staynull', 'dontfilter', 'countryCode', 'disabled'],
2727
async mounted () {
2828
this.loading = true
2929
await this.fetchOrganisations()

resources/assets/js/pages/users/list.vue

Lines changed: 88 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
</b-button>
1111
</b-col>
1212
</page-banner>
13-
<b-row class="pb-2 px-4 pt-4 bg-white" align-v="center">
14-
<b-col cols="12" md="6" lg="3" xl="2">
13+
<b-row class="users-filter-row pb-2 px-4 pt-4 bg-white" align-v="end">
14+
<b-col cols="12" md="6" lg="2" xl="2" class="users-filter-col">
1515
<p class="select-header"> {{ $t('users.list.select_status') }}</p>
1616
<v-select
1717
v-model="activatedFilter"
@@ -23,62 +23,66 @@
2323
]"
2424
label="name"
2525
:reduce="option => option.value"
26+
:disabled="fetchingUsers"
2627
placeholder="Select Status">
2728
</v-select>
2829
</b-col>
29-
<b-col cols="12" md="6" lg="3" xl="2" v-if="!apiUsers">
30+
<b-col cols="12" md="6" lg="2" xl="2" class="users-filter-col" v-if="!apiUsers">
3031
<p class="select-header"> {{ $t('users.list.select_role') }}</p>
3132
<v-select
3233
v-model="roleFilter"
3334
class="v-select-custom"
3435
:options="roleOptions"
3536
label="name"
3637
:reduce="option => option.id"
38+
:disabled="fetchingUsers"
3739
placeholder="Select Role">
3840
</v-select>
3941
</b-col>
40-
<b-col cols="12" md="6" lg="3" xl="2" v-if="apiUsers">
42+
<b-col cols="12" md="6" lg="2" xl="2" class="users-filter-col" v-if="apiUsers">
4143
<p class="select-header"> {{ $t('users.list.select_country') }}</p>
4244
<v-select
4345
v-model="countryFilter"
4446
class="v-select-custom"
4547
:options="countryList"
4648
label="name"
4749
:reduce="option => option.id"
50+
:disabled="fetchingUsers"
4851
placeholder="Select Country">
4952
</v-select>
5053
</b-col>
51-
<b-col cols="12" md="6" lg="4" xl="3" v-if="apiUsers">
54+
<b-col cols="12" md="6" lg="4" xl="3" class="users-filter-col" v-if="apiUsers">
5255
<p class="select-header"> {{ $t('users.list.select_terms') }}</p>
5356
<v-select
5457
v-model="termsFilter"
5558
class="v-select-custom text-nowrap"
5659
:options="termsList"
5760
label="version"
5861
:reduce="option => option.version"
62+
:disabled="fetchingUsers"
5963
placeholder="Select Terms">
6064
</v-select>
6165
</b-col>
62-
<b-col cols="12" md="6" lg="3" xl="2">
63-
<p class="select-header" v-if="!apiUsers"> {{ $t('users.list.select_society') }}</p>
66+
<b-col cols="12" md="6" lg="2" xl="2" class="users-filter-col" v-if="!apiUsers">
67+
<p class="select-header"> {{ $t('users.list.select_society') }}</p>
6468
<selectSociety
65-
class="float-right"
69+
class="users-society-filter"
6670
:selected.sync="selectedSoc"
67-
:staynull="true"
68-
v-if="!apiUsers"/>
71+
:disabled="fetchingUsers"
72+
:staynull="true"/>
6973
</b-col>
70-
<b-col cols="12" md="6" lg="4" xl="3" class="ml-lg-auto">
74+
<b-col cols="12" md="6" lg="3" xl="3" class="users-filter-col users-search-filter-col" :class="{ 'ml-lg-auto': !apiUsers }">
7175
<p class="select-header"> {{ $t('users.list.search') }}</p>
7276
<b-form-input
73-
v-model.trim="searchFilter"
77+
v-model.trim="localSearchFilter"
7478
class="search-filter-input"
7579
type="text"
7680
:disabled="fetchingUsers"
7781
:placeholder="$t('users.list.search_placeholder')">
7882
</b-form-input>
7983
</b-col>
80-
<b-col class="text-right">
81-
<b-button @click="clearFilters" :disabled="noFilters" class="btn-outline-primary clear-filter-btn">
84+
<b-col cols="12" md="6" lg="auto" xl="auto" class="users-filter-col users-clear-filter-col text-lg-right">
85+
<b-button @click="clearFilters" :disabled="fetchingUsers || noFilters" class="btn-outline-primary clear-filter-btn">
8286
{{ $t('users.list.clear_filters') }}
8387
</b-button>
8488
</b-col>
@@ -237,6 +241,8 @@ export default {
237241
roles: null,
238242
locationOptions: null,
239243
searchDebounce: null,
244+
localSearchFilter: '',
245+
pendingSearchFetch: false,
240246
countries: require('country-list')()
241247
}
242248
},
@@ -250,7 +256,7 @@ export default {
250256
deep: true
251257
},
252258
activatedFilter: fetchHandler,
253-
searchFilter: {
259+
localSearchFilter: {
254260
handler (val, oldVal) {
255261
if (val !== oldVal) {
256262
clearTimeout(this.searchDebounce)
@@ -259,12 +265,19 @@ export default {
259265
return
260266
}
261267
this.searchDebounce = setTimeout(() => {
262-
this.currentPage = 1
263-
this.fetchUsers()
268+
this.queueSearchFetch()
264269
}, 350)
265270
}
266271
}
267272
},
273+
searchFilter: {
274+
handler (val) {
275+
const search = val || ''
276+
if (search !== this.localSearchFilter) {
277+
this.localSearchFilter = search
278+
}
279+
}
280+
},
268281
roleFilter: fetchHandler,
269282
countryFilter: fetchHandler,
270283
termsFilter: fetchHandler,
@@ -282,6 +295,7 @@ export default {
282295
},
283296
mounted () {
284297
this.fetchOrganisations()
298+
this.localSearchFilter = this.searchFilter
285299
this.fetchUsers()
286300
this.fetchTerms()
287301
},
@@ -297,6 +311,7 @@ export default {
297311
this.roleFilter = null
298312
this.countryFilter = null
299313
this.selectedSoc = null
314+
this.localSearchFilter = ''
300315
this.searchFilter = ''
301316
this.termsFilter = termsDefault
302317
},
@@ -338,7 +353,27 @@ export default {
338353
async fetchOrganisations () {
339354
await this.$store.dispatch('content/fetchOrganisations')
340355
},
356+
queueSearchFetch () {
357+
const search = this.localSearchFilter ? this.localSearchFilter.trim() : ''
358+
if (search.length > 0 && search.length < 3) {
359+
return
360+
}
361+
this.searchFilter = search
362+
if (this.fetchingUsers) {
363+
this.pendingSearchFetch = true
364+
return
365+
}
366+
if (this.currentPage !== 1) {
367+
this.currentPage = 1
368+
} else {
369+
this.fetchUsers()
370+
}
371+
},
341372
async fetchUsers () {
373+
const search = this.searchFilter ? this.searchFilter.trim() : ''
374+
if (search.length > 0 && search.length < 3) {
375+
return
376+
}
342377
this.fetchingUsers = true
343378
if (this.rolesEmpty) {
344379
await this.fetchRoles()
@@ -349,6 +384,7 @@ export default {
349384
if (filterRoleId === null) {
350385
filterRoleId = this.apiUsers && apiUserRole ? apiUserRole.id : null
351386
}
387+
const excludeRoleId = !this.apiUsers && filterRoleId === null && apiUserRole ? apiUserRole.id : null
352388
353389
if (!apiUserRole && this.apiUsers) {
354390
console.warn('Could not find API User in the role list')
@@ -363,9 +399,10 @@ export default {
363399
society: this.selectedSoc ? this.selectedSoc.countryCode : null,
364400
country_code: this.countryFilter,
365401
search: this.searchFilter,
366-
terms_version: this.termsFilter === termsDefault ? null : this.termsFilter
402+
terms_version: this.termsFilter === termsDefault ? null : this.termsFilter,
403+
exclude_role: excludeRoleId
367404
},
368-
admin: !this.apiUsers && filterRoleId === null,
405+
admin: !this.apiUsers && filterRoleId === null && !apiUserRole,
369406
orderBy: this.orderBy,
370407
sort: this.sortDesc ? 'desc' : 'asc'
371408
})
@@ -374,6 +411,10 @@ export default {
374411
}
375412
376413
this.fetchingUsers = false
414+
if (this.pendingSearchFetch) {
415+
this.pendingSearchFetch = false
416+
this.queueSearchFetch()
417+
}
377418
},
378419
async fetchRoles () {
379420
this.roles = this.roleOptions
@@ -492,7 +533,7 @@ export default {
492533
this.roleFilter === null &&
493534
this.countryFilter === null &&
494535
this.selectedSoc === null &&
495-
!this.searchFilter &&
536+
!this.localSearchFilter &&
496537
this.termsFilter === termsDefault
497538
},
498539
...mapGetters({
@@ -519,8 +560,28 @@ export default {
519560
color: #FFFFFF !important;
520561
}
521562
563+
.users-filter-row {
564+
row-gap: 1rem;
565+
}
566+
.users-filter-col {
567+
margin-bottom: 0.75rem;
568+
}
569+
.users-society-filter {
570+
width: 100%;
571+
}
572+
.users-search-filter-col {
573+
padding-right: 0.5rem;
574+
}
575+
.users-clear-filter-col {
576+
display: flex;
577+
justify-content: flex-end;
578+
padding-left: 0.25rem;
579+
}
522580
.clear-filter-btn {
523-
margin-top: 2.5rem;
581+
align-self: flex-end;
582+
margin-top: 0;
583+
min-height: 2rem;
584+
white-space: nowrap;
524585
}
525586
btn-outline-primary.disabled, .btn-outline-primary:disabled {
526587
color: white;
@@ -536,4 +597,10 @@ export default {
536597
height: 2.45rem;
537598
}
538599
600+
@media (max-width: 991.98px) {
601+
.users-clear-filter-col {
602+
justify-content: flex-start;
603+
}
604+
}
605+
539606
</style>

resources/assets/js/store/modules/users.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ export const actions = {
136136
filterString += filters.society !== null ? `&filters[society]=${filters.society}` : ''
137137
filterString += filters.country_code !== null ? `&filters[country_code]=${filters.country_code}` : ''
138138
filterString += filters.terms_version !== null ? `&filters[terms_version]=${filters.terms_version}` : ''
139+
filterString += filters.exclude_role != null ? `&filters[exclude_role]=${filters.exclude_role}` : ''
139140
const search = filters.search ? filters.search.trim() : ''
140141
filterString += search.length >= 3 ? `&filters[search]=${encodeURIComponent(search)}` : ''
141142

0 commit comments

Comments
 (0)