Skip to content

Commit

Permalink
veraPDF#25: Implemented option for conditional settings
Browse files Browse the repository at this point in the history
  • Loading branch information
Igor Poplavsky committed May 28, 2020
1 parent dd8114e commit c9c688f
Show file tree
Hide file tree
Showing 12 changed files with 252 additions and 58 deletions.
121 changes: 106 additions & 15 deletions src/components/layouts/pages/upload/Upload.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,131 @@
import React, { useMemo } from 'react';
import React, { useMemo, useState, useCallback } from 'react';
import PropTypes from 'prop-types';
import { hasFilesAttached } from '../../../../store/pdfFiles/selectors';
import { connect } from 'react-redux';
import { Redirect } from 'react-router-dom';

import AppPages from '../../../AppPages';
import { toggleUseSettings } from '../../../../store/application/actions';
import { resetProfile } from '../../../../store/job/settings/actions';
import { validate } from '../../../../store/job/actions';
import { hasFilesAttached } from '../../../../store/pdfFiles/selectors';
import { getUseSettings } from '../../../../store/application/selectors';
import { getJobId } from '../../../../store/job/selectors';
import { getProfile } from '../../../../store/job/settings/selectors';
import { getDefaultProfileName } from '../../../../store/validationProfiles/selectors';
import Dropzone from './dropzone/Dropzone';
import Stepper from '../../../shared/stepper/Stepper';
import PageNavigation from '../../../shared/pageNavigation/PageNavigation';
import Dropzone from './dropzone/Dropzone';
import Checkbox from '../../../shared/checkbox/Checkbox';
import Dialog from '../../../shared/dialog/Dialog';

function Upload(props) {
const { filesAttached } = props;
const forwardButton = useMemo(
() => ({
label: 'Configure job',
to: AppPages.SETTINGS,
disabled: !filesAttached,
}),
[filesAttached]
);
const CHECK_SETTINGS = 'Use custom validation settings';

function Upload({
filesAttached,
useSettings,
toggleSettings,
jobId,
profile,
defaultProfile,
resetProfile,
onValidateClick,
}) {
const [resetSettingsDialogOpened, setResetSettingsDialogOpened] = useState(false);
const forwardButton = useMemo(() => {
const button = { disabled: !filesAttached };
if (useSettings) {
return {
...button,
label: 'Configure job',
to: AppPages.SETTINGS,
};
}
return {
...button,
label: 'Validate',
onClick: onValidateClick,
};
}, [filesAttached, onValidateClick, useSettings]);
const onSettingsToggle = useCallback(() => {
if (profile !== defaultProfile && useSettings) {
return setResetSettingsDialogOpened(true);
}
return toggleSettings();
}, [defaultProfile, profile, toggleSettings, useSettings]);
const onResetSettingsClose = useCallback(() => {
setResetSettingsDialogOpened(false);
}, []);
const dialogActions = [
{
label: 'Cancel',
color: 'primary',
align: 'start',
onClick: onResetSettingsClose,
},
{
label: 'Reset settings',
color: 'primary',
variant: 'contained',
onClick: () => {
resetProfile();
toggleSettings();
onResetSettingsClose();
},
},
];

if (!useSettings && jobId) {
// Once job is initialized and we know its ID redirect to status page to track its progress
return <Redirect push to={AppPages.STATUS.url(jobId)} />;
}

return (
<section className="upload">
<Stepper activeStep={AppPages.UPLOAD} />
<Dropzone />
<PageNavigation forward={forwardButton} />
<PageNavigation
back={<Checkbox checked={useSettings} label={CHECK_SETTINGS} onChange={onSettingsToggle} />}
forward={forwardButton}
/>
<Dialog
onClose={onResetSettingsClose}
open={resetSettingsDialogOpened}
actions={dialogActions}
title={`You are about to reset profile to default ${defaultProfile}.`}
>
Proceed?
</Dialog>
</section>
);
}

Upload.propTypes = {
jobId: PropTypes.string,
profile: PropTypes.string,
defaultProfile: PropTypes.string,
useSettings: PropTypes.bool.isRequired,
filesAttached: PropTypes.bool.isRequired,
toggleSettings: PropTypes.func.isRequired,
onValidateClick: PropTypes.func.isRequired,
resetProfile: PropTypes.func.isRequired,
};

const mapStateToProps = state => {
return {
filesAttached: hasFilesAttached(state),
useSettings: getUseSettings(state),
jobId: getJobId(state),
profile: getProfile(state),
defaultProfile: getDefaultProfileName(state),
};
};

const mapDispatchToProps = dispatch => {
return {
toggleSettings: () => dispatch(toggleUseSettings()),
onValidateClick: () => dispatch(validate()),
resetProfile: () => dispatch(resetProfile()),
};
};

export default connect(mapStateToProps)(Upload);
export default connect(mapStateToProps, mapDispatchToProps)(Upload);
1 change: 0 additions & 1 deletion src/components/layouts/pages/upload/dropzone/Dropzone.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

&__container {
width: 70%;
max-width: 700px;
height: 100px;
margin: auto;
padding: 20px;
Expand Down
32 changes: 32 additions & 0 deletions src/components/shared/checkbox/Checkbox.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React, { useCallback } from 'react';
import PropTypes from 'prop-types';

import MaterialCheckbox from '@material-ui/core/Checkbox';
import FormControlLabel from '@material-ui/core/FormControlLabel';

function Checkbox({ checked, label, disabled, onChange }) {
const handleChange = useCallback(e => onChange(e.target.value), [onChange]);

return (
<FormControlLabel
className="checkbox-container"
disabled={disabled}
label={label}
control={<MaterialCheckbox checked={checked} color="primary" onChange={handleChange} />}
/>
);
}

Checkbox.propTypes = {
checked: PropTypes.bool.isRequired,
label: PropTypes.string,
disabled: PropTypes.bool,
onChange: PropTypes.func.isRequired,
};

Checkbox.defaultProps = {
label: '',
disabled: false,
};

export default Checkbox;
35 changes: 30 additions & 5 deletions src/components/shared/dialog/Dialog.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,57 @@
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import MaterialDialog from '@material-ui/core/Dialog';
import DialogTitle from '@material-ui/core/DialogTitle';
import DialogContent from '@material-ui/core/DialogContent';
import DialogContentText from '@material-ui/core/DialogContentText';
import DialogActions from '@material-ui/core/DialogActions';
import Button from '../button/Button';

function Dialog({ title, content, actions, open, onClose }) {
import './Dialog.scss';

function Dialog({ title, actions, open, onClose, children }) {
return (
<MaterialDialog
open={open}
onClose={onClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
className="dialog"
>
{title && <DialogTitle id="alert-dialog-title">{title}</DialogTitle>}
<DialogContent>
<DialogContentText id="alert-dialog-description">{content}</DialogContentText>
<DialogContentText id="alert-dialog-description">{children}</DialogContentText>
</DialogContent>
{actions && <DialogActions>{actions}</DialogActions>}
{actions && (
<DialogActions className="dialog__action">
<Actions actions={actions} />
</DialogActions>
)}
</MaterialDialog>
);
}

function Actions({ actions }) {
return actions.map((props, index) => (
<div key={index} className={classNames({ _start: props.align === 'start' })}>
<Button {...props}>{props.label}</Button>
</div>
));
}

export const ActionShape = PropTypes.shape({
label: PropTypes.string,
variant: PropTypes.string,
color: PropTypes.string,
disabled: PropTypes.bool,
onClick: PropTypes.func,
align: PropTypes.string,
});

Dialog.propTypes = {
content: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired,
actions: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
actions: PropTypes.arrayOf(ActionShape),
title: PropTypes.string,
open: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired,
Expand Down
9 changes: 9 additions & 0 deletions src/components/shared/dialog/Dialog.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.dialog {
&__action {

._start {
flex: 1;
justify-content: flex-start;
}
}
}
30 changes: 17 additions & 13 deletions src/components/shared/pageNavigation/PageNavigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,35 @@ function PageNavigation(props) {
const { back, forward, center } = props;
return (
<nav className="page-navigation">
<section className="page-navigation__start">{getButton(back, TYPE.BACK)}</section>
<section className="page-navigation__center">{getButton(center, TYPE.CENTER)}</section>
<section className="page-navigation__end">{getButton(forward, TYPE.FORWARD)}</section>
<section className="page-navigation__start">{getComponent(back, TYPE.BACK)}</section>
<section className="page-navigation__center">{getComponent(center, TYPE.CENTER)}</section>
<section className="page-navigation__end">{getComponent(forward, TYPE.FORWARD)}</section>
</nav>
);
}

function getButton(buttonObject, type) {
if (buttonObject?.to) {
function getComponent(componentObject, type) {
if (React.isValidElement(componentObject)) {
return componentObject;
}

if (componentObject?.to) {
return (
<NavButton to={buttonObject.to} type={type} disabled={buttonObject.disabled} variant={VARIANTS[type]}>
{buttonObject.label}
<NavButton to={componentObject.to} type={type} disabled={componentObject.disabled} variant={VARIANTS[type]}>
{componentObject.label}
</NavButton>
);
}

if (buttonObject?.onClick) {
if (componentObject?.onClick) {
return (
<Button
variant={VARIANTS[type]}
color="primary"
disabled={buttonObject.disabled}
onClick={buttonObject.onClick}
disabled={componentObject.disabled}
onClick={componentObject.onClick}
>
{buttonObject.label}
{componentObject.label}
</Button>
);
}
Expand All @@ -59,8 +63,8 @@ const ButtonInterface = PropTypes.shape({
});

PageNavigation.propTypes = {
back: ButtonInterface,
forward: ButtonInterface,
back: PropTypes.oneOfType([ButtonInterface, PropTypes.element]),
forward: PropTypes.oneOfType([ButtonInterface, PropTypes.element]),
};

export default PageNavigation;
1 change: 1 addition & 0 deletions src/components/shared/pageNavigation/PageNavigation.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
flex-grow: 1;
flex-basis: 0;
justify-content: center;
align-items: start;

.app-link {
color: inherit;
Expand Down
Loading

0 comments on commit c9c688f

Please sign in to comment.