From 26d77de67affeddf58a32bee81beb7ab945af0a5 Mon Sep 17 00:00:00 2001 From: MaysWind Date: Sun, 21 Jul 2024 23:36:16 +0800 Subject: [PATCH] add transaction tag filter to frontend --- src/lib/common.js | 42 +++ src/lib/services.js | 8 +- src/lib/transaction.js | 18 +- src/locales/en.js | 2 + src/locales/zh_Hans.js | 2 + src/router/desktop.js | 1 + src/router/mobile.js | 6 + src/stores/transaction.js | 51 ++++ src/stores/transactionTag.js | 3 + .../TransactionTagFilterSettingsCard.vue | 284 ++++++++++++++++++ src/views/desktop/transactions/ListPage.vue | 133 +++++++- .../transactions/list/dialogs/EditDialog.vue | 7 +- .../TransactionTagFilterSettingsPage.vue | 255 ++++++++++++++++ src/views/mobile/transactions/EditPage.vue | 7 +- src/views/mobile/transactions/ListPage.vue | 69 ++++- 15 files changed, 874 insertions(+), 14 deletions(-) create mode 100644 src/views/desktop/common/cards/TransactionTagFilterSettingsCard.vue create mode 100644 src/views/mobile/settings/TransactionTagFilterSettingsPage.vue diff --git a/src/lib/common.js b/src/lib/common.js index 94dd3396..c526677b 100644 --- a/src/lib/common.js +++ b/src/lib/common.js @@ -425,6 +425,48 @@ export function categorizedArrayToPlainArray(object) { return ret; } +export function selectAll(filterItemIds, allItemsMap) { + for (let itemId in filterItemIds) { + if (!Object.prototype.hasOwnProperty.call(filterItemIds, itemId)) { + continue; + } + + const item = allItemsMap[itemId]; + + if (item) { + filterItemIds[item.id] = false; + } + } +} + +export function selectNone(filterItemIds, allItemsMap) { + for (let itemId in filterItemIds) { + if (!Object.prototype.hasOwnProperty.call(filterItemIds, itemId)) { + continue; + } + + const item = allItemsMap[itemId]; + + if (item) { + filterItemIds[item.id] = true; + } + } +} + +export function selectInvert(filterItemIds, allItemsMap) { + for (let itemId in filterItemIds) { + if (!Object.prototype.hasOwnProperty.call(filterItemIds, itemId)) { + continue; + } + + const item = allItemsMap[itemId]; + + if (item) { + filterItemIds[item.id] = !filterItemIds[item.id]; + } + } +} + export function isPrimaryItemHasSecondaryValue(primaryItem, primarySubItemsField, secondaryValueField, secondaryValue) { for (let i = 0; i < primaryItem[primarySubItemsField].length; i++) { const secondaryItem = primaryItem[primarySubItemsField][i]; diff --git a/src/lib/services.js b/src/lib/services.js index 4510eec0..a04a562a 100644 --- a/src/lib/services.js +++ b/src/lib/services.js @@ -282,15 +282,15 @@ export default { id }); }, - getTransactions: ({ maxTime, minTime, count, page, withCount, type, categoryIds, accountIds, amountFilter, keyword }) => { + getTransactions: ({ maxTime, minTime, count, page, withCount, type, categoryIds, accountIds, tagIds, amountFilter, keyword }) => { amountFilter = encodeURIComponent(amountFilter); keyword = encodeURIComponent(keyword); - return axios.get(`v1/transactions/list.json?max_time=${maxTime}&min_time=${minTime}&type=${type}&category_ids=${categoryIds}&account_ids=${accountIds}&amount_filter=${amountFilter}&keyword=${keyword}&count=${count}&page=${page}&with_count=${withCount}&trim_account=true&trim_category=true&trim_tag=true`); + return axios.get(`v1/transactions/list.json?max_time=${maxTime}&min_time=${minTime}&type=${type}&category_ids=${categoryIds}&account_ids=${accountIds}&tag_ids=${tagIds}&amount_filter=${amountFilter}&keyword=${keyword}&count=${count}&page=${page}&with_count=${withCount}&trim_account=true&trim_category=true&trim_tag=true`); }, - getAllTransactionsByMonth: ({ year, month, type, categoryIds, accountIds, amountFilter, keyword }) => { + getAllTransactionsByMonth: ({ year, month, type, categoryIds, accountIds, tagIds, amountFilter, keyword }) => { amountFilter = encodeURIComponent(amountFilter); keyword = encodeURIComponent(keyword); - return axios.get(`v1/transactions/list/by_month.json?year=${year}&month=${month}&type=${type}&category_ids=${categoryIds}&account_ids=${accountIds}&amount_filter=${amountFilter}&keyword=${keyword}&trim_account=true&trim_category=true&trim_tag=true`); + return axios.get(`v1/transactions/list/by_month.json?year=${year}&month=${month}&type=${type}&category_ids=${categoryIds}&account_ids=${accountIds}&tag_ids=${tagIds}&amount_filter=${amountFilter}&keyword=${keyword}&trim_account=true&trim_category=true&trim_tag=true`); }, getTransactionStatistics: ({ startTime, endTime, useTransactionTimezone }) => { const queryParams = []; diff --git a/src/lib/transaction.js b/src/lib/transaction.js index 22a8761e..2ae494e2 100644 --- a/src/lib/transaction.js +++ b/src/lib/transaction.js @@ -22,7 +22,7 @@ function getDisplayAmount(amount, currency, hideAmount, formatAmountWithCurrency return formatAmountWithCurrencyFunc(amount, currency); } -export function setTransactionModelByTransaction(transaction, transaction2, allCategories, allCategoriesMap, allVisibleAccounts, allAccountsMap, defaultAccountId, options, setContextData, convertContextTime) { +export function setTransactionModelByTransaction(transaction, transaction2, allCategories, allCategoriesMap, allVisibleAccounts, allAccountsMap, allTagsMap, defaultAccountId, options, setContextData, convertContextTime) { if ((!options.type || options.type === '0') && options.categoryId && options.categoryId !== '0' && allCategoriesMap[options.categoryId]) { const category = allCategoriesMap[options.categoryId]; const type = categoryTypeToTransactionType(category.type); @@ -105,6 +105,22 @@ export function setTransactionModelByTransaction(transaction, transaction2, allC } } + if (allTagsMap && options.tagIds) { + const tagIds = options.tagIds.split(','); + const finalTagIds = []; + + for (let i = 0; i < tagIds.length; i++) { + const tagId = tagIds[i]; + const tag = allTagsMap[tagId]; + + if (tag && !tag.hidden) { + finalTagIds.push(tag.id); + } + } + + transaction.tagIds = finalTagIds; + } + if (transaction2) { if (setContextData) { transaction.id = transaction2.id; diff --git a/src/locales/en.js b/src/locales/en.js index 47ecddc9..bdc39f5f 100644 --- a/src/locales/en.js +++ b/src/locales/en.js @@ -1025,6 +1025,7 @@ export default { 'Multiple Accounts': 'Multiple Accounts', 'Source Account': 'Source Account', 'Destination Account': 'Destination Account', + 'Multiple Tags': 'Multiple Tags', 'Transaction Time': 'Transaction Time', 'Transaction Timezone': 'Transaction Timezone', 'Same time as default timezone': 'Same time as default timezone', @@ -1098,6 +1099,7 @@ export default { 'Sort by Name': 'Sort by Name', 'Filter Accounts': 'Filter Accounts', 'Filter Transaction Categories': 'Filter Transaction Categories', + 'Filter Transaction Tags': 'Filter Transaction Tags', 'User Settings': 'User Settings', 'User Profile': 'User Profile', 'Language': 'Language', diff --git a/src/locales/zh_Hans.js b/src/locales/zh_Hans.js index 4fe3efed..ad4b43f6 100644 --- a/src/locales/zh_Hans.js +++ b/src/locales/zh_Hans.js @@ -1025,6 +1025,7 @@ export default { 'Multiple Accounts': '多个账户', 'Source Account': '来源账户', 'Destination Account': '目标账户', + 'Multiple Tags': '多个标签', 'Transaction Time': '交易时间', 'Transaction Timezone': '交易时区', 'Same time as default timezone': '与默认时区时间相同', @@ -1098,6 +1099,7 @@ export default { 'Sort by Name': '按名称排序', 'Filter Accounts': '过滤账户', 'Filter Transaction Categories': '过滤交易类型', + 'Filter Transaction Tags': '过滤交易标签', 'User Settings': '用户设置', 'User Profile': '用户信息', 'Language': '语言', diff --git a/src/router/desktop.js b/src/router/desktop.js index d0a2091b..6c571bd1 100644 --- a/src/router/desktop.js +++ b/src/router/desktop.js @@ -100,6 +100,7 @@ const router = createRouter({ initType: route.query.type, initCategoryIds: route.query.categoryIds, initAccountIds: route.query.accountIds, + initTagIds: route.query.tagIds, initAmountFilter: route.query.amountFilter, initKeyword: route.query.keyword }) diff --git a/src/router/mobile.js b/src/router/mobile.js index 385b7939..41687770 100644 --- a/src/router/mobile.js +++ b/src/router/mobile.js @@ -19,6 +19,7 @@ import TextSizeSettingsPage from '@/views/mobile/settings/TextSizeSettingsPage.v import PageSettingsPage from '@/views/mobile/settings/PageSettingsPage.vue'; import AccountFilterSettingsPage from '@/views/mobile/settings/AccountFilterSettingsPage.vue'; import CategoryFilterSettingsPage from '@/views/mobile/settings/CategoryFilterSettingsPage.vue'; +import TransactionTagFilterSettingsPage from '@/views/mobile/settings/TransactionTagFilterSettingsPage.vue'; import SettingsPage from '@/views/mobile/SettingsPage.vue'; import ApplicationLockPage from '@/views/mobile/ApplicationLockPage.vue'; @@ -209,6 +210,11 @@ const routes = [ async: asyncResolve(CategoryFilterSettingsPage), beforeEnter: [checkLogin] }, + { + path: '/settings/filter/tag', + async: asyncResolve(TransactionTagFilterSettingsPage), + beforeEnter: [checkLogin] + }, { path: '/settings/page', async: asyncResolve(PageSettingsPage), diff --git a/src/stores/transaction.js b/src/stores/transaction.js index 7dd2409b..2f9343eb 100644 --- a/src/stores/transaction.js +++ b/src/stores/transaction.js @@ -284,6 +284,7 @@ export const useTransactionsStore = defineStore('transactions', { type: 0, categoryIds: '', accountIds: '', + tagIds: '', amountFilter: '', keyword: '' }, @@ -324,6 +325,22 @@ export const useTransactionsStore = defineStore('transactions', { return ret; }, + allFilterTagIds(state) { + if (!state.transactionsFilter.tagIds) { + return {}; + } + + const allTagIds = state.transactionsFilter.tagIds.split(','); + const ret = {}; + + for (let i = 0; i < allTagIds.length; i++) { + if (allTagIds[i]) { + ret[allTagIds[i]] = true; + } + } + + return ret; + }, allFilterCategoryIdsCount(state) { if (!state.transactionsFilter.categoryIds) { return 0; @@ -356,6 +373,22 @@ export const useTransactionsStore = defineStore('transactions', { return count; }, + allFilterTagIdsCount(state) { + if (!state.transactionsFilter.tagIds) { + return 0; + } + + const allTagIds = state.transactionsFilter.tagIds.split(','); + let count = 0; + + for (let i = 0; i < allTagIds.length; i++) { + if (allTagIds[i]) { + count++; + } + } + + return count; + }, noTransaction(state) { for (let i = 0; i < state.transactions.length; i++) { const transactionMonthList = state.transactions[i]; @@ -444,6 +477,7 @@ export const useTransactionsStore = defineStore('transactions', { this.transactionsFilter.type = 0; this.transactionsFilter.categoryIds = ''; this.transactionsFilter.accountIds = ''; + this.transactionsFilter.tagIds = ''; this.transactionsFilter.amountFilter = ''; this.transactionsFilter.keyword = ''; this.transactions = []; @@ -492,6 +526,12 @@ export const useTransactionsStore = defineStore('transactions', { this.transactionsFilter.accountIds = ''; } + if (filter && isString(filter.tagIds)) { + this.transactionsFilter.tagIds = filter.tagIds; + } else { + this.transactionsFilter.tagIds = ''; + } + if (filter && isString(filter.amountFilter)) { this.transactionsFilter.amountFilter = filter.amountFilter; } else { @@ -537,6 +577,11 @@ export const useTransactionsStore = defineStore('transactions', { changed = true; } + if (filter && isString(filter.tagIds) && this.transactionsFilter.tagIds !== filter.tagIds) { + this.transactionsFilter.tagIds = filter.tagIds; + changed = true; + } + if (filter && isString(filter.amountFilter) && this.transactionsFilter.amountFilter !== filter.amountFilter) { this.transactionsFilter.amountFilter = filter.amountFilter; changed = true; @@ -564,6 +609,10 @@ export const useTransactionsStore = defineStore('transactions', { querys.push('categoryIds=' + this.transactionsFilter.categoryIds); } + if (this.transactionsFilter.tagIds) { + querys.push('tagIds=' + this.transactionsFilter.tagIds); + } + querys.push('dateType=' + this.transactionsFilter.dateType); if (this.transactionsFilter.dateType === datetimeConstants.allDateRanges.Custom.type) { @@ -603,6 +652,7 @@ export const useTransactionsStore = defineStore('transactions', { type: self.transactionsFilter.type, categoryIds: self.transactionsFilter.categoryIds, accountIds: self.transactionsFilter.accountIds, + tagIds: self.transactionsFilter.tagIds, amountFilter: self.transactionsFilter.amountFilter, keyword: self.transactionsFilter.keyword }).then(response => { @@ -678,6 +728,7 @@ export const useTransactionsStore = defineStore('transactions', { type: self.transactionsFilter.type, categoryIds: self.transactionsFilter.categoryIds, accountIds: self.transactionsFilter.accountIds, + tagIds: self.transactionsFilter.tagIds, amountFilter: self.transactionsFilter.amountFilter, keyword: self.transactionsFilter.keyword }).then(response => { diff --git a/src/stores/transactionTag.js b/src/stores/transactionTag.js index 3d2503c3..713b8d97 100644 --- a/src/stores/transactionTag.js +++ b/src/stores/transactionTag.js @@ -72,6 +72,9 @@ export const useTransactionTagsStore = defineStore('transactionTags', { } return allVisibleTags; + }, + allVisibleTagsCount(state) { + return state.allTransactionTags.length; } }, actions: { diff --git a/src/views/desktop/common/cards/TransactionTagFilterSettingsCard.vue b/src/views/desktop/common/cards/TransactionTagFilterSettingsCard.vue new file mode 100644 index 00000000..95a21511 --- /dev/null +++ b/src/views/desktop/common/cards/TransactionTagFilterSettingsCard.vue @@ -0,0 +1,284 @@ + + + + + diff --git a/src/views/desktop/transactions/ListPage.vue b/src/views/desktop/transactions/ListPage.vue index 6472abcc..0a2e41aa 100644 --- a/src/views/desktop/transactions/ListPage.vue +++ b/src/views/desktop/transactions/ListPage.vue @@ -308,7 +308,61 @@ - {{ $t('Tags') }} + + + + + + +
+ + {{ $t('All') }} +
+
+
+ + +
+ + {{ $t('Multiple Tags') }} +
+
+
+ +
+
+ {{ $t('Description') }} @@ -427,6 +481,11 @@ @settings:change="changeMultipleCategoriesFilter" /> + + + + @@ -435,6 +494,7 @@ import EditDialog from './list/dialogs/EditDialog.vue'; import AccountFilterSettingsCard from '@/views/desktop/common/cards/AccountFilterSettingsCard.vue'; import CategoryFilterSettingsCard from '@/views/desktop/common/cards/CategoryFilterSettingsCard.vue'; +import TransactionTagFilterSettingsCard from '@/views/desktop/common/cards/TransactionTagFilterSettingsCard.vue'; import { useDisplay } from 'vuetify'; @@ -495,6 +555,7 @@ import { export default { components: { + TransactionTagFilterSettingsCard, EditDialog, AccountFilterSettingsCard, CategoryFilterSettingsCard @@ -506,6 +567,7 @@ export default { 'initType', 'initCategoryIds', 'initAccountIds', + 'initTagIds', 'initAmountFilter', 'initKeyword' ], @@ -533,6 +595,7 @@ export default { showCustomDateRangeDialog: false, showFilterAccountDialog: false, showFilterCategoryDialog: false, + showFilterTagDialog: false, icons: { search: mdiMagnify, check: mdiCheck, @@ -606,12 +669,18 @@ export default { queryAllFilterAccountIds() { return this.transactionsStore.allFilterAccountIds; }, + queryAllFilterTagIds() { + return this.transactionsStore.allFilterTagIds; + }, queryAllFilterCategoryIdsCount() { return this.transactionsStore.allFilterCategoryIdsCount; }, queryAllFilterAccountIdsCount() { return this.transactionsStore.allFilterAccountIdsCount; }, + queryAllFilterTagIdsCount() { + return this.transactionsStore.allFilterTagIdsCount; + }, queryAllSelectedFilterCategoryIds() { if (this.queryAllFilterCategoryIdsCount === 0) { return ''; @@ -630,6 +699,15 @@ export default { return 'multiple'; } }, + queryAllSelectedFilterTagIds() { + if (this.queryAllFilterTagIdsCount === 0) { + return ''; + } else if (this.queryAllFilterTagIdsCount === 1) { + return this.query.tagIds; + } else { // this.queryAllFilterTagIdsCount > 1 + return 'multiple'; + } + }, queryCategoryName() { if (this.queryAllFilterCategoryIdsCount > 1) { return this.$t('Multiple Categories'); @@ -644,6 +722,13 @@ export default { return getNameByKeyValue(this.allAccounts, this.query.accountIds, null, 'name', this.$t('Account')); }, + queryTagName() { + if (this.queryAllFilterTagIdsCount > 1) { + return this.$t('Multiple Tags'); + } + + return getNameByKeyValue(this.allTransactionTags, this.query.tagIds, null, 'name', this.$t('Tags')); + }, queryAmount() { if (!this.query.amountFilter) { return ''; @@ -802,6 +887,9 @@ export default { allTransactionTags() { return this.transactionTagsStore.allTransactionTagsMap; }, + allVisibleTagsCount() { + return this.transactionTagsStore.allVisibleTagsCount; + }, recentMonthDateRanges() { return this.$locale.getAllRecentMonthDateRanges(this.userStore, true, true); }, @@ -820,6 +908,7 @@ export default { type: this.initType, categoryIds: this.initCategoryIds, accountIds: this.initAccountIds, + tagIds: this.initTagIds, amountFilter: this.initAmountFilter, keyword: this.initKeyword }); @@ -849,6 +938,7 @@ export default { type: to.query.type, categoryIds: to.query.categoryIds, accountIds: to.query.accountIds, + tagIds: to.query.tagIds, amountFilter: to.query.amountFilter, keyword: to.query.keyword }); @@ -875,6 +965,7 @@ export default { type: parseInt(query.type) > 0 ? parseInt(query.type) : undefined, categoryIds: query.categoryIds, accountIds: query.accountIds, + tagIds: query.tagIds, amountFilter: query.amountFilter || '', keyword: query.keyword || '' }); @@ -1156,6 +1247,32 @@ export default { this.$router.push(this.getFilterLinkUrl()); } }, + changeTagFilter(tagIds) { + if (this.query.tagIds === tagIds) { + return; + } + + const changed = this.transactionsStore.updateTransactionListFilter({ + tagIds: tagIds + }); + + if (changed) { + this.loading = true; + this.currentPageTransactions = []; + this.transactionsStore.clearTransactions(); + this.$router.push(this.getFilterLinkUrl()); + } + }, + changeMultipleTagsFilter(changed) { + this.showFilterTagDialog = false; + + if (changed) { + this.loading = true; + this.currentPageTransactions = []; + this.transactionsStore.clearTransactions(); + this.$router.push(this.getFilterLinkUrl()); + } + }, changeKeywordFilter(keyword) { if (this.query.keyword === keyword) { return; @@ -1179,7 +1296,8 @@ export default { self.$refs.editDialog.open({ type: self.query.type, categoryId: self.queryAllFilterCategoryIdsCount === 1 ? self.query.categoryIds : '', - accountId: self.queryAllFilterAccountIdsCount === 1 ? self.query.accountIds : '' + accountId: self.queryAllFilterAccountIdsCount === 1 ? self.query.accountIds : '', + tagIds: self.query.tagIds || '' }).then(result => { if (result && result.message) { self.$refs.snackbar.showMessage(result.message); @@ -1252,6 +1370,11 @@ export default { this.scrollMenuToSelectedItem(this.$refs.accountFilterMenu); } }, + scrollTagMenuToSelectedItem(opened) { + if (opened) { + this.scrollMenuToSelectedItem(this.$refs.tagFilterMenu); + } + }, scrollMenuToSelectedItem(menu) { this.$nextTick(() => { scrollToSelectedItem(menu.contentEl, 'div.v-list', 'div.v-list-item.list-item-selected'); @@ -1375,7 +1498,7 @@ export default { } .transaction-table .transaction-table-column-tags { - width: 80px; + width: 90px; max-width: 300px; } @@ -1409,6 +1532,7 @@ export default { .transaction-category-menu .item-icon, .transaction-amount-menu .item-icon, .transaction-account-menu .item-icon, +.transaction-tag-menu .item-icon, .transaction-table .item-icon { padding-bottom: 3px; } @@ -1424,7 +1548,8 @@ export default { .transaction-category-menu .has-children-item-selected span, .transaction-category-menu .item-in-multiple-selection span, -.transaction-account-menu .item-in-multiple-selection span { +.transaction-account-menu .item-in-multiple-selection span, +.transaction-tag-menu .item-in-multiple-selection span { font-weight: bold; } diff --git a/src/views/desktop/transactions/list/dialogs/EditDialog.vue b/src/views/desktop/transactions/list/dialogs/EditDialog.vue index 214e2ddd..7e31bb6d 100644 --- a/src/views/desktop/transactions/list/dialogs/EditDialog.vue +++ b/src/views/desktop/transactions/list/dialogs/EditDialog.vue @@ -488,6 +488,9 @@ export default { allTags() { return this.transactionTagsStore.allVisibleTags; }, + allTagsMap() { + return this.transactionTagsStore.allTransactionTagsMap; + }, hasAvailableExpenseCategories() { if (!this.allCategories || !this.allCategories[this.allCategoryTypes.Expense] || !this.allCategories[this.allCategoryTypes.Expense].length) { return false; @@ -847,11 +850,13 @@ export default { this.allCategoriesMap, this.allVisibleAccounts, this.allAccountsMap, + this.allTagsMap, this.defaultAccountId, { type: options.type, categoryId: options.categoryId, - accountId: options.accountId + accountId: options.accountId, + tagIds: options.tagIds }, setContextData, convertContextTime diff --git a/src/views/mobile/settings/TransactionTagFilterSettingsPage.vue b/src/views/mobile/settings/TransactionTagFilterSettingsPage.vue new file mode 100644 index 00000000..0fd4404e --- /dev/null +++ b/src/views/mobile/settings/TransactionTagFilterSettingsPage.vue @@ -0,0 +1,255 @@ + + + diff --git a/src/views/mobile/transactions/EditPage.vue b/src/views/mobile/transactions/EditPage.vue index 81cbeb39..d4b864ee 100644 --- a/src/views/mobile/transactions/EditPage.vue +++ b/src/views/mobile/transactions/EditPage.vue @@ -504,6 +504,9 @@ export default { allTags() { return this.transactionTagsStore.allTransactionTags; }, + allTagsMap() { + return this.transactionTagsStore.allTransactionTagsMap; + }, hasAvailableExpenseCategories() { if (!this.allCategories || !this.allCategories[this.allCategoryTypes.Expense] || !this.allCategories[this.allCategoryTypes.Expense].length) { return false; @@ -683,11 +686,13 @@ export default { self.allCategoriesMap, self.allVisibleAccounts, self.allAccountsMap, + self.allTagsMap, self.defaultAccountId, { type: query.type, categoryId: query.categoryId, - accountId: query.accountId + accountId: query.accountId, + tagIds: query.tagIds }, (self.mode === 'edit' || self.mode === 'view'), (self.mode === 'edit' || self.mode === 'view') diff --git a/src/views/mobile/transactions/ListPage.vue b/src/views/mobile/transactions/ListPage.vue index d87646d1..961970ff 100644 --- a/src/views/mobile/transactions/ListPage.vue +++ b/src/views/mobile/transactions/ListPage.vue @@ -11,7 +11,7 @@ - + @@ -42,7 +42,7 @@ {{ queryAccountName }} - + @@ -445,6 +445,36 @@ + + + + + + + + + + + + @@ -555,12 +585,18 @@ export default { queryAllFilterAccountIds() { return this.transactionsStore.allFilterAccountIds; }, + queryAllFilterTagIds() { + return this.transactionsStore.allFilterTagIds; + }, queryAllFilterCategoryIdsCount() { return this.transactionsStore.allFilterCategoryIdsCount; }, queryAllFilterAccountIdsCount() { return this.transactionsStore.allFilterAccountIdsCount; }, + queryAllFilterTagIdsCount() { + return this.transactionsStore.allFilterTagIdsCount; + }, queryCategoryName() { if (this.queryAllFilterCategoryIdsCount > 1) { return this.$t('Multiple Categories'); @@ -639,6 +675,9 @@ export default { allTransactionTags() { return this.transactionTagsStore.allTransactionTagsMap; }, + allVisibleTagsCount() { + return this.transactionTagsStore.allVisibleTagsCount; + }, allDateRanges() { return datetimeConstants.allDateRanges; }, @@ -674,7 +713,8 @@ export default { minTime: dateRange ? dateRange.minTime : undefined, type: parseInt(query.type) > 0 ? parseInt(query.type) : undefined, categoryIds: query.categoryIds, - accountIds: query.accountIds + accountIds: query.accountIds, + tagIds: query.tagIds }); this.reload(null); @@ -889,6 +929,21 @@ export default { this.reload(null); } }, + changeTagFilter(tagIds) { + if (this.query.tagIds === tagIds) { + return; + } + + const changed = this.transactionsStore.updateTransactionListFilter({ + tagIds: tagIds + }); + + this.showMorePopover = false; + + if (changed) { + this.reload(null); + } + }, changeAmountFilter(filterType) { if (this.query.amountFilter === filterType) { return; @@ -935,6 +990,9 @@ export default { filterMultipleAccounts() { this.f7router.navigate('/settings/filter/account?type=transactionListCurrent'); }, + filterMultipleTags() { + this.f7router.navigate('/settings/filter/tag?type=transactionListCurrent'); + }, duplicate(transaction) { this.f7router.navigate(`/transaction/add?id=${transaction.id}&type=${transaction.type}`); }, @@ -1170,6 +1228,11 @@ export default { text-overflow: ellipsis; } +.more-popover-menu .transaction-tag-name { + padding-right: 4px; + font-size: var(--f7-list-item-title-font-size); +} + .date-popover-menu .popover-inner, .category-popover-menu .popover-inner, .account-popover-menu .popover-inner,