WIP Display collection
This commit is contained in:
parent
1c97152533
commit
2df3670dc4
9 changed files with 117 additions and 70 deletions
|
@ -187,7 +187,7 @@ class CollectionListRowBase extends React.Component {
|
||||||
key={collection.id}
|
key={collection.id}
|
||||||
>
|
>
|
||||||
<th scope="row">
|
<th scope="row">
|
||||||
<Link to={`/${username}/collections/${collection.id}`}>
|
<Link to={{ pathname: `/${username}/collections/${collection.id}`, state: { skipSavingPath: true } }}>
|
||||||
{renameOpen ? '' : collection.name}
|
{renameOpen ? '' : collection.name}
|
||||||
</Link>
|
</Link>
|
||||||
{renameOpen
|
{renameOpen
|
||||||
|
|
|
@ -7,15 +7,14 @@ import { connect } from 'react-redux';
|
||||||
import { Link } from 'react-router';
|
import { Link } from 'react-router';
|
||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import * as ProjectActions from '../actions/project';
|
import * as ProjectActions from '../../IDE/actions/project';
|
||||||
import * as ProjectsActions from '../actions/projects';
|
import * as ProjectsActions from '../../IDE/actions/projects';
|
||||||
import * as CollectionsActions from '../actions/collections';
|
import * as CollectionsActions from '../../IDE/actions/collections';
|
||||||
import * as ToastActions from '../actions/toast';
|
import * as ToastActions from '../../IDE/actions/toast';
|
||||||
import * as SortingActions from '../actions/sorting';
|
import * as SortingActions from '../../IDE/actions/sorting';
|
||||||
import * as IdeActions from '../actions/ide';
|
import * as IdeActions from '../../IDE/actions/ide';
|
||||||
import { getCollection } from '../selectors/collections';
|
import { getCollection } from '../../IDE/selectors/collections';
|
||||||
import Loader from '../../App/components/loader';
|
import Loader from '../../App/components/loader';
|
||||||
import Overlay from '../../App/components/Overlay';
|
|
||||||
|
|
||||||
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');
|
||||||
|
@ -259,9 +258,13 @@ class Collection extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderCollectionMetadata() {
|
_renderCollectionMetadata() {
|
||||||
|
const { name, description, items, owner } = this.props.collection;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="collections-metadata">
|
<div className="collection-metadata">
|
||||||
<p>{this.props.collection.description}</p>
|
<h2 className="collection-metadata__name">{name}</h2>
|
||||||
|
<p className="collection-metadata__user">{items.length} sketches collected by {owner.username}</p>
|
||||||
|
<p className="collection-metadata__description">{description}</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -299,15 +302,11 @@ class Collection extends React.Component {
|
||||||
const title = this.hasCollection() ? this.getCollectionName() : null;
|
const title = this.hasCollection() ? this.getCollectionName() : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Overlay
|
<section className="collection-container">
|
||||||
ariaLabel="collection"
|
<Helmet>
|
||||||
title={title}
|
<title>{this.getTitle()}</title>
|
||||||
previousPath={this.props.previousPath}
|
</Helmet>
|
||||||
>
|
<div className="">
|
||||||
<div className="sketches-table-container">
|
|
||||||
<Helmet>
|
|
||||||
<title>{this.getTitle()}</title>
|
|
||||||
</Helmet>
|
|
||||||
{this._renderLoader()}
|
{this._renderLoader()}
|
||||||
{this.hasCollection() && this._renderCollectionMetadata()}
|
{this.hasCollection() && this._renderCollectionMetadata()}
|
||||||
{this._renderEmptyTable()}
|
{this._renderEmptyTable()}
|
||||||
|
@ -332,7 +331,7 @@ class Collection extends React.Component {
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>}
|
</table>}
|
||||||
</div>
|
</div>
|
||||||
</Overlay>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -343,7 +342,10 @@ Collection.propTypes = {
|
||||||
authenticated: PropTypes.bool.isRequired
|
authenticated: PropTypes.bool.isRequired
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
getCollections: PropTypes.func.isRequired,
|
getCollections: PropTypes.func.isRequired,
|
||||||
collection: PropTypes.shape({}).isRequired, // TODO
|
collection: PropTypes.shape({
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
description: PropTypes.string,
|
||||||
|
}).isRequired,
|
||||||
username: PropTypes.string,
|
username: PropTypes.string,
|
||||||
loading: PropTypes.bool.isRequired,
|
loading: PropTypes.bool.isRequired,
|
||||||
toggleDirectionForField: PropTypes.func.isRequired,
|
toggleDirectionForField: PropTypes.func.isRequired,
|
||||||
|
|
|
@ -41,7 +41,10 @@ class CollectionCreate extends React.Component {
|
||||||
|
|
||||||
this.props.createCollection(this.state.collection)
|
this.props.createCollection(this.state.collection)
|
||||||
.then(({ id, owner }) => {
|
.then(({ id, owner }) => {
|
||||||
browserHistory.replace(`/${owner.username}/collections/${id}`);
|
const pathname = `/${owner.username}/collections/${id}`;
|
||||||
|
const location = { pathname, state: { skipSavingPath: true } };
|
||||||
|
|
||||||
|
browserHistory.replace(location);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error('Error creating collection', error);
|
console.error('Error creating collection', error);
|
||||||
|
@ -58,42 +61,49 @@ class CollectionCreate extends React.Component {
|
||||||
const invalid = name === '' || name == null;
|
const invalid = name === '' || name == null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="sketches-table-container">
|
<section className="dashboard-header">
|
||||||
<Helmet>
|
<Helmet>
|
||||||
<title>{this.getTitle()}</title>
|
<title>{this.getTitle()}</title>
|
||||||
</Helmet>
|
</Helmet>
|
||||||
|
|
||||||
<form className="form" onSubmit={this.handleCreateCollection}>
|
<div className="dashboard-header__header">
|
||||||
{creationError && <span className="form-error">Couldn't create collection</span>}
|
<h2 className="dashboard-header__header__title">Create collection</h2>
|
||||||
<p className="form__field">
|
</div>
|
||||||
<label htmlFor="name" className="form__label">Collection name</label>
|
<div className="dashboard-content">
|
||||||
<input
|
<div className="sketches-table-container">
|
||||||
className="form__input"
|
<form className="form" onSubmit={this.handleCreateCollection}>
|
||||||
aria-label="name"
|
{creationError && <span className="form-error">Couldn't create collection</span>}
|
||||||
type="text"
|
<p className="form__field">
|
||||||
id="name"
|
<label htmlFor="name" className="form__label">Collection name</label>
|
||||||
value={name}
|
<input
|
||||||
placeholder={generatedCollectionName}
|
className="form__input"
|
||||||
onChange={this.handleTextChange('name')}
|
aria-label="name"
|
||||||
/>
|
type="text"
|
||||||
{invalid && <span className="form-error">Collection name is required</span>}
|
id="name"
|
||||||
</p>
|
value={name}
|
||||||
<p className="form__field">
|
placeholder={generatedCollectionName}
|
||||||
<label htmlFor="description" className="form__label">Description (optional)</label>
|
onChange={this.handleTextChange('name')}
|
||||||
<textarea
|
/>
|
||||||
className="form__input form__input-flexible-height"
|
{invalid && <span className="form-error">Collection name is required</span>}
|
||||||
aria-label="description"
|
</p>
|
||||||
type="text"
|
<p className="form__field">
|
||||||
id="description"
|
<label htmlFor="description" className="form__label">Description (optional)</label>
|
||||||
value={description}
|
<textarea
|
||||||
onChange={this.handleTextChange('description')}
|
className="form__input form__input-flexible-height"
|
||||||
placeholder="My fave sketches"
|
aria-label="description"
|
||||||
rows="4"
|
type="text"
|
||||||
/>
|
id="description"
|
||||||
</p>
|
value={description}
|
||||||
<input type="submit" disabled={invalid} value="Create collection" aria-label="create collection" />
|
onChange={this.handleTextChange('description')}
|
||||||
</form>
|
placeholder="My fave sketches"
|
||||||
</div>
|
rows="4"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<input type="submit" disabled={invalid} value="Create collection" aria-label="create collection" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { updateSettings, initiateVerification, createApiKey, removeApiKey } from
|
||||||
import NavBasic from '../../../components/NavBasic';
|
import NavBasic from '../../../components/NavBasic';
|
||||||
|
|
||||||
import CollectionCreate from '../components/CollectionCreate';
|
import CollectionCreate from '../components/CollectionCreate';
|
||||||
|
import Collection from '../components/Collection';
|
||||||
|
|
||||||
class CollectionView extends React.Component {
|
class CollectionView extends React.Component {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
|
@ -61,7 +62,12 @@ class CollectionView extends React.Component {
|
||||||
return <CollectionCreate />;
|
return <CollectionCreate />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'collection page';
|
return (
|
||||||
|
<Collection
|
||||||
|
collectionId={this.props.params.collection_id}
|
||||||
|
username={this.props.params.username}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -69,15 +75,7 @@ class CollectionView extends React.Component {
|
||||||
<div className="dashboard">
|
<div className="dashboard">
|
||||||
<NavBasic onBack={this.closeAccountPage} />
|
<NavBasic onBack={this.closeAccountPage} />
|
||||||
|
|
||||||
<section className="dashboard-header">
|
{this.renderContent()}
|
||||||
<div className="dashboard-header__header">
|
|
||||||
<h2 className="dashboard-header__header__title">{this.pageTitle()}</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="dashboard-content">
|
|
||||||
{this.renderContent()}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -102,6 +100,7 @@ CollectionView.propTypes = {
|
||||||
pathname: PropTypes.string.isRequired,
|
pathname: PropTypes.string.isRequired,
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
params: PropTypes.shape({
|
params: PropTypes.shape({
|
||||||
|
collection_id: PropTypes.string.isRequired,
|
||||||
username: PropTypes.string.isRequired,
|
username: PropTypes.string.isRequired,
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
previousPath: PropTypes.string.isRequired,
|
previousPath: PropTypes.string.isRequired,
|
||||||
|
|
|
@ -45,7 +45,7 @@ const routes = store => (
|
||||||
<Route path="/:username/sketches" component={IDEView} />
|
<Route path="/:username/sketches" component={IDEView} />
|
||||||
<Route path="/:username/collections" component={DashboardView} />
|
<Route path="/:username/collections" component={DashboardView} />
|
||||||
<Route path="/:username/collections/create" component={CollectionView} />
|
<Route path="/:username/collections/create" component={CollectionView} />
|
||||||
<Route path="/:username/collections/:collection_id" component={DashboardView} />
|
<Route path="/:username/collections/:collection_id" component={CollectionView} />
|
||||||
<Route path="/about" component={IDEView} />
|
<Route path="/about" component={IDEView} />
|
||||||
<Route path="/feedback" component={IDEView} />
|
<Route path="/feedback" component={IDEView} />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
21
client/styles/components/_collection.scss
Normal file
21
client/styles/components/_collection.scss
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
.collection-container {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.collection-metadata {
|
||||||
|
margin: 0px #{56 / $base-font-size}rem;
|
||||||
|
padding: #{24 / $base-font-size}rem #{10 / $base-font-size}rem;
|
||||||
|
|
||||||
|
@include themify() {
|
||||||
|
background-color: getThemifyVariable('modal-background-color');
|
||||||
|
border-bottom: 1px dotted getThemifyVariable('modal-border-color');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.collection-metadata__user {
|
||||||
|
padding-top: #{12 / $base-font-size}rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collection-metadata__description {
|
||||||
|
padding-top: #{24 / $base-font-size}rem;
|
||||||
|
}
|
|
@ -2,6 +2,10 @@
|
||||||
padding: 24px 66px;
|
padding: 24px 66px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dashboard-header--no-vertical-padding {
|
||||||
|
padding: 0 66px;
|
||||||
|
}
|
||||||
|
|
||||||
.dashboard-header__tabs {
|
.dashboard-header__tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding-top: #{24 / $base-font-size}rem;
|
padding-top: #{24 / $base-font-size}rem;
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
@import 'components/tabs';
|
@import 'components/tabs';
|
||||||
@import 'components/dashboard-header';
|
@import 'components/dashboard-header';
|
||||||
@import 'components/editable-input';
|
@import 'components/editable-input';
|
||||||
|
@import 'components/collection';
|
||||||
|
|
||||||
@import 'layout/dashboard';
|
@import 'layout/dashboard';
|
||||||
@import 'layout/ide';
|
@import 'layout/ide';
|
||||||
|
|
|
@ -112,10 +112,14 @@ router.get('/:username/sketches', (req, res) => {
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/:username/collections', (req, res) => {
|
router.get('/:username/collections/create', (req, res) => {
|
||||||
userExists(req.params.username, exists => (
|
userExists(req.params.username, (exists) => {
|
||||||
exists ? res.send(renderIndex()) : get404Sketch(html => res.send(html))
|
const isLoggedInUser = req.user && req.user.username === req.params.username;
|
||||||
));
|
const canAccess = exists && isLoggedInUser;
|
||||||
|
return canAccess ?
|
||||||
|
res.send(renderIndex()) :
|
||||||
|
get404Sketch(html => res.send(html));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/:username/collections/create', (req, res) => {
|
router.get('/:username/collections/create', (req, res) => {
|
||||||
|
@ -136,4 +140,10 @@ router.get('/:username/collections/:id', (req, res) => {
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get('/:username/collections', (req, res) => {
|
||||||
|
userExists(req.params.username, exists => (
|
||||||
|
exists ? res.send(renderIndex()) : get404Sketch(html => res.send(html))
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|
Loading…
Reference in a new issue