From c50a37b08aa5177bdfdcc6e2d086af775abd030d Mon Sep 17 00:00:00 2001 From: cupcakearmy Date: Thu, 23 May 2019 16:55:02 +0200 Subject: [PATCH] shopping list --- api/src/entities/item.ts | 24 +++++++ api/src/routes/index.ts | 4 +- api/src/routes/item.ts | 60 ++++++++++++++++ api/src/server.ts | 3 +- www/pages/list.jsx | 114 +++++++++++++++++++++++++++++++ www/static/icons/ui/add.svg | 2 +- www/static/icons/ui/basket.svg | 1 + www/static/icons/ui/check.svg | 1 + www/static/icons/ui/stats.svg | 1 - www/static/icons/ui/trending.svg | 1 + 10 files changed, 207 insertions(+), 4 deletions(-) create mode 100644 api/src/entities/item.ts create mode 100644 api/src/routes/item.ts create mode 100644 www/pages/list.jsx create mode 100644 www/static/icons/ui/basket.svg create mode 100644 www/static/icons/ui/check.svg delete mode 100644 www/static/icons/ui/stats.svg create mode 100644 www/static/icons/ui/trending.svg diff --git a/api/src/entities/item.ts b/api/src/entities/item.ts new file mode 100644 index 0000000..53a47c7 --- /dev/null +++ b/api/src/entities/item.ts @@ -0,0 +1,24 @@ +import { BaseEntity, Column, Entity, PrimaryColumn } from 'typeorm' +import UUID from 'uuid/v4' + +@Entity() +export default class Item extends BaseEntity { + + @PrimaryColumn() + id!: string + + @Column() + text: string + + @Column() + done: boolean + + constructor(text: string, done: boolean = false) { + super() + + this.id = UUID() + this.text = text + this.done = done + } + +} \ No newline at end of file diff --git a/api/src/routes/index.ts b/api/src/routes/index.ts index 8fa143e..1060c2e 100644 --- a/api/src/routes/index.ts +++ b/api/src/routes/index.ts @@ -1,13 +1,15 @@ import Router from 'koa-router' +import item from './item' import purchase from './purchase' import user from './user' const r = new Router({ - prefix: '/api' + prefix: '/api', }) r.use(user.routes(), user.allowedMethods()) r.use(purchase.routes(), purchase.allowedMethods()) +r.use(item.routes(), purchase.allowedMethods()) export default r \ No newline at end of file diff --git a/api/src/routes/item.ts b/api/src/routes/item.ts new file mode 100644 index 0000000..a401afe --- /dev/null +++ b/api/src/routes/item.ts @@ -0,0 +1,60 @@ +import Router from 'koa-router' + +import Item from '../entities/item' +import { withAuth } from '../lib/auth' +import { Success } from '../lib/responses' + +const r = new Router({ + prefix: '/items', +}) + +r.get('/', withAuth(async ctx => { + return Success(ctx, await Item.find()) +})) + +r.post('/', withAuth(async ctx => { + const { text, done } = ctx.request.body + + return Success(ctx, await new Item(String(text), Boolean(done)).save()) +})) + +r.delete('/', withAuth(async ctx => { + return Success(ctx, await Item.clear()) +})) + +r.get('/:id', withAuth(async ctx => { + const { id } = ctx.params + const item = await Item.findOne(id) + + // 404 + if (!item) return + + return Success(ctx, item) +})) + +r.delete('/:id', withAuth(async ctx => { + const { id } = ctx.params + const item = await Item.findOne(id) + + // 404 + if (!item) return + + await item.remove() + return Success(ctx) +})) + +r.patch('/:id', withAuth(async ctx => { + const { id } = ctx.params + const item = await Item.findOne(id) + + // 404 + if (!item) return + + const { text, done } = ctx.request.body + if (text !== undefined) item.text = String(text) + if (done !== undefined) item.done = Boolean(done) + + return Success(ctx, await item.save()) +})) + +export default r \ No newline at end of file diff --git a/api/src/server.ts b/api/src/server.ts index 2e4dcf6..ccfc8ff 100644 --- a/api/src/server.ts +++ b/api/src/server.ts @@ -5,6 +5,7 @@ import Parser from 'koa-bodyparser' import { join } from 'path' import { createConnection } from 'typeorm' +import Item from './entities/item' import Purchase from './entities/purchase' import User from './entities/user' import { Config } from './lib/config' @@ -15,7 +16,7 @@ import router from './routes' createConnection({ type: 'sqlite', database: join(process.cwd(), 'db.sqlite'), - entities: [User, Purchase], + entities: [User, Purchase, Item], synchronize: true, }).then(async () => { diff --git a/www/pages/list.jsx b/www/pages/list.jsx new file mode 100644 index 0000000..64895d9 --- /dev/null +++ b/www/pages/list.jsx @@ -0,0 +1,114 @@ +import React, { useEffect, useRef, useState } from 'react' + +import { withAuthSync } from '../utils/auth' +import Layout from '../components/layout' +import { callAPI } from '../utils/api' + + +const Item = ({ id, text, done }) => { + + const handleDone = async (e) => { + await callAPI(null, { + url: `/api/items/${id}`, + method: 'patch', + data: { + done: e.target.checked, + }, + }) + window.location.reload() + } + + const handleDelete = async (e) => { + await callAPI(null, { + url: `/api/items/${id}`, + method: 'delete', + }) + window.location.reload() + } + + return + +
+ +
+ + {text} + +
+ + + + +
+ + {/* language=CSS */} + + +} + +const List = ({ items }) => { + + const input = useRef(undefined) + const [text, setText] = useState('') + + useEffect(() => { + if (!input.current) return + input.current.focus() + }, [input]) + + const submit = async () => { + await callAPI(null, { + url: `/api/items/`, + method: 'post', + data: { text }, + }) + window.location.reload() + } + + const deleteAll = async () => { + await callAPI(null, { + url: `/api/items/`, + method: 'delete', + }) + window.location.reload() + } + + return +
+
+ setText(e.target.value)}/> + +
+
+
+ + + {items.map((item, i) => )} + +
+
+ +
+} + +List.getInitialProps = async ctx => ({ + items: await callAPI(ctx, { url: `/api/items` }), +}) + +export default withAuthSync(List) \ No newline at end of file diff --git a/www/static/icons/ui/add.svg b/www/static/icons/ui/add.svg index c131f77..a5bed0d 100644 --- a/www/static/icons/ui/add.svg +++ b/www/static/icons/ui/add.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/www/static/icons/ui/basket.svg b/www/static/icons/ui/basket.svg new file mode 100644 index 0000000..5c09d4e --- /dev/null +++ b/www/static/icons/ui/basket.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/www/static/icons/ui/check.svg b/www/static/icons/ui/check.svg new file mode 100644 index 0000000..c61aa04 --- /dev/null +++ b/www/static/icons/ui/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/www/static/icons/ui/stats.svg b/www/static/icons/ui/stats.svg deleted file mode 100644 index 0abb9c2..0000000 --- a/www/static/icons/ui/stats.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/www/static/icons/ui/trending.svg b/www/static/icons/ui/trending.svg new file mode 100644 index 0000000..504e5ae --- /dev/null +++ b/www/static/icons/ui/trending.svg @@ -0,0 +1 @@ + \ No newline at end of file