From 5824c353f978a5b9ab9696451ee3014c6a614ffc Mon Sep 17 00:00:00 2001 From: Joe Carstairs Date: Tue, 22 Oct 2024 07:46:43 +0100 Subject: Refactors importer to use core stuff --- gui/src/ajax/backend.ts | 8 +++++ .../BudgetUpdatesTable/BudgetUpdatesTable.css | 1 + .../BudgetUpdatesTable/BudgetUpdatesTable.tsx | 36 ++++++++++++++++++++++ gui/src/components/app/App.css | 1 - gui/src/components/app/App.tsx | 33 -------------------- gui/src/components/histogram/Histogram.tsx | 32 ++++++++++++++----- gui/src/index.tsx | 2 +- gui/src/types/budgetUpdate.ts | 31 +++++++++++++++++++ gui/src/types/category.ts | 3 ++ gui/src/types/group.ts | 8 +++++ gui/src/util/groupCategories.ts | 12 ++++++++ gui/src/views/App.css | 5 +++ gui/src/views/App.tsx | 19 ++++++++++++ .../budgetUpdatesTable/BudgetUpdatesTableView.css | 10 ++++++ .../budgetUpdatesTable/BudgetUpdatesTableView.tsx | 32 +++++++++++++++++++ gui/src/views/histogram/HistogramView.tsx | 31 +++++++++++++++++++ 16 files changed, 221 insertions(+), 43 deletions(-) create mode 100644 gui/src/components/BudgetUpdatesTable/BudgetUpdatesTable.css create mode 100644 gui/src/components/BudgetUpdatesTable/BudgetUpdatesTable.tsx delete mode 100644 gui/src/components/app/App.css delete mode 100644 gui/src/components/app/App.tsx create mode 100644 gui/src/types/budgetUpdate.ts create mode 100644 gui/src/types/group.ts create mode 100644 gui/src/util/groupCategories.ts create mode 100644 gui/src/views/App.css create mode 100644 gui/src/views/App.tsx create mode 100644 gui/src/views/budgetUpdatesTable/BudgetUpdatesTableView.css create mode 100644 gui/src/views/budgetUpdatesTable/BudgetUpdatesTableView.tsx create mode 100644 gui/src/views/histogram/HistogramView.tsx (limited to 'gui') 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(params: FetcherMakerParams): Getter { }; } +export const getAllBudgetUpdates: Getter = makeGetter< + BudgetUpdate[] +>({ + path: "/budget-update", + elementParser: newBudgetUpdateFromDto, +}); + export const getAllCategories: Getter = async () => { const balances = await getAllCategoryBalances(); const budgets = await getAllCurrentCategoryBudgets(); diff --git a/gui/src/components/BudgetUpdatesTable/BudgetUpdatesTable.css b/gui/src/components/BudgetUpdatesTable/BudgetUpdatesTable.css new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/gui/src/components/BudgetUpdatesTable/BudgetUpdatesTable.css @@ -0,0 +1 @@ + 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 ( + + + + + + + + + + + { budgetUpdates.map(Row) } + +
DateQuantityPeriod
+ ); +} + +function Row(budgetUpdate: BudgetUpdate) { + return ( + + {budgetUpdate.date.format("DD Mm YYYY")} + {budgetUpdate.newQuantity.toString()} + {budgetUpdate.newPeriod} + + ) +} + +type Props = { + budgetUpdates: BudgetUpdate[]; +} + +export { BudgetUpdatesTable }; diff --git a/gui/src/components/app/App.css b/gui/src/components/app/App.css deleted file mode 100644 index 8b13789..0000000 --- a/gui/src/components/app/App.css +++ /dev/null @@ -1 +0,0 @@ - diff --git a/gui/src/components/app/App.tsx b/gui/src/components/app/App.tsx deleted file mode 100644 index e9ef742..0000000 --- a/gui/src/components/app/App.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { createResource, Match, Resource, Switch } from 'solid-js'; -import Histogram from '../histogram/Histogram' -import './App.css' -import { getAllCategories } from '../../ajax/backend'; -import { Category } from '../../types/category'; - -function App() { - const [categories] = createResource(getAllCategories); - - return ( - - - , { state: 'ready' }>)()} /> - - -

Loading...

-
- -

Unresolved!

-
- -

Error!

-

{JSON.stringify(categories.error, null, 2)}

-

{JSON.stringify(categories(), null, 2)}

-
- -

Refreshing!

-
-
- ); -} - -export default App 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 ( @@ -23,18 +27,26 @@ function Histogram({ categories }: Props) { - - - { - categories - .sort((c1, c2) => BalanceToBudgetRatio.compare(c1.balanceToBudgetRatio, c2.balanceToBudgetRatio)) - .map((category) => Row({ category })) - } - + { + groups.map(g => ) + }
Balance
); } +function RowGroup({ group }: GroupProps) { + return ( + + {group.name} + { + group.categories + .sort((c1, c2) => BalanceToBudgetRatio.compare(c1.balanceToBudgetRatio, c2.balanceToBudgetRatio)) + .map((category) => Row({ category })) + } + + ); +} + function Row({ category }: RowProps) { return ( @@ -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 { + 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 ( +
+ + +
+ ); +} + +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(); + + const filteredAndSortedBudgetUpdates: BudgetUpdate[] = budgetUpdates() + ?.filter((bu) => bu.categoryId === newCategoryId()) + ?.sort((bu1, bu2) => bu2.date.diff(bu1.date)) + ?? []; + + return ( +
+
+ + +
+ +
+ ); +} + +type Props = { + budgetUpdates: Resource; + categories: Resource; +} diff --git a/gui/src/views/histogram/HistogramView.tsx b/gui/src/views/histogram/HistogramView.tsx new file mode 100644 index 0000000..30e64ca --- /dev/null +++ b/gui/src/views/histogram/HistogramView.tsx @@ -0,0 +1,31 @@ +import { Match, Resource, Switch } from 'solid-js'; +import Histogram from '../../components/histogram/Histogram' +import { Category } from '../../types/category'; + +export function HistogramView({ categories }: Props) { + return ( + + + , { state: 'ready' }>)()} /> + + +

Loading...

+
+ +

Unresolved!

+
+ +

Error!

+

{JSON.stringify(categories.error, null, 2)}

+

{JSON.stringify(categories(), null, 2)}

+
+ +

Refreshing!

+
+
+ ); +} + +type Props = { + categories: Resource; +} -- cgit v1.2.3