diff --git a/frontend/src/assets/css/currencyDropdown.css b/frontend/src/assets/css/currencyDropdown.css
new file mode 100644
index 0000000..147b95b
--- /dev/null
+++ b/frontend/src/assets/css/currencyDropdown.css
@@ -0,0 +1,41 @@
+@import url("variables.css");
+
+.currencyOptionList_open, .currencyOptionList_closed {
+ width: 100%
+}
+
+.currencyOptionList_open {
+ transition-duration: 50ms;
+ height: calc(100vh - 5 * var(--itemHeight) - 3.5 * var(--subSectionPadding) - var(--topBarHeight) - 40px);
+ padding-top: calc(var(--subSectionPadding) * 2);
+}
+
+.currencyOptionList_closed {
+ transition-duration: 50ms;
+ height: 0;
+ padding-top: 0;
+ overflow: hidden;
+}
+
+.currencyOption {
+ width: 100%;
+}
+
+.defaultButton {
+ position: relative;
+ z-index: 2;
+}
+
+.defaultContainer {
+ position: relative;
+ z-index: 1;
+ float: left;
+ margin-left: var(--subSectionPadding);
+ margin-top: calc(var(--subSectionPadding) * -1 - var(--standardRadius) * 2);
+ min-height: calc(var(--standardRadius) * 2);
+}
+
+.currencyOption {
+ width: 100%;
+ float: left;
+}
\ No newline at end of file
diff --git a/frontend/src/assets/css/dashboard.css b/frontend/src/assets/css/dashboard.css
index 14615d2..dd0ac3c 100644
--- a/frontend/src/assets/css/dashboard.css
+++ b/frontend/src/assets/css/dashboard.css
@@ -1,9 +1,11 @@
@import url("variables.css");
body {
- background: linear-gradient(90deg, rgba(42,4,126,1) 0%, rgba(77,4,126,1) 100%);
+ /* background: linear-gradient(90deg, rgba(42,4,126,1) 0%, rgba(77,4,126,1) 100%); */
+ background: var(--color1);
overflow: hidden;
font-family: "Roboto Mono", monospace;
+ font-size: var(--standardFontSize);
}
.topBar {
@@ -26,19 +28,21 @@ body {
}
.sideBar {
- background: linear-gradient(180deg, rgba(42,4,126,1) 0%, rgba(77,4,126,1) 100%);
width: var(--sideBarWidth);
height: calc(100vh - var(--topBarHeight));
float: right;
}
.scrollableContent {
+ display: flex;
+ flex-direction: column;
background-color: var(--color2);
box-shadow: inset 0px 10px 20px 0px rgba(0,0,0,0.5);
border-radius: var(--standardRadius);
width: calc(100vw - var(--sideBarWidth));
height: calc(100vh - var(--topBarHeight));
float: left;
- padding: calc( 2 * var(--subSectionPadding));
+ padding: calc( 4 * var(--subSectionPadding));
+ gap: calc( 4 * var(--subSectionPadding));
overflow: scroll;
}
\ No newline at end of file
diff --git a/frontend/src/assets/css/default.css b/frontend/src/assets/css/default.css
new file mode 100644
index 0000000..915dcde
--- /dev/null
+++ b/frontend/src/assets/css/default.css
@@ -0,0 +1,106 @@
+@import url("variables.css");
+
+/* ---- ---- Default Container ---- ---- */
+
+.defaultContainer, .defaultButtonContainer, .defaultDropdownContainer {
+ width: calc(var(--sideBarWidth) - 2 * var(--subSectionPadding));
+ padding: calc(var(--subSectionPadding) * 0.5);
+ border-radius: var(--standardRadius);
+ background: var(--noAffordanceBackground);
+}
+
+/* ---- ---- Default Button and Default Dropdown ---- ---- */
+
+.defaultButtonContainer, .defaultDropdownContainer {
+ transition-duration: 100ms;
+ margin-left: var(--subSectionPadding);
+ margin-bottom: var(--subSectionPadding);
+ overflow: hidden;
+ box-shadow: var(--noAffordanceShadow);
+ float: left;
+}
+
+.defaultButton {
+ transition-duration: 100ms;
+ width: 100%;
+ height: calc(var(--itemHeight) - var(--subSectionPadding));
+ border-radius: calc(var(--standardRadius) * 0.75);
+ background: var(--physicalAffordanceBackground);
+ box-shadow: var(--physicalAffordanceShadow);
+ color: var(--color2);
+ font-size: var(--standardFontSize);
+}
+
+.defaultButtonContainer:hover, .defaultDropdownContainer:hover {
+ transition-duration: 100ms;
+ padding: 0;
+}
+
+.defaultButtonContainer:hover {
+ box-shadow: var(--noAddordanceShadow_hover);
+ background: rgb(100, 100, 100);
+}
+
+.defaultButtonContainer:hover .defaultButton, .defaultDropdownContainer:hover .defaultButton {
+ transition-duration: 100ms;
+ background: var(--physicalAffordanceBackground_hover);
+ box-shadow: var(--physicalAffordanceShadow_hover);
+ border-radius: var(--standardRadius);
+ font-size: calc(var(--standardFontSize) + 1px);
+ height: var(--itemHeight);
+}
+
+/* ---- ---- Goal Bar ---- ---- */
+
+.goalBarContainer, .goalDivider, .subGoalContainer {
+ height: calc((var(--topBarHeight) - 3 * var(--subSectionPadding)) * 0.5);
+}
+
+.goalBarContainer {
+ /* Origonal styling => w-full bg-gray-200 rounded-lg h-6 relative */
+ width: 100%;
+ background: rgb(211, 211, 211);
+ border-radius: var(--standardRadius);
+ position: relative;
+}
+
+.goalBarContainer {
+ padding: 3px;
+ background: var(--noAffordanceBackground);
+ box-shadow: var(--noAffordanceShadow);
+}
+
+.goalBar {
+ /* Origonal styling => bg-gradient-to-r from-blue-400 bg-primary h-full rounded-lg */
+ height: 100%;
+ border-radius: var(--standardRadius);
+ border-top: 2px;
+ background: var(--visualAffordanceBackground);
+ box-shadow: var(--visualAffordanceShadow);
+}
+
+.goalDivider {
+/* Origonal styling => absolute border-l border-gray-400 */
+ position: absolute;
+ border: 1px solid rgba(255, 255, 255, 0.3);
+ top: 0;
+}
+
+.subGoalContainer {
+/* Origonal styling => absolute w-full flex justify-between -top-6 */
+ position: absolute;
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+ top: calc((var(--topBarHeight) - var(--subSectionPadding)) * 0.5);
+}
+
+/* Origonal styling => {`absolute left-1/2 transform -translate-x-1/2 text-xs
+ ${Number(balance) >= Number(subgoal) ? "text-green-700 border-green-500" : "text-gray-300 border-gray-300"}
+ border rounded px-1`} */
+
+.subGoal, .subGoalCompleted {
+ text-align: center;
+ width: 0;
+ position: relative;
+}
\ No newline at end of file
diff --git a/frontend/src/assets/css/defaultButton.css b/frontend/src/assets/css/defaultButton.css
deleted file mode 100644
index d0bdcf1..0000000
--- a/frontend/src/assets/css/defaultButton.css
+++ /dev/null
@@ -1,22 +0,0 @@
-@import url("variables.css");
-
-.defaultButton {
- background-color: var(--color2);
- width: calc(var(--sideBarWidth) - 2 * var(--subSectionPadding));
- height: var(--itemHeight);
- border-radius: var(--standardRadius);
- margin-left: var(--subSectionPadding);
- margin-right: var(--subSectionPadding);
- margin-top: var(--subSectionPadding);
- margin-bottom: var(--subSectionPadding);
-}
-
-.updateGoalButton {
- background-color: var(--color2);
- width: var(--topBarBtnWidth);
- height: var(--topBarBtnHeight);
- border-radius: var(--standardRadius);
- margin-left: var(--subSectionPadding);
- margin-right: var(--subSectionPadding);
- margin-bottom: var(--subSectionPadding);
-}
\ No newline at end of file
diff --git a/frontend/src/assets/css/savingsTracker.css b/frontend/src/assets/css/savingsTracker.css
index 1f931c4..89dd618 100644
--- a/frontend/src/assets/css/savingsTracker.css
+++ b/frontend/src/assets/css/savingsTracker.css
@@ -2,47 +2,30 @@
.trackerContainer {
position: absolute;
- width: calc(100vw - 2 * var(--sideBarWidth) - 2 * var(--subSectionPadding));
- right: var(--sideBarWidth);
+ width: calc(100vw - 2 * var(--sideBarWidth) - 2 * var(--subSectionPadding) - 10vw);
+ right: calc(var(--sideBarWidth) + 5vw);
height: calc(var(--topBarHeight) - 2 * var(--subSectionPadding));
margin-top: var(--subSectionPadding);
margin-left: var(--subSectionPadding);
float: left;
}
-.trackerTextContainer, .progressBarContainer {
+.balanceCounterContainer {
+ display: flex;
+ justify-content: center;
position: absolute;
- left: 0;
+ height: calc((var(--topBarHeight) - 3 * var(--subSectionPadding)) * 0.5);
top: 0;
+ left: 0;
width: 100%;
- height: 100%;
-}
-
-.trackerTextContainer {
- display: flex;
- justify-content: center;
- align-items: center;
}
-.trackerText {
+.balanceCounter {
+ padding-left: var(--subSectionPadding);
+ padding-right: var(--subSectionPadding);
+ width: fit-content;
+ height: calc(100% - var);
+ background-color: rgba(255, 255, 255, 0.5);
text-align: center;
- color: var(--color2);
- z-index: 2;
-}
-
-.progressBarContainer {
- box-sizing: border-box;
- border-width: 2px;
- border-color: var(--color1);
- border-radius: var(--standardRadius);
- overflow: hidden;
-}
-
-.progressBar {
- position: absolute;
- height: 100%;
- left: 0;
- top: 0;
- background-color: var(--color1);
- z-index: 1;
+ font-size: 0.75rem;
}
\ No newline at end of file
diff --git a/frontend/src/assets/css/transactions.css b/frontend/src/assets/css/transactions.css
new file mode 100644
index 0000000..627980a
--- /dev/null
+++ b/frontend/src/assets/css/transactions.css
@@ -0,0 +1,14 @@
+@import url("variables.css");
+
+.transactionLog {
+ display: flex;
+ justify-content: space-between;
+ flex-direction: column;
+ align-items: center;
+ border: solid 4px var(--color3);
+ border-radius: var(--standardRadius);
+}
+
+.transaction {
+
+}
\ No newline at end of file
diff --git a/frontend/src/assets/css/variables.css b/frontend/src/assets/css/variables.css
index c66d8d8..c0c9e45 100644
--- a/frontend/src/assets/css/variables.css
+++ b/frontend/src/assets/css/variables.css
@@ -1,11 +1,27 @@
:root {
- --color1: black;
- --color2: white;
+ --color1: rgb(50, 48, 50);
+ --color2: rgb(222, 218, 225);
+ --color3: rgb(9, 158, 106);
--topBarHeight: 64px;
- --topBarBtnHeight: 32px;
- --topBarBtnWidth: 64px;
--sideBarWidth: calc(16vw);
--subSectionPadding: 8px;
--itemHeight: 10vh;
- --standardRadius: 10px
+ --standardRadius: 10px;
+ --standardFontSize: 16px;
+
+ --color1_gradientInner: rgb(40, 39, 40);
+ --color1_hover: rgb(54, 52, 54);
+ --color1_gradientInner_hover: rgb(44, 43, 44);
+
+ --noAffordanceBackground: var(--color2);
+ --noAffordanceShadow: inset 0px 2px 3px 0px rgba(0,0,0,0.5);
+ --noAddordanceShadow_hover: 0px 4px 4px 0px rgba(0,0,0,0.25);
+
+ --visualAffordanceBackground: linear-gradient(90deg, rgb(5, 87, 68), rgb(43, 177, 99));
+ --visualAffordanceShadow: inset -3px 3px 4px 2px rgba(200, 255, 184, 0.4);
+
+ --physicalAffordanceBackground: linear-gradient(var(--color1), var(--color1_gradientInner));
+ --physicalAffordanceShadow: inset 0px 1px 4px 1px rgba(153, 148, 155, 0.3);
+ --physicalAffordanceBackground_hover: linear-gradient(var(--color1_hover), var(--color1_gradientInner_hover));
+ --physicalAffordanceShadow_hover: inset 0px 1.5px 5px 1px rgba(153, 148, 155, 0.2);
}
\ No newline at end of file
diff --git a/frontend/src/components/GenericButton.jsx b/frontend/src/components/GenericButton.jsx
deleted file mode 100644
index e69de29..0000000
diff --git a/frontend/src/components/Transaction.jsx b/frontend/src/components/Transaction.jsx
index 9146bea..a4cfe47 100644
--- a/frontend/src/components/Transaction.jsx
+++ b/frontend/src/components/Transaction.jsx
@@ -9,7 +9,6 @@ const Transaction = ({ transaction }) => {
const handleCheckboxChange = (e) => {
handleSelect(transaction.id, e.target.checked);
- console.log("clicked: ", transaction.id);
};
return (
diff --git a/frontend/src/components/default/DefaultButton.jsx b/frontend/src/components/default/DefaultButton.jsx
new file mode 100644
index 0000000..8bf544a
--- /dev/null
+++ b/frontend/src/components/default/DefaultButton.jsx
@@ -0,0 +1,12 @@
+import React from 'react';
+import '../../assets/css/default.css';
+
+export default function DefaultButton(props) {
+ return (
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/frontend/src/components/metrics/BalanceGraph.jsx b/frontend/src/components/metrics/BalanceGraph.jsx
index 9033601..87b90d8 100644
--- a/frontend/src/components/metrics/BalanceGraph.jsx
+++ b/frontend/src/components/metrics/BalanceGraph.jsx
@@ -24,11 +24,9 @@ export default function BalanceGraph() {
const parseDate = (dateString) => {
// Parse the date string
const date = new Date(dateString);
- console.log(date)
// Create a new date object for the start of the year
const startOfYear = new Date(date.getFullYear(), 0, 0);
- console.log(startOfYear)
// Calculate the difference in milliseconds
const diff = date - startOfYear;
@@ -36,16 +34,12 @@ export default function BalanceGraph() {
// Convert milliseconds to days and return the day of the year
const oneDay = 1000 * 60 * 60 * 24;
const parseDate = Math.floor(diff / oneDay);
- console.log(parseDate)
return parseDate;
}
useEffect(() => {
- console.log(balance)
- console.log(transactions)
-
let pastBalance = balance
const newBalanceData = transactions.reduce((acc, transaction) => {
@@ -67,9 +61,6 @@ export default function BalanceGraph() {
newBalanceData.push({x: 0, y: pastBalance})
setBalanceData(newBalanceData)
-
- console.log(newBalanceData)
-
}, [balance, transactions])
return (
diff --git a/frontend/src/components/metrics/CurrencyDropdown.jsx b/frontend/src/components/metrics/CurrencyDropdown.jsx
index a369b3d..e669163 100644
--- a/frontend/src/components/metrics/CurrencyDropdown.jsx
+++ b/frontend/src/components/metrics/CurrencyDropdown.jsx
@@ -1,79 +1,50 @@
import { FaSortDown } from "react-icons/fa";
import { useState, useContext } from "react";
import TransactionContext from "../../context/TransactionContext";
-import '../../assets/css/defaultButton.css';
+import '../../assets/css/currencyDropdown.css';
-/*
- * When adding new currencies to the dropdown:
- * Remember to edit the border radius of the last item in the dropdown to match
- * Do this by adding "hover:rounded-bl-3xl hover:rounded-br-3xl" in the label class
-*/
+export default function CurrencyDropdown(props) {
+ const [isOpen, setIsOpen] = useState(false);
+ const [selectedCurrency, setSelectedCurrency] = useState('NZD');
+ const { setCurrency } = useContext(TransactionContext);
-const CurrencyDropdown = () => {
-
- const [isOpen, setIsOpen] = useState(false);
- const [selectedCurrency, setSelectedCurrency] = useState('NZD');
- const { setCurrency } = useContext(TransactionContext);
-
- const handleOpen = () => {
- setIsOpen(!isOpen);
- }
-
- // grabs the id of the selected currency from the selection and sets it as the selected currency
- const handleSelect = (event) => {
- const { id } = event.target;
- setSelectedCurrency(id);
- setIsOpen(false);
- setCurrency(id);
- };
+ const handleOpen = () => {
+ setIsOpen(!isOpen);
+ }
+ function currencyOption (currencyId) {
return (
-
-
- {isOpen && (
-
-
- )}
-
+
);
-}
-
-export default CurrencyDropdown;
\ No newline at end of file
+ }
+
+ function selectOption(currencyId) {
+ setCurrency(currencyId);
+ setSelectedCurrency(currencyId);
+ setIsOpen(false);
+ }
+
+ return (
+ <>
+
+
+
+
+
+ {currencyOption("NZD")}
+ {currencyOption("AUD")}
+ {currencyOption("USD")}
+ {currencyOption("GBP")}
+ {currencyOption("HKD")}
+
+
+ >
+ );
+}
\ No newline at end of file
diff --git a/frontend/src/components/metrics/FinancialMetrics.jsx b/frontend/src/components/metrics/FinancialMetrics.jsx
index 6b9a098..45b5a5e 100644
--- a/frontend/src/components/metrics/FinancialMetrics.jsx
+++ b/frontend/src/components/metrics/FinancialMetrics.jsx
@@ -1,6 +1,7 @@
import React, { useState, useContext } from 'react';
import TransactionContext from '../../context/TransactionContext';
-import '../../assets/css/defaultButton.css';
+import '../../assets/css/default.css';
+import DefaultButton from '../default/DefaultButton.jsx';
export default function FinancialMetrics() {
const [showMetrics, setShowMetrics] = useState(false);
@@ -50,9 +51,9 @@ export default function FinancialMetrics() {
return (
-
+
{/* Conditionally render the modal */}
{showMetrics && (
diff --git a/frontend/src/components/metrics/SavingsTracker.jsx b/frontend/src/components/metrics/SavingsTracker.jsx
index 8be90fe..095a864 100644
--- a/frontend/src/components/metrics/SavingsTracker.jsx
+++ b/frontend/src/components/metrics/SavingsTracker.jsx
@@ -1,30 +1,13 @@
import { useState, useEffect, useContext } from "react";
-import axios from "axios";
-import SetGoal from "./SetGoal";
import TransactionContext from "../../context/TransactionContext";
-import { refreshDisplayBalance } from "../../utility/CurrencyUtil";
-import '../../assets/css/savingsTracker.css';
import GoalBar from '../progress-bar/GoalBar';
-import CompletionMsg from "../progress-bar/CompletionMsg";
+import '../../assets/css/savingsTracker.css'
export default function SavingsTracker() {
- const { currency, balance, goal, setGoal } = useContext(TransactionContext);
+ const { balance, goal, currencySymbol } = useContext(TransactionContext);
const [progress, setProgress] = useState(0);
- const [displayBalance, setDisplayBalance] = useState(0);
- const [showSetGoal, setShowSetGoal] = useState(false);
- const [newGoal, setNewGoal] = useState(0);
- // Variables for axios instance
- const token = localStorage.getItem("token");
- const axiosInstance = axios.create({
- baseURL: "http://localhost:4000",
- headers: { Authorization: `Bearer ${token}` },
- });
-
- // Fetch the user's current balance and convert to specified currency when the component mounts
- useEffect(() => { refreshDisplayBalance(setDisplayBalance, currency); }, [balance, currency]);
-
- // Dynamic progress bar whenver the balance or goal changes
+ /* Dynamic progress bar whenver the balance or goal changes */
useEffect(() => {
if (Number(balance) > Number(goal)) {
setProgress(100);
@@ -39,79 +22,21 @@ export default function SavingsTracker() {
const update = (Number(balance) / Number(goal)) * 100;
setProgress(update);
console.log("Progress: ", update);
+ console.log("AKA: ", balance, " / ", goal);
}, [balance, goal]);
- // Updates the user's savings goal via the Set New Goal button
- const updateGoal = () => {
- //checks if newGoal is null if it is replace it with 0
- //new val updated goal is used because setNewGoal is Aync and might not update in time for sending data to the db
- let updatedGoal = newGoal;
- if (newGoal === '') {
- updatedGoal = 0;
- setNewGoal(0)
- }
-
- //saves newGoal to the DB
- const token = localStorage.getItem("token");
- const axiosInstance = axios.create({
- baseURL: "http://localhost:4000",
- headers: { Authorization: `Bearer ${token}` },
- });
-
- axiosInstance
- .patch("/user/goal", {
- goal: updatedGoal,
- })
- .then((response) => {
- setGoal(updatedGoal);
- setShowSetGoal(false);
- })
- .catch((error) => {
- console.log(error);
- });
- };
-
return (
-
- {/*
Current Savings Goal:
-
- ${balance}/${goal}
-
*/}
-
- {/* Use flexbox to align GoalBar and button */}
-
-
-
-
-
-
- {progress >= 0 && (
-
{/* Margin left to separate the button from GoalBar */}
-
-
- )}
+
+
+
+
+ {Number.parseFloat(balance).toFixed(2)} / {Number.parseFloat(goal).toFixed(2)} ({currencySymbol})
+
-
- {showSetGoal && (
-
setShowSetGoal(false)}
- />
- )}
);
-}
+}
\ No newline at end of file
diff --git a/frontend/src/components/metrics/SetGoal.jsx b/frontend/src/components/metrics/SetGoal.jsx
index 9c2e47b..a5fefeb 100644
--- a/frontend/src/components/metrics/SetGoal.jsx
+++ b/frontend/src/components/metrics/SetGoal.jsx
@@ -1,7 +1,7 @@
import React from "react";
import { useEffect } from "react";
import "../../App.css";
-import '../../assets/css/defaultButton.css'
+import '../../assets/css/default.css'
export default function SetGoal({
newGoal,
diff --git a/frontend/src/components/metrics/UpdateSavingGoal.jsx b/frontend/src/components/metrics/UpdateSavingGoalButton.jsx
similarity index 50%
rename from frontend/src/components/metrics/UpdateSavingGoal.jsx
rename to frontend/src/components/metrics/UpdateSavingGoalButton.jsx
index 08e8cc5..70b6e61 100644
--- a/frontend/src/components/metrics/UpdateSavingGoal.jsx
+++ b/frontend/src/components/metrics/UpdateSavingGoalButton.jsx
@@ -3,9 +3,14 @@ import axios from "axios";
import SetGoal from "./SetGoal";
import TransactionContext from "../../context/TransactionContext";
import { refreshDisplayGoal } from "../../utility/CurrencyUtil";
+import getAxiosInstance from "../../utility/AxiosUtil";
+import DefaultButton from "../default/DefaultButton";
-export default function UpdateSavingGoal() {
- const { currency, goal, setGoal } = useContext(TransactionContext);
+export default function UpdateSavingGoalButton() {
+ const { currency, setGoal } = useContext(TransactionContext);
+ const [newGoal, setNewGoal] = useState(0);
+ const [showSetGoal, setShowSetGoal] = useState(false);
+ const [progress, setProgress] = useState(0);
// Updates the user's savings goal via the Set New Goal button
const updateGoal = () => {
@@ -18,11 +23,7 @@ export default function UpdateSavingGoal() {
}
//saves newGoal to the DB
- const token = localStorage.getItem("token");
- const axiosInstance = axios.create({
- baseURL: "http://localhost:4000",
- headers: { Authorization: `Bearer ${token}` },
- });
+ const axiosInstance = getAxiosInstance();
axiosInstance
.patch("/user/goal", {
@@ -36,4 +37,25 @@ export default function UpdateSavingGoal() {
console.log(error);
});
};
+
+ return (
+
+ {
+ setShowSetGoal(true);
+ }}
+ >
+ Update Savings Goal
+
+ {showSetGoal && (
+ setShowSetGoal(false)}
+ />
+ )}
+
+ );
}
\ No newline at end of file
diff --git a/frontend/src/components/progress-bar/GoalBar.jsx b/frontend/src/components/progress-bar/GoalBar.jsx
index cc9d58c..f1d7eed 100644
--- a/frontend/src/components/progress-bar/GoalBar.jsx
+++ b/frontend/src/components/progress-bar/GoalBar.jsx
@@ -1,58 +1,59 @@
-import React from 'react';
+import {React, useContext} from 'react';
import PropTypes from 'prop-types';
+import '../../assets/css/default.css'
+import '../../assets/css/variables.css'
+import TransactionContext from "../../context/TransactionContext";
function GoalBar({ progress, balance, goal, subgoals }) {
const hasReachedGoal = Number(balance) >= Number(goal);
const filteredSubgoals = subgoals.slice(1, -1);
const subgoalPositions = filteredSubgoals.map(subgoal => (Number(subgoal) / Number(goal)) * 100);
+ const { currencySymbol } = useContext(TransactionContext);
return (
-
+
{/* Progress Bar */}
-
+
-
- {/* need to update the dollar sign with currency change */}
- {/* need to updaate balance with currency change */}
- ${balance}/${goal}
-
-
-
+ className="goalBar"
+ style={{ width: `${progress}%` }}
+ >
{/* Grey Lines for Subgoals */}
-
+
{subgoalPositions.map((position, index) => (
))}
{/* Labels for Subgoals */}
-
+
{subgoals.map((subgoal, index) => (
= Number(subgoal) ? "text-green-700 border-green-500" : "text-red-500 border-red-500"}
+ ${Number(balance) >= Number(subgoal) ? "text-green-700 border-green-500" : "text-gray-300 border-gray-300"}
border rounded px-1`}
>
- ${subgoal}
+ {currencySymbol}{Number.parseFloat(subgoal).toFixed(2)}
))}
+ {/* Completion Message */}
+ {hasReachedGoal && (
+
+
🎉 Congratulations! 🎉
+
You have reached your goal of ${goal}.
+
+ )}
+
);
}
diff --git a/frontend/src/components/transactions/AddTransactionButton.jsx b/frontend/src/components/transactions/AddTransactionButton.jsx
index d6982d7..43fa639 100644
--- a/frontend/src/components/transactions/AddTransactionButton.jsx
+++ b/frontend/src/components/transactions/AddTransactionButton.jsx
@@ -1,12 +1,14 @@
import { useState, useContext } from "react";
-import axios from "axios";
+import getAxiosInstance from "../../utility/AxiosUtil.jsx";
+import { refreshDisplayBalance, convertCurrency } from "../../utility/CurrencyUtil.jsx";
import TransactionForm from "./TransactionForm";
import TransactionContext from "../../context/TransactionContext";
-import '../../assets/css/defaultButton.css';
+import '../../assets/css/default.css';
+import DefaultButton from '../default/DefaultButton.jsx';
export default function AddTransactionButton() {
const [showForm, setShowForm] = useState(false);
- const { balance, setBalance } = useContext(TransactionContext);
+ const { balance, setBalance, currency } = useContext(TransactionContext);
const handleFormSubmit = async ({
title,
@@ -14,50 +16,31 @@ export default function AddTransactionButton() {
description,
transactionType,
}) => {
- const token = localStorage.getItem("token");
-
- if (!token) {
- console.error("User is not authenticated.");
- return;
- }
-
- const axiosInstance = axios.create({
- baseURL: "http://localhost:4000",
- headers: { Authorization: `Bearer ${token}` },
- });
-
- console.log("amount: ", amount);
+ amount = await convertCurrency("NZD", currency, amount);
+ console.log("That is ", amount, " in NZD!");
try {
// Post request to create the transaction
- const response = await axiosInstance.post("/transaction", {
+ const response = await getAxiosInstance().post("/transaction", {
title,
amount,
description,
});
- console.log("Transaction created successfully.", response.data);
-
- // Update the balance after the transaction is created
-
// PATCH request to update the balance
const updateBalance = Number(balance) + Number(amount); // use Number() for strings
- await axiosInstance.patch("/user/balance", { balance: updateBalance });
- console.log("Balance updated successfully.");
- setBalance(balance + amount); // Update the balance state in the context
+ await getAxiosInstance().patch("/user/balance", { balance: updateBalance });
+ refreshDisplayBalance(setBalance, currency); // Update the balance state in the context
} catch (error) {
console.error("Error occurred:", error);
} finally {
- console.log("Im at finally");
setShowForm(false);
}
};
return (
- <>
-
+ <>
+
setShowForm(true)}>Add Transaction
{showForm && (
);
-}
+}
\ No newline at end of file
diff --git a/frontend/src/components/transactions/DeleteTransactionButton.jsx b/frontend/src/components/transactions/DeleteTransactionButton.jsx
index 865a8f3..3c7d935 100644
--- a/frontend/src/components/transactions/DeleteTransactionButton.jsx
+++ b/frontend/src/components/transactions/DeleteTransactionButton.jsx
@@ -1,11 +1,13 @@
import { useContext, useState, useRef } from "react";
+import getAxiosInstance from "../../utility/AxiosUtil.jsx";
import TransactionContext from "../../context/TransactionContext";
-import axios from "axios";
-import '../../assets/css/defaultButton.css';
+import '../../assets/css/default.css';
+import DefaultButton from '../default/DefaultButton.jsx';
+import { refreshDisplayBalance } from "../../utility/CurrencyUtil.jsx";
export default function DeleteTransactionButton() {
- const { selectedTransactions, setSelectedTransactions, requestUiUpdate } =
+ const { selectedTransactions, setSelectedTransactions, requestUiUpdate, setBalance, currency } =
useContext(TransactionContext);
const [disableClick, setDisableClick] = useState(false);
@@ -16,8 +18,6 @@ export default function DeleteTransactionButton() {
disableClickSync.current = true;
setDisableClick(true);
- console.log("Transactions to delete:", selectedTransactions);
-
const token = localStorage.getItem("token");
if (!token) {
@@ -25,10 +25,7 @@ export default function DeleteTransactionButton() {
return;
}
- const axiosInstance = axios.create({
- baseURL: "http://localhost:4000",
- headers: { Authorization: `Bearer ${token}` },
- });
+ const axiosInstance = getAxiosInstance();
try {
// Assuming you have an API function to delete a transaction by ID
@@ -38,8 +35,8 @@ export default function DeleteTransactionButton() {
.then(requestUiUpdate())
)
);
- console.log("Transactions deleted successfully.");
setSelectedTransactions([]); // Clear the selected transactions
+ refreshDisplayBalance(setBalance, currency);
} catch (error) {
console.error("Failed to delete transactions", error);
} finally {
@@ -48,12 +45,8 @@ export default function DeleteTransactionButton() {
}
};
return (
-
+
);
}
diff --git a/frontend/src/components/transactions/Transaction.jsx b/frontend/src/components/transactions/Transaction.jsx
index 8191ead..f38b7cd 100644
--- a/frontend/src/components/transactions/Transaction.jsx
+++ b/frontend/src/components/transactions/Transaction.jsx
@@ -8,7 +8,7 @@ const Transaction = ({ transaction }) => {
const [isAmountNegative, setIsAmountNegative] = useState(false);
const [convertedAmount, setConvertedAmount] = useState(transaction.amount);
const [showDetails, setShowDetails] = useState(false);
- const { currency, handleSelect } =
+ const { currency, handleSelect, currencySymbol } =
useContext(TransactionContext);
// useEffect to check if each transaction is negative and then convert the currency
@@ -27,7 +27,6 @@ const Transaction = ({ transaction }) => {
const handleCheckboxChange = (e) => {
handleSelect(transaction.id, e.target.checked);
- console.log("clicked: ", transaction.id);
};
return (
@@ -41,7 +40,7 @@ const Transaction = ({ transaction }) => {
onClick={() => setShowDetails(true)}>
- {isAmountNegative ? convertedAmount : `+${convertedAmount}`}:{" "}
+ {isAmountNegative ? `-${currencySymbol}${convertedAmount.slice(1)}` : `+${currencySymbol}${convertedAmount}`}:{" "}
{transaction.title}
diff --git a/frontend/src/components/transactions/TransactionLog.jsx b/frontend/src/components/transactions/TransactionLog.jsx
index 75cc5b2..704fdfd 100644
--- a/frontend/src/components/transactions/TransactionLog.jsx
+++ b/frontend/src/components/transactions/TransactionLog.jsx
@@ -4,6 +4,8 @@ import { IoIosArrowForward, IoIosArrowBack } from "react-icons/io";
import TransactionContext from "../../context/TransactionContext";
import { useContext, useState, useEffect } from "react";
+import '../../assets/css/transactions.css'
+
import { LoadingSpinner } from "../LoadingSpinner";
export default function TransactionList() {
@@ -99,7 +101,7 @@ export default function TransactionList() {
Last year
-
+
{loading ? (
diff --git a/frontend/src/context/TransactionContextProvider.jsx b/frontend/src/context/TransactionContextProvider.jsx
index 9fb7848..54ef925 100644
--- a/frontend/src/context/TransactionContextProvider.jsx
+++ b/frontend/src/context/TransactionContextProvider.jsx
@@ -5,7 +5,7 @@ import {
filterPastYearTransactions,
} from "../utility/transactionFilters.js";
import { useEffect, useState } from "react";
-import { refreshDisplayGoal } from "../utility/CurrencyUtil";
+import { refreshDisplayGoal, refreshDisplayBalance } from "../utility/CurrencyUtil";
import axios from "axios";
// Context provider for transactions. Allows for the sharing of transaction data between components
@@ -18,6 +18,7 @@ export function TransactionContextProvider({ children }) {
const [filter, setFilter] = useState("");
const [balance, setBalance] = useState(0);
const [goal, setGoal] = useState(0);
+ const [currencySymbol, setCurrencySymbol] = useState("$");
const [uiUpdateRequest, setUiUpdateRequest] = useState(false);
const [loading, setLoading] = useState(true);
@@ -90,6 +91,18 @@ export function TransactionContextProvider({ children }) {
setUiUpdateRequest(true);
};
+ useEffect(() => {
+ const currencySymbols = {
+ "NZD": "NZ$",
+ "AUD": "AU$",
+ "USD": "US$",
+ "GBP": "£",
+ "HKD": "HK$"
+ }
+
+ setCurrencySymbol(currencySymbols[currency]);
+ }, currency)
+
//functions to filter transactions
const filterYear = () => {
if (filter === "year") {
@@ -127,6 +140,7 @@ export function TransactionContextProvider({ children }) {
// all values and functions that can be accessed when consuming this context provider
const contextValue = {
currency, // the currency to convert to i.e NZD, USD, EUR
+ currencySymbol,
transactions, // the transactions to display (after filtering)
allTransactions, // all transactions of the user
selectedTransactions, // the transactions selected by the user for deletion
diff --git a/frontend/src/pages/Dashboard.jsx b/frontend/src/pages/Dashboard.jsx
index 36c16d2..49c029b 100644
--- a/frontend/src/pages/Dashboard.jsx
+++ b/frontend/src/pages/Dashboard.jsx
@@ -1,3 +1,4 @@
+
import { useContext } from "react";
import Banner from "../components/Banner";
import BalanceGraph from "../components/metrics/BalanceGraph"
@@ -7,8 +8,7 @@ import SavingsTracker from "../components/metrics/SavingsTracker";
import TransactionLog from "../components/transactions/TransactionLog";
import AddTransactionButton from "../components/transactions/AddTransactionButton";
import DeleteTransactionButton from "../components/transactions/DeleteTransactionButton";
-import TransactionContext from "../context/TransactionContext";
-import GoalBar from "../components/progress-bar/GoalBar";
+import UpdateSavingGoalButton from "../components/metrics/UpdateSavingGoalButton";
import FintrackLogo from "../assets/images/FintrackLogo.png";
import FinancialMetrics from "../components/metrics/FinancialMetrics";
@@ -25,61 +25,27 @@ import LuckyAdviser from "../components/gemini/LuckyAdviser";
export default function Dashboard() {
- const { goal, balance } = useContext(TransactionContext); // Access goal and balance from context
-
return (
<>
-
+
-
![logo]({FintrackLogo})
+
-
+
-