Compare commits

...

4 Commits

23 changed files with 438 additions and 228 deletions

View File

@ -5,13 +5,16 @@ import CreateAccount from "./components/accounts/CreateAccount";
import DeleteAccount from "./components/accounts/DeleteAccount";
import UpdateAccount from "./components/accounts/UpdateAccount";
import Accounts from "./components/accounts/Accounts";
import { Login } from "./components/auth/Login";
import Login from "./components/auth/Login";
import { Logout } from "./components/auth/Logout";
import Register from "./components/auth/Register";
import CreateUser from "./components/users/CreateUser";
import DeleteUser from "./components/users/DeleteUser";
import UpdateUser from "./components/users/UpdateUser";
import Users from "./components/users/Users";
import { Routes } from "./components/services/Routes";
import Transactions from "./components/transactions/Transactions";
const AppRoutes = [
{
@ -19,59 +22,75 @@ const AppRoutes = [
element: <Home />
},
{
path: '/home',
path: Routes.HOME,
element: <Home />
},
{
path: '/counter',
path: Routes.COUNTER,
element: <Counter />
},
{
path: '/fetch-data',
path: Routes.FETCH_DATA,
element: <FetchData />
},
{
path: '/login',
path: Routes.LOGIN,
element: <Login />
},
{
path: '/logout',
path: Routes.LOGOUT,
element: <Logout />
},
{
path: '/register',
path: Routes.REGISTER,
element: <Register />
},
{
path: '/admin/users',
path: Routes.USERS,
element: <Users />
},
{
path: '/admin/user/create',
path: Routes.USER_CREATE,
element: <CreateUser />
},
{
path: '/admin/user/edit',
path: Routes.USER_EDIT,
element: <UpdateUser />
},
{
path: '/admin/user/delete',
path: Routes.USER_DELETE,
element: <DeleteUser />
},
{
path: '/admin/accounts',
path: Routes.ACCOUNTS,
element: <Accounts />
},
{
path: '/admin/account/create',
path: Routes.ACCOUNT_CREATE,
element: <CreateAccount />
},
{
path: '/admin/account/edit',
path: Routes.ACCOUNT_EDIT,
element: <UpdateAccount />
},
{
path: '/admin/account/delete',
path: Routes.ACCOUNT_DELETE,
element: <DeleteAccount />
},
{
path: Routes.TRANSACTIONS,
element: <Transactions />
},
{
path: Routes.TRANSACTION_CREATE,
element: <CreateAccount />
},
{
path: Routes.TRANSACTION_EDIT,
element: <UpdateAccount />
},
{
path: Routes.TRANSACTION_DELETE,
element: <DeleteAccount />
},
];

View File

@ -1,6 +1,7 @@
import React, { Component } from 'react';
import { Collapse, Navbar, NavbarBrand, NavbarToggler, NavItem, NavLink } from 'reactstrap';
import { Link } from 'react-router-dom';
import { Routes } from "./services/Routes";
import './NavMenu.css';
export class NavMenu extends Component {
@ -32,30 +33,34 @@ export class NavMenu extends Component {
<NavItem>
<NavLink tag={Link} className="text-dark" to="/">Home</NavLink>
</NavItem>
{/*
<NavItem>
<NavLink tag={Link} className="text-dark" to="/counter">Counter</NavLink>
<NavLink tag={Link} className="text-dark" to={Routes.COUNTER}>Counter</NavLink>
</NavItem>
<NavItem>
<NavLink tag={Link} className="text-dark" to="/fetch-data">Fetch data</NavLink>
</NavItem>
<NavLink tag={Link} className="text-dark" to={Routes.FETCH_DATA}>Fetch data</NavLink>
</NavItem>*/}
{sessionStorage.getItem('userName') == null &&
<NavItem>
<NavLink tag={Link} className="text-dark" to="/login">Login</NavLink>
<NavLink tag={Link} className="text-dark" to={Routes.LOGIN}>Login</NavLink>
</NavItem>
}
{sessionStorage.getItem('userName') != null &&
<>
<NavItem>
<NavLink tag={Link} className="text-dark" to="/admin/users">Users</NavLink>
<NavLink tag={Link} className="text-dark" to={Routes.USERS}>Users</NavLink>
</NavItem>
<NavItem>
<NavLink tag={Link} className="text-dark" to="/admin/accounts">Accounts</NavLink>
<NavLink tag={Link} className="text-dark" to={Routes.ACCOUNTS}>Accounts</NavLink>
</NavItem>
<NavItem>
<NavLink tag={Link} className="text-dark" to={Routes.TRANSACTIONS}>Transactions</NavLink>
</NavItem>
{/*<NavItem>
<NavLink tag={Link} className="text-dark" to="/login">{sessionStorage.getItem('firstName')}</NavLink>
<NavLink tag={Link} className="text-dark" to={Routes.LOGIN}>{sessionStorage.getItem('firstName')}</NavLink>
</NavItem>*/}
<NavItem>
<NavLink tag={Link} className="text-dark" to="/logout">Logout</NavLink>
<NavLink tag={Link} className="text-dark" to={Routes.LOGOUT}>Logout</NavLink>
</NavItem>
</>
}

View File

@ -1,7 +1,8 @@
import { getData } from "../services/AccessAPI";
import { useNavigate } from "react-router-dom";
import { EndPoints, getData } from "../services/AccessAPI";
import { RouterProvider, useNavigate } from "react-router-dom";
import { useEffect } from "react";
import { useState } from 'react';
import { Routes } from "../services/Routes";
export default function Accounts() {
useEffect(() => {
@ -16,23 +17,21 @@ export default function Accounts() {
});
function onAccountCreate() {
navigate('/admin/account/create');
navigate(Routes.ACCOUNT_CREATE);
}
function onAccountEdit(id){
let path = "/admin/account/edit"
function onAccountEdit(id) {
let query = "?id=" + id
navigate(path + query);
navigate(Routes.ACCOUNT_EDIT + query);
}
function onAccountDelete(id){
let path = "/admin/account/delete"
function onAccountDelete(id) {
let query = "?id=" + id
navigate(path + query);
navigate(Routes.ACCOUNT_DELETE + query);
}
function getAllAccountsData() {
getData('Accounts/').then(
getData(EndPoints.ACCOUNTS).then(
(result) => {
if (result) {
console.log(result);

View File

@ -1,42 +1,35 @@
import SessionManager from "../auth/SessionManager";
import { postData } from "../services/AccessAPI";
import { EndPoints, postData } from "../services/AccessAPI";
import { useNavigate } from "react-router-dom";
import { useState } from 'react';
import { Routes } from "../services/Routes";
export default function CreateAccount() {
let navigate = useNavigate();
const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
const [email, setEmail] = useState("");
const [accountname, setAccountname] = useState("");
const [password, setPassword] = useState("");
const [confirmationPassword, setConfirmationPassword] = useState("");
const [role, setRole] = useState("");
const [name, setName] = useState("");
//const [owner, setOwner] = useState(0);
const [initBalance, setInitBalance] = useState("");
//const [currency, setCurrency] = useState(0);
const [extNum, setExtNum] = useState("");
const [loading, setLoading] = useState(true);
function onSubmit(e) {
e.preventDefault();
if (password !== confirmationPassword) {
alert("Password and confirm password are not same");
return;
}
let accountObj = {
firstName: firstName,
lastName: lastName,
email: email,
accountname: accountname,
password: password,
role: role,
name: name,
owner: SessionManager.getUserId(),
initialBalance: initBalance,
currency: 1,
externalAccountNumber: extNum,
}
postData('Accounts/register', accountObj).then((result) => {
postData(EndPoints.ACCOUNTS, accountObj).then((result) => {
setLoading(false);
let responseJson = result;
if (responseJson) {
navigate('/admin/accounts');
navigate(Routes.ACCOUNTS);
}
});
}
@ -45,54 +38,30 @@ export default function CreateAccount() {
e.preventDefault();
if(SessionManager.getToken()){
navigate('/admin/accounts');
navigate(Routes.ACCOUNTS);
}else{
navigate('/login');
navigate(Routes.LOGIN);
}
}
/*function onChange(e) {
//setState({ [e.target.name]: e.target.value });
}*/
return (
<div className="row">
<div className="col-md-4">
<h3>Create new account</h3>
<form onSubmit={onSubmit}>
<div className="form-group">
<label className="control-label">First Name: </label>
<input className="form-control" type="text" name="firstName" value={firstName} onChange={(e) => setFirstName(e.target.value)}></input>
</div>
<div className="form-group">
<label className="control-label">Last Name: </label>
<input className="form-control" type="text" name="lastName" value={lastName} onChange={(e) => setLastName(e.target.value)}></input>
</div>
<div className="form-group">
<label className="control-label">Email: </label>
<input className="form-control" type="text" name="email" value={email} onChange={(e) => setEmail(e.target.value)}></input>
</div>
<div className="form-group">
<label className="control-label">Account Name: </label>
<input className="form-control" type="text" name="accountname" value={accountname} onChange={(e) => setAccountname(e.target.value)}></input>
<input className="form-control" type="text" name="name" value={name} onChange={(e) => setName(e.target.value)}></input>
</div>
<div className="form-group">
<label className="control-label">Role: </label>
<input className="form-control" type="text" name="roles" value={role} onChange={(e) => setRole(e.target.value)}></input>
<label className="control-label">Initial Balance: </label>
<input className="form-control" type="text" name="initBalance" value={initBalance} onChange={(e) => setInitBalance(e.target.value)}></input>
</div>
<div className="form-group">
<label className="control-label">Password: </label>
<input className="form-control" type="password" name="password" value={password} onChange={(e) => setPassword(e.target.value)}></input>
</div>
<div className="form-group">
<label className="control-label">Confirm Password: </label>
<input className="form-control" type="password" name="confirmationPassword" value={confirmationPassword} onChange={(e) => setConfirmationPassword(e.target.value)}></input>
<label className="control-label">External Account Number: </label>
<input className="form-control" type="text" name="extNum" value={extNum} onChange={(e) => setExtNum(e.target.value)}></input>
</div>
<div className="form-group">

View File

@ -1,27 +1,26 @@
import { useNavigate } from "react-router-dom";
import { deleteData, getData } from "../services/AccessAPI";
import { EndPoints, deleteData, getData } from "../services/AccessAPI";
import { useEffect } from "react";
import { useState } from 'react';
import { useLocation } from 'react-router-dom';
import { Routes } from "../services/Routes";
export default function DeleteAccount() {
const search = useLocation().search;
const id = new URLSearchParams(search).get('id')
useEffect(() => {
//const { id } = this.props.match.params;
getData('Accounts/' + id).then(
getData(EndPoints.ACCOUNTS + "/" + id).then(
(result) => {
console.log("Role for edit: ");
console.log(result);
if (result) {
setState({
firstName: result.firstName,
lastName: result.lastName,
accountname: result.accountname,
email: result.email,
roles: result.roles,
name: result.name,
lastActivity: result.lastActivity,
createdOn: result.createdOn,
balance: result.balance,
initialBalance: result.initialBalance,
currencyId: result.currencyId,
externalAccountNumber: result.externalAccountNumber,
loading: false
});
}
@ -32,70 +31,99 @@ export default function DeleteAccount() {
let navigate = useNavigate();
const [state, setState] = useState({
firstName: '',
lastName: '',
accountname: '',
email: '',
roles: [],
name: '',
lastActivity: null,
createdOn: null,
balance: 0,
initialBalance: 0,
currencyId: 0,
externalAccountNumber: '',
loading: true
});
function onCancel() {
navigate('/admin/accounts');
navigate(Routes.ACCOUNTS);
}
function onConfirmation(e) {
e.preventDefault();
deleteData('Accounts/' + id).then((result) => {
deleteData(EndPoints.ACCOUNTS + "/" + id).then((result) => {
let responseJson = result;
if (responseJson) {
navigate('/admin/accounts');
navigate(Routes.ACCOUNTS);
}
}
);
}
return (
<div>
<h2>::Delete account::</h2>
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>Account Information</h4>
<dl className="row">
<dt className="col-sm-2">
First Name:
</dt>
<dd className="col-sm-10">
{state.firstName}
</dd>
</dl>
<dl className="row">
<dt className="col-sm-2">
Last Name:
</dt>
<dd className="col-sm-10">
{state.lastName}
</dd>
</dl>
<dl className="row">
<dt className="col-sm-2">
Account Name:
</dt>
<dd className="col-sm-10">
{state.accountname}
{state.name}
</dd>
</dl>
<dl className="row">
<dt className="col-sm-2">
Email:
Last Activity:
</dt>
<dd className="col-sm-10">
{state.email}
{state.lastActivity}
</dd>
</dl>
<dl className="row">
<dt className="col-sm-2">
Created On:
</dt>
<dd className="col-sm-10">
{state.createdOn}
</dd>
</dl>
<dl className="row">
<dt className="col-sm-2">
Balance:
</dt>
<dd className="col-sm-10">
{state.balance}
</dd>
</dl>
<dl className="row">
<dt className="col-sm-2">
Initial Balance:
</dt>
<dd className="col-sm-10">
{state.initialBalance}
</dd>
</dl>
<dl className="row">
<dt className="col-sm-2">
Currency ID:
</dt>
<dd className="col-sm-10">
{state.currencyId}
</dd>
</dl>
<dl className="row">
<dt className="col-sm-2">
External Account Number:
</dt>
<dd className="col-sm-10">
{state.externalAccountNumber}
</dd>
</dl>

View File

@ -1,35 +1,30 @@
import { getData, putData } from "../services/AccessAPI";
import { EndPoints, getData, putData } from "../services/AccessAPI";
import { useNavigate, useLocation } from "react-router-dom";
import { useEffect } from "react";
import { useState } from 'react';
import { Routes } from "../services/Routes";
export default function UpdateAccount() {
let navigate = useNavigate();
const search = useLocation().search;
const id = new URLSearchParams(search).get('id')
const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
const [email, setEmail] = useState("");
const [accountname, setAccountname] = useState("");
const [role, setRole] = useState("");
const [name, setName] = useState("");
//const [owner, setOwner] = useState(0);
const [initBalance, setInitBalance] = useState("");
//const [currency, setCurrency] = useState(0);
const [extNum, setExtNum] = useState("");
const [loading, setLoading] = useState(false);
useEffect(() => {
//const id = location.pathName.slice(location.pathName.lastIndexOf("/") , location.pathName.length);
getData('Accounts/' + id).then(
getData(EndPoints.ACCOUNTS + "/" + id).then(
(result) => {
//let responseJson = result;
console.log("account for edit: ");
console.log(result);
console.log("Accountname: " + result.accountname)
if (result) {
setFirstName(result.firstName);
setLastName(result.lastName);
setEmail(result.email);
setAccountname(result.accountname);
setRole(result.roles);
setName(result.name);
//setOwner(result.ownerId);
setInitBalance(result.initialBalance);
//setCurrency(result.currencyId);
setExtNum(result.externalAccountNumber);
setLoading(false);
}
}
@ -43,32 +38,26 @@ export default function UpdateAccount() {
}
function onUpdateCancel() {
navigate('/admin/accounts');
navigate(Routes.ACCOUNTS);
}
function onSubmit(e){
function onSubmit(e) {
e.preventDefault();
//const id = location.pathName.slice(location.pathName.lastIndexOf("/") , location.pathName.length);
let accountProfile = {
id: id,
Accountname: accountname,
FirstName: firstName,
LastName: lastName,
Email: email,
name: name,
//owner: ownerId,
initialBalance: initBalance,
//currency: currencyId,
externalAccountNumber: extNum,
}
putData('Accounts/' + id, accountProfile).then((result) => {
console.log("Put Request body: ");
console.log(accountProfile);
putData(EndPoints.ACCOUNTS + "/" + id, accountProfile).then((result) => {
let responseJson = result;
console.log("update response: ");
if(responseJson){
if (responseJson) {
console.log(responseJson);
navigate('/admin/accounts');
navigate(Routes.ACCOUNTS);
}
}
);
@ -79,28 +68,22 @@ export default function UpdateAccount() {
<div className="col-md-4">
<h3>Edit Account</h3>
<form onSubmit={onSubmit}>
<div className="form-group">
<label className="control-label">First Name: </label>
<input className="form-control" type="text" value={firstName} onChange={(e) => setFirstName(e.target.value)} name="firstName"
onKeyDown={onKeyDown} ></input>
</div>
<div className="form-group">
<label className="control-label">Last Name: </label>
<input className="form-control" type="text" value={lastName} onChange={(e) => setLastName(e.target.value)} name="lastName"
onKeyDown={onKeyDown} ></input>
</div>
<div className="form-group">
<label className="control-label">Account Name: </label>
<input className="form-control" type="text" value={accountname} onChange={(e) => setAccountname(e.target.value)} name="accountname"
<input className="form-control" type="text" value={name} onChange={(e) => setName(e.target.value)} name="name"
onKeyDown={onKeyDown} ></input>
</div>
<div className="form-group">
<label className="control-label">Email: </label>
<input className="form-control" type="text" value={email} onChange={(e) => setEmail(e.target.value)} name="email"
onKeyDown={onKeyDown}></input>
<label className="control-label">Initial Balance: </label>
<input className="form-control" type="text" value={initBalance} onChange={(e) => setInitBalance(e.target.value)} name="initBalance"
onKeyDown={onKeyDown} ></input>
</div>
<div className="form-group">
<label className="control-label">External Account Number: </label>
<input className="form-control" type="text" value={extNum} onChange={(e) => setExtNum(e.target.value)} name="extNum"
onKeyDown={onKeyDown} ></input>
</div>
<div className="form-group">

View File

@ -1,9 +1,9 @@
import { useNavigate } from "react-router-dom";
import { useEffect } from "react";
import { useState } from 'react';
import { postDataForLogin } from "../services/AccessAPI";
import { EndPoints, postDataForLogin } from "../services/AccessAPI";
import SessionManager from "./SessionManager";
import { Routes } from "../services/Routes";
export default function Login() {
@ -33,14 +33,14 @@ export default function Login() {
}
//console.log("login info: " + userInfo.password);
postDataForLogin('Users/authenticate', userObj).then((result) => {
postDataForLogin(EndPoints.USER_AUTHENTICATE, userObj).then((result) => {
if (result?.token) {
SessionManager.setUserSession(result.username, result.token, result.id, result.firstName, result.lastName)
if (SessionManager.getToken()) {
setLoading(false);
navigate('/home');
navigate(Routes.HOME);
}
}
@ -70,7 +70,7 @@ export default function Login() {
}
function registration() {
navigate('/register');
navigate(Routes.REGISTER);
}

View File

@ -1,5 +1,6 @@
import { Component } from "react";
import SessionManager from "./SessionManager";
import { Routes } from "../services/Routes";
export class Logout extends Component{
constructor(){
@ -12,7 +13,7 @@ export class Logout extends Component{
componentDidMount(){
console.log("component did mount for logout");
SessionManager.removeUserSession();
window.location.href = "/login";
window.location.href = Routes.LOGIN;
}
render(){

View File

@ -1,7 +1,8 @@
import { useNavigate } from "react-router-dom";
import { useEffect } from "react";
import { useState } from 'react';
import { postData } from "../services/AccessAPI";
import { EndPoints, postData } from "../services/AccessAPI";
import { Routes } from "../services/Routes";
export default function Register() {
@ -44,9 +45,9 @@ export default function Register() {
role: role,
}
postData('Users/register', userObj).then((result) => {
postData(EndPoints.USER_REGISTER, userObj).then((result) => {
if (result) {
navigate('/login');
navigate(Routes.LOGIN);
} else {
let errors = '';
for (const key in result?.errors) {

View File

@ -6,6 +6,12 @@ const SessionManager = {
else return null;
},
getUserId() {
const id = sessionStorage.getItem('userId');
if (id) return id;
else return null;
},
setUserSession(userName, token, userId, firstName, lastName) {
sessionStorage.setItem('userName', userName);
sessionStorage.setItem('token', token);

View File

@ -1,6 +1,14 @@
import SessionManager from "../auth/SessionManager";
import { BASE_URL } from "./Settings";
export const EndPoints = {
USERS: "Users",
USER_AUTHENTICATE: "Users/authenticate",
USER_REGISTER: "Users/register",
ACCOUNTS: "Accounts",
CURRENCYTYPES: "CurrencyTypes",
TRANSACTIONS: "Transactions",
}
export function getData(endPoint) {

View File

@ -0,0 +1,20 @@
export const Routes = {
HOME: "/home",
COUNTER: "/counter",
FETCH_DATA: "/fetch-data",
LOGIN: "/login",
LOGOUT: "/logout",
REGISTER: "/register",
USERS: "/admin/users",
USER_CREATE: "/admin/user/create",
USER_EDIT: "/admin/user/edit",
USER_DELETE: "/admin/user/delete",
ACCOUNTS: "/admin/accounts",
ACCOUNT_CREATE: "/admin/account/create",
ACCOUNT_EDIT: "/admin/account/edit",
ACCOUNT_DELETE: "/admin/account/delete",
TRANSACTIONS: "/admin/transactions",
TRANSACTION_CREATE: "/admin/transaction/create",
TRANSACTION_EDIT: "/admin/transaction/edit",
TRANSACTION_DELETE: "/admin/transaction/delete",
};

View File

@ -0,0 +1,120 @@
import { getData } from "../services/AccessAPI";
import { useNavigate, useLocation } from "react-router-dom";
import { useEffect } from "react";
import { useState } from 'react';
import { Routes } from "../services/Routes";
export default function Transactions() {
useEffect(() => {
getAllTransactionsData();
}, [])
let navigate = useNavigate();
const search = useLocation().search;
const accountId = new URLSearchParams(search).get('accountId')
const [state, setState] = useState({
transactions: [],
loading: false
});
function onTransactionCreate() {
navigate(Routes.TRANSACTION_CREATE);
}
function onTransactionEdit(id){
let query = "?id=" + id
navigate(Routes.TRANSACTION_EDIT + query);
}
function onTransactionDelete(id){
let query = "?id=" + id
navigate(Routes.TRANSACTION_DELETE + query);
}
function getAllTransactionsData() {
let url = 'Transactions/';
if (accountId) {
url += '?accountId=' + accountId;
}
getData(url).then(
(result) => {
if (result) {
console.log(result);
setState({
transactions: result,
loading: false
});
}
}
);
}
function renderAllTransactionsTable(transactions) {
return (
<table className="table table-striped">
<thead>
<tr>
<th>Amount</th>
<th>Description</th>
<th>Date</th>
<th>External ID</th>
<th>Debit Acc</th>
<th>Credit Acc</th>
<th>Pending</th>
</tr>
</thead>
<tbody>
{
transactions.map(transaction => (
<tr key={transaction.id}>
<td>{formatAmount(
transaction.amount,
transaction.currencyType,
accountId ? accountId === transaction.debitAccountId : null
)}</td>
<td>{transaction.description}</td>
<td>{transaction.date.split("T")[0]}</td>
<td>{transaction.externalId}</td>
<td>{transaction.debitAccountId}</td>
<td>{transaction.debitAccountId}</td>
<td>{transaction.isPending ? "True" : "False"}</td>
<td><button onClick={() => onTransactionEdit(transaction.id)} className="btn btn-success">Edit</button> ||
<button onClick={() => onTransactionDelete(transaction.id)} className="btn btn-danger">Delete</button></td>
</tr>
))
}
</tbody>
</table>
);
}
function formatAmount(amount, currencyType, isDebit = null)
{
let str = currencyType.symbol + amount
if (isDebit != null) {
str = (isDebit ? "-" : "+") + str;
}
return str;
}
let content = state.loading ? (
<p>
<em>Loading...</em>
</p>
) : (
renderAllTransactionsTable(state.transactions)
)
return (
<div>
<h3>List of Transactions</h3>
<button onClick={() => onTransactionCreate()} className="btn btn-primary">Create new transaction</button>
{content}
</div>
);
}

View File

@ -1,7 +1,8 @@
import SessionManager from "../auth/SessionManager";
import { postData } from "../services/AccessAPI";
import { EndPoints, postData } from "../services/AccessAPI";
import { useNavigate } from "react-router-dom";
import { useState } from 'react';
import { Routes } from "../services/Routes";
export default function CreateUser() {
let navigate = useNavigate();
@ -32,11 +33,11 @@ export default function CreateUser() {
role: role,
}
postData('Users/register', userObj).then((result) => {
postData(EndPoints.USER_REGISTER, userObj).then((result) => {
setLoading(false);
let responseJson = result;
if (responseJson) {
navigate('/admin/users');
navigate(Routes.USERS);
}
});
}
@ -45,9 +46,9 @@ export default function CreateUser() {
e.preventDefault();
if(SessionManager.getToken()){
navigate('/admin/users');
navigate(Routes.USERS);
}else{
navigate('/login');
navigate(Routes.LOGIN);
}
}

View File

@ -1,8 +1,9 @@
import { useNavigate } from "react-router-dom";
import { deleteData, getData } from "../services/AccessAPI";
import { EndPoints, deleteData, getData } from "../services/AccessAPI";
import { useEffect } from "react";
import { useState } from 'react';
import { useLocation } from 'react-router-dom';
import { Routes } from "../services/Routes";
export default function DeleteUser() {
const search = useLocation().search;
@ -11,7 +12,7 @@ export default function DeleteUser() {
useEffect(() => {
//const { id } = this.props.match.params;
getData('Users/' + id).then(
getData(EndPoints.USERS + "/" + id).then(
(result) => {
console.log("Role for edit: ");
console.log(result);
@ -41,16 +42,16 @@ export default function DeleteUser() {
});
function onCancel() {
navigate('/admin/users');
navigate(Routes.USERS);
}
function onConfirmation(e) {
e.preventDefault();
deleteData('Users/' + id).then((result) => {
deleteData(EndPoints.USERS + "/" + id).then((result) => {
let responseJson = result;
if (responseJson) {
navigate('/admin/users');
navigate(Routes.USERS);
}
}
);

View File

@ -1,7 +1,8 @@
import { getData, putData } from "../services/AccessAPI";
import { getData, putData, EndPoints } from "../services/AccessAPI";
import { useNavigate, useLocation } from "react-router-dom";
import { useEffect } from "react";
import { useState } from 'react';
import { Routes } from "../services/Routes";
export default function UpdateUser() {
let navigate = useNavigate();
@ -18,7 +19,7 @@ export default function UpdateUser() {
useEffect(() => {
//const id = location.pathName.slice(location.pathName.lastIndexOf("/") , location.pathName.length);
getData('Users/' + id).then(
getData(EndPoints.USERS + "/" + id).then(
(result) => {
//let responseJson = result;
console.log("user for edit: ");
@ -43,7 +44,7 @@ export default function UpdateUser() {
}
function onUpdateCancel() {
navigate('/admin/users');
navigate(Routes.USERS);
}
function onSubmit(e){
@ -59,7 +60,7 @@ export default function UpdateUser() {
Email: email,
}
putData('Users/' + id, userProfile).then((result) => {
putData(EndPoints.USERS + "/" + id, userProfile).then((result) => {
console.log("Put Request body: ");
console.log(userProfile);
@ -68,7 +69,7 @@ export default function UpdateUser() {
if(responseJson){
console.log(responseJson);
navigate('/admin/users');
navigate(Routes.USERS);
}
}
);

View File

@ -1,7 +1,8 @@
import { getData } from "../services/AccessAPI";
import { getData, EndPoints } from "../services/AccessAPI";
import { useNavigate } from "react-router-dom";
import { useEffect } from "react";
import { useState } from 'react';
import { Routes } from "../services/Routes";
export default function Users() {
useEffect(() => {
@ -16,23 +17,21 @@ export default function Users() {
});
function onUserCreate() {
navigate('/admin/user/create');
navigate(Routes.USER_CREATE);
}
function onUserEdit(id){
let path = "/admin/user/edit"
let query = "?id=" + id
navigate(path + query);
navigate(Routes.USER_EDIT + query);
}
function onUserDelete(id){
let path = "/admin/user/delete"
let query = "?id=" + id
navigate(path + query);
navigate(Routes.USER_DELETE + query);
}
function getAllUsersData() {
getData('Users/').then(
getData(EndPoints.USERS).then(
(result) => {
if (result) {
console.log(result);

View File

@ -30,7 +30,7 @@ public class TransactionsController : ControllerBase
}
[HttpGet]
public IActionResult GetAll()
public IActionResult GetAll(int? accountId = null)
{
List<TransactionDto> transactionDtos = new List<TransactionDto>();

View File

@ -41,16 +41,10 @@ public class AutoMapperProfile : Profile
// AccountUpdateRequest -> Account
CreateMap<AccountUpdateRequest, Account>()
.ForAllMembers(x => x.Condition(
(src, dest, prop) =>
{
// ignore both null & empty string properties
if (prop == null) return false;
if (prop.GetType() == typeof(string) && string.IsNullOrEmpty((string)prop)) return false;
return true;
}
));
.ForMember(
dest => dest.OwnerId,
opt => opt.MapFrom(src => src.Owner)
);
// AccountCreateRequest -> Account
CreateMap<AccountCreateRequest, Account>()

View File

@ -5,11 +5,9 @@ using active_allocator.Entities;
public class AccountUpdateRequest
{
public string Name { get; set; }
public int OwnerId { get; set; }
public string InitialBalance { get; set; }
public int CurrencyId { get; set; }
public string ExternalAccountNumber { get; set; }
public ICollection<int> Allocs { get; set; }
public string Name { get; set; } = null;
public int? Owner { get; set; } = null;
public string InitialBalance { get; set; } = null;
public int? Currency { get; set; } = null;
public string ExternalAccountNumber { get; set; } = null;
}

View File

@ -10,6 +10,7 @@ using System.Collections.Generic;
using System.Linq;
using System;
using Internal;
using Microsoft.EntityFrameworkCore;
public interface IAccountService
{
@ -87,18 +88,71 @@ public class AccountService : IAccountService
public void Update(int id, AccountUpdateRequest model)
{
var account = getAccount(id);
Account account = getAccount(id);
// validate
if (model.Name != account.Name && _context.Accounts.Any(x => x.Name == model.Name))
throw new AppException("Account with the name '" + model.Name + "' already exists");
// Name
if (!string.IsNullOrWhiteSpace(model.Name))
account.Name = model.Name;
// Owner
if (model.Owner.HasValue)
{
account.OwnerId = model.Owner.Value;
account.Owner = _userService.GetById(model.Owner.Value);
}
// Initial Balance
if (!string.IsNullOrWhiteSpace(model.InitialBalance))
account.InitialBalance = Convert.ToDecimal(model.InitialBalance);
// CurrencyType
if (model.Currency.HasValue)
{
account.CurrencyId = model.Currency.Value;
account.Currency = _context.CurrencyTypes.Find(model.Currency.Value);
}
// External Account Number
if (!string.IsNullOrWhiteSpace(model.ExternalAccountNumber))
account.ExternalAccountNumber = model.ExternalAccountNumber;
// copy model to account and save
_mapper.Map(model, account);
//_mapper.Map(model, account);
account.Balance = RecalculateBalance(id);
_context.Accounts.Update(account);
_context.SaveChanges();
}
//NEEDS TO BE SWITCHED TO AN EVENT HANDLER STYLE IMPLEMENTATION
public decimal RecalculateBalance(int id)
{
Account account = getAccount(id);
decimal amount = account.InitialBalance;
List<Transaction> transactions = _context.Transactions
.Include(t => t.DebitAccount)
.Include(t => t.CreditAccount)
.Where(t =>
(t.DebitAccount != null && t.DebitAccount.Id == id)
|| (t.CreditAccount != null && t.CreditAccount.Id == id))
.ToList();
foreach (Transaction t in transactions)
{
if (t.DebitAccount?.Id == id) {
amount -= t.Amount;
} else if (t.CreditAccount?.Id == id) {
amount += t.Amount;
}
}
return amount;
}
public void Delete(int id)
{
var account = getAccount(id);

View File

@ -64,6 +64,9 @@ public class TransactionService : ITransactionService
IsPending = model.IsPending,
};
if (transaction.DebitAccount.Id == transaction.CreditAccount.Id)
throw new AppException("The debit and credit accounts of a transaction cannot be the same.");
// Transaction Duplication Check
if (transaction.ExternalId != null && _context.Transactions.Any(x => x.ExternalId == transaction.ExternalId))
throw new AppException("Transaction with the external ID '" + transaction.ExternalId + "' already exists");

View File

@ -1,6 +1,6 @@
{
"ConnectionStrings": {
"PSQLConnection": "Server=localhost;Port=15432;Database=AADB;User Id=postgres;Password=nqA3UV3CliLLHpLL"
"PSQLConnection": "Server=localhost;Port=15432;Database=aadb;User Id=postgres;Password=nqA3UV3CliLLHpLL"
},
"Logging": {
"LogLevel": {