Creating SearchResults component

This commit is contained in:
James Barnsley
2020-06-09 08:17:19 +12:00
parent d88f66798f
commit cfd1222445
6 changed files with 23964 additions and 304 deletions

View File

@ -34,7 +34,7 @@ class SearchForm extends React.Component {
return false;
}
handleBlur() {
handleBlur = () => {
const { onBlur } = this.props;
const { term } = this.state;
this.setState({ pristine: false });
@ -43,11 +43,11 @@ class SearchForm extends React.Component {
}
}
handleFocus(e) {
handleFocus = () => {
this.setState({ pristine: false });
}
handleSubmit(e) {
handleSubmit = (e) => {
e.preventDefault();
// check for uri type matching
@ -84,8 +84,8 @@ class SearchForm extends React.Component {
type="text"
placeholder="Search..."
onChange={(e) => this.setState({ term: e.target.value, pristine: false })}
onBlur={(e) => this.handleBlur}
onFocus={(e) => this.handleFocus}
onBlur={this.handleBlur}
onFocus={this.handleFocus}
value={this.state.term}
/>
</label>

View File

@ -0,0 +1,92 @@
import React from 'react';
import { connect } from 'react-redux';
import { titleCase, getIndexedRecords } from '../util/helpers';
import { sortItems } from '../util/arrays';
import URILink from './URILink';
import Icon from './Icon';
import AlbumGrid from './AlbumGrid';
import ArtistGrid from './ArtistGrid';
import PlaylistGrid from './PlaylistGrid';
import TrackList from './TrackList';
import LazyLoadListener from './LazyLoadListener';
import { pseudoRandomBytes } from 'crypto';
const SearchResults = ({
type,
query,
loadMore,
index,
mopidy_search_results,
spotify_search_results,
sort,
sort_reverse,
sort_map,
all,
}) => {
const encodedTerm = encodeURIComponent(query.term);
let results = [];
if (mopidy_search_results.query === query.term && mopidy_search_results[type]) {
results = [...results, ...getIndexedRecords(index, mopidy_search_results[type])];
}
if (spotify_search_results.query === query.term && spotify_search_results[type]) {
results = [...results, ...getIndexedRecords(index, spotify_search_results[type])];
}
results = sortItems(results, sort, sort_reverse, sort_map);
const resultsCount = results.length;
if (all && type !== 'tracks' && results.length > 5) {
results = results.slice(0, 6);
}
if (results.length <= 0) return null;
return (
<div>
<h4>
{!all && (
<span>
<URILink uri={`iris:search:all:${encodedTerm}`}>
{'Search '}
</URILink>
<Icon type="fontawesome" name="angle-right" />
{` ${titleCase(type)}`}
</span>
)}
{all && (
<URILink uri={`iris:search:${type}:${encodedTerm}`}>
{titleCase(type)}
</URILink>
)}
</h4>
<section className="grid-wrapper">
{type === 'artists' && <ArtistGrid artists={results} show_source_icon mini={all} />}
{type === 'albums' && <AlbumGrid albums={results} show_source_icon mini={all} />}
{type === 'playlists' && <PlaylistGrid playlists={results} show_source_icon mini={all} />}
{type === 'tracks' && <TrackList tracks={results} uri={`iris:search:${query.type}:${encodedTerm}`} show_source_icon />}
{/*<LazyLoadListener enabled={this.props.artists_more && spotify_search_enabled} loadMore={loadMore} />*/}
{resultsCount > results.length && (
<URILink uri={`iris:search:${type}:${encodedTerm}`} className="button button--default">
{`All ${type} (${resultsCount})`}
</URILink>
)}
</section>
</div>
);
};
const mapStateToProps = (state, ownProps) => ({
index: state.core[ownProps.type] || [],
uri_schemes_priority: state.ui.uri_schemes_priority || [],
mopidy_search_results: state.mopidy.search_results || {},
spotify_search_results: state.spotify.search_results || {},
sort: state.ui.search_results_sort || 'followers.total',
sort_reverse: !!state.ui.search_results_sort_reverse,
});
const mapDispatchToProps = () => ({});
export default connect(mapStateToProps, mapDispatchToProps)(SearchResults);

View File

@ -13,6 +13,7 @@ import PlaylistGrid from '../components/PlaylistGrid';
import LazyLoadListener from '../components/LazyLoadListener';
import SearchForm from '../components/Fields/SearchForm';
import URILink from '../components/URILink';
import SearchResults from '../components/SearchResults';
import * as coreActions from '../services/core/actions';
import * as uiActions from '../services/ui/actions';
import * as mopidyActions from '../services/mopidy/actions';
@ -74,7 +75,9 @@ class Search extends React.Component {
}
}
handleSubmit(term) {
handleSubmit = (term) => {
const { type } = this.state;
const { history, term: propTerm } = this.props;
const encodedTerm = encodeURIComponent(term);
this.setState(
@ -82,10 +85,10 @@ class Search extends React.Component {
// Unchanged term, so this is a forced re-search
// Often the other search parameters have changed instead, but we can't
// push a URL change when the term hasn't changed
if (this.props.term == term) {
if (propTerm === term) {
this.search();
} else {
this.props.history.push(`/search/${this.state.type}/${encodedTerm}`);
history.push(`/search/${type}/${encodedTerm}`);
}
},
);
@ -309,7 +312,19 @@ class Search extends React.Component {
);
}
render() {
render = () => {
const {
term,
type,
} = this.state;
const {
search_settings,
uri_schemes,
sort,
uri_schemes_priority,
mopidy_search_results,
spotify_search_results,
} = this.props;
const sort_options = [
{
value: 'followers',
@ -334,21 +349,19 @@ class Search extends React.Component {
];
const provider_options = [];
for (let i = 0; i < this.props.uri_schemes.length; i++) {
for (let i = 0; i < uri_schemes.length; i++) {
provider_options.push({
value: this.props.uri_schemes[i],
label: titleCase(this.props.uri_schemes[i].replace(':', '').replace('+', ' ')),
value: uri_schemes[i],
label: titleCase(uri_schemes[i].replace(':', '').replace('+', ' ')),
});
}
const spotify_search_enabled = (this.props.search_settings && this.props.search_settings.spotify);
const { sort } = this.props;
const spotify_search_enabled = (search_settings && search_settings.spotify);
let { sort_reverse } = this.props;
let sort_map = null;
switch (this.props.sort) {
switch (sort) {
case 'uri':
sort_map = this.props.uri_schemes_priority;
sort_map = uri_schemes_priority;
break;
// Followers (aka popularlity works in reverse-numerical order)
@ -359,40 +372,42 @@ class Search extends React.Component {
}
let artists = [];
if (this.props.mopidy_search_results.artists) {
artists = [...artists, ...getIndexedRecords(this.props.artists, this.props.mopidy_search_results.artists)];
}
if (this.props.spotify_search_results.artists) {
artists = [...artists, ...getIndexedRecords(this.props.artists, this.props.spotify_search_results.artists)];
}
artists = sortItems(artists, sort, sort_reverse, sort_map);
let albums = [];
if (this.props.mopidy_search_results.albums) {
albums = [...albums, ...getIndexedRecords(this.props.albums, this.props.mopidy_search_results.albums)];
}
if (this.props.spotify_search_results.albums) {
albums = [...albums, ...getIndexedRecords(this.props.albums, this.props.spotify_search_results.albums)];
}
albums = sortItems(albums, sort, sort_reverse, sort_map);
let playlists = [];
if (this.props.mopidy_search_results.playlists) {
playlists = [...playlists, ...getIndexedRecords(this.props.playlists, this.props.mopidy_search_results.playlists)];
}
if (this.props.spotify_search_results.playlists) {
playlists = [...playlists, ...getIndexedRecords(this.props.playlists, this.props.spotify_search_results.playlists)];
}
playlists = sortItems(playlists, sort, sort_reverse, sort_map);
let tracks = [];
if (this.props.mopidy_search_results.tracks) {
tracks = [...tracks, ...this.props.mopidy_search_results.tracks];
}
if (this.props.spotify_search_results.tracks) {
tracks = [...tracks, ...this.props.spotify_search_results.tracks];
if (mopidy_search_results.query === term) {
if (mopidy_search_results.artists && mopidy_search_results.query === term) {
artists = [...artists, ...getIndexedRecords(this.props.artists, mopidy_search_results.artists)];
}
if (mopidy_search_results.albums) {
albums = [...albums, ...getIndexedRecords(this.props.albums, mopidy_search_results.albums)];
}
if (mopidy_search_results.playlists) {
playlists = [...playlists, ...getIndexedRecords(this.props.playlists, mopidy_search_results.playlists)];
}
if (mopidy_search_results.tracks) {
tracks = [...tracks, ...mopidy_search_results.tracks];
}
}
if (spotify_search_results.query === term) {
if (spotify_search_results.artists) {
artists = [...artists, ...getIndexedRecords(this.props.artists, spotify_search_results.artists)];
}
if (spotify_search_results.albums) {
albums = [...albums, ...getIndexedRecords(this.props.albums, spotify_search_results.albums)];
}
if (spotify_search_results.playlists) {
playlists = [...playlists, ...getIndexedRecords(this.props.playlists, spotify_search_results.playlists)];
}
if (spotify_search_results.tracks) {
tracks = [...tracks, ...spotify_search_results.tracks];
}
}
albums = sortItems(albums, sort, sort_reverse, sort_map);
playlists = sortItems(playlists, sort, sort_reverse, sort_map);
artists = sortItems(artists, sort, sort_reverse, sort_map);
tracks = sortItems(tracks, (sort == 'followers' ? 'popularity' : sort), sort_reverse, sort_map);
const options = (
@ -400,7 +415,7 @@ class Search extends React.Component {
<DropdownField
icon="swap_vert"
name="Sort"
value={this.props.sort}
value={sort}
valueAsLabel
options={sort_options}
selected_icon={this.props.sort_reverse ? 'keyboard_arrow_up' : 'keyboard_arrow_down'}
@ -436,24 +451,29 @@ class Search extends React.Component {
<div className="content-wrapper">
<Switch>
<Route path="/search/artist/:term">
{this.renderArtists(artists, spotify_search_enabled)}
<Route path="/search/artists/:term">
<SearchResults type="artists" query={{ term, type }} />
</Route>
<Route path="/search/album/:term">
{this.renderAlbums(albums, spotify_search_enabled)}
<Route path="/search/albums/:term">
<SearchResults type="albums" query={{ term, type }} />
</Route>
<Route path="/search/playlist/:term">
{this.renderPlaylists(playlists, spotify_search_enabled)}
<Route path="/search/playlists/:term">
<SearchResults type="playlists" query={{ term, type }} />
</Route>
<Route path="/search/track/:term">
{this.renderTracks(tracks, spotify_search_enabled)}
<Route path="/search/tracks/:term">
<SearchResults type="tracks" query={{ term, type }} />
</Route>
<Route path="/search">
{this.renderAll(artists, albums, playlists, tracks, spotify_search_enabled)}
<div className="search-result-sections cf">
<SearchResults type="artists" query={{ term, type }} all />
<SearchResults type="albums" query={{ term, type }} all />
<SearchResults type="playlists" query={{ term, type }} all />
</div>
<SearchResults type="tracks" query={{ term, type }} all />
</Route>
</Switch>