2020-07-23 09:43:12 +00:00
|
|
|
import React, { useState, useCallback, useEffect } from 'react';
|
2020-07-22 10:49:22 +00:00
|
|
|
import { Grommet } from 'grommet';
|
2020-07-23 09:43:12 +00:00
|
|
|
import { debounce } from 'lodash';
|
|
|
|
import { gql, useLazyQuery } from '@apollo/client';
|
|
|
|
|
2020-07-22 13:57:37 +00:00
|
|
|
import { Header } from './Header';
|
2020-07-23 09:43:12 +00:00
|
|
|
import { Search } from './Search';
|
|
|
|
import { Results } from './Results';
|
|
|
|
import { Artists, Artist } from '../interfaces';
|
2020-07-22 10:49:22 +00:00
|
|
|
|
2020-07-23 14:23:15 +00:00
|
|
|
const QUERY_ARTISTS = gql`
|
2020-07-23 09:43:12 +00:00
|
|
|
query Artist($byName: String!) {
|
|
|
|
queryArtists(byName: $byName) {
|
|
|
|
name
|
|
|
|
image
|
|
|
|
id
|
|
|
|
albums {
|
|
|
|
name
|
|
|
|
image
|
|
|
|
id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`;
|
|
|
|
|
|
|
|
export default function App() {
|
|
|
|
const [inputValue, setInputValue] = useState('');
|
2020-07-23 14:23:15 +00:00
|
|
|
const [getArtists, { data }] = useLazyQuery(QUERY_ARTISTS);
|
2020-07-23 17:53:47 +00:00
|
|
|
const [artists, setArtists] = useState<Artists>([]);
|
2020-07-24 11:58:02 +00:00
|
|
|
const [suggestions, setSuggestions] = useState<string[]>([]);
|
2020-07-23 12:23:26 +00:00
|
|
|
const [selected, setSelected] = useState(false);
|
2020-07-23 09:43:12 +00:00
|
|
|
|
|
|
|
// Debounce the database query
|
2020-07-23 12:07:29 +00:00
|
|
|
// Based on: https://archive.is/wip/6JDqb
|
2020-07-24 11:58:02 +00:00
|
|
|
const handleChange = (value: string) => {
|
|
|
|
setInputValue(value);
|
2020-07-23 17:53:47 +00:00
|
|
|
};
|
|
|
|
|
2020-07-23 09:43:12 +00:00
|
|
|
const updateQuery = () => {
|
|
|
|
getArtists({ variables: { byName: inputValue } });
|
|
|
|
};
|
2020-07-23 17:53:47 +00:00
|
|
|
|
2020-07-24 11:58:02 +00:00
|
|
|
const delayedQuery = useCallback(debounce(updateQuery, 200), [inputValue]);
|
2020-07-23 17:53:47 +00:00
|
|
|
|
2020-07-23 09:43:12 +00:00
|
|
|
useEffect(() => {
|
|
|
|
delayedQuery();
|
|
|
|
// Cancel previous debounce calls during useEffect cleanup.
|
|
|
|
return delayedQuery.cancel;
|
|
|
|
}, [inputValue, delayedQuery]);
|
2020-07-23 12:23:26 +00:00
|
|
|
|
2020-07-24 11:58:02 +00:00
|
|
|
const handleSelect = (suggestion: string) => {
|
2020-07-23 17:53:47 +00:00
|
|
|
let updatedArtists: Artists = [];
|
|
|
|
|
2020-07-24 11:58:02 +00:00
|
|
|
let suggestedArtists: Artists = data.queryArtists.slice(0, 5);
|
2020-07-23 14:23:15 +00:00
|
|
|
|
|
|
|
// Find the selected artist and move it to index 0
|
2020-07-23 17:53:47 +00:00
|
|
|
for (let i = 0; i < suggestedArtists!.length; i++) {
|
2020-07-24 11:58:02 +00:00
|
|
|
if (suggestedArtists![i].name === suggestion) {
|
2020-07-23 17:53:47 +00:00
|
|
|
let selectedArtist: Artists = suggestedArtists?.splice(i, 1);
|
|
|
|
let otherArtists: Artists = suggestedArtists;
|
|
|
|
updatedArtists = [...selectedArtist, ...otherArtists];
|
2020-07-23 14:23:15 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setArtists(updatedArtists);
|
2020-07-23 12:23:26 +00:00
|
|
|
setSelected(true);
|
|
|
|
};
|
|
|
|
|
2020-07-24 11:58:02 +00:00
|
|
|
const handleClick = (name: string) => {
|
|
|
|
let updatedArtists: Artists = [];
|
|
|
|
|
|
|
|
for (let i = 0; i < artists.length; i++) {
|
|
|
|
if (artists[i].name === name) {
|
|
|
|
let selectedArtist: Artists = artists.splice(i, 1);
|
|
|
|
let otherArtists: Artists = artists;
|
|
|
|
updatedArtists = [...selectedArtist, ...otherArtists];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setArtists(updatedArtists);
|
|
|
|
};
|
2020-07-23 23:10:57 +00:00
|
|
|
|
2020-07-23 09:43:12 +00:00
|
|
|
useEffect(() => {
|
|
|
|
if (data && data.queryArtists !== []) {
|
|
|
|
// Limit artists to 5
|
|
|
|
const updatedArtists = data.queryArtists.slice(0, 5);
|
|
|
|
const updatedSuggestions: string[] = updatedArtists.map(
|
|
|
|
(el: Artist) => {
|
|
|
|
return el.name;
|
|
|
|
},
|
|
|
|
);
|
|
|
|
setSuggestions(updatedSuggestions);
|
|
|
|
}
|
|
|
|
}, [data]);
|
2020-07-22 09:57:07 +00:00
|
|
|
|
|
|
|
return (
|
2020-07-22 10:49:22 +00:00
|
|
|
<Grommet theme={theme}>
|
2020-07-22 13:57:37 +00:00
|
|
|
<Header>
|
|
|
|
<h1>Spoti Search</h1>
|
|
|
|
</Header>
|
2020-07-23 09:43:12 +00:00
|
|
|
<Search
|
|
|
|
inputValue={inputValue}
|
|
|
|
handleChange={handleChange}
|
|
|
|
suggestions={suggestions}
|
2020-07-23 12:23:26 +00:00
|
|
|
handleSelect={handleSelect}
|
2020-07-23 09:43:12 +00:00
|
|
|
/>
|
2020-07-24 11:58:02 +00:00
|
|
|
{selected && (
|
|
|
|
<Results artists={artists} handleClick={handleClick} />
|
|
|
|
)}
|
2020-07-22 10:49:22 +00:00
|
|
|
</Grommet>
|
2020-07-22 09:57:07 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-07-23 09:43:12 +00:00
|
|
|
const theme = {
|
|
|
|
global: {
|
|
|
|
font: {
|
|
|
|
family: 'Roboto',
|
|
|
|
size: '18px',
|
|
|
|
height: '20px',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|