Skip to content
Snippets Groups Projects
Unverified Commit f6891f20 authored by Jessie Keck's avatar Jessie Keck Committed by GitHub
Browse files

Merge pull request #1895 from ProjectMirador/form-styles

Style the add resource form
parents 157a4832 bd27e4e4
No related branches found
No related tags found
No related merge requests found
import React from 'react';
import { shallow } from 'enzyme';
import ManifestForm from '../../../src/components/ManifestForm';
/** create wrapper */
function createWrapper(props) {
return shallow(
<ManifestForm
fetchManifest={() => {}}
t={str => str}
{...props}
/>,
);
}
describe('ManifestForm', () => {
it('renders', () => {
const wrapper = createWrapper();
expect(wrapper.find('TextField[label="addManifestUrl"]').length).toBe(1);
expect(wrapper.find('WithStyles(Button)[type="submit"]').length).toBe(1);
});
it('has a cancel button when a cancel action is provided', () => {
const onCancel = jest.fn();
const wrapper = createWrapper({ onCancel });
expect(wrapper.find('WithStyles(Button)[onClick]').length).toBe(1);
wrapper.find('WithStyles(Button)[onClick]').simulate('click');
expect(onCancel).toHaveBeenCalled();
});
it('triggers an action when the form is submitted', () => {
const fetchManifest = jest.fn();
const wrapper = createWrapper({ fetchManifest });
wrapper.setState({ formValue: 'http://example.com/iiif' });
wrapper.find('form').simulate('submit', { preventDefault: () => {} });
expect(fetchManifest).toHaveBeenCalledWith('http://example.com/iiif');
});
});
......@@ -13,7 +13,7 @@ function createWrapper(props) {
t={str => str}
{...props}
/>,
);
).dive();
}
describe('WorkspaceAddButton', () => {
......@@ -29,4 +29,33 @@ describe('WorkspaceAddButton', () => {
wrapper.find('Connect(LoadNamespace(WithStyles(ManifestListItem)))').first().props().handleClose();
expect(setWorkspaceAddVisibility).toHaveBeenCalledWith(false);
});
it('has a button to add new resources', () => {
const wrapper = createWrapper();
expect(wrapper.find('WithStyles(Fab)').length).toBe(1);
wrapper.find('WithStyles(Fab)').simulate('click');
expect(wrapper.state().addResourcesOpen).toBe(true);
expect(wrapper.find('WithStyles(Fab)').props().disabled).toBe(true);
});
it('has a toggle-able drawer to add new resources', () => {
const wrapper = createWrapper();
wrapper.setState({ addResourcesOpen: true });
expect(wrapper.find('WithStyles(Drawer)').props().open).toBe(true);
expect(wrapper.find('WithStyles(Drawer) WithStyles(Typography)').dive().dive().text()).toBe('addResource');
wrapper.find('WithStyles(Drawer) WithStyles(AppBar)').simulate('click');
expect(wrapper.find('WithStyles(Drawer)').props().open).toBe(false);
});
it('passes a cancel action through to the form', () => {
const wrapper = createWrapper();
wrapper.setState({ addResourcesOpen: true });
expect(wrapper.find('WithStyles(Drawer) Connect(LoadNamespace(ManifestForm))').length).toBe(1);
wrapper.find('WithStyles(Drawer) Connect(LoadNamespace(ManifestForm))').props().onCancel();
expect(wrapper.find('WithStyles(Drawer)').props().open).toBe(false);
});
});
......@@ -2,9 +2,13 @@
"translation": {
"aboutThisItem": "About this item",
"add": "Add",
"addManifestUrl": "Resource location",
"addManifestUrlHelp": "The URL of a IIIF resource",
"addResource": "Add resource",
"addedFromUrl": "(Added from URL)",
"book": "Book",
"bottom": "Bottom",
"cancel": "Cancel",
"canvasIndex": "Index",
"closeCompanionWindow": "Close this companion window",
"closeInfoCompanionWindow": "Close information companion window",
......@@ -13,7 +17,7 @@
"dark": "Dark",
"downloadExport": "Download/Export",
"downloadExportWorkspace": "Download/export workspace",
"fetchManifest": "Fetch Manifest",
"fetchManifest": "Add",
"fullScreen": "Full Screen",
"light": "Light",
"listAllOpenWindows": "List all open windows",
......
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Button from '@material-ui/core/Button';
import Grid from '@material-ui/core/Grid';
import TextField from '@material-ui/core/TextField';
/**
* Provides a form for user input of a manifest url
......@@ -50,16 +53,33 @@ class ManifestForm extends Component {
*/
render() {
const { formValue } = this.state;
const { t } = this.props;
const { t, onCancel } = this.props;
return (
<form onSubmit={this.formSubmit}>
<input
<Grid container spacing={24}>
<Grid item sm={9}>
<TextField
fullWidth
value={formValue}
id="manifestURL"
type="text"
onChange={this.handleInputChange}
variant="filled"
label={t('addManifestUrl')}
helperText={t('addManifestUrlHelp')}
/>
<button id="fetchBtn" type="submit">{t('fetchManifest')}</button>
</Grid>
<Grid item sm={3}>
{ onCancel && (
<Button onClick={onCancel}>
{t('cancel')}
</Button>
)}
<Button id="fetchBtn" type="submit" variant="contained" color="primary">
{t('fetchManifest')}
</Button>
</Grid>
</Grid>
</form>
);
}
......@@ -67,11 +87,13 @@ class ManifestForm extends Component {
ManifestForm.propTypes = {
fetchManifest: PropTypes.func.isRequired,
onCancel: PropTypes.func,
t: PropTypes.func,
};
ManifestForm.defaultProps = {
t: key => key,
onCancel: null,
};
export default ManifestForm;
import React from 'react';
import PropTypes from 'prop-types';
import AddIcon from '@material-ui/icons/Add';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import AppBar from '@material-ui/core/AppBar';
import Drawer from '@material-ui/core/Drawer';
import Fab from '@material-ui/core/Fab';
import IconButton from '@material-ui/core/IconButton';
import Paper from '@material-ui/core/Paper';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import { withStyles } from '@material-ui/core/styles';
import ns from '../config/css-ns';
import ManifestForm from '../containers/ManifestForm';
import ManifestListItem from '../containers/ManifestListItem';
......@@ -11,11 +20,30 @@ import ManifestListItem from '../containers/ManifestListItem';
* @private
*/
class WorkspaceAdd extends React.Component {
/** */
constructor(props) {
super(props);
this.state = { addResourcesOpen: false };
this.setAddResourcesVisibility = this.setAddResourcesVisibility.bind(this);
}
/**
* @private
*/
setAddResourcesVisibility(bool) {
this.setState({ addResourcesOpen: bool });
}
/**
* render
*/
render() {
const { manifests, setWorkspaceAddVisibility } = this.props;
const {
manifests, setWorkspaceAddVisibility, t, classes,
} = this.props;
const { addResourcesOpen } = this.state;
const manifestList = Object.keys(manifests).map(manifest => (
<ManifestListItem
......@@ -29,10 +57,15 @@ class WorkspaceAdd extends React.Component {
<div className={ns('workspace-add')}>
{manifestList}
<Fab variant="extended" disabled={addResourcesOpen} className={classes.fab} color="primary" onClick={() => (this.setAddResourcesVisibility(true))}>
<AddIcon />
{t('addResource')}
</Fab>
<Drawer
variant="permanent"
open
variant="persistent"
anchor="bottom"
open={addResourcesOpen}
PaperProps={{ style: { position: 'absolute', left: 100 } }}
ModalProps={{
disablePortal: true,
......@@ -40,9 +73,21 @@ class WorkspaceAdd extends React.Component {
style: { position: 'absolute' },
}}
>
<ManifestForm
id="add-form"
/>
<Paper
className={classes.form}
>
<AppBar position="absolute" color="primary" onClick={() => (this.setAddResourcesVisibility(false))}>
<Toolbar>
<IconButton className={classes.menuButton} color="inherit" aria-label={t('closeMenu')}>
<ExpandMoreIcon />
</IconButton>
<Typography variant="h2" noWrap color="inherit" className={classes.typographyBody}>
{t('addResource')}
</Typography>
</Toolbar>
</AppBar>
<ManifestForm onCancel={() => (this.setAddResourcesVisibility(false))} />
</Paper>
</Drawer>
</div>
);
......@@ -52,6 +97,36 @@ class WorkspaceAdd extends React.Component {
WorkspaceAdd.propTypes = {
manifests: PropTypes.instanceOf(Object).isRequired,
setWorkspaceAddVisibility: PropTypes.func.isRequired,
classes: PropTypes.object, // eslint-disable-line react/forbid-prop-types
t: PropTypes.func,
};
export default WorkspaceAdd;
WorkspaceAdd.defaultProps = {
classes: {},
t: key => key,
};
/** */
const styles = theme => ({
form: {
...theme.mixins.gutters(),
paddingTop: theme.spacing.unit * 2,
paddingBottom: theme.spacing.unit * 2,
marginTop: 64,
},
fab: {
position: 'absolute',
bottom: theme.spacing.unit * 2,
right: theme.spacing.unit * 2,
},
typographyBody: {
flexGrow: 1,
fontSize: '1em',
},
menuButton: {
marginLeft: -12,
marginRight: 20,
},
});
export default withStyles(styles)(WorkspaceAdd);
import { compose } from 'redux';
import { connect } from 'react-redux';
import { withNamespaces } from 'react-i18next';
import * as actions from '../state/actions';
import WorkspaceAdd from '../components/WorkspaceAdd';
......@@ -19,6 +20,7 @@ const mapDispatchToProps = { setWorkspaceAddVisibility: actions.setWorkspaceAddV
const enhance = compose(
connect(mapStateToProps, mapDispatchToProps),
withNamespaces(),
// further HOC go here
);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment