Compare commits
10 Commits
095fcd88f4
...
585bb26773
Author | SHA1 | Date | |
---|---|---|---|
585bb26773 | |||
4df133699a | |||
03406b8b4d | |||
2404fd9444 | |||
46bdab07b3 | |||
7974eb8687 | |||
40fe18d89e | |||
1edebc9dda | |||
e77b9c1bc1 | |||
57abe0bb4c |
@ -13,6 +13,10 @@ Reference for adding JWT authentication is [here](https://jasonwatmore.com/net-7
|
||||
|
||||
### User Interface
|
||||
|
||||
Use [layoutit.com](https://www.layoutit.com/build).
|
||||
|
||||
[React Select](https://react-select.com/home#fixed-options)
|
||||
|
||||
* View Income overview
|
||||
* Projected Income - Based on statistical metrics (with controls for fine-tuning sample date range)
|
||||
* Historical Income (with source breakdown)
|
||||
|
932
active-allocator/ClientApp/package-lock.json
generated
932
active-allocator/ClientApp/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -9,10 +9,12 @@
|
||||
"merge": "^2.1.1",
|
||||
"oidc-client": "^1.11.5",
|
||||
"react": "^18.2.0",
|
||||
"react-datepicker": "^4.25.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-bootstrap": "^0.26.2",
|
||||
"react-router-dom": "^6.11.0",
|
||||
"react-scripts": "^5.0.1",
|
||||
"react-select": "^5.8.0",
|
||||
"reactstrap": "^9.1.9",
|
||||
"rimraf": "^5.0.0",
|
||||
"web-vitals": "^3.3.1",
|
||||
|
@ -5,13 +5,17 @@ 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";
|
||||
import CreateTransaction from "./components/transactions/CreateTransaction";
|
||||
|
||||
const AppRoutes = [
|
||||
{
|
||||
@ -19,59 +23,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: <CreateTransaction />
|
||||
},
|
||||
{
|
||||
path: Routes.TRANSACTION_EDIT,
|
||||
element: <UpdateAccount />
|
||||
},
|
||||
{
|
||||
path: Routes.TRANSACTION_DELETE,
|
||||
element: <DeleteAccount />
|
||||
},
|
||||
];
|
||||
|
@ -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>
|
||||
</>
|
||||
}
|
||||
|
@ -1,11 +1,15 @@
|
||||
import { getData } from "../services/AccessAPI";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { EndPoints, getData, putData } from "../services/AccessAPI";
|
||||
import { RouterProvider, useNavigate } from "react-router-dom";
|
||||
import { useEffect } from "react";
|
||||
import { useState } from 'react';
|
||||
import { Routes } from "../services/Routes";
|
||||
import RowButton from "../ui-elements/table/RowButton";
|
||||
import DataFormatter, { RenderType } from "../ui-elements/table/DataFormatter";
|
||||
|
||||
export default function Accounts() {
|
||||
useEffect(() => {
|
||||
getAllAccountsData();
|
||||
getAllUsersData();
|
||||
}, [])
|
||||
|
||||
let navigate = useNavigate();
|
||||
@ -15,27 +19,26 @@ export default function Accounts() {
|
||||
loading: false
|
||||
});
|
||||
|
||||
const [users, setUsers] = useState(null);
|
||||
|
||||
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);
|
||||
setState({
|
||||
accounts: result,
|
||||
loading: false
|
||||
@ -45,33 +48,68 @@ export default function Accounts() {
|
||||
);
|
||||
}
|
||||
|
||||
function getAllUsersData() {
|
||||
getData(EndPoints.USERS).then(
|
||||
(result) => {
|
||||
if (result) {
|
||||
setUsers(result);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function refreshAccount(id) {
|
||||
getData(EndPoints.ACCOUNTS_REFRESHBALANCE + "/" + id).then(
|
||||
(result) => {
|
||||
if (result) {
|
||||
getAllAccountsData();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function findUserName(id) {
|
||||
return users?.find(x => x.id)?.username;
|
||||
}
|
||||
|
||||
function renderAllAccountsTable(accounts) {
|
||||
return (
|
||||
<table className="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Owner</th>
|
||||
<th>Balance</th>
|
||||
<th>External Account Number</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{
|
||||
accounts.map(account => (
|
||||
<tr key={account.id}>
|
||||
<td>{account.name}</td>
|
||||
<td>{account.owner}</td>
|
||||
<td>{account.balance}</td>
|
||||
<td>{account.externalAccountNumber}</td>
|
||||
<td><button onClick={() => onAccountEdit(account.id)} className="btn btn-success">Edit</button> ||
|
||||
<button onClick={() => onAccountDelete(account.id)} className="btn btn-danger">Delete</button></td>
|
||||
</tr>
|
||||
))
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
<div className="container-fluid">
|
||||
<div className="row">
|
||||
<div className="col-md-12">
|
||||
<table className="table table-sm table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Owner</th>
|
||||
<th>Balance</th>
|
||||
<th>External Account Number</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{
|
||||
accounts.map(account => (
|
||||
<tr key={account.id}>
|
||||
<td><DataFormatter data={account.name} /></td>
|
||||
<td><DataFormatter data={findUserName(account.ownerId)} /></td>
|
||||
<td><DataFormatter data={account.balance} renderType={RenderType.MoneyUnsigned} /></td>
|
||||
<td><DataFormatter data={account.externalAccountNumber} /></td>
|
||||
<td>
|
||||
<RowButton className="btn btn-sm btn-outline-primary" text="Edit" onClick={() => onAccountEdit(account.id)} />
|
||||
|
||||
<RowButton className="btn btn-sm btn-outline-danger" text="Delete" onClick={() => onAccountDelete(account.id)} />
|
||||
|
||||
<RowButton className="btn btn-sm btn-outline-warning" text="Refresh" onClick={() => refreshAccount(account.id)} />
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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">
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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">
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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(){
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -1,6 +1,15 @@
|
||||
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",
|
||||
ACCOUNTS_REFRESHBALANCE: "Accounts/RefreshBalance",
|
||||
CURRENCYTYPES: "CurrencyTypes",
|
||||
TRANSACTIONS: "Transactions",
|
||||
}
|
||||
|
||||
export function getData(endPoint) {
|
||||
|
||||
|
20
active-allocator/ClientApp/src/components/services/Routes.js
Normal file
20
active-allocator/ClientApp/src/components/services/Routes.js
Normal 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",
|
||||
};
|
@ -0,0 +1,167 @@
|
||||
import SessionManager from "../auth/SessionManager";
|
||||
import { EndPoints, postData, getData } from "../services/AccessAPI";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useState } from 'react';
|
||||
import { useEffect } from "react";
|
||||
import { Routes } from "../services/Routes";
|
||||
import Select from 'react-select'
|
||||
import DatePicker from 'react-datepicker'
|
||||
|
||||
export default function CreateTransaction() {
|
||||
useEffect(() => {
|
||||
getAllAccountsData();
|
||||
//getAllUsersData();
|
||||
}, [])
|
||||
|
||||
let navigate = useNavigate();
|
||||
|
||||
//const [users, setUsers] = useState(null);
|
||||
const [accounts, setAccounts] = useState([]);
|
||||
const [description, setDescription] = useState("");
|
||||
//const [owner, setOwner] = useState(0);
|
||||
const [date, setDate] = useState("");
|
||||
const [debitAccount, setDebitAccount] = useState(0);
|
||||
const [creditAccount, setCreditAccount] = useState(0);
|
||||
const [amount, setAmount] = useState(0);
|
||||
const [notes, setNotes] = useState("");
|
||||
//const [currencyType, setCurrencyType] = useState(0);
|
||||
const [extNum, setExtNum] = useState("");
|
||||
const [isPending, setIsPending] = useState(false);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
function onSubmit(e) {
|
||||
e.preventDefault();
|
||||
|
||||
let transactionObj = {
|
||||
owner: SessionManager.getUserId(),
|
||||
date: date,//"2023-12-23T19:29:12.909Z"
|
||||
externalId: extNum,
|
||||
description: description,
|
||||
debitAccount: debitAccount,
|
||||
creditAccount: creditAccount,
|
||||
amount: amount,
|
||||
currencyType: 1,
|
||||
notes: notes,
|
||||
isPending: isPending
|
||||
}
|
||||
|
||||
postData(EndPoints.TRANSACTIONS, transactionObj).then((result) => {
|
||||
setLoading(false);
|
||||
let responseJson = result;
|
||||
if (responseJson) {
|
||||
navigate(Routes.ACCOUNTS);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getAllAccountsData() {
|
||||
getData(EndPoints.ACCOUNTS).then(
|
||||
(result) => {
|
||||
if (result) {
|
||||
setAccounts(result.map(a => {
|
||||
return {
|
||||
value: a.id,
|
||||
label: a.name
|
||||
}
|
||||
}));
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/*function getAllUsersData() {
|
||||
getData(EndPoints.USERS).then(
|
||||
(result) => {
|
||||
if (result) {
|
||||
setUsers(result);
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
);
|
||||
}*/
|
||||
|
||||
function onClickBack(e){
|
||||
e.preventDefault();
|
||||
|
||||
if(SessionManager.getToken()){
|
||||
navigate(Routes.TRANSACTIONS);
|
||||
}else{
|
||||
navigate(Routes.LOGIN);
|
||||
}
|
||||
}
|
||||
const options = [
|
||||
{ value: 'chocolate', label: 'Chocolate' },
|
||||
{ value: 'strawberry', label: 'Strawberry' },
|
||||
{ value: 'vanilla', label: 'Vanilla' }
|
||||
]
|
||||
|
||||
/*
|
||||
{
|
||||
"date": "2023-12-23T21:44:31.930Z",
|
||||
"isPending": true
|
||||
}
|
||||
*/
|
||||
return (
|
||||
<div className="row">
|
||||
<div className="col-md-4">
|
||||
<h3>Create new transaction</h3>
|
||||
<form onSubmit={onSubmit}>
|
||||
<div className="form-group">
|
||||
<label className="control-label">Description: </label>
|
||||
<input className="form-control" type="text" name="description" value={description} onChange={(e) => setDescription(e.target.value)}></input>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label className="control-label">Amount: </label>
|
||||
<input className="form-control" type="text" name="amount" value={amount} onChange={(e) => setAmount(e.target.value)}></input>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label className="control-label">Debit Account: </label>
|
||||
<Select onChange={(e) => setDebitAccount(e.value)} name="debitAccount" options={accounts} isSearchable="true" isLoading={loading} />
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label className="control-label">Credit Account: </label>
|
||||
<Select onChange={(e) => setCreditAccount(e.value)} name="creditAccount" options={accounts} isSearchable="true" isLoading={loading} />
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label className="control-label">Date: </label>
|
||||
{/*<DatePicker selected={date} onChange={(date) => setDate(date)} />*/}
|
||||
<input className="form-control" type="text" name="date" value={date} onChange={(e) => setDate(e.target.value)}></input>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label className="control-label">External Transaction Number: </label>
|
||||
<input className="form-control" type="text" name="extNum" value={extNum} onChange={(e) => setExtNum(e.target.value)}></input>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label className="control-label">Notes: </label>
|
||||
<input className="form-control" type="text" name="notes" value={notes} onChange={(e) => setNotes(e.target.value)}></input>
|
||||
</div>
|
||||
|
||||
<div className="form-check">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="isPending"
|
||||
checked={isPending}
|
||||
onChange={(e) => setIsPending(!isPending)}
|
||||
className="form-check-input"
|
||||
/>
|
||||
Is Pending
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<input type="submit" value="Create Transaction" className="btn btn-primary"></input>
|
||||
<input type="button" value="Back" onClick={onClickBack} className="btn btn-primary"></input>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -0,0 +1,131 @@
|
||||
import { EndPoints, getData } from "../services/AccessAPI";
|
||||
import { useNavigate, useLocation } from "react-router-dom";
|
||||
import { useEffect } from "react";
|
||||
import { useState } from 'react';
|
||||
import { Routes } from "../services/Routes";
|
||||
import RowButton from "../ui-elements/table/RowButton";
|
||||
import DataFormatter, { RenderType } from "../ui-elements/table/DataFormatter";
|
||||
|
||||
export default function Transactions() {
|
||||
useEffect(() => {
|
||||
getAllTransactionsData();
|
||||
getAllAccountsData();
|
||||
}, [])
|
||||
|
||||
let navigate = useNavigate();
|
||||
//const search = useLocation().search;
|
||||
//const accountId = new URLSearchParams(search).get('accountId')
|
||||
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [transactions, setTransactions] = useState([]);
|
||||
const [accounts, setAccounts] = useState([]);
|
||||
|
||||
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 = EndPoints.TRANSACTIONS + '/';
|
||||
/*if (accountId) {
|
||||
url += '?accountId=' + accountId;
|
||||
}*/
|
||||
|
||||
getData(EndPoints.TRANSACTIONS).then(
|
||||
(result) => {
|
||||
if (result) {
|
||||
console.log()
|
||||
setTransactions(result);
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function getAllAccountsData() {
|
||||
getData(EndPoints.ACCOUNTS).then(
|
||||
(result) => {
|
||||
if (result) {
|
||||
setAccounts(result);
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function findAccountName(id) {
|
||||
let name = accounts?.find(x => x.id == id)?.name;
|
||||
console.log("Id: " + id + ", Name: " + name);
|
||||
return name;
|
||||
}
|
||||
|
||||
function renderAllTransactionsTable(transactions) {
|
||||
return (
|
||||
<div className="container-fluid">
|
||||
<div className="row">
|
||||
<div className="col-md-12">
|
||||
<table className="table table-sm 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><DataFormatter data={transaction.amount} renderType={RenderType.MoneyUnsigned}/></td>
|
||||
<td><DataFormatter data={transaction.description} /></td>
|
||||
<td><DataFormatter data={transaction.date} /></td>
|
||||
<td><DataFormatter data={transaction.externalId} /></td>
|
||||
<td><DataFormatter data={findAccountName(transaction.debitAccountId)} /></td>
|
||||
<td><DataFormatter data={findAccountName(transaction.creditAccountId)} /></td>
|
||||
<td><DataFormatter data={transaction.isPending ? "True" : "False"} /></td>
|
||||
<td>
|
||||
<RowButton className="btn btn-sm btn-outline-primary" text="Edit" onClick={() => onTransactionEdit(transaction.id)} />
|
||||
|
||||
<RowButton className="btn btn-sm btn-outline-danger" text="Delete" onClick={() => onTransactionDelete(transaction.id)} />
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
let content = loading ? (
|
||||
<p>
|
||||
<em>Loading...</em>
|
||||
</p>
|
||||
) : (
|
||||
renderAllTransactionsTable(transactions)
|
||||
)
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h3>List of Transactions</h3>
|
||||
<button onClick={() => onTransactionCreate()} className="btn btn-primary">Create new transaction</button>
|
||||
{content}
|
||||
</div>
|
||||
);
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
import React from 'react';
|
||||
import '../main.css';
|
||||
|
||||
export const RenderType = {
|
||||
MoneyUnsigned: "money-unsigned",
|
||||
MoneySigned: "money-signed",
|
||||
MoneyNoColor: "money-nocolor",
|
||||
MoneyNothing: "money-nothing",
|
||||
}
|
||||
|
||||
export default function DataFormatter({
|
||||
data,
|
||||
renderType,
|
||||
currencySymbol = "$"
|
||||
}) {
|
||||
|
||||
const isNotUndefinedOrNull = (object) => {
|
||||
return !(object === undefined || object === null);
|
||||
}
|
||||
|
||||
function filterData(data) {
|
||||
if (renderType != undefined && renderType != null) {
|
||||
let num = Number(data)
|
||||
let moneySign = true;
|
||||
|
||||
switch (renderType)
|
||||
{
|
||||
case RenderType.MoneyUnsigned:
|
||||
moneySign = false;
|
||||
case RenderType.MoneySigned:
|
||||
if (num >= 0) {
|
||||
return <span className='text-success'>{ moneySign && "+"}{currencySymbol + (Math.round(num * 100) / 100).toFixed(2)}</span>
|
||||
} else {
|
||||
return <span className='text-danger'>{ moneySign && "-"}{currencySymbol + (Math.round(num * -100) / 100).toFixed(2)}</span>
|
||||
}
|
||||
break;
|
||||
case RenderType.MoneyNoColor:
|
||||
if (num >= 0) {
|
||||
return moneySign && "+" + currencySymbol + (Math.round(num * 100) / 100).toFixed(2)
|
||||
} else {
|
||||
return moneySign && "-" + currencySymbol + (Math.round(num * -100) / 100).toFixed(2)
|
||||
}
|
||||
case RenderType.MoneyNothing:
|
||||
return currencySymbol + (Math.round(Math.abs(num) * 100) / 100).toFixed(2)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
return (
|
||||
filterData(data)
|
||||
);
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
import React from 'react';
|
||||
import '../main.css';
|
||||
|
||||
export default function RowButton({ text, onClick, hidden, className, disabled }) {
|
||||
return (
|
||||
<button disabled={disabled} className={className} onClick={onClick} hidden={hidden}>
|
||||
{text}
|
||||
</button>
|
||||
);
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
import React from 'react';
|
||||
import '../main.css';
|
||||
//import VintageButton from '../../VintageButton';
|
||||
//import { Badge } from 'reactstrap';
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
export default function Table({
|
||||
headerRender,
|
||||
bodyRender,
|
||||
}) {
|
||||
let navigate = useNavigate();
|
||||
const routeChange = () =>{
|
||||
//let path = `/services/gallery/project?id=` + projectId;
|
||||
//navigate(path);
|
||||
}
|
||||
|
||||
const isNotUndefinedOrNull = (object) => {
|
||||
return !(object === undefined || object === null);
|
||||
}
|
||||
|
||||
return (
|
||||
<table>
|
||||
<thead>
|
||||
{ headerRender() }
|
||||
</thead>
|
||||
<tbody>
|
||||
{ bodyRender() }
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
|
||||
/*
|
||||
|
||||
<div className="outer-border floating-shadow vintage-gallery-card">
|
||||
<div className="mid-border">
|
||||
<div className="inner-border card">
|
||||
<img src={imageUrl} className='card-img-top' style={{borderRadius: 0}} alt={imageCaption}/>
|
||||
{(isNotUndefinedOrNull(title) || isNotUndefinedOrNull(dateText) || isNotUndefinedOrNull(body)
|
||||
|| isNotUndefinedOrNull(priceText) || isNotUndefinedOrNull(buttonText)) &&
|
||||
<div className='card-body'>
|
||||
{isNotUndefinedOrNull(title) && <h5 className='card-title'>{title}</h5>}
|
||||
{isNotUndefinedOrNull(dateText) && <p>{dateText}</p>}
|
||||
{isNotUndefinedOrNull(body) && <p className='card-text'>{body}</p>}
|
||||
{isNotUndefinedOrNull(priceText) && <p style={{fontSize: 20}}><Badge className='vintage-badge' color='dark'>{priceText}</Badge></p>}
|
||||
{isNotUndefinedOrNull(buttonText) && <VintageButton text={buttonText} onClick={routeChange}></VintageButton>}
|
||||
</div>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
*/
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
import React from 'react';
|
||||
import '../main.css';
|
||||
|
||||
export default function Tr({
|
||||
keyValue,
|
||||
body
|
||||
}) {
|
||||
|
||||
const isNotUndefinedOrNull = (object) => {
|
||||
return !(object === undefined || object === null);
|
||||
}
|
||||
|
||||
function filterData(data) {
|
||||
return data
|
||||
}
|
||||
|
||||
console.log("Key: " + keyValue);
|
||||
|
||||
return (
|
||||
<tr key={keyValue}>{ body }</tr>
|
||||
);
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -1,7 +1,9 @@
|
||||
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";
|
||||
import RowButton from "../ui-elements/table/RowButton";
|
||||
|
||||
export default function Users() {
|
||||
useEffect(() => {
|
||||
@ -16,23 +18,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);
|
||||
@ -75,12 +75,52 @@ export default function Users() {
|
||||
);
|
||||
}
|
||||
|
||||
function renderBootstrapTable(users) {
|
||||
return (
|
||||
<div className="container-fluid">
|
||||
<div className="row">
|
||||
<div className="col-md-12">
|
||||
<table className="table table-sm table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>First Name</th>
|
||||
<th>Last Name</th>
|
||||
<th>User Name</th>
|
||||
<th>Email</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{
|
||||
users.map(user => (
|
||||
<tr key={user.id}>
|
||||
<td>{user.firstName}</td>
|
||||
<td>{user.lastName}</td>
|
||||
<td>{user.username}</td>
|
||||
<td>{user.email}</td>
|
||||
<td>
|
||||
<RowButton className="btn btn-sm btn-outline-primary" text="Edit" onClick={() => onUserEdit(user.id)} />
|
||||
|
||||
<RowButton className="btn btn-sm btn-outline-danger" text="Delete" onClick={() => onUserDelete(user.id)} />
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
let content = state.loading ? (
|
||||
<p>
|
||||
<em>Loading...</em>
|
||||
</p>
|
||||
) : (
|
||||
renderAllUsersTable(state.users)
|
||||
//renderAllUsersTable(state.users)
|
||||
renderBootstrapTable(state.users)
|
||||
)
|
||||
|
||||
|
||||
|
@ -67,4 +67,11 @@ public class AccountsController : ControllerBase
|
||||
_accountService.Delete(id);
|
||||
return Ok(new { message = "account deleted" });
|
||||
}
|
||||
|
||||
[HttpGet("RefreshBalance/{id}")]
|
||||
public IActionResult RefreshBalance(int id)
|
||||
{
|
||||
Account account = _accountService.RefreshAccountBalance(id);
|
||||
return Ok(_mapper.Map<Account, AccountDTO>(account));
|
||||
}
|
||||
}
|
@ -30,7 +30,7 @@ public class TransactionsController : ControllerBase
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult GetAll()
|
||||
public IActionResult GetAll(int? accountId = null)
|
||||
{
|
||||
List<TransactionDto> transactionDtos = new List<TransactionDto>();
|
||||
|
||||
|
@ -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>()
|
||||
|
@ -3,6 +3,7 @@ namespace active_allocator.Helpers;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using active_allocator.Entities;
|
||||
using System.Diagnostics;
|
||||
using System;
|
||||
|
||||
public class DataContext : DbContext
|
||||
{
|
||||
@ -19,6 +20,44 @@ public class DataContext : DbContext
|
||||
options.UseInMemoryDatabase("TestDb");
|
||||
}*/
|
||||
|
||||
public void AddAmountToAccount(int accoundId, decimal amount)
|
||||
{
|
||||
Account account = this.Accounts.Find(accoundId);
|
||||
if (account != null)
|
||||
{
|
||||
account.Balance += amount;
|
||||
this.Accounts.Update(account);
|
||||
this.SaveChanges();
|
||||
}
|
||||
}
|
||||
|
||||
public void RecalculateAccountBalance(int id)
|
||||
{
|
||||
Account account = this.Accounts.Find(id);
|
||||
decimal amount = account.InitialBalance;
|
||||
|
||||
List<Transaction> transactions = this.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;
|
||||
}
|
||||
}
|
||||
|
||||
account.Balance = amount;
|
||||
this.Accounts.Update(account);
|
||||
this.SaveChanges();
|
||||
}
|
||||
|
||||
public DbSet<User> Users { get; set; }
|
||||
public DbSet<Account> Accounts { get; set; }
|
||||
public DbSet<Alloc> Allocs { get; set; }
|
||||
|
@ -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;
|
||||
}
|
@ -10,14 +10,16 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using Internal;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
public interface IAccountService
|
||||
{
|
||||
IEnumerable<Account> GetAll();
|
||||
Account GetById(int id);
|
||||
Account GetById(int accountId);
|
||||
void Create(AccountCreateRequest model);
|
||||
void Update(int id, AccountUpdateRequest model);
|
||||
void Delete(int id);
|
||||
void Update(int accountId, AccountUpdateRequest model);
|
||||
Account RefreshAccountBalance(int accountId);
|
||||
void Delete(int accountId);
|
||||
}
|
||||
|
||||
public class AccountService : IAccountService
|
||||
@ -44,9 +46,9 @@ public class AccountService : IAccountService
|
||||
return _context.Accounts;
|
||||
}
|
||||
|
||||
public Account GetById(int id)
|
||||
public Account GetById(int accountId)
|
||||
{
|
||||
return getAccount(id);
|
||||
return getAccount(accountId);
|
||||
}
|
||||
|
||||
public void Create(AccountCreateRequest model)
|
||||
@ -85,23 +87,56 @@ public class AccountService : IAccountService
|
||||
_context.SaveChanges();
|
||||
}
|
||||
|
||||
public void Update(int id, AccountUpdateRequest model)
|
||||
public void Update(int accountId, AccountUpdateRequest model)
|
||||
{
|
||||
var account = getAccount(id);
|
||||
Account account = getAccount(accountId);
|
||||
|
||||
// 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);
|
||||
_context.Accounts.Update(account);
|
||||
_context.SaveChanges();
|
||||
_context.RecalculateAccountBalance(accountId);
|
||||
}
|
||||
|
||||
public void Delete(int id)
|
||||
public Account RefreshAccountBalance(int accountId)
|
||||
{
|
||||
var account = getAccount(id);
|
||||
_context.RecalculateAccountBalance(accountId);
|
||||
return _context.Accounts.Find(accountId);
|
||||
}
|
||||
|
||||
public void Delete(int accountId)
|
||||
{
|
||||
var account = getAccount(accountId);
|
||||
_context.Accounts.Remove(account);
|
||||
_context.SaveChanges();
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Internal;
|
||||
|
||||
public interface ITransactionService
|
||||
{
|
||||
@ -47,6 +48,20 @@ public class TransactionService : ITransactionService
|
||||
return getTransaction(id);
|
||||
}
|
||||
|
||||
private Account prepareAccount(int? accountId)
|
||||
{
|
||||
if (accountId == null || accountId.Value == 0)
|
||||
{
|
||||
accountId = 0;
|
||||
}
|
||||
|
||||
Account account = _context.Accounts.Find(accountId.Value);
|
||||
if (account == null)
|
||||
throw new AppException("Could not find account with ID of '" + accountId.Value + "'.");
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
public void Create(TransactionCreate model)
|
||||
{
|
||||
Transaction transaction = new Transaction {
|
||||
@ -55,17 +70,20 @@ public class TransactionService : ITransactionService
|
||||
Date = model.Date,
|
||||
CreatedOn = DateTime.UtcNow,
|
||||
UpdatedOn = DateTime.UtcNow,
|
||||
ExternalId = model.ExternalId,
|
||||
DebitAccount = model.DebitAccount == null ? null : _context.Accounts.Find(model.DebitAccount.Value),
|
||||
CreditAccount = model.CreditAccount == null ? null : _context.Accounts.Find(model.CreditAccount.Value),
|
||||
ExternalId = string.IsNullOrWhiteSpace(model.ExternalId) ? "" : model.ExternalId,
|
||||
DebitAccount = prepareAccount(model.DebitAccount),
|
||||
CreditAccount = prepareAccount(model.CreditAccount),
|
||||
Amount = Convert.ToDecimal(model.Amount),
|
||||
CurrencyType = _context.CurrencyTypes.Find(model.CurrencyType),
|
||||
Notes = model.Notes,
|
||||
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))
|
||||
if (!string.IsNullOrWhiteSpace(transaction.ExternalId) && _context.Transactions.Any(x => x.ExternalId == transaction.ExternalId))
|
||||
throw new AppException("Transaction with the external ID '" + transaction.ExternalId + "' already exists");
|
||||
|
||||
if (_context.Transactions.Any(x =>
|
||||
@ -78,33 +96,22 @@ public class TransactionService : ITransactionService
|
||||
{
|
||||
throw new AppException("Transaction with the same fields already exists");
|
||||
}
|
||||
|
||||
// map model to new account object
|
||||
//var account = _mapper.Map<Account>(model);
|
||||
|
||||
_context.Transactions.Add(transaction);
|
||||
_context.SaveChanges();
|
||||
|
||||
_context.AddAmountToAccount(transaction.DebitAccount.Id, -transaction.Amount);
|
||||
_context.AddAmountToAccount(transaction.CreditAccount.Id, transaction.Amount);
|
||||
}
|
||||
|
||||
/*public void Update(int id, AccountUpdateRequest model)
|
||||
{
|
||||
var account = getOuterTransaction(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");
|
||||
|
||||
// copy model to account and save
|
||||
_mapper.Map(model, account);
|
||||
_context.Accounts.Update(account);
|
||||
_context.SaveChanges();
|
||||
}*/
|
||||
|
||||
public void Delete(int id)
|
||||
{
|
||||
var transaction = getTransaction(id);
|
||||
_context.Transactions.Remove(transaction);
|
||||
_context.SaveChanges();
|
||||
|
||||
_context.AddAmountToAccount(transaction.DebitAccount.Id, transaction.Amount);
|
||||
_context.AddAmountToAccount(transaction.CreditAccount.Id, -transaction.Amount);
|
||||
}
|
||||
|
||||
private Transaction getTransaction(int id)
|
||||
|
@ -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": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user