diff --git a/src/views/desktop/transactions/ListPage.vue b/src/views/desktop/transactions/ListPage.vue
index b74ea2a4..056d7575 100644
--- a/src/views/desktop/transactions/ListPage.vue
+++ b/src/views/desktop/transactions/ListPage.vue
@@ -41,7 +41,18 @@
{{ $t('Transaction List') }}
{{ $t('Add') }}
+ :disabled="loading || !canAddTransaction" @click="add">
+ {{ $t('Add') }}
+
+
+
+
+
+
@@ -516,11 +527,13 @@ import { useAccountsStore } from '@/stores/account.js';
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
import { useTransactionTagsStore } from '@/stores/transactionTag.js';
import { useTransactionsStore } from '@/stores/transaction.js';
+import { useTransactionTemplatesStore } from '@/stores/transactionTemplate.js';
import numeralConstants from '@/consts/numeral.js';
import datetimeConstants from '@/consts/datetime.js';
import accountConstants from '@/consts/account.js';
import transactionConstants from '@/consts/transaction.js';
+import templateConstants from '@/consts/template.js';
import { isString, getNameByKeyValue } from '@/lib/common.js';
import logger from '@/lib/logger.js';
import {
@@ -562,6 +575,7 @@ import {
mdiArrowLeft,
mdiArrowRight,
mdiPound,
+ mdiTextBoxOutline,
mdiDotsVertical
} from '@mdi/js';
@@ -621,12 +635,13 @@ export default {
arrowLeft: mdiArrowLeft,
arrowRight: mdiArrowRight,
tag: mdiPound,
+ templates: mdiTextBoxOutline,
more: mdiDotsVertical
}
};
},
computed: {
- ...mapStores(useSettingsStore, useUserStore, useAccountsStore, useTransactionCategoriesStore, useTransactionTagsStore, useTransactionsStore),
+ ...mapStores(useSettingsStore, useUserStore, useAccountsStore, useTransactionCategoriesStore, useTransactionTagsStore, useTransactionsStore, useTransactionTemplatesStore),
defaultCurrency() {
return getUnifiedSelectedAccountsCurrencyOrDefaultCurrency(this.allAccounts, this.queryAllFilterAccountIds, this.userStore.currentUserDefaultCurrency);
},
@@ -907,6 +922,10 @@ export default {
allAvailableTagsCount() {
return this.transactionTagsStore.allAvailableTagsCount;
},
+ allTransactionTemplates() {
+ const allVisibleTemplates = this.transactionTemplatesStore.allVisibleTemplates;
+ return allVisibleTemplates[templateConstants.allTemplateTypes.Normal] || [];
+ },
recentMonthDateRanges() {
return this.$locale.getAllRecentMonthDateRanges(this.userStore, true, true);
},
@@ -992,6 +1011,11 @@ export default {
this.currentPage = 1;
this.reload(false);
+
+ this.transactionTemplatesStore.loadAllTemplates({
+ templateType: templateConstants.allTemplateTypes.Normal,
+ force: false
+ });
},
reload(force) {
const self = this;
@@ -1307,14 +1331,15 @@ export default {
this.$router.push(this.getFilterLinkUrl());
}
},
- add() {
+ add(template) {
const self = this;
self.$refs.editDialog.open({
type: self.query.type,
categoryId: self.queryAllFilterCategoryIdsCount === 1 ? self.query.categoryIds : '',
accountId: self.queryAllFilterAccountIdsCount === 1 ? self.query.accountIds : '',
- tagIds: self.query.tagIds || ''
+ tagIds: self.query.tagIds || '',
+ template: template
}).then(result => {
if (result && result.message) {
self.$refs.snackbar.showMessage(result.message);
diff --git a/src/views/desktop/transactions/list/dialogs/EditDialog.vue b/src/views/desktop/transactions/list/dialogs/EditDialog.vue
index 3b141562..aab4e0dc 100644
--- a/src/views/desktop/transactions/list/dialogs/EditDialog.vue
+++ b/src/views/desktop/transactions/list/dialogs/EditDialog.vue
@@ -669,6 +669,10 @@ export default {
self.mode = 'add';
self.editId = null;
+ if (options.template) {
+ self.setTransaction(options.template, options, false, false);
+ }
+
if (self.settingsStore.appSettings.autoGetCurrentGeoLocation
&& !self.geoLocationStatus && !self.transaction.geoLocation) {
self.updateGeoLocation(false);
diff --git a/src/views/mobile/HomePage.vue b/src/views/mobile/HomePage.vue
index ad82bf1e..4afe6ce8 100644
--- a/src/views/mobile/HomePage.vue
+++ b/src/views/mobile/HomePage.vue
@@ -172,7 +172,7 @@
{{ $t('Accounts') }}
-
+
@@ -184,6 +184,19 @@
{{ $t('Settings') }}
+
+
@@ -191,19 +204,25 @@
import { mapStores } from 'pinia';
import { useSettingsStore } from '@/stores/setting.js';
import { useUserStore } from '@/stores/user.js';
+import { useTransactionTemplatesStore } from '@/stores/transactionTemplate.js';
import { useOverviewStore } from '@/stores/overview.js';
import datetimeConstants from '@/consts/datetime.js';
+import templateConstants from '@/consts/template.js';
import { formatUnixTime } from '@/lib/datetime.js';
export default {
+ props: [
+ 'f7router'
+ ],
data() {
return {
- loading: true
+ loading: true,
+ showTransactionTemplatePopover: false
};
},
computed: {
- ...mapStores(useSettingsStore, useUserStore, useOverviewStore),
+ ...mapStores(useSettingsStore, useUserStore, useTransactionTemplatesStore, useOverviewStore),
showAmountInHomePage: {
get: function() {
return this.settingsStore.appSettings.showAmountInHomePage;
@@ -215,6 +234,10 @@ export default {
defaultCurrency() {
return this.userStore.currentUserDefaultCurrency;
},
+ allTransactionTemplates() {
+ const allTemplates = this.transactionTemplatesStore.allVisibleTemplates;
+ return allTemplates[templateConstants.allTemplateTypes.Normal] || [];
+ },
allDateRanges() {
return datetimeConstants.allDateRanges;
},
@@ -260,6 +283,11 @@ export default {
self.$toast(error.message || error);
}
});
+
+ self.transactionTemplatesStore.loadAllTemplates({
+ templateType: templateConstants.allTemplateTypes.Normal,
+ force: false
+ });
}
},
methods: {
@@ -292,6 +320,16 @@ export default {
}
});
},
+ addTransaction(template) {
+ if (template && template.id) {
+ this.f7router.navigate('/transaction/add?templateId=' + template.id);
+ }
+ },
+ openTransactionTemplatePopover() {
+ if (this.allTransactionTemplates && this.allTransactionTemplates.length) {
+ this.showTransactionTemplatePopover = true;
+ }
+ },
getDisplayCurrency(value, currencyCode) {
return this.$locale.formatAmountWithCurrency(this.settingsStore, this.userStore, value, currencyCode);
},
@@ -387,4 +425,9 @@ export default {
height: var(--ebk-big-icon-button-size);
line-height: var(--ebk-big-icon-button-size);
}
+
+.template-popover-menu .popover-inner{
+ max-height: 400px;
+ overflow-y: auto;
+}
diff --git a/src/views/mobile/transactions/EditPage.vue b/src/views/mobile/transactions/EditPage.vue
index fe391220..b5aa256a 100644
--- a/src/views/mobile/transactions/EditPage.vue
+++ b/src/views/mobile/transactions/EditPage.vue
@@ -355,10 +355,12 @@ import { useAccountsStore } from '@/stores/account.js';
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
import { useTransactionTagsStore } from '@/stores/transactionTag.js';
import { useTransactionsStore } from '@/stores/transaction.js';
+import { useTransactionTemplatesStore } from '@/stores/transactionTemplate.js';
import { useExchangeRatesStore } from '@/stores/exchangeRates.js';
import categoryConstants from '@/consts/category.js';
import transactionConstants from '@/consts/transaction.js';
+import templateConstants from '@/consts/template.js';
import logger from '@/lib/logger.js';
import {
getNameByKeyValue
@@ -413,7 +415,7 @@ export default {
};
},
computed: {
- ...mapStores(useSettingsStore, useUserStore, useAccountsStore, useTransactionCategoriesStore, useTransactionTagsStore, useTransactionsStore, useExchangeRatesStore),
+ ...mapStores(useSettingsStore, useUserStore, useAccountsStore, useTransactionCategoriesStore, useTransactionTagsStore, useTransactionsStore, useTransactionTemplatesStore, useExchangeRatesStore),
title() {
if (this.mode === 'add') {
return 'Add Transaction';
@@ -654,7 +656,8 @@ export default {
const promises = [
self.accountsStore.loadAllAccounts({ force: false }),
self.transactionCategoriesStore.loadAllCategories({ force: false }),
- self.transactionTagsStore.loadAllTags({ force: false })
+ self.transactionTagsStore.loadAllTags({ force: false }),
+ self.transactionTemplatesStore.loadAllTemplates({ force: false, templateType: templateConstants.allTemplateTypes.Normal })
];
if (query.id) {
@@ -676,15 +679,23 @@ export default {
}
Promise.all(promises).then(function (responses) {
- if (query.id && !responses[3]) {
+ if (query.id && !responses[4]) {
self.$toast('Unable to retrieve transaction');
self.loadingError = 'Unable to retrieve transaction';
return;
}
+ let fromTransaction = null;
+
+ if (query.id) {
+ fromTransaction = responses[4];
+ } else if (query.templateId && self.transactionTemplatesStore.allTransactionTemplatesMap && self.transactionTemplatesStore.allTransactionTemplatesMap[templateConstants.allTemplateTypes.Normal]) {
+ fromTransaction = self.transactionTemplatesStore.allTransactionTemplatesMap[templateConstants.allTemplateTypes.Normal][query.templateId];
+ }
+
setTransactionModelByTransaction(
self.transaction,
- query.id ? responses[3] : null,
+ fromTransaction,
self.allCategories,
self.allCategoriesMap,
self.allVisibleAccounts,