simplify move money page
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import './App.css';
|
||||
import { Navbar, Dropdown, Icon } from 'react-materialize';
|
||||
import MakeMoneyMove from './cash/MakeMoneyMove';
|
||||
import Flow from "./homies/Flow";
|
||||
import Cash from './cash/Cash';
|
||||
import Homies from './homies/Homies';
|
||||
@@ -11,15 +10,16 @@ import axios from 'axios';
|
||||
import {
|
||||
CRIB,
|
||||
GANGS,
|
||||
MAKE_MONEY_MOVE,
|
||||
HOMIE_FLOW,
|
||||
HOMIES,
|
||||
HOMIE_MOVE_MONEY,
|
||||
PUT_IN_WORK
|
||||
} from './RouteNames';
|
||||
import PutInWork from "./cash/PutInWork";
|
||||
import GangOnboarding from "./gangOnboarding/GangOnboarding";
|
||||
import Gangs from './gangs/Gangs';
|
||||
import {errorToast} from "./common/errorHelpers";
|
||||
import MoveMoney from "./homies/MoveMoney";
|
||||
|
||||
|
||||
const App = (props) => {
|
||||
@@ -50,7 +50,7 @@ const App = (props) => {
|
||||
<Route key='2' exact path={GANGS} component={() => <Gangs gangs={gangs} gangsSetter={setGangs} />} />,
|
||||
<Route key='3' exact path={HOMIES} component={() => <Homies gang={selectedGang} />} />,
|
||||
<Route key='4' path={HOMIE_FLOW} component={() => <Flow gang={selectedGang} />} />,
|
||||
<Route key='5' path={MAKE_MONEY_MOVE} component={() => <MakeMoneyMove gang={selectedGang} />} />,
|
||||
<Route key='5' path={HOMIE_MOVE_MONEY} component={() => <MoveMoney gang={selectedGang} />} />,
|
||||
<Route key='6' path={PUT_IN_WORK} component={() => <PutInWork gang={selectedGang} />} />
|
||||
]
|
||||
);
|
||||
@@ -117,10 +117,6 @@ const App = (props) => {
|
||||
Homies
|
||||
</RoutableNavItem>
|
||||
|
||||
<RoutableNavItem href={MAKE_MONEY_MOVE}>
|
||||
Make Money Move
|
||||
</RoutableNavItem>
|
||||
|
||||
<RoutableNavItem href={PUT_IN_WORK}>
|
||||
Put in Work
|
||||
</RoutableNavItem>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export const CRIB = '/';
|
||||
export const HOMIES = '/homies';
|
||||
export const MAKE_MONEY_MOVE = '/make-money-move';
|
||||
export const HOMIE_MOVE_MONEY = '/homie/:homie_id/move-money';
|
||||
export const PUT_IN_WORK = '/put-in-work';
|
||||
export const HOMIE_FLOW = '/homie/:homie_id/flow';
|
||||
export const GANGS = '/gangs';
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Button, Table } from 'react-materialize';
|
||||
import { Button, Icon, Table } from 'react-materialize';
|
||||
import './Cash.css';
|
||||
import axios from 'axios';
|
||||
import { MAKE_MONEY_MOVE } from '../RouteNames';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import { formatMoney, formatTime } from '../common/formatting';
|
||||
import RoutableNavItem from "../common/RoutableNavItem";
|
||||
@@ -21,7 +20,7 @@ const Cash = (props) => {
|
||||
}
|
||||
};
|
||||
getCashForHomies();
|
||||
}, []);
|
||||
}, [gang]);
|
||||
|
||||
const cashTableBody = homiesCash.map( (homieLine) => {
|
||||
return (
|
||||
@@ -35,7 +34,13 @@ const Cash = (props) => {
|
||||
<td className="cash-cell-right">
|
||||
{ formatMoney(homieLine.amount, gang) }
|
||||
</td>
|
||||
<td className="cash-cell-left">
|
||||
<td className="cash-cell-right">
|
||||
<RoutableNavItem href={`/homie/${homieLine.homie.id}/move-money`}>
|
||||
<Button>
|
||||
Move money
|
||||
<Icon left>monetization_on</Icon>
|
||||
</Button>
|
||||
</RoutableNavItem>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
@@ -52,10 +57,10 @@ const Cash = (props) => {
|
||||
<th>
|
||||
Work
|
||||
</th>
|
||||
<th>
|
||||
<th className="cash-cell-right">
|
||||
Cash
|
||||
</th>
|
||||
<th>
|
||||
<th className="cash-cell-right">
|
||||
Actions
|
||||
</th>
|
||||
</tr>
|
||||
@@ -64,24 +69,8 @@ const Cash = (props) => {
|
||||
{ cashTableBody }
|
||||
</tbody>
|
||||
</Table>
|
||||
|
||||
<Button
|
||||
floating
|
||||
large
|
||||
className="green"
|
||||
fab={{direction: 'bottom'}}
|
||||
waves="light"
|
||||
icon="add"
|
||||
onClick={
|
||||
() => {
|
||||
props.history.push(MAKE_MONEY_MOVE)
|
||||
}
|
||||
}
|
||||
/>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export default withRouter(Cash);
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
import React, {useState, useEffect} from 'react';
|
||||
import M from 'materialize-css';
|
||||
import {Icon, Select, Button, Textarea} from 'react-materialize';
|
||||
import './Cash.css';
|
||||
import axios from 'axios';
|
||||
|
||||
const MakeMoneyMove = (props) => {
|
||||
const [selectedFrom, setSelectedFrom] = useState("");
|
||||
const [selectedTo, setSelectedTo] = useState("-1");
|
||||
const [homiesCash, setHomiesCash] = useState([]);
|
||||
const [amountToMove, setAmountToMove] = useState('');
|
||||
const [moveDescription, setMoveDescription] = useState("");
|
||||
const [submitInProgress, setSubmitInProgress] = useState(false);
|
||||
|
||||
const gang = props.gang;
|
||||
|
||||
useEffect(() => {
|
||||
const getCashForHomies = async () => {
|
||||
try {
|
||||
const cash = await axios.get(`/api/gangs/${gang.id}/homies/info`);
|
||||
setHomiesCash(cash.data);
|
||||
} catch (e) {
|
||||
console.log("Error fetching", e);
|
||||
}
|
||||
};
|
||||
getCashForHomies();
|
||||
}, []);
|
||||
|
||||
const handleAmountChange = (e) => {
|
||||
setAmountToMove(parseFloat(e.target.value))
|
||||
}
|
||||
|
||||
const homieToOptionMapper = (homieCash) => {
|
||||
const homie = homieCash.homie;
|
||||
return (
|
||||
<option key={homie.id} value={homie.id}>{homie.name}</option>
|
||||
);
|
||||
};
|
||||
|
||||
const homieOptions = homiesCash.map(homieToOptionMapper);
|
||||
|
||||
const handleFromHomieChange = (e) => {
|
||||
setSelectedFrom(e.target.value);
|
||||
|
||||
if (selectedTo === e.target.value) {
|
||||
setSelectedTo('-1');
|
||||
}
|
||||
};
|
||||
|
||||
const notSayingOption = <option value="">NOT SAYIN'</option>
|
||||
|
||||
const filteredHomieOptions = () => {
|
||||
if (selectedFrom === ''){
|
||||
return homiesCash.map(homieToOptionMapper);
|
||||
}else{
|
||||
const filteredHomieCashes = homiesCash.filter((homieCash) => homieCash.homie.id !== parseInt(selectedFrom));
|
||||
return [
|
||||
notSayingOption,
|
||||
...filteredHomieCashes.map(homieToOptionMapper)
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const handleToHomieChange = (e) => {
|
||||
setSelectedTo(e.target.value);
|
||||
}
|
||||
|
||||
const handleDescriptionChange = (e) => {
|
||||
setMoveDescription(e.target.value);
|
||||
}
|
||||
|
||||
const clearForm = () => {
|
||||
setAmountToMove("");
|
||||
setSelectedFrom("");
|
||||
setSelectedTo("");
|
||||
setMoveDescription("");
|
||||
}
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
setSubmitInProgress(true);
|
||||
const moneyMoveRequest = {
|
||||
money_move: {
|
||||
amount: amountToMove,
|
||||
from_homie_id: selectedFrom,
|
||||
to_homie_id: selectedTo,
|
||||
description: moveDescription
|
||||
}
|
||||
}
|
||||
|
||||
const submitResponse = await axios.post('/api/money_moves', moneyMoveRequest);
|
||||
|
||||
if (submitResponse && submitResponse.status === 200 && submitResponse.data === true) {
|
||||
M.toast({html: "Money lounde...moved"});
|
||||
clearForm();
|
||||
} else {
|
||||
M.toast({html: "Yo! It ain't workin'"});
|
||||
}
|
||||
setSubmitInProgress(false);
|
||||
}
|
||||
|
||||
const formComplete = () => (
|
||||
selectedFrom !== selectedTo &&
|
||||
selectedTo !== '-1' &&
|
||||
amountToMove > 0
|
||||
);
|
||||
|
||||
const disableSubmit = () => (!formComplete() || submitInProgress);
|
||||
|
||||
return (
|
||||
<div className="center-align container">
|
||||
<form onSubmit={handleSubmit}>
|
||||
<h3>Make Money Move</h3>
|
||||
|
||||
<div className="input-field col s12">
|
||||
<input id="how-much" type="number" className="validate" step="0.01" required="required" value={amountToMove} onChange={handleAmountChange} pattern="^\\?(([1-9](\\d*|\\d{0,2}(,\\d{3})*))|0)(\\.\\d{1,2})?$" />
|
||||
<label className="required" htmlFor="how-much">How much?</label>
|
||||
<span className="helper-text" data-error="Yo! Put some money" />
|
||||
</div>
|
||||
|
||||
<label className="required">From (only if you can say): </label>
|
||||
<Select value={selectedFrom} name="from_homie" onChange={handleFromHomieChange}>
|
||||
{notSayingOption}
|
||||
{homieOptions}
|
||||
</Select>
|
||||
|
||||
<label className="required">To (only if you can say): </label>
|
||||
<Select value={selectedTo} name="to_homie" onChange={handleToHomieChange} required="required">
|
||||
<option disabled value="-1">Select Homie</option>
|
||||
{filteredHomieOptions()}
|
||||
</Select>
|
||||
|
||||
<br/>
|
||||
|
||||
<Textarea label="Tag" value={moveDescription} onChange={handleDescriptionChange}/>
|
||||
|
||||
<div>
|
||||
<Button disabled={disableSubmit()} waves="light">
|
||||
Do it
|
||||
<Icon left>
|
||||
attach_money
|
||||
</Icon>
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
export default MakeMoneyMove;
|
||||
@@ -25,7 +25,7 @@ const PutInWork = (props) => {
|
||||
errorToast();
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
}, [gang]);
|
||||
|
||||
const homieOptions = homies.map(homie => <option key={homie.id} value={homie.id}>{homie.name}</option>);
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { withRouter } from 'react-router-dom';
|
||||
|
||||
const RoutableNavItem = (props) => {
|
||||
return (
|
||||
<NavItem data-target="mobile-nav" className="sidenav-close" onClick={
|
||||
<NavItem data-target="mobile-nav" className={`sidenav-close ${props.additionalClasses}`} onClick={
|
||||
() => {
|
||||
props.history.push(props.href);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React from 'react';
|
||||
import NewGangForm from "./NewGangForm";
|
||||
import axios from "axios";
|
||||
import {errorToast} from "../common/errorHelpers";
|
||||
|
||||
@@ -103,6 +103,20 @@ const CashFlow = (props) => {
|
||||
confirmAction={(settleAmount) => settleFlowForHomie(homie_id, settleAmount)}
|
||||
triggerNode={<Button className="orange">Settle</Button>}
|
||||
/>
|
||||
|
||||
<Button
|
||||
floating
|
||||
large
|
||||
className="green"
|
||||
fab={{direction: 'bottom'}}
|
||||
waves="light"
|
||||
icon="add"
|
||||
onClick={
|
||||
() => {
|
||||
props.history.push(`/homie/${homie_id}/move-money`);
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -36,4 +36,12 @@
|
||||
.switch-box {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.push {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.bump {
|
||||
margin-left: 1em;
|
||||
}
|
||||
@@ -3,9 +3,10 @@ import { withRouter } from 'react-router-dom';
|
||||
import axios from 'axios';
|
||||
import { errorToast } from "../common/errorHelpers";
|
||||
import NewHomieForm from './NewHomieForm';
|
||||
import { Button } from 'react-materialize';
|
||||
import { Button, Icon } from 'react-materialize';
|
||||
import M from 'materialize-css';
|
||||
import YesNoModal from "../common/YesNoModal";
|
||||
import RoutableNavItem from "../common/RoutableNavItem";
|
||||
|
||||
const Homies = (props) => {
|
||||
const [homies, setHomies] = useState([]);
|
||||
@@ -25,7 +26,7 @@ const Homies = (props) => {
|
||||
errorToast();
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
}, [gang]);
|
||||
|
||||
const deleteHomie = async (id) => {
|
||||
try {
|
||||
@@ -52,6 +53,13 @@ const Homies = (props) => {
|
||||
<div className="grey-text">{ homie.about }</div>
|
||||
</div>
|
||||
|
||||
<RoutableNavItem additionalClasses="push" href={`/homie/${homie.id}/move-money`}>
|
||||
<Button>
|
||||
Move money
|
||||
<Icon left>monetization_on</Icon>
|
||||
</Button>
|
||||
</RoutableNavItem>
|
||||
|
||||
<YesNoModal
|
||||
body={"Maan, y'a sure about this?"}
|
||||
yesAction={() => deleteHomie(homie.id)}
|
||||
|
||||
149
client/src/homies/MoveMoney.js
Normal file
149
client/src/homies/MoveMoney.js
Normal file
@@ -0,0 +1,149 @@
|
||||
import React, {useState, useEffect} from 'react';
|
||||
import M from 'materialize-css';
|
||||
import {Icon, Select, Button, Textarea, Switch} from 'react-materialize';
|
||||
import '../cash/Cash.css';
|
||||
import axios from 'axios';
|
||||
import {useParams} from "react-router-dom";
|
||||
import {errorToast} from "../common/errorHelpers";
|
||||
import {CRIB} from "../RouteNames";
|
||||
import { withRouter } from 'react-router-dom';
|
||||
|
||||
const MoveMoney = (props) => {
|
||||
const { homie_id } = useParams();
|
||||
const gang = props.gang;
|
||||
|
||||
const [selectedHomie, setSelectedHomie] = useState(null);
|
||||
const [secondaryHomie, setSecondaryHomie] = useState("");
|
||||
const [homies, setHomies] = useState([]);
|
||||
const [amountToMove, setAmountToMove] = useState('');
|
||||
const [moveDescription, setMoveDescription] = useState("");
|
||||
const [submitInProgress, setSubmitInProgress] = useState(false);
|
||||
const [moveType, setMoveType] = useState('collect');
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
const homiesInfo = await axios.get(`/api/gangs/${gang.id}/homies/info`);
|
||||
if (homiesInfo.status === 200 && homiesInfo.data){
|
||||
const homie = homiesInfo.data.find(homie => homie.homie.id === parseInt(homie_id));
|
||||
if (homie && homie.homie){
|
||||
setHomies(homiesInfo.data);
|
||||
setSelectedHomie(homie.homie);
|
||||
}else{
|
||||
window.location.href = CRIB;
|
||||
}
|
||||
}else{
|
||||
errorToast();
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Error fetching", e);
|
||||
}
|
||||
})();
|
||||
}, [gang, homie_id]);
|
||||
|
||||
const homieToOptionMapper = (homieData) => {
|
||||
const homie = homieData.homie;
|
||||
return (
|
||||
<option key={homie.id} value={homie.id}>{homie.name}</option>
|
||||
);
|
||||
};
|
||||
|
||||
const homieOptions = homies.filter((homieData) => homieData.homie.id !== parseInt(homie_id)).map(homieToOptionMapper);
|
||||
|
||||
const notSayingOption = <option value="">NOT SAYIN'</option>
|
||||
|
||||
const clearForm = () => {
|
||||
setAmountToMove("");
|
||||
setSecondaryHomie("");
|
||||
setMoveDescription("");
|
||||
}
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
setSubmitInProgress(true);
|
||||
let moneyMoveRequest = {};
|
||||
if (moveType === 'collect') {
|
||||
moneyMoveRequest = {
|
||||
money_move: {
|
||||
amount: amountToMove,
|
||||
from_homie_id: secondaryHomie,
|
||||
to_homie_id: homie_id,
|
||||
description: moveDescription
|
||||
}
|
||||
}
|
||||
}else{
|
||||
moneyMoveRequest = {
|
||||
money_move: {
|
||||
amount: amountToMove,
|
||||
from_homie_id: homie_id,
|
||||
to_homie_id: secondaryHomie,
|
||||
description: moveDescription
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const submitResponse = await axios.post('/api/money_moves', moneyMoveRequest);
|
||||
|
||||
if (submitResponse && submitResponse.status === 200 && submitResponse.data === true) {
|
||||
M.toast({html: "Money lounde...moved"});
|
||||
props.history.push(`/homie/${homie_id}/flow`);
|
||||
props.history.push(props.href);
|
||||
} else {
|
||||
M.toast({html: "Yo! It ain't workin'"});
|
||||
}
|
||||
setSubmitInProgress(false);
|
||||
}
|
||||
|
||||
const formComplete = () => parseFloat(amountToMove) > 0;
|
||||
|
||||
const disableSubmit = () => (!formComplete() || submitInProgress);
|
||||
|
||||
const homieSelectLabel = () => moveType === 'collect' ? 'From' : 'To';
|
||||
|
||||
return (
|
||||
<div className="center-align container">
|
||||
<form onSubmit={handleSubmit}>
|
||||
<h3>{selectedHomie && selectedHomie.name}</h3>
|
||||
|
||||
<div className='switch-box'>
|
||||
<Switch
|
||||
offLabel="Collect"
|
||||
onChange={(e) => setMoveType(e.target.checked === true ? 'pay' : 'collect')}
|
||||
onLabel="Pay"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
<h5 className="required">{homieSelectLabel()}</h5>
|
||||
<Select value={secondaryHomie} name="secondary-homie" onChange={(e) => setSecondaryHomie(e.target.value)}>
|
||||
{notSayingOption}
|
||||
{homieOptions}
|
||||
</Select>
|
||||
|
||||
<div className="input-field col s12">
|
||||
<input id="how-much" type="number" className="validate" step="0.01" required="required" value={amountToMove} onChange={(e) =>setAmountToMove(parseFloat(e.target.value))} pattern="^\\?(([1-9](\\d*|\\d{0,2}(,\\d{3})*))|0)(\\.\\d{1,2})?$" />
|
||||
<label className="required" htmlFor="how-much">How much?</label>
|
||||
<span className="helper-text" data-error="Yo! Put some money" />
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
<Textarea label="Tag" value={moveDescription} onChange={(e) => setMoveDescription(e.target.value)}/>
|
||||
|
||||
<div>
|
||||
<Button disabled={disableSubmit()} waves="light">
|
||||
Do it
|
||||
<Icon left>
|
||||
attach_money
|
||||
</Icon>
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
export default withRouter(MoveMoney);
|
||||
Reference in New Issue
Block a user