diff --git a/.env b/.env new file mode 100644 index 00000000..f95c81f1 --- /dev/null +++ b/.env @@ -0,0 +1 @@ +VITE_APP_BACKEND_URL=http://localhost:5000 \ No newline at end of file diff --git a/.gitignore b/.gitignore index d7de12f3..a547bf36 100644 --- a/.gitignore +++ b/.gitignore @@ -12,8 +12,6 @@ dist dist-ssr *.local -.env - # Editor directories and files .vscode/* !.vscode/extensions.json diff --git a/package-lock.json b/package-lock.json index fb50dd28..b8f8182f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "name": "npm-task", "version": "0.0.0", "dependencies": { - "axios": "^1.7.7", + "axios": "^1.7.9", "react": "^18.3.1", "react-dom": "^18.3.1" }, @@ -1887,9 +1887,9 @@ } }, "node_modules/axios": { - "version": "1.7.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", - "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", diff --git a/package.json b/package.json index 0b121eef..e4727ed7 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "test": "vitest" }, "dependencies": { - "axios": "^1.7.7", + "axios": "^1.7.9", "react": "^18.3.1", "react-dom": "^18.3.1" }, diff --git a/src/App.jsx b/src/App.jsx index 899cfa00..1e1e998f 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,27 +1,94 @@ import TaskList from './components/TaskList.jsx'; +import NewTaskForm from './components/NewTaskForm.jsx'; import './App.css'; - -const TASKS = [ - { - id: 1, - title: 'Mow the lawn', - isComplete: false, - }, - { - id: 2, - title: 'Cook Pasta', - isComplete: true, - }, -]; +import { useState, useEffect } from 'react'; +import axios from 'axios'; const App = () => { + const [tasks, setTasks] = useState([]); + const API_BASE_URL = import.meta.env.VITE_APP_BACKEND_URL; + + useEffect(() => { + axios + .get(`${API_BASE_URL}/tasks`) + .then((response) => { + const formattedTasks = response.data.map((task) => ({ + id: task.id, + title: task.title, + isComplete: task.is_complete, + })); + setTasks(formattedTasks); + }) + .catch((error) => { + console.error('Error fetching tasks:', error); + }); + }, []); + + const toggleCompleteTask = (taskId, isComplete) => { + const endpoint = isComplete + ? `${API_BASE_URL}/tasks/${taskId}/mark_incomplete` + : `${API_BASE_URL}/tasks/${taskId}/mark_complete`; + + axios + .patch(endpoint) + .then(() => { + setTasks((prevTasks) => + prevTasks.map((task) => + task.id === taskId ? { ...task, isComplete: !isComplete } : task + ) + ); + }) + .catch((error) => { + console.error('Error toggling task completion:', error); + }); + }; + + const deleteTask = (taskId) => { + axios + .delete(`${API_BASE_URL}/tasks/${taskId}`) + .then(() => { + setTasks((prevTasks) => prevTasks.filter((task) => task.id !== taskId)); + }) + .catch((error) => { + console.error('Error deleting task:', error); + }); + }; + + const convertFromApi = (apiTask) => { + const newTask = { + ...apiTask, + isComplete: apiTask.is_complete, + }; + delete newTask.is_complete; + return newTask; + }; + + const handleSubmit = (taskData) => { + axios.post(`${API_BASE_URL}/tasks`, taskData) + .then((result) => { + setTasks((prevTasks) => [convertFromApi(result.data.task), ...prevTasks]); + }) + .catch((error) => console.log(error)); + }; + return (