Commit 24421d30 authored by TJHeeringa's avatar TJHeeringa

Finished creation support for debt collections; deletion still needed

parent 018011de
......@@ -19,10 +19,10 @@ export class AssociationInfo extends Component {
"Email": association.email
};
data["Legal"] = {
"Articles of Association": <a href={"articles_of_association"}>Articles of Association</a>,
"Bylaws": <a href={"bylaws"}>Bylaws</a>,
"Privacy Statement": <a href={"privacy_statements"}>Privacy Statement</a>,
"Terms of Service": <a href={"terms_of_service"}>Terms of Service</a>
"Articles of Association": <a href={association.articles_of_association}>Articles of Association</a>,
"Bylaws": <a href={association.bylaws}>Bylaws</a>,
"Privacy Statement": <a href={association.privacy_statements}>Privacy Statement</a>,
"Terms of Service": <a href={association.terms_of_service}>Terms of Service</a>
};
return data
......@@ -30,6 +30,7 @@ export class AssociationInfo extends Component {
render() {
const {association} = this.props;
console.log(association);
return (
<Info
data={this.morphAssociationToData(association)}
......
......@@ -7,17 +7,24 @@ import Collapse from '@material-ui/core/Collapse';
import ExpandLess from '@material-ui/icons/ExpandLess';
import ExpandMore from '@material-ui/icons/ExpandMore';
import PropTypes from "prop-types";
import { makeStyles } from '@material-ui/core/styles';
import {fade, makeStyles} from '@material-ui/core/styles';
const useStyles = makeStyles(theme => ({
tableStriped: {
backgroundColor: fade(theme.palette.primary.main, 0.35),
},
}));
const CollapsableList = ({ component: Component, listItemText, ...passThroughProps }) => {
const classes = useStyles();
const [open, setOpen] = React.useState(false);
const handleToggle = () => setOpen(!open);
return (
<List>
<ListItem button onClick={handleToggle} style={{backgroundColor: 'grey'}}>
<ListItem button onClick={handleToggle} className={classes.tableStriped}>
<ListItemText primary={listItemText} />
{open ? <ExpandLess /> : <ExpandMore />}
</ListItem>
......@@ -26,7 +33,7 @@ const CollapsableList = ({ component: Component, listItemText, ...passThroughPro
</Collapse>
</List>
)
}
};
CollapsableList.propTypes = {
listItemText: PropTypes.string.isRequired,
......
......@@ -5,7 +5,7 @@ import Button from '@material-ui/core/Button';
import Divider from '@material-ui/core/Divider';
import Typography from '@material-ui/core/Typography';
const useStyles = makeStyles(theme => ({
const useStyles = theme => ({
paper: {
width: 400,
backgroundColor: theme.palette.background.paper,
......@@ -24,7 +24,7 @@ const useStyles = makeStyles(theme => ({
marginTop: '15px',
marginBottom: '15px'
}
}));
});
export default function ConfirmationModal(props){
......
import React from "react";
import Modal from '@material-ui/core/Modal';
import Dialog from '@material-ui/core/Dialog';
import DialogTitle from '@material-ui/core/DialogTitle';
import Button from '@material-ui/core/Button';
import Divider from '@material-ui/core/Divider';
import Typography from '@material-ui/core/Typography';
import { withStyles, makeStyles, useTheme } from '@material-ui/core/styles';
import PropTypes from "prop-types";
import {ValidatorForm} from "react-material-ui-form-validator";
const useStyles = makeStyles(theme => ({
modal: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
paper: {
backgroundColor: theme.palette.background.paper,
margin: 'auto',
padding: theme.spacing(2, 4, 3),
top: '50%',
position: 'relative',
borderRadius: '0.3rem',
display: 'flex',
flexDirection: 'column',
width: 'fit-content',
},
buttonGroup: {
justifyContent: 'space-between',
display: 'flex'
},
divider: {
marginTop: '15px',
marginBottom: '15px'
}
}));
const FormModal = (props) => {
const { onSubmit, onCancel, title, open, size, cancelButtonText, submitButtonText} = props;
const classes = useStyles();
return (
<Dialog
open={open}
fullWidth={true}
maxWidth={size}
aria-labelledby="contained-modal-title-vcenter"
className={classes.modal}
>
<ValidatorForm
onSubmit={onSubmit}
onError={errors => console.log(errors)}
>
<div className={classes.paper}>
<Typography variant="h5">{title}</Typography>
<Divider className={classes.divider}/>
{props.children}
<Divider className={classes.divider}/>
<div className={classes.buttonGroup}>
<Button variant="contained" onClick={onCancel}>{cancelButtonText}</Button>
<Button variant="contained" color='primary' type={'submit'}>{submitButtonText}</Button>
</div>
</div>
</ValidatorForm>
</Dialog>
)
};
FormModal.propTypes = {
onSubmit: PropTypes.func.isRequired,
onCancel: PropTypes.func.isRequired,
title: PropTypes.string.isRequired,
open: PropTypes.bool.isRequired,
size: PropTypes.string,
cancelButtonText: PropTypes.string,
submitButtonText: PropTypes.string,
};
FormModal.defaultProps = {
size: 'm',
cancelButtonText: 'Cancel',
submitButtonText: 'Submit',
};
export default FormModal;
\ No newline at end of file
......@@ -370,7 +370,7 @@ const ExtremeTable = (props) => {
};
ExtremeTable.propTypes = {
// Required properties
// ---- Required properties ----
/* Headers above the table */
headers: PropTypes.arrayOf(PropTypes.exact({
name: PropTypes.string,
......@@ -378,7 +378,8 @@ ExtremeTable.propTypes = {
})).isRequired,
/* Rows in the table */
rows: PropTypes.arrayOf(PropTypes.object).isRequired,
// Optional properties
// ---- Optional properties ----
/* Boolean that enables selection */
showSelect: PropTypes.bool,
/* Boolean for showing the checkbox with allows selecting of all at once */
......@@ -429,13 +430,14 @@ ExtremeTable.defaultProps = {
selectByRowClick: false,
pageSizes: [5,10,25,50,100,500],
defaultFilters: [],
defaultSorting: [{ columnName: 'given_name', direction: 'asc' }],
defaultSorting: [],
defaultHiddenColumnNames: [],
editingStateColumnExtensions: [],
booleanColumns: [],
choiceColumns: [],
currencyColumns: [],
dateColumns: [],
numberColumns: [],
rowSelectionEnabledFilter: (row, selection) => true,
selection: {selection: undefined, setSelection: undefined}
};
......
......@@ -6,7 +6,7 @@ import ExtremeTable from "App/Components/Tables/ExtremeTable"
const MemberTable = props => {
const { rows, headers, memberTypes, editingStateColumnExtensions, choiceSelectionOptions } = props;
const { rows, headers, editingStateColumnExtensions, choiceSelectionOptions } = props;
const extremeHeaders = headers.map(header=>{return {"name": header.name, "title": header.title} });
......
......@@ -238,101 +238,101 @@ class Membertype extends Component {
}}
/>
</div>
<MuiPickersUtilsProvider libInstance={moment} utils={MomentUtils}>
<div className={classes.wrapper}>
<EventAvailableIcon className={classes.icon} color="action"/>
<SelectValidator
{...textEditorProps('Start date - month')}
validators={['required']}
errorMessages={['A type has to be set']}
value={membertype.start_date.split('-')[0]}
onChange={(event) => {
this.handleDataChange('start_date', event.target.value + '-' + membertype.start_date.split('-')[1])
}}
>
<MenuItem value={"01"}>January</MenuItem>
<MenuItem value={"02"}>February</MenuItem>
<MenuItem value={"03"}>March</MenuItem>
<MenuItem value={"04"}>April</MenuItem>
<MenuItem value={"05"}>May</MenuItem>
<MenuItem value={"06"}>June</MenuItem>
<MenuItem value={"07"}>July</MenuItem>
<MenuItem value={"08"}>August</MenuItem>
<MenuItem value={"09"}>September</MenuItem>
<MenuItem value={"10"}>October</MenuItem>
<MenuItem value={"11"}>November</MenuItem>
<MenuItem value={"12"}>December</MenuItem>
</SelectValidator>
<SelectValidator
{...textEditorProps('Start date - day')}
validators={['required']}
errorMessages={['A type has to be set']}
value={membertype.start_date.split('-')[1]}
onChange={(event) => {
this.handleDataChange('start_date', membertype.start_date.split('-')[0] + '-' + event.target.value)
}}
>
{[...Array(monthToNumberOfDays[membertype.start_date.split('-')[0]]).keys()].map((day, id) =>
<MenuItem key={id} value={padStart(day + 1,2,'0')}>{day + 1}</MenuItem>
)}
</SelectValidator>
</div>
<div className={classes.wrapper}>
<EventBusyIcon className={classes.icon} color="action"/>
<SelectValidator
{...textEditorProps('End date - month')}
validators={['required']}
errorMessages={['A type has to be set']}
value={membertype.end_date.split('-')[0]}
onChange={(event) => {
this.handleDataChange('end_date', event.target.value + '-' + membertype.end_date.split('-')[1])
}}
>
<MenuItem value={'01'}>January</MenuItem>
<MenuItem value={'02'}>February</MenuItem>
<MenuItem value={'03'}>March</MenuItem>
<MenuItem value={'04'}>April</MenuItem>
<MenuItem value={'05'}>May</MenuItem>
<MenuItem value={'06'}>June</MenuItem>
<MenuItem value={'07'}>July</MenuItem>
<MenuItem value={'08'}>August</MenuItem>
<MenuItem value={'09'}>September</MenuItem>
<MenuItem value={'10'}>October</MenuItem>
<MenuItem value={'11'}>November</MenuItem>
<MenuItem value={'12'}>December</MenuItem>
</SelectValidator>
<SelectValidator
{...textEditorProps('End date - day')}
validators={['required']}
errorMessages={['A type has to be set']}
value={membertype.end_date.split('-')[1]}
onChange={(event) => {
this.handleDataChange('end_date', membertype.end_date.split('-')[0] + '-' + event.target.value)
}}
>
{[...Array(monthToNumberOfDays[membertype.end_date.split('-')[0]]).keys()].map((day, id) =>
<MenuItem key={id} value={padStart(day + 1,2,'0')}>{day + 1}</MenuItem>
)}
</SelectValidator>
</div>
</MuiPickersUtilsProvider>
<div className={classes.wrapper}>
<BallotIcon className={classes.icon} color="action"/>
<SelectValidator
{...textEditorProps('payment per')}
validators={['required']}
errorMessages={['A type has to be set']}
value={membertype.payment_per}
onChange={(event) => {
this.handleDataChange('payment_per', event.target.value)
}}
>
<MenuItem value={'year'}>Year</MenuItem>
<MenuItem value={'semester'}>Semester</MenuItem>
<MenuItem value={'month'}>Month</MenuItem>
<MenuItem value={'week'}>Week</MenuItem>
</SelectValidator>
</div>
{/*<MuiPickersUtilsProvider libInstance={moment} utils={MomentUtils}>*/}
{/*<div className={classes.wrapper}>*/}
{/*<EventAvailableIcon className={classes.icon} color="action"/>*/}
{/*<SelectValidator*/}
{/*{...textEditorProps('Start date - month')}*/}
{/*validators={['required']}*/}
{/*errorMessages={['A type has to be set']}*/}
{/*value={membertype.start_date.split('-')[0]}*/}
{/*onChange={(event) => {*/}
{/*this.handleDataChange('start_date', event.target.value + '-' + membertype.start_date.split('-')[1])*/}
{/*}}*/}
{/*>*/}
{/*<MenuItem value={"01"}>January</MenuItem>*/}
{/*<MenuItem value={"02"}>February</MenuItem>*/}
{/*<MenuItem value={"03"}>March</MenuItem>*/}
{/*<MenuItem value={"04"}>April</MenuItem>*/}
{/*<MenuItem value={"05"}>May</MenuItem>*/}
{/*<MenuItem value={"06"}>June</MenuItem>*/}
{/*<MenuItem value={"07"}>July</MenuItem>*/}
{/*<MenuItem value={"08"}>August</MenuItem>*/}
{/*<MenuItem value={"09"}>September</MenuItem>*/}
{/*<MenuItem value={"10"}>October</MenuItem>*/}
{/*<MenuItem value={"11"}>November</MenuItem>*/}
{/*<MenuItem value={"12"}>December</MenuItem>*/}
{/*</SelectValidator>*/}
{/*<SelectValidator*/}
{/*{...textEditorProps('Start date - day')}*/}
{/*validators={['required']}*/}
{/*errorMessages={['A type has to be set']}*/}
{/*value={membertype.start_date.split('-')[1]}*/}
{/*onChange={(event) => {*/}
{/*this.handleDataChange('start_date', membertype.start_date.split('-')[0] + '-' + event.target.value)*/}
{/*}}*/}
{/*>*/}
{/*{[...Array(monthToNumberOfDays[membertype.start_date.split('-')[0]]).keys()].map((day, id) =>*/}
{/*<MenuItem key={id} value={padStart(day + 1,2,'0')}>{day + 1}</MenuItem>*/}
{/*)}*/}
{/*</SelectValidator>*/}
{/*</div>*/}
{/*<div className={classes.wrapper}>*/}
{/*<EventBusyIcon className={classes.icon} color="action"/>*/}
{/*<SelectValidator*/}
{/*{...textEditorProps('End date - month')}*/}
{/*validators={['required']}*/}
{/*errorMessages={['A type has to be set']}*/}
{/*value={membertype.end_date.split('-')[0]}*/}
{/*onChange={(event) => {*/}
{/*this.handleDataChange('end_date', event.target.value + '-' + membertype.end_date.split('-')[1])*/}
{/*}}*/}
{/*>*/}
{/*<MenuItem value={'01'}>January</MenuItem>*/}
{/*<MenuItem value={'02'}>February</MenuItem>*/}
{/*<MenuItem value={'03'}>March</MenuItem>*/}
{/*<MenuItem value={'04'}>April</MenuItem>*/}
{/*<MenuItem value={'05'}>May</MenuItem>*/}
{/*<MenuItem value={'06'}>June</MenuItem>*/}
{/*<MenuItem value={'07'}>July</MenuItem>*/}
{/*<MenuItem value={'08'}>August</MenuItem>*/}
{/*<MenuItem value={'09'}>September</MenuItem>*/}
{/*<MenuItem value={'10'}>October</MenuItem>*/}
{/*<MenuItem value={'11'}>November</MenuItem>*/}
{/*<MenuItem value={'12'}>December</MenuItem>*/}
{/*</SelectValidator>*/}
{/*<SelectValidator*/}
{/*{...textEditorProps('End date - day')}*/}
{/*validators={['required']}*/}
{/*errorMessages={['A type has to be set']}*/}
{/*value={membertype.end_date.split('-')[1]}*/}
{/*onChange={(event) => {*/}
{/*this.handleDataChange('end_date', membertype.end_date.split('-')[0] + '-' + event.target.value)*/}
{/*}}*/}
{/*>*/}
{/*{[...Array(monthToNumberOfDays[membertype.end_date.split('-')[0]]).keys()].map((day, id) =>*/}
{/*<MenuItem key={id} value={padStart(day + 1,2,'0')}>{day + 1}</MenuItem>*/}
{/*)}*/}
{/*</SelectValidator>*/}
{/*</div>*/}
{/*</MuiPickersUtilsProvider>*/}
{/*<div className={classes.wrapper}>*/}
{/*<BallotIcon className={classes.icon} color="action"/>*/}
{/*<SelectValidator*/}
{/*{...textEditorProps('payment per')}*/}
{/*validators={['required']}*/}
{/*errorMessages={['A type has to be set']}*/}
{/*value={membertype.payment_per}*/}
{/*onChange={(event) => {*/}
{/*this.handleDataChange('payment_per', event.target.value)*/}
{/*}}*/}
{/*>*/}
{/*<MenuItem value={'year'}>Year</MenuItem>*/}
{/*<MenuItem value={'semester'}>Semester</MenuItem>*/}
{/*<MenuItem value={'month'}>Month</MenuItem>*/}
{/*<MenuItem value={'week'}>Week</MenuItem>*/}
{/*</SelectValidator>*/}
{/*</div>*/}
<div className={classes.wrapper}>
<GradeIcon className={classes.icon} color="action"/>
<SelectValidator
......
......@@ -3,39 +3,40 @@ import { makeStyles } from '@material-ui/core/styles';
import PropTypes from "prop-types";
import SimpleTable from "App/Components/Tables/SimpleTable"
import ExtremeTable from "App/Components/Tables/ExtremeTable"
import { zipObject } from 'lodash';
import { zipObject, snakeCase } from 'lodash';
import CardGrid from "../../Components/Card/CardGrid";
const useStyles = makeStyles(theme => ({
root: {}
}));
const DebtCollectionDetail = ({rows, ...props}) => {
const DebtCollectionDetail = ({debtCollection, ...props}) => {
const classes = useStyles();
const number_of_rows = 500;
const headers = ["Who", "Amount", "Identifier", "Bank Account", "Email"];
const dummyRow = "Pie is kind of pi".split(" ");
const dummyRows = Array.apply(null, Array(number_of_rows)).map(i=>dummyRow);
const headers = ["Who", "Amount", "Identifier", "Bank Account", "Email"];
const extremeHeaders = headers.map(header=>{return {name: header.toLowerCase(), title: header}});
const extremeDummyRow = zipObject(headers.map(header=>header.toLowerCase()), dummyRow);
const extremeDummyRows = Array.apply(null, Array(number_of_rows)).map(i=>extremeDummyRow);
const extremeHeaders = headers.map(header=>{return {name: snakeCase(header), title: header}});
return (
<>
{/*<SimpleTable headers={headers} rows={dummyRows}/>*/}
<ExtremeTable
headers={extremeHeaders}
rows={extremeDummyRows}
showExporter={true}
showGrouping={false}
showSelect={false}
/>
</>
<ExtremeTable
headers={extremeHeaders}
rows={debtCollection.debt_entries || []}
showExporter={true}
showGrouping={false}
showSelect={false}
{...props}
/>
)
};
DebtCollectionDetail.propTypes = {
debt_collection: PropTypes.object
};
CardGrid.defaultProps = {
debt_collection: {
debt_entries: []
}
};
export default DebtCollectionDetail;
\ No newline at end of file
......@@ -7,8 +7,18 @@ import PropTypes from "prop-types";
import { makeStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
import DebtCollectionDetail from "./DebtCollectionDetail";
import FormModal from 'App/Components/Modals/FormModal';
import CalendarToday from '@material-ui/icons/CalendarToday';
import { KeyboardDateTimePicker, MuiPickersUtilsProvider } from '@material-ui/pickers';
import MomentUtils from '@date-io/moment';
import moment from 'moment';
import { v4 as uuidv4 } from 'uuid';
import {useGet} from "restful-react/lib";
import { Helper } from "App/Helper";
import { useAlertHandler } from "App/Contexts/AlertHandler";
import Button from '@material-ui/core/Button';
const useStyles = makeStyles((theme) => ({
root: {
margin: theme.spacing(2),
......@@ -21,37 +31,149 @@ const useStyles = makeStyles((theme) => ({
},
addButton: {
width: '100%',
}
},
wrapper: {
display: 'flex',
justifyContent: 'space-between',
padding: theme.spacing(1, 0),
},
icon: {
margin: theme.spacing(2, 0),
marginRight: theme.spacing(2),
},
textField: {
width: '100%',
},
}));
const DebtCollections = (props) => {
const classes = useStyles();
const alertHandler = useAlertHandler();
const pickerEditorProps = field => ({
className: classes.picker,
ampm: false,
inputVariant: 'outlined',
format: 'YYYY/MM/DD HH:mm',
label: field,
});
const DummyDebtCollections = [
{slug: "a", date: new Date("2020-07-08"), amount: 48.09},
{slug: "b", date: new Date("2019-11-18"), amount: 2011},
{slug: "c", date: new Date("2019-09-21"), amount: 182.50},
{slug: "d", date: new Date("2019-08-31"), amount: 3787},
{slug: "e", date: new Date("2019-08-14"), amount: 508.48},
];
const default_new_debt_collection = {
association: props.association.url,
debt_collection_date: moment().add(1,'days')
};
const [debtCollections, setebtCollections] = React.useState([]);
let { data: debtCollections, loading: loadingdebtCollections } = useGet({
path: process.env.REACT_APP_API_URL + '/debt_collections',
queryParams: {limit: 10000, association__slug: props.association.slug, ordering: '-debt_collection_date'},
resolve: data => data && data.results.map(morphDataToDebtCollection)
});
const [newDebtCollection, setNewDebtCollection] = React.useState(default_new_debt_collection);
const [selectedDebtCollection, setSelectedDebtCollection] = React.useState({});
const [modalOpen, setModalOpen] = React.useState(false);
const morphDataToDebtCollection = (data) => {
data.debt_collection_date = moment(data.debt_collection_date);
if (data.debt_entries !== undefined) {
data.debt_entries = data.debt_entries.map(morphDataToDebtEntry)
}
return data
};
const morphNewDebtCollectionToApiData = (debt_collection) => {
debt_collection.debt_collection_date = debt_collection.debt_collection_date.toDate();
return debt_collection
};
const morphDataToDebtEntry = (data) => {
return {
who: data.profile.surname,
amount: data.total_price,
identifier: undefined,
bank_account: data.profile.iban,
email: data.profile.email,
};
};
const handleDebtCollectionSelection = (debt_collection) => {