Add sketch to collection from collection view

This commit is contained in:
Andrew Nicolaou 2019-09-17 20:48:37 +02:00
parent 709aa8eccb
commit b980ec7854
5 changed files with 172 additions and 91 deletions

View file

@ -0,0 +1,24 @@
import React from 'react';
import PropTypes from 'prop-types';
import InlineSVG from 'react-inlinesvg';
const addIcon = require('../images/plus.svg');
const removeIcon = require('../images/minus.svg');
const AddRemoveButton = ({ type, onClick }) => {
const alt = type === 'add' ? 'add to collection' : 'remove from collection';
const icon = type === 'add' ? addIcon : removeIcon;
return (
<button className="overlay__close-button" onClick={onClick}>
<InlineSVG src={icon} alt={alt} />
</button>
);
};
AddRemoveButton.propTypes = {
type: PropTypes.oneOf(['add', 'remove']).isRequired,
onClick: PropTypes.func.isRequired,
};
export default AddRemoveButton;

View file

@ -9,26 +9,9 @@ import * as ProjectActions from '../../actions/project';
import * as CollectionsActions from '../../actions/collections';
import * as IdeActions from '../../actions/ide';
import * as ToastActions from '../../actions/toast';
import AddRemoveButton from '../../../../components/AddRemoveButton';
const downFilledTriangle = require('../../../../images/down-filled-triangle.svg');
const addIcon = require('../../../../images/plus.svg');
const removeIcon = require('../../../../images/minus.svg');
const AddRemoveButton = ({ type, onClick }) => {
const alt = type === 'add' ? 'add to collection' : 'remove from collection';
const icon = type === 'add' ? addIcon : removeIcon;
return (
<button className="overlay__close-button" onClick={onClick}>
<InlineSVG src={icon} alt={alt} />
</button>
);
};
AddRemoveButton.propTypes = {
type: PropTypes.oneOf(['add', 'remove']).isRequired,
onClick: PropTypes.func.isRequired,
};
class CollectionListRowBase extends React.Component {
static projectInCollection(project, collection) {

View file

@ -9,11 +9,13 @@ import { bindActionCreators } from 'redux';
import classNames from 'classnames';
import * as ProjectActions from '../actions/project';
import * as ProjectsActions from '../actions/projects';
import * as CollectionsActions from '../actions/collections';
import * as ToastActions from '../actions/toast';
import * as SortingActions from '../actions/sorting';
import * as IdeActions from '../actions/ide';
import getSortedSketches from '../selectors/projects';
import Loader from '../../App/components/loader';
import AddRemoveButton from '../../../components/AddRemoveButton';
const arrowUp = require('../../../images/sort-arrow-up.svg');
const arrowDown = require('../../../images/sort-arrow-down.svg');
@ -133,32 +135,11 @@ class SketchListRowBase extends React.Component {
}
}
render() {
const { sketch, username } = this.props;
const { renameOpen, optionsOpen, renameValue } = this.state;
renderDropdown = () => {
const { optionsOpen } = this.state;
const userIsOwner = this.props.user.username === this.props.username;
return (
<tr
className="sketches-table__row"
key={sketch.id}
>
<th scope="row">
<Link to={`/${username}/sketches/${sketch.id}`}>
{renameOpen ? '' : sketch.name}
</Link>
{renameOpen
&&
<input
value={renameValue}
onChange={this.handleRenameChange}
onKeyUp={this.handleRenameEnter}
onBlur={this.resetSketchName}
onClick={e => e.stopPropagation()}
/>
}
</th>
<td>{format(new Date(sketch.createdAt), 'MMM D, YYYY h:mm A')}</td>
<td>{format(new Date(sketch.updatedAt), 'MMM D, YYYY h:mm A')}</td>
<td className="sketch-list__dropdown-column">
<button
className="sketch-list__dropdown-button"
@ -227,6 +208,50 @@ class SketchListRowBase extends React.Component {
</li>}
</ul>}
</td>
);
}
renderAddRemoveButtons = () => {
return (
<td className="sketch-list__dropdown-column">{
this.props.inCollection ?
<AddRemoveButton type="remove" onClick={this.props.onCollectionRemove} /> :
<AddRemoveButton type="add" onClick={this.props.onCollectionAdd} />
}
</td>
);
}
renderActions = () => {
return this.props.addMode === true ? this.renderAddRemoveButtons() : this.renderDropdown();
}
render() {
const { sketch, username } = this.props;
const { renameOpen, renameValue } = this.state;
return (
<tr
className="sketches-table__row"
key={sketch.id}
>
<th scope="row">
<Link to={`/${username}/sketches/${sketch.id}`}>
{renameOpen ? '' : sketch.name}
</Link>
{renameOpen
&&
<input
value={renameValue}
onChange={this.handleRenameChange}
onKeyUp={this.handleRenameEnter}
onBlur={this.resetSketchName}
onClick={e => e.stopPropagation()}
/>
}
</th>
<td>{format(new Date(sketch.createdAt), 'MMM D, YYYY h:mm A')}</td>
<td>{format(new Date(sketch.updatedAt), 'MMM D, YYYY h:mm A')}</td>
{this.renderActions()}
</tr>);
}
}
@ -306,6 +331,14 @@ class SketchList extends React.Component {
);
}
handleCollectionAdd = (sketchId) => {
this.props.addToCollection(this.props.collection.id, sketchId);
}
handleCollectionRemove = (sketchId) => {
this.props.removeFromCollection(this.props.collection.id, sketchId);
}
render() {
const username = this.props.username !== undefined ? this.props.username : this.props.user.username;
return (
@ -332,6 +365,10 @@ class SketchList extends React.Component {
sketch={sketch}
user={this.props.user}
username={username}
addMode={this.props.addMode}
onCollectionAdd={() => this.handleCollectionAdd(sketch.id)}
onCollectionRemove={() => this.handleCollectionRemove(sketch.id)}
inCollection={this.props.collection && this.props.collection.items.find(item => item.project.id === sketch.id) != null}
/>))}
</tbody>
</table>}
@ -359,7 +396,8 @@ SketchList.propTypes = {
sorting: PropTypes.shape({
field: PropTypes.string.isRequired,
direction: PropTypes.string.isRequired
}).isRequired
}).isRequired,
addMode: PropTypes.bool,
};
SketchList.defaultProps = {
@ -376,7 +414,7 @@ function mapStateToProps(state) {
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(Object.assign({}, ProjectsActions, ToastActions, SortingActions), dispatch);
return bindActionCreators(Object.assign({}, ProjectsActions, CollectionsActions, ToastActions, SortingActions), dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(SketchList);

View file

@ -16,6 +16,8 @@ import * as IdeActions from '../../IDE/actions/ide';
import { getCollection } from '../../IDE/selectors/collections';
import Loader from '../../App/components/loader';
import EditableInput from '../../IDE/components/EditableInput';
import Overlay from '../../App/components/Overlay';
import SketchList from '../../IDE/components/SketchList';
const arrowUp = require('../../../images/sort-arrow-up.svg');
const arrowDown = require('../../../images/sort-arrow-down.svg');
@ -232,6 +234,12 @@ class Collection extends React.Component {
this.props.getCollections(this.props.username);
this.props.resetSorting();
this._renderFieldHeader = this._renderFieldHeader.bind(this);
this.showAddSketches = this.showAddSketches.bind(this);
this.hideAddSketches = this.hideAddSketches.bind(this);
this.state = {
isAddingSketches: false,
};
}
getTitle() {
@ -318,9 +326,21 @@ class Collection extends React.Component {
);
}
showAddSketches() {
this.setState({
isAddingSketches: true,
});
}
hideAddSketches() {
this.setState({
isAddingSketches: false,
});
}
_renderEmptyTable() {
if (!this.hasCollectionItems()) {
return (<p className="sketches-table__empty">No sketches in collection.</p>);
return (<p className="sketches-table__empty">No sketches in collection. <button onClick={this.showAddSketches}>Add some sketches</button></p>);
}
return null;
}
@ -379,8 +399,19 @@ class Collection extends React.Component {
/>))}
</tbody>
</table>
<p><button onClick={this.showAddSketches}>Add more sketches</button></p>
</div>
}
{
this.state.isAddingSketches && (
<Overlay title="Add sketches" closeOverlay={this.hideAddSketches}>
<div className="collection-add-sketch">
<SketchList username={this.props.username} addMode collection={this.props.collection} />
</div>
</Overlay>
)
}
</div>
</section>
);

View file

@ -43,3 +43,8 @@
.collection-table-wrapper {
margin: #{28 / $base-font-size}rem #{56 / $base-font-size}rem;
}
.collection-add-sketch {
padding: #{24 / $base-font-size}rem;
overflow: scroll;
}