Merge branch 'add-list-of-transactions' into 'master'

Add list of transactions

See merge request saburly/gangsta/roraccounting!11
This commit was merged in pull request #11.
This commit is contained in:
Senad Uka
2020-09-11 09:55:25 +00:00
10 changed files with 275 additions and 35 deletions

View File

@@ -1,6 +1,12 @@
class MoneyMovesController < ApplicationController
def index
json_response(MoneyMove.find(:all).order(:created_at))
if params[:homie_id]
money_moves = MoneyMove.where(homie_id: params[:homie_id].to_i).all.order(created_at: :desc)
else
money_moves = MoneyMove.all.order(created_at: :desc)
end
json_response money_moves
end
def create

View File

@@ -9,6 +9,7 @@
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-materialize": "^3.3.1",
"react-router-dom": "^5.2.0",
"react-scripts": "3.0.1"
},
"scripts": {

View File

@@ -2,16 +2,19 @@ import React from 'react';
import './App.css';
import { Navbar } from 'react-materialize';
import MakeMoneyMove from './cash/MakeMoneyMove';
import Flow from "./homies/Flow";
import Cash from './cash/Cash';
import Chips from './chips/Chips';
import { BrowserRouter as Router, Route } from "react-router-dom";
import RoutableNavItem from './common/RoutableNavItem';
import {
import {
CRIB,
CHIPS,
MAKE_MONEY_MOVE
MAKE_MONEY_MOVE,
HOMIE_FLOW
} from './RouteNames';
function App() {
return (
<Router>
@@ -37,6 +40,7 @@ function App() {
<div className="autoscrolling">
<Route exact path={CRIB} component={Cash} />
<Route path={HOMIE_FLOW} component={Flow} />
<Route path={CHIPS} component={Chips} />
<Route path={MAKE_MONEY_MOVE} component={MakeMoneyMove} />
</div>

View File

@@ -1,3 +1,4 @@
export const CRIB = '/';
export const CHIPS = '/chips';
export const MAKE_MONEY_MOVE = '/make-money-move';
export const HOMIE_FLOW = '/homie/:homie_id/flow';

View File

@@ -4,6 +4,7 @@ import './Cash.css';
import axios from 'axios';
import { MAKE_MONEY_MOVE } from '../RouteNames';
import { withRouter } from 'react-router-dom';
import { formatMoney } from '../common/formatting';
const Cash = (props) => {
const [homiesCash, setHomiesCash] = useState([]);
@@ -21,17 +22,11 @@ const Cash = (props) => {
getCashForHomies();
}, []);
const formatMoney = (amount) => {
const formatted = Number.parseFloat(amount).toFixed(2);
return `${formatted} KM`;
}
const cashTableBody = homiesCash.map( (homieLine) => {
return (
<tr key={homieLine.homie.id}>
<td className="cash-cell-left">
{ homieLine.homie.name }
<a href={`/homie/${homieLine.homie.id}/flow`}>{ homieLine.homie.name }</a>
</td>
<td className="cash-cell-right">
{ formatMoney(homieLine.amount) }
@@ -44,39 +39,39 @@ const Cash = (props) => {
});
return (
<div>
<div className="container">
<Table>
<thead>
<tr>
<th>
Homie
</th>
<th>
Cash
</th>
<th>
Actions
</th>
</tr>
</thead>
<tbody>
{ cashTableBody }
</tbody>
</Table>
<Table>
<thead>
<tr>
<th>
Homie
</th>
<th>
Cash
</th>
<th>
Actions
</th>
</tr>
</thead>
<tbody>
{ cashTableBody }
</tbody>
</Table>
<Button
<Button
floating
large
className="green"
fab={{direction: 'bottom'}}
waves="light"
icon="add"
icon="add"
onClick={
() => {
props.history.push(MAKE_MONEY_MOVE)
}
}/>
}
/>
</div>
);

View File

@@ -1,6 +1,6 @@
import React, {useState, useEffect} from 'react';
import M from 'materialize-css';
import {Icon, Select, TextInput, Button, Textarea} from 'react-materialize';
import {Icon, Select, Button, Textarea} from 'react-materialize';
import './Cash.css';
import axios from 'axios';

View File

@@ -0,0 +1,16 @@
const formatMoney = (amount) => {
const formatted = Number.parseFloat(amount).toFixed(2);
return `${formatted} KM`;
}
const timestampToDate = (timestamp) => {
const dateOptions = { year: 'numeric', month: 'long', day: 'numeric' };
const date = new Date(timestamp);
return date.toLocaleDateString('en-GB', dateOptions);
}
export {
formatMoney,
timestampToDate
}

View File

@@ -0,0 +1,34 @@
.amount-green {
background-color: rgba(72, 172, 152, 0.35);
padding: 3px 5px;
font-weight: 500;
color: rgb(72, 172, 152);
border-radius: 5px;
}
.opposite-sides-content {
width: 100%;
justify-content: space-between;
}
.flex-row {
display: flex;
flex-direction: row;
align-items: stretch;
}
.flex-center {
align-self: center;
}
.flex-col {
display: flex;
flex-direction: column;
align-items: stretch;
}
.record:hover {
border-left: rgb(72, 172, 152) solid 4px;
box-sizing: border-box;
padding-left: 11px;
}

78
client/src/homies/Flow.js Normal file
View File

@@ -0,0 +1,78 @@
import React, { useState, useEffect } from 'react';
import { withRouter, useParams } from 'react-router-dom';
import axios from "axios";
import M from "materialize-css";
import './Flow.css';
import { formatMoney, timestampToDate } from "../common/formatting";
const Flow = (props) => {
const { homie_id } = useParams();
const [flow, setFlow] = useState([]);
useEffect( () => {
(async () => {
try {
const response = await axios.get(`/api/money_moves?homie_id=${parseInt(homie_id)}`);
if (response.status === 200 && response.data){
setFlow(response.data);
}
} catch (e) {
M.toast({ html: "Yo! It ain't workin'" });
}
})();
}, [homie_id]);
const dateBlock = (timestamp) => <span className="grey-text">{ timestampToDate(timestamp) }</span>
const flowData = flow.map( (singleFlowData, index) => (
<li key={index}>
<div className="collapsible-header record">
<div className="flex-row opposite-sides-content">
<div className="flex-col">
<div>{ singleFlowData.description }</div>
<div>{ dateBlock(singleFlowData['created_at']) }</div>
</div>
<div className={`flex-center ${singleFlowData.amount > 0 ? 'amount-green' : ''}`}>{ formatMoney(singleFlowData.amount) }</div>
</div>
</div>
</li>
));
const totalStats = () => {
const totalCount = flow.length;
const firstFlowRow = totalCount > 0 ? flow[0] : undefined;
const lastFlowRow = totalCount > 0 ? flow[flow.length - 1] : undefined;
const totalFlow = flow.reduce((sum, record) => sum + parseInt(record.amount), 0);
const fromDate = lastFlowRow ? timestampToDate(lastFlowRow['created_at']) : '';
const toDate = firstFlowRow ? timestampToDate(firstFlowRow['created_at']) : '';
return (
<div>
<br />
<div className="row">
<div className="col s6">
<strong>{`${totalCount} Records`}</strong><span className="grey-text">{` ${fromDate} - ${toDate}`}</span>
</div>
<div className="col s6 right-align">
<span className="grey-text">Total flow:</span> <strong>{formatMoney(totalFlow)}</strong>
</div>
</div>
</div>
)
}
return (
<div className="container">
{ totalStats() }
<ul className="collapsible">
{ flowData }
</ul>
</div>
);
}
export default withRouter(Flow);

View File

@@ -859,6 +859,13 @@
dependencies:
regenerator-runtime "^0.13.2"
"@babel/runtime@^7.1.2", "@babel/runtime@^7.5.5":
version "7.11.2"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736"
integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==
dependencies:
regenerator-runtime "^0.13.4"
"@babel/template@^7.1.0", "@babel/template@^7.4.0", "@babel/template@^7.4.4":
version "7.4.4"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237"
@@ -4449,6 +4456,18 @@ hex-color-regex@^1.1.0:
resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e"
integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==
history@^4.9.0:
version "4.10.1"
resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3"
integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==
dependencies:
"@babel/runtime" "^7.1.2"
loose-envify "^1.2.0"
resolve-pathname "^3.0.0"
tiny-invariant "^1.0.2"
tiny-warning "^1.0.0"
value-equal "^1.0.1"
hmac-drbg@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
@@ -4458,6 +4477,13 @@ hmac-drbg@^1.0.0:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1"
hoist-non-react-statics@^3.1.0:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
dependencies:
react-is "^16.7.0"
hosted-git-info@^2.1.4:
version "2.7.1"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047"
@@ -5068,6 +5094,11 @@ is-wsl@^1.1.0:
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=
isarray@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
@@ -5903,7 +5934,7 @@ loglevel@^1.4.1:
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.1.tgz#e0fc95133b6ef276cdc8887cdaf24aa6f156f8fa"
integrity sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@@ -6097,6 +6128,14 @@ mimic-fn@^2.0.0:
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
mini-create-react-context@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.4.0.tgz#df60501c83151db69e28eac0ef08b4002efab040"
integrity sha512-b0TytUgFSbgFJGzJqXPKCFCBWigAjpjo+Fl7Vf7ZbKRDptszpppKxXH6DRXEABZ/gcEQczeb0iZ7JvL8e8jjCA==
dependencies:
"@babel/runtime" "^7.5.5"
tiny-warning "^1.0.3"
mini-css-extract-plugin@0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.5.0.tgz#ac0059b02b9692515a637115b0cc9fed3a35c7b0"
@@ -6845,6 +6884,13 @@ path-to-regexp@0.1.7:
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
path-to-regexp@^1.7.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a"
integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==
dependencies:
isarray "0.0.1"
path-type@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73"
@@ -7893,6 +7939,11 @@ react-error-overlay@^5.1.6:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-5.1.6.tgz#0cd73407c5d141f9638ae1e0c63e7b2bf7e9929d"
integrity sha512-X1Y+0jR47ImDVr54Ab6V9eGk0Hnu7fVWGeHQSOXHf/C2pF9c6uy3gef8QUeuUiWlNb0i08InPSE5a/KJzNzw1Q==
react-is@^16.6.0, react-is@^16.7.0:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
react-is@^16.8.1, react-is@^16.8.4:
version "16.8.6"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16"
@@ -7907,6 +7958,35 @@ react-materialize@^3.3.1:
react "^16.8.5"
react-dom "^16.8.5"
react-router-dom@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.2.0.tgz#9e65a4d0c45e13289e66c7b17c7e175d0ea15662"
integrity sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==
dependencies:
"@babel/runtime" "^7.1.2"
history "^4.9.0"
loose-envify "^1.3.1"
prop-types "^15.6.2"
react-router "5.2.0"
tiny-invariant "^1.0.2"
tiny-warning "^1.0.0"
react-router@5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.2.0.tgz#424e75641ca8747fbf76e5ecca69781aa37ea293"
integrity sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==
dependencies:
"@babel/runtime" "^7.1.2"
history "^4.9.0"
hoist-non-react-statics "^3.1.0"
loose-envify "^1.3.1"
mini-create-react-context "^0.4.0"
path-to-regexp "^1.7.0"
prop-types "^15.6.2"
react-is "^16.6.0"
tiny-invariant "^1.0.2"
tiny-warning "^1.0.0"
react-scripts@3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-3.0.1.tgz#e5565350d8069cc9966b5998d3fe3befe3d243ac"
@@ -8078,6 +8158,11 @@ regenerator-runtime@^0.11.0:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
regenerator-runtime@^0.13.4:
version "0.13.7"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
regenerator-transform@^0.13.4:
version "0.13.4"
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.13.4.tgz#18f6763cf1382c69c36df76c6ce122cc694284fb"
@@ -8261,6 +8346,11 @@ resolve-from@^4.0.0:
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
resolve-pathname@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd"
integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==
resolve-url@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
@@ -9126,6 +9216,16 @@ timsort@^0.3.0:
resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
tiny-invariant@^1.0.2:
version "1.1.0"
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875"
integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==
tiny-warning@^1.0.0, tiny-warning@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
tmp@^0.0.33:
version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
@@ -9484,6 +9584,11 @@ validate-npm-package-license@^3.0.1:
spdx-correct "^3.0.0"
spdx-expression-parse "^3.0.0"
value-equal@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c"
integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==
vary@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"