diff --git a/backend/db.sqlite3 b/backend/db.sqlite3 index 6265512..dca19f7 100644 Binary files a/backend/db.sqlite3 and b/backend/db.sqlite3 differ diff --git a/package.json b/package.json index c583f14..6bc9fee 100644 --- a/package.json +++ b/package.json @@ -1,45 +1,50 @@ { - "name": "swpp-p3-react-tutorial", - "version": "0.1.0", - "private": true, - "dependencies": { - "@testing-library/jest-dom": "5.16.5", - "@testing-library/react": "13.3.0", - "@testing-library/user-event": "13.5.0", - "@types/jest": "27.5.2", - "@types/node": "16.11.56", - "@types/react": "18.0.17", - "@types/react-dom": "18.0.6", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-router": "6.3.0", - "react-router-dom": "6.3.0", - "react-scripts": "5.0.1", - "typescript": "4.7.4", - "web-vitals": "2.1.4" - }, - "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test", - "eject": "react-scripts eject" - }, - "eslintConfig": { - "extends": [ - "react-app", - "react-app/jest" - ] - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } + "name": "swpp-p3-react-tutorial", + "version": "0.1.0", + "private": false, + "proxy": "http://127.0.0.1:8000", + "dependencies": { + "@reduxjs/toolkit": "^1.8.5", + "@testing-library/jest-dom": "5.16.5", + "@testing-library/react": "13.3.0", + "@testing-library/user-event": "13.5.0", + "@types/jest": "27.5.2", + "@types/node": "16.11.56", + "@types/react": "18.0.17", + "@types/react-dom": "18.0.6", + "axios": "^0.27.2", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-redux": "^8.0.4", + "react-router": "6.3.0", + "react-router-dom": "6.3.0", + "react-scripts": "5.0.1", + "redux": "^4.2.0", + "typescript": "4.7.4", + "web-vitals": "2.1.4" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } } diff --git a/redux-basics.js b/redux-basics.js new file mode 100644 index 0000000..c37baf8 --- /dev/null +++ b/redux-basics.js @@ -0,0 +1,21 @@ +const { configureStore } = require("@reduxjs/toolkit"); // load module in Node.js +const initialState = { number: 0 }; // default state +// create identity reducer +const reducer = (state = initialState, action) => { + if (action.type === "ADD") { + return { ...state, number: state.number + 1 }; + } else if (action.type === "ADD_VALUE") { + return { ...state, number: state.number + action.value }; + } + return state; +}; + +// create redux store +const store = configureStore({ reducer: reducer }); + +store.subscribe(() => { + console.log("[Subscription]", store.getState()); +}); +store.dispatch({ type: "ADD" }); +store.dispatch({ type: "ADD_VALUE", value: 5 }); +console.log(store.getState()); diff --git a/src/App.tsx b/src/App.tsx index 4a1c771..0d2971c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,19 +5,25 @@ import NewTodo from "./containers/TodoList/NewTodo/NewTodo"; import TodoDetail from "./components/TodoDetail/TodoDetail"; function App() { - return ( -
- - - } /> - } /> - } /> - } /> - Not Found} /> - - -
- ); + return ( +
+ + + } + /> + } /> + } /> + } + /> + Not Found} /> + + +
+ ); } export default App; diff --git a/src/components/Todo/Todo.tsx b/src/components/Todo/Todo.tsx index c207bad..156991f 100644 --- a/src/components/Todo/Todo.tsx +++ b/src/components/Todo/Todo.tsx @@ -1,19 +1,28 @@ import "./Todo.css"; interface IProps { - title: string; - clicked?: React.MouseEventHandler; // Defined by React - done: boolean; + title: string; + clickDetail?: React.MouseEventHandler; // Defined by React + clickDone?: () => void; + clickDelete?: () => void; + done: boolean; } const Todo = (props: IProps) => { - return ( -
-
- {props.title} -
- {props.done &&
} -
- ); + return ( +
+
+ {props.title} +
+ {props.done &&
} + + +
+ ); }; export default Todo; diff --git a/src/components/TodoDetail/TodoDetail.tsx b/src/components/TodoDetail/TodoDetail.tsx index dd6fc30..a8da688 100644 --- a/src/components/TodoDetail/TodoDetail.tsx +++ b/src/components/TodoDetail/TodoDetail.tsx @@ -1,22 +1,30 @@ +import { useEffect } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { useParams } from "react-router"; +import { AppDispatch } from "../../store"; +import { selectTodo, fetchTodo } from "../../store/slices/todo"; import "./TodoDetail.css"; -type Props = { - title: string; - content: string; -}; +const TodoDetail = () => { + const { id } = useParams(); + const dispatch = useDispatch(); + const todoState = useSelector(selectTodo); + useEffect(() => { + dispatch(fetchTodo(Number(id))); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [id]); -const TodoDetail = (props: Props) => { - return ( -
-
-
Name:
-
{props.title}
-
-
-
Content:
-
{props.content}
-
-
- ); + return ( +
+
+
Name:
+
{todoState.selectedTodo?.title}
+
+
+
Content:
+
{todoState.selectedTodo?.content}
+
+
+ ); }; export default TodoDetail; diff --git a/src/containers/TodoList/NewTodo/NewTodo.tsx b/src/containers/TodoList/NewTodo/NewTodo.tsx index c23a5fb..8c21195 100644 --- a/src/containers/TodoList/NewTodo/NewTodo.tsx +++ b/src/containers/TodoList/NewTodo/NewTodo.tsx @@ -1,47 +1,55 @@ import { useState } from "react"; import { Navigate } from "react-router-dom"; +import { useDispatch } from "react-redux"; +import { AppDispatch } from "../../../store"; +import { postTodo } from "../../../store/slices/todo"; // import { useNavigate } from "react-router-dom"; import "./NewTodo.css"; export default function NewTodo() { - const [title, setTitle] = useState(""); - const [content, setContent] = useState(""); - const [submitted, setSubmitted] = useState(false); + const [title, setTitle] = useState(""); + const [content, setContent] = useState(""); + const [submitted, setSubmitted] = useState(false); + const dispatch = useDispatch(); - // const navigate = useNavigate() - // const postTodoHandler = () => { - // const data = { title: title, content: content }; - // alert("Submitted\n" + data.title + "\n" + data.content); - // setSubmitted(true); - // navigate('/todos') - // }; + // const navigate = useNavigate() + // const postTodoHandler = () => { + // const data = { title: title, content: content }; + // alert("Submitted\n" + data.title + "\n" + data.content); + // setSubmitted(true); + // navigate('/todos') + // }; - const postTodoHandler = () => { - const data = { title: title, content: content }; - alert("Submitted\n" + data.title + "\n" + data.content); - setSubmitted(true); - }; + const postTodoHandler = async () => { + const data = { title: title, content: content }; + const result = await dispatch(postTodo(data)); + if (result.payload) { + setSubmitted(true); + } else { + alert("Error on post Todo"); + } + }; - if (submitted) { - return ; - } else { - return ( -
-

Add a Todo

- - setTitle(event.target.value)} - /> - -