Files
crates/crates/components/search.tsx
T
2025-04-25 19:01:47 +10:00

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;