diff --git a/back/api/@me.js b/back/api/@me.js index 080731e..fdcbbe3 100644 --- a/back/api/@me.js +++ b/back/api/@me.js @@ -1,6 +1,6 @@ const express = require('express'); const router = express.Router(); -const { getConnection, getUserAccounts, getUserCards, getUserTransfers, setAccountBalance, getAccount, addTransfer } = require('../libs/mysql'); +const { getConnection, getUserAccounts, getUserCards, getUserTransfers, setAccountBalance, getAccount, addTransfer, getUserReceivers, addReceiver, removeReceiver } = require('../libs/mysql'); const { checkAuth } = require('../libs/middlewares'); router.post('/', checkAuth, async (req, res) => { @@ -32,6 +32,60 @@ router.post('/transfers', checkAuth, async (req, res) => { res.send(transfers); }); +router.post('/receivers', checkAuth, async (req, res) => { + const user = req.user; + const connection = await getConnection(); + const receivers = await getUserReceivers(connection, user.id); + connection.end(); + res.send(receivers); +}); + +router.post('/add-receiver', checkAuth, async (req, res) => { + const user = req.user; + const { account_id, name } = req.body; + + if (!account_id || !name) { + return res.status(400).send({ error: 'Missing required fields' }); + } + + const connection = await getConnection(); + const account = await getAccount(connection, account_id); + + if (!account[0]) { + return res.status(400).send({ error: 'Invalid account ID' }); + } + + await addReceiver(connection, user.id, account_id, name); + connection.end(); + + res.send({ message: 'Receiver added successfully' }); +}); + +router.post('/remove-receiver', checkAuth, async (req, res) => { + const user = req.user; + const { id } = req.body; + + if (!id) { + return res.status(400).send({ error: 'Missing required fields' }); + } + + const connection = await getConnection(); + const receiver = await getUserReceivers(connection, user.id); + + if (!receiver[0]) { + return res.status(400).send({ error: 'Invalid receiver ID' }); + } + + if (receiver[0].user_id !== user.id) { + return res.status(403).send({ error: 'You are not authorized to remove this receiver' }); + } + + await removeReceiver(connection, id); + connection.end(); + + res.send({ message: 'Receiver removed successfully' }); +}); + router.post('/send-money', checkAuth, async (req, res) => { const user = req.user; const { account_from_id, account_to_id, amount, name } = req.body; diff --git a/back/bank.sql b/back/bank.sql index abd6e08..5203dca 100644 --- a/back/bank.sql +++ b/back/bank.sql @@ -3,7 +3,7 @@ -- https://www.phpmyadmin.net/ -- -- Host: mysql --- Generation Time: Apr 27, 2025 at 01:27 PM +-- Generation Time: Apr 28, 2025 at 06:36 AM -- Server version: 10.11.3-MariaDB-1:10.11.3+maria~ubu2204 -- PHP Version: 8.1.19 @@ -48,8 +48,8 @@ CREATE TABLE IF NOT EXISTS `accounts` ( CREATE TABLE IF NOT EXISTS `cards` ( `id` int(11) NOT NULL AUTO_INCREMENT, `account_id` int(11) NOT NULL, - `number` int(11) NOT NULL, - `expiration` timestamp NOT NULL, + `number` int(11) UNSIGNED NOT NULL, + `expiration` varchar(10) NOT NULL, `cvc` int(11) NOT NULL, PRIMARY KEY (`id`), KEY `account_id` (`account_id`) @@ -57,6 +57,22 @@ CREATE TABLE IF NOT EXISTS `cards` ( -- -------------------------------------------------------- +-- +-- Table structure for table `receivers` +-- + +CREATE TABLE IF NOT EXISTS `receivers` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `account_id` int(11) NOT NULL, + `name` varchar(30) NOT NULL, + PRIMARY KEY (`id`), + KEY `user_id` (`user_id`), + KEY `account_id2` (`account_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + -- -- Table structure for table `transfers` -- @@ -105,6 +121,13 @@ ALTER TABLE `accounts` ALTER TABLE `cards` ADD CONSTRAINT `account_id` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE ON UPDATE CASCADE; +-- +-- Constraints for table `receivers` +-- +ALTER TABLE `receivers` + ADD CONSTRAINT `account_id2` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, + ADD CONSTRAINT `user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE; + -- -- Constraints for table `transfers` -- diff --git a/back/libs/mysql.js b/back/libs/mysql.js index 98433bb..8a9f9d7 100644 --- a/back/libs/mysql.js +++ b/back/libs/mysql.js @@ -211,10 +211,11 @@ function removeCard(connection, id) { function getUserTransfers(connection, id) { return new Promise((resolve, reject) => { connection.query( - `SELECT * + `SELECT transfers.*, sender.name AS sender_name, users.name AS receiver_name, users.lastname AS receiver_lastname FROM transfers JOIN accounts as sender ON transfers.account_from_id = sender.id JOIN accounts as receiver ON transfers.account_to_id = receiver.id + JOIN users ON receiver.client_id = users.id WHERE sender.client_id = ? OR receiver.client_id = ?`, [id, id], (error, result) => { @@ -242,6 +243,59 @@ function addTransfer(connection, account_from_id, account_to_id, name, amount) { }); } +// +-------------------------------+ +// | Receivers | +// +-------------------------------+ + +function getUserReceivers(connection, id) { + return new Promise((resolve, reject) => { + connection.query( + `SELECT receivers.* + FROM receivers + JOIN users ON receivers.user_id = users.id + JOIN accounts ON receivers.account_id = accounts.id + WHERE users.id = ?`, + [id], + (error, result) => { + if (error) { + reject(new Error(error)); + } + resolve(result); + } + ); + }); +} + +function addReceiver(connection, user_id, account_id, name) { + return new Promise((resolve, reject) => { + connection.query( + `INSERT INTO receivers (user_id, account_id, name) VALUES (?, ?, ?)`, + [user_id, account_id, name], + (error, result) => { + if (error) { + reject(new Error(error)); + } + resolve(result); + } + ); + }); +} + +function removeReceiver(connection, id) { + return new Promise((resolve, reject) => { + connection.query( + `DELETE FROM receivers WHERE id = ?`, + [id], + (error, result) => { + if (error) { + reject(new Error(error)); + } + resolve(result); + } + ); + }); +} + module.exports = { getConnection, @@ -262,4 +316,8 @@ module.exports = { getUserTransfers, addTransfer, + + getUserReceivers, + addReceiver, + removeReceiver, }; diff --git a/front/src/pages/Home.tsx b/front/src/pages/Home.tsx index a4e9f1b..cb0ecb1 100644 --- a/front/src/pages/Home.tsx +++ b/front/src/pages/Home.tsx @@ -1,6 +1,6 @@ import { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; -import { User, Accounts, Cards, Transfers } from '../types'; +import { User, Accounts, Cards, Transfers, Receivers } from '../types'; import axios from 'axios'; import TopBar from '../components/TopBar'; @@ -11,10 +11,13 @@ export default function Home () { const [transfers, setTransfers] = useState([]); const [accounts, setAccounts] = useState([]); const [cards, setCards] = useState([]); + const [receivers, setReceivers] = useState([]); const [accountId, setAccountId] = useState(0); const [accountToId, setAccountToId] = useState(0); const [amount, setAmount] = useState(0); const [message, setMessage] = useState(""); + const [receiverId, setReceiverId] = useState(0); + const [receiverName, setReceiverName] = useState(""); const token = localStorage.getItem("token"); function sendMoney (e: React.FormEvent) { @@ -29,6 +32,8 @@ export default function Home () { name: message }) .then(() => { + setAmount(0); + setMessage(""); axios .post("/api/@me/accounts", { token: token }) .then((response) => { @@ -40,12 +45,70 @@ export default function Home () { .catch(() => { console.error("Failed to fetch accounts"); }); + + axios + .post("/api/@me/transfers", { token: token }) + .then((response) => { + setTransfers(response.data); + }) + .catch(() => { + console.error("Failed to fetch transfers"); + }); }) .catch((error) => { console.error("Failed to send money", error.response.data); }); } + function deleteReceiver (id: number) { + if (!window.confirm("Are you sure you want to delete this receiver?")) { + return; + } + axios + .post("/api/@me/remove-receiver", { + token: token, + id: id + }) + .then(() => { + axios + .post("/api/@me/receivers", { token: token }) + .then((response) => { + setReceivers(response.data); + setAccountToId(response.data[0].account_id); + }) + .catch(() => { + console.error("Failed to fetch receivers"); + }); + }) + .catch((error) => { + console.error("Failed to delete receiver", error.response.data); + }); + } + + function addReceiver (e: React.FormEvent) { + e.preventDefault(); + axios + .post("/api/@me/add-receiver", { + token: token, + account_id: receiverId, + name: receiverName, + }) + .then(() => { + axios + .post("/api/@me/receivers", { token: token }) + .then((response) => { + setReceivers(response.data); + setAccountToId(response.data[0].account_id); + }) + .catch(() => { + console.error("Failed to fetch receivers"); + }); + }) + .catch((error) => { + console.error("Failed to add receiver", error.response.data); + }); + } + useEffect(() => { const storedToken = localStorage.getItem("token"); if (storedToken) { @@ -87,6 +150,16 @@ export default function Home () { .catch(() => { console.error("Failed to fetch cards"); }); + + axios + .post("/api/@me/receivers", { token: storedToken }) + .then((response) => { + setReceivers(response.data); + setAccountToId(response.data[0].account_id); + }) + .catch(() => { + console.error("Failed to fetch receivers"); + }); } else { navigate("/login"); } @@ -116,7 +189,7 @@ export default function Home () {
    {transfers.map((transfer) => (
  • - Transfer ID: {transfer.id}, Amount: {transfer.value} + Message: {transfer.name}, Amount: {transfer.value}, From: {transfer.sender_name}, To: {transfer.receiver_name} {transfer.receiver_lastname}
  • ))}
@@ -124,7 +197,7 @@ export default function Home () {

No transfers found.

)} - {accounts.length > 0 && ( + {accounts.length > 0 && receivers.length > 0 && (

Send money

@@ -136,7 +209,14 @@ export default function Home () { ))} setAmount(Number(e.target.value))} value={amount}/> - setAccountToId(Number(e.target.value))} value={accountToId}/> + + setMessage(e.target.value)} value={message}/>
@@ -145,13 +225,13 @@ export default function Home () {

Your Accounts

{accounts.length > 0 ? ( -
    - {accounts.map((account) => ( -
  • - Account ID: {account.id}, Balance: {account.balance}, Interest: {account.interest} -
  • - ))} -
+ accounts.map((account) => ( +
+

+ Name: {account.name} - Balance: {account.balance} - Interest: {account.interest} - Account ID: {account.id} +

+
+ )) ) : (

No accounts found.

)} @@ -159,17 +239,40 @@ export default function Home () {

Your Cards

{cards.length > 0 ? ( -
    - {cards.map((card) => ( -
  • - Card ID: {card.id}, Account ID: {card.account_id}, Number: {card.number}, Expiration: {card.expiration} -
  • - ))} -
+ cards.map((card: any) => ( +
+

+ Card Account: {card.account_name} - Card Number: {card.number} - Expiration: {card.expiration} - CVC: {card.cvc} +

+
+ )) ) : (

No cards found.

)}
+
+

Your Receivers

+ {receivers.length > 0 ? ( + receivers.map((receiver: any) => ( +
+

+ Receiver Name: {receiver.name} - Account ID: {receiver.account_id} +

+ +
+ )) + ) : ( +

No receivers found.

+ )} +
+
+

Add Receiver

+
+ setReceiverName(e.target.value)} value={receiverName}/> + setReceiverId(Number(e.target.value))} value={receiverId}/> + +
+
) } \ No newline at end of file diff --git a/front/src/pages/UserPage.tsx b/front/src/pages/UserPage.tsx index 6f10167..c62a59e 100644 --- a/front/src/pages/UserPage.tsx +++ b/front/src/pages/UserPage.tsx @@ -194,7 +194,7 @@ export default function UserPage() { accounts.map((account: any) => (

- Name: {account.name} - Balance: {account.balance} - Interest: {account.interest} + Name: {account.name} - Balance: {account.balance} - Interest: {account.interest} - Account ID: {account.id}

@@ -232,7 +232,7 @@ export default function UserPage() { cards.map((card: any) => (

- Card Account: {card.account_name} - Card Number: {card.number} - Expiration: {card.expiration} - CVC: {card.cvc} + Card Account: {card.account_name} - Card Number: {card.number} - Expiration: {card.expiration} - CVC: {card.cvc}

diff --git a/front/src/types.ts b/front/src/types.ts index 0d51f2e..8993193 100644 --- a/front/src/types.ts +++ b/front/src/types.ts @@ -16,6 +16,9 @@ export type Transfer = { account_to_id: number; name: string; value: number; + sender_name: string; + receiver_name: string; + receiver_lastname: string; } export type Transfers = Transfer[]; @@ -39,3 +42,12 @@ export type Card = { } export type Cards = Card[]; + +export type Receiver = { + id: number; + user_id: number; + account_id: number; + name: string; +} + +export type Receivers = Receiver[];