Compare commits

...

2 Commits

8 changed files with 218 additions and 26 deletions

View File

@ -13,6 +13,8 @@ Reference for adding JWT authentication is [here](https://jasonwatmore.com/net-7
### User Interface
Use [layoutit.com](https://www.layoutit.com/build).
* View Income overview
* Projected Income - Based on statistical metrics (with controls for fine-tuning sample date range)
* Historical Income (with source breakdown)

View File

@ -3,6 +3,8 @@ 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(() => {
@ -46,31 +48,40 @@ export default function Accounts() {
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={account.owner} /></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)} />
</td>
</tr>
))
}
</tbody>
</table>
</div>
</div>
</div>
);
}

View File

@ -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)
);
}

View File

@ -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>
);
}

View File

@ -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>
*/
}

View File

@ -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>
);
}

View File

@ -3,6 +3,7 @@ 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(() => {
@ -74,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)
)