From 3ad844b8257bda31f9ab3a9a90f3221a4028dbc3 Mon Sep 17 00:00:00 2001 From: ShalomShrek Date: Mon, 7 Oct 2024 14:27:06 +0200 Subject: [PATCH 1/3] Transaction History UI Created Transaction History UI --- API/routes/payments.js | 2 +- API/server.js | 4 +-- Frontend/src/App.js | 8 +++++- Frontend/src/History.css | 34 +++++++++++++++++++++++++ Frontend/src/History.js | 55 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 99 insertions(+), 4 deletions(-) create mode 100644 Frontend/src/History.css create mode 100644 Frontend/src/History.js diff --git a/API/routes/payments.js b/API/routes/payments.js index 49d4742..305ae08 100644 --- a/API/routes/payments.js +++ b/API/routes/payments.js @@ -1,7 +1,7 @@ const express = require("express"); const Joi = require("joi"); const router = express.Router(); -const Payment = require("../models/payment"); // Import your Payment model +const Payment = require("../models/Payment"); // Import your Payment model // Joi Schema for payment validation const paymentSchema = Joi.object({ diff --git a/API/server.js b/API/server.js index 90d30e3..930fbe7 100644 --- a/API/server.js +++ b/API/server.js @@ -124,8 +124,8 @@ app.post("/api/payment", async (req, res) => { }); // Read the SSL certificate and key -const privateKey = fs.readFileSync("C:/Users/andre/source/repos/APDS7311POE/API/server.key", "utf8"); -const certificate = fs.readFileSync("C:/Users/andre/source/repos/APDS7311POE/API/server.cert", "utf8"); +const privateKey = fs.readFileSync("C:/Users/callu/OneDrive/Documents/GitHub/PROG7312_POE/APDS7311POE/API/server.key", "utf8"); +const certificate = fs.readFileSync("C:/Users/callu/OneDrive/Documents/GitHub/PROG7312_POE/APDS7311POE/API/server.cert", "utf8"); const credentials = { key: privateKey, cert: certificate }; diff --git a/Frontend/src/App.js b/Frontend/src/App.js index 3106d4a..e3e8ee5 100644 --- a/Frontend/src/App.js +++ b/Frontend/src/App.js @@ -3,6 +3,7 @@ import { BrowserRouter as Router, Route, Routes, Link, useLocation } from "react import Register from "./Register"; import Login from "./Login"; import Dashboard from "./Dashboard"; +import History from "./History" import "./App.css"; import Payments from "./Payment"; function NavBar() { @@ -11,7 +12,7 @@ function NavBar() { @@ -46,6 +51,7 @@ function App() { } /> } /> } /> + }/> diff --git a/Frontend/src/History.css b/Frontend/src/History.css new file mode 100644 index 0000000..364e79c --- /dev/null +++ b/Frontend/src/History.css @@ -0,0 +1,34 @@ +.card { + background: white; + border-radius: 8px; + padding: 20px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + max-width: 400px; + margin: auto; + } + + .card h2 { + margin-bottom: 20px; + } + + input { + width: 100%; + padding: 10px; + margin-bottom: 10px; + border: 1px solid #ddd; + border-radius: 4px; + } + + button { + width: 100%; + padding: 10px; + background-color: #007bff; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + } + + button:hover { + background-color: #0056b3; + } \ No newline at end of file diff --git a/Frontend/src/History.js b/Frontend/src/History.js new file mode 100644 index 0000000..7788627 --- /dev/null +++ b/Frontend/src/History.js @@ -0,0 +1,55 @@ +import React, { useEffect, useState } from "react"; +import "./History.css"; + +const History = () => { + const [transactions, setTransactions] = useState([]); + + // Fetch data when component loads (replace the API URL with your actual endpoint) + // useEffect(() => { + // axios.get("/api/transactions") // Change this to your API endpoint + // .then((response) => { + // setTransactions(response.data); // Assuming the response contains an array of transactions + // }) + // .catch((error) => { + // console.error("Error fetching data:", error); + // }); + // }, []); + + return ( +
+

Transaction History

+ + + + + + + + + + + + + {transactions.length > 0 ? ( + transactions.map((transaction) => ( + {/* Assuming each transaction has a unique _id */} + + + + + + + + )) + ) : ( + + + + )} + +
AmountCurrencyProviderAccount NumberSWIFT CodeCreated At
{transaction.amount}{transaction.currency}{transaction.provider}{transaction.accountNumber}{transaction.swiftCode}{new Date(transaction.createdAt).toLocaleDateString()}
No transactions found
+
+ ); + }; + +export default History \ No newline at end of file From 2dbb12a610db08ef8c8fc7a79d8e9df92f3c9a7d Mon Sep 17 00:00:00 2001 From: ShalomShrek Date: Tue, 8 Oct 2024 12:10:49 +0200 Subject: [PATCH 2/3] Connected API Connected API to transaction history page --- API/.gitignore | 3 +- API/node_modules/.package-lock.json | 1 + API/package-lock.json | 1 + API/server.js | 32 +++++++-------- Frontend/package-lock.json | 32 +++++++++++++++ Frontend/package.json | 1 + Frontend/src/History.js | 61 ++++++++++++++++++----------- Frontend/src/Login.js | 14 +++---- Frontend/src/Payment.js | 3 +- 9 files changed, 99 insertions(+), 49 deletions(-) diff --git a/API/.gitignore b/API/.gitignore index b512c09..2840d5b 100644 --- a/API/.gitignore +++ b/API/.gitignore @@ -1 +1,2 @@ -node_modules \ No newline at end of file +node_modules +apds-c658e-firebase-adminsdk-6jvhj-4d82d2b89f.json \ No newline at end of file diff --git a/API/node_modules/.package-lock.json b/API/node_modules/.package-lock.json index 6b28f16..9f53dc7 100644 --- a/API/node_modules/.package-lock.json +++ b/API/node_modules/.package-lock.json @@ -1146,6 +1146,7 @@ "version": "12.6.0", "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-12.6.0.tgz", "integrity": "sha512-gc0pDiUmxscxBhcjMcttmjvExJmnQdVRb+IIth95CvMm7F9rLdabrQZThW2mK02HR696P+rzd6NqkdUA3URu4w==", + "license": "Apache-2.0", "dependencies": { "@fastify/busboy": "^3.0.0", "@firebase/database-compat": "^1.0.2", diff --git a/API/package-lock.json b/API/package-lock.json index 38349db..d2e2d4d 100644 --- a/API/package-lock.json +++ b/API/package-lock.json @@ -1162,6 +1162,7 @@ "version": "12.6.0", "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-12.6.0.tgz", "integrity": "sha512-gc0pDiUmxscxBhcjMcttmjvExJmnQdVRb+IIth95CvMm7F9rLdabrQZThW2mK02HR696P+rzd6NqkdUA3URu4w==", + "license": "Apache-2.0", "dependencies": { "@fastify/busboy": "^3.0.0", "@firebase/database-compat": "^1.0.2", diff --git a/API/server.js b/API/server.js index 0ad12ae..4dcacc4 100644 --- a/API/server.js +++ b/API/server.js @@ -160,22 +160,22 @@ app.post("/api/payment", async (req, res) => { app.get("/api/payments/:accountNumber", async (req, res) => { - const { username } = req.params; - - try { - const userRef = db.collection("users").doc(username); - const paymentsSnapshot = await userRef.collection("payments").get(); - - if (paymentsSnapshot.empty) { - return res.status(404).json({ message: "No payments found for user." }); - } - - const payments = paymentsSnapshot.docs.map(doc => doc.data()); - res.status(200).json(payments); - } catch (error) { - console.error(error); - res.status(500).json({ message: "Error retrieving payments" }); - } + const { accountNumber } = req.params; + + try { + const userRef = db.collection("users").doc(accountNumber); + const paymentsSnapshot = await userRef.collection("payments").get(); + + if (paymentsSnapshot.empty) { + return res.status(404).json({ message: "No payments found for this account." }); + } + + const payments = paymentsSnapshot.docs.map(doc => doc.data()); + res.status(200).json(payments); + } catch (error) { + console.error(error); + res.status(500).json({ message: "Error retrieving payments" }); + } }); diff --git a/Frontend/package-lock.json b/Frontend/package-lock.json index e304714..daa4f1f 100644 --- a/Frontend/package-lock.json +++ b/Frontend/package-lock.json @@ -11,6 +11,7 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "axios": "^1.7.7", "react": "^18.3.1", "react-dom": "^18.3.1", "react-google-recaptcha": "^3.1.0", @@ -5396,6 +5397,31 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/axobject-query": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", @@ -14639,6 +14665,12 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", diff --git a/Frontend/package.json b/Frontend/package.json index f3c4712..2955a49 100644 --- a/Frontend/package.json +++ b/Frontend/package.json @@ -6,6 +6,7 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "axios": "^1.7.7", "react": "^18.3.1", "react-dom": "^18.3.1", "react-google-recaptcha": "^3.1.0", diff --git a/Frontend/src/History.js b/Frontend/src/History.js index 7788627..5992aab 100644 --- a/Frontend/src/History.js +++ b/Frontend/src/History.js @@ -1,23 +1,39 @@ import React, { useEffect, useState } from "react"; +import axios from "axios"; import "./History.css"; const History = () => { - const [transactions, setTransactions] = useState([]); - - // Fetch data when component loads (replace the API URL with your actual endpoint) - // useEffect(() => { - // axios.get("/api/transactions") // Change this to your API endpoint - // .then((response) => { - // setTransactions(response.data); // Assuming the response contains an array of transactions - // }) - // .catch((error) => { - // console.error("Error fetching data:", error); - // }); - // }, []); - - return ( -
-

Transaction History

+ const [transactions, setTransactions] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(""); + + const accountNumber = localStorage.getItem("accNo"); + + useEffect(() => { + if (accountNumber) { + axios + .get(`https://localhost:443/api/payments/${accountNumber}`) + .then((response) => { + setTransactions(response.data); + setLoading(false); + }) + .catch((error) => { + console.error("Error fetching transactions:", error); + setError("Error fetching transactions."); + setLoading(false); + }); + } else { + setError("Account number not found."); + setLoading(false); + } + }, [accountNumber]); + + return ( +
+

Transaction History

+ {loading &&

Loading...

} + {error &&

{error}

} + {!loading && !error && ( @@ -26,19 +42,17 @@ const History = () => { - {transactions.length > 0 ? ( transactions.map((transaction) => ( - {/* Assuming each transaction has a unique _id */} + - )) ) : ( @@ -48,8 +62,9 @@ const History = () => { )}
Provider Account Number SWIFT CodeCreated At
{transaction.amount} {transaction.currency} {transaction.provider} {transaction.accountNumber} {transaction.swiftCode}{new Date(transaction.createdAt).toLocaleDateString()}
-
- ); - }; + )} +
+ ); +}; -export default History \ No newline at end of file +export default History; \ No newline at end of file diff --git a/Frontend/src/Login.js b/Frontend/src/Login.js index 59c427e..37ee1ee 100644 --- a/Frontend/src/Login.js +++ b/Frontend/src/Login.js @@ -9,9 +9,9 @@ function Login() { const handleLogin = async (e) => { e.preventDefault(); - const accountNumber = e.target[0].value; // ID - const username = e.target[1].value; // Full Name - const password = e.target[2].value; // Password + const accountNumber = e.target[0].value; + const username = e.target[1].value; + const password = e.target[2].value; const userData = { accountNumber, @@ -30,7 +30,7 @@ function Login() { console.log(JSON.stringify(userData)) const data = await response.json(); if (response.ok) { - // Store the full name in localStorage after a successful login + localStorage.setItem("accNo", accountNumber); setMessage("Login successful!"); @@ -47,9 +47,9 @@ function Login() {

Login

- {/* ID */} - {/* Full Name */} - {/* Password */} + + +
{message &&

{message}

} diff --git a/Frontend/src/Payment.js b/Frontend/src/Payment.js index c45a2ce..2a47764 100644 --- a/Frontend/src/Payment.js +++ b/Frontend/src/Payment.js @@ -12,7 +12,6 @@ function Payments() { const provider = e.target[2].value; const swiftCode = e.target[3].value; - // Retrieve accountNumber from localStorage const accountNumber = localStorage.getItem('accNo'); if (!accountNumber) { @@ -47,7 +46,7 @@ function Payments() { method: "POST", headers: { "Content-Type": "application/json", - "account-number": accountNumber, // Send accountNumber from localStorage as a header + "account-number": accountNumber, }, body: JSON.stringify(paymentData), }); From 06183046d928a84a06d3e1ed834e7cb194981692 Mon Sep 17 00:00:00 2001 From: ShalomShrek Date: Tue, 8 Oct 2024 12:15:00 +0200 Subject: [PATCH 3/3] Update .gitignore --- API/.gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/API/.gitignore b/API/.gitignore index 2840d5b..b512c09 100644 --- a/API/.gitignore +++ b/API/.gitignore @@ -1,2 +1 @@ -node_modules -apds-c658e-firebase-adminsdk-6jvhj-4d82d2b89f.json \ No newline at end of file +node_modules \ No newline at end of file