Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix form usability issues #74

Merged
merged 7 commits into from
Aug 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 8 additions & 3 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,17 @@ class App extends Component {
};

render() {
const {isMobile} = this.props;
const {isMobile, history} = this.props;
// If we are on the mobile create reports page, show nothing. Otherwise, show either the mobile header or the
// desktop header.
const header = isMobile && history.location.pathname === '/reports/create' ? null : isMobile ? <Header/> : <DesktopHeader/>;
// If we are on mobile, and not on the create reports page, show a footer.
const footer = isMobile && history.location.pathname !== '/reports/create' ? <Footer/> : null;
return (
<div className="App">
{isMobile ? <Header/> : <DesktopHeader/>}
{header}
<Main/>
{isMobile ? <Footer/> : null}
{footer}
</div>
);
}
Expand Down
69 changes: 4 additions & 65 deletions src/components/Footer.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import React, { Component } from 'react';
import AddIcon from '@material-ui/icons/Add';
import ClearIcon from '@material-ui/icons/Clear';
import MapIcon from '@material-ui/icons/Map';
import SettingsIcon from '@material-ui/icons/Settings';
import Button from '@material-ui/core/Button';
import Fab from '@material-ui/core/Fab';
import Drawer from '@material-ui/core/Drawer';
import { withStyles } from '@material-ui/core/styles';
import { setOnExplore } from '../store/actions';

import Form from './Form';
import { withRouter } from "react-router";
import {connect} from "react-redux";

const styles = theme => ({
list: {
Expand Down Expand Up @@ -57,42 +52,8 @@ const styles = theme => ({
}
});

class Footer extends Component {
state = {
open: false,
};

componentDidMount() {
const { location } = this.props;
if (window.innerWidth < 768 && location.pathname === '/reports/create') {
this.handleDrawer(true);
}
}

toggleDrawer = drawerState => () => {
const { history } = this.props;
const { open } = this.state;

this.setState({
open: drawerState
}, () => {
if (open) {
history.push('/');
} else {
history.push('/reports/create');
}
});
};

handleDrawer = state => {
this.setState({
open: state
});
};

render() {
const { open } = this.state;
const { classes, history, isOnExplore } = this.props;
const Footer = (props) => {
const { classes, history } = props;

return (
<div className={classes.footerIconDiv}>
Expand All @@ -103,24 +64,9 @@ class Footer extends Component {
</Button>
</div>
<div className={classes.flexColumn}>
<Fab color="primary" aria-label="Add" className={classes.plusButton} size="large" onClick={this.toggleDrawer(!open)}>
<Fab color="primary" aria-label="Add" className={classes.plusButton} size={"large"} onClick={() => history.push('/reports/create')}>
<AddIcon/>
</Fab>
<Drawer
anchor="bottom"
open={open}
onClose={this.toggleDrawer(!open)}
className="formWizard"
>
<div tabIndex={0}>
<div>
<Fab color="primary" aria-label="Add" className={classes.fab}>
<ClearIcon onClick={this.toggleDrawer(!open)}/>
</Fab>
</div>
<Form handleDrawerState={this.handleDrawer} fromDrawer/>
</div>
</Drawer>
</div>
<div className={classes.flexColumn}>
<Button className={classes.footerIcons} style={{ float: 'right', marginRight: '50px', color: history.location.pathname==='/resources'?
Expand All @@ -132,13 +78,6 @@ class Footer extends Component {
</div>
</div>
);
}
}

const mapStateToProps = (state) => {
return {
isOnExplore: state.isOnExplore
};
};

export default withRouter(connect(mapStateToProps)(withStyles(styles)(Footer)));
export default withRouter(withStyles(styles)(Footer));
87 changes: 43 additions & 44 deletions src/components/Form.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ import MediaUpload from './MediaUpload';
import FormMap from './FormMap';
import StaticFormMap from './StaticFormMap'
import MediaDisplay from './MediaDisplay';
import FormRadioButtons from './FormRadioButtons';
import NeighborhoodService from '../services/NeighborhoodService';
import {Collapse, Fab, withStyles} from "@material-ui/core";
import ClearIcon from '@material-ui/icons/Clear';
import "react-responsive-carousel/lib/styles/carousel.min.css";
import { Carousel } from 'react-responsive-carousel';
import Info from '@material-ui/icons/InfoOutlined';
Expand Down Expand Up @@ -59,17 +61,17 @@ const DIALOG_MODES = {
ERROR: 'error',
LARGE_FILES: 'largeFiles',
PERMISSION: 'permission',
CLOSED: 'closed'
CLOSED: 'closed',
MISSING_FIELD: 'missing field',
};

const styles = {
allContent: {
height: '100%',
overflow: 'scroll',
position: 'static',
display: 'flex',
flexDirection: 'column',
backgroundColor: 'white'
overlay: {
height: '100vh',
width: '100vw',
position: 'fixed',
top: 0,
zIndex: 999,
},
header: {
display: 'flex',
Expand Down Expand Up @@ -130,9 +132,8 @@ const styles = {
paddingRight: 35,
},
addButtonContainer: {
position: 'absolute',
left: '34%',
top: '15%',
position: 'relative',
top: -250,
zIndex: 0,
},
doneButtonContainer: {
Expand All @@ -146,7 +147,7 @@ const styles = {
},
interactiveMapInnerContainer: {
flex: 1,
}
},
};

//https://github.com/Hacker0x01/react-datepicker/issues/942#issuecomment-485934975
Expand Down Expand Up @@ -259,10 +260,13 @@ class Form extends Component {
.then(response => {
this.setState({submitting: false});
if (response.status === 200) {
this.setState({dialogMode: DIALOG_MODES.THANKS}); // Open the submission recieved dialog
this.setState({dialogMode: DIALOG_MODES.THANKS}); // Open the submission received dialog
} else {
this.setState({dialogMode: DIALOG_MODES.ERROR});
}
})
.catch(err => {
this.setState({submitting: false, dialogMode: DIALOG_MODES.ERROR});
});
};

Expand Down Expand Up @@ -381,6 +385,11 @@ class Form extends Component {
open={true}
onClose={this.handleClose}
message={THANKS_FOR_SUBMITTING}/>;
case DIALOG_MODES.MISSING_FIELD:
return <FormInfoDialog
open={true}
onClose={() => this.setState({dialogMode: DIALOG_MODES.CLOSED})}
message={"Your report is missing some required fields! Please fill in all required fields and re-submit."}/>;
default:
return null;
}
Expand Down Expand Up @@ -433,16 +442,21 @@ class Form extends Component {
const {
mapLat, mapLng, timestamp, confidence, numberOfAdultSpecies,
numberOfYoungSpecies, numberOfAdults, numberOfChildren, reaction, reactionDescription, numberOfDogs, dogSize,
onLeash, animalBehavior, animalEating, vocalization, vocalizationDesc, carnivoreResponse, carnivoreConflict,
onLeash, animalBehavior, animalEating, vocalization, vocalizationDesc, carnivoreResponse, carnivoreConflict,
conflictDesc, contactName, contactEmail, contactPhone, generalComments, media, submitting,
neighborhood, dialogMode, showObserverDetails, showAnimalBehavior, showContactInformation, spinnerActive, addMode,
imagePaths, audioPaths, videoPaths
imagePaths, audioPaths, videoPaths, species
} = this.state;
const {classes, isMobile} = this.props;
const {classes, isMobile, history} = this.props;
return (
<LoadingOverlay active={submitting} spinner text='Submitting...'>
<>
{submitting ? <LoadingOverlay active={submitting} spinner text='Submitting...' className={classes.overlay} />: null}
{isMobile ?
<Fab color="primary" aria-label="Add" className={classes.fab}>
<ClearIcon onClick={() => history.push('/')}/>
</Fab>: null}
<h2>Report a carnivore sighting</h2>
<ValidatorForm onError={errors => console.log(errors)}
<ValidatorForm onError={() => this.setState({dialogMode: DIALOG_MODES.MISSING_FIELD})}
onSubmit={this.handleSubmit}
className="formWizardBody" autoComplete="off">
{this.renderMap(classes, isMobile,neighborhood, mapLng, mapLat)}
Expand Down Expand Up @@ -514,28 +528,13 @@ class Form extends Component {
</Carousel>
</DialogContent>
</Dialog>
{speciesLst.map((type, idx) =>
<span className={isMobile ? classes.radioButtonContainerMobile : "radioButtonContainer"} key={idx}>
<div >
<label >
<input
type="radio"
name="react-tips"
value={type}
onChange={() => this.setState({species: type})}
/>
{type}
</label>
</div>
<div>
<ResizableIconButton
onClick={() => this.openCarousel(idx)}
backgroundColor={'white'}
color={'#4385E9'}>
<Info />
</ResizableIconButton>
</div>
</span>)}
<FormRadioButtons
species={speciesLst}
onChangeSelection={(species) => () => this.setState({species})}
onClickInfo={(index) => () => this.openCarousel(index)}
validators={['required']}
errorMessages={['This field is required']}
value={species}/>
</div>

<div className="formItem">
Expand Down Expand Up @@ -571,7 +570,7 @@ class Form extends Component {
<hr/>

{/*Observer details*/}
<div className={classes.allContent}>
<div>
{/* Species Identification Tips */}
{this.getCollapse(classes, "Observer Details (Optional)", this.toggleShow('showObserverDetails'), showObserverDetails,
<div>
Expand Down Expand Up @@ -659,7 +658,7 @@ class Form extends Component {
<br/>

{/*Animal behavior*/}
<div className={classes.allContent}>
<div>
{/* Species Identification Tips */}
{this.getCollapse(classes, "Animal Behavior (Optional)", this.toggleShow('showAnimalBehavior'), showAnimalBehavior,
<div>
Expand Down Expand Up @@ -768,7 +767,7 @@ class Form extends Component {
<br/>

{/*Contact*/}
<div className={classes.allContent}>
<div>
{/* Species Identification Tips */}
{this.getCollapse(classes, "Contact Information (Optional)", this.toggleShow('showContactInformation'), showContactInformation,
<div>
Expand Down Expand Up @@ -843,7 +842,7 @@ class Form extends Component {
</Button>
</ValidatorForm>
{this.getDialogFromMode(dialogMode)}
</LoadingOverlay>
</>
);
}
}
Expand Down
77 changes: 77 additions & 0 deletions src/components/FormRadioButtons.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { ValidatorComponent } from 'react-material-ui-form-validator';
import ResizableIconButton from "./ResizableIconButton";
import Info from '@material-ui/icons/InfoOutlined';
import React from "react";
import { withStyles } from "@material-ui/core"
import { connect } from "react-redux";

const styles = (theme) => ({
radioButtonContainerMobile: {
display: 'flex',
alignItems: 'baseline',
flexDirection: 'row',
justifyContent: 'space-between',
position: 'relative',
paddingLeft: 35,
paddingRight: 35,
},
radioButtonContainer: {
display: 'flex',
alignItems: 'baseline',
flexDirection: 'row',
justifyContent: 'spaceBetween',
paddingLeft: '35%',
paddingRight: '35%',
position: 'relative'
}
});

class FormRadioButtons extends ValidatorComponent {

render = () => {
const { species, classes, isMobile, onChangeSelection, onClickInfo } = this.props;
return <div>
{this.errorText()}
{species.map((type, idx) =>
<span className={isMobile ? classes.radioButtonContainerMobile : "radioButtonContainer"} key={idx}>
<div >
<label >
<input
type="radio"
name="react-tips"
value={type}
onChange={onChangeSelection(type)}
/>
{type}
</label>
</div>
<div>
<ResizableIconButton
onClick={onClickInfo(idx)}
backgroundColor={'white'}
color={'#4385E9'}>
<Info />
</ResizableIconButton>
</div>
</span>)}
</div>
};

errorText = () => {
const { isValid } = this.state;
if (isValid) {
return null;
}
return (
<div style={{ color: 'red' }}>
{this.getErrorMessage()}
</div>
);
}
}

const mapStateToProps = (state) => {
return {isMobile: state.isMobile};
};

export default withStyles(styles)(connect(mapStateToProps)(FormRadioButtons));