Skip to content

Commit 0aadc8c

Browse files
authored
Merge pull request #2353 from lindapaiste/refactor/AddToCollectionList
Fix #2351 & cleanup `AddToCollectionList` component
2 parents 7e069ee + 6cc1177 commit 0aadc8c

File tree

4 files changed

+59
-168
lines changed

4 files changed

+59
-168
lines changed

client/modules/IDE/actions/collections.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { setToastText, showToast } from './toast';
66

77
const TOAST_DISPLAY_TIME_MS = 1500;
88

9-
// eslint-disable-next-line
109
export function getCollections(username) {
1110
return (dispatch) => {
1211
dispatch(startLoader());
@@ -16,8 +15,7 @@ export function getCollections(username) {
1615
} else {
1716
url = '/collections';
1817
}
19-
console.log(url);
20-
apiClient
18+
return apiClient
2119
.get(url)
2220
.then((response) => {
2321
dispatch({
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,19 @@
11
import PropTypes from 'prop-types';
2-
import React from 'react';
2+
import React, { useEffect, useState } from 'react';
33
import { Helmet } from 'react-helmet';
4-
import { connect } from 'react-redux';
5-
import { bindActionCreators } from 'redux';
6-
import { withTranslation } from 'react-i18next';
4+
import { useTranslation } from 'react-i18next';
5+
import { useDispatch, useSelector } from 'react-redux';
76
import styled from 'styled-components';
8-
import * as ProjectActions from '../actions/project';
9-
import * as ProjectsActions from '../actions/projects';
10-
import * as CollectionsActions from '../actions/collections';
11-
import * as ToastActions from '../actions/toast';
12-
import * as SortingActions from '../actions/sorting';
13-
import getSortedCollections from '../selectors/collections';
147
import Loader from '../../App/components/loader';
8+
import {
9+
addToCollection,
10+
getCollections,
11+
removeFromCollection
12+
} from '../actions/collections';
13+
import getSortedCollections from '../selectors/collections';
1514
import QuickAddList from './QuickAddList';
1615
import { remSize } from '../../../theme';
1716

18-
const projectInCollection = (project, collection) =>
19-
collection.items.find((item) => item.projectId === project.id) != null;
20-
2117
export const CollectionAddSketchWrapper = styled.div`
2218
width: ${remSize(600)};
2319
max-width: 100%;
@@ -31,166 +27,67 @@ export const QuickAddWrapper = styled.div`
3127
height: 100%;
3228
`;
3329

34-
class CollectionList extends React.Component {
35-
constructor(props) {
36-
super(props);
30+
const AddToCollectionList = ({ projectId }) => {
31+
const { t } = useTranslation();
3732

38-
if (props.projectId) {
39-
props.getProject(props.projectId);
40-
}
33+
const dispatch = useDispatch();
4134

42-
this.props.getCollections(this.props.user.username);
35+
const username = useSelector((state) => state.user.username);
4336

44-
this.state = {
45-
hasLoadedData: false
46-
};
47-
}
37+
const collections = useSelector(getSortedCollections);
4838

49-
componentDidUpdate(prevProps) {
50-
if (prevProps.loading === true && this.props.loading === false) {
51-
// eslint-disable-next-line react/no-did-update-set-state
52-
this.setState({
53-
hasLoadedData: true
54-
});
55-
}
56-
}
39+
// TODO: improve loading state
40+
const loading = useSelector((state) => state.loading);
41+
const [hasLoadedData, setHasLoadedData] = useState(false);
42+
const showLoader = loading && !hasLoadedData;
5743

58-
getTitle() {
59-
if (this.props.username === this.props.user.username) {
60-
return this.props.t('AddToCollectionList.Title');
61-
}
62-
return this.props.t('AddToCollectionList.AnothersTitle', {
63-
anotheruser: this.props.username
64-
});
65-
}
44+
useEffect(() => {
45+
dispatch(getCollections(username)).then(() => setHasLoadedData(true));
46+
}, [dispatch, username]);
6647

67-
handleCollectionAdd = (collection) => {
68-
this.props.addToCollection(collection.id, this.props.project.id);
48+
const handleCollectionAdd = (collection) => {
49+
dispatch(addToCollection(collection.id, projectId));
6950
};
7051

71-
handleCollectionRemove = (collection) => {
72-
this.props.removeFromCollection(collection.id, this.props.project.id);
52+
const handleCollectionRemove = (collection) => {
53+
dispatch(removeFromCollection(collection.id, projectId));
7354
};
7455

75-
render() {
76-
const { collections, project } = this.props;
77-
const hasCollections = collections.length > 0;
78-
const collectionWithSketchStatus = collections.map((collection) => ({
79-
...collection,
80-
url: `/${collection.owner.username}/collections/${collection.id}`,
81-
isAdded: projectInCollection(project, collection)
82-
}));
83-
84-
let content = null;
85-
86-
if (this.props.loading && !this.state.hasLoadedData) {
87-
content = <Loader />;
88-
} else if (hasCollections) {
89-
content = (
90-
<QuickAddList
91-
items={collectionWithSketchStatus}
92-
onAdd={this.handleCollectionAdd}
93-
onRemove={this.handleCollectionRemove}
94-
t={this.props.t}
95-
/>
96-
);
97-
} else {
98-
content = this.props.t('AddToCollectionList.Empty');
56+
const collectionWithSketchStatus = collections.map((collection) => ({
57+
...collection,
58+
url: `/${collection.owner.username}/collections/${collection.id}`,
59+
isAdded: collection.items.some((item) => item.projectId === projectId)
60+
}));
61+
62+
const getContent = () => {
63+
if (showLoader) {
64+
return <Loader />;
65+
} else if (collections.length === 0) {
66+
return t('AddToCollectionList.Empty');
9967
}
100-
10168
return (
102-
<CollectionAddSketchWrapper>
103-
<QuickAddWrapper>
104-
<Helmet>
105-
<title>{this.getTitle()}</title>
106-
</Helmet>
107-
{content}
108-
</QuickAddWrapper>
109-
</CollectionAddSketchWrapper>
69+
<QuickAddList
70+
items={collectionWithSketchStatus}
71+
onAdd={handleCollectionAdd}
72+
onRemove={handleCollectionRemove}
73+
/>
11074
);
111-
}
112-
}
113-
114-
const ProjectShape = PropTypes.shape({
115-
id: PropTypes.string.isRequired,
116-
name: PropTypes.string.isRequired,
117-
createdAt: PropTypes.string.isRequired,
118-
updatedAt: PropTypes.string.isRequired,
119-
user: PropTypes.shape({
120-
username: PropTypes.string.isRequired
121-
}).isRequired
122-
});
123-
124-
const ItemsShape = PropTypes.shape({
125-
createdAt: PropTypes.string.isRequired,
126-
updatedAt: PropTypes.string.isRequired,
127-
project: ProjectShape
128-
});
75+
};
12976

130-
CollectionList.propTypes = {
131-
user: PropTypes.shape({
132-
username: PropTypes.string,
133-
authenticated: PropTypes.bool.isRequired
134-
}).isRequired,
135-
projectId: PropTypes.string.isRequired,
136-
getCollections: PropTypes.func.isRequired,
137-
getProject: PropTypes.func.isRequired,
138-
addToCollection: PropTypes.func.isRequired,
139-
removeFromCollection: PropTypes.func.isRequired,
140-
collections: PropTypes.arrayOf(
141-
PropTypes.shape({
142-
id: PropTypes.string.isRequired,
143-
name: PropTypes.string.isRequired,
144-
description: PropTypes.string,
145-
createdAt: PropTypes.string.isRequired,
146-
updatedAt: PropTypes.string.isRequired,
147-
items: PropTypes.arrayOf(ItemsShape)
148-
})
149-
).isRequired,
150-
username: PropTypes.string,
151-
loading: PropTypes.bool.isRequired,
152-
project: PropTypes.shape({
153-
id: PropTypes.string,
154-
owner: PropTypes.shape({
155-
id: PropTypes.string
156-
})
157-
}),
158-
t: PropTypes.func.isRequired
77+
return (
78+
<CollectionAddSketchWrapper>
79+
<QuickAddWrapper>
80+
<Helmet>
81+
<title>{t('AddToCollectionList.Title')}</title>
82+
</Helmet>
83+
{getContent()}
84+
</QuickAddWrapper>
85+
</CollectionAddSketchWrapper>
86+
);
15987
};
16088

161-
CollectionList.defaultProps = {
162-
project: {
163-
id: undefined,
164-
owner: undefined
165-
},
166-
username: undefined
89+
AddToCollectionList.propTypes = {
90+
projectId: PropTypes.string.isRequired
16791
};
16892

169-
function mapStateToProps(state, ownProps) {
170-
return {
171-
user: state.user,
172-
collections: getSortedCollections(state),
173-
sorting: state.sorting,
174-
loading: state.loading,
175-
project: ownProps.project || state.project,
176-
projectId: ownProps && ownProps.params ? ownProps.prams.project_id : null
177-
};
178-
}
179-
180-
function mapDispatchToProps(dispatch) {
181-
return bindActionCreators(
182-
Object.assign(
183-
{},
184-
CollectionsActions,
185-
ProjectsActions,
186-
ProjectActions,
187-
ToastActions,
188-
SortingActions
189-
),
190-
dispatch
191-
);
192-
}
193-
194-
export default withTranslation()(
195-
connect(mapStateToProps, mapDispatchToProps)(CollectionList)
196-
);
93+
export default AddToCollectionList;

client/modules/IDE/components/IDEOverlays.jsx

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { useTranslation } from 'react-i18next';
33
import { useDispatch, useSelector } from 'react-redux';
4-
import { useLocation, useParams } from 'react-router-dom';
4+
import { useLocation } from 'react-router-dom';
55
import Overlay from '../../App/components/Overlay';
66
import {
77
closeKeyboardShortcutModal,
@@ -25,7 +25,6 @@ export default function IDEOverlays() {
2525
const { t } = useTranslation();
2626
const dispatch = useDispatch();
2727
const location = useLocation();
28-
const params = useParams();
2928

3029
const {
3130
modalIsVisible,
@@ -79,8 +78,7 @@ export default function IDEOverlays() {
7978
isFixedHeight
8079
>
8180
<AddToCollectionList
82-
projectId={params.project_id}
83-
username={params.username}
81+
projectId={this.state.sketchToAddToCollection.id}
8482
/>
8583
</Overlay>
8684
)}

client/modules/IDE/components/SketchList.jsx

+1-3
Original file line numberDiff line numberDiff line change
@@ -418,9 +418,7 @@ class SketchList extends React.Component {
418418
}
419419
>
420420
<AddToCollectionList
421-
project={this.state.sketchToAddToCollection}
422-
username={this.props.username}
423-
user={this.props.user}
421+
projectId={this.state.sketchToAddToCollection.id}
424422
/>
425423
</Overlay>
426424
)}

0 commit comments

Comments
 (0)