228 lines
6.0 KiB
JavaScript

import React from "react"
import { Map } from "immutable"
import fuzzy from "fuzzy";
import InfiniteScroll from "react-infinite-scroller";
import ListFilter from "./filter"
import ExplorerOptions from "./explorerOptions"
import Poster from "./poster"
import Loader from "../loader/loader"
const DEFAULT_ADD_EXTRA_ITEMS = 30;
export default class ListPosters extends React.PureComponent {
constructor(props) {
super(props);
this.loadMore = this.loadMore.bind(this);
this.state = this.getNextState(props);
}
loadMore() {
// Nothing to do if the app is loading
if (this.props.loading) {
return;
}
if (this.props.data === undefined) {
return;
}
this.setState(this.getNextState(this.props));
}
getNextState(props) {
let totalListSize = props.data !== undefined ? props.data.size : 0;
let currentListSize = (this.state && this.state.items) ? this.state.items : 0;
let nextListSize = currentListSize + DEFAULT_ADD_EXTRA_ITEMS;
let hasMore = true;
if (nextListSize >= totalListSize) {
nextListSize = totalListSize;
hasMore = false;
}
return {
items: nextListSize,
hasMore: hasMore,
};
}
componentWillReceiveProps(nextProps) {
if (this.props.data === undefined) { return }
if (nextProps.data === undefined) { return }
if (this.props.data.size !== nextProps.data.size) {
this.setState(this.getNextState(nextProps));
}
}
render() {
let elmts = this.props.data;
const listSize = elmts !== undefined ? elmts.size : 0;
const colSize = (listSize !== 0) ? "col-xs-5 col-md-8" : "col-xs-12";
// Filter the list of elements
if (this.props.filter !== "") {
elmts = elmts.filter((v) => fuzzy.test(this.props.filter, v.get("title")), this);
} else {
elmts = elmts.slice(0, this.state.items);
}
// Chose when to display filter / explore options
let displayFilter = true;
if ((this.props.params
&& this.props.params.category
&& this.props.params.category !== ""
&& this.props.params.source
&& this.props.params.source !== "")
|| (listSize === 0)) {
displayFilter = false;
}
let displayExplorerOptions = false;
if (listSize !== 0) {
displayExplorerOptions = !displayFilter;
}
return (
<div className={colSize}>
{displayFilter &&
<ListFilter
updateFilter={this.props.updateFilter}
placeHolder={this.props.placeHolder}
/>
}
<ExplorerOptions
type={this.props.type}
display={displayExplorerOptions}
params={this.props.params}
router={this.props.router}
options={this.props.exploreOptions}
/>
<Posters
elmts={elmts}
loading={this.props.loading}
hasMore={this.state.hasMore}
loadMore={this.loadMore}
selectedImdbId={this.props.selectedImdbId}
selectPoster={this.props.onClick}
onDoubleClick={this.props.onDoubleClick}
onKeyEnter={this.props.onKeyEnter}
/>
</div>
);
}
}
class Posters extends React.PureComponent {
constructor(props) {
super(props);
this.posterRef = React.createRef();
}
componentDidUpdate() {
// Always focus on the poster list
if (this.posterRef.current != null) {
this.posterRef.current.focus();
}
}
move(event) {
// Detect which direction to go
const keyToDiff = Map({
"ArrowRight": 1,
"l": 1,
"ArrowLeft": -1,
"h": -1,
"ArrowUp": -6,
"k": -6,
"ArrowDown": 6,
"j": 6,
});
if (event.key === "Enter") {
this.props.onKeyEnter(this.props.selectedImdbId);
}
if (! keyToDiff.has(event.key) ) {
return;
}
var diff = keyToDiff.get(event.key);
// Don't scroll when changing poster
event.preventDefault();
// Get the index of the currently selected item
const idx = this.props.elmts.keySeq().findIndex(k => k === this.props.selectedImdbId);
var newIdx = idx + diff;
// Handle edge cases
if (newIdx > this.props.elmts.size -1) {
newIdx = this.props.elmts.size -1;
} else if (newIdx < 0) {
newIdx = 0;
}
// Get the imdbID of the newly selected item
var selectedImdb = Object.keys(this.props.elmts.toJS())[newIdx];
// Select the movie
this.props.selectPoster(selectedImdb);
}
render() {
if (this.props.loading) {
return (<Loader />);
}
if (this.props.elmts.size === 0) {
return (
<div className="jumbotron">
<h2>No result</h2>
</div>
);
}
return (
<div tabIndex="0"
ref={this.posterRef}
onKeyDown={(event) => this.move(event)}
className="poster-list"
>
<InfiniteScroll
hasMore={this.props.hasMore}
loadMore={this.props.loadMore}
className="row"
>
{this.props.elmts.toIndexedSeq().map(function(movie, index) {
const imdbId = movie.get("imdb_id");
const selected = (imdbId === this.props.selectedImdbId) ? true : false;
let clearFixes = [];
if ((index % 6) === 0) { clearFixes.push("clearfix visible-lg") };
if ((index % 4) === 0) { clearFixes.push("clearfix visible-md") };
if ((index % 2) === 0) { clearFixes.push("clearfix visible-sm") };
return (
<div key={imdbId}>
{clearFixes.length > 0 && clearFixes.map(function(el, i) {
return (
<div key={`clearfix-${imdbId}-${i}`} className={el}></div>
);
})}
<Poster
data={movie}
key={`poster-${imdbId}`}
selected={selected}
onClick={() => this.props.selectPoster(imdbId)}
onDoubleClick={() => this.props.onDoubleClick(imdbId)}
/>
</div>
)
} ,this)}
</InfiniteScroll>
</div>
);
}
}