summaryrefslogtreecommitdiff
path: root/gui/src/types
diff options
context:
space:
mode:
Diffstat (limited to 'gui/src/types')
-rw-r--r--gui/src/types/BalanceToBudgetRatio.spec.ts307
-rw-r--r--gui/src/types/account.ts33
-rw-r--r--gui/src/types/balanceMap.ts17
-rw-r--r--gui/src/types/balanceToBudgetRatio.ts83
-rw-r--r--gui/src/types/budget.ts12
-rw-r--r--gui/src/types/budgetMap.ts16
-rw-r--r--gui/src/types/budgetUpdate.ts31
-rw-r--r--gui/src/types/category.ts48
-rw-r--r--gui/src/types/currency/currency.ts6
-rw-r--r--gui/src/types/currency/gbp.ts54
-rw-r--r--gui/src/types/group.ts8
11 files changed, 0 insertions, 615 deletions
diff --git a/gui/src/types/BalanceToBudgetRatio.spec.ts b/gui/src/types/BalanceToBudgetRatio.spec.ts
deleted file mode 100644
index 3a956ea..0000000
--- a/gui/src/types/BalanceToBudgetRatio.spec.ts
+++ /dev/null
@@ -1,307 +0,0 @@
-import { describe, expect, it } from "vitest";
-import { BalanceToBudgetRatio } from "./balanceToBudgetRatio";
-import { Gbp } from "./currency/gbp";
-
-describe("balanceToBudgetRatio", () => {
- it("new() returns null when budget is null", () => {
- const result = BalanceToBudgetRatio.new(new Gbp(1, 0, 1), null);
- expect(result).toBeNull();
- });
-
- it("toString() rounds to 2 decimal places", () => {
- const mockCurrencyPi = { valueOf: () => Math.PI };
- const mockCurrencyUnit = { valueOf: () => 1 };
- const sut = BalanceToBudgetRatio.new(mockCurrencyPi, {
- quantity: mockCurrencyUnit,
- period: 42,
- });
-
- const result = sut?.toString();
-
- expect(result).toBe("3.14");
- });
-
- it("new() sets normalisedRatio to 1 when balance and budget are equal and positive", () => {
- const twoFifty = new Gbp(2, 50, 1);
- const result = BalanceToBudgetRatio.new(twoFifty, {
- quantity: twoFifty,
- period: 42,
- });
- expect(result?.normalisedRatio).toBeCloseTo(1.0);
- });
-
- it("new() sets normalisedRatio to 2 when balance is twice budget", () => {
- const twoFifty = new Gbp(2, 50, 1);
- const oneTwentyFive = new Gbp(1, 25, 1);
- const result = BalanceToBudgetRatio.new(twoFifty, {
- quantity: oneTwentyFive,
- period: 42,
- });
- expect(result?.normalisedRatio).toBeCloseTo(2.0);
- });
-
- it("new() sets normalisedRatio to -2 when a negative balance is -1 * twice budget", () => {
- const minusTwoFifty = new Gbp(2, 50, -1);
- const oneTwentyFive = new Gbp(1, 25, 1);
- const result = BalanceToBudgetRatio.new(minusTwoFifty, {
- quantity: oneTwentyFive,
- period: 42,
- });
- expect(result?.normalisedRatio).toBeCloseTo(-2.0);
- });
-
- it("new() sets normalisedRatio to -0.5 when balance is -1 * half a negative budget", () => {
- const oneTwentyFive = new Gbp(1, 25, 1);
- const minusTwoFifty = new Gbp(2, 50, -1);
- const result = BalanceToBudgetRatio.new(oneTwentyFive, {
- quantity: minusTwoFifty,
- period: 42,
- });
- expect(result?.normalisedRatio).toBeCloseTo(-0.5);
- });
-
- it("new() sets normalisedRatio to 1 when balance and budget are equal and negative", () => {
- const minusTwoFifty = new Gbp(2, 50, -1);
- const result = BalanceToBudgetRatio.new(minusTwoFifty, {
- quantity: minusTwoFifty,
- period: 42,
- });
- expect(result?.normalisedRatio).toBeCloseTo(1.0);
- });
-
- it('new() sets recommended action to "arrears" when ratio is less than 0', () => {
- const oneTwentyFive = new Gbp(1, 25, 1);
- const minusTwoFifty = new Gbp(2, 50, -1);
-
- const result = BalanceToBudgetRatio.new(oneTwentyFive, {
- quantity: minusTwoFifty,
- period: 42,
- });
-
- expect(result?.recommendedAction).toBe("arrears");
- });
-
- it('new() sets recommended action to "save" when ratio is between 0 and 1', () => {
- const oneTwentyFive = new Gbp(1, 25, 1);
- const twoFifty = new Gbp(2, 50, 1);
-
- const result = BalanceToBudgetRatio.new(oneTwentyFive, {
- quantity: twoFifty,
- period: 42,
- });
-
- expect(result?.recommendedAction).toBe("save");
- });
-
- it('new() sets recommended action to "spend" when ratio is larger than 1', () => {
- const oneTwentyFive = new Gbp(1, 25, 1);
- const twoFifty = new Gbp(2, 50, 1);
-
- const result = BalanceToBudgetRatio.new(twoFifty, {
- quantity: oneTwentyFive,
- period: 42,
- });
-
- expect(result?.recommendedAction).toBe("spend");
- });
-
- it("normalises to a factor of 2 when all ratios are positive", () => {
- const oneTwentyFive = new Gbp(1, 25, 1);
- const twoFifty = new Gbp(2, 50, 1);
- const twoOverOne = BalanceToBudgetRatio.new(twoFifty, {
- quantity: oneTwentyFive,
- period: 42,
- });
- const twoOverTwo = BalanceToBudgetRatio.new(twoFifty, {
- quantity: twoFifty,
- period: 42,
- });
- const oneOverOne = BalanceToBudgetRatio.new(oneTwentyFive, {
- quantity: oneTwentyFive,
- period: 42,
- });
- const oneOverTwo = BalanceToBudgetRatio.new(oneTwentyFive, {
- quantity: twoFifty,
- period: 42,
- });
-
- const normaliser = BalanceToBudgetRatio.makeNormaliser(
- twoOverOne,
- twoOverTwo,
- oneOverOne,
- oneOverTwo,
- );
-
- expect(normaliser(twoOverOne).normalisedRatio).toBeCloseTo(1.0);
- expect(normaliser(twoOverTwo).normalisedRatio).toBeCloseTo(0.5);
- expect(normaliser(oneOverOne).normalisedRatio).toBeCloseTo(0.5);
- expect(normaliser(oneOverTwo).normalisedRatio).toBeCloseTo(0.25);
- });
-
- it("normalises to a factor of 2 when all ratios are negative", () => {
- const oneTwentyFive = new Gbp(1, 25, 1);
- const twoFifty = new Gbp(2, 50, 1);
- const minusOneTwentyFive = new Gbp(1, 25, -1);
- const minusTwoFifty = new Gbp(2, 50, -1);
- const minusTwoOverOne = BalanceToBudgetRatio.new(minusTwoFifty, {
- quantity: oneTwentyFive,
- period: 42,
- });
- const minusTwoOverTwo = BalanceToBudgetRatio.new(minusTwoFifty, {
- quantity: twoFifty,
- period: 42,
- });
- const minusOneOverOne = BalanceToBudgetRatio.new(minusOneTwentyFive, {
- quantity: oneTwentyFive,
- period: 42,
- });
- const minusOneOverTwo = BalanceToBudgetRatio.new(minusOneTwentyFive, {
- quantity: twoFifty,
- period: 42,
- });
-
- const normaliser = BalanceToBudgetRatio.makeNormaliser(
- minusTwoOverOne,
- minusTwoOverTwo,
- minusOneOverOne,
- minusOneOverTwo,
- );
-
- expect(normaliser(minusTwoOverOne).normalisedRatio).toBeCloseTo(-1.0);
- expect(normaliser(minusTwoOverTwo).normalisedRatio).toBeCloseTo(-0.5);
- expect(normaliser(minusOneOverOne).normalisedRatio).toBeCloseTo(-0.5);
- expect(normaliser(minusOneOverTwo).normalisedRatio).toBeCloseTo(-0.25);
- });
-
- it("normalises to a factor of 2 when ratios are a mix of positive and negative", () => {
- const oneTwentyFive = new Gbp(1, 25, 1);
- const twoFifty = new Gbp(2, 50, 1);
- const minusOneTwentyFive = new Gbp(1, 25, -1);
- const minusTwoFifty = new Gbp(2, 50, -1);
- const twoOverOne = BalanceToBudgetRatio.new(twoFifty, {
- quantity: oneTwentyFive,
- period: 42,
- });
- const twoOverTwo = BalanceToBudgetRatio.new(twoFifty, {
- quantity: twoFifty,
- period: 42,
- });
- const oneOverOne = BalanceToBudgetRatio.new(oneTwentyFive, {
- quantity: oneTwentyFive,
- period: 42,
- });
- const oneOverTwo = BalanceToBudgetRatio.new(oneTwentyFive, {
- quantity: twoFifty,
- period: 42,
- });
- const minusTwoOverOne = BalanceToBudgetRatio.new(minusTwoFifty, {
- quantity: oneTwentyFive,
- period: 42,
- });
- const minusTwoOverTwo = BalanceToBudgetRatio.new(minusTwoFifty, {
- quantity: twoFifty,
- period: 42,
- });
- const minusOneOverOne = BalanceToBudgetRatio.new(minusOneTwentyFive, {
- quantity: oneTwentyFive,
- period: 42,
- });
- const minusOneOverTwo = BalanceToBudgetRatio.new(minusOneTwentyFive, {
- quantity: twoFifty,
- period: 42,
- });
-
- const normaliser = BalanceToBudgetRatio.makeNormaliser(
- twoOverOne,
- twoOverTwo,
- oneOverOne,
- oneOverTwo,
- minusTwoOverOne,
- minusTwoOverTwo,
- minusOneOverOne,
- minusOneOverTwo,
- );
-
- expect(normaliser(twoOverOne).normalisedRatio).toBeCloseTo(1.0);
- expect(normaliser(twoOverTwo).normalisedRatio).toBeCloseTo(0.5);
- expect(normaliser(oneOverOne).normalisedRatio).toBeCloseTo(0.5);
- expect(normaliser(oneOverTwo).normalisedRatio).toBeCloseTo(0.25);
- expect(normaliser(minusTwoOverOne).normalisedRatio).toBeCloseTo(-1.0);
- expect(normaliser(minusTwoOverTwo).normalisedRatio).toBeCloseTo(-0.5);
- expect(normaliser(minusOneOverOne).normalisedRatio).toBeCloseTo(-0.5);
- expect(normaliser(minusOneOverTwo).normalisedRatio).toBeCloseTo(-0.25);
- });
-
- it("sorts large positive ratios before small positive ratios", () => {
- const oneTwentyFive = new Gbp(1, 25, 1);
- const twoFifty = new Gbp(2, 50, 1);
- const twoOverTwo = BalanceToBudgetRatio.new(twoFifty, {
- quantity: twoFifty,
- period: 42,
- });
- const oneOverTwo = BalanceToBudgetRatio.new(oneTwentyFive, {
- quantity: twoFifty,
- period: 42,
- });
-
- const resultLeftways = BalanceToBudgetRatio.compare(twoOverTwo, oneOverTwo);
- const resultRightways = BalanceToBudgetRatio.compare(
- oneOverTwo,
- twoOverTwo,
- );
-
- expect(resultLeftways).toBeCloseTo(-resultRightways);
- expect(resultLeftways).toBeLessThan(0);
- });
-
- it("sorts small negative ratios before large negative ratios", () => {
- const twoFifty = new Gbp(2, 50, 1);
- const minusOneTwentyFive = new Gbp(1, 25, -1);
- const minusTwoFifty = new Gbp(2, 50, -1);
- const minusTwoOverTwo = BalanceToBudgetRatio.new(minusTwoFifty, {
- quantity: twoFifty,
- period: 42,
- });
- const minusOneOverTwo = BalanceToBudgetRatio.new(minusOneTwentyFive, {
- quantity: twoFifty,
- period: 42,
- });
-
- const resultLeftways = BalanceToBudgetRatio.compare(
- minusOneOverTwo,
- minusTwoOverTwo,
- );
- const resultRightways = BalanceToBudgetRatio.compare(
- minusTwoOverTwo,
- minusOneOverTwo,
- );
-
- expect(resultLeftways).toBeCloseTo(-resultRightways);
- expect(resultLeftways).toBeLessThan(0);
- });
-
- it("sorts positive ratios before negative ratios", () => {
- const twoFifty = new Gbp(2, 50, 1);
- const minusTwoFifty = new Gbp(2, 50, -1);
- const twoOverTwo = BalanceToBudgetRatio.new(twoFifty, {
- quantity: twoFifty,
- period: 42,
- });
- const minusTwoOverTwo = BalanceToBudgetRatio.new(minusTwoFifty, {
- quantity: twoFifty,
- period: 42,
- });
-
- const resultLeftways = BalanceToBudgetRatio.compare(
- twoOverTwo,
- minusTwoOverTwo,
- );
- const resultRightways = BalanceToBudgetRatio.compare(
- minusTwoOverTwo,
- twoOverTwo,
- );
-
- expect(resultLeftways).toBeCloseTo(-resultRightways);
- expect(resultLeftways).toBeLessThan(0);
- });
-});
diff --git a/gui/src/types/account.ts b/gui/src/types/account.ts
deleted file mode 100644
index a463304..0000000
--- a/gui/src/types/account.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import moment, { Moment } from "moment";
-import Currency from "./currency/currency";
-import Gbp from "./currency/gbp";
-
-function newAccountFromDto(dto: unknown): Account {
- const dtoDangerous = dto as AccountDto;
- return {
- id: dtoDangerous.id,
- name: dtoDangerous.name,
- openingBalance: new Gbp(
- Math.floor(Math.abs(dtoDangerous.opening_balance) / 100),
- Math.abs(dtoDangerous.opening_balance) % 100,
- dtoDangerous.opening_balance < 0 ? -1 : 1,
- ),
- openingDate: moment(dtoDangerous.opening_date),
- };
-}
-
-interface AccountDto {
- readonly id: number;
- readonly name: string;
- readonly opening_balance: number;
- readonly opening_date: string;
-}
-
-interface Account {
- readonly id: number;
- readonly name: string;
- readonly openingBalance: Currency;
- readonly openingDate: Moment;
-}
-
-export { type Account, newAccountFromDto };
diff --git a/gui/src/types/balanceMap.ts b/gui/src/types/balanceMap.ts
deleted file mode 100644
index 760843f..0000000
--- a/gui/src/types/balanceMap.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { Category } from "./category";
-import Currency from "./currency/currency";
-import { newGbpFromDto } from "./currency/gbp";
-
-type BalanceMap<T extends { id: any }> = {
- [id in T["id"]]: Currency;
-};
-
-function newCategoryBalanceMapFromDto(dto: unknown): BalanceMap<Category> {
- return Object.fromEntries(
- (dto as { category_id: Category["id"]; balance: number }[]).map(
- ({ category_id, balance }) => [category_id, newGbpFromDto(balance)],
- ),
- );
-}
-
-export { type BalanceMap, newCategoryBalanceMapFromDto };
diff --git a/gui/src/types/balanceToBudgetRatio.ts b/gui/src/types/balanceToBudgetRatio.ts
deleted file mode 100644
index 2f8000c..0000000
--- a/gui/src/types/balanceToBudgetRatio.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-import { Budget } from "./budget";
-import Currency from "./currency/currency";
-
-class BalanceToBudgetRatio {
- toString(): string {
- return this._ratio?.toFixed(2) ?? "";
- }
-
- public readonly recommendedAction: "arrears" | "save" | "spend" | null;
- public readonly normalisedRatio: number | null;
-
- private constructor(
- private readonly _ratio: number | null,
- private readonly _normalisationFactor: number,
- ) {
- if (this._ratio === null) {
- this.normalisedRatio = null;
- this.recommendedAction = null;
- return;
- }
-
- this.normalisedRatio = this._ratio * this._normalisationFactor;
-
- if (this._ratio < 0) {
- this.recommendedAction = "arrears";
- } else if (this._ratio >= 1) {
- this.recommendedAction = "spend";
- } else {
- this.recommendedAction = "save";
- }
- }
-
- static new(balance: Currency, budget: Budget | null) {
- if (budget === null || budget.quantity === 0 || budget.quantity === -0) {
- return null;
- }
-
- return new BalanceToBudgetRatio(
- balance.valueOf() / budget.quantity.valueOf(),
- 1,
- );
- }
-
- static makeNormaliser(
- ...balanceToBudgetRatios: (BalanceToBudgetRatio | null)[]
- ): (r: BalanceToBudgetRatio | null) => BalanceToBudgetRatio {
- const validRatios = balanceToBudgetRatios.filter(
- (r) =>
- r &&
- r._ratio &&
- !isNaN(r._ratio) &&
- Infinity > r._ratio &&
- -Infinity < r._ratio,
- );
-
- const maxAbsRatio = Math.max(
- ...validRatios.map((r) => Math.abs(r?._ratio ?? 0)),
- );
-
- const normalisationFactor = 1 / maxAbsRatio;
- return (r) =>
- new BalanceToBudgetRatio(r?._ratio ?? null, normalisationFactor);
- }
-
- static compare(
- lhs: BalanceToBudgetRatio | null,
- rhs: BalanceToBudgetRatio | null,
- ): number {
- if (lhs === null || lhs._ratio === null) {
- if (rhs === null || rhs._ratio === null) {
- return 0;
- }
- return 1;
- }
- if (rhs === null || rhs._ratio === null) {
- return -1;
- }
-
- return rhs._ratio - lhs._ratio;
- }
-}
-
-export { BalanceToBudgetRatio };
diff --git a/gui/src/types/budget.ts b/gui/src/types/budget.ts
deleted file mode 100644
index 5a19a1b..0000000
--- a/gui/src/types/budget.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import Currency from "./currency/currency";
-
-interface Budget {
- quantity: Currency;
- period: number;
-}
-
-function newBudgetFromDto(dto: unknown) {
- return dto as Budget;
-}
-
-export { type Budget, newBudgetFromDto };
diff --git a/gui/src/types/budgetMap.ts b/gui/src/types/budgetMap.ts
deleted file mode 100644
index 5fa09f2..0000000
--- a/gui/src/types/budgetMap.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { Budget, newBudgetFromDto } from "./budget";
-import { Category } from "./category";
-
-type BudgetMap<T extends { id: any }> = {
- [id in T["id"]]: Budget | null;
-};
-
-function newCategoryBudgetMapFromDto(dto: unknown): BudgetMap<Category> {
- return Object.fromEntries(
- (dto as { category_id: number; budget: unknown }[]).map(
- ({ category_id, budget }) => [category_id, newBudgetFromDto(budget)],
- ),
- );
-}
-
-export { type BudgetMap, newCategoryBudgetMapFromDto as newBudgetMapFromDto };
diff --git a/gui/src/types/budgetUpdate.ts b/gui/src/types/budgetUpdate.ts
deleted file mode 100644
index 0696f8a..0000000
--- a/gui/src/types/budgetUpdate.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-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
deleted file mode 100644
index 9c2a651..0000000
--- a/gui/src/types/category.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import { BalanceMap } from "./balanceMap";
-import { BalanceToBudgetRatio } from "./balanceToBudgetRatio";
-import { Budget } from "./budget";
-import { BudgetMap } from "./budgetMap";
-import Currency from "./currency/currency";
-
-interface Category {
- id: number;
- name: string;
- groupName: string;
- currentBalance: Currency;
- currentBudget: Budget | null;
- balanceToBudgetRatio: BalanceToBudgetRatio | null;
-}
-
-interface CategoryDto {
- id: number;
- name: string;
- group: string;
-}
-
-function newCategoryFromDto(
- balances: BalanceMap<Category> | null,
- budgets: BudgetMap<Category> | null,
-): (dto: unknown) => Category | null {
- if (balances === null || budgets === null) {
- return () => null;
- }
-
- return function (dto: unknown): Category {
- const dtoDangerous = dto as CategoryDto;
- const currentBalance = balances[dtoDangerous.id];
- const currentBudget = budgets[dtoDangerous.id];
- return {
- id: dtoDangerous.id,
- name: dtoDangerous.name,
- groupName: dtoDangerous.group,
- currentBalance,
- currentBudget,
- balanceToBudgetRatio: BalanceToBudgetRatio.new(
- currentBalance,
- currentBudget,
- ),
- };
- };
-}
-
-export { type Category, newCategoryFromDto };
diff --git a/gui/src/types/currency/currency.ts b/gui/src/types/currency/currency.ts
deleted file mode 100644
index 7c15324..0000000
--- a/gui/src/types/currency/currency.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-interface Currency {
- valueOf(): number;
- toString(): string;
-}
-
-export default Currency;
diff --git a/gui/src/types/currency/gbp.ts b/gui/src/types/currency/gbp.ts
deleted file mode 100644
index b88aae3..0000000
--- a/gui/src/types/currency/gbp.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import Currency from "./currency";
-
-class Gbp implements Currency {
- private readonly sign: 1 | -1;
- private readonly pounds: number;
- private readonly pence: number;
-
- constructor(pounds: number, pence: number, sign?: 1 | -1) {
- sign = sign ?? 1;
-
- if (Math.round(pounds) !== pounds) {
- throw new Error(
- `Cannot construct GBP with non-whole number of pounds: ${pounds}`,
- );
- }
- if (Math.round(pence) !== pence) {
- throw new Error(
- `Cannot construct GBP with non-whole number of pence: ${pence}`,
- );
- }
- if (pounds < 0) {
- throw new Error(
- `Cannot construct GBP with negative number of pounds: ${pounds}`,
- );
- }
- if (pence < 0) {
- throw new Error(
- `Cannot construct GBP with negative number of pounds: ${pounds}`,
- );
- }
-
- this.sign = sign;
- this.pounds = pounds;
- this.pence = pence;
- }
-
- valueOf(): number {
- return this.sign * (this.pounds * 100 + this.pence);
- }
-
- toString(): string {
- return `£${this.pounds}·${this.pence < 10 ? `0${this.pence}` : this.pence}`;
- }
-}
-
-function newGbpFromDto(dto: unknown): Gbp {
- const signedPence = dto as number;
- const pounds = Math.floor(Math.abs(signedPence) / 100);
- const pence = Math.abs(signedPence) % 100;
- const sign = signedPence < 0 ? -1 : 1;
- return new Gbp(pounds, pence, sign);
-}
-
-export { Gbp, newGbpFromDto };
diff --git a/gui/src/types/group.ts b/gui/src/types/group.ts
deleted file mode 100644
index 4a04019..0000000
--- a/gui/src/types/group.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { Category } from "./category";
-
-interface Group {
- name: string;
- categories: Category[];
-}
-
-export { type Group };