diff --git a/client/modules/User/components/Collection.jsx b/client/modules/User/components/Collection.jsx
index 3301dfbb5c..101ec7df7f 100644
--- a/client/modules/User/components/Collection.jsx
+++ b/client/modules/User/components/Collection.jsx
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import React, { useState, useRef, useEffect } from 'react';
+import React from 'react';
import { Helmet } from 'react-helmet';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
@@ -7,8 +7,6 @@ import { bindActionCreators } from 'redux';
import { useTranslation, withTranslation } from 'react-i18next';
import classNames from 'classnames';
-import Button from '../../../common/Button';
-import { DropdownArrowIcon } from '../../../common/icons';
import * as ProjectActions from '../../IDE/actions/project';
import * as ProjectsActions from '../../IDE/actions/projects';
import * as CollectionsActions from '../../IDE/actions/collections';
@@ -17,61 +15,12 @@ import * as SortingActions from '../../IDE/actions/sorting';
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 AddToCollectionSketchList from '../../IDE/components/AddToCollectionSketchList';
-import CopyableInput from '../../IDE/components/CopyableInput';
-import { SketchSearchbar } from '../../IDE/components/Searchbar';
import dates from '../../../utils/formatDate';
import ArrowUpIcon from '../../../images/sort-arrow-up.svg';
import ArrowDownIcon from '../../../images/sort-arrow-down.svg';
import RemoveIcon from '../../../images/close.svg';
-
-const ShareURL = ({ value }) => {
- const [showURL, setShowURL] = useState(false);
- const node = useRef();
- const { t } = useTranslation();
-
- const handleClickOutside = (e) => {
- if (node.current.contains(e.target)) {
- return;
- }
- setShowURL(false);
- };
-
- useEffect(() => {
- if (showURL) {
- document.addEventListener('mousedown', handleClickOutside);
- } else {
- document.removeEventListener('mousedown', handleClickOutside);
- }
-
- return () => {
- document.removeEventListener('mousedown', handleClickOutside);
- };
- }, [showURL]);
-
- return (
-
-
- {showURL && (
-
-
-
- )}
-
- );
-};
-
-ShareURL.propTypes = {
- value: PropTypes.string.isRequired
-};
+import CollectionMetadata from './CollectionMetadata';
const CollectionItemRowBase = ({
collection,
@@ -172,12 +121,6 @@ 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() {
@@ -195,10 +138,6 @@ class Collection extends React.Component {
: this.props.user.username;
}
- getCollectionName() {
- return this.props.collection.name;
- }
-
isOwner() {
let isOwner = false;
@@ -226,115 +165,6 @@ class Collection extends React.Component {
return null;
}
- _renderCollectionMetadata() {
- const { id, name, description, items, owner } = this.props.collection;
-
- const hostname = window.location.origin;
- const { username } = this.props;
-
- const baseURL = `${hostname}/${username}/collections/`;
-
- const handleEditCollectionName = (value) => {
- if (value === name) {
- return;
- }
-
- this.props.editCollection(id, { name: value });
- };
-
- const handleEditCollectionDescription = (value) => {
- if (value === description) {
- return;
- }
-
- this.props.editCollection(id, { description: value });
- };
-
- //
- // TODO: Implement UI for editing slug
- //
- // const handleEditCollectionSlug = (value) => {
- // if (value === slug) {
- // return;
- // }
- //
- // this.props.editCollection(id, { slug: value });
- // };
-
- return (
-
-
-
-
- {this.isOwner() ? (
- value !== ''}
- />
- ) : (
- name
- )}
-
-
-
- {this.isOwner() ? (
-
- ) : (
- description
- )}
-
-
-
- {this.props.t('Collection.By')}
-
- {owner.username}
-
-
-
-
- {this.props.t('Collection.NumSketches', { count: items.length })}
-
-
-
-
-
-
-
- {this.isOwner() && (
-
- )}
-
-
-
- );
- }
-
- showAddSketches() {
- this.setState({
- isAddingSketches: true
- });
- }
-
- hideAddSketches() {
- this.setState({
- isAddingSketches: false
- });
- }
-
_renderEmptyTable() {
if (this.hasCollection() && !this.hasCollectionItems()) {
return (
@@ -408,7 +238,6 @@ class Collection extends React.Component {
}
render() {
- const title = this.hasCollection() ? this.getCollectionName() : null;
const isOwner = this.isOwner();
return (
@@ -421,7 +250,7 @@ class Collection extends React.Component {
{this.getTitle()}
{this._renderLoader()}
- {this.hasCollection() && this._renderCollectionMetadata()}
+
{this._renderEmptyTable()}
@@ -461,19 +290,6 @@ class Collection extends React.Component {
)}
- {this.state.isAddingSketches && (
-
}
- closeOverlay={this.hideAddSketches}
- isFixedHeight
- >
-
-
- )}
@@ -483,6 +299,7 @@ class Collection extends React.Component {
}
Collection.propTypes = {
+ collectionId: PropTypes.string.isRequired,
user: PropTypes.shape({
username: PropTypes.string,
authenticated: PropTypes.bool.isRequired
@@ -501,7 +318,6 @@ Collection.propTypes = {
username: PropTypes.string,
loading: PropTypes.bool.isRequired,
toggleDirectionForField: PropTypes.func.isRequired,
- editCollection: PropTypes.func.isRequired,
resetSorting: PropTypes.func.isRequired,
sorting: PropTypes.shape({
field: PropTypes.string.isRequired,
diff --git a/client/modules/User/components/CollectionMetadata.jsx b/client/modules/User/components/CollectionMetadata.jsx
new file mode 100644
index 0000000000..4b1be7ff5f
--- /dev/null
+++ b/client/modules/User/components/CollectionMetadata.jsx
@@ -0,0 +1,126 @@
+import classNames from 'classnames';
+import PropTypes from 'prop-types';
+import React, { useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import { useDispatch, useSelector } from 'react-redux';
+import { Link } from 'react-router-dom';
+import Button from '../../../common/Button';
+import Overlay from '../../App/components/Overlay';
+import { editCollection } from '../../IDE/actions/collections';
+import AddToCollectionSketchList from '../../IDE/components/AddToCollectionSketchList';
+import EditableInput from '../../IDE/components/EditableInput';
+import { SketchSearchbar } from '../../IDE/components/Searchbar';
+import { getCollection } from '../../IDE/selectors/collections';
+import ShareURL from './CollectionShareButton';
+
+function CollectionMetadata({ collectionId }) {
+ const { t } = useTranslation();
+
+ const dispatch = useDispatch();
+
+ const collection = useSelector((state) => getCollection(state, collectionId));
+ const currentUsername = useSelector((state) => state.user.username);
+
+ const [isAddingSketches, setIsAddingSketches] = useState(false);
+
+ if (!collection) {
+ return null;
+ }
+
+ const { id, name, description, items, owner } = collection;
+ const { username } = owner;
+ const isOwner = !!currentUsername && currentUsername === username;
+
+ const hostname = window.location.origin;
+
+ const handleEditCollectionName = (value) => {
+ if (value === name) {
+ return;
+ }
+ dispatch(editCollection(id, { name: value }));
+ };
+
+ const handleEditCollectionDescription = (value) => {
+ if (value === description) {
+ return;
+ }
+ dispatch(editCollection(id, { description: value }));
+ };
+
+ // TODO: Implement UI for editing slug
+
+ return (
+
+ );
+}
+
+CollectionMetadata.propTypes = {
+ collectionId: PropTypes.string.isRequired
+};
+
+export default CollectionMetadata;
diff --git a/client/modules/User/components/CollectionShareButton.jsx b/client/modules/User/components/CollectionShareButton.jsx
new file mode 100644
index 0000000000..c4e0bba915
--- /dev/null
+++ b/client/modules/User/components/CollectionShareButton.jsx
@@ -0,0 +1,54 @@
+import PropTypes from 'prop-types';
+import React, { useEffect, useRef, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+
+import Button from '../../../common/Button';
+import { DropdownArrowIcon } from '../../../common/icons';
+import CopyableInput from '../../IDE/components/CopyableInput';
+
+const ShareURL = ({ value }) => {
+ const [showURL, setShowURL] = useState(false);
+ const node = useRef();
+ const { t } = useTranslation();
+
+ const handleClickOutside = (e) => {
+ if (node.current?.contains(e.target)) {
+ return;
+ }
+ setShowURL(false);
+ };
+
+ useEffect(() => {
+ if (showURL) {
+ document.addEventListener('mousedown', handleClickOutside);
+ } else {
+ document.removeEventListener('mousedown', handleClickOutside);
+ }
+
+ return () => {
+ document.removeEventListener('mousedown', handleClickOutside);
+ };
+ }, [showURL]);
+
+ return (
+
+
+ {showURL && (
+
+
+
+ )}
+
+ );
+};
+
+ShareURL.propTypes = {
+ value: PropTypes.string.isRequired
+};
+
+export default ShareURL;