diff --git a/api/auth.js b/api/auth.js index df1fdcc..638669c 100644 --- a/api/auth.js +++ b/api/auth.js @@ -37,7 +37,9 @@ router.post('/', parseJSON, loginValidation, async (req, res) => { req.session.uuid = session.uuid - res.json(user) + const {password_hash, ...result} = user + + res.json(result) }) // TODO: Login link stuff diff --git a/api/cart.js b/api/cart.js new file mode 100644 index 0000000..96910dd --- /dev/null +++ b/api/cart.js @@ -0,0 +1,13 @@ +const router = module.exports = require('express-promise-router')() +const parseJSON = require('body-parser').json() +const db = require('../db') + +// TODO: Actually implement cart! + +router.get('/', async (req, res)=>{ + res.json(null); +}) + +router.post('/add', parseJSON, async (req, res) => { + res.json(null) +}) \ No newline at end of file diff --git a/api/index.js b/api/index.js index 422b1e9..a407ffe 100644 --- a/api/index.js +++ b/api/index.js @@ -17,6 +17,7 @@ router.use((req, res, next)=>{ router.use(require('cookie-session')({name: 'sos-session', secret: process.env.COOKIE_SECRET})) router.use(require('./middleware/session')) router.use('/auth', require('./auth')) +router.use('/cart', require('./cart')) router.use('/users/', require('./users')) router.use('/items/', require('./items')) router.use('/images/', require('./images')) diff --git a/api/items.js b/api/items.js index 90c2b4a..86272be 100644 --- a/api/items.js +++ b/api/items.js @@ -44,6 +44,11 @@ router.post('/', parseJSON, newItemValidators, async (req, res) => { res.json(item) }) +router.get('/by-slug/:slug', async (req, res) => { + const item = await db.item.findBySlug(req.params.slug); + res.json(item) +}) + router.delete('/:uuid', async (req, res) => { const result = await db.item.removeItem(req.params.uuid) res.json({deleted: true}) diff --git a/components/card/card.js b/components/card/card.js index bf5ba3f..6a6bfc9 100644 --- a/components/card/card.js +++ b/components/card/card.js @@ -9,7 +9,7 @@ export default function Card({item, numberInCart}) { return (
-

{item.name}

+

{item.name}

{featuredImage && }
diff --git a/components/form/form.js b/components/form/form.js index 65bfd36..00949ac 100644 --- a/components/form/form.js +++ b/components/form/form.js @@ -4,6 +4,7 @@ import axios from 'axios' import styles from './styles.module.css' export const Input = require('./input.js').default +export const NumInput = require('./numInput.js').default export const Button = require('./button.js').default const errorReducer = (errors, action) => { @@ -15,7 +16,6 @@ const errorReducer = (errors, action) => { return newErrors case 'clear_error': - console.log('clear_error', action) return { ...errors, [action.field]: undefined @@ -72,7 +72,7 @@ const formReducer = errorDispatch => (state, action)=>{ } -export const FormController = function FormController({children, url, method = 'POST', afterSubmit = ()=>null}){ +export const FormController = function FormController({children, className, url, method = 'POST', afterSubmit = ()=>null}){ const initialState = { fields: {} } @@ -85,7 +85,7 @@ export const FormController = function FormController({children, url, method = name: child.props.name, validate: child.props.validate, value: child.props.initialValue || "", - isValid: false, + isValid: child.props.initialValue ? child.props.validate(child.props.initialValue): false, touched: false } }) @@ -139,7 +139,7 @@ export const FormController = function FormController({children, url, method = }) return ( -
+ {_children}
) diff --git a/components/form/numInput.js b/components/form/numInput.js new file mode 100644 index 0000000..7a39841 --- /dev/null +++ b/components/form/numInput.js @@ -0,0 +1,24 @@ +import React from 'react' + +import styles from './styles.module.css' + +export default function Input({label, minimum = 0, maximum, error, hint, name, value, onChange, onBlur, isValid}){ + const current = parseInt(value, 10) || 0 + const nextUp = maximum !== undefined ? Math.min(current + 1, maximum) : current + 1 + const nextDown = minimum !== undefined ? Math.max(current - 1, minimum) : current - 1 + + const valueUp = ()=>onChange({target: {value: nextUp + ""}}) + const valueDown = ()=>onChange({target: {value: nextDown + ""}}) + + return ( +
+ +
+ + + +
+ {error || (isValid ? '' : hint)} +
+ ) +} diff --git a/components/form/styles.module.css b/components/form/styles.module.css index dcc56f8..5c9479f 100644 --- a/components/form/styles.module.css +++ b/components/form/styles.module.css @@ -19,37 +19,60 @@ } .formElementContainer input { + padding: 10px; +} + +.formElementContainer input, .formElementContainer .complexInput { box-sizing: border-box; width: 100%; min-width: 0; - padding: 10px; border: solid 1px rgba(0,0,0,.2); border-radius: 2px; transition-property: border-color,box-shadow; transition: .2s ease-in-out; } +:global(.dark) .formElementContainer input, :global(.dark) .formElementContainer .complexInput { + border: none; +} + +.complexInput { + display: flex; + flex-direction: row; + overflow: hidden; +} + +.complexInput > button { + width: 38px; + display: inline-block; +} + +.complexInput > input { + flex: 1; + border: 0; + border-radius: 0; +} + .formElementContainer span.hint { display: block; margin-top: 8px; - color: red; + color: var(--error-color); opacity: 0; transition: .2s opacity; user-select: none; height: 18.5px; } -.formElementContainer input.invalid { - border: solid 1px red; - box-shadow: red; +.formElementContainer .invalid { + border: solid 1px var(--error-color); + box-shadow: var(--error-color); } -.formElementContainer input.invalid + span.hint { - opacity: .5; +.formElementContainer .invalid + span.hint { + opacity: 1; } .formElementContainer button { - width: 100%; min-height: 20px; background: rgb(156, 39, 176); color: white; @@ -60,6 +83,10 @@ transition-duration: .2s; } +.formElementContainer > button { + width: 100%; +} + .formElementContainer button[type="submit"] { margin-top: 10px; } diff --git a/db/models/item.js b/db/models/item.js index 76369ee..9e03bac 100644 --- a/db/models/item.js +++ b/db/models/item.js @@ -46,7 +46,7 @@ item.findBySlug = async (item_slug) => { item.create = async (name, urlslug, description, price_cents, published) => { const query = { - text: 'select * from sos..create_item($1::text, $2::citext, $3::text, $4::integer, $5::boolean)', + text: 'select * from sos.create_item($1::text, $2::citext, $3::text, $4::integer, $5::boolean)', values: [ name, urlslug, diff --git a/pages/_app.js b/pages/_app.js index 48e4495..6657417 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -9,23 +9,31 @@ import "../styles/layout.css" Layout.getInitialProps = async ({Component, ctx}) => { // Configure axios instance ctx.axios = axios.create({ - headers: ctx.req ? {cookie: ctx.req.headers.cookie} : undefined + headers: (ctx.req && ctx.req.headers && ctx.req.headers.cookie) + ? {cookie: ctx.req.headers.cookie} + : undefined }) - const {data: user} = await ctx.axios.get(`/api/auth`) + const promises = { + user: ctx.axios.get(`/api/auth`), + cart: ctx.axios.get(`/api/cart`) + } + + const {data: user} = await promises.user + const {data: cart} = await promises.cart let pageProps = {}; if(Component.getInitialProps) pageProps = await Component.getInitialProps({ctx}) - return {pageProps, user} + return {pageProps, user, cart} } -function Layout({ Component, pageProps, user }){ +function Layout({ Component, pageProps, user, cart }){ return ( <>
-
+