spoti-search/src/components/App.tsx

125 lines
2.9 KiB
TypeScript
Raw Normal View History

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
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('');
const [getArtists, { data }] = useLazyQuery(QUERY_ARTISTS);
const [artists, setArtists] = useState<Artists>([]);
const [suggestions, setSuggestions] = useState<string[]>([]);
const [selected, setSelected] = useState(false);
2020-07-23 09:43:12 +00:00
// Debounce the database query
// Based on: https://archive.is/wip/6JDqb
const handleChange = (value: string) => {
setInputValue(value);
};
2020-07-23 09:43:12 +00:00
const updateQuery = () => {
getArtists({ variables: { byName: inputValue } });
};
const delayedQuery = useCallback(debounce(updateQuery, 200), [inputValue]);
2020-07-23 09:43:12 +00:00
useEffect(() => {
delayedQuery();
// Cancel previous debounce calls during useEffect cleanup.
return delayedQuery.cancel;
}, [inputValue, delayedQuery]);
const handleSelect = (suggestion: string) => {
let updatedArtists: Artists = [];
let suggestedArtists: Artists = data.queryArtists.slice(0, 5);
// Find the selected artist and move it to index 0
for (let i = 0; i < suggestedArtists!.length; i++) {
if (suggestedArtists![i].name === suggestion) {
let selectedArtist: Artists = suggestedArtists?.splice(i, 1);
let otherArtists: Artists = suggestedArtists;
updatedArtists = [...selectedArtist, ...otherArtists];
break;
}
}
setArtists(updatedArtists);
setSelected(true);
};
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 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}
handleSelect={handleSelect}
2020-07-23 09:43:12 +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',
},
},
};