move to koa and add user pages

This commit is contained in:
ntr committed 2022-08-07 14:27:13 +10:00
1 parent b4114a2440
commit bd32044427
11 files changed
+1079 -107

No files matched your search

+7
View File
@@ -5,6 +5,13 @@ const actions = store => ({
const { data: bundles } = await axios.get('http://localhost:41337/bundles'); const { data: bundles } = await axios.get('http://localhost:41337/bundles');
return { bundles }; return { bundles };
}, },
getUserOffers: async (state, userId) => {
store.setState({ offers: [] });
const { data: offers } = await axios.get(`http://localhost:41337/user/${userId}/offers`);
console.log(userId, offers);
return { offers };
},
}); });
export default actions; export default actions;
+2 -3
View File
@@ -8,7 +8,7 @@ import actions from './actions';
import Header from './components/header'; import Header from './components/header';
import Home from './routes/home'; import Home from './routes/home';
import Profile from './routes/profile'; import User from './routes/user';
const store = mcratesStore(); const store = mcratesStore();
@@ -20,8 +20,7 @@ const App = () => (
<Header /> <Header />
<Router> <Router>
<Route path="/" component={Home} /> <Route path="/" component={Home} />
<Route path="/profile/" component={Profile} user="me" /> <Route path="/user/:userId" component={User} />
<Route path="/profile/:user" component={Profile} />
</Router> </Router>
</div> </div>
</Provider> </Provider>
+22
View File
@@ -0,0 +1,22 @@
import { h } from 'preact';
export default function Bundle(bundle) {
console.log(bundle);
return (
<div class="bundle">
<h2>{bundle.username} - {bundle.seller}</h2>
<h3>{bundle.items.length} items - {bundle.total} {bundle.currency}</h3>
<h4>Ships: {bundle.mentionsAustralia && 'AU'} {bundle.mentionsWorldwide && 'WORLD'}</h4>
{bundle.items.map(i => (
<div key={i.id}>
<a href={i.uri}>
<h4>{i.description}</h4>
</a>
<h5>{i.user.name}</h5>
<h5>{i.price} {i.currency}</h5>
<hr />
</div>
))}
</div>
)
}
+4 -2
View File
@@ -6,8 +6,10 @@ const Header = () => (
<h1>Mates Crates</h1> <h1>Mates Crates</h1>
<nav> <nav>
<Link activeClassName={'active'} href="/">Home</Link> <Link activeClassName={'active'} href="/">Home</Link>
<Link activeClassName={'active'} href="/profile">Me</Link> <Link activeClassName={'active'} href="/user/cf2384d7-f67f-45a3-a522-68e847345073">ntr</Link>
<Link activeClassName={'active'} href="/profile/john">John</Link> <Link activeClassName={'active'} href="/user/0ad6c6fc-4637-4ea6-9ecc-d0dcdc7f2da2">jen</Link>
<Link activeClassName={'active'} href="/user/ac132ae3-7876-4877-ace4-c0d96a2e4174">james</Link>
<Link activeClassName={'active'} href="/user/aa2b287d-ea3f-443a-8559-e1477b8fec07">rhys</Link>
</nav> </nav>
</header> </header>
); );
+1 -23
View File
@@ -2,35 +2,13 @@ import { h } from 'preact';
import { connect } from 'unistore/preact' import { connect } from 'unistore/preact'
import actions from './../actions'; import actions from './../actions';
import Bundle from './../components/bundle';
// import Bundle from './../components/bundle';
interface Props { interface Props {
bundles: any[]; bundles: any[];
getBundles: () => void, getBundles: () => void,
} }
function Bundle(bundle) {
return (
<div class="bundle">
<h2>{bundle.username} - {bundle.seller}</h2>
<h3>{bundle.items.length} items - {bundle.total} {bundle.currency}</h3>
<h4>Ships: {bundle.mentionsAustralia && 'AU'} {bundle.mentionsWorldwide && 'WORLD'}</h4>
{bundle.items.map(i => (
<div key={i.id}>
<a href={i.uri}>
<h4>{i.description}</h4>
</a>
<h5>{i.user}</h5>
<h5>{i.price} {i.currency}</h5>
<hr />
</div>
))}
</div>
)
}
function Home({ bundles, getBundles }: Props) { function Home({ bundles, getBundles }: Props) {
if (!bundles.length) { if (!bundles.length) {
getBundles(); getBundles();
-35
View File
@@ -1,35 +0,0 @@
import { h } from 'preact';
import { useEffect, useState } from 'preact/hooks';
import style from './style.less';
interface Props {
user: string;
}
const Profile = ({ user }: Props) => {
const [time, setTime] = useState<number>(Date.now());
const [count, setCount] = useState<number>(0);
useEffect(() => {
let timer = setInterval(() => setTime(Date.now()), 1000);
return () => clearInterval(timer);
}, []);
return (
<div class={'profile'}>
<h1>Profile: {user}</h1>
<p>This is the user profile for a user named { user }.</p>
<div>Current time: {new Date(time).toLocaleString()}</div>
<p>
<button onClick={() => setCount((count) => count + 1)}>Click Me</button>
{' '}
Clicked {count} times.
</p>
</div>
);
};
export default Profile;
+44
View File
@@ -0,0 +1,44 @@
import { h } from 'preact';
import { useState, useEffect } from 'preact/hooks';
import { connect } from 'unistore/preact';
import axios from 'axios';
import style from './style.less';
import actions from './../actions';
import Bundle from './../components/bundle';
interface Props {
userId: string,
offers: any[],
getUserOffers: (userId: string) => void,
}
const User = ({ userId }: Props) => {
const [offers, setOffers] = useState([]);
useEffect(() => {
async function fetchOffers() {
const { data } = await axios.get(`http://localhost:41337/user/${userId}/offers`);
setOffers(data);
}
fetchOffers();
}, [userId]);
if (!offers.length) {
return (
<div class={'home'}>
loading...
</div>
);
}
return (
<div class={'home'}>
{offers.map(Bundle)}
</div>
);
};
export default connect(['offers'], actions)(User);
+4 -1
View File
@@ -1,6 +1,9 @@
import createStore from 'unistore' import createStore from 'unistore'
export default function mcratesStore() { export default function mcratesStore() {
return createStore({ bundles: [] }) return createStore({
bundles: [],
offers: []
});
} }
+942 -12
View File
File diff suppressed because it is too large. Load diff
+5 -2
View File
@@ -14,18 +14,21 @@
"devDependencies": { "devDependencies": {
"@types/bluebird": "^3.5.36", "@types/bluebird": "^3.5.36",
"@types/lodash": "^4.14.182", "@types/lodash": "^4.14.182",
"@types/koa": "^2.13.5",
"node-dev": "^7.4.3", "node-dev": "^7.4.3",
"prisma": "^4.1.0", "prisma": "^4.1.0",
"ts-node-dev": "^2.0.0", "ts-node-dev": "^2.0.0",
"typescript": "^4.7.4" "typescript": "^4.7.4"
}, },
"dependencies": { "dependencies": {
"@koa/cors": "^3.3.0",
"@koa/router": "^12.0.0",
"@prisma/client": "^4.1.0", "@prisma/client": "^4.1.0",
"axios": "^0.27.2", "axios": "^0.27.2",
"bluebird": "^3.7.2", "bluebird": "^3.7.2",
"bunyan": "^1.8.15", "bunyan": "^1.8.15",
"cors": "^2.8.5", "koa": "^2.13.4",
"express": "^4.18.1", "koa-body": "^5.0.0",
"lodash": "^4.17.21" "lodash": "^4.17.21"
} }
} }
+48 -29
View File
@@ -1,6 +1,8 @@
import express from 'express'; import koa from 'koa';
import bodyParser from 'koa-body';
import koaRouter from '@koa/router'
import cors from '@koa/cors';
import http from 'http'; import http from 'http';
import cors from 'cors';
import { groupBy } from 'lodash'; import { groupBy } from 'lodash';
import Bluebird from 'bluebird'; import Bluebird from 'bluebird';
@@ -12,8 +14,21 @@ import type { Listing, User, Want, Prisma } from '@prisma/client';
export default function createApi(log: Log, pg: Pg, discogs) { export default function createApi(log: Log, pg: Pg, discogs) {
const PORT = 41337; const PORT = 41337;
const app = express(); const app = new koa();
const server = http.createServer(app);
app.use(async (ctx, next) => {
try {
await next();
} catch (err) {
log.error(err);
ctx.status = err.statusCode || err.status || 500;
ctx.body = {
message: err.message
};
}
});
const router = koaRouter();
interface ListingData extends Listing { interface ListingData extends Listing {
data: any, data: any,
@@ -33,13 +48,11 @@ export default function createApi(log: Log, pg: Pg, discogs) {
currency: l.data.original_price.curr_abbr, currency: l.data.original_price.curr_abbr,
condition: l.data.condition, condition: l.data.condition,
uri: l.data.uri, uri: l.data.uri,
user: l.want.user.name, user: l.want.user,
})); }));
const shipping = b[0]?.data.seller.shipping; const shipping = b[0]?.data.seller.shipping;
console.log(b.map(l => l.data));
const bundle = { const bundle = {
username: b[0]?.data.seller.username, username: b[0]?.data.seller.username,
seller: b[0]?.data.seller.id, seller: b[0]?.data.seller.id,
@@ -78,56 +91,62 @@ export default function createApi(log: Log, pg: Pg, discogs) {
function listen() { function listen() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
server.on('error', err => { app.on('error', err => {
reject(err); reject(err);
}) })
server.listen(PORT, () => { app.listen(PORT, () => {
log.info('listening', { PORT }); log.info('listening', { PORT });
}); });
}); });
} }
app.use(cors()); app.use(cors());
app.use(express.json()) app.use(bodyParser())
app.get('/bundles', async (req, res, next) => { router.get('/bundles', async (ctx, next) => {
const bundles = await getBundles(); const bundles = await getBundles();
// log.info(bundles); ctx.response.body = bundles;
res.json(bundles);
}) })
app.get('/user/:id/offers', async function userOffersGet(req, res, next) { router.get('/user/:id/offers', async function userOffersGet(ctx, next) {
const { id } = req.params; const { id } = ctx.request.params;
const user = await pg.userFindId(id); const user = await pg.userFindId(id);
res.json(user);
// if (!user) return ctx.response.status = 404;
const bundles = (await getBundles())
.map(b => {
b.items = b.items.filter(i => i.user.id === user.id)
return b;
})
.filter(b => b.items.length);
ctx.response.body = bundles;
}); });
app.post('/user', async function usersPost(req, res, next) { router.post('/user', async function usersPost(ctx, next) {
const { name } = req.body; const { name } = ctx.request.body;
const user = await pg.userUpsert(null, name, null); const user = await pg.userUpsert(null, name, null);
res.json(user); ctx.response.body = user;
}); });
app.post('/user/populate', async function usersPopulate(req, res, next) { router.post('/user/populate', async function usersPopulate(ctx, next) {
const { userId } = req.body; const { userId } = ctx.request.body;
const user = await pg.userFindId(userId); const user = await pg.userFindId(userId);
const listings = await populateUserListings(user); const listings = await populateUserListings(user);
res.json(listings); ctx.response.body = listings;
}); });
app.post('/want', async function wantPost(req, res, next) { router.post('/want', async function wantPost(ctx, next) {
const { userId, releaseId } = req.body; const { userId, releaseId } = ctx.request.body;
const user = await pg.userFindId(userId); const user = await pg.userFindId(userId);
const release = await discogs.release(releaseId); const release = await discogs.release(releaseId);
const want = await pg.wantUpsert(release, user); const want = await pg.wantUpsert(release, user);
return res.json(want); ctx.response.body = want;
}); });
app.use(function errorHandler(req, res, next, error) { app.use(router.routes());
log.warn(error);
res.status(500).send({ error });
});
return { return {
app, app,