diff --git a/api/categories.js b/api/categories.js
index fc10d85..52e6b74 100644
--- a/api/categories.js
+++ b/api/categories.js
@@ -10,6 +10,12 @@ router.get('/', async (req, res) => {
res.json(categories)
})
+router.get('/by-slug/:slug', async (req, res) => {
+ const category = await db.category.findBySlug(req.params.slug)
+
+ res.json(category)
+})
+
const newCategoryValidators = [
validate.validUrlSlug('urlslug'),
validate.requiredString('name'),
@@ -35,3 +41,8 @@ router.delete('/:category_uuid/items/:item_uuid', async (req, res) => {
const category = await db.category.removeItem(req.params.category_uuid, req.params.item_uuid);
res.json(category)
})
+
+router.put('/:parent_uuid/children/:child_uuid', async (req, res) => {
+ const category = await db.category.addCategory(req.params.parent_uuid, req.params.child_uuid);
+ res.json(category)
+})
diff --git a/components/card/card.js b/components/card/card.js
index 6a6bfc9..db40cd3 100644
--- a/components/card/card.js
+++ b/components/card/card.js
@@ -10,9 +10,11 @@ export default function Card({item, numberInCart}) {
return (
-
- {featuredImage &&
}
-
+ {featuredImage && (
+
+
+
+ )}
{item.description}
0 ? '' : ' ' + styles['out-of-stock'])}>
-
diff --git a/db/mappings/item.js b/db/mappings/item.js
index 02035b6..dbf3f5b 100644
--- a/db/mappings/item.js
+++ b/db/mappings/item.js
@@ -40,7 +40,19 @@ module.exports = [{
'description',
'urlslug'
],
+ associations: [
+ {name: 'parent', mapId: 'bareCategoryMap', columnPrefix: 'parent_category_'}
+ ],
collections: [
- {name: 'items', mapId: 'itemMap', columnPrefix: 'item_'}
+ {name: 'items', mapId: 'itemMap', columnPrefix: 'item_'},
+ {name: 'children', mapId: 'bareCategoryMap', columnPrefix: 'child_category_'}
+ ]
+},{
+ mapId: 'bareCategoryMap',
+ idProperty: 'uuid',
+ properties: [
+ 'name',
+ 'description',
+ 'urlslug'
]
}]
diff --git a/db/models/category.js b/db/models/category.js
index b988666..3a9e400 100644
--- a/db/models/category.js
+++ b/db/models/category.js
@@ -14,6 +14,18 @@ category.findAll = async () => {
return joinjs.map(rows, mappings, 'categoryMap', 'category_');
}
+category.findBySlug = async slug => {
+ const query = {
+ text: 'select * from sos.v_category where category_urlslug = $1',
+ values: [slug]
+ }
+
+ debug(query);
+
+ const {rows} = await pg.query(query)
+ return joinjs.map(rows, mappings, 'categoryMap', 'category_')[0];
+}
+
category.create = async (name, urlslug, description) => {
const query = {
text: 'select * from sos.create_category($1::text, $2::citext, $3::text)',
@@ -60,3 +72,18 @@ category.removeItem = async (category_uuid, item_uuid) => {
return joinjs.map(rows, mappings, 'categoryMap', 'category_')[0];
}
+category.addCategory = async (parent_uuid, child_uuid) => {
+ const query = {
+ text: 'select * from sos.add_category_to_category($1, $2)',
+ values: [
+ parent_uuid,
+ child_uuid
+ ]
+ }
+
+ debug(query)
+
+ const {rows} = await pg.query(query);
+ return joinjs.map(rows, mappings, 'categoryMap', 'category_')[0];
+}
+
diff --git a/db/sql/2-views.sql b/db/sql/2-views.sql
index 8860356..eacf0fd 100644
--- a/db/sql/2-views.sql
+++ b/db/sql/2-views.sql
@@ -53,9 +53,14 @@ create or replace view sos.v_category as
"child_category".category_uuid as child_category_uuid,
"child_category".category_name as child_category_name,
"child_category".category_urlslug as child_category_urlslug,
+ "parent_category".category_uuid as parent_category_uuid,
+ "parent_category".category_name as parent_category_name,
+ "parent_category".category_urlslug as parent_category_urlslug,
v_item.*
from sos."category"
- left join sos."category_category" on "category".category_uuid = "category_category".category_category_parent_uuid
- left join sos."category" "child_category" on "category_category".category_category_child_uuid = "child_category".category_uuid
+ left join sos."category_category" "child_category_link" on "category".category_uuid = "child_category_link".category_category_parent_uuid
+ left join sos."category_category" "parent_category_link" on "category".category_uuid = "parent_category_link".category_category_child_uuid
+ left join sos."category" "child_category" on "child_category_link".category_category_child_uuid = "child_category".category_uuid
+ left join sos."category" "parent_category" on "parent_category_link".category_category_parent_uuid = "parent_category".category_uuid
left join sos."category_item" on "category".category_uuid = "category_item".category_item_category_uuid
left join sos.v_item on "category_item".category_item_item_uuid = item_uuid;
diff --git a/db/sql/3-functions.sql b/db/sql/3-functions.sql
index dc76bc1..3f4ef2a 100644
--- a/db/sql/3-functions.sql
+++ b/db/sql/3-functions.sql
@@ -192,6 +192,38 @@ begin
return query select * from sos.v_category where category_uuid = _category_uuid;
end; $function$;
+create or replace function sos.add_item_to_category(_category_uuid uuid, _item_uuid uuid)
+ returns setof sos.v_category
+ language plpgsql
+as $function$
+begin
+ insert into sos."category_item" (
+ category_item_item_uuid,
+ category_item_category_uuid
+ ) values (
+ _item_uuid,
+ _category_uuid
+ );
+
+ return query select * from sos.v_category where category_uuid = _category_uuid;
+end; $function$;
+
+create or replace function sos.add_category_to_category(_parent_uuid uuid, _child_uuid uuid)
+ returns setof sos.v_category
+ language plpgsql
+as $function$
+begin
+ insert into sos."category_category" (
+ category_category_parent_uuid,
+ category_category_child_uuid
+ ) values (
+ _parent_uuid,
+ _child_uuid
+ );
+
+ return query select * from sos.v_category where category_uuid = _parent_uuid;
+end; $function$;
+
create or replace function sos.create_cart(_session_uuid uuid)
returns setof sos.v_cart
language plpgsql
diff --git a/pages/store/cart.js b/pages/store/cart.js
index dfe8a9e..6ffcbba 100644
--- a/pages/store/cart.js
+++ b/pages/store/cart.js
@@ -22,51 +22,49 @@ export default function Cart({cart, setCart}){
return (
<>
Cart
- <>
-
Cart
+ Cart
- {
- numItems > 0
- ? row.item.name},
- {name: 'Quantity in Cart', extractor: row => row.count},
- {name: 'Price Each', extractor: row => '$' + (row.item.price_cents / 100).toFixed(2)},
- {name: 'Total Price', extractor: row => '$' + (row.count * row.item.price_cents / 100).toFixed(2)},
- {name: '', extractor: row =>
-
- }
- ]}
- rows={cart?.items?.map(row=>({
- ...row,
- id: row.item.uuid
- }))}
- foot={[
- 'Total:',
- cart?.items.map(r=>r.count).reduce((a,b) => (a+b), 0) || 0,
- '',
- '$' + ((cart?.items.map(r=>r.count * r.item.price_cents).reduce((a,b) => (a+b), 0) || 0) / 100).toFixed(2),
- ''
- ]}
- />
- // Empty cart table
- :
- }
+ {
+ numItems > 0
+ ? row.item.name},
+ {name: 'Quantity in Cart', extractor: row => row.count},
+ {name: 'Price Each', extractor: row => '$' + (row.item.price_cents / 100).toFixed(2)},
+ {name: 'Total Price', extractor: row => '$' + (row.count * row.item.price_cents / 100).toFixed(2)},
+ {name: '', extractor: row =>
+
+ }
+ ]}
+ rows={cart?.items?.map(row=>({
+ ...row,
+ id: row.item.uuid
+ }))}
+ foot={[
+ 'Total:',
+ cart?.items.map(r=>r.count).reduce((a,b) => (a+b), 0) || 0,
+ '',
+ '$' + ((cart?.items.map(r=>r.count * r.item.price_cents).reduce((a,b) => (a+b), 0) || 0) / 100).toFixed(2),
+ ''
+ ]}
+ />
+ // Empty cart table
+ :
+ }
-
-
-
- >
+
+
+
>
)
}
diff --git a/pages/store/category/[slug].js b/pages/store/category/[slug].js
new file mode 100644
index 0000000..5ee8238
--- /dev/null
+++ b/pages/store/category/[slug].js
@@ -0,0 +1,52 @@
+import React, {useState} from 'react'
+import Head from 'next/head'
+import Link from 'next/link'
+
+import Card from '~/components/card'
+import styles from './style.module.css'
+
+Category.getInitialProps = async function({ctx: {axios, query: {slug}}}){
+ console.log(slug)
+ const {data: category} = await axios.get(`/api/categories/by-slug/${slug}`)
+
+ console.log(category)
+
+ if(!category) {
+ const err = new Error("Not found")
+ err.status = 404
+ throw err;
+ }
+
+ return {category}
+}
+
+export default function Category({category: {items, children, parent, ...category}}){
+ return (
+ <>
+ {category.name}
+ {category.name}
+
+ {parent && (
+
< Back to {parent.name}
+ )}
+
{category.description}
+ {children.length > 0 &&
}
+
+ {items.length > 0 ? (
+
+ {items.map(item=>
+
+ )}
+
+ ) :
No items found
}
+
+
+ >
+ )
+}
diff --git a/pages/store/category/style.module.css b/pages/store/category/style.module.css
new file mode 100644
index 0000000..71ab5d6
--- /dev/null
+++ b/pages/store/category/style.module.css
@@ -0,0 +1,36 @@
+.pageContainer {
+ max-width: 800px;
+ margin: 0 auto;
+ width: calc(100% - 100px);
+ position: relative;
+}
+
+.parentLink {
+ position: absolute;
+ top: -65px;
+ color: rgb(121, 10, 141);
+}
+
+.description {
+ text-align: center;
+ margin-top: -20px;
+}
+
+.childCategories {
+ width: 100%;
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ flex-wrap: wrap;
+}
+
+.childCategories > a {
+ display: inline-block;
+ border: solid 1px rgb(248, 48, 255);
+ background: rgba(248, 48, 255, 0.4);
+ padding: 4px 10px;
+ border-radius: 15px;
+ text-decoration: none;
+ color: black;
+ margin: 10px 20px;
+}
\ No newline at end of file
diff --git a/pages/store/item/[slug].js b/pages/store/item/[slug].js
index 84001d0..8044746 100644
--- a/pages/store/item/[slug].js
+++ b/pages/store/item/[slug].js
@@ -4,7 +4,7 @@ import Router from 'next/router'
import {FormController, NumInput, Button} from '~/components/form'
import isNum from 'validator/lib/isNumeric'
-import styles from './slug.module.css'
+import styles from './style.module.css'
Item.getInitialProps = async function({ctx: {axios, query: {slug}}}){
const {data: item} = await axios.get(`/api/items/by-slug/${slug}`)
diff --git a/pages/store/item/slug.module.css b/pages/store/item/style.module.css
similarity index 100%
rename from pages/store/item/slug.module.css
rename to pages/store/item/style.module.css