127 lines
3.9 KiB
TypeScript
127 lines
3.9 KiB
TypeScript
import { h } from 'preact';
|
|
import { useState, useRef, useEffect } from 'preact/hooks';
|
|
import { ExternalLink, Check } from 'react-feather';
|
|
import { useSelector } from 'react-redux'
|
|
|
|
import { State } from './../store';
|
|
import { info, error as toastError } from './../toast';
|
|
|
|
import http from '../http';
|
|
|
|
function Result(r, wants, ws) {
|
|
async function onClick() {
|
|
ws.sendWantAdd(r.id);
|
|
}
|
|
|
|
// releaseIds are bigints on server
|
|
const wanted = wants.some(w => BigInt(w.release) === BigInt(r.id));
|
|
|
|
const classes = `${wanted ? 'added' : ''}`;
|
|
const btnText = wanted
|
|
? <Check />
|
|
: '+';
|
|
|
|
return (
|
|
<article key={r.id}>
|
|
<button onClick={onClick} disabled={wanted} class={classes} >{btnText}</button>
|
|
<div>
|
|
<h3>{r.title} <a href={`https://discogs.com${r.uri}`} target="_blank" rel="noreferrer"><ExternalLink /></a></h3>
|
|
<h5 class='alt-text' >{r.year}</h5>
|
|
<h5 class='alt-text'>{r.country}</h5>
|
|
<h5 class='alt-text'>{r.format.join(' ')}</h5>
|
|
</div>
|
|
<img src={r.thumb} />
|
|
</article>
|
|
);
|
|
}
|
|
|
|
const User = () => {
|
|
const [query, setQuery] = useState('')
|
|
const [username, setUsername] = useState('');
|
|
const [results, setResults] = useState([]);
|
|
|
|
const wants = useSelector((state: State) => state.wants);
|
|
const ws = useSelector((state: State) => state.ws);
|
|
|
|
async function fetchResults() {
|
|
const [error, results] = await http.postWantSearch(query);
|
|
|
|
if (error) {
|
|
setResults([]);
|
|
toastError('Error', error);
|
|
}
|
|
|
|
if (results.length === 0) {
|
|
setResults([]);
|
|
return info('No Results', 'No results returned from search');
|
|
}
|
|
|
|
setResults(results);
|
|
}
|
|
|
|
async function submitWantlist() {
|
|
const [error, wants] = await http.postDiscogs(username);
|
|
|
|
if (error) {
|
|
setResults([]);
|
|
toastError('Error', error);
|
|
}
|
|
|
|
if (wants.length === 0) {
|
|
setResults([]);
|
|
return info('Success', 'No new additions');
|
|
}
|
|
|
|
info('Success', `Added ${wants.length} items to your list.`);
|
|
}
|
|
|
|
const searchRef = useRef<HTMLInputElement>();
|
|
const resultsRef = useRef<HTMLDivElement>();
|
|
|
|
useEffect(() => {
|
|
searchRef.current.focus()
|
|
}, [])
|
|
|
|
function handleSubmit(e) {
|
|
e.preventDefault();
|
|
fetchResults();
|
|
}
|
|
|
|
function handleDiscogsSubmit(e) {
|
|
e.preventDefault();
|
|
submitWantlist();
|
|
}
|
|
|
|
const topEl = results.length
|
|
? <button onClick={() => resultsRef.current.scrollTo(0, 0)}> top </button>
|
|
: null;
|
|
|
|
return (
|
|
<div class='search'>
|
|
<div>
|
|
<form action="" method="get">
|
|
<label for="query">Query</label>
|
|
<input type="text" name="query" ref={searchRef} placeholder="ben klock subzero" id="query" value={query} onChange={e => setQuery((e.target as HTMLInputElement).value) } required />
|
|
<input type="submit" value="Search" onClick={handleSubmit} />
|
|
</form>
|
|
<hr />
|
|
<div>
|
|
<form action="" method="get">
|
|
<label for="Discogs">Discogs Username</label>
|
|
<input type="text" name="username" placeholder="Discogs Username" id="username" value={username} onChange={e => setUsername((e.target as HTMLInputElement).value) } required />
|
|
<input type="submit" value="Sync Wantlist" onClick={handleDiscogsSubmit} />
|
|
</form>
|
|
</div>
|
|
<hr />
|
|
<p>Data provided by Discogs.</p>
|
|
</div>
|
|
<div class='results' ref={resultsRef}>
|
|
{results.map(r => Result(r, wants, ws))}
|
|
{topEl}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default User;
|