diff --git a/src/App.js b/src/App.js index 6dcaf9b..6222eff 100644 --- a/src/App.js +++ b/src/App.js @@ -2,115 +2,18 @@ import { useState, useEffect } from 'react'; import './App.css'; import Header from './components/Header'; import Todos from './components/Todos'; -import dayjs from 'dayjs'; +import { TodoProvider } from './components/TodoContext'; function App() { - const todoData = [ - { - _id: 1, - title: 'Read boyd language book', - status: false, - deadline: dayjs('2020-09-18T17:11:54'), - }, - { - _id: 2, - title: 'Do My Home Work', - status: true, - deadline: dayjs('2012-02-18T10:16:04'), - }, - { - _id: 3, - title: 'create mini project react', - status: false, - deadline: dayjs('2018-08-18T21:11:54'), - }, - ] - - const [listTasks, setListTasks] = useState(todoData); - const [showListTasks, setShowListTasks] = useState([]); - const [modeSort, setModeSort] = useState('All'); - - const handleSubmit = (task) => { - setListTasks([ - ...listTasks, - { - ...task, - } - ]); - } - - const handleDelete = (_id) => { - setListTasks( - listTasks.filter( t => t._id !== _id) - ) - - } - - const handleCheck = (task) => { - setListTasks( - listTasks.map( t => { - if (t._id === task._id) { - let checkedTask = { - ...task, - status: !task.status, - } - return checkedTask; - } else { - return t; - } - }) - ); - } - - const handleEdit = (task) => { - setListTasks( - listTasks.map( t => { - if ( t._id === task._id) { - return task; - } else { - return t; - } - }) - ) - } - - const handleSortList = (mode) => { - setModeSort(mode); - } - - useEffect(() => { - if( modeSort === 'All') { - setShowListTasks( - listTasks - ) - } else if ( modeSort === 'Incomplete') { - let sortedListTasks = listTasks.filter( t => !t.status ); - setShowListTasks( - sortedListTasks - ) - } else { - let sortedListTasks = listTasks.filter( t => t.status ); - setShowListTasks( - sortedListTasks - ) - } - },[listTasks, modeSort]) - - return ( -
+ +

ToDo List

-
- +
+
+
); } diff --git a/src/components/DialogTodoItem.jsx b/src/components/DialogTodoItem.jsx index 1cb8341..931027e 100644 --- a/src/components/DialogTodoItem.jsx +++ b/src/components/DialogTodoItem.jsx @@ -11,18 +11,20 @@ import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker'; import { v4 as uuid } from 'uuid'; +import { useTodosDispatch } from './TodoContext'; -const DialogTodoItem = ({ mode, open, setOpen, handleSubmit, taskEdited }) => { +const DialogTodoItem = ({ mode, open, setOpen, taskEdited }) => { let id = uuid(); - + const [dateOpen, setDateOpen] = useState(false); const [task, setTask] = useState({ _id: id, title: '', status: false, deadline: dayjs('2018-08-18T21:11:54'), }); - const [dateOpen, setDateOpen] = useState(false); + + const dispatch = useTodosDispatch(); const handleChangeTask = (e) => { if (mode === 'edit') { @@ -54,18 +56,25 @@ const DialogTodoItem = ({ mode, open, setOpen, handleSubmit, taskEdited }) => { }; const submitHandler = () => { - handleSubmit(task) + if ( mode ==='add') { + console.log('add: ',task) + dispatch({ + type: 'added_todo', + payload: task + }) + } else { + dispatch({ + type: 'changed_todo', + payload: task + }) + } setOpen(false); - setTask({ - _id: "", - title: "", - status: false, - deadline: dayjs('2018-08-18T21:11:54') - }); + setTask(null); } useEffect(() => { if( mode === 'edit' ) { + console.log('ini edit: ', taskEdited) setTask({ ...taskEdited }) @@ -98,9 +107,9 @@ const DialogTodoItem = ({ mode, open, setOpen, handleSubmit, taskEdited }) => { name="status" select label="Status" - defaultValue="Incompelete" + defaultValue={task.status} fullWidth - value={task.status} + value={ task.status } onChange={handleChangeTask} required > @@ -116,7 +125,8 @@ const DialogTodoItem = ({ mode, open, setOpen, handleSubmit, taskEdited }) => { onClose={() => setDateOpen(false)} onChange={handleChangeDateTask} renderInput={(params) => setDateOpen(true)} />} + onClick={() => setDateOpen(true)} + />} /> diff --git a/src/components/Header.jsx b/src/components/Header.jsx index 3c28b3f..3318962 100644 --- a/src/components/Header.jsx +++ b/src/components/Header.jsx @@ -1,21 +1,28 @@ import { useState } from 'react'; import DialogTodoItem from './DialogTodoItem'; +import { useTodosDispatch } from './TodoContext'; -const Header = ({ handleSubmit, sortHandler }) => { +const Header = () => { const [open, setOpen] = useState(false); + const dispatch = useTodosDispatch(); return(
- dispatch({ + type: 'sorted_todo', + payload: e.target.value + }) + } className="bg-gray-300 rounded-lg font-medium text-gray-600 px-4 py-2" > - { open && } + { open && }
) diff --git a/src/components/TodoContext.jsx b/src/components/TodoContext.jsx new file mode 100644 index 0000000..b59ac3c --- /dev/null +++ b/src/components/TodoContext.jsx @@ -0,0 +1,116 @@ +import { createContext, useContext, useReducer } from 'react'; +import dayjs from 'dayjs'; + +const TodosContext = createContext(null); +const TodosDispatchContext = createContext(null); + +export const TodoProvider = ({ children }) => { + const [todos, dispatch] = useReducer(TodoReducer, initialTodos); + + return( + + + {children} + + + ) +} + +const TodoReducer = ({data: todos, filteredData}, { type, payload, status }) => { + switch(type) { + case 'added_todo': { + let data = [ + ...todos, + { + ...payload + } + ]; + return { + data: data, + filteredData: null + }; + + } + case 'changed_todo': { + + let data = todos.map( t => { + if (t._id === payload._id) { + return { + ...payload, + status: status + } + } else { + return t; + } + }); + + return { + data: data, + filteredData: null + } + + } + case 'sorted_todo': { + if( payload === 'All') { + return { + data: todos, + filteredData: null + }; + } else if ( payload === 'Incomplete') { + return { + data: todos, + filteredData: todos.filter( t => !t.status ) + }; + } else { + return { + data: todos, + filteredData: todos.filter( t => t.status ) + } + } + } + case 'deleted_todo': { + let data = todos.filter( t => t._id !== payload._id); + return { + data: data, + filteredData: null + } + } + default: { + throw Error('Unknown action: ' + payload.type); + } + } + +} + +export const useTodos = () => { + return useContext(TodosContext); +} + +export const useTodosDispatch = () => { + return useContext(TodosDispatchContext); +} + +const initialTodos = { + data: [ + { + _id: 1, + title: 'Read boyd language book', + status: false, + deadline: dayjs('2020-09-18T17:11:54'), + }, + { + _id: 2, + title: 'Do My Home Work', + status: true, + deadline: dayjs('2012-02-18T10:16:04'), + }, + { + _id: 3, + title: 'create mini project react', + status: false, + deadline: dayjs('2018-08-18T21:11:54'), + }, + + ], + filteredData: null +} \ No newline at end of file diff --git a/src/components/TodoItem.jsx b/src/components/TodoItem.jsx index 5cad033..e2fb546 100644 --- a/src/components/TodoItem.jsx +++ b/src/components/TodoItem.jsx @@ -3,31 +3,45 @@ import CheckBoxIcon from '@mui/icons-material/CheckBox'; import DeleteIcon from '@mui/icons-material/Delete'; import EditIcon from '@mui/icons-material/Edit'; import DialogTodoItem from './DialogTodoItem'; +import { useTodosDispatch } from './TodoContext'; -const Task = ( { task, deleteHandler, checkHandler, editeHandler } ) => { +const Task = ({ todo }) => { const [openEdit, setOpenEdit] = useState(false); + const dispatch = useTodosDispatch(); + // console.log(todo.deadline) return(
-
- {task.title} + className={`text-gray-700 font-medium ${todo.status && 'line-through'} `} > + {todo.title} - {task.deadline.$d.toLocaleString()} + {(todo.deadline.$d).toLocaleString()}
-
{ openEdit && - + }
) diff --git a/src/components/Todos.jsx b/src/components/Todos.jsx index c8ec8b4..3358ffb 100644 --- a/src/components/Todos.jsx +++ b/src/components/Todos.jsx @@ -1,20 +1,27 @@ import Task from './TodoItem'; +import { useTodos } from './TodoContext'; -const Tasks = ({ tasks, deleteHandler, checkHandler, editeHandler }) => { +const Tasks = () => { + + const {data: todos, filteredData} = useTodos(); return(
- { tasks.length > 0 ? tasks.map( (task, i) => ( + + { filteredData != null ? filteredData.map( (todo, i) => ( - )) : ( -
- No Todo Found! -
+ )) : ( + todos.length > 0 ? todos.map( (todo, i) => ( + + )) : ( +
+ No Todo Found! +
+ ) ) }