Skip to content

Commit

Permalink
✨ feat(BooksDownloadDialog): Add advanced mode.
Browse files Browse the repository at this point in the history
Fixes #77.
  • Loading branch information
make-github-pseudonymous-again committed Mar 8, 2020
1 parent 844a232 commit 04bbbfa
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 29 deletions.
3 changes: 3 additions & 0 deletions imports/api/books.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,5 +109,8 @@ export const books = {
} ,

MAX_CONSULTATIONS: 50 ,
DOWNLOAD_FIRST_BOOK: 1,
DOWNLOAD_LAST_BOOK: 99,
DOWNLOAD_MAX_ROWS: 60,

} ;
17 changes: 9 additions & 8 deletions imports/api/consultations.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,19 +205,20 @@ function sanitize ( {

Meteor.methods({

'books.year.csv'(year) {
'books.interval.csv'(begin, end, firstBook, lastBook, maxRows) {

if (!this.userId) {
throw new Meteor.Error('not-authorized');
}

check(year, Number);
check(begin, Date);
check(end, Date);
check(firstBook, Number);
check(lastBook, Number);
check(maxRows, Number);

const begin = new Date(`${year}-01-01`);
const end = new Date(`${year+1}-01-01`);
const beginBook = 1;
const endBook = 100;
const maxEntries = 60;
const beginBook = firstBook;
const endBook = lastBook + 1;

const consultations = Consultations.find({
datetime: {
Expand Down Expand Up @@ -255,7 +256,7 @@ Meteor.methods({
const header = list(map(([year, book]) => books.format(year, book), product([range(beginYear, endYear), range(beginBook, endBook)]))) ;
const lines = [] ;

for ( const i of range(maxEntries) ) {
for ( const i of range(maxRows) ) {
const line = [];
for ( const bookSlug of header ) {
if ( data[bookSlug] !== undefined && data[bookSlug][i] !== undefined ) {
Expand Down
116 changes: 96 additions & 20 deletions imports/ui/books/BooksDownloadDialog.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { Meteor } from 'meteor/meteor' ;

import React, {useState, useEffect} from 'react';
import React, {Fragment, useState, useEffect} from 'react';
import PropTypes from 'prop-types';

import startOfYear from 'date-fns/startOfYear';
import endOfYear from 'date-fns/endOfYear';
import dateFormat from 'date-fns/format' ;
import addYears from 'date-fns/addYears';

import { withStyles } from '@material-ui/core/styles';
import { makeStyles } from '@material-ui/core/styles';

import Button from '@material-ui/core/Button';
import TextField from '@material-ui/core/TextField';
Expand All @@ -17,35 +18,62 @@ import DialogContent from '@material-ui/core/DialogContent';
import DialogContentText from '@material-ui/core/DialogContentText';
import DialogTitle from '@material-ui/core/DialogTitle';

import { DatePicker } from "@material-ui/pickers";

import SaveIcon from '@material-ui/icons/Save';
import CancelIcon from '@material-ui/icons/Cancel';
import TuneIcon from '@material-ui/icons/Tune';

import saveTextAs from '../../client/saveTextAs.js';

const styles = theme => ({
import { books } from '../../api/books.js';

const useStyles = makeStyles(theme => ({
rightIcon: {
marginLeft: theme.spacing(1),
},
}) ;
})) ;

export default function BooksDownloadDialog ( { open, onClose, initialAdvancedFunctionality, initialBegin, initialEnd } ) {

function BooksDownloadDialog ( { classes, open, onClose, initialYear } ) {
const classes = useStyles();

const [year, setYear] = useState(initialYear);
const [advancedFunctionality, setAdvancedFunctionality] = useState(initialAdvancedFunctionality);
const [begin, setBegin] = useState(initialBegin);
const [end, setEnd] = useState(initialEnd || addYears(initialBegin, 1));
const [firstBook, setFirstBook] = useState(''+books.DOWNLOAD_FIRST_BOOK);
const [lastBook, setLastBook] = useState(''+books.DOWNLOAD_LAST_BOOK);
const [maxRows, setMaxRows] = useState(''+books.DOWNLOAD_MAX_ROWS);

const setYear = year => {
const newBegin = new Date(year, 0, 1);
const newEnd = addYears(newBegin, 1);
setBegin(newBegin);
setEnd(newEnd);
} ;

useEffect(
() => {
setYear(initialYear);
setAdvancedFunctionality(initialAdvancedFunctionality);
setBegin(initialBegin);
setEnd(initialEnd || addYears(initialBegin, 1));
setFirstBook(''+books.DOWNLOAD_FIRST_BOOK);
setLastBook(''+books.DOWNLOAD_LAST_BOOK);
setMaxRows(''+books.DOWNLOAD_MAX_ROWS);
} ,
[initialYear]
[initialAdvancedFunctionality, initialBegin, initialEnd]
) ;

const downloadData = event => {
event.preventDefault();
const _year = parseInt(year, 10) ;
Meteor.call('books.year.csv', _year, (err, res) => {
const _firstBook = parseInt(firstBook, 10);
const _lastBook = parseInt(lastBook, 10);
const _maxRows = parseInt(maxRows, 10);
Meteor.call('books.interval.csv', begin, end, _firstBook, _lastBook, _maxRows , (err, res) => {
if ( err ) console.error( err ) ;
else {
saveTextAs(res, `carnets-${_year}.csv`);
const filename = advancedFunctionality ? 'carnets.csv' : `carnets-${begin.getFullYear()}.csv`;
saveTextAs(res, filename);
onClose();
}
});
Expand All @@ -61,19 +89,69 @@ function BooksDownloadDialog ( { classes, open, onClose, initialYear } ) {
<DialogTitle id="books-download-dialog-title">Download book data as CSV</DialogTitle>
<DialogContent>
<DialogContentText>
Choose range then click download.
{advancedFunctionality ? "Tune parameters" : "Choose year"} then click download.
</DialogContentText>
<TextField
{ advancedFunctionality ?
<Fragment>
<div>
<DatePicker
label="Begin"
value={begin}
onChange={date => setBegin(date)}
/>
</div>
<div>
<DatePicker
label="End"
value={end}
onChange={date => setEnd(date)}
/>
</div>
<div>
<TextField
label="First book"
value={firstBook}
onChange={e => setFirstBook(e.target.value)}
error={!/^\d+$/.test(firstBook)}
/>
</div>
<div>
<TextField
label="Last book"
value={lastBook}
onChange={e => setLastBook(e.target.value)}
error={!/^\d+$/.test(lastBook)}
/>
</div>
<div>
<TextField
label="Max rows"
value={maxRows}
onChange={e => setMaxRows(e.target.value)}
error={!/^\d+$/.test(maxRows)}
/>
</div>
</Fragment>
:
<div>
<DatePicker
views={["year"]}
label="Year"
value={year}
onChange={e => setYear(e.target.value)}
value={begin}
onChange={date => setYear(date.getFullYear())}
/>
</div>
}
</DialogContent>
<DialogActions>
<Button type="submit" onClick={onClose} color="default">
Cancel
<CancelIcon className={classes.rightIcon}/>
</Button>
{<Button onClick={e => setAdvancedFunctionality(true)} disabled={advancedFunctionality} color="default">
Advanced
<TuneIcon className={classes.rightIcon}/>
</Button>}
<Button onClick={downloadData} color="primary">
Download
<SaveIcon className={classes.rightIcon}/>
Expand All @@ -85,14 +163,12 @@ function BooksDownloadDialog ( { classes, open, onClose, initialYear } ) {
}

BooksDownloadDialog.defaultProps = {
initialYear: dateFormat(new Date(), 'yyyy'),
initialAdvancedFunctionality: false,
} ;

BooksDownloadDialog.propTypes = {
open: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired,
classes: PropTypes.object.isRequired,
initialYear: PropTypes.string.isRequired,
initialBegin: PropTypes.instanceOf(Date).isRequired,
initialEnd: PropTypes.instanceOf(Date),
} ;

export default withStyles(styles)(BooksDownloadDialog) ;
4 changes: 3 additions & 1 deletion imports/ui/books/BooksList.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ function BooksList ( { classes , match , year , page , perpage } ) {

const query = { fiscalYear: _year } ;

const initialBegin = new Date(_year, 0, 1);

return (
<div>
<YearJumper current={_year} toURL={x => `/books/${x}`}/>
Expand All @@ -52,7 +54,7 @@ function BooksList ( { classes , match , year , page , perpage } ) {
<Fab className={classes.saveButton} color="secondary" onClick={e => setDownloading(true)}>
<SaveIcon/>
</Fab>
<BooksDownloadDialog initialYear={year} open={downloading} onClose={e => setDownloading(false)}/>
<BooksDownloadDialog initialBegin={initialBegin} open={downloading} onClose={e => setDownloading(false)}/>
</div>
) ;

Expand Down

0 comments on commit 04bbbfa

Please sign in to comment.