Skip to content

Commit 6937c82

Browse files
committed
ref(gov): multi-select for option filter
1 parent 09db11f commit 6937c82

4 files changed

Lines changed: 75 additions & 37 deletions

File tree

components/modules/proposal/ProposalOverview.vue

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,27 @@ const votes = ref([])
4343
const votesTotal = ref(0)
4444
4545
const defaultFilters = {
46-
option: null,
46+
option: {
47+
yes: false,
48+
no: false,
49+
no_with_veto: false,
50+
abstain: false,
51+
},
4752
}
4853
const { filters, setFilter, resetFilter } = useFilters(defaultFilters)
4954
const handleUpdateFilter = (target, newFilter, withRefetch) => {
5055
setFilter(target, newFilter)
51-
if (withRefetch) getVotes()
56+
if (withRefetch) {
57+
getVotes()
58+
page.value = 1
59+
}
5260
}
5361
const handleResetFilters = (target, withRefetch) => {
5462
resetFilter(target)
55-
if (withRefetch) getVotes()
63+
if (withRefetch) {
64+
getVotes()
65+
page.value = 1
66+
}
5667
}
5768
5869
/** Pagination */
@@ -71,7 +82,9 @@ const getVotes = async () => {
7182
const { data } = await fetchProposalVotes({
7283
id: props.proposal.id,
7384
offset: (page.value - 1) * 10,
74-
option: filters.option,
85+
option: Object.keys(filters.value.option)
86+
.filter((opt) => filters.value.option[opt])
87+
.join(","),
7588
voter: (activeTab.value === "validators_votes" && "validator") || (activeTab.value === "addresses_votes" && "address") || null,
7689
})
7790
votes.value = data.value

components/modules/proposal/VotesTable.vue

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,15 @@ import Button from "@/components/ui/Button.vue"
1111
import Tooltip from "@/components/ui/Tooltip.vue"
1212
import Popover from "@/components/ui/Popover.vue"
1313
import Radio from "@/components/ui/Radio.vue"
14+
import Checkbox from "@/components/ui/Checkbox.vue"
1415
1516
/** Shared Components */
1617
import TablePlaceholderView from "@/components/shared/TablePlaceholderView.vue"
1718
19+
/** Store */
20+
import { useEnumStore } from "@/store/enums"
21+
const enumStore = useEnumStore()
22+
1823
const emit = defineEmits(["onPrevPage", "onNextPage", "updatePage", "updateFilters", "onFiltersReset"])
1924
const props = defineProps({
2025
proposal: {
@@ -44,33 +49,52 @@ const props = defineProps({
4449
4550
const router = useRouter()
4651
52+
const options = enumStore.enums.voteOption
53+
4754
/** Filter by vote option */
48-
const optionFilter = ref()
55+
const setDefaultOptionFilter = () => {
56+
options.forEach((opt) => {
57+
optionFilter[opt] = false
58+
})
59+
}
60+
const optionFilter = reactive({})
61+
setDefaultOptionFilter()
62+
4963
const cachedOptionFilter = ref()
5064
51-
const hasActiveFilters = computed(() => !!optionFilter.value)
65+
const hasActiveOptionFilters = computed(() => {
66+
let hasActiveFilter = false
67+
Object.keys(optionFilter).forEach((opt) => {
68+
if (optionFilter[opt]) {
69+
hasActiveFilter = true
70+
}
71+
})
72+
return hasActiveFilter
73+
})
5274
5375
const isOptionPopoverOpen = ref(false)
5476
const handleOpenOptionPopover = () => {
5577
isOptionPopoverOpen.value = true
5678
57-
cachedOptionFilter.value = optionFilter.value
79+
cachedOptionFilter.value = { ...optionFilter }
5880
}
5981
const onOptionPopoverClose = () => {
6082
isOptionPopoverOpen.value = false
6183
62-
optionFilter.value = cachedOptionFilter.value
84+
options.forEach((opt) => {
85+
optionFilter[opt] = cachedOptionFilter.value[opt]
86+
})
6387
}
6488
const handleApplyOptionFilters = () => {
6589
isOptionPopoverOpen.value = false
6690
67-
emit("updateFilters", "option", optionFilter.value, true)
91+
emit("updateFilters", "option", optionFilter, true)
6892
}
6993
const handleResetOptionFilter = () => {
7094
isOptionPopoverOpen.value = false
7195
7296
emit("onFiltersReset", "option", true)
73-
optionFilter.value = null
97+
setDefaultOptionFilter()
7498
}
7599
76100
/** Pagination */
@@ -90,7 +114,7 @@ const handleNextPage = () => {
90114
watch(
91115
() => props.filters.option,
92116
() => {
93-
if (!props.filters.option) optionFilter.value = null
117+
if (!props.filters.option) setDefaultOptionFilter()
94118
},
95119
)
96120
</script>
@@ -99,13 +123,18 @@ watch(
99123
<Flex direction="column" :class="[$style.wrapper, isLoadingVotes && $style.disabled]">
100124
<Flex wrap="wrap" align="center" gap="8" :class="$style.filters">
101125
<Popover :open="isOptionPopoverOpen" @on-close="onOptionPopoverClose" width="200">
102-
<Button @click="handleOpenOptionPopover" type="secondary" size="mini" :disabled="!votes.length && !hasActiveFilters">
103-
<Icon name="plus-circle" size="12" :color="optionFilter ? 'brand' : 'tertiary'" />
104-
<Text color="secondary">Option<template v-if="optionFilter">:</template></Text>
126+
<Button @click="handleOpenOptionPopover" type="secondary" size="mini" :disabled="!votes.length && !hasActiveOptionFilters">
127+
<Icon name="plus-circle" size="12" :color="hasActiveOptionFilters ? 'brand' : 'tertiary'" />
128+
<Text color="secondary">Option<template v-if="hasActiveOptionFilters">:</template></Text>
105129

106-
<template v-if="optionFilter">
130+
<template v-if="hasActiveOptionFilters">
107131
<Text size="12" weight="600" color="primary" style="text-transform: capitalize">
108-
{{ optionFilter.replaceAll("_", " ") }}
132+
{{
133+
options
134+
.map((opt) => optionFilter[opt] && opt.replaceAll("_", " "))
135+
.filter(Boolean)
136+
.join(", ")
137+
}}
109138
</Text>
110139

111140
<Icon @click.stop="handleResetOptionFilter" name="close-circle" size="12" color="secondary" />
@@ -117,25 +146,20 @@ watch(
117146
<Text size="12" weight="600" color="secondary">Filter by Vote Option</Text>
118147

119148
<Flex direction="column" gap="8">
120-
<Radio v-model="optionFilter" value="yes">
121-
<Text size="12" weight="600" color="primary">Yes</Text>
122-
</Radio>
123-
<Radio v-model="optionFilter" value="no">
124-
<Text size="12" weight="600" color="primary">No</Text>
125-
</Radio>
126-
<Radio v-model="optionFilter" value="no_with_veto">
127-
<Text size="12" weight="600" color="primary">No with veto</Text>
128-
</Radio>
129-
<Radio v-model="optionFilter" value="abstain">
130-
<Text size="12" weight="600" color="primary">Abstain</Text>
131-
</Radio>
149+
<Checkbox v-for="opt in options" v-model="optionFilter[opt]">
150+
<Text size="12" weight="600" color="primary" style="text-transform: capitalize">
151+
{{ opt.replaceAll("_", " ") }}
152+
</Text>
153+
</Checkbox>
132154
</Flex>
133155

134156
<Flex gap="8">
135-
<Button @click="handleApplyOptionFilters" type="secondary" size="mini" wide :disabled="!optionFilter">
157+
<Button @click="handleApplyOptionFilters" type="secondary" size="mini" wide :disabled="!hasActiveOptionFilters">
136158
Apply
137159
</Button>
138-
<Button v-if="optionFilter" @click="handleResetOptionFilter" type="tertiary" size="mini" wide>Reset</Button>
160+
<Button v-if="hasActiveOptionFilters" @click="handleResetOptionFilter" type="tertiary" size="mini" wide>
161+
Reset
162+
</Button>
139163
</Flex>
140164
</Flex>
141165
</template>
@@ -217,7 +241,7 @@ watch(
217241
icon="governance"
218242
subIcon="search"
219243
:descriptionWidth="260"
220-
:callback="optionFilter ? () => handleResetOptionFilter() : null"
244+
:callback="hasActiveOptionFilters ? () => handleResetOptionFilter() : null"
221245
callbackText="Reset Filters"
222246
style="height: 100%"
223247
/>

components/ui/Checkbox.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const emit = defineEmits(["update:modelValue"])
2323
<style module>
2424
.wrapper {
2525
cursor: pointer;
26+
user-select: none;
2627
2728
&:hover {
2829
.checkbox {

composables/filters.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
export const useFilters = (defaultFilters) => {
2-
const filters = reactive({ ...defaultFilters })
2+
const filters = ref({ ...defaultFilters })
33

44
const setFilter = (target, filter) => {
5-
if (!(target in filters)) return
6-
filters[target] = filter
5+
if (!(target in filters.value)) return
6+
filters.value[target] = filter
77
}
88

99
const resetFilter = (target) => {
10-
if (!(target in filters)) return
11-
filters[target] = defaultFilters[target]
10+
if (!(target in filters.value)) return
11+
filters.value[target] = defaultFilters[target]
1212
}
1313

1414
const resetAllFilters = () => {
15-
filters = { ...defaultFilters }
15+
filters.value = { ...defaultFilters }
1616
}
1717

1818
return { filters, setFilter, resetFilter, resetAllFilters }

0 commit comments

Comments
 (0)