Skip to content

Commit

Permalink
Consolidate add-on detail views before converting it to saga (#2520)
Browse files Browse the repository at this point in the history
  • Loading branch information
kumar303 committed Jun 6, 2017
1 parent 8e8e983 commit 0a0e650
Show file tree
Hide file tree
Showing 18 changed files with 362 additions and 311 deletions.
1 change: 1 addition & 0 deletions .ackrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# that make searching the addons-frontend code a bit easier.

--ignore-dir=coverage
--ignore-dir=flow/logs
--ignore-dir=dist
--ignore-dir=locale
--ignore-dir=node_modules
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ Alternatively, you can start the test runner with a
[specific file or regular expression](https://facebook.github.io/jest/docs/en/cli.html#jest-regexfortestfiles),
like:
```
yarn test tests/unit/amo/components/TestAddonDetail.js
yarn test tests/unit/amo/components/TestAddon.js
```

#### Run all tests
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,25 @@ import AddonMoreInfo from 'amo/components/AddonMoreInfo';
import DefaultRatingManager from 'amo/components/RatingManager';
import ScreenShots from 'amo/components/ScreenShots';
import Link from 'amo/components/Link';
import 'amo/css/AddonDetail.scss';
import fallbackIcon from 'amo/img/icons/default-64.png';
import InstallButton from 'core/components/InstallButton';
import { ADDON_TYPE_THEME, ENABLED } from 'core/constants';
import { ADDON_TYPE_THEME, ENABLED, UNKNOWN } from 'core/constants';
import { withInstallHelpers } from 'core/installAddon';
import {
isAllowedOrigin,
getClientCompatibility as _getClientCompatibility,
loadAddonIfNeeded,
nl2br,
safeAsyncConnect,
sanitizeHTML,
} from 'core/utils';
import translate from 'core/i18n/translate';
import Card from 'ui/components/Card';
import Icon from 'ui/components/Icon';
import ShowMoreCard from 'ui/components/ShowMoreCard';

import './styles.scss';


export const allowedDescriptionTags = [
'a',
Expand All @@ -43,7 +46,7 @@ export const allowedDescriptionTags = [
'ul',
];

export class AddonDetailBase extends React.Component {
export class AddonBase extends React.Component {
static propTypes = {
RatingManager: PropTypes.element,
addon: PropTypes.object.isRequired,
Expand All @@ -55,7 +58,7 @@ export class AddonDetailBase extends React.Component {
location: PropTypes.object.isRequired,
resetThemePreview: PropTypes.func.isRequired,
themePreviewNode: PropTypes.element,
status: PropTypes.string.isRequired,
installStatus: PropTypes.string.isRequired,
toggleThemePreview: PropTypes.func.isRequired,
userAgentInfo: PropTypes.object.isRequired,
}
Expand All @@ -82,39 +85,39 @@ export class AddonDetailBase extends React.Component {
getBrowserThemeData,
i18n,
isPreviewingTheme,
status,
installStatus,
} = this.props;
const { previewURL, type } = addon;
const iconUrl = isAllowedOrigin(addon.icon_url) ? addon.icon_url :
fallbackIcon;

if (type === ADDON_TYPE_THEME) {
const label = isPreviewingTheme ? i18n.gettext('Cancel preview') : i18n.gettext('Tap to preview');
const imageClassName = 'AddonDetail-theme-header-image';
const imageClassName = 'Addon-theme-header-image';
const headerImage = <img alt={label} className={imageClassName} src={previewURL} />;

return (
<div
className="AddonDetail-theme-header"
id="AddonDetail-theme-header"
className="Addon-theme-header"
id="Addon-theme-header"
data-browsertheme={getBrowserThemeData()}
ref={(el) => { this.wrapper = el; }}
onClick={this.onClick}
>
{status !== ENABLED ?
{installStatus !== ENABLED ?
<button
disabled={!compatible}
className="Button AddonDetail-theme-header-label"
htmlFor="AddonDetail-theme-header">
<Icon name="eye" className="AddonDetail-theme-preview-icon" />
className="Button Addon-theme-header-label"
htmlFor="Addon-theme-header">
<Icon name="eye" className="Addon-theme-preview-icon" />
{label}
</button> : null}
{headerImage}
</div>
);
}
return (
<div className="AddonDetail-icon">
<div className="Addon-icon">
<img alt="" src={iconUrl} />
</div>
);
Expand All @@ -134,7 +137,7 @@ export class AddonDetailBase extends React.Component {

footerPropName = 'footerLink';
content = (
<Link className="AddonDetail-all-reviews-link"
<Link className="Addon-all-reviews-link"
to={`/addon/${addon.slug}/reviews/`}>
{linkText}
</Link>
Expand All @@ -146,12 +149,12 @@ export class AddonDetailBase extends React.Component {

const props = {
[footerPropName]: (
<div className="AddonDetail-read-reviews-footer">{content}</div>),
<div className="Addon-read-reviews-footer">{content}</div>),
};
return (
<Card
header={i18n.gettext('Rate your experience')}
className="AddonDetail-overall-rating"
className="Addon-overall-rating"
{...props}>
<RatingManager
addon={addon}
Expand Down Expand Up @@ -182,7 +185,7 @@ export class AddonDetailBase extends React.Component {
i18n.gettext('%(addonName)s %(startSpan)sby %(authorList)s%(endSpan)s'), {
addonName: addon.name,
authorList: authorList.join(', '),
startSpan: '<span class="AddonDetail-author">',
startSpan: '<span class="Addon-author">',
endSpan: '</span>',
});

Expand All @@ -192,19 +195,19 @@ export class AddonDetailBase extends React.Component {

// eslint-disable react/no-danger
return (
<div className="AddonDetail">
<header className="AddonDetail-header">
<div className="Addon">
<header className="Addon-header">
{this.headerImage({ compatible })}
<div className="AddonDetail-title">
<div className="Addon-title">
<h1
dangerouslySetInnerHTML={sanitizeHTML(title, ['a', 'span'])}
className="AddonDetail-title-heading" />
className="Addon-title-heading" />
</div>
<p className="AddonDetail-summary"
<p className="Addon-summary"
dangerouslySetInnerHTML={summarySanitized} />
</header>

<section className="AddonDetail-metadata">
<section className="Addon-metadata">
<h2 className="visually-hidden">
{i18n.gettext('Extension Metadata')}
</h2>
Expand All @@ -218,7 +221,7 @@ export class AddonDetailBase extends React.Component {

{addon.previews.length > 0
? (
<Card className="AddonDetail-screenshots">
<Card className="Addon-screenshots">
<ScreenShots previews={addon.previews} />
</Card>
) : null}
Expand All @@ -240,15 +243,25 @@ export class AddonDetailBase extends React.Component {
}
}

export function mapStateToProps(state) {
export function mapStateToProps(state, ownProps) {
const { slug } = ownProps.params;
const addon = state.addons[slug];
const installation = state.installations[addon.guid];

return {
addon,
installStatus: installation ? installation.status : UNKNOWN,
clientApp: state.api.clientApp,
userAgentInfo: state.api.userAgentInfo,
};
}

export default compose(
safeAsyncConnect([{
key: 'Addon',
promise: loadAddonIfNeeded,
}]),
translate({ withRef: true }),
withInstallHelpers({ src: 'dp-btn-primary' }),
connect(mapStateToProps),
)(AddonDetailBase);
)(AddonBase);
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@
$page-margin: 20px 10px;

// Put the margin on the immediate children so that the header can be full width and blue.
.AddonDetail > * {
.Addon > * {
margin: $page-margin;
}

.AddonDetail-title {
.Addon-title {
margin-top: 10px;
}

.AddonDetail-title-heading {
.Addon-title-heading {
font-size: $font-size-l;
margin-bottom: 10px;
word-wrap: break-word;
}

.AddonDetail-author {
.Addon-author {
display: block;
opacity: 0.75;
word-wrap: break-word;
Expand All @@ -32,7 +32,7 @@ $page-margin: 20px 10px;
}
}

.AddonDetail-summary {
.Addon-summary {
margin-bottom: 0;
margin-top: 0;

Expand All @@ -42,7 +42,7 @@ $page-margin: 20px 10px;
}
}

.AddonDetail-header {
.Addon-header {
background: $masthead-color;
color: $header-font-color;
margin: 0;
Expand All @@ -54,7 +54,7 @@ $page-margin: 20px 10px;
}
}

.AddonDetail-metadata {
.Addon-metadata {
align-items: center;
background-color: $masthead-light-color;
color: #fff;
Expand All @@ -70,12 +70,12 @@ $page-margin: 20px 10px;
}
}

.AddonDetail-theme-header {
.Addon-theme-header {
line-height: 0;
position: relative;
}

.AddonDetail-theme-header-image {
.Addon-theme-header-image {
border-radius: 12px;
object-fit: cover;
object-position: top right;
Expand All @@ -84,7 +84,7 @@ $page-margin: 20px 10px;
width: 100%;
}

.AddonDetail-theme-header-label {
.Addon-theme-header-label {
$label-margin: 12px;

@include start($label-margin);
Expand All @@ -100,13 +100,13 @@ $page-margin: 20px 10px;
user-select: none;
}

.AddonDetail-theme-preview-icon {
.Addon-theme-preview-icon {
@include margin-end(8px);

vertical-align: top;
}

.AddonDetail-icon {
.Addon-icon {
align-items: center;
display: flex;
flex-direction: row;
Expand Down
5 changes: 3 additions & 2 deletions src/amo/containers/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import { addChangeListeners } from 'core/addonManager';
import {
logOutUser as logOutUserAction, setUserAgent as setUserAgentAction,
} from 'core/actions';
import { INSTALL_STATE, maximumSetTimeoutDelay } from 'core/constants';
import { setInstallState } from 'core/actions/installations';
import { maximumSetTimeoutDelay } from 'core/constants';
import DefaultErrorPage from 'core/components/ErrorPage';
import InfoDialog from 'core/containers/InfoDialog';
import translate from 'core/i18n/translate';
Expand Down Expand Up @@ -227,7 +228,7 @@ export function mapDispatchToProps(dispatch: DispatchFunc) {
dispatch(logOutUserAction());
},
handleGlobalEvent(payload: InstalledAddon) {
dispatch({ type: INSTALL_STATE, payload });
dispatch(setInstallState(payload));
},
setUserAgent(userAgent: string) {
dispatch(setUserAgentAction(userAgent));
Expand Down
37 changes: 0 additions & 37 deletions src/amo/containers/DetailPage.js

This file was deleted.

4 changes: 2 additions & 2 deletions src/amo/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import CategoryPage from './containers/CategoryPage';
import FeaturedAddons from './components/FeaturedAddons';
import LandingPage from './components/LandingPage';
import Home from './containers/Home';
import DetailPage from './containers/DetailPage';
import Addon from './components/Addon';
import NotAuthorized from './components/ErrorPage/NotAuthorized';
import NotFound from './components/ErrorPage/NotFound';
import SearchPage from './containers/SearchPage';
Expand All @@ -30,7 +30,7 @@ import ServerError from './components/ErrorPage/ServerError';
export default (
<Route path="/:lang/:application" component={App}>
<IndexRoute component={Home} />
<Route path="addon/:slug/" component={DetailPage} />
<Route path="addon/:slug/" component={Addon} />
<Route path="addon/:addonSlug/reviews/" component={AddonReviewList} />
<Route path=":visibleAddonType/categories/" component={Categories} />
<Route path=":visibleAddonType/featured/" component={FeaturedAddons} />
Expand Down
15 changes: 15 additions & 0 deletions src/core/actions/installations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* @flow */
/* global Node */
import { INSTALL_STATE } from 'core/constants';
import type {
InstalledAddon, InstallationAction,
} from 'core/reducers/installations';

export function setInstallState(
installation: InstalledAddon,
): InstallationAction {
return {
type: INSTALL_STATE,
payload: installation,
};
}

0 comments on commit 0a0e650

Please sign in to comment.