Skip to content

Commit

Permalink
Filters multiple values (#144)
Browse files Browse the repository at this point in the history
- create standard to define all filter behaviours
- implement filters for transactions-list
- implement dashboard savings navigation to transactions-list
  • Loading branch information
cioraneanu authored Dec 25, 2024
1 parent 0638e85 commit ce8ab72
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 112 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<van-cell-group inset >
<van-cell-group inset @click="onNavigate">
<div class="van-cell-group-title">Savings summary:</div>

<van-grid :column-num="3">
Expand All @@ -13,6 +13,7 @@
</template>
<script setup>
import TablerIconConstants from '~/constants/TablerIconConstants.js'
import RouteConstants from '~/constants/RouteConstants.js'
const profileStore = useProfileStore()
const dataStore = useDataStore()
Expand All @@ -23,4 +24,8 @@ const savingsAmountClass = computed(() => (dataStore.transactionsListSavingsAmou
const savingsPercentFormatted = computed(() => {
return `${Math.trunc(dataStore.transactionsListSavingsPercentage)} %`
})
const onNavigate = async () => {
let transactionIds = dataStore.transactionsListSavings.map(item => item.id).join(',')
await navigateTo(`${RouteConstants.ROUTE_TRANSACTION_LIST}?id=${transactionIds}`)
}
</script>
2 changes: 1 addition & 1 deletion front/components/transaction/transaction-filters.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
<budget-select v-model="budget" :disabled="!!withoutBudget" class="flex-1" :is-multi-select="false" :auto-select-parents="false" />
</div>

<account-select v-model="account" />
<account-select v-model="account" :isMultiSelect="true" />

<div class="flex-center-vertical">
<app-date class="flex-1" v-model="dateStart" label="Date after" />
Expand Down
2 changes: 1 addition & 1 deletion front/pages/transactions/[[id]].vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<div class="mb-10" />

<transaction-assistant v-if="!itemId" @change="onAssistant" />
<transaction-assistant v-if="!itemId" @change="onAssistant" @keyup.enter="saveItem" />

<transaction-type-tabs v-model="type" class="mx-3 mt-1 mb-1" />

Expand Down
114 changes: 5 additions & 109 deletions front/pages/transactions/list.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import { get, isEqual } from 'lodash'
import anime from 'animejs'
import { animateSwipeList } from '~/utils/AnimationUtils.js'
import Budget from '~/models/Budget.js'
import TransactionFilterUtils from '~/utils/TransactionFilterUtils.js'
const dataStore = useDataStore()
const route = useRoute()
Expand Down Expand Up @@ -97,100 +98,15 @@ const formClass = computed(() => ({
let filters = ref({})
let filtersDictionary = computed(() => {
const _filter = filters.value
return [
{
display: `Description: ${_filter.description}`,
filter: `description_contains:"${_filter.description}"`,
active: !isStringEmpty(_filter.description),
},
{
display: `Type: ${get(_filter, 'transactionType.name')}`,
filter: `type:"${get(_filter, 'transactionType.fireflyCode')}"`,
active: !!_filter.transactionType,
},
{
display: `Tag: ${Tag.getDisplayNameEllipsized(_filter.tag)}`,
filter: `tag_is:"${Tag.getDisplayNameEllipsized(_filter.tag)}"`,
active: !!_filter.tag,
},
{
display: `- Tag: ${Tag.getDisplayNameEllipsized(_filter.excludedTag)}`,
filter: `-tag_is:"${Tag.getDisplayNameEllipsized(_filter.excludedTag)}"`,
active: !!_filter.excludedTag,
},
{
display: `No tags`,
filter: `has_any_tag:false"`,
active: !!_filter.withoutTag,
},
{
display: `Category: ${Category.getDisplayName(_filter.category)}`,
filter: `category_is:"${Category.getDisplayName(_filter.category)}"`,
active: !!_filter.category,
},
{
display: `- Category: ${Category.getDisplayName(_filter.excludedCategory)}`,
filter: `-category_is:"${Category.getDisplayName(_filter.excludedCategory)}"`,
active: !!_filter.excludedCategory,
},
{
display: `No category`,
filter: `has_any_category:false"`,
active: !!_filter.withoutCategory,
},
{
display: `Budget: ${Budget.getDisplayName(_filter.budget)}`,
filter: `budget_is:"${Budget.getDisplayName(_filter.budget)}"`,
active: !!_filter.budget,
},
{
display: `No budget`,
filter: `has_any_budget:false"`,
active: !!_filter.withoutBudget,
},
{
display: `Account: ${Account.getDisplayName(_filter.account)}`,
filter: `account_is:"${Account.getDisplayName(_filter.account)}"`,
active: !!_filter.account,
},
{
display: `- Account: ${Account.getDisplayName(_filter.excludedAccount)}`,
filter: `-account_is:"${Account.getDisplayName(_filter.excludedAccount)}"`,
active: !!_filter.excludedAccount,
},
{
display: `Amount > ${_filter.amountStart}`,
filter: `more:"${_filter.amountStart}"`,
active: !!_filter.amountStart,
},
{
display: `Amount < ${_filter.amountEnd}`,
filter: `less:"${_filter.amountEnd}"`,
active: !!_filter.amountEnd,
},
{
display: `Date > ${DateUtils.dateToUI(_filter.dateStart)}`,
filter: `date_after:"${DateUtils.dateToString(_filter.dateStart)}"`,
active: !!_filter.dateStart,
},
{
display: `Date < ${DateUtils.dateToUI(_filter.dateEnd)}`,
filter: `date_before:"${DateUtils.dateToString(_filter.dateEnd)}"`,
active: !!_filter.dateEnd,
},
].map((item) => {
item.filter = item.filter.replace(/(\w+):"([^"]+)"/g, (match, key, content) => `${key}:"${encodeURIComponent(content)}"`)
return item
})
return TransactionFilterUtils.getActiveFilters(filters.value)
})
let filtersDisplayList = computed(() => {
return filtersDictionary.value.filter((item) => item.active).map((item) => item.display)
return filtersDictionary.value.map((item) => item.display)
})
let filtersBackendList = computed(() => {
return filtersDictionary.value.filter((item) => item.active).map((item) => item.filter)
return filtersDictionary.value.map((item) => item.filter)
})
watch(filtersBackendList, (newValue, oldValue) => {
Expand All @@ -208,31 +124,11 @@ const onClearFilters = () => {
const toolbar = useToolbar()
toolbar.init({
title: 'Transactions list',
// subtitle: 'bla'
subtitle: computed(() => `${listTotalCount.value} Items`),
// backRoute: RouteConstants.ROUTE_EXTRAS,
})
onMounted(() => {
let urlFilters = {
tag: dataStore.tagDictionaryById[get(route.query, 'tag_id')],
excludedTag: dataStore.tagDictionaryById[get(route.query, 'excluded_tag_id')],
transactionType: Object.values(Transaction.types).find((item) => item.code === get(route.query, 'type')),
category: dataStore.categoryDictionary[get(route.query, 'category_id')],
budget: dataStore.budgetDictionary[get(route.query, 'budget_id')],
excludedCategory: dataStore.categoryDictionary[get(route.query, 'excluded_category_id')],
account: dataStore.accountDictionary[get(route.query, 'account_id')],
excludedAccount: dataStore.accountDictionary[get(route.query, 'excluded_account_id')],
description: get(route.query, 'description'),
dateStart: DateUtils.stringToDate(get(route.query, 'date_start')),
dateEnd: DateUtils.stringToDate(get(route.query, 'date_end')),
amountStart: get(route.query, 'amount_start'),
amountEnd: get(route.query, 'amount_end'),
withoutTag: get(route.query, 'without_tag'),
withoutBudget: get(route.query, 'without_budget'),
withoutCategory: get(route.query, 'without_category'),
}
filters.value = urlFilters
filters.value = TransactionFilterUtils.getFiltersFromURL()
})
animateSwipeList(list)
Expand Down
176 changes: 176 additions & 0 deletions front/utils/TransactionFilterUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import { get, isArray } from 'lodash'
import Transaction from '~/models/Transaction.js'
import Tag from '~/models/Tag.js'
import Category from '~/models/Category.js'
import Budget from '~/models/Budget.js'
import Account from '~/models/Account.js'

export default {
filters: {
id: {
displayName: 'Id',
filterName: 'id',
bagKey: 'id',
displayValue: (item) => ellipsizeText(item, 100),
},
description: {
displayName: 'Description',
filterName: 'description_contains',
bagKey: 'description',
},
transactionType: {
displayName: 'Type',
filterName: 'type',
bagKey: 'transactionType',
displayValue: (item) => get(item, 'name'),
filterValue: (item) => get(item, 'fireflyCode'),
},
tag: {
displayName: 'Tag',
filterName: 'tag_is',
bagKey: 'tag',
displayValue: (item) => Tag.getDisplayNameEllipsized(item),
filterValue: (item) => Tag.getDisplayName(item),
},
excludeTag: {
displayName: '- Tag',
filterName: '-tag_is',
bagKey: 'excludedTag',
displayValue: (item) => Tag.getDisplayNameEllipsized(item),
filterValue: (item) => Tag.getDisplayName(item),
},
noTag: {
displayName: 'No tags',
filterName: 'has_any_tag',
bagKey: 'withoutTag',
filterValue: (item) => (item ? 'false' : null),
},
category: {
displayName: 'Category',
filterName: 'category_is',
bagKey: 'category',
displayValue: (item) => Category.getDisplayName(item),
filterValue: (item) => Category.getDisplayName(item),
},
exceptCategory: {
displayName: ' -Category',
filterName: '-category_is',
bagKey: 'excludedCategory',
displayValue: (item) => Category.getDisplayName(item),
filterValue: (item) => Category.getDisplayName(item),
},
noCategory: {
displayName: 'No category',
filterName: 'has_any_category',
bagKey: 'withoutCategory',
filterValue: (item) => (item ? 'false' : null),
},
budget: {
displayName: 'Budget',
filterName: 'budget_is',
bagKey: 'budget',
displayValue: (item) => Budget.getDisplayName(item),
filterValue: (item) => Budget.getDisplayName(item),
},
noBudget: {
displayName: 'No budget',
filterName: 'has_any_budget',
bagKey: 'withoutBudget',
filterValue: (item) => (item ? 'false' : null),
},
account: {
displayName: 'Account',
filterName: 'account_id',
bagKey: 'account',
displayValue: (item) => Account.getDisplayName(item),
filterValue: (item) => item?.id,
},
exceptAccount: {
displayName: '- Account',
filterName: '-account_id',
bagKey: 'excludedAccount',
displayValue: (item) => Account.getDisplayName(item),
filterValue: (item) => item?.id,
},
amountMore: {
displayName: 'Amount >',
filterName: 'more',
bagKey: 'amountStart',
},
amountLess: {
displayName: 'Amount <',
filterName: 'less',
bagKey: 'amountEnd',
},
dateAfter: {
displayName: 'Date >',
filterName: 'date_after',
bagKey: 'dateStart',
displayValue: (item) => DateUtils.dateToUI(item),
filterValue: (item) => DateUtils.dateToString(item)
},
dateBefore: {
displayName: 'Date <',
filterName: 'date_before',
bagKey: 'dateEnd',
displayValue: (item) => DateUtils.dateToUI(item),
filterValue: (item) => DateUtils.dateToString(item)
},
},



getFiltersFromURL() {
let dataStore = useDataStore()
const route = useRoute()

return {
id: get(route.query, 'id'),
tag: dataStore.tagDictionaryById[get(route.query, 'tag_id')],
excludedTag: dataStore.tagDictionaryById[get(route.query, 'excluded_tag_id')],
transactionType: Object.values(Transaction.types).find((item) => item.code === get(route.query, 'type')),
category: dataStore.categoryDictionary[get(route.query, 'category_id')],
budget: dataStore.budgetDictionary[get(route.query, 'budget_id')],
excludedCategory: dataStore.categoryDictionary[get(route.query, 'excluded_category_id')],
// account: dataStore.accountDictionary[get(route.query, 'account_id')],
account: this.getFilterValueFromDictionary(get(route.query, 'account_id'), dataStore.accountDictionary),
excludedAccount: dataStore.accountDictionary[get(route.query, 'excluded_account_id')],
description: get(route.query, 'description'),
dateStart: DateUtils.stringToDate(get(route.query, 'date_start')),
dateEnd: DateUtils.stringToDate(get(route.query, 'date_end')),
amountStart: get(route.query, 'amount_start'),
amountEnd: get(route.query, 'amount_end'),
withoutTag: get(route.query, 'without_tag'),
withoutBudget: get(route.query, 'without_budget'),
withoutCategory: get(route.query, 'without_category'),
}
},


getActiveFilters(filterBag) {
return Object.values(this.filters)
.map((item) => {
let value = get(filterBag, item.bagKey)
if (!value) {
return null
}
let displayValue = item.displayValue ? (isArray(value) ? value.map((singleValue) => item.displayValue(singleValue)) : item.displayValue(value)) : value
let filterValue = item.filterValue ? (isArray(value) ? value.map((singleValue) => item.filterValue(singleValue)) : item.filterValue(value)) : value

return {
...item,
displayValue,
filterValue,
}
})
.filter((item) => !!item?.filterValue)
.map((item) => ({
display: `${item.displayName}: ${item.displayValue}`,
filter: `${item.filterName}:${item.filterValue}`,
}))
},

getFilterValueFromDictionary(value, dictionary) {
return value ? value.split(',').map((item) => dictionary[item]) : null
},
}

0 comments on commit ce8ab72

Please sign in to comment.