want events

This commit is contained in:
ntr committed 2022-08-17 23:22:48 +10:00
1 parent f5e75f4fe6
commit 30bf7426e4
19 files changed
+293 -108

No files matched your search

+1
View File
@@ -0,0 +1 @@
This application uses Discogs’ API but is not affiliated with, sponsored or endorsed by Discogs. ‘Discogs’ is a trademark of Zink Media, LLC.
+23 -9
View File
@@ -12,6 +12,7 @@
"preact": "^10.10.0",
"preact-render-to-string": "^5.2.1",
"preact-router": "^3.2.1",
"react-feather": "^2.0.10",
"react-redux": "^8.0.2",
"redux": "^4.2.0",
"unistore": "^3.5.2"
@@ -12778,7 +12779,6 @@
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -15798,7 +15798,6 @@
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"dev": true,
"dependencies": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
@@ -15808,8 +15807,7 @@
"node_modules/prop-types/node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"dev": true
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"node_modules/proxy-addr": {
"version": "2.0.7",
@@ -16113,6 +16111,17 @@
"node": ">=0.10.0"
}
},
"node_modules/react-feather": {
"version": "2.0.10",
"resolved": "https://registry.npmjs.org/react-feather/-/react-feather-2.0.10.tgz",
"integrity": "sha512-BLhukwJ+Z92Nmdcs+EMw6dy1Z/VLiJTzEQACDUEnWMClhYnFykJCGWQx+NmwP/qQHGX/5CzQ+TGi8ofg2+HzVQ==",
"dependencies": {
"prop-types": "^15.7.2"
},
"peerDependencies": {
"react": ">=16.8.6"
}
},
"node_modules/react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
@@ -31062,8 +31071,7 @@
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"dev": true
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
},
"object-copy": {
"version": "0.1.0",
@@ -33326,7 +33334,6 @@
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"dev": true,
"requires": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
@@ -33336,8 +33343,7 @@
"react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"dev": true
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
}
}
},
@@ -33580,6 +33586,14 @@
"loose-envify": "^1.1.0"
}
},
"react-feather": {
"version": "2.0.10",
"resolved": "https://registry.npmjs.org/react-feather/-/react-feather-2.0.10.tgz",
"integrity": "sha512-BLhukwJ+Z92Nmdcs+EMw6dy1Z/VLiJTzEQACDUEnWMClhYnFykJCGWQx+NmwP/qQHGX/5CzQ+TGi8ofg2+HzVQ==",
"requires": {
"prop-types": "^15.7.2"
}
},
"react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+1
View File
@@ -22,6 +22,7 @@
"preact": "^10.10.0",
"preact-render-to-string": "^5.2.1",
"preact-router": "^3.2.1",
"react-feather": "^2.0.10",
"react-redux": "^8.0.2",
"redux": "^4.2.0",
"unistore": "^3.5.2"
+9 -1
View File
@@ -49,7 +49,15 @@ const actions = {
},
getWants: async function getWants() {
return api.get('/wants');
return api.get('/want/all');
},
postWant: async function postWant(releaseId) {
return api.post('/want', { releaseId });
},
postDiscogs: async function postDiscogs(username) {
return api.post('/want/discogs', { username });
},
getLogin: async function getLogin() {
+4 -2
View File
@@ -9,7 +9,8 @@ import Header from './components/header';
import Home from './routes/home';
import Login from './routes/login';
import Search from './routes/search';
import User from './routes/user';
import List from './routes/list';
import Offers from './routes/offers';
function App() {
const [user, setUser] = useState(null);
@@ -38,7 +39,8 @@ function App() {
<Route path="/" component={Home} />
<Route path="/login" component={Login} success={loginSuccess} />
<Route path="/search" component={Search} />
<Route path="/list/" component={User} user={user} />
<Route path="/list" component={List} user={user} />
<Route path="/offers" component={Offers} user={user} />
</Router>
</main>
);
+1 -1
View File
@@ -4,7 +4,7 @@ import { Link } from 'preact-router/match';
const Header = ({ user }) => {
const nav = () => (
<nav>
<a href="/search">Offers</a>
<a href="/">Offers</a>
<a href='/list'>List</a>
<a href="/search">Search</a>
</nav>
+20
View File
@@ -0,0 +1,20 @@
import { h } from 'preact';
function Want(want) {
console.log(want);
const r = want.data;
return (
<article key={r.id}>
<div>
<h3>{r.artists_sort} - {r.title}</h3>
<h5 class='alt-text' >{r.year}</h5>
<h5 class='alt-text'>{r.country}</h5>
<h5 class='alt-text'>{r.formats[0].descriptions.join(' ')}</h5>
</div>
<img src={r.thumb} />
</article>
);
}
export default Want;
+7 -2
View File
@@ -4,12 +4,17 @@ import { useState, useEffect } from 'preact/hooks';
import actions from './../actions';
import Bundle from './../components/bundle';
function Home() {
const [bundles, setBundles] = useState([]);
useEffect(() => {
actions.getBundles().then(setBundles);
async function getBundles() {
const [error, bundles] = await actions.getBundles();
if (error) return console.error(error);
console.log(bundles, 'bundles')
setBundles(bundles);
}
getBundles();
}, []);
if (!bundles.length) {
@@ -3,40 +3,37 @@ import { useState, useEffect } from 'preact/hooks';
// import style from './style.less';
import actions from './../actions';
import Bundle from './../components/bundle';
import Want from './../components/want';
interface Props {
user: any,
offers: any[],
wants: any[],
getUserOffers: (userId: string) => void,
}
const User = ({ user }: Props) => {
const [offers, setOffers] = useState([]);
const List = ({ user }: Props) => {
const [wants, setOffers] = useState([]);
useEffect(() => {
async function getWants() {
const [error, wants] = await actions.getWants();
if (error) return console.error(error);
console.log(wants, 'wants')
setOffers(wants);
}
getWants();
}, []);
if (!offers.length) {
return (
<div class={'home'}>
loading...
</div>
);
if (!wants.length) {
return <div> loading... </div>;
}
return (
<div class={'home'}>
{offers.map(Bundle)}
<div class="list">
{wants.map(Want)}
</div>
);
};
export default User;
export default List;
+70
View File
@@ -0,0 +1,70 @@
import { h } from 'preact';
import { useState } from 'preact/hooks';
import axios from 'axios';
import actions from '../actions';
function result(r) {
function onClick() {
actions.postWant(r.id);
}
return (
<article key={r.id}>
<button onClick={onClick}> + </button>
<div>
<h3>{r.title}</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 [results, setResults] = useState([]);
const [noResults, setNoResults] = useState(false);
async function fetchResults() {
const { data } = await actions.getBundles();
console.log(data);
if (data.length === 0) {
setResults([]);
return setNoResults(true);
}
setNoResults(false);
setResults(data);
}
function handleSubmit(e) {
e.preventDefault();
fetchResults();
}
const topEl = results.length
? <button onClick={() => window.scrollTo(0, 0)}> top </button>
: null;
const noResultsEl = noResults
? <article>No Results</article>
: null;
return (
<div class='search'>
<div></div>
<div></div>
<div>
{noResultsEl}
{results.map(result)}
{topEl}
</div>
</div>
);
};
export default User;
+42 -11
View File
@@ -1,13 +1,20 @@
import { h } from 'preact';
import { useState } from 'preact/hooks';
import axios from 'axios';
import { ExternalLink } from 'react-feather';
import actions from '../actions';
function result(r) {
function onClick() {
actions.postWant(r.id);
}
return (
<article key={r.id}>
<button> + </button>
<button onClick={onClick}> + </button>
<div>
<h3>{r.title}</h3>
<h3>{r.title} <a href={`https://discogs.com${r.uri}`}><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>
@@ -20,11 +27,12 @@ function result(r) {
const User = () => {
const [artist, setArtist] = useState('nine inch nails')
const [title, setTitle] = useState('the fragile');
const [username, setUsername] = useState('');
const [results, setResults] = useState([]);
const [noResults, setNoResults] = useState(false);
async function fetchResults() {
const { data } = await axios.post(`http://localhost:41337/wants/search`, {
const { data } = await axios.post(`http://localhost:41337/want/search`, {
artist,
title,
});
@@ -40,11 +48,22 @@ const User = () => {
setResults(data);
}
async function submitWantlist() {
const [error, wants] = await actions.postDiscogs(username);
// setNoResults(false);
// setResults(data);
}
function handleSubmit(e) {
e.preventDefault();
fetchResults();
}
function handleDiscogsSubmit(e) {
e.preventDefault();
submitWantlist();
}
const topEl = results.length
? <button onClick={() => window.scrollTo(0, 0)}> top </button>
: null;
@@ -55,14 +74,26 @@ const User = () => {
return (
<div class='search'>
<form action="" method="get">
<label for="artist">Artist</label>
<input type="text" name="artist" placeholder="Ben Klock" id="artist" value={artist} onChange={e => setArtist(e.target.value) } required />
<label for="title">Title</label>
<input type="text" name="title" placeholder="Subzero" id="title" value={title} onChange={e => setTitle(e.target.value)} required />
<input type="submit" value="Search" onClick={handleSubmit} />
</form>
<div></div>
<div>
<form action="" method="get">
<label for="artist">Artist</label>
<input type="text" name="artist" placeholder="Ben Klock" id="artist" value={artist} onChange={e => setArtist(e.target.value) } required />
<label for="title">Title</label>
<input type="text" name="title" placeholder="Subzero" id="title" value={title} onChange={e => setTitle(e.target.value)} required />
<input type="submit" value="Search" onClick={handleSubmit} />
</form>
<p>Data provided by Discogs.</p>
<hr />
<div>
<p>Sync Discogs Wantlist</p>
<form action="" method="get">
<label for="Discogs">Discogs Username</label>
<input type="text" name="username" placeholder="username" id="username" value={username} onChange={e => setUsername(e.target.value) } required />
<input type="submit" value="Search" onClick={handleDiscogsSubmit} />
</form>
</div>
</div>
<div />
<div>
{noResultsEl}
{results.map(result)}
+23 -9
View File
@@ -180,22 +180,36 @@ button, [type=submit] {
text-transform: uppercase;
}
article {
background-color: var(--secondary-background-color);
}
.search {
display: grid;
grid-template-columns: 1fr 0.5fr 2fr;
article {
display: grid;
grid-template-columns: 1fr 4fr 1fr;
background-color: var(--secondary-background-color);
padding: var(--base-spacing);
margin-bottom: var(--base-spacing);
grid-template-columns: 1fr 4fr 1fr;
}
button {
margin-right: var(--base-spacing);
background: var(--tertiary-background-color);
border-color: var(--secondary-background-color);
}
button {
margin-right: var(--base-spacing);
background: var(--tertiary-background-color);
border-color: var(--secondary-background-color);
}
}
.list {
display: flex;
article {
flex: 1;
padding: var(--base-spacing);
margin: var(--base-spacing-half);
}
}
@@ -246,11 +260,11 @@ header {
}
.home {
display: grid;
grid-template-columns: 1fr 0.5fr 2fr;
display: flex;
.bundle {
flex: 1;
padding-right: 1em;
}
}