From 1e8180fad7d665717f1d8c141ea4e11aa71e41f3 Mon Sep 17 00:00:00 2001 From: Tobias Prima Date: Wed, 20 Mar 2024 01:39:39 +0800 Subject: [PATCH 1/3] feat: api slice mutations --- src/App.test.js | 1 + src/app/api/apiSlice.js | 34 +++++++++++++++++++++++++++++++++- src/features/todos/TodoList.js | 12 +++++++++++- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/App.test.js b/src/App.test.js index d8b22c0..308e927 100644 --- a/src/App.test.js +++ b/src/App.test.js @@ -30,6 +30,7 @@ test('allows user to type in a new todo', () => { ); const inputElement = screen.getByLabelText(/Add to list/i); + // eslint-disable-next-line testing-library/no-unnecessary-act act(() => { fireEvent.change(inputElement, { target: { value: 'New Todo Item' } }); }); diff --git a/src/app/api/apiSlice.js b/src/app/api/apiSlice.js index c2bc2df..76c5fb6 100644 --- a/src/app/api/apiSlice.js +++ b/src/app/api/apiSlice.js @@ -6,10 +6,42 @@ export const apiSlice = createApi({ endpoints: (builder) => ({ getTodos: builder.query({ query: () => '/todos' + }), + addTodo: builder.mutation({ + query: (todo) => ({ + url: '/todo', + method: 'POST', + body: todo + }) + }), + updateTodo: builder.mutation({ + query: (todo) => ({ + url: `/todo/${todo.id}/title`, + method: 'PATCH', + body: todo + }) + }), + doneTodo: builder.mutation({ + query: (todo) => ({ + url: `/todo/${todo.id}/status`, + method: 'PATCH', + body: todo + }) + }), + deleteTodo: builder.mutation({ + query: ({ id })=> ({ + url: `/todo/${id}`, + method: 'DELETE', + body: id + }) }) }) }) export const { - useGetTodosQuery + useGetTodosQuery, + useAddTodoMutation, + useUpdateTodoMutation, + useDoneTodoMutation, + useDeleteTodoMutation } = apiSlice \ No newline at end of file diff --git a/src/features/todos/TodoList.js b/src/features/todos/TodoList.js index 3c61bb5..f2591e4 100644 --- a/src/features/todos/TodoList.js +++ b/src/features/todos/TodoList.js @@ -2,7 +2,13 @@ import React from 'react' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faTrash, faUpload } from '@fortawesome/free-solid-svg-icons' import { useState } from 'react' -import { useGetTodosQuery } from '../../app/api/apiSlice' +import { + useGetTodosQuery, + useAddTodoMutation, + useUpdateTodoMutation, + useDoneTodoMutation, + useDeleteTodoMutation +} from '../../app/api/apiSlice' const TodoList = () => { const [ newTodo, setNewTodo ] = useState('') @@ -14,6 +20,10 @@ const TodoList = () => { isError, error } = useGetTodosQuery() + const [ addTodo ] = useAddTodoMutation() + const [ updateTodo ] = useUpdateTodoMutation() + const [ doneTodo ] = useDoneTodoMutation() + const [ deleteTodo ] = useDeleteTodoMutation() const handleSubmit = (e)=> { e.preventDefault() From 90e4429be73f35581fa026cd05f758df994ce480 Mon Sep 17 00:00:00 2001 From: Tobias Prima Date: Wed, 20 Mar 2024 01:47:20 +0800 Subject: [PATCH 2/3] feat: add hooks to todolist --- src/features/todos/TodoList.js | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/features/todos/TodoList.js b/src/features/todos/TodoList.js index f2591e4..f72e3d9 100644 --- a/src/features/todos/TodoList.js +++ b/src/features/todos/TodoList.js @@ -21,13 +21,12 @@ const TodoList = () => { error } = useGetTodosQuery() const [ addTodo ] = useAddTodoMutation() - const [ updateTodo ] = useUpdateTodoMutation() const [ doneTodo ] = useDoneTodoMutation() const [ deleteTodo ] = useDeleteTodoMutation() const handleSubmit = (e)=> { e.preventDefault() - //addTodo + addTodo({title: newTodo}) setNewTodo('') } @@ -52,7 +51,24 @@ const TodoList = () => { if (isLoading) { content =

Loading ...

} else if (isSuccess){ - content = JSON.stringify(todos) + content = todos.map(todo => { + return ( +
+
+ doneTodo({ ...todo, status: !todo.status})} + /> + +
+ +
+ ) + }) } else if (isError) { content =

{error.message || 'Error fetching todos'}

} From 7f6d37afb1dabe559fa8664c4ba0b4e308630ef5 Mon Sep 17 00:00:00 2001 From: Tobias Prima Date: Wed, 20 Mar 2024 01:52:26 +0800 Subject: [PATCH 3/3] feat: add styling --- src/index.css | 96 ++++++++++++++++++++++++++++++++++++++++++++++----- src/index.js | 2 +- 2 files changed, 88 insertions(+), 10 deletions(-) diff --git a/src/index.css b/src/index.css index ec2585e..1914530 100644 --- a/src/index.css +++ b/src/index.css @@ -1,13 +1,91 @@ +@import url('https://fonts.googleapis.com/css2?family=Nunito&display=swap'); + body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; + font-family: 'Nunito', sans-serif; + font-size: 1.5rem; +} + +input[type="text"], button { + font: inherit; +} + +main { + margin: auto; + max-width: 600px; +} + +h1 { + margin-bottom: 0.5rem; +} + +article { + padding: 1rem; + display: flex; + justify-content: space-between; + align-items: center; + border: 1px solid hsl(0, 0%, 58%); +} + +.todo { + display: flex; + justify-content: flex-start; + align-items: center; +} + +input[type="checkbox"] { + min-width: 30px; + min-height: 30px; + margin-right: 1rem; +} + +button { + min-width: 50px; + min-height: 50px; + border: 1px solid #333; + border-radius: 10%; + cursor: pointer; +} + +.trash { + background-color: #fff; + color: mediumvioletred; +} + +.trash:focus, .trash:hover { + filter:brightness(120%) +} + +form { + padding: 1rem; + display: flex; + justify-content: space-between; + align-items: center; + border: 1px solid #333; + margin-bottom: 1rem; } -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; +form label { + position: absolute; + left: -10000px; } + +.new-todo { + width: 100%; + padding-right: 30px; +} + +input[type="text"] { + width: 100%; + padding: 0.5rem; + border-radius: 10px; + border: 0.5px solid #333; +} + +.submit { + background-color: gray; + color: #fff; +} + +.submit:focus, .submit:hover { + background-color: limegreen; +} \ No newline at end of file diff --git a/src/index.js b/src/index.js index e13abdb..232ef2c 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,5 @@ import React from 'react'; -import ReactDOM from 'react-dom'; +import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App';