Merge pull request #1480 from andrewn/bugfix/deleted-collection-sketch

Allow deleted sketches in collections to be removed (fixes #1465)
This commit is contained in:
Cassie Tarakajian 2020-07-06 13:09:42 -04:00 committed by GitHub
commit 5e0d5226e7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 55 additions and 29 deletions

View file

@ -71,41 +71,50 @@ ShareURL.propTypes = {
value: PropTypes.string.isRequired, value: PropTypes.string.isRequired,
}; };
class CollectionItemRowBase extends React.Component { const CollectionItemRowBase = ({
handleSketchRemove = () => { collection, item, isOwner, removeFromCollection
if (window.confirm(`Are you sure you want to remove "${this.props.item.project.name}" from this collection?`)) { }) => {
this.props.removeFromCollection(this.props.collection.id, this.props.item.project.id); const projectIsDeleted = item.isDeleted;
const handleSketchRemove = () => {
const name = projectIsDeleted ? 'deleted sketch' : item.project.name;
if (window.confirm(`Are you sure you want to remove "${name}" from this collection?`)) {
removeFromCollection(collection.id, item.projectId);
} }
} };
render() { const name = projectIsDeleted ? <span>Sketch was deleted</span> : (
const { item } = this.props; <Link to={`/${item.project.user.username}/sketches/${item.projectId}`}>
const sketchOwnerUsername = item.project.user.username; {item.project.name}
const sketchUrl = `/${item.project.user.username}/sketches/${item.project.id}`; </Link>
);
return ( const sketchOwnerUsername = projectIsDeleted ? null : item.project.user.username;
<tr
className="sketches-table__row" return (
> <tr
<th scope="row"> className={`sketches-table__row ${projectIsDeleted ? 'is-deleted' : ''}`}
<Link to={sketchUrl}> >
{item.project.name} <th scope="row">
</Link> {name}
</th> </th>
<td>{format(new Date(item.createdAt), 'MMM D, YYYY h:mm A')}</td> <td>{format(new Date(item.createdAt), 'MMM D, YYYY h:mm A')}</td>
<td>{sketchOwnerUsername}</td> <td>{sketchOwnerUsername}</td>
<td className="collection-row__action-column "> <td className="collection-row__action-column ">
{isOwner &&
<button <button
className="collection-row__remove-button" className="collection-row__remove-button"
onClick={this.handleSketchRemove} onClick={handleSketchRemove}
aria-label="Remove sketch from collection" aria-label="Remove sketch from collection"
> >
<RemoveIcon focusable="false" aria-hidden="true" /> <RemoveIcon focusable="false" aria-hidden="true" />
</button> </button>
</td> }
</tr>); </td>
} </tr>);
} };
CollectionItemRowBase.propTypes = { CollectionItemRowBase.propTypes = {
collection: PropTypes.shape({ collection: PropTypes.shape({
@ -114,14 +123,17 @@ CollectionItemRowBase.propTypes = {
}).isRequired, }).isRequired,
item: PropTypes.shape({ item: PropTypes.shape({
createdAt: PropTypes.string.isRequired, createdAt: PropTypes.string.isRequired,
projectId: PropTypes.string.isRequired,
isDeleted: PropTypes.bool.isRequired,
project: PropTypes.shape({ project: PropTypes.shape({
id: PropTypes.string.isRequired, id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
user: PropTypes.shape({ user: PropTypes.shape({
username: PropTypes.string.isRequired username: PropTypes.string.isRequired
}) }),
}).isRequired, }).isRequired,
}).isRequired, }).isRequired,
isOwner: PropTypes.bool.isRequired,
user: PropTypes.shape({ user: PropTypes.shape({
username: PropTypes.string, username: PropTypes.string,
authenticated: PropTypes.bool.isRequired authenticated: PropTypes.bool.isRequired
@ -342,6 +354,7 @@ class Collection extends React.Component {
render() { render() {
const title = this.hasCollection() ? this.getCollectionName() : null; const title = this.hasCollection() ? this.getCollectionName() : null;
const isOwner = this.isOwner();
return ( return (
<main className="collection-container" data-has-items={this.hasCollectionItems() ? 'true' : 'false'}> <main className="collection-container" data-has-items={this.hasCollectionItems() ? 'true' : 'false'}>
@ -372,6 +385,7 @@ class Collection extends React.Component {
user={this.props.user} user={this.props.user}
username={this.getUsername()} username={this.getUsername()}
collection={this.props.collection} collection={this.props.collection}
isOwner={isOwner}
/>))} />))}
</tbody> </tbody>
</table> </table>

View file

@ -85,6 +85,10 @@
} }
} }
.sketches-table__row.is-deleted > * {
font-style: italic;
}
.sketches-table thead { .sketches-table thead {
font-size: #{12 / $base-font-size}rem; font-size: #{12 / $base-font-size}rem;
@include themify() { @include themify() {

View file

@ -32,7 +32,7 @@ export default function addProjectToCollection(req, res) {
return null; return null;
} }
const projectInCollection = collection.items.find(p => p.project._id === project._id); const projectInCollection = collection.items.find(p => p.projectId === project._id);
if (projectInCollection) { if (projectInCollection) {
sendFailure(404, 'Project already in collection'); sendFailure(404, 'Project already in collection');

View file

@ -23,7 +23,7 @@ export default function addProjectToCollection(req, res) {
return null; return null;
} }
const project = collection.items.find(p => p.project._id === projectId); const project = collection.items.find(p => p.projectId === projectId);
if (project != null) { if (project != null) {
project.remove(); project.remove();

View file

@ -15,6 +15,14 @@ collectedProjectSchema.virtual('id').get(function getId() {
return this._id.toHexString(); return this._id.toHexString();
}); });
collectedProjectSchema.virtual('projectId').get(function projectId() {
return this.populated('project');
});
collectedProjectSchema.virtual('isDeleted').get(function isDeleted() {
return this.project == null;
});
collectedProjectSchema.set('toJSON', { collectedProjectSchema.set('toJSON', {
virtuals: true virtuals: true
}); });