diff --git a/web/src/pages/Budgeting.vue b/web/src/pages/Budgeting.vue index d3d84a8..8143222 100644 --- a/web/src/pages/Budgeting.vue +++ b/web/src/pages/Budgeting.vue @@ -60,13 +60,11 @@ export default defineComponent({ Activity Available - + {{category.Group}} {{category.Name}} - - - - + + {{category.AvailableLastMonth}} {{category.Assigned}} {{category.Activity}} diff --git a/web/src/router/index.ts b/web/src/router/index.ts index b8e4b0a..8d3aa52 100644 --- a/web/src/router/index.ts +++ b/web/src/router/index.ts @@ -15,7 +15,7 @@ const routes = [ { path: "/login", name: "Login", component: Login }, { path: "/register", name: "Register", component: Register }, { path: "/budget/:budgetid", name: "Budget", components: { default: Budgeting, sidebar: BudgetSidebar }, props: true }, - { path: "/budget/:budgetid/:year/:month", name: "Budget", components: { default: Budgeting, sidebar: BudgetSidebar }, props: true }, + { path: "/budget/:budgetid/:year/:month", name: "Budget with date", components: { default: Budgeting, sidebar: BudgetSidebar }, props: true }, { path: "/budget/:budgetid/Settings", name: "Budget Settings", components: { default: Settings, sidebar: BudgetSidebar }, props: true }, { path: "/budget/:budgetid/account/:accountid", name: "Account", components: { default: Account, sidebar: BudgetSidebar }, props: true }, ] diff --git a/web/src/store/budget/index.ts b/web/src/store/budget/index.ts new file mode 100644 index 0000000..bc04f3b --- /dev/null +++ b/web/src/store/budget/index.ts @@ -0,0 +1,117 @@ +import { Module } from "vuex"; +import { FETCH_ACCOUNT, FETCH_BUDGET, SET_CURRENT_ACCOUNT } from "../action-types"; +import { LOGOUT, TITLE } from "../mutation-types"; + +export interface BudgetState { + Accounts: Map, + CurrentAccountID?: string, + Categories: Map, + Transactions: [], + Assignments: [] +} + +export interface Account { + ID: string + OnBudget: boolean +} + +export interface Category { + Group: string + Name: string + AvailableLastMonth: number + Assigned: number + Activity: number + Available: number +} + +export const budgetStore : Module = { + state: { + Accounts: new Map(), + CurrentAccountID: undefined, + Categories: new Map(), + Transactions: [], + Assignments: [] + }, + + mutations: { + initializeStore(state) { + const store = localStorage.getItem("store"); + if (!store) + return; + + const restoredState = JSON.parse(store); + if (!restoredState) + return; + + state.CurrentAccountID = restoredState.CurrentAccountID; + + for (const account of restoredState.Accounts || []) { + state.Accounts.set(account[0], account[1]); + } + }, + [LOGOUT](state) { + state.Accounts.clear(); + state.Categories.clear(); + state.Transactions = []; + state.Assignments = []; + }, + addAccount(state, account) { + state.Accounts.set(account.ID, account); + }, + addCategory(state, category) { + state.Categories.set(category.ID, category); + }, + setCurrentAccountID(state, accountid) { + state.CurrentAccountID = accountid; + }, + setTransactions(state, transactions) { + state.Transactions = transactions; + } + }, + + getters: { + Accounts(state) { + return state.Accounts.values(); + }, + Categories: (state) => (year : number, month : number) => { + return state.Categories.values(); + }, + CurrentAccount(state) : Account | undefined { + if (state.CurrentAccountID == null) + return undefined; + return state.Accounts.get(state.CurrentAccountID); + }, + OnBudgetAccounts(state) { + return Array.from(state.Accounts.values()).filter(x => x.OnBudget); + }, + OffBudgetAccounts(state) { + return Array.from(state.Accounts.values()).filter(x => !x.OnBudget); + }, + Transactions(state) { + return (state.Transactions || []); + } + }, + + actions: { + async [SET_CURRENT_ACCOUNT]({ state, commit, dispatch, getters }, { budgetid, accountid }) { + if (budgetid == null) + return + + commit("setCurrentAccountID", accountid); + if (accountid == null) + return + + commit(TITLE, getters.CurrentAccount.Name); + await dispatch(FETCH_ACCOUNT, accountid) + }, + async [FETCH_ACCOUNT]({ state, commit, rootState }, accountid) { + const result = await fetch("/api/v1/account/" + accountid + "/transactions", { + headers: { + 'Authorization': 'Bearer ' + rootState.Session.Token + } + }); + const response = await result.json(); + commit("setTransactions", response.Transactions); + }, + } +} \ No newline at end of file diff --git a/web/src/store/index.ts b/web/src/store/index.ts index 4552a49..03dcb57 100644 --- a/web/src/store/index.ts +++ b/web/src/store/index.ts @@ -2,6 +2,7 @@ import { InjectionKey } from 'vue' import { createStore, Store, createLogger } from 'vuex' import { LOGIN_SUCCESS, LOGOUT, TITLE } from './mutation-types' import { FETCH_ACCOUNT, FETCH_BUDGET, GET, REGISTER, IMPORT_YNAB, LOGIN, NEW_BUDGET, POST, SET_CURRENT_ACCOUNT, SET_CURRENT_BUDGET } from './action-types' +import { budgetStore } from './budget' export interface State { Session: { @@ -11,11 +12,6 @@ export interface State { ShowMenu?: boolean, Budgets: Map, CurrentBudgetID?: string, - Accounts: Map, - CurrentAccountID?: string, - Categories: Array, - Transactions: [], - Assignments: [] } export interface Budget { @@ -24,20 +20,6 @@ export interface Budget { AvailableBalance: number } -export interface Account { - ID: string - OnBudget: boolean -} - -export interface Category { - Group: string - Name: string - AvailableLastMonth: number - Assigned: number - Activity: number - Available: number -} - export const key: InjectionKey> = Symbol() export const store = createStore({ @@ -49,11 +31,6 @@ export const store = createStore({ ShowMenu: undefined, Budgets: new Map(), CurrentBudgetID: undefined, - Accounts: new Map(), - CurrentAccountID: undefined, - Categories: [], - Transactions: [], - Assignments: [] }, mutations: { deleteBudget(state: State, budgetid: string) { @@ -73,15 +50,11 @@ export const store = createStore({ state.Session = restoredState.Session; state.CurrentBudgetID = restoredState.CurrentBudgetID; - state.CurrentAccountID = restoredState.CurrentAccountID; state.ShowMenu = restoredState.ShowMenu; for (const budget of restoredState.Budgets || []) { state.Budgets.set(budget[0], budget[1]); } - for (const account of restoredState.Accounts || []) { - state.Accounts.set(account[0], account[1]); - } }, [TITLE](state, title) { document.title = "Budgeteer - " + title; @@ -98,26 +71,13 @@ export const store = createStore({ addBudget(state, budget) { state.Budgets.set(budget.ID, budget); }, - addAccount(state, account) { - state.Accounts.set(account.ID, account); - }, - [LOGOUT](state, token) { + [LOGOUT](state) { state.Session = { Token: undefined, User: undefined }; state.Budgets.clear(); - state.Accounts.clear(); - state.Categories = []; - state.Transactions = []; - state.Assignments = []; }, setCurrentBudgetID(state, budgetid) { state.CurrentBudgetID = budgetid; }, - setCurrentAccountID(state, accountid) { - state.CurrentAccountID = accountid; - }, - setTransactions(state, transactions) { - state.Transactions = transactions; - } }, actions: { [LOGIN]({ state, commit }, login) { @@ -176,36 +136,15 @@ export const store = createStore({ for (const account of response.Accounts || []) { commit("addAccount", account); } + for (const category of response.Categories || []) { + commit("addCategory", category); + } }, - async [FETCH_ACCOUNT]({ state, commit, rootState }, accountid) { - const result = await fetch("/api/v1/account/" + accountid + "/transactions", { - headers: { - 'Authorization': 'Bearer ' + rootState.Session.Token - } - }); - const response = await result.json(); - commit("setTransactions", response.Transactions); - }, - async [SET_CURRENT_ACCOUNT]({ state, commit, dispatch, getters }, { budgetid, accountid }) { - if (budgetid == null) - return - - await dispatch(FETCH_BUDGET, budgetid); - commit("setCurrentAccountID", accountid); - if (accountid == null) - return - - commit(TITLE, getters.CurrentAccount.Name); - await dispatch(FETCH_ACCOUNT, accountid) - } }, getters: { Budgets(state) { return state.Budgets.values(); }, - Accounts(state) { - return state.Accounts.values(); - }, AuthHeaders(state) { return { 'Authorization': 'Bearer ' + state.Session.Token @@ -229,31 +168,20 @@ export const store = createStore({ return currentBudget.Name; return ""; }, - CurrentAccount(state) : Account | undefined { - if (state.CurrentAccountID == null) - return undefined; - return state.Accounts.get(state.CurrentAccountID); - }, - OnBudgetAccounts(state) { - return Array.from(state.Accounts.values()).filter(x => x.OnBudget); - }, - OffBudgetAccounts(state) { - return Array.from(state.Accounts.values()).filter(x => !x.OnBudget); - }, - Transactions(state) { - return (state.Transactions || []); - } }, - plugins: [createLogger()] + plugins: [createLogger()], + modules: { + budget: budgetStore + } }) store.subscribe((mutation, state) => { let persistedState = { Session: state.Session, Budgets: [...state.Budgets], - Accounts: [...state.Accounts], +// Accounts: [...state.Accounts], CurrentBudgetID: state.CurrentBudgetID, - CurrentAccountID: state.CurrentAccountID, + //CurrentAccountID: state.CurrentAccountID, ShowMenu: state.ShowMenu } localStorage.setItem("store", JSON.stringify(persistedState));