From 2bac81fa9130c80bb1d97978fa393a15f18da215 Mon Sep 17 00:00:00 2001 From: Robert Lucas <100799838+Robert-M-Lucas@users.noreply.github.com> Date: Mon, 29 Apr 2024 17:24:32 +0100 Subject: [PATCH] Added Graphs --- src/pages/dashboard/DashboardPage.tsx | 18 +++- .../graph tiles/BalanceGraphTile.tsx | 70 ++++++++++++++++ .../graph tiles/ExpenseGraphTile.tsx | 72 ++++++++++++++++ .../dashboard/graph tiles/IncomeGraphTile.tsx | 72 ++++++++++++++++ .../dashboard/graph tiles/NeedsGraphTile.tsx | 81 ++++++++++++++++++ .../graph tiles/SavingsGraphTile.tsx | 83 +++++++++++++++++++ .../dashboard/graph tiles/WantsGraphTile.tsx | 81 ++++++++++++++++++ 7 files changed, 474 insertions(+), 3 deletions(-) create mode 100644 src/pages/dashboard/graph tiles/BalanceGraphTile.tsx create mode 100644 src/pages/dashboard/graph tiles/ExpenseGraphTile.tsx create mode 100644 src/pages/dashboard/graph tiles/IncomeGraphTile.tsx create mode 100644 src/pages/dashboard/graph tiles/NeedsGraphTile.tsx create mode 100644 src/pages/dashboard/graph tiles/SavingsGraphTile.tsx create mode 100644 src/pages/dashboard/graph tiles/WantsGraphTile.tsx diff --git a/src/pages/dashboard/DashboardPage.tsx b/src/pages/dashboard/DashboardPage.tsx index c865d81..65d7739 100644 --- a/src/pages/dashboard/DashboardPage.tsx +++ b/src/pages/dashboard/DashboardPage.tsx @@ -20,6 +20,12 @@ import goalTracking from "./goal tracking tile/GoalTrackingTile.tsx"; import motivationTile from "./motivation tile/MotivationTile.tsx"; import AddTransactionTile from "./add transaction tile/AddTransactionTile.tsx"; import tipOfTheDayTile from "./tip of the day tile/TipOfTheDayTile.tsx"; +import savingsGraphTile from "./graph tiles/SavingsGraphTile.tsx"; +import needsGraphTile from "./graph tiles/NeedsGraphTile.tsx"; +import wantsGraphTile from "./graph tiles/WantsGraphTile.tsx"; +import balanceGraphTile from "./graph tiles/BalanceGraphTile.tsx"; +import incomeGraphTile from "./graph tiles/IncomeGraphTile.tsx"; +import expenseGraphTile from "./graph tiles/ExpenseGraphTile.tsx"; export default function Dashboard() { // const [balance, setBalance] = useState(0); @@ -109,12 +115,18 @@ export default function Dashboard() { TileElement.newTSX(() => totalTile(transactions), 2, 1, columns), TileElement.newTSX(() => (goalSettingTile(userPrefs, forceUpdatePrefs)), 2, 2, columns), TileElement.newTSX(tipOfTheDayTile, 2, 1, columns), + TileElement.newTSX(() => savingsGraphTile(transactions, userPrefs), 3, 2, columns), + TileElement.newTSX(() => needsGraphTile(transactions, userPrefs), 3, 2, columns), + TileElement.newTSX(() => wantsGraphTile(transactions, userPrefs), 3, 2, columns), + TileElement.newTSX(() => balanceGraphTile(transactions), 3, 2, columns), + TileElement.newTSX(() => incomeGraphTile(transactions), 3, 2, columns), + TileElement.newTSX(() => expenseGraphTile(transactions), 3, 2, columns), TileElement.newTSX(() => goalTracking(transactions, userPrefs), 3, 1, columns), TileElement.newTSX(() => motivationTile(transactions, userPrefs), 1, 1, columns), TileElement.newTSX(() => AddTransactionTile(forceUpdateTransactions), 1, 1, columns), - TileElement.newGraph(transactionPoints.raw, 3, 2, columns), - TileElement.newGraph(transactionPoints.in, 3, 2, columns), - TileElement.newGraph(transactionPoints.out, 3, 2, columns), + // TileElement.newGraph(transactionPoints.raw, 3, 2, columns), + // TileElement.newGraph(transactionPoints.in, 3, 2, columns), + // TileElement.newGraph(transactionPoints.out, 3, 2, columns), ]; const renderTile: RenderTileFunction = ({ data, isDragging }) => ( diff --git a/src/pages/dashboard/graph tiles/BalanceGraphTile.tsx b/src/pages/dashboard/graph tiles/BalanceGraphTile.tsx new file mode 100644 index 0000000..0736ea4 --- /dev/null +++ b/src/pages/dashboard/graph tiles/BalanceGraphTile.tsx @@ -0,0 +1,70 @@ +import {Line, LineChart, ResponsiveContainer, Tooltip, XAxis, YAxis} from "recharts"; +import {Transaction} from "../../../utils/transaction.ts"; +import strftime from "strftime"; +import {round} from "lodash"; + +export default function balanceGraphTile(transactions: Transaction[]) { + const data: { + date: string, + amount: number, + }[] = []; + + let currentBalance = 0; + + if (transactions.length == 0) { + return

No Data

; + } + + const revTransactions = transactions.slice().reverse(); + + let currentDate = revTransactions[0].dateTime; + + for (const transaction of revTransactions) { + const transDate = strftime("%d/%m/%y", new Date(transaction.dateTime)); + + // eslint-disable-next-line no-constant-condition + while (true) { + const date = strftime("%d/%m/%y", new Date(currentDate)); + if (date === transDate) { + break; + } + if (date === data[data.length - 1].date) { + currentDate += 8.64e7; + continue; + } + data.push( + { + date: date, + amount: round(currentBalance, 2), + } + ) + currentDate += 8.64e7; + } + + currentBalance += transaction.amount; + + const val = { + date: transDate, + amount: round(currentBalance, 2), + }; + + if (data.length > 0 && data[data.length - 1].date === transDate) { + data[data.length - 1] = val; + } + else { + data.push(val) + } + } + + return <> +

Balance

+ + + + + + + + + ; +} \ No newline at end of file diff --git a/src/pages/dashboard/graph tiles/ExpenseGraphTile.tsx b/src/pages/dashboard/graph tiles/ExpenseGraphTile.tsx new file mode 100644 index 0000000..8fae29c --- /dev/null +++ b/src/pages/dashboard/graph tiles/ExpenseGraphTile.tsx @@ -0,0 +1,72 @@ +import {Line, LineChart, ResponsiveContainer, Tooltip, XAxis, YAxis} from "recharts"; +import {Transaction} from "../../../utils/transaction.ts"; +import strftime from "strftime"; +import {round} from "lodash"; + +export default function expenseGraphTile(transactions: Transaction[]) { + const data: { + date: string, + amount: number, + }[] = []; + + let currentExpenses = 0; + + if (transactions.length == 0) { + return

No Data

; + } + + const revTransactions = transactions.slice().reverse(); + + let currentDate = revTransactions[0].dateTime; + + for (const transaction of revTransactions) { + const transDate = strftime("%d/%m/%y", new Date(transaction.dateTime)); + + // eslint-disable-next-line no-constant-condition + while (true) { + const date = strftime("%d/%m/%y", new Date(currentDate)); + if (date === transDate) { + break; + } + if (date === data[data.length - 1].date) { + currentDate += 8.64e7; + continue; + } + data.push( + { + date: date, + amount: round(-currentExpenses, 2), + } + ) + currentDate += 8.64e7; + } + + if (transaction.amount < 0) { + currentExpenses += transaction.amount; + } + + const val = { + date: transDate, + amount: round(-currentExpenses, 2), + }; + + if (data.length > 0 && data[data.length - 1].date === transDate) { + data[data.length - 1] = val; + } + else { + data.push(val) + } + } + + return <> +

Expenses

+ + + + + + + + + ; +} \ No newline at end of file diff --git a/src/pages/dashboard/graph tiles/IncomeGraphTile.tsx b/src/pages/dashboard/graph tiles/IncomeGraphTile.tsx new file mode 100644 index 0000000..dc82e91 --- /dev/null +++ b/src/pages/dashboard/graph tiles/IncomeGraphTile.tsx @@ -0,0 +1,72 @@ +import {Line, LineChart, ResponsiveContainer, Tooltip, XAxis, YAxis} from "recharts"; +import {Transaction} from "../../../utils/transaction.ts"; +import strftime from "strftime"; +import {round} from "lodash"; + +export default function incomeGraphTile(transactions: Transaction[]) { + const data: { + date: string, + amount: number, + }[] = []; + + let currentIncome = 0; + + if (transactions.length == 0) { + return

No Data

; + } + + const revTransactions = transactions.slice().reverse(); + + let currentDate = revTransactions[0].dateTime; + + for (const transaction of revTransactions) { + const transDate = strftime("%d/%m/%y", new Date(transaction.dateTime)); + + // eslint-disable-next-line no-constant-condition + while (true) { + const date = strftime("%d/%m/%y", new Date(currentDate)); + if (date === transDate) { + break; + } + if (date === data[data.length - 1].date) { + currentDate += 8.64e7; + continue; + } + data.push( + { + date: date, + amount: round(currentIncome, 2), + } + ) + currentDate += 8.64e7; + } + + if (transaction.amount > 0) { + currentIncome += transaction.amount; + } + + const val = { + date: transDate, + amount: round(currentIncome, 2), + }; + + if (data.length > 0 && data[data.length - 1].date === transDate) { + data[data.length - 1] = val; + } + else { + data.push(val) + } + } + + return <> +

Income

+ + + + + + + + + ; +} \ No newline at end of file diff --git a/src/pages/dashboard/graph tiles/NeedsGraphTile.tsx b/src/pages/dashboard/graph tiles/NeedsGraphTile.tsx new file mode 100644 index 0000000..472fd96 --- /dev/null +++ b/src/pages/dashboard/graph tiles/NeedsGraphTile.tsx @@ -0,0 +1,81 @@ +import {Line, LineChart, ResponsiveContainer, Tooltip, XAxis, YAxis} from "recharts"; +import {Transaction} from "../../../utils/transaction.ts"; +import {UserPrefs} from "../../../utils/user_prefs.ts"; +import strftime from "strftime"; +import {round} from "lodash"; + +export default function needsGraphTile(transactions: Transaction[], userPrefs: UserPrefs) { + const data: { + date: string, + amount: number, + goal: number + }[] = []; + + let currentIncome = 0; + let currentNeeds = 0; + + if (transactions.length == 0) { + return

No Data

; + } + + const revTransactions = transactions.slice().reverse(); + + let currentDate = revTransactions[0].dateTime; + + for (const transaction of revTransactions) { + const transDate = strftime("%d/%m/%y", new Date(transaction.dateTime)); + + // eslint-disable-next-line no-constant-condition + while (true) { + const date = strftime("%d/%m/%y", new Date(currentDate)); + if (date === transDate) { + break; + } + if (date === data[data.length - 1].date) { + currentDate += 8.64e7; + continue; + } + data.push( + { + date: date, + amount: round(-currentNeeds, 2), + goal: round(currentIncome * userPrefs.getNeedsBudget(), 2), + } + ) + currentDate += 8.64e7; + } + + if (transaction.amount > 0) { + currentIncome += transaction.amount; + } + if (transaction.getCategoryCategory() == "Needs") { + currentNeeds += transaction.amount; + } + + const val = { + date: transDate, + amount: round(-currentNeeds, 2), + goal: round(currentIncome * userPrefs.getNeedsBudget(), 2), + }; + + if (data.length > 0 && data[data.length - 1].date === transDate) { + data[data.length - 1] = val; + } + else { + data.push(val) + } + } + + return <> +

Needs

+ + + + + + + + + + ; +} \ No newline at end of file diff --git a/src/pages/dashboard/graph tiles/SavingsGraphTile.tsx b/src/pages/dashboard/graph tiles/SavingsGraphTile.tsx new file mode 100644 index 0000000..25fd02a --- /dev/null +++ b/src/pages/dashboard/graph tiles/SavingsGraphTile.tsx @@ -0,0 +1,83 @@ +import {Line, LineChart, ResponsiveContainer, Tooltip, XAxis, YAxis} from "recharts"; +import {Transaction} from "../../../utils/transaction.ts"; +import {UserPrefs} from "../../../utils/user_prefs.ts"; +import strftime from "strftime"; +import {round} from "lodash"; + +export default function savingsGraphTile(transactions: Transaction[], userPrefs: UserPrefs) { + const data: { + date: string, + amount: number, + goal: number + }[] = []; + + let currentIncome = 0; + let currentSavings = 0; + let currentBalance = 0; + + if (transactions.length == 0) { + return

No Data

; + } + + const revTransactions = transactions.slice().reverse(); + + let currentDate = revTransactions[0].dateTime; + + for (const transaction of revTransactions) { + const transDate = strftime("%d/%m/%y", new Date(transaction.dateTime)); + + // eslint-disable-next-line no-constant-condition + while (true) { + const date = strftime("%d/%m/%y", new Date(currentDate)); + if (date === transDate) { + break; + } + if (date === data[data.length - 1].date) { + currentDate += 8.64e7; + continue; + } + data.push( + { + date: date, + amount: round(currentSavings + currentBalance, 2), + goal: round(currentIncome * userPrefs.getSavingsBudget(), 2), + } + ) + currentDate += 8.64e7; + } + + if (transaction.amount > 0) { + currentIncome += transaction.amount; + } + if (transaction.getCategoryCategory() == "Savings") { + currentSavings += transaction.amount; + } + currentBalance += transaction.amount; + + const val = { + date: transDate, + amount: round(currentSavings + currentBalance, 2), + goal: round(currentIncome * userPrefs.getSavingsBudget(), 2), + }; + + if (data.length > 0 && data[data.length - 1].date === transDate) { + data[data.length - 1] = val; + } + else { + data.push(val) + } + } + + return <> +

Savings + Balance

+ + + + + + + + + + ; +} \ No newline at end of file diff --git a/src/pages/dashboard/graph tiles/WantsGraphTile.tsx b/src/pages/dashboard/graph tiles/WantsGraphTile.tsx new file mode 100644 index 0000000..4b871f3 --- /dev/null +++ b/src/pages/dashboard/graph tiles/WantsGraphTile.tsx @@ -0,0 +1,81 @@ +import {Line, LineChart, ResponsiveContainer, Tooltip, XAxis, YAxis} from "recharts"; +import {Transaction} from "../../../utils/transaction.ts"; +import {UserPrefs} from "../../../utils/user_prefs.ts"; +import strftime from "strftime"; +import {round} from "lodash"; + +export default function wantsGraphTile(transactions: Transaction[], userPrefs: UserPrefs) { + const data: { + date: string, + amount: number, + goal: number + }[] = []; + + let currentIncome = 0; + let currentWants = 0; + + if (transactions.length == 0) { + return

No Data

; + } + + const revTransactions = transactions.slice().reverse(); + + let currentDate = revTransactions[0].dateTime; + + for (const transaction of revTransactions) { + const transDate = strftime("%d/%m/%y", new Date(transaction.dateTime)); + + // eslint-disable-next-line no-constant-condition + while (true) { + const date = strftime("%d/%m/%y", new Date(currentDate)); + if (date === transDate) { + break; + } + if (date === data[data.length - 1].date) { + currentDate += 8.64e7; + continue; + } + data.push( + { + date: date, + amount: round(-currentWants, 2), + goal: round(currentIncome * userPrefs.getWantsBudget(), 2), + } + ) + currentDate += 8.64e7; + } + + if (transaction.amount > 0) { + currentIncome += transaction.amount; + } + if (transaction.getCategoryCategory() == "Wants") { + currentWants += transaction.amount; + } + + const val = { + date: transDate, + amount: round(-currentWants, 2), + goal: round(currentIncome * userPrefs.getWantsBudget(), 2), + }; + + if (data.length > 0 && data[data.length - 1].date === transDate) { + data[data.length - 1] = val; + } + else { + data.push(val) + } + } + + return <> +

Wants

+ + + + + + + + + + ; +} \ No newline at end of file