move to koa and add user pages
This commit is contained in:
1 parent
b4114a2440
commit
bd32044427
11 files changed
+1079
-107
No files matched your search
@@ -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
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
|
||||||
@@ -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);
|
||||||
@@ -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: []
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Generated
+942
-12
File diff suppressed because it is too large.
Load diff
+5
-2
@@ -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
@@ -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,
|
||||||
|
|||||||
Reference in new issue
Block a user