diff --git a/package-lock.json b/package-lock.json index bf55955d..b80251c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11282,6 +11282,11 @@ "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", "dev": true }, + "vuex": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/vuex/-/vuex-3.6.0.tgz", + "integrity": "sha512-W74OO2vCJPs9/YjNjW8lLbj+jzT24waTo2KShI8jLvJW8OaIkgb3wuAMA7D+ZiUxDOx3ubwSZTaJBip9G8a3aQ==" + }, "watchpack": { "version": "1.7.4", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.4.tgz", diff --git a/package.json b/package.json index d75f0902..c1d31439 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,8 @@ "vue-i18n": "^8.22.1", "vue-i18n-filter": "^0.1.6", "vue-moment": "^4.1.0", - "vue-pincode-input": "^0.4.0" + "vue-pincode-input": "^0.4.0", + "vuex": "^3.6.0" }, "devDependencies": { "@vue/cli-plugin-babel": "~4.5.0", diff --git a/src/lib/utils.js b/src/lib/utils.js index 620d6447..476515d9 100644 --- a/src/lib/utils.js +++ b/src/lib/utils.js @@ -405,28 +405,6 @@ function getCategorizedAccounts(allAccounts) { return ret; } -function getAccountByAccountId(categorizedAccounts, accountId) { - for (let category in categorizedAccounts) { - if (!Object.prototype.hasOwnProperty.call(categorizedAccounts, category)) { - continue; - } - - if (!categorizedAccounts[category].accounts) { - continue; - } - - const accountList = categorizedAccounts[category].accounts; - - for (let i = 0; i < accountList.length; i++) { - if (accountList[i].id === accountId) { - return accountList[i]; - } - } - } - - return null; -} - function getAllFilteredAccountsBalance(categorizedAccounts, accountFilter) { const allAccountCategories = accountConstants.allCategories; const ret = []; @@ -514,6 +492,5 @@ export default { getCategoryInfo, getPlainAccounts, getCategorizedAccounts, - getAccountByAccountId, getAllFilteredAccountsBalance, }; diff --git a/src/locales/en.js b/src/locales/en.js index dab896ac..c3850e73 100644 --- a/src/locales/en.js +++ b/src/locales/en.js @@ -642,6 +642,8 @@ export default { 'Tag Title': 'Tag Title', 'No available tag': 'No available tag', 'Unable to get tag list': 'Unable to get tag list', + 'Unable to add tag': 'Unable to add tag', + 'Unable to save tag': 'Unable to save tag', 'Unable to move tag': 'Unable to move tag', 'Unable to hide this tag': 'Unable to hide this tag', 'Unable to unhide this tag': 'Unable to unhide this tag', diff --git a/src/locales/zh_Hans.js b/src/locales/zh_Hans.js index adc723ba..5de3abea 100644 --- a/src/locales/zh_Hans.js +++ b/src/locales/zh_Hans.js @@ -642,6 +642,8 @@ export default { 'Tag Title': '标签标题', 'No available tag': '没有可用的标签', 'Unable to get tag list': '无法获取标签列表', + 'Unable to add tag': '无法添加标签', + 'Unable to save tag': '无法保存标签', 'Unable to move tag': '无法移动标签', 'Unable to hide this tag': '无法隐藏该标签', 'Unable to unhide this tag': '无法取消隐藏该标签', diff --git a/src/mobile-main.js b/src/mobile-main.js index fb9d5274..2e401d9c 100644 --- a/src/mobile-main.js +++ b/src/mobile-main.js @@ -1,4 +1,5 @@ import Vue from 'vue'; +import Vuex from 'vuex'; import VueI18n from 'vue-i18n'; import VueI18nFilter from 'vue-i18n-filter'; import Framework7 from 'framework7/framework7.esm.bundle.js'; @@ -30,6 +31,7 @@ import userstate from './lib/userstate.js'; import exchangeRates from './lib/exchangeRates.js'; import webauthn from './lib/webauthn.js'; import utils from './lib/utils.js'; +import stores from './store/index.js'; import itemFieldContentFilter from './filters/itemFieldContent.js'; import currencyFilter from './filters/currency.js'; import iconFilter from './filters/icon.js'; @@ -54,6 +56,7 @@ import InformationSheet from "./components/mobile/InformationSheet.vue"; import NumberPadSheet from "./components/mobile/NumberPadSheet.vue"; import App from './Mobile.vue'; +Vue.use(Vuex); Vue.use(VueI18n); Vue.use(VueI18nFilter); Vue.use(VueMoment, { moment }); @@ -72,6 +75,7 @@ Vue.component('InformationSheet', InformationSheet); Vue.component('NumberPadSheet', NumberPadSheet); Framework7.use(Framework7Vue); +const store = new Vuex.Store(stores); const i18n = new VueI18n(getI18nOptions()); Vue.prototype.$version = version.getVersion(); @@ -238,6 +242,7 @@ if (userstate.isUserLogined()) { new Vue({ el: '#app', i18n: i18n, + store: store, render: h => h(App), mounted: function () { const app = this.$f7; diff --git a/src/store/account.js b/src/store/account.js new file mode 100644 index 00000000..71d27b5d --- /dev/null +++ b/src/store/account.js @@ -0,0 +1,318 @@ +import services from '../lib/services.js'; +import logger from '../lib/logger.js'; + +import { + LOAD_ACCOUNT_LIST, + ADD_ACCOUNT_TO_ACCOUNT_LIST, + SAVE_ACCOUNT_IN_ACCOUNT_LIST, + CHANGE_ACCOUNT_DISPLAY_ORDER_IN_ACCOUNT_LIST, + UPDATE_ACCOUNT_VISIBILITY_IN_ACCOUNT_LIST, + REMOVE_ACCOUNT_FROM_ACCOUNT_LIST, + UPDATE_ACCOUNT_LIST_INVALID_STATE +} from './mutations.js'; + +function loadAllAccounts(context, { force }) { + if (!force && !context.state.accountListStateInvalid) { + return new Promise((resolve) => { + resolve(context.state.allAccounts); + }); + } + + return new Promise((resolve, reject) => { + services.getAllAccounts({ + visibleOnly: false + }).then(response => { + const data = response.data; + + if (!data || !data.success || !data.result) { + reject({ message: 'Unable to get account list' }); + return; + } + + context.commit(LOAD_ACCOUNT_LIST, data.result); + context.commit(UPDATE_ACCOUNT_LIST_INVALID_STATE, false); + + resolve(data.result); + }).catch(error => { + if (force) { + logger.error('failed to force load account list', error); + } else { + logger.error('failed to load account list', error); + } + + if (error.response && error.response.data && error.response.data.errorMessage) { + reject({ error: error.response.data }); + } else if (!error.processed) { + reject({ message: 'Unable to get account list' }); + } else { + reject(error); + } + }); + }); +} + +function getAccount(context, { accountId }) { + return new Promise((resolve, reject) => { + services.getAccount({ + id: accountId + }).then(response => { + const data = response.data; + + if (!data || !data.success || !data.result) { + reject({ message: 'Unable to get account' }); + return; + } + + resolve(data.result); + }).catch(error => { + logger.error('failed to load account info', error); + + if (error.response && error.response.data && error.response.data.errorMessage) { + reject({ error: error.response.data }); + } else if (!error.processed) { + reject({ message: 'Unable to get account' }); + } else { + reject(error); + } + }); + }); +} + +function saveAccount(context, { account }) { + return new Promise((resolve, reject) => { + let promise = null; + + if (!account.id) { + promise = services.addAccount(account); + } else { + promise = services.modifyAccount(account); + } + + promise.then(response => { + const data = response.data; + + if (!data || !data.success || !data.result) { + if (!account.id) { + reject({ message: 'Unable to add account' }); + } else { + reject({ message: 'Unable to save account' }); + } + return; + } + + if (!account.id) { + context.commit(ADD_ACCOUNT_TO_ACCOUNT_LIST, data.result); + } else { + context.commit(SAVE_ACCOUNT_IN_ACCOUNT_LIST, data.result); + } + + resolve(data.result); + }).catch(error => { + logger.error('failed to save account', error); + + if (error.response && error.response.data && error.response.data.errorMessage) { + reject({ error: error.response.data }); + } else if (!error.processed) { + if (!account.id) { + reject({ message: 'Unable to add account' }); + } else { + reject({ message: 'Unable to save account' }); + } + } else { + reject(error); + } + }); + }); +} + +function changeAccountDisplayOrder(context, { accountId, from, to }) { + const account = context.state.allAccountsMap[accountId]; + + return new Promise((resolve, reject) => { + if (!account || + !context.state.allCategorizedAccounts[account.category] || + !context.state.allCategorizedAccounts[account.category].accounts || + !context.state.allCategorizedAccounts[account.category].accounts[to]) { + reject({ message: 'Unable to move account' }); + return; + } + + context.commit(UPDATE_ACCOUNT_LIST_INVALID_STATE, true); + context.commit(CHANGE_ACCOUNT_DISPLAY_ORDER_IN_ACCOUNT_LIST, { + account: account, + from: from, + to: to + }); + + resolve(); + }); +} + +function updateAccountDisplayOrders(context) { + const newDisplayOrders = []; + + for (let category in context.state.allCategorizedAccounts) { + if (!Object.prototype.hasOwnProperty.call(context.state.allCategorizedAccounts, category)) { + continue; + } + + const accountList = context.state.allCategorizedAccounts[category].accounts; + + for (let i = 0; i < accountList.length; i++) { + newDisplayOrders.push({ + id: accountList[i].id, + displayOrder: i + 1 + }); + } + } + + return new Promise((resolve, reject) => { + services.moveAccount({ + newDisplayOrders: newDisplayOrders + }).then(response => { + const data = response.data; + + if (!data || !data.success || !data.result) { + reject({ message: 'Unable to move account' }); + return; + } + + context.commit(UPDATE_ACCOUNT_LIST_INVALID_STATE, false); + + resolve(data.result); + }).catch(error => { + logger.error('failed to save accounts display order', error); + + if (error.response && error.response.data && error.response.data.errorMessage) { + reject({ error: error.response.data }); + } else if (!error.processed) { + reject({ message: 'Unable to move account' }); + } else { + reject(error); + } + }); + }); +} + +function hideAccount(context, { account, hidden }) { + return new Promise((resolve, reject) => { + services.hideAccount({ + id: account.id, + hidden: hidden + }).then(response => { + const data = response.data; + + if (!data || !data.success || !data.result) { + if (hidden) { + reject({ message: 'Unable to hide this account' }); + } else { + reject({ message: 'Unable to unhide this account' }); + } + + return; + } + + context.commit(UPDATE_ACCOUNT_VISIBILITY_IN_ACCOUNT_LIST, { + account: account, + hidden: hidden + }); + + resolve(data.result); + }).catch(error => { + logger.error('failed to change account visibility', error); + + if (error.response && error.response.data && error.response.data.errorMessage) { + reject({ error: error.response.data }); + } else if (!error.processed) { + if (hidden) { + reject({ message: 'Unable to hide this account' }); + } else { + reject({ message: 'Unable to unhide this account' }); + } + } else { + reject(error); + } + }); + }); +} + +function deleteAccount(context, { account, beforeResolve }) { + return new Promise((resolve, reject) => { + services.deleteAccount({ + id: account.id + }).then(response => { + const data = response.data; + + if (!data || !data.success || !data.result) { + reject({ message: 'Unable to delete this account' }); + return; + } + + if (beforeResolve) { + beforeResolve(() => { + context.commit(REMOVE_ACCOUNT_FROM_ACCOUNT_LIST, account); + }); + } else { + context.commit(REMOVE_ACCOUNT_FROM_ACCOUNT_LIST, account); + } + + resolve(data.result); + }).catch(error => { + logger.error('failed to delete account', error); + + if (error.response && error.response.data && error.response.data.errorMessage) { + reject({ error: error.response.data }); + } else if (!error.processed) { + reject({ message: 'Unable to delete this account' }); + } else { + reject(error); + } + }); + }); +} + +function allAvailableAccountsCount(state) { + let allAccountCount = 0; + + for (let category in state.allCategorizedAccounts) { + if (!Object.prototype.hasOwnProperty.call(state.allCategorizedAccounts, category)) { + continue; + } + + allAccountCount += state.allCategorizedAccounts[category].accounts.length; + } + + return allAccountCount; +} + +function allVisibleAccountsCount(state) { + let shownAccountCount = 0; + + for (let category in state.allCategorizedAccounts) { + if (!Object.prototype.hasOwnProperty.call(state.allCategorizedAccounts, category)) { + continue; + } + + const accountList = state.allCategorizedAccounts[category].accounts; + + for (let i = 0; i < accountList.length; i++) { + if (!accountList[i].hidden) { + shownAccountCount++; + } + } + } + + return shownAccountCount; +} + +export default { + loadAllAccounts, + getAccount, + saveAccount, + changeAccountDisplayOrder, + updateAccountDisplayOrders, + hideAccount, + deleteAccount, + allAvailableAccountsCount, + allVisibleAccountsCount, +} diff --git a/src/store/index.js b/src/store/index.js new file mode 100644 index 00000000..90f2058f --- /dev/null +++ b/src/store/index.js @@ -0,0 +1,231 @@ +import utils from "../lib/utils.js"; + +import { + LOAD_ACCOUNT_LIST, + ADD_ACCOUNT_TO_ACCOUNT_LIST, + SAVE_ACCOUNT_IN_ACCOUNT_LIST, + CHANGE_ACCOUNT_DISPLAY_ORDER_IN_ACCOUNT_LIST, + UPDATE_ACCOUNT_VISIBILITY_IN_ACCOUNT_LIST, + REMOVE_ACCOUNT_FROM_ACCOUNT_LIST, + UPDATE_ACCOUNT_LIST_INVALID_STATE, + + LOAD_TRANSACTION_CATEGORY_LIST, + + LOAD_TRANSACTION_TAG_LIST, + ADD_TAG_TO_TRANSACTION_TAG_LIST, + SAVE_TAG_IN_TRANSACTION_TAG_LIST, + CHANGE_TAG_DISPLAY_ORDER_IN_TRANSACTION_TAG_LIST, + UPDATE_TAG_VISIBILITY_IN_TRANSACTION_TAG_LIST, + REMOVE_TAG_FROM_TRANSACTION_TAG_LIST, + UPDATE_TRANSACTION_TAG_LIST_INVALID_STATE +} from './mutations.js'; + +import account from './account.js'; +import transactionTag from './transactionTag.js'; + +const stores = { + strict: process.env.NODE_ENV !== 'production', + state: { + allAccounts: [], + allAccountsMap: {}, + allCategorizedAccounts: {}, + accountListStateInvalid: true, + allTransactionCategories: [], + allTransactionCategoriesMap: {}, + allTransactionTags: [], + allTransactionTagsMap: {}, + transactionTagListStateInvalid: true, + transactions: [], + }, + getters: { + allAvailableAccountsCount: account.allAvailableAccountsCount, + allVisibleAccountsCount: account.allVisibleAccountsCount, + }, + mutations: { + [LOAD_ACCOUNT_LIST] (state, accounts) { + state.allAccounts = accounts; + state.allAccountsMap = {}; + + for (let i = 0; i < accounts.length; i++) { + const account = accounts[i]; + state.allAccountsMap[account.id] = account; + } + + state.allCategorizedAccounts = utils.getCategorizedAccounts(accounts); + }, + [ADD_ACCOUNT_TO_ACCOUNT_LIST] (state, account) { + let insertIndexToAllList = 0; + + for (let i = 0; i < state.allAccounts.length; i++) { + if (state.allAccounts[i].category > account.category) { + insertIndexToAllList = i; + break; + } + } + + state.allAccounts.splice(insertIndexToAllList, 0, account); + + state.allAccountsMap[account.id] = account; + + if (state.allCategorizedAccounts[account.category]) { + const accountList = state.allCategorizedAccounts[account.category].accounts; + accountList.push(account); + } else { + state.allCategorizedAccounts = utils.getCategorizedAccounts(state.allAccounts); + } + }, + [SAVE_ACCOUNT_IN_ACCOUNT_LIST] (state, account) { + for (let i = 0; i < state.allAccounts.length; i++) { + if (state.allAccounts[i].id === account.id) { + state.allAccounts.splice(i, 1, account); + break; + } + } + + state.allAccountsMap[account.id] = account; + + if (state.allCategorizedAccounts[account.category]) { + const accountList = state.allCategorizedAccounts[account.category].accounts; + + for (let i = 0; i < accountList.length; i++) { + if (accountList[i].id === account.id) { + accountList.splice(i, 1, account); + break; + } + } + } + }, + [CHANGE_ACCOUNT_DISPLAY_ORDER_IN_ACCOUNT_LIST] (state, { account, from, to }) { + let fromAccount = null; + let toAccount = null; + + if (state.allCategorizedAccounts[account.category]) { + const accountList = state.allCategorizedAccounts[account.category].accounts; + fromAccount = accountList[from]; + toAccount = accountList[to]; + + accountList.splice(to, 0, accountList.splice(from, 1)[0]); + } + + if (fromAccount && toAccount) { + let globalFromIndex = -1; + let globalToIndex = -1; + + for (let i = 0; i < state.allAccounts.length; i++) { + if (state.allAccounts[i].id === fromAccount.id) { + globalFromIndex = i; + } else if (state.allAccounts[i].id === toAccount.id) { + globalToIndex = i; + } + } + + if (globalFromIndex >= 0 && globalToIndex >= 0) { + state.allAccounts.splice(globalToIndex, 0, state.allAccounts.splice(globalFromIndex, 1)[0]); + } + } + }, + [UPDATE_ACCOUNT_VISIBILITY_IN_ACCOUNT_LIST] (state, { account, hidden }) { + if (state.allAccountsMap[account.id]) { + state.allAccountsMap[account.id].hidden = hidden; + } + }, + [REMOVE_ACCOUNT_FROM_ACCOUNT_LIST] (state, account) { + for (let i = 0; i < state.allAccounts.length; i++) { + if (state.allAccounts[i].id === account.id) { + state.allAccounts.splice(i, 1); + break; + } + } + + if (state.allAccountsMap[account.id]) { + delete state.allAccountsMap[account.id]; + } + + if (state.allCategorizedAccounts[account.category]) { + const accountList = state.allCategorizedAccounts[account.category].accounts; + + for (let i = 0; i < accountList.length; i++) { + if (accountList[i].id === account.id) { + accountList.splice(i, 1); + break; + } + } + } + }, + [UPDATE_ACCOUNT_LIST_INVALID_STATE] (state, invalidState) { + state.accountListStateInvalid = invalidState; + }, + [LOAD_TRANSACTION_CATEGORY_LIST] (state, categories) { + state.allTransactionCategories = categories; + state.allTransactionCategoriesMap = {}; + + for (let i = 0; i < categories.length; i++) { + const category = categories[i]; + state.allTransactionCategoriesMap[category.id] = category; + } + }, + [LOAD_TRANSACTION_TAG_LIST] (state, tags) { + state.allTransactionTags = tags; + state.allTransactionTagsMap = {}; + + for (let i = 0; i < tags.length; i++) { + const tag = tags[i]; + state.allTransactionTagsMap[tag.id] = tag; + } + }, + [ADD_TAG_TO_TRANSACTION_TAG_LIST] (state, tag) { + state.allTransactionTags.push(tag); + state.allTransactionTagsMap[tag.id] = tag; + }, + [SAVE_TAG_IN_TRANSACTION_TAG_LIST] (state, tag) { + for (let i = 0; i < state.allTransactionTags.length; i++) { + if (state.allTransactionTags[i].id === tag.id) { + state.allTransactionTags.splice(i, 1, tag); + break; + } + } + + state.allTransactionTagsMap[tag.id] = tag; + }, + [CHANGE_TAG_DISPLAY_ORDER_IN_TRANSACTION_TAG_LIST] (state, { from, to }) { + state.allTransactionTags.splice(to, 0, state.allTransactionTags.splice(from, 1)[0]); + }, + [UPDATE_TAG_VISIBILITY_IN_TRANSACTION_TAG_LIST] (state, { tag, hidden }) { + if (state.allTransactionTagsMap[tag.id]) { + state.allTransactionTagsMap[tag.id].hidden = hidden; + } + }, + [REMOVE_TAG_FROM_TRANSACTION_TAG_LIST] (state, tag) { + for (let i = 0; i < state.allTransactionTags.length; i++) { + if (state.allTransactionTags[i].id === tag.id) { + state.allTransactionTags.splice(i, 1); + break; + } + } + + if (state.allTransactionTagsMap[tag.id]) { + delete state.allTransactionTagsMap[tag.id]; + } + }, + [UPDATE_TRANSACTION_TAG_LIST_INVALID_STATE] (state, invalidState) { + state.transactionTagListStateInvalid = invalidState; + }, + }, + actions: { + loadAllAccounts: account.loadAllAccounts, + saveAccount: account.saveAccount, + getAccount: account.getAccount, + changeAccountDisplayOrder: account.changeAccountDisplayOrder, + updateAccountDisplayOrders: account.updateAccountDisplayOrders, + hideAccount: account.hideAccount, + deleteAccount: account.deleteAccount, + loadAllTags: transactionTag.loadAllTags, + saveTag: transactionTag.saveTag, + changeTagDisplayOrder: transactionTag.changeTagDisplayOrder, + updateTagDisplayOrders: transactionTag.updateTagDisplayOrders, + hideTag: transactionTag.hideTag, + deleteTag: transactionTag.deleteTag, + } +}; + +export default stores; diff --git a/src/store/mutations.js b/src/store/mutations.js new file mode 100644 index 00000000..68a69a13 --- /dev/null +++ b/src/store/mutations.js @@ -0,0 +1,17 @@ +export const LOAD_ACCOUNT_LIST = 'LOAD_ACCOUNT_LIST'; +export const ADD_ACCOUNT_TO_ACCOUNT_LIST = 'ADD_ACCOUNT_TO_ACCOUNT_LIST'; +export const SAVE_ACCOUNT_IN_ACCOUNT_LIST = 'SAVE_ACCOUNT_IN_ACCOUNT_LIST'; +export const CHANGE_ACCOUNT_DISPLAY_ORDER_IN_ACCOUNT_LIST = 'CHANGE_ACCOUNT_DISPLAY_ORDER_IN_ACCOUNT_LIST'; +export const UPDATE_ACCOUNT_VISIBILITY_IN_ACCOUNT_LIST = 'UPDATE_ACCOUNT_VISIBILITY_IN_ACCOUNT_LIST'; +export const REMOVE_ACCOUNT_FROM_ACCOUNT_LIST = 'REMOVE_ACCOUNT_FROM_ACCOUNT_LIST'; +export const UPDATE_ACCOUNT_LIST_INVALID_STATE = 'UPDATE_ACCOUNT_LIST_INVALID_STATE'; + +export const LOAD_TRANSACTION_CATEGORY_LIST = 'LOAD_TRANSACTION_CATEGORY_LIST'; + +export const LOAD_TRANSACTION_TAG_LIST = 'LOAD_TRANSACTION_TAG_LIST'; +export const ADD_TAG_TO_TRANSACTION_TAG_LIST = 'ADD_TAG_TO_TRANSACTION_TAG_LIST'; +export const SAVE_TAG_IN_TRANSACTION_TAG_LIST = 'SAVE_TAG_IN_TRANSACTION_TAG_LIST'; +export const CHANGE_TAG_DISPLAY_ORDER_IN_TRANSACTION_TAG_LIST = 'CHANGE_TAG_DISPLAY_ORDER_IN_TRANSACTION_TAG_LIST'; +export const UPDATE_TAG_VISIBILITY_IN_TRANSACTION_TAG_LIST = 'UPDATE_TAG_VISIBILITY_IN_TRANSACTION_TAG_LIST'; +export const REMOVE_TAG_FROM_TRANSACTION_TAG_LIST = 'REMOVE_TAG_FROM_TRANSACTION_TAG_LIST'; +export const UPDATE_TRANSACTION_TAG_LIST_INVALID_STATE = 'UPDATE_TRANSACTION_TAG_LIST_INVALID_STATE'; diff --git a/src/store/transactionTag.js b/src/store/transactionTag.js new file mode 100644 index 00000000..126b2b2e --- /dev/null +++ b/src/store/transactionTag.js @@ -0,0 +1,248 @@ +import services from '../lib/services.js'; +import logger from '../lib/logger.js'; + +import { + LOAD_TRANSACTION_TAG_LIST, + ADD_TAG_TO_TRANSACTION_TAG_LIST, + SAVE_TAG_IN_TRANSACTION_TAG_LIST, + CHANGE_TAG_DISPLAY_ORDER_IN_TRANSACTION_TAG_LIST, + UPDATE_TAG_VISIBILITY_IN_TRANSACTION_TAG_LIST, + REMOVE_TAG_FROM_TRANSACTION_TAG_LIST, + UPDATE_TRANSACTION_TAG_LIST_INVALID_STATE, +} from './mutations.js'; + +function loadAllTags(context, { force }) { + if (!force && !context.state.transactionTagListStateInvalid) { + return new Promise((resolve) => { + resolve(context.state.allTransactionTags); + }); + } + + return new Promise((resolve, reject) => { + services.getAllTransactionTags().then(response => { + const data = response.data; + + if (!data || !data.success || !data.result) { + reject({ message: 'Unable to get tag list' }); + return; + } + + context.commit(LOAD_TRANSACTION_TAG_LIST, data.result); + context.commit(UPDATE_TRANSACTION_TAG_LIST_INVALID_STATE, false); + + resolve(data.result); + }).catch(error => { + if (force) { + logger.error('failed to force load tag list', error); + } else { + logger.error('failed to load tag list', error); + } + + if (error.response && error.response.data && error.response.data.errorMessage) { + reject({ error: error.response.data }); + } else if (!error.processed) { + reject({ message: 'Unable to get tag list' }); + } else { + reject(error); + } + }); + }); +} + +function saveTag(context, { tag }) { + return new Promise((resolve, reject) => { + let promise = null; + + if (!tag.id) { + promise = services.addTransactionTag(tag); + } else { + promise = services.modifyTransactionTag(tag); + } + + promise.then(response => { + const data = response.data; + + if (!data || !data.success || !data.result) { + if (!tag.id) { + reject({ message: 'Unable to add tag' }); + } else { + reject({ message: 'Unable to save tag' }); + } + return; + } + + if (!tag.id) { + context.commit(ADD_TAG_TO_TRANSACTION_TAG_LIST, data.result); + } else { + context.commit(SAVE_TAG_IN_TRANSACTION_TAG_LIST, data.result); + } + + resolve(data.result); + }).catch(error => { + logger.error('failed to save tag', error); + + if (error.response && error.response.data && error.response.data.errorMessage) { + reject({ error: error.response.data }); + } else if (!error.processed) { + if (!tag.id) { + reject({ message: 'Unable to add tag' }); + } else { + reject({ message: 'Unable to save tag' }); + } + } else { + reject(error); + } + }); + }); +} + +function changeTagDisplayOrder(context, { tagId, from, to }) { + return new Promise((resolve, reject) => { + let tag = null; + + for (let i = 0; i < context.state.allTransactionTags.length; i++) { + if (context.state.allTransactionTags[i].id === tagId) { + tag = context.state.allTransactionTags[i]; + break; + } + } + + if (!tag || !context.state.allTransactionTags[to]) { + reject({ message: 'Unable to move tag' }); + return; + } + + context.commit(UPDATE_TRANSACTION_TAG_LIST_INVALID_STATE, true); + context.commit(CHANGE_TAG_DISPLAY_ORDER_IN_TRANSACTION_TAG_LIST, { + tag: tag, + from: from, + to: to + }); + + resolve(); + }); +} + +function updateTagDisplayOrders(context) { + const newDisplayOrders = []; + + for (let i = 0; i < context.state.allTransactionTags.length; i++) { + newDisplayOrders.push({ + id: context.state.allTransactionTags[i].id, + displayOrder: i + 1 + }); + } + + return new Promise((resolve, reject) => { + services.moveTransactionTag({ + newDisplayOrders: newDisplayOrders + }).then(response => { + const data = response.data; + + if (!data || !data.success || !data.result) { + reject({ message: 'Unable to move tag' }); + return; + } + + context.commit(UPDATE_TRANSACTION_TAG_LIST_INVALID_STATE, false); + + resolve(data.result); + }).catch(error => { + logger.error('failed to save tags display order', error); + + if (error.response && error.response.data && error.response.data.errorMessage) { + reject({ error: error.response.data }); + } else if (!error.processed) { + reject({ message: 'Unable to move tag' }); + } else { + reject(error); + } + }); + }); +} + +function hideTag(context, { tag, hidden }) { + return new Promise((resolve, reject) => { + services.hideTransactionTag({ + id: tag.id, + hidden: hidden + }).then(response => { + const data = response.data; + + if (!data || !data.success || !data.result) { + if (hidden) { + reject({ message: 'Unable to hide this tag' }); + } else { + reject({ message: 'Unable to unhide this tag' }); + } + + return; + } + + context.commit(UPDATE_TAG_VISIBILITY_IN_TRANSACTION_TAG_LIST, { + tag: tag, + hidden: hidden + }); + + resolve(data.result); + }).catch(error => { + logger.error('failed to change tag visibility', error); + + if (error.response && error.response.data && error.response.data.errorMessage) { + reject({ error: error.response.data }); + } else if (!error.processed) { + if (hidden) { + reject({ message: 'Unable to hide this tag' }); + } else { + reject({ message: 'Unable to unhide this tag' }); + } + } else { + reject(error); + } + }); + }); +} + +function deleteTag(context, { tag, beforeResolve }) { + return new Promise((resolve, reject) => { + services.deleteTransactionTag({ + id: tag.id + }).then(response => { + const data = response.data; + + if (!data || !data.success || !data.result) { + reject({ message: 'Unable to delete this tag' }); + return; + } + + if (beforeResolve) { + beforeResolve(() => { + context.commit(REMOVE_TAG_FROM_TRANSACTION_TAG_LIST, tag); + }); + } else { + context.commit(REMOVE_TAG_FROM_TRANSACTION_TAG_LIST, tag); + } + + resolve(data.result); + }).catch(error => { + logger.error('failed to delete tag', error); + + if (error.response && error.response.data && error.response.data.errorMessage) { + reject({ error: error.response.data }); + } else if (!error.processed) { + reject({ message: 'Unable to delete this tag' }); + } else { + reject(error); + } + }); + }); +} + +export default { + loadAllTags, + saveTag, + changeTagDisplayOrder, + updateTagDisplayOrders, + hideTag, + deleteTag, +} diff --git a/src/views/mobile/accounts/Edit.vue b/src/views/mobile/accounts/Edit.vue index f9d6bffa..febe412c 100644 --- a/src/views/mobile/accounts/Edit.vue +++ b/src/views/mobile/accounts/Edit.vue @@ -384,18 +384,10 @@ export default { self.loading = true; self.editAccountId = query.id; - self.$services.getAccount({ - id: self.editAccountId - }).then(response => { - const data = response.data; - if (!data || !data.success || !data.result) { - self.$toast('Unable to get account'); - router.back(); - return; - } - - const account = data.result; + self.$store.dispatch('getAccount', { + accountId: self.editAccountId + }).then(account => { self.account.id = account.id; self.account.category = account.category; self.account.type = account.type; @@ -406,6 +398,7 @@ export default { self.account.balance = account.balance; self.account.comment = account.comment; self.account.visible = !account.hidden; + self.subAccounts = []; if (account.subAccounts && account.subAccounts.length > 0) { for (let i = 0; i < account.subAccounts.length; i++) { @@ -431,13 +424,10 @@ export default { self.loading = false; }).catch(error => { - self.$logger.error('failed to load account info', error); + self.loading = false; - if (error.response && error.response.data && error.response.data.errorMessage) { - self.$toast({ error: error.response.data }); - router.back(); - } else if (!error.processed) { - self.$toast('Unable to get account'); + if (!error.processed) { + self.$toast(error.message || error); router.back(); } }); @@ -550,29 +540,16 @@ export default { subAccounts: self.account.type === self.$constants.account.allAccountTypes.SingleAccount ? null : subAccounts, }; - let promise = null; - - if (!self.editAccountId) { - promise = self.$services.addAccount(submitAccount); - } else { + if (self.editAccountId) { submitAccount.id = self.account.id; submitAccount.hidden = !self.account.visible; - promise = self.$services.modifyAccount(submitAccount); } - promise.then(response => { + self.$store.dispatch('saveAccount', { + account: submitAccount + }).then(() => { self.submitting = false; self.$hideLoading(); - const data = response.data; - - if (!data || !data.success || !data.result) { - if (!self.editAccountId) { - self.$toast('Unable to add account'); - } else { - self.$toast('Unable to save account'); - } - return; - } if (!self.editAccountId) { self.$toast('You have added a new account'); @@ -582,19 +559,11 @@ export default { router.back(); }).catch(error => { - self.$logger.error('failed to save account', error); - self.submitting = false; self.$hideLoading(); - if (error.response && error.response.data && error.response.data.errorMessage) { - self.$toast({ error: error.response.data }); - } else if (!error.processed) { - if (!self.editAccountId) { - self.$toast('Unable to add account'); - } else { - self.$toast('Unable to save account'); - } + if (!error.processed) { + self.$toast(error.message || error); } }); }, diff --git a/src/views/mobile/accounts/List.vue b/src/views/mobile/accounts/List.vue index ab80217f..965826eb 100644 --- a/src/views/mobile/accounts/List.vue +++ b/src/views/mobile/accounts/List.vue @@ -116,7 +116,7 @@ - + {{ $t(accountCategory.name) }} @@ -124,12 +124,12 @@ - + @@ -147,7 +147,7 @@ @@ -201,7 +201,6 @@ export default { data() { return { - categorizedAccounts: {}, loading: true, showHidden: false, sortable: false, @@ -217,61 +216,22 @@ export default { defaultCurrency() { return this.$user.getUserInfo() ? this.$user.getUserInfo().defaultCurrency : this.$t('default.currency'); }, + allAccountCategories() { + return this.$constants.account.allCategories; + }, + categorizedAccounts() { + return this.$store.state.allCategorizedAccounts; + }, allAccountCount() { - let allAccountCount = 0; - - for (let category in this.categorizedAccounts) { - if (!Object.prototype.hasOwnProperty.call(this.categorizedAccounts, category)) { - continue; - } - - allAccountCount += this.categorizedAccounts[category].accounts.length; - } - - return allAccountCount; + return this.$store.getters.allAvailableAccountsCount; }, noAvailableAccount() { - let allAccountCount = 0; - let shownAccountCount = 0; - - for (let category in this.categorizedAccounts) { - if (!Object.prototype.hasOwnProperty.call(this.categorizedAccounts, category)) { - continue; - } - - const accountList = this.categorizedAccounts[category].accounts; - - for (let i = 0; i < accountList.length; i++) { - if (!accountList[i].hidden) { - shownAccountCount++; - } - - allAccountCount++; - } - } - if (this.showHidden) { - return allAccountCount < 1; + return this.$store.getters.allAvailableAccountsCount < 1; } else { - return shownAccountCount < 1; + return this.$store.getters.allVisibleAccountsCount < 1; } }, - usedAccountCategories() { - const allAccountCategories = this.$constants.account.allCategories; - const usedAccountCategories = []; - - for (let i = 0; i < allAccountCategories.length; i++) { - const accountCategory = allAccountCategories[i]; - - if (this.categorizedAccounts[accountCategory.id] && - this.$utilities.isArray(this.categorizedAccounts[accountCategory.id].accounts) && - this.categorizedAccounts[accountCategory.id].accounts.length) { - usedAccountCategories.push(accountCategory); - } - } - - return usedAccountCategories; - }, netAssets() { if (!this.showAccountBalance) { return '***'; @@ -369,36 +329,23 @@ export default { self.loading = true; - self.$services.getAllAccounts({ visibleOnly: false }).then(response => { - const data = response.data; - - if (!data || !data.success || !data.result) { - self.$toast('Unable to get account list'); - router.back(); - return; - } - - self.categorizedAccounts = self.$utilities.getCategorizedAccounts(data.result); + self.$store.dispatch('loadAllAccounts', { + force: false + }).then(() => { self.loading = false; }).catch(error => { - self.$logger.error('failed to load account list', error); + self.loading = false; - if (error.response && error.response.data && error.response.data.errorMessage) { - self.$toast({ error: error.response.data }); - router.back(); - } else if (!error.processed) { - self.$toast('Unable to get account list'); + if (!error.processed) { + self.$toast(error.message || error); router.back(); } }); }, methods: { onPageAfterIn() { - const self = this; - const previousRoute = self.$f7router.previousRoute; - - if (previousRoute && (previousRoute.path === '/account/add' || previousRoute.path === '/account/edit') && !self.loading) { - self.reload(null); + if (this.$store.state.accountListStateInvalid && !this.loading) { + this.reload(null); } }, reload(done) { @@ -409,34 +356,23 @@ export default { const self = this; - self.$services.getAllAccounts({ visibleOnly: false }).then(response => { + self.$store.dispatch('loadAllAccounts', { + force: true + }).then(() => { if (done) { done(); } - - const data = response.data; - - if (!data || !data.success || !data.result) { - self.$toast('Unable to get account list'); - return; - } - - self.categorizedAccounts = self.$utilities.getCategorizedAccounts(data.result); }).catch(error => { - self.$logger.error('failed to reload account list', error); - if (done) { done(); } - if (error.response && error.response.data && error.response.data.errorMessage) { - self.$toast({ error: error.response.data }); - } else if (!error.processed) { - self.$toast('Unable to get account list'); + if (!error.processed) { + self.$toast(error.message || error); } }); }, - hasShownAccount(accountCategory) { + hasAccount(accountCategory, visibleOnly) { if (!this.categorizedAccounts[accountCategory.id] || !this.categorizedAccounts[accountCategory.id].accounts || !this.categorizedAccounts[accountCategory.id].accounts.length) { @@ -448,7 +384,7 @@ export default { for (let i = 0; i < this.categorizedAccounts[accountCategory.id].accounts.length; i++) { const account = this.categorizedAccounts[accountCategory.id].accounts[i]; - if (!account.hidden) { + if (!visibleOnly || !account.hidden) { shownCount++; } } @@ -528,30 +464,27 @@ export default { this.displayOrderModified = false; }, onSort(event) { + const self = this; + if (!event || !event.el || !event.el.id || event.el.id.indexOf('account_') !== 0) { - this.$toast('Unable to move account'); + self.$toast('Unable to move account'); return; } const id = event.el.id.substr(8); // account_ - const account = this.$utilities.getAccountByAccountId(this.categorizedAccounts, id); - if (!account || - !this.categorizedAccounts[account.category] || - !this.categorizedAccounts[account.category].accounts || - !this.categorizedAccounts[account.category].accounts[event.to]) { - this.$toast('Unable to move account'); - return; - } - - const accountList = this.categorizedAccounts[account.category].accounts; - accountList.splice(event.to, 0, accountList.splice(event.from, 1)[0]); - - this.displayOrderModified = true; + self.$store.dispatch('changeAccountDisplayOrder', { + accountId: id, + from: event.from, + to: event.to + }).then(() => { + self.displayOrderModified = true; + }).catch(error => { + self.$toast(error.message || error); + }); }, saveSortResult() { const self = this; - const newDisplayOrders = []; if (!self.displayOrderModified) { self.showHidden = false; @@ -560,50 +493,21 @@ export default { } self.displayOrderSaving = true; - - for (let category in self.categorizedAccounts) { - if (!Object.prototype.hasOwnProperty.call(self.categorizedAccounts, category)) { - continue; - } - - const accountList = self.categorizedAccounts[category].accounts; - - for (let i = 0; i < accountList.length; i++) { - newDisplayOrders.push({ - id: accountList[i].id, - displayOrder: i + 1 - }); - } - } - self.$showLoading(); - self.$services.moveAccount({ - newDisplayOrders: newDisplayOrders - }).then(response => { + self.$store.dispatch('updateAccountDisplayOrders').then(() => { self.displayOrderSaving = false; self.$hideLoading(); - const data = response.data; - - if (!data || !data.success || !data.result) { - self.$toast('Unable to move account'); - return; - } - self.showHidden = false; self.sortable = false; self.displayOrderModified = false; }).catch(error => { - self.$logger.error('failed to save accounts display order', error); - self.displayOrderSaving = false; self.$hideLoading(); - if (error.response && error.response.data && error.response.data.errorMessage) { - self.$toast({ error: error.response.data }); - } else if (!error.processed) { - self.$toast('Unable to move account'); + if (!error.processed) { + self.$toast(error.message || error); } }); }, @@ -615,37 +519,16 @@ export default { self.$showLoading(); - self.$services.hideAccount({ - id: account.id, + self.$store.dispatch('hideAccount', { + account: account, hidden: hidden - }).then(response => { + }).then(() => { self.$hideLoading(); - const data = response.data; - - if (!data || !data.success || !data.result) { - if (hidden) { - self.$toast('Unable to hide this account'); - } else { - self.$toast('Unable to unhide this account'); - } - - return; - } - - account.hidden = hidden; }).catch(error => { - self.$logger.error('failed to change account visibility', error); - self.$hideLoading(); - if (error.response && error.response.data && error.response.data.errorMessage) { - self.$toast({ error: error.response.data }); - } else if (!error.processed) { - if (hidden) { - self.$toast('Unable to hide this account'); - } else { - self.$toast('Unable to unhide this account'); - } + if (!error.processed) { + self.$toast(error.message || error); } }); }, @@ -669,34 +552,20 @@ export default { self.accountToDelete = null; self.$showLoading(); - self.$services.deleteAccount({ - id: account.id - }).then(response => { - self.$hideLoading(); - const data = response.data; - - if (!data || !data.success || !data.result) { - self.$toast('Unable to delete this account'); - return; + self.$store.dispatch('deleteAccount', { + account: account, + beforeResolve: (done) => { + app.swipeout.delete($$(`#${self.$options.filters.accountDomId(account)}`), () => { + done(); + }); } - - app.swipeout.delete($$(`#${self.$options.filters.accountDomId(account)}`), () => { - const accountList = self.categorizedAccounts[account.category].accounts; - for (let i = 0; i < accountList.length; i++) { - if (accountList[i].id === account.id) { - accountList.splice(i, 1); - } - } - }); + }).then(() => { + self.$hideLoading(); }).catch(error => { - self.$logger.error('failed to delete account', error); - self.$hideLoading(); - if (error.response && error.response.data && error.response.data.errorMessage) { - self.$toast({ error: error.response.data }); - } else if (!error.processed) { - self.$toast('Unable to delete this account'); + if (!error.processed) { + self.$toast(error.message || error); } }); } diff --git a/src/views/mobile/tags/List.vue b/src/views/mobile/tags/List.vue index 59212413..9a2bfd64 100644 --- a/src/views/mobile/tags/List.vue +++ b/src/views/mobile/tags/List.vue @@ -62,15 +62,15 @@
+ v-if="editingTag.id !== tag.id"> {{ tag.name }}
@@ -80,30 +80,59 @@ raised fill icon-f7="checkmark_alt" color="blue" - v-if="tag.editing" - @click="save(tag)"> + v-if="editingTag.id === tag.id" + @click="save(editingTag)"> + v-if="editingTag.id === tag.id" + @click="cancelSave(editingTag)"> - + - +
+ + + +
+ + + +
+
+ + + + +
@@ -133,7 +162,11 @@ export default { data() { return { - tags: [], + newTag: null, + editingTag: { + id: '', + name: '' + }, loading: true, showHidden: false, sortable: false, @@ -146,6 +179,9 @@ export default { }; }, computed: { + tags() { + return this.$store.state.allTransactionTags; + }, noAvailableTag() { for (let i = 0; i < this.tags.length; i++) { if (this.showHidden || !this.tags[i].hidden) { @@ -156,13 +192,7 @@ export default { return true; }, hasEditingTag() { - for (let i = 0; i < this.tags.length; i++) { - if (this.tags[i].editing) { - return true; - } - } - - return false; + return this.newTag || (this.editingTag.id && this.editingTag.id !== ''); } }, created() { @@ -171,30 +201,15 @@ export default { self.loading = true; - self.$services.getAllTransactionTags().then(response => { - const data = response.data; - - if (!data || !data.success || !data.result) { - self.$toast('Unable to get tag list'); - router.back(); - return; - } - - for (let i = 0; i < data.result.length; i++) { - data.result[i].editing = false; - data.result[i].newName = data.result[i].name; - } - - self.tags = data.result; + self.$store.dispatch('loadAllTags', { + force: false + }).then(() => { self.loading = false; }).catch(error => { - self.$logger.error('failed to load tag list', error); + self.loading = false; - if (error.response && error.response.data && error.response.data.errorMessage) { - self.$toast({ error: error.response.data }); - router.back(); - } else if (!error.processed) { - self.$toast('Unable to get tag list'); + if (!error.processed) { + self.$toast(error.message || error); router.back(); } }); @@ -208,35 +223,19 @@ export default { const self = this; - self.$services.getAllTransactionTags().then(response => { + self.$store.dispatch('loadAllTags', { + force: true + }).then(() => { if (done) { done(); } - - const data = response.data; - - if (!data || !data.success || !data.result) { - self.$toast('Unable to get tag list'); - return; - } - - for (let i = 0; i < data.result.length; i++) { - data.result[i].editing = false; - data.result[i].newName = data.result[i].name; - } - - self.tags = data.result; }).catch(error => { - self.$logger.error('failed to reload tag list', error); - if (done) { done(); } - if (error.response && error.response.data && error.response.data.errorMessage) { - self.$toast({ error: error.response.data }); - } else if (!error.processed) { - self.$toast('Unable to get category list'); + if (!error.processed) { + self.$toast(error.message || error); } }); }, @@ -250,33 +249,27 @@ export default { this.displayOrderModified = false; }, onSort(event) { + const self = this; + if (!event || !event.el || !event.el.id || event.el.id.indexOf('tag_') !== 0) { - this.$toast('Unable to move tag'); + self.$toast('Unable to move tag'); return; } const id = event.el.id.substr(4); // tag_ - let tag = null; - for (let i = 0; i < this.tags.length; i++) { - if (this.tags[i].id === id) { - tag = this.tags[i]; - break; - } - } - - if (!tag || !this.tags[event.to]) { - this.$toast('Unable to move tag'); - return; - } - - this.tags.splice(event.to, 0, this.tags.splice(event.from, 1)[0]); - - this.displayOrderModified = true; + self.$store.dispatch('changeTagDisplayOrder', { + tagId: id, + from: event.from, + to: event.to + }).then(() => { + self.displayOrderModified = true; + }).catch(error => { + self.$toast(error.message || error); + }); }, saveSortResult() { const self = this; - const newDisplayOrders = []; if (!self.displayOrderModified) { self.showHidden = false; @@ -285,158 +278,87 @@ export default { } self.displayOrderSaving = true; - - for (let i = 0; i < self.tags.length; i++) { - newDisplayOrders.push({ - id: self.tags[i].id, - displayOrder: i + 1 - }); - } - self.$showLoading(); - self.$services.moveTransactionTag({ - newDisplayOrders: newDisplayOrders - }).then(response => { + self.$store.dispatch('updateTagDisplayOrders').then(() => { self.displayOrderSaving = false; self.$hideLoading(); - const data = response.data; - - if (!data || !data.success || !data.result) { - self.$toast('Unable to move tag'); - return; - } - self.showHidden = false; self.sortable = false; self.displayOrderModified = false; }).catch(error => { - self.$logger.error('failed to save tags display order', error); - self.displayOrderSaving = false; self.$hideLoading(); - if (error.response && error.response.data && error.response.data.errorMessage) { - self.$toast({ error: error.response.data }); - } else if (!error.processed) { - self.$toast('Unable to move tag'); + if (!error.processed) { + self.$toast(error.message || error); } }); }, add() { - this.tags.push({ - id: '', - name: '', - newName: '', - hidden: false, - editing: true - }); + this.newTag = { + name: '' + }; }, edit(tag) { - tag.newName = tag.name; - tag.editing = true; + this.editingTag.id = tag.id; + this.editingTag.name = tag.name; }, save(tag) { - if (tag.newName === tag.name) { - return; - } - const self = this; self.$showLoading(); - let promise = null; - - if (tag.id) { - promise = self.$services.modifyTransactionTag({ - id: tag.id, - name: tag.newName - }); - } else { - promise = self.$services.addTransactionTag({ - name: tag.newName - }); - } - - promise.then(response => { + self.$store.dispatch('saveTag', { + tag: tag + }).then(() => { self.$hideLoading(); - const data = response.data; - if (!data || !data.success || !data.result) { - self.$toast('Unable to save this tag'); - return; + if (tag.id) { + this.editingTag.id = ''; + this.editingTag.name = ''; + } else { + this.newTag = null; } - - tag.id = data.result.id; - tag.name = data.result.name; - tag.hidden = data.result.hidden; - tag.editing = false; }).catch(error => { - self.$logger.error('failed to save tag', error); - self.$hideLoading(); - if (error.response && error.response.data && error.response.data.errorMessage) { - self.$toast({ error: error.response.data }); - } else if (!error.processed) { - self.$toast('Unable to save this tag'); + if (!error.processed) { + self.$toast(error.message || error); } }); }, cancelSave(tag) { if (tag.id) { - tag.newName = ''; + this.editingTag.id = ''; + this.editingTag.name = ''; } else { - for (let i = 0; i < this.tags.length; i++) { - if (this.tags[i] === tag) { - this.tags.splice(i, 1); - break; - } - } + this.newTag = null; } - - tag.editing = false; }, isTagModified(tag) { - return tag.newName !== tag.name; + if (tag.id) { + return this.editingTag.name !== '' && this.editingTag.name !== tag.name; + } else { + return tag.name !== ''; + } }, hide(tag, hidden) { const self = this; self.$showLoading(); - self.$services.hideTransactionTag({ - id: tag.id, + self.$store.dispatch('hideTag', { + tag: tag, hidden: hidden - }).then(response => { + }).then(() => { self.$hideLoading(); - const data = response.data; - - if (!data || !data.success || !data.result) { - if (hidden) { - self.$toast('Unable to hide this tag'); - } else { - self.$toast('Unable to unhide this tag'); - } - - return; - } - - tag.hidden = hidden; }).catch(error => { - self.$logger.error('failed to change tag visibility', error); - self.$hideLoading(); - if (error.response && error.response.data && error.response.data.errorMessage) { - self.$toast({ error: error.response.data }); - } else if (!error.processed) { - if (hidden) { - self.$toast('Unable to hide this tag'); - } else { - self.$toast('Unable to unhide this tag'); - } + if (!error.processed) { + self.$toast(error.message || error); } }); }, @@ -460,33 +382,20 @@ export default { self.tagToDelete = null; self.$showLoading(); - self.$services.deleteTransactionTag({ - id: tag.id - }).then(response => { - self.$hideLoading(); - const data = response.data; - - if (!data || !data.success || !data.result) { - self.$toast('Unable to delete this tag'); - return; + self.$store.dispatch('deleteTag', { + tag: tag, + beforeResolve: (done) => { + app.swipeout.delete($$(`#${self.$options.filters.tagDomId(tag)}`), () => { + done(); + }); } - - app.swipeout.delete($$(`#${self.$options.filters.tagDomId(tag)}`), () => { - for (let i = 0; i < self.tags.length; i++) { - if (self.tags[i].id === tag.id) { - self.tags.splice(i, 1); - } - } - }); + }).then(() => { + self.$hideLoading(); }).catch(error => { - self.$logger.error('failed to delete tag', error); - self.$hideLoading(); - if (error.response && error.response.data && error.response.data.errorMessage) { - self.$toast({ error: error.response.data }); - } else if (!error.processed) { - self.$toast('Unable to delete this tag'); + if (!error.processed) { + self.$toast(error.message || error); } }); }