Add UI page for reported transactions, member dropdown
This commit is contained in:
parent
7d3d06033d
commit
9fd7e76486
|
@ -6,6 +6,42 @@ 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';
|
||||||
|
|
||||||
|
export function AdminReportedTransactions(props) {
|
||||||
|
const { token, user } = props;
|
||||||
|
const [transactions, setTransactions] = useState(false);
|
||||||
|
const [error, setError] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
requester('/transactions/', 'GET', token)
|
||||||
|
.then(res => {
|
||||||
|
setTransactions(res.results);
|
||||||
|
setError(false);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.log(err);
|
||||||
|
setError(true);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<Header size='large'>Reported Transactions</Header>
|
||||||
|
|
||||||
|
{!error ?
|
||||||
|
transactions ?
|
||||||
|
<div>
|
||||||
|
<TransactionList transactions={transactions} />
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<p>Loading...</p>
|
||||||
|
:
|
||||||
|
<NotFound />
|
||||||
|
}
|
||||||
|
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export function AdminTransactions(props) {
|
export function AdminTransactions(props) {
|
||||||
const { token, result, refreshResult } = props;
|
const { token, result, refreshResult } = props;
|
||||||
const transactions = result.transactions;
|
const transactions = result.transactions;
|
||||||
|
|
|
@ -3,12 +3,13 @@ import { BrowserRouter as Router, Switch, Route, Link, useParams, useHistory } f
|
||||||
import './semantic-ui/semantic.min.css';
|
import './semantic-ui/semantic.min.css';
|
||||||
import './light.css';
|
import './light.css';
|
||||||
import { Container, Divider, Dropdown, Form, Grid, Header, Icon, Image, Menu, Message, Segment, Table } from 'semantic-ui-react';
|
import { Container, Divider, Dropdown, Form, Grid, Header, Icon, Image, Menu, Message, Segment, Table } from 'semantic-ui-react';
|
||||||
import { requester } from './utils.js';
|
import { isAdmin, requester } from './utils.js';
|
||||||
import { Home } from './Home.js';
|
import { Home } from './Home.js';
|
||||||
import { Account } from './Account.js';
|
import { Account } from './Account.js';
|
||||||
import { Transactions, TransactionDetail } from './Transactions.js';
|
import { Transactions, TransactionDetail } from './Transactions.js';
|
||||||
import { Cards } from './Cards.js';
|
import { Cards } from './Cards.js';
|
||||||
import { Training } from './Training.js';
|
import { Training } from './Training.js';
|
||||||
|
import { AdminReportedTransactions } from './Admin.js';
|
||||||
import { Courses, CourseDetail } from './Courses.js';
|
import { Courses, CourseDetail } from './Courses.js';
|
||||||
import { Classes, ClassDetail } from './Classes.js';
|
import { Classes, ClassDetail } from './Classes.js';
|
||||||
import { Members, MemberDetail } from './Members.js';
|
import { Members, MemberDetail } from './Members.js';
|
||||||
|
@ -116,6 +117,12 @@ function App() {
|
||||||
as={Link}
|
as={Link}
|
||||||
to='/classes'
|
to='/classes'
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{user && isAdmin(user) && <Dropdown.Item
|
||||||
|
content='Admin Trans.'
|
||||||
|
as={Link}
|
||||||
|
to='/admintrans'
|
||||||
|
/>}
|
||||||
</Dropdown.Menu>
|
</Dropdown.Menu>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
|
|
||||||
|
@ -177,6 +184,12 @@ function App() {
|
||||||
<Members token={token} />
|
<Members token={token} />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
|
{user && isAdmin(user) &&
|
||||||
|
<Route path='/admintrans'>
|
||||||
|
<AdminReportedTransactions token={token} user={user} />
|
||||||
|
</Route>
|
||||||
|
}
|
||||||
|
|
||||||
<Route path='/:page'>
|
<Route path='/:page'>
|
||||||
<NotFound />
|
<NotFound />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
|
@ -6,6 +6,50 @@ import { statusColor, isAdmin, BasicTable, staticUrl, requester } from './utils.
|
||||||
import { NotFound, PleaseLogin } from './Misc.js';
|
import { NotFound, PleaseLogin } from './Misc.js';
|
||||||
import { AdminMemberInfo, AdminMemberPause, AdminMemberForm, AdminMemberCards, AdminTransactions } from './Admin.js';
|
import { AdminMemberInfo, AdminMemberPause, AdminMemberForm, AdminMemberCards, AdminTransactions } from './Admin.js';
|
||||||
|
|
||||||
|
export function MembersDropdown(props) {
|
||||||
|
const { token, name, onChange, value, initial } = props;
|
||||||
|
const [response, setResponse] = useState({ results: [] });
|
||||||
|
const searchDefault = {seq: 0, q: initial || ''};
|
||||||
|
const [search, setSearch] = useState(searchDefault);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
requester('/search/', 'POST', token, search)
|
||||||
|
.then(res => {
|
||||||
|
if (!search.seq || res.seq > response.seq) {
|
||||||
|
setResponse(res);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
}, [search]);
|
||||||
|
|
||||||
|
const options = response.results.map((x, i) => ({
|
||||||
|
key: x.member.id,
|
||||||
|
value: x.member.id,
|
||||||
|
text: x.member.preferred_name + ' ' + x.member.last_name,
|
||||||
|
image: { avatar: true, src: x.member.photo_small ? staticUrl + '/' + x.member.photo_small : '/nophoto.png' },
|
||||||
|
}));
|
||||||
|
|
||||||
|
console.log(value, initial);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dropdown
|
||||||
|
clearable
|
||||||
|
fluid
|
||||||
|
selection
|
||||||
|
search
|
||||||
|
name={name}
|
||||||
|
options={options}
|
||||||
|
value={value}
|
||||||
|
placeholder='Search for Member'
|
||||||
|
onChange={onChange}
|
||||||
|
onSearchChange={(e, v) => setSearch({seq: parseInt(e.timeStamp), q: v.searchQuery})}
|
||||||
|
/>
|
||||||
|
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export function Members(props) {
|
export function Members(props) {
|
||||||
const [response, setResponse] = useState(false);
|
const [response, setResponse] = useState(false);
|
||||||
const searchDefault = {seq: 0, q: ''};
|
const searchDefault = {seq: 0, q: ''};
|
||||||
|
|
|
@ -2,11 +2,12 @@ import React, { useState, useEffect } from 'react';
|
||||||
import { BrowserRouter as Router, Switch, Route, Link, useParams } from 'react-router-dom';
|
import { BrowserRouter as Router, Switch, Route, Link, useParams } from 'react-router-dom';
|
||||||
import './light.css';
|
import './light.css';
|
||||||
import { Container, Divider, Dropdown, Form, Grid, Header, Icon, Image, Menu, Message, Segment, Table } from 'semantic-ui-react';
|
import { Container, Divider, Dropdown, Form, Grid, Header, Icon, Image, Menu, Message, Segment, Table } from 'semantic-ui-react';
|
||||||
|
import { MembersDropdown } from './Members.js';
|
||||||
import { isAdmin, BasicTable, requester } from './utils.js';
|
import { isAdmin, BasicTable, requester } from './utils.js';
|
||||||
import { NotFound, PleaseLogin } from './Misc.js';
|
import { NotFound, PleaseLogin } from './Misc.js';
|
||||||
|
|
||||||
export function TransactionEditor(props) {
|
export function TransactionEditor(props) {
|
||||||
const { input, setInput, error } = props;
|
const { token, input, setInput, error } = props;
|
||||||
|
|
||||||
const handleValues = (e, v) => setInput({ ...input, [v.name]: v.value });
|
const handleValues = (e, v) => setInput({ ...input, [v.name]: v.value });
|
||||||
const handleUpload = (e, v) => setInput({ ...input, [v.name]: e.target.files[0] });
|
const handleUpload = (e, v) => setInput({ ...input, [v.name]: e.target.files[0] });
|
||||||
|
@ -26,7 +27,7 @@ export function TransactionEditor(props) {
|
||||||
{ key: '2', text: 'Square (Credit)', value: 'Square Pmt' },
|
{ key: '2', text: 'Square (Credit)', value: 'Square Pmt' },
|
||||||
{ key: '3', text: 'Dream Payments (Debit/Credit)', value: 'Dream Pmt' },
|
{ key: '3', text: 'Dream Payments (Debit/Credit)', value: 'Dream Pmt' },
|
||||||
{ key: '4', text: 'Deposit to TD (Not Interac)', value: 'TD Chequing' },
|
{ key: '4', text: 'Deposit to TD (Not Interac)', value: 'TD Chequing' },
|
||||||
{ key: '5', text: 'PayPal', value: 'Paypal' },
|
{ key: '5', text: 'PayPal', value: 'PayPal' },
|
||||||
{ key: '6', text: 'Member Balance / Protocash', value: 'Member' },
|
{ key: '6', text: 'Member Balance / Protocash', value: 'Member' },
|
||||||
{ key: '7', text: 'Supense (Clearing) Acct / Membership Adjustment', value: 'Clearing' },
|
{ key: '7', text: 'Supense (Clearing) Acct / Membership Adjustment', value: 'Clearing' },
|
||||||
];
|
];
|
||||||
|
@ -37,7 +38,7 @@ export function TransactionEditor(props) {
|
||||||
{ key: '2', text: 'System', value: 'System' },
|
{ key: '2', text: 'System', value: 'System' },
|
||||||
{ key: '3', text: 'Receipt or Statement', value: 'Receipt or Stmt' },
|
{ key: '3', text: 'Receipt or Statement', value: 'Receipt or Stmt' },
|
||||||
{ key: '4', text: 'Quicken Import', value: 'Quicken Import' },
|
{ key: '4', text: 'Quicken Import', value: 'Quicken Import' },
|
||||||
{ key: '5', text: 'PayPal IPN', value: 'Paypal IPN' },
|
{ key: '5', text: 'PayPal IPN', value: 'PayPal IPN' },
|
||||||
{ key: '6', text: 'Auto', value: 'Auto' },
|
{ key: '6', text: 'Auto', value: 'Auto' },
|
||||||
{ key: '7', text: 'Nexus Database Bulk', value: 'Nexus DB Bulk' },
|
{ key: '7', text: 'Nexus Database Bulk', value: 'Nexus DB Bulk' },
|
||||||
{ key: '8', text: 'IPN Trigger', value: 'IPN Trigger' },
|
{ key: '8', text: 'IPN Trigger', value: 'IPN Trigger' },
|
||||||
|
@ -60,6 +61,16 @@ export function TransactionEditor(props) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='transaction-editor'>
|
<div className='transaction-editor'>
|
||||||
|
<Form.Field error={error.member_id}>
|
||||||
|
<label>Member (search)</label>
|
||||||
|
<MembersDropdown
|
||||||
|
token={token}
|
||||||
|
{...makeProps('member_id')}
|
||||||
|
onChange={handleValues}
|
||||||
|
initial={input.member_name}
|
||||||
|
/>
|
||||||
|
</Form.Field>
|
||||||
|
|
||||||
<Form.Group widths='equal'>
|
<Form.Group widths='equal'>
|
||||||
<Form.Input
|
<Form.Input
|
||||||
label='Date'
|
label='Date'
|
||||||
|
@ -144,7 +155,8 @@ function EditTransaction(props) {
|
||||||
const handleSubmit = (e) => {
|
const handleSubmit = (e) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setSuccess(false);
|
setSuccess(false);
|
||||||
requester('/transactions/'+id+'/', 'PUT', token, input)
|
const data = { ...input, report_type: null, report_memo: '' };
|
||||||
|
requester('/transactions/'+id+'/', 'PUT', token, data)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setSuccess(true);
|
setSuccess(true);
|
||||||
|
@ -167,7 +179,7 @@ function EditTransaction(props) {
|
||||||
<Header size='medium'>Edit Transaction</Header>
|
<Header size='medium'>Edit Transaction</Header>
|
||||||
|
|
||||||
<Form onSubmit={handleSubmit}>
|
<Form onSubmit={handleSubmit}>
|
||||||
<TransactionEditor input={input} setInput={setInput} error={error} />
|
<TransactionEditor token={token} input={input} setInput={setInput} error={error} />
|
||||||
|
|
||||||
<Form.Button loading={loading} error={error.non_field_errors}>
|
<Form.Button loading={loading} error={error.non_field_errors}>
|
||||||
Save
|
Save
|
||||||
|
@ -201,7 +213,7 @@ export function TransactionList(props) {
|
||||||
</Table.Cell>
|
</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>
|
||||||
<Table.Cell>{x.memo}</Table.Cell>
|
<Table.Cell>{x.memo || x.report_memo}</Table.Cell>
|
||||||
</Table.Row>
|
</Table.Row>
|
||||||
)
|
)
|
||||||
:
|
:
|
||||||
|
@ -295,6 +307,15 @@ export function TransactionDetail(props) {
|
||||||
<Table.Cell>Memo:</Table.Cell>
|
<Table.Cell>Memo:</Table.Cell>
|
||||||
<Table.Cell>{transaction.memo}</Table.Cell>
|
<Table.Cell>{transaction.memo}</Table.Cell>
|
||||||
</Table.Row>
|
</Table.Row>
|
||||||
|
|
||||||
|
{transaction.report_type && <Table.Row>
|
||||||
|
<Table.Cell>Report Type:</Table.Cell>
|
||||||
|
<Table.Cell>{transaction.report_type}</Table.Cell>
|
||||||
|
</Table.Row>}
|
||||||
|
{transaction.report_memo && <Table.Row>
|
||||||
|
<Table.Cell>Report Memo:</Table.Cell>
|
||||||
|
<Table.Cell>{transaction.report_memo}</Table.Cell>
|
||||||
|
</Table.Row>}
|
||||||
</Table.Body>
|
</Table.Body>
|
||||||
</BasicTable>
|
</BasicTable>
|
||||||
</Grid.Column>
|
</Grid.Column>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user