jam-cloud/jam-ui/src/components/jamtracks/JKJamTracksAutoComplete.js

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);