diff --git a/api/categories.js b/api/categories.js index c54e38e..3253a45 100644 --- a/api/categories.js +++ b/api/categories.js @@ -57,3 +57,8 @@ 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) }) + +router.delete('/:parent_uuid/children/:child_uuid', async (req, res) => { + const category = await db.category.removeCategory(req.params.parent_uuid, req.params.child_uuid); + res.json(category) +}) diff --git a/db/models/category.js b/db/models/category.js index fa103d8..2e6e0db 100644 --- a/db/models/category.js +++ b/db/models/category.js @@ -88,6 +88,21 @@ category.addCategory = async (parent_uuid, child_uuid) => { return joinjs.map(rows, mappings, 'categoryMap', 'category_')[0]; } +category.removeCategory = async (parent_uuid, child_uuid) => { + const query = { + text: 'select * from sos.remove_category_from_category($1, $2)', + values: [ + parent_uuid, + child_uuid + ] + } + + debug(query) + + const {rows} = await pg.query(query); + return joinjs.map(rows, mappings, 'categoryMap', 'category_')[0]; +} + category.update = async (uuid, name, urlslug, description) => dbUtil.executeFunction({ name: 'update_category', diff --git a/db/sql/3-functions.sql b/db/sql/3-functions.sql index 42d77b5..a334376 100644 --- a/db/sql/3-functions.sql +++ b/db/sql/3-functions.sql @@ -270,6 +270,18 @@ begin return query select * from sos.v_category where category_uuid = _category_uuid; end; $function$; +create or replace function sos.remove_item_from_category(_category_uuid uuid, _item_uuid uuid) + returns setof sos.v_category + language plpgsql +as $function$ +begin + delete from sos."category_item" + where category_item_item_uuid = _item_uuid + and category_item_category_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 @@ -286,6 +298,18 @@ begin return query select * from sos.v_category where category_uuid = _parent_uuid; end; $function$; +create or replace function sos.remove_category_from_category(_parent_uuid uuid, _child_uuid uuid) + returns setof sos.v_category + language plpgsql +as $function$ +begin + delete from sos."category_category" + where category_category_parent_uuid = _parent_uuid + and category_category_child_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/admin/categories/[slug]/children.js b/pages/admin/categories/[slug]/children.js new file mode 100644 index 0000000..9ca2b31 --- /dev/null +++ b/pages/admin/categories/[slug]/children.js @@ -0,0 +1,68 @@ +import React, {useState} from 'react' +import Link from 'next/link' +import axios from 'axios' + +import ActionBar from '~/components/admin/actionBar' +import Table from '~/components/table' + +CategoryChildren.getInitialProps = async ({ctx: {axios, query: {slug}}}) => { + const {data: category} = await axios.get(`/api/categories/by-slug/${slug}`) + const {data: allCategories} = await axios.get(`/api/categories`) + return {category, allCategories} +} + +export default function CategoryChildren({category: _category, allCategories}) { + const [category, updateCategory] = useState(_category) + + const childrenUUIDs = category.children.map(child => child.uuid) + const possibleChildren = allCategories.filter(cat => !cat.parent && cat.uuid !== category.uuid && !childrenUUIDs.includes(cat.uuid)) + + const removeChild = uuid => async ev => { + if(ev) ev.preventDefault() + + const {data: updated} = await axios.delete(`/api/categories/${category.uuid}/children/${uuid}`) + updateCategory(updated) + } + + const addChild = uuid => async ev => { + if(ev) ev.preventDefault() + + const {data: updated} = await axios.put(`/api/categories/${category.uuid}/children/${uuid}`) + updateCategory(updated) + } + + return ( + <> + +

Child Categories

+ category.name}, + {name: 'URL Slug', extractor: category => {category.urlslug} }, + {name: 'Actions', extractor: category => ( + + + + )} + ]} + // Map in an id property so the table can use array.map + rows={category.children} + /> + +

Add Child Category

+
category.name}, + {name: 'URL Slug', extractor: category => {category.urlslug} }, + {name: 'Actions', extractor: category => ( + + + + )} + ]} + // Map in an id property so the table can use array.map + rows={possibleChildren} + /> + + ) +} diff --git a/pages/admin/categories/[slug]/items.js b/pages/admin/categories/[slug]/items.js new file mode 100644 index 0000000..0c5fea2 --- /dev/null +++ b/pages/admin/categories/[slug]/items.js @@ -0,0 +1,68 @@ +import React, {useState} from 'react' +import Link from 'next/link' +import axios from 'axios' + +import ActionBar from '~/components/admin/actionBar' +import Table from '~/components/table' + +CategoryItems.getInitialProps = async ({ctx: {axios, query: {slug}}}) => { + const {data: category} = await axios.get(`/api/categories/by-slug/${slug}`) + const {data: allItems} = await axios.get(`/api/items`) + return {category, allItems} +} + +export default function CategoryItems({category: _category, allItems}) { + const [category, updateCategory] = useState(_category) + + const itemUUIDs = category.items.map(item => item.uuid) + const possibleItems = allItems.filter(item => !itemUUIDs.includes(item.uuid)) + + const removeItem = uuid => async ev => { + if(ev) ev.preventDefault() + + const {data: updated} = await axios.delete(`/api/categories/${category.uuid}/items/${uuid}`) + updateCategory(updated) + } + + const addItem = uuid => async ev => { + if(ev) ev.preventDefault() + + const {data: updated} = await axios.put(`/api/categories/${category.uuid}/items/${uuid}`) + updateCategory(updated) + } + + return ( + <> + +

Items in this category

+
category.name}, + {name: 'URL Slug', extractor: category => {category.urlslug} }, + {name: 'Actions', extractor: category => ( + + + + )} + ]} + // Map in an id property so the table can use array.map + rows={category.items} + /> + +

Add item

+
category.name}, + {name: 'URL Slug', extractor: category => {category.urlslug} }, + {name: 'Actions', extractor: category => ( + + + + )} + ]} + // Map in an id property so the table can use array.map + rows={possibleItems} + /> + + ) +}