Add historical transactions to Admin Transactions page
This commit is contained in:
parent
65ffdcc00f
commit
dac93abd78
|
@ -2,6 +2,8 @@ import React, { useState, useEffect } from 'react';
|
||||||
import { BrowserRouter as Router, Switch, Route, Link, useParams, useHistory } from 'react-router-dom';
|
import { BrowserRouter as Router, Switch, Route, Link, useParams, useHistory } from 'react-router-dom';
|
||||||
import './light.css';
|
import './light.css';
|
||||||
import { Button, Container, Checkbox, Dimmer, Divider, Dropdown, Form, Grid, Header, Icon, Image, Menu, Message, Segment, Table } from 'semantic-ui-react';
|
import { Button, Container, Checkbox, Dimmer, Divider, Dropdown, Form, Grid, Header, Icon, Image, Menu, Message, Segment, Table } from 'semantic-ui-react';
|
||||||
|
import * as Datetime from 'react-datetime';
|
||||||
|
import 'react-datetime/css/react-datetime.css';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { statusColor, BasicTable, staticUrl, requester } from './utils.js';
|
import { statusColor, BasicTable, staticUrl, requester } from './utils.js';
|
||||||
import { TransactionList, TransactionEditor } from './Transactions.js';
|
import { TransactionList, TransactionEditor } from './Transactions.js';
|
||||||
|
@ -25,9 +27,7 @@ export function AdminReportedTransactions(props) {
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<div>
|
||||||
<Header size='large'>Reported Transactions</Header>
|
|
||||||
|
|
||||||
{!error ?
|
{!error ?
|
||||||
transactions ?
|
transactions ?
|
||||||
<div>
|
<div>
|
||||||
|
@ -36,14 +36,91 @@ export function AdminReportedTransactions(props) {
|
||||||
:
|
:
|
||||||
<p>Loading...</p>
|
<p>Loading...</p>
|
||||||
:
|
:
|
||||||
<NotFound />
|
<p>Error loading.</p>
|
||||||
}
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
</Container>
|
let transactionsCache = false;
|
||||||
|
|
||||||
|
export function AdminHistoricalTransactions(props) {
|
||||||
|
const { token, user } = props;
|
||||||
|
const [input, setInput] = useState({ month: moment() });
|
||||||
|
const [transactions, setTransactions] = useState(transactionsCache);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [error, setError] = useState(false);
|
||||||
|
|
||||||
|
const handleDatetime = (v) => setInput({ ...input, month: v });
|
||||||
|
|
||||||
|
const handleSubmit = (e) => {
|
||||||
|
if (loading) return;
|
||||||
|
setLoading(true);
|
||||||
|
const month = input.month.format('YYYY-MM');
|
||||||
|
requester('/transactions/?month=' + month, 'GET', token)
|
||||||
|
.then(res => {
|
||||||
|
setLoading(false);
|
||||||
|
setError(false);
|
||||||
|
setTransactions(res.results);
|
||||||
|
transactionsCache = res.results;
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
setLoading(false);
|
||||||
|
console.log(err);
|
||||||
|
setError(true);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Form onSubmit={handleSubmit}>
|
||||||
|
<label>Month</label>
|
||||||
|
<Form.Group>
|
||||||
|
<Form.Field>
|
||||||
|
<Datetime
|
||||||
|
dateFormat='YYYY-MM'
|
||||||
|
timeFormat={false}
|
||||||
|
value={input.month}
|
||||||
|
onChange={handleDatetime}
|
||||||
|
/>
|
||||||
|
</Form.Field>
|
||||||
|
|
||||||
|
<Form.Button loading={loading}>
|
||||||
|
Submit
|
||||||
|
</Form.Button>
|
||||||
|
</Form.Group>
|
||||||
|
</Form>
|
||||||
|
|
||||||
|
{!error ?
|
||||||
|
transactions && <div>
|
||||||
|
<p>Found {transactions.length} transactions.</p>
|
||||||
|
{!!transactions.length &&
|
||||||
|
<Header size='small'>{moment(transactions[0].date, 'YYYY-MM-DD').format('MMMM YYYY')} Transactions</Header>
|
||||||
|
}
|
||||||
|
<TransactionList transactions={transactions} />
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<p>Error loading transactions.</p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export function AdminTransactions(props) {
|
export function AdminTransactions(props) {
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<Header size='large'>Admin Transactions</Header>
|
||||||
|
|
||||||
|
<Header size='medium'>Reported</Header>
|
||||||
|
<AdminReportedTransactions {...props} />
|
||||||
|
|
||||||
|
<Header size='medium'>Historical</Header>
|
||||||
|
<AdminHistoricalTransactions {...props} />
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AdminMemberTransactions(props) {
|
||||||
const { token, result, refreshResult } = props;
|
const { token, result, refreshResult } = props;
|
||||||
const transactions = result.transactions;
|
const transactions = result.transactions;
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
@ -92,7 +169,7 @@ export function AdminTransactions(props) {
|
||||||
|
|
||||||
{transactions.length ?
|
{transactions.length ?
|
||||||
open ?
|
open ?
|
||||||
<TransactionList transactions={transactions} />
|
<TransactionList noMember transactions={transactions} />
|
||||||
:
|
:
|
||||||
<Button onClick={() => setOpen(true)}>
|
<Button onClick={() => setOpen(true)}>
|
||||||
View / Edit Transactions
|
View / Edit Transactions
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { Transactions, TransactionDetail } from './Transactions.js';
|
||||||
import { Paymaster } from './Paymaster.js';
|
import { Paymaster } from './Paymaster.js';
|
||||||
import { Cards } from './Cards.js';
|
import { Cards } from './Cards.js';
|
||||||
import { Training } from './Training.js';
|
import { Training } from './Training.js';
|
||||||
import { AdminReportedTransactions } from './AdminTransactions.js';
|
import { AdminTransactions } from './AdminTransactions.js';
|
||||||
import { Admin } from './Admin.js';
|
import { Admin } from './Admin.js';
|
||||||
import { Paste } from './Paste.js';
|
import { Paste } from './Paste.js';
|
||||||
import { Courses, CourseDetail } from './Courses.js';
|
import { Courses, CourseDetail } from './Courses.js';
|
||||||
|
@ -237,7 +237,7 @@ function App() {
|
||||||
|
|
||||||
{user && isAdmin(user) &&
|
{user && isAdmin(user) &&
|
||||||
<Route path='/admintrans'>
|
<Route path='/admintrans'>
|
||||||
<AdminReportedTransactions token={token} user={user} />
|
<AdminTransactions token={token} user={user} />
|
||||||
</Route>
|
</Route>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { Button, Container, Divider, Dropdown, Form, Grid, Header, Icon, Image,
|
||||||
import { statusColor, isAdmin, BasicTable, staticUrl, requester } from './utils.js';
|
import { statusColor, isAdmin, BasicTable, staticUrl, requester } from './utils.js';
|
||||||
import { NotFound, PleaseLogin } from './Misc.js';
|
import { NotFound, PleaseLogin } from './Misc.js';
|
||||||
import { AdminMemberInfo, AdminMemberPause, AdminMemberForm, AdminMemberCards } from './AdminMembers.js';
|
import { AdminMemberInfo, AdminMemberPause, AdminMemberForm, AdminMemberCards } from './AdminMembers.js';
|
||||||
import { AdminTransactions } from './AdminTransactions.js';
|
import { AdminMemberTransactions } from './AdminTransactions.js';
|
||||||
|
|
||||||
export function MembersDropdown(props) {
|
export function MembersDropdown(props) {
|
||||||
const { token, name, onChange, value, initial } = props;
|
const { token, name, onChange, value, initial } = props;
|
||||||
|
@ -194,7 +194,7 @@ export function MemberDetail(props) {
|
||||||
</Segment>}
|
</Segment>}
|
||||||
|
|
||||||
{isAdmin(user) && <Segment padded>
|
{isAdmin(user) && <Segment padded>
|
||||||
<AdminTransactions result={result} refreshResult={refreshResult} {...props} />
|
<AdminMemberTransactions result={result} refreshResult={refreshResult} {...props} />
|
||||||
</Segment>}
|
</Segment>}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -49,12 +49,12 @@ export function TransactionEditor(props) {
|
||||||
|
|
||||||
const categoryOptions = [
|
const categoryOptions = [
|
||||||
{ key: '0', text: 'Membership Dues', value: 'Membership' },
|
{ key: '0', text: 'Membership Dues', value: 'Membership' },
|
||||||
{ key: '1', text: 'Payment On Account or Prepayment', value: 'OnAcct' },
|
{ key: '1', text: 'Payment On Account (ie. Course Fee)', value: 'OnAcct' },
|
||||||
{ key: '2', text: 'Snack / Pop / Coffee', value: 'Snacks' },
|
{ key: '2', text: 'Snack / Pop / Coffee', value: 'Snacks' },
|
||||||
{ key: '3', text: 'Donations', value: 'Donation' },
|
{ key: '3', text: 'Donations', value: 'Donation' },
|
||||||
{ key: '4', text: 'Consumables (Specify which in memo)', value: 'Consumables' },
|
{ key: '4', text: 'Consumables (Specify which in memo)', value: 'Consumables' },
|
||||||
{ key: '5', text: 'Purchases of Goods or Parts or Stock', value: 'Purchases' },
|
{ key: '5', text: 'Purchase of Locker / Goods / Merch / Stock', value: 'Purchases' },
|
||||||
{ key: '6', text: 'Auction, Garage Sale, Nearly Free Shelf, Etc.', value: 'Garage Sale' },
|
{ key: '6', text: 'Auction, Garage Sale, Nearly Free Shelf', value: 'Garage Sale' },
|
||||||
{ key: '7', text: 'Reimbursement (Enter a negative value)', value: 'Reimburse' },
|
{ key: '7', text: 'Reimbursement (Enter a negative value)', value: 'Reimburse' },
|
||||||
{ key: '8', text: 'Other (Explain in memo)', value: 'Other' },
|
{ key: '8', text: 'Other (Explain in memo)', value: 'Other' },
|
||||||
];
|
];
|
||||||
|
@ -250,15 +250,17 @@ function ReportTransaction(props) {
|
||||||
};
|
};
|
||||||
|
|
||||||
export function TransactionList(props) {
|
export function TransactionList(props) {
|
||||||
const { transactions } = props;
|
const { transactions, noMember, noCategory } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Table basic='very'>
|
<Table basic='very'>
|
||||||
<Table.Header>
|
<Table.Header>
|
||||||
<Table.Row>
|
<Table.Row>
|
||||||
<Table.HeaderCell>Date</Table.HeaderCell>
|
<Table.HeaderCell>Date</Table.HeaderCell>
|
||||||
|
{!noMember && <Table.HeaderCell>Member</Table.HeaderCell>}
|
||||||
<Table.HeaderCell>Amount</Table.HeaderCell>
|
<Table.HeaderCell>Amount</Table.HeaderCell>
|
||||||
<Table.HeaderCell>Account</Table.HeaderCell>
|
<Table.HeaderCell>Account</Table.HeaderCell>
|
||||||
|
{!noCategory && <Table.HeaderCell>Category</Table.HeaderCell>}
|
||||||
<Table.HeaderCell>Memo</Table.HeaderCell>
|
<Table.HeaderCell>Memo</Table.HeaderCell>
|
||||||
</Table.Row>
|
</Table.Row>
|
||||||
</Table.Header>
|
</Table.Header>
|
||||||
|
@ -270,8 +272,18 @@ export function TransactionList(props) {
|
||||||
<Table.Cell>
|
<Table.Cell>
|
||||||
<Link to={'/transactions/'+x.id}>{x.date}</Link>
|
<Link to={'/transactions/'+x.id}>{x.date}</Link>
|
||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
|
{!noMember && <Table.Cell>
|
||||||
|
{x.member_id ?
|
||||||
|
<Link to={'/members/'+x.member_id}>
|
||||||
|
{x.member_name}
|
||||||
|
</Link>
|
||||||
|
:
|
||||||
|
x.member_name
|
||||||
|
}
|
||||||
|
</Table.Cell>}
|
||||||
<Table.Cell>${x.amount}</Table.Cell>
|
<Table.Cell>${x.amount}</Table.Cell>
|
||||||
<Table.Cell>{x.account_type}</Table.Cell>
|
<Table.Cell>{x.account_type}</Table.Cell>
|
||||||
|
{!noCategory && <Table.Cell>{x.category}</Table.Cell>}
|
||||||
<Table.Cell>{x.memo || x.report_memo}</Table.Cell>
|
<Table.Cell>{x.memo || x.report_memo}</Table.Cell>
|
||||||
</Table.Row>
|
</Table.Row>
|
||||||
)
|
)
|
||||||
|
@ -290,7 +302,7 @@ export function Transactions(props) {
|
||||||
<Container>
|
<Container>
|
||||||
<Header size='large'>Transactions</Header>
|
<Header size='large'>Transactions</Header>
|
||||||
|
|
||||||
<TransactionList transactions={user.transactions} />
|
<TransactionList noMember noCategory transactions={user.transactions} />
|
||||||
|
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user