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
14 changes: 11 additions & 3 deletions src/disco/api.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import { Schema, arrayOf } from 'normalizr';

import { addon, callApi } from 'core/api';
import { callApi } from 'core/api';

export const discoResult = new Schema('discoResults', {idAttribute: (result) => result.addon.slug});
discoResult.addon = addon;
export function getGuid(result) {
if (result.type === 'persona') {
return `${result.id}@personas.mozilla.org`;
}
return result.guid;
}

export const discoResult =
new Schema('discoResults', {idAttribute: (result) => getGuid(result.addon)});
export const addon = new Schema('addons', {idAttribute: getGuid});
discoResult.addon = addon;

export function getDiscoveryAddons({ api }) {
return callApi({
Expand Down
6 changes: 3 additions & 3 deletions src/disco/components/Addon.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ export class Addon extends React.Component {
editorialDescription: PropTypes.string.isRequired,
errorMessage: PropTypes.string,
footerURL: PropTypes.string,
guid: PropTypes.string.isRequired,
headerURL: PropTypes.string,
heading: PropTypes.string.isRequired,
i18n: PropTypes.string.isRequired,
iconUrl: PropTypes.string,
id: PropTypes.string.isRequired,
previewURL: PropTypes.string,
name: PropTypes.string.isRequired,
slug: PropTypes.string.isRequired,
status: PropTypes.oneOf(validInstallStates).isRequired,
textcolor: PropTypes.string,
themeAction: PropTypes.func,
Expand Down Expand Up @@ -117,7 +117,7 @@ export class Addon extends React.Component {
}

render() {
const { heading, slug, type } = this.props;
const { guid, heading, type } = this.props;

if (!validAddonTypes.includes(type)) {
throw new Error(`Invalid addon type "${type}"`);
Expand All @@ -141,7 +141,7 @@ export class Addon extends React.Component {
{this.getDescription()}
</div>
<div className="install-button">
<InstallButton slug={slug} />
<InstallButton guid={guid} />
</div>
</div>
</div>
Expand Down
47 changes: 23 additions & 24 deletions src/disco/containers/InstallButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import 'disco/css/InstallButton.scss';
export class InstallButton extends React.Component {
static propTypes = {
handleChange: PropTypes.func,
guid: PropTypes.string,
guid: PropTypes.string.isRequired,
install: PropTypes.func.isRequired,
installTheme: PropTypes.func.isRequired,
i18n: PropTypes.object.isRequired,
Expand All @@ -45,20 +45,19 @@ export class InstallButton extends React.Component {
}

componentDidMount() {
const { guid, installURL, setInitialStatus, slug } = this.props;
setInitialStatus({guid, installURL, slug});
const { guid, installURL, setInitialStatus } = this.props;
setInitialStatus({guid, installURL});
}

handleClick = (e) => {
e.preventDefault();
const { guid, install, installURL, name, slug,
status, installTheme, type, uninstall } = this.props;
const { guid, install, installURL, name, status, installTheme, type, uninstall } = this.props;
if (type === THEME_TYPE && status === UNINSTALLED) {
installTheme(this.refs.themeData, slug, name);
installTheme(this.refs.themeData, guid, name);
} else if (status === UNINSTALLED) {
install({ guid, installURL, slug, name });
install({ guid, installURL, name });
} else if (status === INSTALLED) {
uninstall({ guid, installURL, slug, name, type });
uninstall({ guid, installURL, name, type });
}
}

Expand Down Expand Up @@ -97,21 +96,21 @@ export class InstallButton extends React.Component {
}

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

export function makeProgressHandler(dispatch, slug) {
export function makeProgressHandler(dispatch, guid) {
return (addonInstall) => {
if (addonInstall.state === 'STATE_DOWNLOADING') {
const downloadProgress = parseInt(
100 * addonInstall.progress / addonInstall.maxProgress, 10);
dispatch({type: 'DOWNLOAD_PROGRESS', payload: {slug, downloadProgress}});
dispatch({type: 'DOWNLOAD_PROGRESS', payload: {guid, downloadProgress}});
} else if (addonInstall.state === 'STATE_INSTALLING') {
dispatch({type: 'START_INSTALL', payload: {slug}});
dispatch({type: 'START_INSTALL', payload: {guid}});
} else if (addonInstall.state === 'STATE_INSTALLED') {
dispatch({type: 'INSTALL_COMPLETE', payload: {slug}});
dispatch({type: 'INSTALL_COMPLETE', payload: {guid}});
}
};
}
Expand All @@ -121,9 +120,9 @@ export function mapDispatchToProps(dispatch) {
return {};
}
return {
setInitialStatus({ guid, installURL, slug }) {
setInitialStatus({ guid, installURL }) {
const addonManager = new AddonManager(guid, installURL);
const payload = {guid, slug, url: installURL};
const payload = {guid, url: installURL};
return addonManager.getAddon()
.then(
(addon) => {
Expand All @@ -133,34 +132,34 @@ export function mapDispatchToProps(dispatch) {
() => dispatch({type: 'INSTALL_STATE', payload: {...payload, status: UNINSTALLED}}));
},

install({ guid, installURL, slug, name }) {
const addonManager = new AddonManager(guid, installURL, makeProgressHandler(dispatch, slug));
dispatch({type: 'START_DOWNLOAD', payload: {slug}});
install({ guid, installURL, name }) {
const addonManager = new AddonManager(guid, installURL, makeProgressHandler(dispatch, guid));
dispatch({type: 'START_DOWNLOAD', payload: {guid}});
tracking.sendEvent({action: 'addon', category: INSTALL_CATEGORY, label: name});
return addonManager.install();
},

installTheme(node, slug, name, _themeAction = themeAction) {
installTheme(node, guid, name, _themeAction = themeAction) {
_themeAction(node, THEME_INSTALL);
tracking.sendEvent({action: 'theme', category: INSTALL_CATEGORY, label: name});
return new Promise((resolve) => {
setTimeout(() => {
dispatch({type: 'INSTALL_STATE', payload: {slug, status: INSTALLED}});
dispatch({type: 'INSTALL_STATE', payload: {guid, status: INSTALLED}});
resolve();
}, 250);
});
},

uninstall({ guid, installURL, slug, name, type }) {
uninstall({ guid, installURL, name, type }) {
const addonManager = new AddonManager(guid, installURL);
dispatch({type: 'START_UNINSTALL', payload: {slug}});
dispatch({type: 'START_UNINSTALL', payload: {guid}});
const action = {
ADDON_TYPE: 'addon',
THEME_TYPE: 'theme',
}[type] || 'invalid';
tracking.sendEvent({action, category: UNINSTALL_CATEGORY, label: name});
return addonManager.uninstall()
.then(() => dispatch({type: 'UNINSTALL_COMPLETE', payload: {slug}}));
.then(() => dispatch({type: 'UNINSTALL_COMPLETE', payload: {guid}}));
},
};
}
Expand Down
7 changes: 3 additions & 4 deletions src/disco/reducers/installations.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,11 @@ export default function installations(state = {}, { type, payload }) {
return state;
}
let addon;
if (state[payload.slug]) {
addon = {...state[payload.slug]};
if (state[payload.guid]) {
addon = {...state[payload.guid]};
}
if (type === 'INSTALL_STATE') {
addon = {
slug: payload.slug,
guid: payload.guid,
url: payload.url,
downloadProgress: 0,
Expand Down Expand Up @@ -56,6 +55,6 @@ export default function installations(state = {}, { type, payload }) {
}
return {
...state,
[payload.slug]: addon,
[payload.guid]: addon,
};
}
Loading