Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 38 additions & 85 deletions src/amo/components/Collection/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ import { connect } from 'react-redux';
import { compose } from 'redux';

import AddonsCard from 'amo/components/AddonsCard';
import CollectionDetails from 'amo/components/CollectionDetails';
import CollectionManager from 'amo/components/CollectionManager';
import NotFound from 'amo/components/ErrorPage/NotFound';
import Link from 'amo/components/Link';
import { isFeaturedCollection } from 'amo/components/Home';
import {
collectionEditUrl,
collectionUrl,
convertFiltersToQueryParams,
deleteCollectionAddonNotes,
deleteCollection,
Expand Down Expand Up @@ -40,12 +43,8 @@ import {
import { withFixedErrorHandler } from 'core/errorHandler';
import translate from 'core/i18n/translate';
import log from 'core/logger';
import { sanitizeHTML } from 'core/utils';
import Button from 'ui/components/Button';
import Card from 'ui/components/Card';
import ConfirmButton from 'ui/components/ConfirmButton';
import LoadingText from 'ui/components/LoadingText';
import MetadataCard from 'ui/components/MetadataCard';
import Select from 'ui/components/Select';
import type {
CollectionFilters,
Expand Down Expand Up @@ -86,6 +85,7 @@ type InternalProps = {|
username: string,
|},
router: ReactRouterType,
showEditButton: boolean,
|};

export type RemoveCollectionAddonFunc = (addonId: number) => void;
Expand Down Expand Up @@ -137,16 +137,29 @@ export class CollectionBase extends React.Component<InternalProps> {
};

onSortSelect = (event: SyntheticEvent<HTMLSelectElement>) => {
const { clientApp, editing, filters, lang, router } = this.props;
const {
collection,
clientApp,
editing,
filters,
lang,
params,
router,
} = this.props;

const collectionSort = event.currentTarget.value;
const newFilters = {
...filters,
collectionSort,
};

const urlParams = {
authorUsername: params.username,
collection,
collectionSlug: params.slug,
};
const pathname = `/${lang}/${clientApp}${
editing ? this.editUrl() : this.url()
editing ? collectionEditUrl(urlParams) : collectionUrl(urlParams)
}`;
router.push({
pathname,
Expand Down Expand Up @@ -248,43 +261,6 @@ export class CollectionBase extends React.Component<InternalProps> {
}
}

url() {
const { params } = this.props;

return `/collections/${params.username}/${params.slug}/`;
}

editUrl() {
return `${this.url()}edit/`;
}

editCollectionLink() {
const { _config, i18n, filters } = this.props;
const props = {};

if (_config.get('enableNewCollectionsUI')) {
// TODO: make this a real link when the form is ready for release.
// https://github.com/mozilla/addons-frontend/issues/4293
props.to = {
pathname: this.editUrl(),
query: convertFiltersToQueryParams(filters),
};
} else {
props.href = this.editUrl();
}

return (
<Button
className="Collection-edit-link"
buttonType="neutral"
puffy
{...props}
>
{i18n.gettext('Edit this collection')}
</Button>
);
}

removeAddon: RemoveCollectionAddonFunc = (addonId: number) => {
const { collection, dispatch, errorHandler, filters } = this.props;

Expand Down Expand Up @@ -362,8 +338,7 @@ export class CollectionBase extends React.Component<InternalProps> {
creating,
editing,
filters,
hasEditPermission,
i18n,
showEditButton,
} = this.props;

if (creating || editing) {
Expand All @@ -376,43 +351,13 @@ export class CollectionBase extends React.Component<InternalProps> {
);
}

/* eslint-disable react/no-danger */
return (
<React.Fragment>
<h1 className="Collection-title">
{collection ? collection.name : <LoadingText />}
</h1>
<p className="Collection-description">
{collection ? (
<span
dangerouslySetInnerHTML={sanitizeHTML(collection.description)}
/>
) : (
<LoadingText />
)}
</p>
<MetadataCard
metadata={[
{
content: collection ? collection.numberOfAddons : null,
title: i18n.gettext('Add-ons'),
},
{
content: collection ? collection.authorName : null,
title: i18n.gettext('Creator'),
},
{
content: collection
? i18n.moment(collection.lastUpdatedDate).format('ll')
: null,
title: i18n.gettext('Last updated'),
},
]}
/>
{hasEditPermission ? this.editCollectionLink() : null}
</React.Fragment>
<CollectionDetails
collection={collection}
filters={filters}
showEditButton={showEditButton}
/>
);
/* eslint-enable react/no-danger */
}

renderDeleteButton() {
Expand Down Expand Up @@ -474,7 +419,11 @@ export class CollectionBase extends React.Component<InternalProps> {
LinkComponent={Link}
count={collection.numberOfAddons}
currentPage={filters.page}
pathname={editing ? this.editUrl() : this.url()}
pathname={
editing
? collectionEditUrl({ collection })
: collectionUrl({ collection })
}
perPage={collection.pageSize}
queryParams={convertFiltersToQueryParams(filters)}
/>
Expand Down Expand Up @@ -592,15 +541,18 @@ export const mapStateToProps = (state: AppState, ownProps: InternalProps) => {
const isOwner =
collection && currentUser && collection.authorId === currentUser.id;
let hasEditPermission = false;
let showEditButton = false;

if (collection && currentUser) {
hasEditPermission =
isOwner ||
// User can edit mozilla collections, and it is a mozilla collection.
(collection.authorUsername === MOZILLA_COLLECTIONS_USERNAME &&
hasPermission(state, MOZILLA_COLLECTIONS_EDIT)) ||
// User can edit the featured theme collection, and it is the featured
// theme collection.
hasPermission(state, MOZILLA_COLLECTIONS_EDIT));
showEditButton =
hasEditPermission ||
// User can maintain the featured themes collection, and it is the featured
// themes collection.
(collection.authorUsername === MOZILLA_COLLECTIONS_USERNAME &&
collection.slug === FEATURED_THEMES_COLLECTION_SLUG &&
hasPermission(state, FEATURED_THEMES_COLLECTION_EDIT));
Expand All @@ -610,11 +562,12 @@ export const mapStateToProps = (state: AppState, ownProps: InternalProps) => {
clientApp: state.api.clientApp,
collection,
filters,
hasEditPermission,
isLoggedIn: !!currentUser,
isOwner,
lang: state.api.lang,
loading,
hasEditPermission,
showEditButton,
};
};

Expand Down
25 changes: 0 additions & 25 deletions src/amo/components/Collection/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,12 @@

.Collection {
@include page-padding();

.MetadataCard {
@include respond-to(large) {
margin-top: 12px;
}
}
}

.Collection-login {
display: flex;
}

.Collection-title {
@include font-light();

font-size: $font-size-l;
hyphens: auto;
word-wrap: break-word;
}

.Collection-description {
font-size: $font-size-s;
hyphens: auto;
word-wrap: break-word;
}

.Collection-detail,
.CollectionList-create {
.Card-contents {
Expand Down Expand Up @@ -95,11 +75,6 @@
}
}

.Collection-edit-link {
margin-top: $padding-page;
width: 100%;
}

.Collection-delete-button {
margin-top: 16px;

Expand Down
93 changes: 93 additions & 0 deletions src/amo/components/CollectionDetails/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/* @flow */
import * as React from 'react';
import { compose } from 'redux';

import {
collectionEditUrl,
convertFiltersToQueryParams,
} from 'amo/reducers/collections';
import translate from 'core/i18n/translate';
import { sanitizeHTML } from 'core/utils';
import Button from 'ui/components/Button';
import LoadingText from 'ui/components/LoadingText';
import MetadataCard from 'ui/components/MetadataCard';
import type {
CollectionFilters,
CollectionType,
} from 'amo/reducers/collections';
import type { I18nType } from 'core/types/i18n';

import './styles.scss';

export type Props = {|
collection: CollectionType | null,
filters: CollectionFilters,
showEditButton: boolean,
|};

type InternalProps = {|
...Props,
i18n: I18nType,
|};

export class CollectionDetailsBase extends React.Component<InternalProps> {
render() {
const { collection, filters, i18n, showEditButton } = this.props;

return (
<div className="CollectionDetails">
<h1 className="CollectionDetails-title">
{collection ? collection.name : <LoadingText />}
</h1>
<p className="CollectionDetails-description">
{collection ? (
<span
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={sanitizeHTML(collection.description)}
/>
) : (
<LoadingText />
)}
</p>
<MetadataCard
metadata={[
{
content: collection ? collection.numberOfAddons : null,
title: i18n.gettext('Add-ons'),
},
{
content: collection ? collection.authorName : null,
title: i18n.gettext('Creator'),
},
{
content: collection
? i18n.moment(collection.lastUpdatedDate).format('ll')
: null,
title: i18n.gettext('Last updated'),
},
]}
/>
{showEditButton &&
collection && (
<Button
className="CollectionDetails-edit-link"
buttonType="neutral"
puffy
to={{
pathname: collectionEditUrl({ collection }),
query: convertFiltersToQueryParams(filters),
}}
>
{i18n.gettext('Edit this collection')}
</Button>
)}
</div>
);
}
}

const CollectionDetails: React.ComponentType<Props> = compose(translate())(
CollectionDetailsBase,
);

export default CollectionDetails;
30 changes: 30 additions & 0 deletions src/amo/components/CollectionDetails/styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
@import '~amo/css/inc/vars';
@import '~core/css/inc/mixins';
@import '~ui/css/vars';

.CollectionDetails {
.MetadataCard {
@include respond-to(large) {
margin-top: 12px;
}
}
}

.CollectionDetails-title {
@include font-light();

font-size: $font-size-l;
hyphens: auto;
word-wrap: break-word;
}

.CollectionDetails-description {
font-size: $font-size-s;
hyphens: auto;
word-wrap: break-word;
}

.CollectionDetails-edit-link {
margin-top: $padding-page;
width: 100%;
}
Loading