diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index f94d6794..9660bd83 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -3,6 +3,7 @@ import { Elysia, t } from 'elysia' import { migrate } from 'drizzle-orm/bun-sqlite/migrator' import { db } from './db/db' import { todos } from './db/schema' +import { eq } from 'drizzle-orm' migrate(db, { migrationsFolder: './drizzle' }) @@ -38,14 +39,15 @@ const app = new Elysia() .get('/todos', () => db.select().from(todos)) .get( '/todos/:id', - ({ params, error }) => { - const todo = todoList.find((todo) => todo.id === params.id) + async ({params, set, body, error}) => { + const todo = await db.select().from(todos).where(eq(todos.id, params.id)) - if (!todo) { - return error(404, 'Todo not found.') + if(!todo[0]) { + return error(404, 'Todo not found'); } - return todo + set.status = 'OK' + return todo[0] }, { params: t.Object({ @@ -56,27 +58,41 @@ const app = new Elysia() .post( '/todos', async ({ body, set }) => { - await db.insert(todos).values(body) + let newTodo = await db.insert(todos) + .values(body) + .returning() + console.log(newTodo) set.status = 'Created' + return { + "id": newTodo[0].id + }; }, { body: t.Object({ - desc: t.String() + desc: t.String(), + starred: t.Boolean(), + completed: t.Boolean() }) } ) .put( '/todos/:id', - ({ params, body, error }) => { - const todo = todoList.find((todo) => todo.id === params.id) + async ({params, set, body, error}) => { + const todo = await db.select().from(todos).where(eq(todos.id, params.id)) - if (!todo) { - return error(204, 'Todo can not be updated.') + if(!todo[0]) { + return error(404, 'Todo not found for update'); } - Object.assign(todo, body) + const updatedTodo = await db.update(todos) + .set(body) + .where(eq(todos.id, params.id)) + .returning() + if(!updatedTodo[0]) { + return error(500, 'Todo could not be updated') + } - return todo + set.status = 'OK' }, { params: t.Object({ @@ -91,16 +107,22 @@ const app = new Elysia() ) .patch( '/todos/:id', - ({ params, body, error }) => { - const todo = todoList.find((todo) => todo.id === params.id) + async ({params, set, body, error}) => { + const todo = await db.select().from(todos).where(eq(todos.id, params.id)) - if (!todo) { - return error(204, 'Todo can not be updated.') + if(!todo[0]) { + return error(404, 'Todo not found for update'); } - Object.assign(todo, body) + const updatedTodo = await db.update(todos) + .set(body) + .where(eq(todos.id, params.id)) + .returning() + if(!updatedTodo[0]) { + return error(500, 'Todo could not be updated') + } - return todo + set.status = 'OK' }, { params: t.Object({ @@ -115,16 +137,22 @@ const app = new Elysia() ) .delete( '/todos/:id', - ({ params, error }) => { - const todo = todoList.find((todo) => todo.id === params.id) - - if (!todo) { - return error(204, 'Todo can not be deleted.') + async ({ params, set, error }) => { + try { + const deletedTodo = await db.delete(todos) + .where(eq(todos.id, params.id)) + .returning(); + + if (!deletedTodo) { + return error(404, 'Todo not found for deletion.'); + } + + set.status = 'No Content' + return + } catch (err) { + console.error('Error deleting todo:', err); + return error(500, "Interval server error: " + err); } - - todoList.splice(todoList.indexOf(todo), 1) - - return todo }, { params: t.Object({ diff --git a/packages/frontend/src/App.tsx b/packages/frontend/src/App.tsx index 68e45643..53c61564 100644 --- a/packages/frontend/src/App.tsx +++ b/packages/frontend/src/App.tsx @@ -13,6 +13,7 @@ import { useEffect, useRef, useState } from 'react' import { Input } from './components/ui/input' import type { App } from 'backend/src/index' import { treaty } from '@elysiajs/eden' +import { compileFunction } from 'vm' const client = treaty('localhost:3000') @@ -79,34 +80,155 @@ function App() { }) }, []) - const handleDelete = (id: number) => - setTodos(todos.filter((todo) => todo.id !== id)) + const handleDelete = (id: number) => { + let toDelete = todos.filter((todo) => todo.id === id)[0] + setTodos(prev => prev.filter((todo) => todo.id !== id)) + + client.todos({id}) + .delete() + .then((res) => { + if(res.error) { + setTodos(prev => [...prev, toDelete]) + } + + if(res.data) { + // do nothing? + } + }) + .catch((error) => { + // Handle errors, including timeouts + console.error('Error sending request:', error); + // Revert optimistic update + setTodos(prev => [...prev, toDelete]); + }) + } + + + + const toggleStar = (id: number) =>{ + let toggleTodo = todos.find((todo) => todo.id === id) + if(!toggleTodo) { + return + } + + let initialState = toggleTodo?.starred - const toggleStar = (id: number) => setTodos( todos.map((todo) => todo.id === id ? { ...todo, starred: !todo.starred } : todo ) ) - const toggleChecked = (id: number) => + client.todos({id}) + .patch({ + starred: !initialState + }) + .then((res) => { + if(res.error) { + setTodos( + todos.map((todo) => + todo.id === id ? { ...todo, starred: !todo.starred } : todo + ) + ) + } + }) + .catch((error) => { + // Handle errors, including timeouts + console.error('Error sending request:', error); + // Revert optimistic update (remove temporary todo) + setTodos(todos.map((todo) => + todo.id === id ? { ...todo, starred: !todo.starred } : todo + )); + }) + } + + const toggleChecked = (id: number) =>{ + let toggleTodo = todos.find((todo) => todo.id === id) + if(!toggleTodo) { + return + } + + let initialState = toggleTodo?.completed + setTodos( todos.map((todo) => todo.id === id ? { ...todo, completed: !todo.completed } : todo ) ) + client.todos({id}) + .patch({ + completed: !initialState + }) + .then((res) => { + if(res.error) { + setTodos( + todos.map((todo) => + todo.id === id ? { ...todo, completed: !todo.completed } : todo + ) + ) + } + }) + .catch((error) => { + // Handle errors, including timeouts + console.error('Error sending request:', error); + // Revert optimistic update (remove temporary todo) + setTodos(todos.map((todo) => + todo.id === id ? { ...todo, starred: !todo.starred } : todo + )); + }) + } + const addTodo = () => { - setTodos([ - ...todos, + + let toAdd = { + desc: inputRef.current!.value, + starred: false, + completed: false, + } + + let randId = Math.random() + setTodos(prev => [ + ...prev, { - id: todos.length, - desc: inputRef.current!.value, - starred: false, - completed: false + id: randId, + ...toAdd } ]) - inputRef.current!.value = '' + + client.todos + .post(toAdd) + .then((res) => { + if(res.error || !res.data) { + // getting rid of the one i optimistically (prematurely) added + setTodos(prev => prev.filter((todo) => todo.id != randId)) + } + + if(res.data) { + const newId = res.data.id + setTodos(prev => prev.map(todo => + todo.id === randId ? { ...todo, id: newId} : todo + )) + inputRef.current!.value = '' + } + }) + .catch((error) => { + // Handle errors, including timeouts + console.error('Error sending request:', error); + // Revert optimistic update (remove temporary todo) + setTodos(prev => prev.filter((todo) => todo.id != randId)); + }) + + // setTodos([ + // ...todos, + // { + // id: todos.length, + // desc: inputRef.current!.value, + // starred: false, + // completed: false + // } + // ]) + // inputRef.current!.value = '' } return (