Add sketch to collection from collection view

This commit is contained in:
Andrew Nicolaou 2019-09-17 20:48:37 +02:00 committed by Cassie Tarakajian
parent 7f78fda073
commit 27804acd6a
5 changed files with 171 additions and 96 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 CollectionsActions from '../../actions/collections';
import * as IdeActions from '../../actions/ide'; import * as IdeActions from '../../actions/ide';
import * as ToastActions from '../../actions/toast'; import * as ToastActions from '../../actions/toast';
import AddRemoveButton from '../../../../components/AddRemoveButton';
const downFilledTriangle = require('../../../../images/down-filled-triangle.svg'); 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 { class CollectionListRowBase extends React.Component {
static projectInCollection(project, collection) { static projectInCollection(project, collection) {

View file

@ -10,11 +10,13 @@ import classNames from 'classnames';
import slugify from 'slugify'; import slugify from 'slugify';
import * as ProjectActions from '../actions/project'; import * as ProjectActions from '../actions/project';
import * as ProjectsActions from '../actions/projects'; import * as ProjectsActions from '../actions/projects';
import * as CollectionsActions from '../actions/collections';
import * as ToastActions from '../actions/toast'; import * as ToastActions from '../actions/toast';
import * as SortingActions from '../actions/sorting'; import * as SortingActions from '../actions/sorting';
import * as IdeActions from '../actions/ide'; import * as IdeActions from '../actions/ide';
import getSortedSketches from '../selectors/projects'; import getSortedSketches from '../selectors/projects';
import Loader from '../../App/components/loader'; import Loader from '../../App/components/loader';
import AddRemoveButton from '../../../components/AddRemoveButton';
const arrowUp = require('../../../images/sort-arrow-up.svg'); const arrowUp = require('../../../images/sort-arrow-up.svg');
const arrowDown = require('../../../images/sort-arrow-down.svg'); const arrowDown = require('../../../images/sort-arrow-down.svg');
@ -134,36 +136,11 @@ class SketchListRowBase extends React.Component {
} }
} }
render() { renderDropdown = () => {
const { sketch, username } = this.props; const { optionsOpen } = this.state;
const { renameOpen, optionsOpen, renameValue } = this.state;
const userIsOwner = this.props.user.username === this.props.username; const userIsOwner = this.props.user.username === this.props.username;
let url = `/${username}/sketches/${sketch.id}`;
if (username === 'p5') {
url = `/${username}/sketches/${slugify(sketch.name, '_')}`;
}
return ( return (
<tr
className="sketches-table__row"
key={sketch.id}
>
<th scope="row">
<Link to={url}>
{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"> <td className="sketch-list__dropdown-column">
<button <button
className="sketch-list__dropdown-button" className="sketch-list__dropdown-button"
@ -232,6 +209,54 @@ class SketchListRowBase extends React.Component {
</li>} </li>}
</ul>} </ul>}
</td> </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;
let url = `/${username}/sketches/${sketch.id}`;
if (username === 'p5') {
url = `/${username}/sketches/${slugify(sketch.name, '_')}`;
}
return (
<tr
className="sketches-table__row"
key={sketch.id}
>
<th scope="row">
<Link to={url}>
{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>); </tr>);
} }
} }
@ -311,6 +336,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() { render() {
const username = this.props.username !== undefined ? this.props.username : this.props.user.username; const username = this.props.username !== undefined ? this.props.username : this.props.user.username;
return ( return (
@ -337,6 +370,10 @@ class SketchList extends React.Component {
sketch={sketch} sketch={sketch}
user={this.props.user} user={this.props.user}
username={username} 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> </tbody>
</table>} </table>}
@ -365,12 +402,7 @@ SketchList.propTypes = {
field: PropTypes.string.isRequired, field: PropTypes.string.isRequired,
direction: PropTypes.string.isRequired direction: PropTypes.string.isRequired
}).isRequired, }).isRequired,
project: PropTypes.shape({ addMode: PropTypes.bool,
id: PropTypes.string,
owner: PropTypes.shape({
id: PropTypes.string
})
})
}; };
SketchList.defaultProps = { SketchList.defaultProps = {
@ -392,7 +424,7 @@ function mapStateToProps(state) {
} }
function mapDispatchToProps(dispatch) { 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); 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 { getCollection } from '../../IDE/selectors/collections';
import Loader from '../../App/components/loader'; import Loader from '../../App/components/loader';
import EditableInput from '../../IDE/components/EditableInput'; 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 arrowUp = require('../../../images/sort-arrow-up.svg');
const arrowDown = require('../../../images/sort-arrow-down.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.getCollections(this.props.username);
this.props.resetSorting(); this.props.resetSorting();
this._renderFieldHeader = this._renderFieldHeader.bind(this); this._renderFieldHeader = this._renderFieldHeader.bind(this);
this.showAddSketches = this.showAddSketches.bind(this);
this.hideAddSketches = this.hideAddSketches.bind(this);
this.state = {
isAddingSketches: false,
};
} }
getTitle() { getTitle() {
@ -318,9 +326,21 @@ class Collection extends React.Component {
); );
} }
showAddSketches() {
this.setState({
isAddingSketches: true,
});
}
hideAddSketches() {
this.setState({
isAddingSketches: false,
});
}
_renderEmptyTable() { _renderEmptyTable() {
if (!this.hasCollectionItems()) { 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; return null;
} }
@ -379,8 +399,19 @@ class Collection extends React.Component {
/>))} />))}
</tbody> </tbody>
</table> </table>
<p><button onClick={this.showAddSketches}>Add more sketches</button></p>
</div> </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> </div>
</section> </section>
); );

View file

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