Remove popover and "add to collection" code from SketchList
This commit is contained in:
parent
ad13684fe3
commit
161725cb28
4 changed files with 52 additions and 300 deletions
|
@ -1,144 +0,0 @@
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React from 'react';
|
|
||||||
import InlineSVG from 'react-inlinesvg';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { bindActionCreators } from 'redux';
|
|
||||||
|
|
||||||
import * as CollectionsActions from '../../actions/collections';
|
|
||||||
import getSortedCollections from '../../selectors/collections';
|
|
||||||
|
|
||||||
import exitUrl from '../../../../images/exit.svg';
|
|
||||||
|
|
||||||
import Loader from '../../../App/components/loader';
|
|
||||||
import { Searchbar } from '../Searchbar';
|
|
||||||
import Item from './Item';
|
|
||||||
|
|
||||||
const NoCollections = () => (
|
|
||||||
<div className="collection-popover__empty">
|
|
||||||
<p>No collections</p>
|
|
||||||
</div>);
|
|
||||||
|
|
||||||
const projectInCollection = (project, collection) => (
|
|
||||||
collection.items.find(item => item.project.id === project.id) != null
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
const CollectionPopover = ({
|
|
||||||
loading, onClose, project, collections, addToCollection, removeFromCollection, getCollections, user
|
|
||||||
}) => {
|
|
||||||
const [didLoadData, setDidLoadData] = React.useState(null);
|
|
||||||
const [searchTerm, setSearchTerm] = React.useState('');
|
|
||||||
const filteredCollections = searchTerm === '' ?
|
|
||||||
collections :
|
|
||||||
collections.filter(({ name }) => name.toUpperCase().includes(searchTerm.toUpperCase()));
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
getCollections(user.username);
|
|
||||||
}, [user]);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (didLoadData === true) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loading && didLoadData === null) {
|
|
||||||
setDidLoadData(false);
|
|
||||||
} else if (!loading && didLoadData === false) {
|
|
||||||
setDidLoadData(true);
|
|
||||||
}
|
|
||||||
}, [loading]);
|
|
||||||
|
|
||||||
const handleAddToCollection = (collectionId) => {
|
|
||||||
addToCollection(collectionId, project.id);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRemoveFromCollection = (collectionId) => {
|
|
||||||
removeFromCollection(collectionId, project.id);
|
|
||||||
};
|
|
||||||
|
|
||||||
let content = null;
|
|
||||||
|
|
||||||
if (didLoadData && collections.length === 0) {
|
|
||||||
content = <NoCollections />;
|
|
||||||
} else if (didLoadData) {
|
|
||||||
content = (
|
|
||||||
<ul>
|
|
||||||
{
|
|
||||||
filteredCollections.map((collection) => {
|
|
||||||
const inCollection = projectInCollection(project, collection);
|
|
||||||
const handleSelect = inCollection ? handleRemoveFromCollection : handleAddToCollection;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Item
|
|
||||||
inCollection={inCollection}
|
|
||||||
key={collection.id}
|
|
||||||
collection={collection}
|
|
||||||
onSelect={() => handleSelect(collection.id)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</ul>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
content = <Loader />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="collection-popover">
|
|
||||||
<div className="collection-popover__header">
|
|
||||||
<h4>Add to collection</h4>
|
|
||||||
<button className="collection-popover__exit-button" onClick={onClose}>
|
|
||||||
<InlineSVG src={exitUrl} alt="Close Add to Collection" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="collection-popover__filter">
|
|
||||||
<Searchbar
|
|
||||||
searchLabel="Search collections..."
|
|
||||||
searchTerm={searchTerm}
|
|
||||||
setSearchTerm={setSearchTerm}
|
|
||||||
resetSearchTerm={() => setSearchTerm('')}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="collection-popover__items">
|
|
||||||
{content}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
CollectionPopover.propTypes = {
|
|
||||||
loading: PropTypes.bool.isRequired,
|
|
||||||
onClose: PropTypes.func.isRequired,
|
|
||||||
getCollections: PropTypes.func.isRequired,
|
|
||||||
addToCollection: PropTypes.func.isRequired,
|
|
||||||
removeFromCollection: PropTypes.func.isRequired,
|
|
||||||
user: PropTypes.shape({
|
|
||||||
username: PropTypes.string.isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
collections: PropTypes.arrayOf(PropTypes.shape({
|
|
||||||
name: PropTypes.string,
|
|
||||||
})).isRequired,
|
|
||||||
project: PropTypes.shape({
|
|
||||||
id: PropTypes.string,
|
|
||||||
}).isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
function mapStateToProps(state, ownProps) {
|
|
||||||
return {
|
|
||||||
user: state.user,
|
|
||||||
collections: getSortedCollections(state),
|
|
||||||
loading: state.loading,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
|
||||||
return bindActionCreators(
|
|
||||||
Object.assign({}, CollectionsActions),
|
|
||||||
dispatch
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(CollectionPopover);
|
|
|
@ -1,37 +0,0 @@
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React from 'react';
|
|
||||||
import { Link } from 'react-router';
|
|
||||||
import InlineSVG from 'react-inlinesvg';
|
|
||||||
|
|
||||||
import check from '../../../../images/check.svg';
|
|
||||||
|
|
||||||
const checkIcon = (
|
|
||||||
<InlineSVG className="sketch-list__check-icon" src={check} alt="In collection" />
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
const CollectionItem = ({ inCollection, collection, onSelect }) => (
|
|
||||||
<li className="collection-popover__item">
|
|
||||||
<div className="collection-popover__item__info">
|
|
||||||
{inCollection && checkIcon}
|
|
||||||
|
|
||||||
<button onClick={onSelect}>
|
|
||||||
{collection.name}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="collection-popover__item__view">
|
|
||||||
<Link className="collection-popover__item__view-button" to={`/${collection.owner.username}/collections/${collection.id}`}>View</Link>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
|
|
||||||
CollectionItem.propTypes = {
|
|
||||||
inCollection: PropTypes.bool.isRequired,
|
|
||||||
onSelect: PropTypes.func.isRequired,
|
|
||||||
collection: PropTypes.shape({
|
|
||||||
name: PropTypes.string,
|
|
||||||
}).isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CollectionItem;
|
|
|
@ -1 +0,0 @@
|
||||||
export { default } from './CollectionPopover.jsx';
|
|
|
@ -16,32 +16,12 @@ 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 CollectionPopover from './CollectionPopover';
|
import Overlay from '../../App/components/Overlay';
|
||||||
|
import AddToCollectionList from './AddToCollectionList';
|
||||||
|
|
||||||
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');
|
||||||
const downFilledTriangle = require('../../../images/down-filled-triangle.svg');
|
const downFilledTriangle = require('../../../images/down-filled-triangle.svg');
|
||||||
const check = require('../../../images/check_encircled.svg');
|
|
||||||
const close = require('../../../images/close.svg');
|
|
||||||
|
|
||||||
const Icons = ({ inCollection }) => {
|
|
||||||
const classes = [
|
|
||||||
'sketch-list__icon',
|
|
||||||
inCollection ? 'sketch-list__icon--in-collection' : 'sketch-list__icon--not-in-collection'
|
|
||||||
].join(' ');
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classes}>
|
|
||||||
<InlineSVG className="sketch-list__remove-icon" src={close} alt="Remove from collection" />
|
|
||||||
<InlineSVG className="sketch-list__in-icon" src={check} alt="In collection" />
|
|
||||||
<InlineSVG className="sketch-list__add-icon" src={close} alt="Add to collection" />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Icons.propTypes = {
|
|
||||||
inCollection: PropTypes.bool.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
class SketchListRowBase extends React.Component {
|
class SketchListRowBase extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -51,7 +31,6 @@ class SketchListRowBase extends React.Component {
|
||||||
renameOpen: false,
|
renameOpen: false,
|
||||||
renameValue: props.sketch.name,
|
renameValue: props.sketch.name,
|
||||||
isFocused: false,
|
isFocused: false,
|
||||||
showPopover: false,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,18 +120,6 @@ class SketchListRowBase extends React.Component {
|
||||||
this.props.exportProjectAsZip(this.props.sketch.id);
|
this.props.exportProjectAsZip(this.props.sketch.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleShowCollectionPopover = () => {
|
|
||||||
this.setState({
|
|
||||||
showPopover: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleCloseCollectionPopover = () => {
|
|
||||||
this.setState({
|
|
||||||
showPopover: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSketchDuplicate = () => {
|
handleSketchDuplicate = () => {
|
||||||
this.closeAll();
|
this.closeAll();
|
||||||
this.props.cloneProject(this.props.sketch.id);
|
this.props.cloneProject(this.props.sketch.id);
|
||||||
|
@ -170,18 +137,6 @@ class SketchListRowBase extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleRowClick = (evt) => {
|
|
||||||
if (!this.props.addMode) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.props.inCollection) {
|
|
||||||
this.props.onCollectionRemove();
|
|
||||||
} else {
|
|
||||||
this.props.onCollectionAdd();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
renderViewButton = sketchURL => (
|
renderViewButton = sketchURL => (
|
||||||
<td className="sketch-list__dropdown-column">
|
<td className="sketch-list__dropdown-column">
|
||||||
<Link to={sketchURL}>View</Link>
|
<Link to={sketchURL}>View</Link>
|
||||||
|
@ -242,7 +197,10 @@ class SketchListRowBase extends React.Component {
|
||||||
<li>
|
<li>
|
||||||
<button
|
<button
|
||||||
className="sketch-list__action-option"
|
className="sketch-list__action-option"
|
||||||
onClick={this.handleShowCollectionPopover}
|
onClick={() => {
|
||||||
|
this.props.onAddToCollection();
|
||||||
|
this.closeAll();
|
||||||
|
}}
|
||||||
onBlur={this.onBlurComponent}
|
onBlur={this.onBlurComponent}
|
||||||
onFocus={this.onFocusComponent}
|
onFocus={this.onFocusComponent}
|
||||||
>
|
>
|
||||||
|
@ -271,24 +229,14 @@ class SketchListRowBase extends React.Component {
|
||||||
</button>
|
</button>
|
||||||
</li>}
|
</li>}
|
||||||
</ul>}
|
</ul>}
|
||||||
{this.state.showPopover &&
|
|
||||||
<CollectionPopover
|
|
||||||
onClose={this.handleCloseCollectionPopover}
|
|
||||||
project={this.props.sketch}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
</td>
|
</td>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderActions = sketchURL => (this.props.addMode === true ? this.renderViewButton(sketchURL) : this.renderDropdown())
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
sketch,
|
sketch,
|
||||||
username,
|
username,
|
||||||
addMode,
|
|
||||||
inCollection,
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { renameOpen, renameValue } = this.state;
|
const { renameOpen, renameValue } = this.state;
|
||||||
let url = `/${username}/sketches/${sketch.id}`;
|
let url = `/${username}/sketches/${sketch.id}`;
|
||||||
|
@ -296,53 +244,43 @@ class SketchListRowBase extends React.Component {
|
||||||
url = `/${username}/sketches/${slugify(sketch.name, '_')}`;
|
url = `/${username}/sketches/${slugify(sketch.name, '_')}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const name = addMode ?
|
const name = (
|
||||||
<span className="sketches-table__name">{sketch.name}</span>
|
<React.Fragment>
|
||||||
: (
|
<Link to={url}>
|
||||||
<React.Fragment>
|
{renameOpen ? '' : sketch.name}
|
||||||
<Link to={url}>
|
</Link>
|
||||||
{renameOpen ? '' : sketch.name}
|
{renameOpen
|
||||||
</Link>
|
&&
|
||||||
{renameOpen
|
<input
|
||||||
&&
|
value={renameValue}
|
||||||
<input
|
onChange={this.handleRenameChange}
|
||||||
value={renameValue}
|
onKeyUp={this.handleRenameEnter}
|
||||||
onChange={this.handleRenameChange}
|
onBlur={this.resetSketchName}
|
||||||
onKeyUp={this.handleRenameEnter}
|
onClick={e => e.stopPropagation()}
|
||||||
onBlur={this.resetSketchName}
|
/>
|
||||||
onClick={e => e.stopPropagation()}
|
}
|
||||||
/>
|
</React.Fragment>
|
||||||
}
|
);
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<tr
|
<tr
|
||||||
className={`sketches-table__row ${addMode ? 'sketches-table__row--is-add-mode' : ''}`}
|
className="sketches-table__row"
|
||||||
key={sketch.id}
|
key={sketch.id}
|
||||||
onClick={this.handleRowClick}
|
onClick={this.handleRowClick}
|
||||||
>
|
>
|
||||||
{
|
|
||||||
this.props.addMode &&
|
|
||||||
<td className="sketches-table__icon-cell">
|
|
||||||
<Icons inCollection={inCollection} />
|
|
||||||
</td>
|
|
||||||
}
|
|
||||||
<th scope="row">
|
<th scope="row">
|
||||||
{name}
|
{name}
|
||||||
</th>
|
</th>
|
||||||
{!this.props.addMode && <td>{format(new Date(sketch.createdAt), 'MMM D, YYYY h:mm A')}</td>}
|
<td>{format(new Date(sketch.createdAt), 'MMM D, YYYY h:mm A')}</td>
|
||||||
{!this.props.addMode && <td>{format(new Date(sketch.updatedAt), 'MMM D, YYYY h:mm A')}</td>}
|
<td>{format(new Date(sketch.updatedAt), 'MMM D, YYYY h:mm A')}</td>
|
||||||
{this.renderActions(url)}
|
{this.renderDropdown()}
|
||||||
</tr>
|
</tr>
|
||||||
</React.Fragment>);
|
</React.Fragment>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SketchListRowBase.propTypes = {
|
SketchListRowBase.propTypes = {
|
||||||
addMode: PropTypes.bool.isRequired,
|
|
||||||
inCollection: PropTypes.bool.isRequired,
|
|
||||||
sketch: PropTypes.shape({
|
sketch: PropTypes.shape({
|
||||||
id: PropTypes.string.isRequired,
|
id: PropTypes.string.isRequired,
|
||||||
name: PropTypes.string.isRequired
|
name: PropTypes.string.isRequired
|
||||||
|
@ -357,8 +295,7 @@ SketchListRowBase.propTypes = {
|
||||||
cloneProject: PropTypes.func.isRequired,
|
cloneProject: PropTypes.func.isRequired,
|
||||||
exportProjectAsZip: PropTypes.func.isRequired,
|
exportProjectAsZip: PropTypes.func.isRequired,
|
||||||
changeProjectName: PropTypes.func.isRequired,
|
changeProjectName: PropTypes.func.isRequired,
|
||||||
onCollectionAdd: PropTypes.func.isRequired,
|
onAddToCollection: PropTypes.func.isRequired,
|
||||||
onCollectionRemove: PropTypes.func.isRequired,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function mapDispatchToPropsSketchListRow(dispatch) {
|
function mapDispatchToPropsSketchListRow(dispatch) {
|
||||||
|
@ -435,14 +372,6 @@ 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 (
|
||||||
|
@ -454,16 +383,14 @@ class SketchList extends React.Component {
|
||||||
{this._renderEmptyTable()}
|
{this._renderEmptyTable()}
|
||||||
{this.hasSketches() &&
|
{this.hasSketches() &&
|
||||||
<table className="sketches-table" summary="table containing all saved projects">
|
<table className="sketches-table" summary="table containing all saved projects">
|
||||||
{!this.props.addMode &&
|
<thead>
|
||||||
<thead>
|
<tr>
|
||||||
<tr>
|
{this._renderFieldHeader('name', 'Sketch')}
|
||||||
{this._renderFieldHeader('name', 'Sketch')}
|
{this._renderFieldHeader('createdAt', 'Date Created')}
|
||||||
{this._renderFieldHeader('createdAt', 'Date Created')}
|
{this._renderFieldHeader('updatedAt', 'Date Updated')}
|
||||||
{this._renderFieldHeader('updatedAt', 'Date Updated')}
|
<th scope="col"></th>
|
||||||
<th scope="col"></th>
|
</tr>
|
||||||
</tr>
|
</thead>
|
||||||
</thead>
|
|
||||||
}
|
|
||||||
<tbody>
|
<tbody>
|
||||||
{this.props.sketches.map(sketch =>
|
{this.props.sketches.map(sketch =>
|
||||||
(<SketchListRow
|
(<SketchListRow
|
||||||
|
@ -471,14 +398,25 @@ 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}
|
onAddToCollection={() => {
|
||||||
onCollectionAdd={() => this.handleCollectionAdd(sketch.id)}
|
this.setState({ sketchToAddToCollection: sketch });
|
||||||
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>}
|
||||||
|
{
|
||||||
|
this.state.sketchToAddToCollection &&
|
||||||
|
<Overlay
|
||||||
|
title="Add to collection"
|
||||||
|
closeOverlay={() => this.setState({ sketchToAddToCollection: null })}
|
||||||
|
>
|
||||||
|
<AddToCollectionList
|
||||||
|
project={this.state.sketchToAddToCollection}
|
||||||
|
username={this.props.username}
|
||||||
|
user={this.props.user}
|
||||||
|
/>
|
||||||
|
</Overlay>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -513,13 +451,9 @@ SketchList.propTypes = {
|
||||||
field: PropTypes.string.isRequired,
|
field: PropTypes.string.isRequired,
|
||||||
direction: PropTypes.string.isRequired
|
direction: PropTypes.string.isRequired
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
addToCollection: PropTypes.func.isRequired,
|
|
||||||
removeFromCollection: PropTypes.func.isRequired,
|
|
||||||
addMode: PropTypes.bool,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
SketchList.defaultProps = {
|
SketchList.defaultProps = {
|
||||||
addMode: false,
|
|
||||||
username: undefined
|
username: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue