diff --git a/api/src/api.ts b/api/src/api.ts index b7d59d4..2f2e056 100644 --- a/api/src/api.ts +++ b/api/src/api.ts @@ -22,17 +22,17 @@ export default function createApi(log: Log, pg: Pg, discogs) { const app = new koa(); const server = http.createServer(app.callback()); - // 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 - // }; - // } - // }); + app.use(async (ctx, next) => { + try { + await next(); + } catch (err) { + log.error(err); + ctx.status = err.statusCode || err.status || 500; + ctx.body = { + error: err.message + }; + } + }); const router = koaRouter(); @@ -128,7 +128,7 @@ export default function createApi(log: Log, pg: Pg, discogs) { const { id } = ctx.request.params; const user = await pg.userFindId(id); - // if (!user) return ctx.response.status = 404; + ctx.assert(user, 404, `user ${id} not found`); const bundles = (await getBundles()) .map(b => { diff --git a/api/src/auth.passport.ts b/api/src/auth.passport.ts deleted file mode 100644 index df1ca22..0000000 --- a/api/src/auth.passport.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { KoaPassport } from 'koa-passport'; -import { Strategy as LocalStrategy } from 'passport-local'; - -export default function authService(pg) { - const passport = new KoaPassport(); - - passport.serializeUser((user, done) => done(null, user.id)); - passport.deserializeUser((id, done) => { - pg.userFindId(id) - .then(u => done(null, u)) - .catch(e => done(e, null)); - }) - - passport.use(new LocalStrategy( - { usernameField: 'email '}, - function localStrategy(email, password, done) { - pg.userFindEmail(email) - .then(user => { - if (!user) return done(null, false); - // if (!user.verifyPassword(password)) return done(null, false); - return done(null, user); - }) - .catch(e => done(e, null)); - } - )); - - return passport; -} diff --git a/api/src/routers/router.auth.ts b/api/src/routers/router.auth.ts index 6b55cd9..c3e8f21 100644 --- a/api/src/routers/router.auth.ts +++ b/api/src/routers/router.auth.ts @@ -38,7 +38,7 @@ export default function authRouter(log, pg: Pg) { authRouter.post('/login', async (ctx, next) => { await passport.authenticate('local', (err, user, info, status) => { - ctx.assert(user, 401, { error: 'incorrect login' }); + ctx.assert(user, 401, 'incorrect login'); ctx.login(user); ctx.status = 200; @@ -50,11 +50,12 @@ export default function authRouter(log, pg: Pg) { }); authRouter.get('/login', async (ctx, next) => { - ctx.assert(ctx.isAuthenticated(), 401, { error: 'log in required' }); + ctx.assert(ctx.isAuthenticated(), 401, 'log in required'); const user = ctx.state.user; ctx.status = 200; ctx.body = { + id: user.id, email: user.email, discogs: user.discogs, }; @@ -68,6 +69,7 @@ export default function authRouter(log, pg: Pg) { ctx.login(user); ctx.status = 200; ctx.body = { + id: user.id, email: user.email, discogs: user.discogs, }; diff --git a/client/src/actions.ts b/client/src/actions.ts index b09002e..042d210 100644 --- a/client/src/actions.ts +++ b/client/src/actions.ts @@ -6,22 +6,22 @@ const api = axios.create({ }); const actions = { - getBundles: async () => { + getBundles: async function getBundles() { const { data: bundles } = await api.get('/bundles'); return bundles; }, - getUserOffers: async (state, userId) => { + getUserOffers: async function getUserOffers(state, userId) { const { data: offers } = await api.get(`/user/${userId}/offers`); return offers; }, - getOffers: async (userId) => { + getOffers: async function getOffers(userId) { const { data } = await api.get(`/user/${userId}/offers`); return data; }, - getLogin: async () => { + getLogin: async function getLogin() { try { const { data: user } = await api.get('/auth/login') console.log(user); @@ -31,16 +31,17 @@ const actions = { } }, - postLogin: async (email, password) => { + postLogin: async function postLogin(email, password) { const { data } = await api.post('/auth/login', { email, password, + // discogs, }); return data; }, - postRegister: async (email, password) => { + postRegister: async function postRegister(email, password) { const { data } = await api.post('/auth/register', { email, password, diff --git a/client/src/app.tsx b/client/src/app.tsx index 1c58479..9372b95 100644 --- a/client/src/app.tsx +++ b/client/src/app.tsx @@ -9,7 +9,6 @@ import Header from './components/header'; import Home from './routes/home'; import Login from './routes/login'; -import Register from './routes/register'; import Search from './routes/search'; import User from './routes/user'; @@ -22,6 +21,8 @@ function App() { async function getLogin() { const user = await actions.getLogin(); if (!user) return route('/login'); + setUser(user); + route('/'); } getLogin(); @@ -32,15 +33,15 @@ function App() { } return ( -
-
+
+
-
+ ); } diff --git a/client/src/components/header.tsx b/client/src/components/header.tsx index 461e13a..add4044 100644 --- a/client/src/components/header.tsx +++ b/client/src/components/header.tsx @@ -1,17 +1,21 @@ import { h } from 'preact'; import { Link } from 'preact-router/match'; -const Header = () => ( -
-

Mates Crates

+const Header = ({ user }) => { + const nav = () => ( -
-); + ); + + return ( +
+

N8CR8

+ {user ? nav() : null} +
+ ); +} export default Header; diff --git a/client/src/routes/login.tsx b/client/src/routes/login.tsx index a59b7ef..453a8e3 100644 --- a/client/src/routes/login.tsx +++ b/client/src/routes/login.tsx @@ -6,6 +6,8 @@ const Login = ({ success }) => { const [mode, setMode] = useState('login') const [email, setEmail] = useState('') const [password, setPassword] = useState(''); + // const [discogs, setDiscogs] = useState(''); + const [confirmPassword, setConfirmPassword] = useState(''); async function postLogin() { const user = await actions.postLogin(email, password); @@ -17,17 +19,62 @@ const Login = ({ success }) => { postLogin(); } - return ( -
-
- - setEmail(e.target.value)} /> - - setPassword(e.target.value)} /> - + if (mode === 'register') return ( +
+ + ); + + return ( +
+
+
+ + setEmail(e.target.value)} /> +
+
+ + setPassword(e.target.value)} /> +
+
+ +
+
+ +
); }; -export default Login; +function LoginPage({ success }) { + return ( +
+ +
+

Mates Crates is a record importing service.

+

We bundle orders together from thousands of online stores to reduce the cost of shipping vinyl.

+

Based in Preston.

+
+
+ ) +} + +export default LoginPage; diff --git a/client/src/routes/register.tsx b/client/src/routes/register.tsx deleted file mode 100644 index d040d56..0000000 --- a/client/src/routes/register.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { h } from 'preact'; -import { useState } from 'preact/hooks'; - -import actions from './../actions'; - -const Register = ({ success }) => { - const [email, setEmail] = useState('') - const [password, setPassword] = useState(''); - - async function postRegister() { - const user = await actions.postRegister(email, password); - success(user); - } - - function handleSubmit(e) { - e.preventDefault(); - postRegister(); - } - - function emailChange(e) { - setEmail(e.target.value); - } - - function passwordChange(e) { - setPassword(e.target.value); - } - - return ( -
-
- - - - - -
-
- ); -}; - -export default Register; diff --git a/client/src/routes/search.tsx b/client/src/routes/search.tsx index 914ed36..37baf14 100644 --- a/client/src/routes/search.tsx +++ b/client/src/routes/search.tsx @@ -31,9 +31,9 @@ const User = () => {
- + setArtist(e.target.value) } required /> - + setTitle(e.target.value)} required />
diff --git a/client/src/style/index.less b/client/src/style/index.less index eca50c8..ca6a162 100644 --- a/client/src/style/index.less +++ b/client/src/style/index.less @@ -1,91 +1,183 @@ -html, body { - height: 100%; - width: 100%; - padding: 0; - margin: 0; - background: #FAFAFA; - font-family: 'Helvetica Neue', arial, sans-serif; - font-weight: 400; - color: #444; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; +// Digital Ocean reset +html { + box-sizing: border-box; + font-size: 16px; } -* { - box-sizing: border-box; +*, *:before, *:after { + box-sizing: inherit; } -#app { - height: 100%; +body, h1, h2, h3, h4, h5, h6, p, ol, ul { + margin: 0; + padding: 0; + font-weight: normal; +} + +ol, ul { + list-style: none; +} + +img { + max-width: 100%; + height: auto; +} + +/* latin */ +@font-face { + font-family: 'Raleway'; + font-style: normal; + font-weight: 400; + src: url(https://fonts.gstatic.com/s/raleway/v28/1Ptxg8zYS_SKggPN4iEgvnHyvveLxVvaorCIPrE.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +// stuff from UX laws +html { + color:var(--base-font-color); + font-size:clamp(var(--min-font-size),calc(50% + 1vw),var(--max-font-size)); + font-family:var(--base-font-family); + line-height:var(--base-line-height); + -webkit-text-size-adjust:100%; + background:var(--base-background-color); + box-sizing:border-box +} + +// @charset "UTF-8"; +:root { + --breakpoint-medium: 35em; + --breakpoint-large: 56em; + --color-dark-blue: #101014; + --color-mid-blue: #16171d; + --color-light-blue: #1f2128; + --color-mid-grey: #9BA0B3; + --color-off-white: #F4F1D0; + --color-accent-blue: #5E9ED6; + --base-accent-color: var(--color-accent-blue); + --hover-link-color: var(--color-off-white); + --base-background-color: var(--color-dark-blue); + --secondary-background-color: var(--color-mid-blue); + --tertiary-background-color: var(--color-light-blue); + --small-font-size: 0.75em; + --base-font-size: 1em; + --smedium-font-size: 1.333em; + --medium-font-size: 1.777em; + --large-font-size: 2.369em; + --xlarge-font-size: 3.157em; + --base-font-family: 'Raleway', Arial, Sans-Serif; + --secondary-font-family: monospace; + --base-font-color: var(--color-off-white); + --secondary-font-color: var(--color-mid-grey); + --base-line-height: 1.4; + --header-line-height: 1.2; + --min-font-size: var(--base-font-size); + --max-font-size: var(--large-font-size); + --base-duration: .3s; + --base-timing: cubic-bezier(0.645, 0.045, 0.355, 1.000); + --base-border-color: var(--secondary-font-color); + --base-border: 1px solid var(--base-border-color); + --hover-border: 1px solid var(--base-font-color); + --focus-border: 1px solid var(--base-font-color); + --base-border-radius: .2rem; + --base-focus: 2px solid var(--base-accent-color); + --base-outline-offset: 0.25em; + --base-box-shadow: 0 1px 2px 0px rgba(0, 0, 0, .25); + --hover-box-shadow: 0 2px 10px 1px rgba(0, 0, 0, .5); + --base-spacing: 1rem; + --base-spacing-half: calc(var(--base-spacing)/2); + --utility-bar-header-height: calc(var(--base-spacing) * 1.5); +} + +button, input, optgroup, select, textarea { + margin:0; + border:var(--base-border); + border-radius:var(--base-border-radius); + background:0 0; + font-family:inherit; + font-size:100%; + color:inherit; + line-height:var(--base-line-height); +} + +input:hover, textarea:hover { + color:var(--base-font-color); + border:var(--hover-border) +} + +input:focus, textarea:focus { + border:var(--focus-border); + outline:0 +} + +button, input { + overflow:visible +} + +button, select { + text-transform:none +} + +button, [type=button], [type=reset], [type=submit] { + -webkit-appearance:button; + cursor:pointer +} + +// ok actual styles + +body { + padding-top: calc(var(--base-spacing)/2); +} + +main { + padding: 0 10% 0 10%; +} + +button, [type=submit] { + padding: var(--base-spacing-half); +} + +.landing { + display: flex; + + .login { + flex: 1; + } + + .info { + flex: 1; + + p { + margin-bottom: var(--base-spacing); + } + } + +} + +form { + margin-bottom: var(--base-spacing); + + label { + margin-bottom: var(--base-spacing-half); + } + + label, input { + display: block; + } +} + + +.header { + display: flex; } .home { - padding: 56px 20px; - min-height: 100%; - width: 100%; + min-height: 100%; + width: 100%; - display: flex; + display: flex; - .bundle { - flex: 1; - padding-right: 1em; - } + .bundle { + flex: 1; + padding-right: 1em; + } } - -.profile { - padding: 56px 20px; - min-height: 100%; - width: 100%; -} - -.header { - position: fixed; - left: 0; - top: 0; - width: 100%; - height: 56px; - padding: 0; - background: #673AB7; - box-shadow: 0 0 5px rgba(0, 0, 0, 0.5); - z-index: 50; -} - -.header { - h1 { - float: left; - margin: 0; - padding: 0 15px; - font-size: 24px; - line-height: 56px; - font-weight: 400; - color: #FFF; - } - - nav { - float: right; - font-size: 100%; - } - - nav a { - display: inline-block; - height: 56px; - line-height: 56px; - padding: 0 15px; - min-width: 50px; - text-align: center; - background: rgba(255,255,255,0); - text-decoration: none; - color: #FFF; - will-change: background-color; - } - - nav a:hover, - nav a:active { - background: rgba(0,0,0,0.2); - } - - nav a.active { - background: rgba(0,0,0,0.4); - } -} -