2016-07-07 23:23:18 +02:00
|
|
|
import React, { Component, PropTypes } from "react";
|
|
|
|
import { Link} from "react-router";
|
2016-07-28 23:14:52 +02:00
|
|
|
import { defineMessages, FormattedMessage } from "react-intl";
|
2016-07-07 23:23:18 +02:00
|
|
|
import Fuse from "fuse.js";
|
|
|
|
|
|
|
|
import FilterBar from "./elements/FilterBar";
|
|
|
|
import Pagination from "./elements/Pagination";
|
2016-07-28 23:14:52 +02:00
|
|
|
import { formatLength, messagesMap } from "../utils";
|
|
|
|
|
|
|
|
import commonMessages from "../locales/messagesDescriptors/common";
|
|
|
|
import messages from "../locales/messagesDescriptors/Songs";
|
|
|
|
|
|
|
|
const songsMessages = defineMessages(messagesMap(Array.concat([], commonMessages, messages)));
|
2016-07-07 23:23:18 +02:00
|
|
|
|
|
|
|
export class SongsTableRow extends Component {
|
|
|
|
render () {
|
|
|
|
const length = formatLength(this.props.song.length);
|
|
|
|
const linkToArtist = "/artist/" + this.props.song.artist.id;
|
|
|
|
const linkToAlbum = "/album/" + this.props.song.album.id;
|
|
|
|
return (
|
|
|
|
<tr>
|
|
|
|
<td></td>
|
|
|
|
<td className="title">{this.props.song.name}</td>
|
|
|
|
<td className="artist"><Link to={linkToArtist}>{this.props.song.artist.name}</Link></td>
|
|
|
|
<td className="artist"><Link to={linkToAlbum}>{this.props.song.album.name}</Link></td>
|
|
|
|
<td className="genre">{this.props.song.genre}</td>
|
|
|
|
<td className="length">{length}</td>
|
|
|
|
</tr>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SongsTableRow.propTypes = {
|
|
|
|
song: PropTypes.object.isRequired
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
export class SongsTable extends Component {
|
|
|
|
render () {
|
|
|
|
var displayedSongs = this.props.songs;
|
|
|
|
if (this.props.filterText) {
|
|
|
|
// Use Fuse for the filter
|
|
|
|
displayedSongs = new Fuse(
|
|
|
|
this.props.songs,
|
|
|
|
{
|
|
|
|
"keys": ["name"],
|
|
|
|
"threshold": 0.4,
|
|
|
|
"include": ["score"]
|
|
|
|
}).search(this.props.filterText);
|
|
|
|
// Keep only items in results
|
|
|
|
displayedSongs = displayedSongs.map(function (item) { return item.item; });
|
|
|
|
}
|
|
|
|
|
|
|
|
var rows = [];
|
|
|
|
displayedSongs.forEach(function (song) {
|
|
|
|
rows.push(<SongsTableRow song={song} key={song.id} />);
|
|
|
|
});
|
|
|
|
return (
|
2016-07-27 13:51:30 +02:00
|
|
|
<div className="table-responsive">
|
|
|
|
<table className="table table-hover songs">
|
|
|
|
<thead>
|
|
|
|
<tr>
|
|
|
|
<th></th>
|
2016-07-28 23:14:52 +02:00
|
|
|
<th>
|
|
|
|
<FormattedMessage {...songsMessages["app.songs.title"]} />
|
|
|
|
</th>
|
|
|
|
<th>
|
|
|
|
<FormattedMessage {...songsMessages["app.common.artist"]} />
|
|
|
|
</th>
|
|
|
|
<th>
|
|
|
|
<FormattedMessage {...songsMessages["app.common.album"]} />
|
|
|
|
</th>
|
|
|
|
<th>
|
|
|
|
<FormattedMessage {...songsMessages["app.common.genre"]} />
|
|
|
|
</th>
|
|
|
|
<th>
|
|
|
|
<FormattedMessage {...songsMessages["app.songs.length"]} />
|
|
|
|
</th>
|
2016-07-27 13:51:30 +02:00
|
|
|
</tr>
|
|
|
|
</thead>
|
|
|
|
<tbody>{rows}</tbody>
|
|
|
|
</table>
|
|
|
|
</div>
|
2016-07-07 23:23:18 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SongsTable.propTypes = {
|
|
|
|
songs: PropTypes.array.isRequired,
|
|
|
|
filterText: PropTypes.string
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
export default class FilterablePaginatedSongsTable extends Component {
|
|
|
|
constructor (props) {
|
|
|
|
super(props);
|
|
|
|
this.state = {
|
|
|
|
filterText: ""
|
|
|
|
};
|
|
|
|
|
|
|
|
this.handleUserInput = this.handleUserInput.bind(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
handleUserInput (filterText) {
|
|
|
|
this.setState({
|
|
|
|
filterText: filterText.trim()
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
render () {
|
|
|
|
const nPages = Math.ceil(this.props.songsTotalCount / this.props.songsPerPage);
|
|
|
|
return (
|
|
|
|
<div>
|
|
|
|
<FilterBar filterText={this.state.filterText} onUserInput={this.handleUserInput} />
|
|
|
|
<SongsTable songs={this.props.songs} filterText={this.state.filterText} />
|
|
|
|
<Pagination nPages={nPages} currentPage={this.props.currentPage} location={this.props.location} />
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FilterablePaginatedSongsTable.propTypes = {
|
|
|
|
songs: PropTypes.array.isRequired,
|
|
|
|
songsTotalCount: PropTypes.number.isRequired,
|
|
|
|
songsPerPage: PropTypes.number.isRequired,
|
|
|
|
currentPage: PropTypes.number.isRequired,
|
|
|
|
location: PropTypes.object.isRequired
|
|
|
|
};
|