179 lines
4.9 KiB
JavaScript
179 lines
4.9 KiB
JavaScript
import React, { useEffect, useState, useRef } from 'react';
|
|
import { Row, Col, FormGroup, Input, InputGroup, InputGroupText, ListGroup, ListGroupItem } from 'reactstrap';
|
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
import PropTypes from 'prop-types';
|
|
import useDebouncedValue from '../../hooks/useDebounceValue';
|
|
|
|
const JKJamTracksAutoComplete = ({
|
|
fetchFunc,
|
|
onSelect,
|
|
onEnter,
|
|
showDropdown,
|
|
setShowDropdown,
|
|
inputValue,
|
|
setInputValue,
|
|
inputPlaceholder
|
|
}) => {
|
|
const [artists, setArtists] = useState([]);
|
|
const [songs, setSongs] = useState([]);
|
|
const [loading, setLoading] = useState(false);
|
|
const inputRef = useRef(null);
|
|
const MIN_FETCH_LIMIT = 5;
|
|
const DELAY = 400;
|
|
|
|
const debouncedValue = useDebouncedValue(inputValue, DELAY);
|
|
|
|
const fetchAutoCompleteResults = () => {
|
|
// fetch tracks
|
|
setLoading(true);
|
|
fetchFunc(debouncedValue, MIN_FETCH_LIMIT)
|
|
.then(resp => {
|
|
return resp.json();
|
|
})
|
|
.then(data => {
|
|
console.log('tracks', data);
|
|
if (data.songs) {
|
|
const updatedSongs = data.songs.map(song => {
|
|
song.type = 'song';
|
|
return song;
|
|
});
|
|
setSongs(updatedSongs);
|
|
}
|
|
if (data.artists) {
|
|
const updatedArtists = data.artists.map(artist => {
|
|
artist.type = 'artist';
|
|
return artist;
|
|
});
|
|
setArtists(updatedArtists);
|
|
}
|
|
if (data.jamtracks) {
|
|
const updatedSongs = data.jamtracks.map(song => {
|
|
song.type = 'song';
|
|
return song;
|
|
});
|
|
setSongs(updatedSongs);
|
|
}
|
|
setShowDropdown(true);
|
|
})
|
|
.finally(() => {
|
|
setLoading(false);
|
|
});
|
|
}
|
|
|
|
useEffect(() => {
|
|
console.log('debounced value', debouncedValue)
|
|
if(debouncedValue && debouncedValue.length > 0){
|
|
fetchAutoCompleteResults()
|
|
}
|
|
}, [debouncedValue]);
|
|
|
|
const handleInputChange = e => {
|
|
const val = e.target.value;
|
|
setInputValue(val);
|
|
};
|
|
|
|
const handleOnKeyDown = event => {
|
|
if (event.key && event.key === 'Enter' && inputValue.length > 0) {
|
|
setShowDropdown(false);
|
|
onEnter(inputValue);
|
|
}
|
|
};
|
|
|
|
const handleOnClick = track => {
|
|
onSelect(track);
|
|
handleAfterSelect();
|
|
};
|
|
|
|
const handleAfterSelect = () => {
|
|
setShowDropdown(false);
|
|
inputRef.current.focus();
|
|
setInputValue('');
|
|
};
|
|
|
|
const highlight = event => {
|
|
event.target.classList.add('bg-light');
|
|
};
|
|
|
|
const unhighlight = event => {
|
|
event.target.classList.remove('bg-light');
|
|
};
|
|
|
|
return (
|
|
<Row className="">
|
|
<Col md={12}>
|
|
<FormGroup className="mb-3">
|
|
<div className="d-flex align-items-center">
|
|
<InputGroup>
|
|
<InputGroupText style={{ borderRadius: '0', borderRight: '0' }}>
|
|
{loading ? (
|
|
<span className="spinner-grow spinner-grow-sm" aria-hidden="true" />
|
|
) : (
|
|
<FontAwesomeIcon icon="search" transform="shrink-4 down-1" />
|
|
)}
|
|
</InputGroupText>
|
|
|
|
<Input
|
|
onChange={handleInputChange}
|
|
onKeyDown={handleOnKeyDown}
|
|
value={inputValue}
|
|
innerRef={inputRef}
|
|
placeholder={inputPlaceholder}
|
|
data-testid="autocomplete-text"
|
|
type="search"
|
|
/>
|
|
</InputGroup>
|
|
</div>
|
|
|
|
<ListGroup className={showDropdown ? 'd-block' : 'd-none'} data-testid="autocomplete-list">
|
|
{artists.map((track, index) => (
|
|
<ListGroupItem
|
|
key={`${index}-${track.original_artist}`}
|
|
onMouseOver={highlight}
|
|
onMouseOut={unhighlight}
|
|
onClick={() => handleOnClick(track)}
|
|
style={{ cursor: 'pointer' }}
|
|
>
|
|
Artist: {track.original_artist}
|
|
</ListGroupItem>
|
|
))}
|
|
{songs.map(track => (
|
|
<ListGroupItem
|
|
key={track.id}
|
|
onMouseOver={highlight}
|
|
onMouseOut={unhighlight}
|
|
onClick={() => handleOnClick(track)}
|
|
style={{ cursor: 'pointer' }}
|
|
>
|
|
Song: {track.name} by {track.original_artist}
|
|
</ListGroupItem>
|
|
))}
|
|
</ListGroup>
|
|
</FormGroup>
|
|
</Col>
|
|
</Row>
|
|
);
|
|
};
|
|
|
|
JKJamTracksAutoComplete.propTypes = {
|
|
fetchFunc: PropTypes.func.isRequired,
|
|
onSelect: PropTypes.func.isRequired,
|
|
onEnter: PropTypes.func.isRequired,
|
|
showDropdown: PropTypes.bool.isRequired,
|
|
setShowDropdown: PropTypes.func.isRequired,
|
|
inputValue: PropTypes.string.isRequired,
|
|
setInputValue: PropTypes.func.isRequired,
|
|
inputPlaceholder: PropTypes.string.isRequired
|
|
};
|
|
|
|
JKJamTracksAutoComplete.defaultProps = {
|
|
onSelect: () => {},
|
|
onEnter: () => {},
|
|
showDropdown: false,
|
|
setShowDropdown: () => {},
|
|
inputValue: '',
|
|
setInputValue: () => {},
|
|
inputPlaceholder: ''
|
|
};
|
|
|
|
export default React.memo(JKJamTracksAutoComplete);
|