frontend/src/components/list/partials/filter-popup.vue

117 lines
2.1 KiB
Vue

<template>
<x-button
v-if="hasFilters"
type="secondary"
@click="clearFilters"
>
{{ $t('filters.clear') }}
</x-button>
<filters
:class="{'is-open': visibleInternal}"
class="filter-popup"
v-model="value"
@change="update"
ref="filters"
/>
</template>
<script>
import {closeWhenClickedOutside} from '@/helpers/closeWhenClickedOutside'
import Filters from '../../../components/list/partials/filters'
import {defaultParams} from '../../tasks/mixins/taskList'
export default {
name: 'filter-popup',
components: {
Filters,
},
props: {
modelValue: {
required: true,
},
visible: {
type: Boolean,
default: false,
},
},
emits: ['update:modelValue'],
data() {
return {
visibleInternal: false,
value: null,
}
},
computed: {
hasFilters() {
// this.value also contains the page parameter which we don't want to include in filters
const {sort_by, order_by, filter_by, filter_value, filter_comparator, filter_concat, s} = this.value
const filterParams = {
sort_by,
order_by,
filter_by,
filter_value,
filter_comparator,
filter_concat,
s: s ?? null,
}
const def = {...defaultParams(), s: null}
return JSON.stringify(filterParams) !== JSON.stringify(def)
},
},
mounted() {
document.addEventListener('click', this.hidePopup)
},
beforeUnmount() {
document.removeEventListener('click', this.hidePopup)
},
watch: {
modelValue: {
handler(value) {
this.value = value
},
immediate: true,
},
value() {
this.update()
},
visible() {
this.visibleInternal = !this.visibleInternal
},
},
methods: {
hidePopup(e) {
if (!this.visibleInternal) {
return
}
closeWhenClickedOutside(e, this.$refs.filters.$el, () => {
this.visibleInternal = false
})
},
clearFilters() {
this.value = {...defaultParams()}
},
update() {
this.$emit('update:modelValue', this.value)
},
},
}
</script>
<style lang="scss">
.filter-popup {
transition: opacity $transition;
opacity: 0;
height: 0;
overflow: hidden;
position: absolute;
top: 2rem;
&.is-open {
opacity: 1;
height: auto;
}
}
</style>