-
+
-
-
+
+
+
Income
+
+
+
+
Expenses
+
+
+
+
Recent Transactions
+
+
\ No newline at end of file
+
+
\ No newline at end of file
diff --git a/src/components/BudgetList.vue b/src/components/BudgetList.vue
index 50d131e..91e6ada 100644
--- a/src/components/BudgetList.vue
+++ b/src/components/BudgetList.vue
@@ -1,13 +1,13 @@
-
+ :to="{ name: 'budgetDetails', params: { id: budget.id } }"
+ />
+
diff --git a/src/components/CategoryList.vue b/src/components/CategoryList.vue
index 3000a8f..2cd15ab 100644
--- a/src/components/CategoryList.vue
+++ b/src/components/CategoryList.vue
@@ -1,29 +1,73 @@
+
\ No newline at end of file
diff --git a/src/components/ProgressBar.vue b/src/components/ProgressBar.vue
new file mode 100644
index 0000000..59879a3
--- /dev/null
+++ b/src/components/ProgressBar.vue
@@ -0,0 +1,57 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/TransactionDetails.vue b/src/components/TransactionDetails.vue
new file mode 100644
index 0000000..9d8cbbf
--- /dev/null
+++ b/src/components/TransactionDetails.vue
@@ -0,0 +1,64 @@
+
+
+
{{ transaction.name }}
+
{{ (transaction.amount / 100).toLocaleString(undefined, {style: 'currency', currency: 'USD'}) }} {{ transaction.expense ? 'Expense' : 'Income' }}
+
{{ new Date(transaction.date).toLocaleDateString() }}
+
{{ transaction.description }}
+
Category: {{ category.name }}
+
Budget: {{ budget.name }}
+
+ Registered By:
+
+ {{ new Date(transaction.createdDate).toLocaleDateString() }}
+
+
+ Updated By:
+
+ {{ new Date(transaction.updatedDate).toLocaleDateString() }}
+
+
+
+
diff --git a/src/components/TransactionList.vue b/src/components/TransactionList.vue
new file mode 100644
index 0000000..4c8a8f0
--- /dev/null
+++ b/src/components/TransactionList.vue
@@ -0,0 +1,74 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/router/index.js b/src/router/index.js
index 7bf204a..b6f6373 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -1,6 +1,9 @@
import VueRouter from 'vue-router'
import Vue from 'vue'
import BudgetDetails from '../components/BudgetDetails'
+import CategoryDetails from '../components/CategoryDetails'
+import AddEditTransaction from '../components/AddEditTransaction'
+import TransactionDetails from '../components/TransactionDetails'
Vue.use(VueRouter)
@@ -9,7 +12,27 @@ const routes = [
path: '/budgets/:id',
name: 'budgetDetails',
component: BudgetDetails,
- }
+ },
+ {
+ path: '/categories/:id',
+ name: 'categoryDetails',
+ component: CategoryDetails,
+ },
+ {
+ path: '/transactions/new',
+ name: 'newTransaction',
+ component: AddEditTransaction,
+ },
+ {
+ path: '/transactions/:id',
+ name: 'transactionDetails',
+ component: TransactionDetails,
+ },
+ {
+ path: '/transactions/:id/edit',
+ name: 'editTransaction',
+ component: AddEditTransaction,
+ },
]
export default new VueRouter({
diff --git a/src/store/index.js b/src/store/index.js
index 079ff5a..18b1785 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -1,56 +1,189 @@
import Vue from 'vue'
import Vuex from 'vuex'
import axios from '@nextcloud/axios'
+import router from '../router'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
budgets: [],
+ budgetBalances: {},
currentBudget: 0,
- categories: {},
+ categories: [],
+ categoryBalances: {},
currentCategory: 0,
transactions: [],
currentTransaction: 0,
},
getters: {
- budgets: (state) => {
- return state.budgets
+ budgets: (state) => state.budgets,
+ budget: (state) => (id) => state.budgets.find(budget => budget.id === id),
+ budgetBalance: (state) => (id) => state.budgetBalances[id],
+ categories: (state) => state.categories,
+ category: (state) => (id) => {
+ return state.categories.find(category => category.id === id)
},
- budget: (state) => (id) => {
- return state.budgets.find(budget => budget.id === id)
+ categoryBalance: (state) => (categoryId) => {
+ return state.categoryBalances[categoryId];
},
- categories: (state) => (budgetId) => {
- return state.categories[budgetId]
+ categoryRemainingBalance: (state, getters) => (category) => {
+ const modifier = category.expense ? -1 : 1;
+ return category.amount - (getters.categoryBalance(category.id) * modifier);
},
+ transactions: (state) => state.transactions,
+ transaction: (state) => state.transactions.find(transaction => transaction.id === state.currentTransaction),
},
actions: {
budgetListViewed({ commit }) {
axios.get(OC.generateUrl('/apps/twigs/api/v1.0/budgets'))
.then(function (response) {
commit('setBudgets', response.data)
- })
- },
- budgetDetailsViewed({ commit }, budgetId) {
- axios.get(OC.generateUrl(`/apps/twigs/api/v1.0/categories?budgetId=${budgetId}`))
- .then(function (response) {
- commit({
- type: 'setCategories',
- budgetId: budgetId,
- categories: response.data
+ response.data.forEach(budget => {
+ axios.get(OC.generateUrl(`/apps/twigs/api/v1.0/transactions/sum?budgetId=${budget.id}`))
+ .then(function (response) {
+ commit({
+ type: 'setBudgetBalance',
+ ...response.data
+ })
+ })
})
})
- }
+ },
+ budgetClicked({ commit }, budgetId) {
+ router.push({ name: "budgetDetails", params: { id: budgetId } })
+ },
+ budgetDetailsViewed({ commit }, budgetId) {
+ commit('setCurrentBudget', budgetId)
+ commit('setCategories', [])
+ commit('setTransactions', [])
+ commit('setCurrentCategory', undefined)
+ axios.get(OC.generateUrl(`/apps/twigs/api/v1.0/categories?budgetId=${budgetId}`))
+ .then(function (response) {
+ commit('setCategories', response.data)
+ response.data.forEach(category => {
+ axios.get(OC.generateUrl(`/apps/twigs/api/v1.0/transactions/sum?categoryId=${category.id}`))
+ .then(function (response) {
+ commit({
+ type: 'setCategoryBalance',
+ ...response.data
+ })
+ })
+ });
+ })
+ axios.get(OC.generateUrl(`/apps/twigs/api/v1.0/transactions?budgetId=${budgetId}?count=10`))
+ .then((response) => commit('setTransactions', response.data))
+ },
+ categoryClicked({ commit }, categoryId) {
+ router.push({ name: "categoryDetails", params: { id: categoryId } })
+ },
+ categoryDetailsViewed({ commit, state }, categoryId) {
+ commit('setCurrentCategory', categoryId)
+ if (state.categories.length === 0) {
+ axios.get(OC.generateUrl(`/apps/twigs/api/v1.0/categories/${categoryId}`))
+ .then((response) => {
+ commit('setCategories', [response.data])
+ })
+ }
+ axios.get(OC.generateUrl(`/apps/twigs/api/v1.0/transactions?categoryId=${categoryId}`))
+ .then((response) => commit('setTransactions', response.data))
+ },
+ addTransactionClicked({ commit }) {
+ router.push({ name: "newTransaction" })
+ },
+ addEditTransactionViewed({ commit, state, getters }, transactionId) {
+ if (transactionId && getters.transaction(transactionId) === undefined) {
+ axios.get(OC.generateUrl(`/apps/twigs/api/v1.0/transactions/${transactionId}`))
+ .then((response) => {
+ commit('setTransactions', [response.data])
+ })
+ }
+ },
+ addEditTransactionBudgetSelected({ commit, state }, budgetId) {
+ commit('setCategories', [])
+ if (!budgetId) return;
+ axios.get(OC.generateUrl(`/apps/twigs/api/v1.0/categories?budgetId=${budgetId}`))
+ .then(function (response) {
+ commit('setCategories', response.data)
+ })
+ },
+ addEditTransactionSaveClicked({ commit }, transaction) {
+ let request;
+ if (transaction.id) {
+ request = axios.put(OC.generateUrl(`/apps/twigs/api/v1.0/transactions/${transaction.id}`), transaction)
+ } else {
+ request = axios.post(OC.generateUrl(`/apps/twigs/api/v1.0/transactions`), transaction)
+ }
+ request.then(response => {
+ commit('addTransaction', response.data)
+ router.push({ name: "transactionDetails", params: { id: response.data.id } })
+ })
+ },
+ transactionClicked({ commit }, transactionId) {
+ router.push({ name: "transactionDetails", params: { id: transactionId } })
+ },
+ transactionDetailsViewed({ commit, state }, transactionId) {
+ commit('setCurrentTransaction', transactionId)
+
+ if (state.transactions.length === 0) {
+ axios.get(OC.generateUrl(`/apps/twigs/api/v1.0/transactions/${transactionId}`))
+ .then((response) => {
+ commit('setTransactions', [response.data])
+ if (state.categories.length === 0) {
+ axios.get(OC.generateUrl(`/apps/twigs/api/v1.0/categories?budgetId=${response.data.budgetId}`))
+ .then(function (response) {
+ commit('setCategories', response.data)
+ response.data.forEach(category => {
+ axios.get(OC.generateUrl(`/apps/twigs/api/v1.0/transactions/sum?categoryId=${category.id}`))
+ .then(function (response) {
+ commit({
+ type: 'setCategoryBalance',
+ ...response.data
+ })
+ })
+ });
+ })
+ }
+ })
+ }
+ },
},
mutations: {
+ setCurrentBudget(state, budgetId) {
+ state.currentBudget = Number.parseInt(budgetId)
+ },
+ setBudgetBalance(state, data) {
+ state.budgetBalances = {
+ ...state.budgetBalances,
+ [data.budgetId]: data.sum
+ }
+ },
setBudgets(state, budgets) {
state.budgets = budgets
},
+ setCurrentCategory(state, categoryId) {
+ state.currentCategory = Number.parseInt(categoryId)
+ },
setCategories(state, data) {
- state.categories = {
- ...state.categories,
- [data.budgetId]: data.categories
+ state.categories = data
+ },
+ setCategoryBalance(state, data) {
+ state.categoryBalances = {
+ ...state.categoryBalances,
+ [data.categoryId]: data.sum
}
- }
+ },
+ addTransaction(state, transaction) {
+ state.transactions = [
+ ...state.transactions.filter(t => t.id !== transaction.id),
+ transaction
+ ]
+ },
+ setTransactions(state, data) {
+ state.transactions = data
+ },
+ setCurrentTransaction(state, transactionId) {
+ state.currentTransaction = Number.parseInt(transactionId)
+ },
}
})