Add more prettty and human readable artists URLs

This commit is contained in:
Lucas Verney 2016-08-12 13:11:14 +02:00
parent 85dcf6d271
commit e232ec8c16
7 changed files with 44 additions and 18 deletions

View File

@ -46,3 +46,10 @@ homogeneous.
## Hooks ## Hooks
Usefuls Git hooks are located in `hooks` folder. Usefuls Git hooks are located in `hooks` folder.
## Notes on URLs
Text after any dash in a URL parameter is considered as a comment and
discarded. In `/artist/1-foobar`, the artist ID is `1` and the `foobar` text
is simply considered as a comment for human readable URLs.

View File

@ -26,6 +26,9 @@ export default class Artists extends Component {
itemsLabel: "app.common.artist", itemsLabel: "app.common.artist",
subItemsType: "albums", subItemsType: "albums",
subItemsLabel: "app.common.album", subItemsLabel: "app.common.album",
buildLinkTo: (itemType, item) => {
return "/" + itemType + "/" + item.get("id") + "-" + encodeURIComponent(item.get("name"));
},
}; };
return ( return (

View File

@ -64,7 +64,10 @@ class GridItemCSSIntl extends Component {
{ itemCount: nSubItems } { itemCount: nSubItems }
); );
const to = "/" + this.props.itemsType + "/" + this.props.item.get("id"); let to = "/" + this.props.itemsType + "/" + this.props.item.get("id");
if (this.props.buildLinkTo) {
to = this.props.buildLinkTo(this.props.itemsType, this.props.item);
}
const id = "grid-item-" + this.props.itemsType + "/" + this.props.item.get("id"); const id = "grid-item-" + this.props.itemsType + "/" + this.props.item.get("id");
const title = formatMessage(gridMessages["app.grid.goTo" + this.props.itemsType.capitalize() + "Page"]); const title = formatMessage(gridMessages["app.grid.goTo" + this.props.itemsType.capitalize() + "Page"]);
@ -85,6 +88,7 @@ GridItemCSSIntl.propTypes = {
itemsLabel: PropTypes.string.isRequired, itemsLabel: PropTypes.string.isRequired,
subItemsType: PropTypes.string.isRequired, subItemsType: PropTypes.string.isRequired,
subItemsLabel: PropTypes.string.isRequired, subItemsLabel: PropTypes.string.isRequired,
buildLinkTo: PropTypes.func,
intl: intlShape.isRequired, intl: intlShape.isRequired,
}; };
export let GridItem = injectIntl(CSSModules(GridItemCSSIntl, css)); export let GridItem = injectIntl(CSSModules(GridItemCSSIntl, css));
@ -237,9 +241,9 @@ export class Grid extends Component {
// Build grid items // Build grid items
let gridItems = []; let gridItems = [];
const { itemsType, itemsLabel, subItemsType, subItemsLabel } = this.props; const { itemsType, itemsLabel, subItemsType, subItemsLabel, buildLinkTo } = this.props;
this.props.items.forEach(function (item) { this.props.items.forEach(function (item) {
gridItems.push(<GridItem item={item} itemsType={itemsType} itemsLabel={itemsLabel} subItemsType={subItemsType} subItemsLabel={subItemsLabel} key={item.get("id")} />); gridItems.push(<GridItem item={item} itemsType={itemsType} itemsLabel={itemsLabel} subItemsType={subItemsType} subItemsLabel={subItemsLabel} buildLinkTo={buildLinkTo} key={item.get("id")} />);
}); });
return ( return (
@ -264,6 +268,7 @@ Grid.propTypes = {
itemsLabel: PropTypes.string.isRequired, itemsLabel: PropTypes.string.isRequired,
subItemsType: PropTypes.string.isRequired, subItemsType: PropTypes.string.isRequired,
subItemsLabel: PropTypes.string.isRequired, subItemsLabel: PropTypes.string.isRequired,
buildLinkTo: PropTypes.func,
filterText: PropTypes.string, filterText: PropTypes.string,
}; };

View File

@ -1,12 +1,12 @@
// NPM imports // NPM imports
import React, { Component } from "react"; import React, { Component, PropTypes } from "react";
import { bindActionCreators } from "redux"; import { bindActionCreators } from "redux";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { defineMessages, injectIntl, intlShape } from "react-intl"; import { defineMessages, injectIntl, intlShape } from "react-intl";
import Immutable from "immutable"; import Immutable from "immutable";
// Local imports // Local imports
import { messagesMap, handleErrorI18nObject } from "../utils"; import { messagesMap, handleErrorI18nObject, filterInt } from "../utils";
// Actions // Actions
import * as actionCreators from "../actions"; import * as actionCreators from "../actions";
@ -26,9 +26,16 @@ const artistMessages = defineMessages(messagesMap(Array.concat([], APIMessages))
*/ */
class ArtistPageIntl extends Component { class ArtistPageIntl extends Component {
componentWillMount() { componentWillMount() {
const id = filterInt(this.props.params.id.split("-")[0]);
if (isNaN(id)) {
// Redirect to homepage
this.context.router.replace({
pathname: "/",
});
}
// Load the data // Load the data
this.props.actions.loadArtist({ this.props.actions.loadArtist({
filter: this.props.params.id, filter: id,
include: ["albums", "songs"], include: ["albums", "songs"],
}); });
} }
@ -53,10 +60,14 @@ class ArtistPageIntl extends Component {
ArtistPageIntl.propTypes = { ArtistPageIntl.propTypes = {
intl: intlShape.isRequired, intl: intlShape.isRequired,
}; };
ArtistPageIntl.contextTypes = {
router: PropTypes.object.isRequired,
};
const mapStateToProps = (state, ownProps) => { const mapStateToProps = (state, ownProps) => {
const id = ownProps.params.id.split("-")[0];
// Get artist // Get artist
let artist = state.entities.getIn(["entities", "artist", ownProps.params.id]); let artist = state.entities.getIn(["entities", "artist", id]);
let albums = new Immutable.List(); let albums = new Immutable.List();
let songs = new Immutable.Map(); let songs = new Immutable.Map();
if (artist) { if (artist) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long