diff --git a/api/cart.js b/api/cart.js index c9e6cd4..0062c4a 100644 --- a/api/cart.js +++ b/api/cart.js @@ -29,3 +29,11 @@ router.post('/add/:item_uuid', parseJSON, cartAddValidators, async (req, res) => res.json(cart) }) + +router.post('/remove/:item_uuid', async (req, res) => { + if(!req.cart) return res.json(null) + + const cart = await db.cart.removeItemFromCart(req.cart.uuid, req.params.item_uuid); + + res.json(cart) +}) \ No newline at end of file diff --git a/api/middleware/session.js b/api/middleware/session.js index ee86ba4..71b9f41 100644 --- a/api/middleware/session.js +++ b/api/middleware/session.js @@ -4,7 +4,8 @@ const sessionMiddleware = (req, res, next)=>{ (async ()=>{ let session = await db.session.validate(req.session.uuid); - if(!session) return; + if(!session) + return req.session.uuid = null; // Update last active session = await db.session.update(req.session.uuid); diff --git a/components/form/form.js b/components/form/form.js index 00949ac..c7b95ff 100644 --- a/components/form/form.js +++ b/components/form/form.js @@ -85,7 +85,9 @@ export const FormController = function FormController({children, className, url name: child.props.name, validate: child.props.validate, value: child.props.initialValue || "", - isValid: child.props.initialValue ? child.props.validate(child.props.initialValue): false, + isValid: child.props.validate + ?(child.props.initialValue ? child.props.validate(child.props.initialValue): false) + :true, touched: false } }) @@ -106,7 +108,8 @@ export const FormController = function FormController({children, className, url if(url) try { - await axios({ method, url, data }) + const {data: response} = await axios({ method, url, data }) + return afterSubmit(response) } catch (err) { if(!err.response || err.response.status !== 422) throw err; @@ -123,7 +126,8 @@ export const FormController = function FormController({children, className, url const _children = React.Children.map(children, child => { if(child.type === Button && child.props.type.toLowerCase() === 'submit') return React.cloneElement(child, { - enabled: !Object.values(state.fields).some(field=>!field.isValid), + // Allow enabled prop to disable, but not solely enable + enabled: child.props.enabled !== false && !Object.values(state.fields).some(field=>!field.isValid), onClick: handleSubmit }) diff --git a/components/form/input.js b/components/form/input.js index 20cd2a2..1ef9b05 100644 --- a/components/form/input.js +++ b/components/form/input.js @@ -7,7 +7,7 @@ export default function Input({label, error, hint, type, name, value, onChange,
- {error || (isValid ? '' : hint)} + {hint && {error || (isValid ? '' : hint)}}
) } diff --git a/components/form/numInput.js b/components/form/numInput.js index cad09cb..96ab610 100644 --- a/components/form/numInput.js +++ b/components/form/numInput.js @@ -18,7 +18,7 @@ export default function Input({label, minimum = 0, maximum, error, hint, name, v - {error || (isValid ? '' : hint)} + {hint && {error || (isValid ? '' : hint)}} ) } diff --git a/components/table/table.js b/components/table/table.js new file mode 100644 index 0000000..8dee501 --- /dev/null +++ b/components/table/table.js @@ -0,0 +1,33 @@ +import styles from './table.module.css' + +export default function Table({columns, rows, foot}) { + return ( + + + + {columns.map(column=> + + )} + + + + {rows.map(row=> + + {columns.map(column=> + + )} + + )} + + {foot && + + {foot.map((item, i) => + + )} + + } +
{column.name}
{column.extractor(row)}
+ {item} +
+ ) +} \ No newline at end of file diff --git a/components/table/table.module.css b/components/table/table.module.css new file mode 100644 index 0000000..ae4c23a --- /dev/null +++ b/components/table/table.module.css @@ -0,0 +1,24 @@ +.table { + width: calc(100% - 100px); + max-width: 800px; + margin: 0 auto; + background: white; + border-collapse: collapse; + border: solid 1px gray; +} + +.table td, .table th { + border-top: solid 1px gray; + border-bottom: solid 1px gray; + text-align: left; +} + +.table th { + padding: 5px 15px; + font-family: 'Cormorant SC',serif; + font-weight: bold; +} + +.table td { + padding: 15px; +} \ No newline at end of file diff --git a/db/models/cart.js b/db/models/cart.js index 39856f6..f5dd6e3 100644 --- a/db/models/cart.js +++ b/db/models/cart.js @@ -35,13 +35,12 @@ cart.addItemToCart = async (cart_uuid, item_uuid, amount) => { return joinjs.map(rows, mappings, 'cartMap', 'cart_')[0]; } -cart.removeItemFromCart = async (cart_uuid, item_uuid, amount) => { +cart.removeItemFromCart = async (cart_uuid, item_uuid) => { const query = { - text: 'select * from sos.remove_item_from_cart($1, $2, $3)', + text: 'select * from sos.remove_item_from_cart($1, $2)', values: [ cart_uuid, - item_uuid, - amount + item_uuid ] } diff --git a/db/sql/3-functions.sql b/db/sql/3-functions.sql index 852fa57..dc76bc1 100644 --- a/db/sql/3-functions.sql +++ b/db/sql/3-functions.sql @@ -284,3 +284,33 @@ begin -- Return cart return query select * from sos.v_cart where cart_uuid = _cart_uuid; end; $function$; + +create or replace function sos.remove_item_from_cart(_cart_uuid uuid, _item_uuid uuid) + returns setof sos.v_cart + language plpgsql +as $function$ +declare + _row_count integer; +begin + -- Check if we already have a row for this combination + select + count(*) + into _row_count + from sos.cart_item + where cart_item_cart_uuid = _cart_uuid + and cart_item_item_uuid = _item_uuid + group by cart_item_uuid, cart_item_count; + + -- If we do not have a row, just exit + if _row_count < 1 then + return query select * from sos.v_cart where cart_uuid = _cart_uuid; + end if; + + -- If we have a row, then delete it + delete from sos.cart_item + where cart_item_cart_uuid = _cart_uuid + and cart_item_item_uuid = _item_uuid; + + -- Return cart + return query select * from sos.v_cart where cart_uuid = _cart_uuid; +end; $function$; diff --git a/pages/_app.js b/pages/_app.js index f4cd337..b1ade88 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -1,4 +1,4 @@ -import React from "react" +import React, {useState} from "react" import PropTypes from "prop-types" import axios from 'axios' @@ -29,11 +29,13 @@ Layout.getInitialProps = async ({Component, ctx}) => { return {pageProps, user, cart} } -function Layout({ Component, pageProps, user, cart }){ +function Layout({ Component, pageProps, user, cart: _cart }){ + const [cart, setCart] = useState(_cart) + return ( <>
-
+