summaryrefslogtreecommitdiff
path: root/gui/src
diff options
context:
space:
mode:
Diffstat (limited to 'gui/src')
-rw-r--r--gui/src/ajax/backend.ts8
-rw-r--r--gui/src/components/BudgetUpdatesTable/BudgetUpdatesTable.css (renamed from gui/src/components/app/App.css)0
-rw-r--r--gui/src/components/BudgetUpdatesTable/BudgetUpdatesTable.tsx36
-rw-r--r--gui/src/components/histogram/Histogram.tsx32
-rw-r--r--gui/src/index.tsx2
-rw-r--r--gui/src/types/budgetUpdate.ts31
-rw-r--r--gui/src/types/category.ts3
-rw-r--r--gui/src/types/group.ts8
-rw-r--r--gui/src/util/groupCategories.ts12
-rw-r--r--gui/src/views/App.css5
-rw-r--r--gui/src/views/App.tsx19
-rw-r--r--gui/src/views/budgetUpdatesTable/BudgetUpdatesTableView.css10
-rw-r--r--gui/src/views/budgetUpdatesTable/BudgetUpdatesTableView.tsx32
-rw-r--r--gui/src/views/histogram/HistogramView.tsx (renamed from gui/src/components/app/App.tsx)14
14 files changed, 195 insertions, 17 deletions
diff --git a/gui/src/ajax/backend.ts b/gui/src/ajax/backend.ts
index 90a7ea5..4a2462f 100644
--- a/gui/src/ajax/backend.ts
+++ b/gui/src/ajax/backend.ts
@@ -1,5 +1,6 @@
import { BalanceMap, newCategoryBalanceMapFromDto } from "../types/balanceMap";
import { BudgetMap, newBudgetMapFromDto } from "../types/budgetMap";
+import { BudgetUpdate, newBudgetUpdateFromDto } from "../types/budgetUpdate";
import { Category, newCategoryFromDto } from "../types/category";
const backendUrl = "http://localhost:8000";
@@ -23,6 +24,13 @@ function makeGetter<T>(params: FetcherMakerParams<T>): Getter<T> {
};
}
+export const getAllBudgetUpdates: Getter<BudgetUpdate[]> = makeGetter<
+ BudgetUpdate[]
+>({
+ path: "/budget-update",
+ elementParser: newBudgetUpdateFromDto,
+});
+
export const getAllCategories: Getter<Category[]> = async () => {
const balances = await getAllCategoryBalances();
const budgets = await getAllCurrentCategoryBudgets();
diff --git a/gui/src/components/app/App.css b/gui/src/components/BudgetUpdatesTable/BudgetUpdatesTable.css
index 8b13789..8b13789 100644
--- a/gui/src/components/app/App.css
+++ b/gui/src/components/BudgetUpdatesTable/BudgetUpdatesTable.css
diff --git a/gui/src/components/BudgetUpdatesTable/BudgetUpdatesTable.tsx b/gui/src/components/BudgetUpdatesTable/BudgetUpdatesTable.tsx
new file mode 100644
index 0000000..479d69f
--- /dev/null
+++ b/gui/src/components/BudgetUpdatesTable/BudgetUpdatesTable.tsx
@@ -0,0 +1,36 @@
+import { BudgetUpdate } from '../../types/budgetUpdate';
+import './BudgetUpdatesTable.css';
+
+function BudgetUpdatesTable({ budgetUpdates }: Props) {
+ return (
+ <table>
+ <thead>
+ <tr>
+ <td>Date</td>
+ <td>Quantity</td>
+ <td>Period</td>
+ </tr>
+ </thead>
+
+ <tbody>
+ { budgetUpdates.map(Row) }
+ </tbody>
+ </table>
+ );
+}
+
+function Row(budgetUpdate: BudgetUpdate) {
+ return (
+ <tr>
+ <td>{budgetUpdate.date.format("DD Mm YYYY")}</td>
+ <td>{budgetUpdate.newQuantity.toString()}</td>
+ <td>{budgetUpdate.newPeriod}</td>
+ </tr>
+ )
+}
+
+type Props = {
+ budgetUpdates: BudgetUpdate[];
+}
+
+export { BudgetUpdatesTable };
diff --git a/gui/src/components/histogram/Histogram.tsx b/gui/src/components/histogram/Histogram.tsx
index 3a8309b..1dd8c65 100644
--- a/gui/src/components/histogram/Histogram.tsx
+++ b/gui/src/components/histogram/Histogram.tsx
@@ -1,5 +1,7 @@
import { BalanceToBudgetRatio } from "../../types/balanceToBudgetRatio";
import { Category } from "../../types/category";
+import { Group } from "../../types/group";
+import { groupCategories } from "../../util/groupCategories";
import './Histogram.scss';
function Histogram({ categories }: Props) {
@@ -14,6 +16,8 @@ function Histogram({ categories }: Props) {
category.balanceToBudgetRatio = balanceToBudgetRatioNormaliser(category.balanceToBudgetRatio);
}
+ const groups = [...groupCategories(categories)];
+
return (
<table>
<thead>
@@ -23,18 +27,26 @@ function Histogram({ categories }: Props) {
<th>Balance</th>
</tr>
</thead>
-
- <tbody>
- {
- categories
- .sort((c1, c2) => BalanceToBudgetRatio.compare(c1.balanceToBudgetRatio, c2.balanceToBudgetRatio))
- .map((category) => Row({ category }))
- }
- </tbody>
+ {
+ groups.map(g => <RowGroup group={g} />)
+ }
</table>
);
}
+function RowGroup({ group }: GroupProps) {
+ return (
+ <tbody>
+ <tr role="heading" aria-level="3">{group.name}</tr>
+ {
+ group.categories
+ .sort((c1, c2) => BalanceToBudgetRatio.compare(c1.balanceToBudgetRatio, c2.balanceToBudgetRatio))
+ .map((category) => Row({ category }))
+ }
+ </tbody>
+ );
+}
+
function Row({ category }: RowProps) {
return (
<tr>
@@ -57,6 +69,10 @@ type Props = {
categories: Category[] | null,
};
+type GroupProps = {
+ group: Group;
+}
+
type RowProps = {
category: Category,
};
diff --git a/gui/src/index.tsx b/gui/src/index.tsx
index eec284c..d2f18a0 100644
--- a/gui/src/index.tsx
+++ b/gui/src/index.tsx
@@ -2,7 +2,7 @@
import { render } from 'solid-js/web'
import './index.css'
-import App from './components/app/App'
+import App from './views/App'
const root = document.getElementById('root')
diff --git a/gui/src/types/budgetUpdate.ts b/gui/src/types/budgetUpdate.ts
new file mode 100644
index 0000000..0696f8a
--- /dev/null
+++ b/gui/src/types/budgetUpdate.ts
@@ -0,0 +1,31 @@
+import moment, { Moment } from "moment";
+import Currency from "./currency/currency";
+
+interface BudgetUpdate {
+ id: number;
+ categoryId: number;
+ date: Moment;
+ newQuantity: Currency;
+ newPeriod: number;
+}
+
+interface BudgetUpdateDto {
+ id: number;
+ category_id: number;
+ date: string;
+ new_budget: number;
+ new_period: number;
+}
+
+function newBudgetUpdateFromDto(dto: unknown): BudgetUpdate {
+ const typedDto = dto as BudgetUpdateDto;
+ return {
+ id: typedDto.id,
+ categoryId: typedDto.category_id,
+ date: moment(typedDto.date),
+ newQuantity: typedDto.new_budget,
+ newPeriod: typedDto.new_period,
+ };
+}
+
+export { type BudgetUpdate, type BudgetUpdateDto, newBudgetUpdateFromDto };
diff --git a/gui/src/types/category.ts b/gui/src/types/category.ts
index 005c041..9c2a651 100644
--- a/gui/src/types/category.ts
+++ b/gui/src/types/category.ts
@@ -7,6 +7,7 @@ import Currency from "./currency/currency";
interface Category {
id: number;
name: string;
+ groupName: string;
currentBalance: Currency;
currentBudget: Budget | null;
balanceToBudgetRatio: BalanceToBudgetRatio | null;
@@ -15,6 +16,7 @@ interface Category {
interface CategoryDto {
id: number;
name: string;
+ group: string;
}
function newCategoryFromDto(
@@ -32,6 +34,7 @@ function newCategoryFromDto(
return {
id: dtoDangerous.id,
name: dtoDangerous.name,
+ groupName: dtoDangerous.group,
currentBalance,
currentBudget,
balanceToBudgetRatio: BalanceToBudgetRatio.new(
diff --git a/gui/src/types/group.ts b/gui/src/types/group.ts
new file mode 100644
index 0000000..4a04019
--- /dev/null
+++ b/gui/src/types/group.ts
@@ -0,0 +1,8 @@
+import { Category } from "./category";
+
+interface Group {
+ name: string;
+ categories: Category[];
+}
+
+export { type Group };
diff --git a/gui/src/util/groupCategories.ts b/gui/src/util/groupCategories.ts
new file mode 100644
index 0000000..a0336ea
--- /dev/null
+++ b/gui/src/util/groupCategories.ts
@@ -0,0 +1,12 @@
+import { Category } from "../types/category";
+import { Group } from "../types/group";
+
+export function* groupCategories(categories: Category[]): Generator<Group> {
+ const groupNames = new Set(categories.map(c => c.groupName));
+ for (const name of groupNames) {
+ yield {
+ name,
+ categories: categories.filter(c => c.groupName === name)
+ };
+ }
+}
diff --git a/gui/src/views/App.css b/gui/src/views/App.css
new file mode 100644
index 0000000..9775b76
--- /dev/null
+++ b/gui/src/views/App.css
@@ -0,0 +1,5 @@
+div {
+ display: flex;
+ justify-content: space-evenly;
+ width: 100%;
+}
diff --git a/gui/src/views/App.tsx b/gui/src/views/App.tsx
new file mode 100644
index 0000000..80eb051
--- /dev/null
+++ b/gui/src/views/App.tsx
@@ -0,0 +1,19 @@
+import { createResource } from 'solid-js';
+import './App.css'
+import { getAllBudgetUpdates, getAllCategories } from '../ajax/backend';
+import { HistogramView } from './histogram/HistogramView';
+import { BudgetUpdatesTableView } from './budgetUpdatesTable/BudgetUpdatesTableView';
+
+function App() {
+ const [categories] = createResource(getAllCategories);
+ const [budgetUpdates] = createResource(getAllBudgetUpdates);
+
+ return (
+ <div>
+ <HistogramView categories={categories} />
+ <BudgetUpdatesTableView budgetUpdates={budgetUpdates} categories={categories} />
+ </div>
+ );
+}
+
+export default App
diff --git a/gui/src/views/budgetUpdatesTable/BudgetUpdatesTableView.css b/gui/src/views/budgetUpdatesTable/BudgetUpdatesTableView.css
new file mode 100644
index 0000000..e862976
--- /dev/null
+++ b/gui/src/views/budgetUpdatesTable/BudgetUpdatesTableView.css
@@ -0,0 +1,10 @@
+div {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+}
+
+form {
+ display: flex;
+ gap: 1rem;
+}
diff --git a/gui/src/views/budgetUpdatesTable/BudgetUpdatesTableView.tsx b/gui/src/views/budgetUpdatesTable/BudgetUpdatesTableView.tsx
new file mode 100644
index 0000000..465ea92
--- /dev/null
+++ b/gui/src/views/budgetUpdatesTable/BudgetUpdatesTableView.tsx
@@ -0,0 +1,32 @@
+import { createSignal, Match, Resource, Switch } from 'solid-js';
+import { BudgetUpdate } from '../../types/budgetUpdate';
+import { BudgetUpdatesTable } from '../../components/BudgetUpdatesTable/BudgetUpdatesTable';
+import { Category } from '../../types/category';
+import './BudgetUpdatesTableView.css';
+
+export function BudgetUpdatesTableView({ budgetUpdates, categories }: Props) {
+ const [newCategoryId, setCategoryId] = createSignal<number>();
+
+ const filteredAndSortedBudgetUpdates: BudgetUpdate[] = budgetUpdates()
+ ?.filter((bu) => bu.categoryId === newCategoryId())
+ ?.sort((bu1, bu2) => bu2.date.diff(bu1.date))
+ ?? [];
+
+ return (
+ <div>
+ <form action="none">
+ <label for="category">Category</label>
+ <select id="category" onChange={(e) => setCategoryId(Number(e.target.value))}>
+ {(categories() ?? []).map((c) =>
+ <option value={c.id}>{c.name}</option>)}
+ </select>
+ </form>
+ <BudgetUpdatesTable budgetUpdates={filteredAndSortedBudgetUpdates as BudgetUpdate[]} />
+ </div>
+ );
+}
+
+type Props = {
+ budgetUpdates: Resource<BudgetUpdate[] | null>;
+ categories: Resource<Category[] | null>;
+}
diff --git a/gui/src/components/app/App.tsx b/gui/src/views/histogram/HistogramView.tsx
index e9ef742..30e64ca 100644
--- a/gui/src/components/app/App.tsx
+++ b/gui/src/views/histogram/HistogramView.tsx
@@ -1,12 +1,8 @@
-import { createResource, Match, Resource, Switch } from 'solid-js';
-import Histogram from '../histogram/Histogram'
-import './App.css'
-import { getAllCategories } from '../../ajax/backend';
+import { Match, Resource, Switch } from 'solid-js';
+import Histogram from '../../components/histogram/Histogram'
import { Category } from '../../types/category';
-function App() {
- const [categories] = createResource(getAllCategories);
-
+export function HistogramView({ categories }: Props) {
return (
<Switch>
<Match when={categories.state === 'ready'}>
@@ -30,4 +26,6 @@ function App() {
);
}
-export default App
+type Props = {
+ categories: Resource<Category[] | null>;
+}