You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
251 lines
5.6 KiB
251 lines
5.6 KiB
7 years ago
|
import _ from 'lodash';
|
||
|
import PropTypes from 'prop-types';
|
||
|
import React, { Component } from 'react';
|
||
|
import Autosuggest from 'react-autosuggest';
|
||
|
import jdu from 'jdu';
|
||
|
import { icons } from 'Helpers/Props';
|
||
|
import Icon from 'Components/Icon';
|
||
|
import keyboardShortcuts, { shortcuts } from 'Components/keyboardShortcuts';
|
||
7 years ago
|
import ArtistSearchResult from './ArtistSearchResult';
|
||
|
import styles from './ArtistSearchInput.css';
|
||
7 years ago
|
|
||
|
const ADD_NEW_TYPE = 'addNew';
|
||
|
|
||
7 years ago
|
class ArtistSearchInput extends Component {
|
||
7 years ago
|
|
||
|
//
|
||
|
// Lifecycle
|
||
|
|
||
|
constructor(props, context) {
|
||
|
super(props, context);
|
||
|
|
||
|
this._autosuggest = null;
|
||
|
|
||
|
this.state = {
|
||
|
value: '',
|
||
|
suggestions: []
|
||
|
};
|
||
|
}
|
||
|
|
||
|
componentDidMount() {
|
||
7 years ago
|
this.props.bindShortcut(shortcuts.ARTIST_SEARCH_INPUT.key, this.focusInput);
|
||
7 years ago
|
}
|
||
|
|
||
|
//
|
||
|
// Control
|
||
|
|
||
|
setAutosuggestRef = (ref) => {
|
||
|
this._autosuggest = ref;
|
||
|
}
|
||
|
|
||
|
focusInput = (event) => {
|
||
|
event.preventDefault();
|
||
|
this._autosuggest.input.focus();
|
||
|
}
|
||
|
|
||
|
getSectionSuggestions(section) {
|
||
|
return section.suggestions;
|
||
|
}
|
||
|
|
||
|
renderSectionTitle(section) {
|
||
|
return (
|
||
|
<div className={styles.sectionTitle}>
|
||
|
{section.title}
|
||
|
</div>
|
||
|
);
|
||
|
}
|
||
|
|
||
|
getSuggestionValue({ title }) {
|
||
|
return title;
|
||
|
}
|
||
|
|
||
|
renderSuggestion(item, { query }) {
|
||
|
if (item.type === ADD_NEW_TYPE) {
|
||
|
return (
|
||
|
<div className={styles.addNewSeriesSuggestion}>
|
||
|
Search for {query}
|
||
|
</div>
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return (
|
||
7 years ago
|
<ArtistSearchResult
|
||
7 years ago
|
query={query}
|
||
|
{...item}
|
||
|
/>
|
||
|
);
|
||
|
}
|
||
|
|
||
|
goToSeries(series) {
|
||
|
this.setState({ value: '' });
|
||
7 years ago
|
this.props.onGoToSeries(series.nameSlug);
|
||
7 years ago
|
}
|
||
|
|
||
|
reset() {
|
||
|
this.setState({
|
||
|
value: '',
|
||
|
suggestions: []
|
||
|
});
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Listeners
|
||
|
|
||
|
onChange = (event, { newValue }) => {
|
||
|
this.setState({ value: newValue });
|
||
|
}
|
||
|
|
||
|
onKeyDown = (event) => {
|
||
|
if (event.key !== 'Tab' && event.key !== 'Enter') {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const {
|
||
|
suggestions,
|
||
|
value
|
||
|
} = this.state;
|
||
|
|
||
|
const {
|
||
|
highlightedSectionIndex,
|
||
|
highlightedSuggestionIndex
|
||
|
} = this._autosuggest.state;
|
||
|
|
||
|
if (!suggestions.length || highlightedSectionIndex) {
|
||
7 years ago
|
this.props.onGoToAddNewArtist(value);
|
||
7 years ago
|
this._autosuggest.input.blur();
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// If an suggestion is not selected go to the first series,
|
||
|
// otherwise go to the selected series.
|
||
|
|
||
|
if (highlightedSuggestionIndex == null) {
|
||
|
this.goToSeries(suggestions[0]);
|
||
|
} else {
|
||
|
this.goToSeries(suggestions[highlightedSuggestionIndex]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
onBlur = () => {
|
||
|
this.reset();
|
||
|
}
|
||
|
|
||
|
onSuggestionsFetchRequested = ({ value }) => {
|
||
|
const lowerCaseValue = jdu.replace(value).toLowerCase();
|
||
|
|
||
|
const suggestions = _.filter(this.props.series, (series) => {
|
||
|
// Check the title first and if there isn't a match fallback to the alternate titles
|
||
|
|
||
7 years ago
|
const titleMatch = jdu.replace(series.artistName).toLowerCase().contains(lowerCaseValue);
|
||
7 years ago
|
|
||
|
return titleMatch || _.some(series.alternateTitles, (alternateTitle) => {
|
||
|
return jdu.replace(alternateTitle.title).toLowerCase().contains(lowerCaseValue);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
this.setState({ suggestions });
|
||
|
}
|
||
|
|
||
|
onSuggestionsClearRequested = () => {
|
||
|
this.reset();
|
||
|
}
|
||
|
|
||
|
onSuggestionSelected = (event, { suggestion, sectionIndex }) => {
|
||
|
if (suggestion.type === ADD_NEW_TYPE) {
|
||
7 years ago
|
this.props.onGoToAddNewArtist(this.state.value);
|
||
7 years ago
|
} else {
|
||
|
this.goToSeries(suggestion);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Render
|
||
|
|
||
|
render() {
|
||
|
const {
|
||
|
value,
|
||
|
suggestions
|
||
|
} = this.state;
|
||
|
|
||
|
const suggestionGroups = [];
|
||
|
|
||
|
if (suggestions.length) {
|
||
|
suggestionGroups.push({
|
||
7 years ago
|
title: 'Existing Artist',
|
||
7 years ago
|
suggestions
|
||
|
});
|
||
|
}
|
||
|
|
||
|
if (suggestions.length <= 3) {
|
||
|
suggestionGroups.push({
|
||
7 years ago
|
title: 'Add New Artist',
|
||
7 years ago
|
suggestions: [
|
||
|
{
|
||
|
type: ADD_NEW_TYPE,
|
||
|
title: value
|
||
|
}
|
||
|
]
|
||
|
});
|
||
|
}
|
||
|
|
||
|
const inputProps = {
|
||
|
ref: this.setInputRef,
|
||
|
className: styles.input,
|
||
|
name: 'seriesSearch',
|
||
|
value,
|
||
|
placeholder: 'Search',
|
||
|
autoComplete: 'off',
|
||
|
spellCheck: false,
|
||
|
onChange: this.onChange,
|
||
|
onKeyDown: this.onKeyDown,
|
||
|
onBlur: this.onBlur,
|
||
|
onFocus: this.onFocus
|
||
|
};
|
||
|
|
||
|
const theme = {
|
||
|
container: styles.container,
|
||
|
containerOpen: styles.containerOpen,
|
||
|
suggestionsContainer: styles.seriesContainer,
|
||
|
suggestionsList: styles.list,
|
||
|
suggestion: styles.listItem,
|
||
|
suggestionHighlighted: styles.highlighted
|
||
|
};
|
||
|
|
||
|
return (
|
||
|
<div className={styles.wrapper}>
|
||
|
<Icon
|
||
|
className={styles.icon}
|
||
|
name={icons.SEARCH}
|
||
|
/>
|
||
|
|
||
|
<Autosuggest
|
||
|
ref={this.setAutosuggestRef}
|
||
|
id={name}
|
||
|
inputProps={inputProps}
|
||
|
theme={theme}
|
||
|
focusInputOnSuggestionClick={false}
|
||
|
multiSection={true}
|
||
|
suggestions={suggestionGroups}
|
||
|
getSectionSuggestions={this.getSectionSuggestions}
|
||
|
renderSectionTitle={this.renderSectionTitle}
|
||
|
getSuggestionValue={this.getSuggestionValue}
|
||
|
renderSuggestion={this.renderSuggestion}
|
||
|
onSuggestionSelected={this.onSuggestionSelected}
|
||
|
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
|
||
|
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
|
||
|
/>
|
||
|
</div>
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
7 years ago
|
ArtistSearchInput.propTypes = {
|
||
7 years ago
|
series: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||
|
onGoToSeries: PropTypes.func.isRequired,
|
||
7 years ago
|
onGoToAddNewArtist: PropTypes.func.isRequired,
|
||
7 years ago
|
bindShortcut: PropTypes.func.isRequired
|
||
|
};
|
||
|
|
||
7 years ago
|
export default keyboardShortcuts(ArtistSearchInput);
|