import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Autosuggest from 'react-autosuggest';
import Fuse from 'fuse.js';
import { icons } from 'Helpers/Props';
import Icon from 'Components/Icon';
import keyboardShortcuts, { shortcuts } from 'Components/keyboardShortcuts';
import ArtistSearchResult from './ArtistSearchResult';
import styles from './ArtistSearchInput.css';
const ADD_NEW_TYPE = 'addNew';
const fuseOptions = {
shouldSort: true,
includeMatches: true,
threshold: 0.3,
location: 0,
distance: 100,
maxPatternLength: 32,
minMatchCharLength: 1,
keys: [
'artistName',
'tags.label'
]
};
class ArtistSearchInput extends Component {
//
// Lifecycle
constructor(props, context) {
super(props, context);
this._autosuggest = null;
this.state = {
value: '',
suggestions: []
};
}
componentDidMount() {
this.props.bindShortcut(shortcuts.ARTIST_SEARCH_INPUT.key, this.focusInput);
}
//
// Control
setAutosuggestRef = (ref) => {
this._autosuggest = ref;
}
focusInput = (event) => {
event.preventDefault();
this._autosuggest.input.focus();
}
getSectionSuggestions(section) {
return section.suggestions;
}
renderSectionTitle(section) {
return (
{section.title}
);
}
getSuggestionValue({ title }) {
return title || '';
}
renderSuggestion(item, { query }) {
if (item.type === ADD_NEW_TYPE) {
return (
Search for {query}
);
}
return (
);
}
goToArtist(item) {
this.setState({ value: '' });
this.props.onGoToArtist(item.item.foreignArtistId);
}
reset() {
this.setState({
value: '',
suggestions: []
});
}
//
// Listeners
onChange = (event, { newValue, method }) => {
if (method === 'up' || method === 'down') {
return;
}
this.setState({ value: newValue });
}
onKeyDown = (event) => {
if (event.key !== 'Tab' && event.key !== 'Enter' || event.key !== 'ArrowDown' || event.key !== 'ArrowUp') {
return;
}
const {
suggestions,
value
} = this.state;
const {
highlightedSectionIndex,
highlightedSuggestionIndex
} = this._autosuggest.state;
if (!suggestions.length || highlightedSectionIndex && (event.key !== 'ArrowDown' || event.key !== 'ArrowUp')) {
this.props.onGoToAddNewArtist(value);
this._autosuggest.input.blur();
this.reset();
return;
}
// If an suggestion is not selected go to the first artist,
// otherwise go to the selected artist.
if (highlightedSuggestionIndex == null && (event.key !== 'ArrowDown' || event.key !== 'ArrowUp')) {
this.goToArtist(suggestions[0]);
} else {
this.goToArtist(suggestions[highlightedSuggestionIndex]);
}
this._autosuggest.input.blur();
this.reset();
}
onBlur = () => {
this.reset();
}
onSuggestionsFetchRequested = ({ value }) => {
const fuse = new Fuse(this.props.artists, fuseOptions);
const suggestions = fuse.search(value).slice(0, 15);
this.setState({ suggestions });
}
onSuggestionsClearRequested = () => {
this.setState({
suggestions: []
});
}
onSuggestionSelected = (event, { suggestion }) => {
if (suggestion.type === ADD_NEW_TYPE) {
this.props.onGoToAddNewArtist(this.state.value);
} else {
this.goToArtist(suggestion);
}
}
//
// Render
render() {
const {
value,
suggestions
} = this.state;
const suggestionGroups = [];
if (suggestions.length) {
suggestionGroups.push({
title: 'Existing Artist',
suggestions
});
}
suggestionGroups.push({
title: 'Add New Artist',
suggestions: [
{
type: ADD_NEW_TYPE,
title: value
}
]
});
const inputProps = {
ref: this.setInputRef,
className: styles.input,
name: 'artistSearch',
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.artistContainer,
suggestionsList: styles.list,
suggestion: styles.listItem,
suggestionHighlighted: styles.highlighted
};
return (
);
}
}
ArtistSearchInput.propTypes = {
artists: PropTypes.arrayOf(PropTypes.object).isRequired,
onGoToArtist: PropTypes.func.isRequired,
onGoToAddNewArtist: PropTypes.func.isRequired,
bindShortcut: PropTypes.func.isRequired
};
export default keyboardShortcuts(ArtistSearchInput);