diff --git a/.env b/.env
index 5bb4b74..50bf507 100644
--- a/.env
+++ b/.env
@@ -1 +1 @@
-REACT_APP_API_ENDPOINT=https://dev.jsonplaceholder.typicode.com/todos
+REACT_APP_API_ENDPOINT=https://jsonplaceholder.typicode.com/todos
diff --git a/src/App.js b/src/App.js
index 8f4e8de..3940c2d 100644
--- a/src/App.js
+++ b/src/App.js
@@ -5,13 +5,25 @@ import TaskList from './components/TaskList';
import { useFetch } from './hooks/useFetch';
const App = () => {
- const [state, tasks] = useFetch(process.env.REACT_APP_API_ENDPOINT);
+ const [state, tasks, update, add] = useFetch(
+ process.env.REACT_APP_API_ENDPOINT,
+ );
+
+ const updateTask = (task) => {
+ update(task.id, task);
+ };
+
+ const addTask = (title) => {
+ add({ title, completed: false });
+ };
return (
<>
TODO List
{state === 'PENDING' && }
- {state === 'SUCCESS' && }
+ {state === 'SUCCESS' && (
+
+ )}
{state === 'FAILED' && Something went wrong}
>
);
diff --git a/src/components/Task.js b/src/components/Task.js
index e205dae..af8c84d 100644
--- a/src/components/Task.js
+++ b/src/components/Task.js
@@ -1,21 +1,11 @@
-import { useState } from 'react';
-
-const Task = ({ task }) => {
- const [item, setItem] = useState(task);
-
- const inputId = `task-${item.id}`;
+const Task = ({ task, updateTask }) => {
+ const inputId = `task-${task.id}`;
const handleInputChange = (event) => {
- setItem({
- ...item,
+ updateTask({
+ ...task,
completed: event.target.checked,
});
-
- fetch(`${process.env.REACT_APP_API_ENDPOINT}/${item.id}`, {
- method: 'PUT',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ completed: event.target.checked }),
- });
};
return (
@@ -23,14 +13,14 @@ const Task = ({ task }) => {
);
diff --git a/src/components/TaskForm.js b/src/components/TaskForm.js
new file mode 100644
index 0000000..dbca0a2
--- /dev/null
+++ b/src/components/TaskForm.js
@@ -0,0 +1,28 @@
+import { useInput } from '../hooks/useInput';
+
+const TaskForm = ({ addTask }) => {
+ const [{ task }, update, reset] = useInput({ task: '' });
+
+ const handleInputChange = (event) => {
+ update(event);
+ };
+
+ const handleSubmit = (event) => {
+ event.preventDefault();
+ addTask(task);
+ reset();
+ };
+
+ return (
+
+ );
+};
+
+export default TaskForm;
diff --git a/src/components/TaskList.js b/src/components/TaskList.js
index 613a3d7..2e63cef 100644
--- a/src/components/TaskList.js
+++ b/src/components/TaskList.js
@@ -1,11 +1,15 @@
import Task from './Task';
+import TaskForm from './TaskForm';
-const TaskList = ({ tasks }) => {
+const TaskList = ({ tasks, updateTask, addTask }) => {
return (
{tasks.map((task) => (
-
+
))}
+ -
+
+
);
};
diff --git a/src/hooks/useFetch.js b/src/hooks/useFetch.js
index ccc34dc..06010f0 100644
--- a/src/hooks/useFetch.js
+++ b/src/hooks/useFetch.js
@@ -5,6 +5,10 @@ export const useFetch = (url) => {
const [requestState, setRequestState] = useState('INITIAL');
useEffect(() => {
+ if (!url) {
+ return;
+ }
+
setRequestState('PENDING');
fetch(url)
@@ -16,5 +20,30 @@ export const useFetch = (url) => {
.catch(() => setRequestState('FAILED'));
}, [url]);
- return [requestState, requestResponse];
+ const patchRequest = async (id, request) => {
+ await fetch(`${process.env.REACT_APP_API_ENDPOINT}/${id}`, {
+ method: 'PATCH',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(request),
+ });
+
+ setRequestResponse((previous) => {
+ return previous.map((object) => (object.id === id ? request : object));
+ });
+ };
+
+ const postRequest = async (request) => {
+ const response = await fetch(`${process.env.REACT_APP_API_ENDPOINT}`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(request),
+ });
+ const json = await response.json();
+
+ setRequestResponse((previous) => {
+ return [...previous, json];
+ });
+ };
+
+ return [requestState, requestResponse, patchRequest, postRequest];
};
diff --git a/src/hooks/useInput.js b/src/hooks/useInput.js
new file mode 100644
index 0000000..310af22
--- /dev/null
+++ b/src/hooks/useInput.js
@@ -0,0 +1,17 @@
+import { useState } from 'react';
+
+export const useInput = (initialValues) => {
+ const [input, setInput] = useState(initialValues);
+
+ const update = (event) => {
+ setInput((previous) => {
+ return { ...previous, [event.target.name]: event.target.value };
+ });
+ };
+
+ const reset = () => {
+ setInput(initialValues);
+ };
+
+ return [input, update, reset];
+};