Skip to content

Context reducer #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 6 additions & 103 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<div className="flex flex-col items-center w-full h-full bg-white my-10 gap-6">
<TodoProvider>
<div className="flex flex-col items-center w-full h-full bg-white my-10 gap-6">
<h1 className="text-4xl font-bold uppercase text-gray-600">ToDo List</h1>
<Header
handleSubmit={handleSubmit}
sortHandler={handleSortList}
/>
<Todos
tasks={showListTasks}
checkHandler={handleCheck}
deleteHandler={handleDelete}
editeHandler={handleEdit} />
<Header />
<Todos />
</div>
</TodoProvider>
);
}

Expand Down
36 changes: 23 additions & 13 deletions src/components/DialogTodoItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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') {
Expand Down Expand Up @@ -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
})
Expand Down Expand Up @@ -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
>
Expand All @@ -116,7 +125,8 @@ const DialogTodoItem = ({ mode, open, setOpen, handleSubmit, taskEdited }) => {
onClose={() => setDateOpen(false)}
onChange={handleChangeDateTask}
renderInput={(params) => <TextField fullWidth {...params}
onClick={() => setDateOpen(true)} />}
onClick={() => setDateOpen(true)}
/>}
/>
</LocalizationProvider>
</Box>
Expand Down
13 changes: 10 additions & 3 deletions src/components/Header.jsx
Original file line number Diff line number Diff line change
@@ -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(
<div className="flex justify-between w-2/4">
<button onClick={() => setOpen(true)}
className="bg-indigo-500 hover:bg-indigo-600 text-white font-medium rounded-md px-5 py-2">Add Task</button>
<select onChange={(e) => sortHandler(e.target.value)}
<select onChange={
(e) => dispatch({
type: 'sorted_todo',
payload: e.target.value
})
}
className="bg-gray-300 rounded-lg font-medium text-gray-600 px-4 py-2" >
<option value="All">All</option>
<option value="Incomplete">Incomplete</option>
<option value="Complete">Complete</option>
</select>

{ open && <DialogTodoItem mode="add" open={open} setOpen={setOpen} handleSubmit={handleSubmit}/> }
{ open && <DialogTodoItem mode="add" open={open} setOpen={setOpen} /> }

</div>
)
Expand Down
116 changes: 116 additions & 0 deletions src/components/TodoContext.jsx
Original file line number Diff line number Diff line change
@@ -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(
<TodosContext.Provider value={todos}>
<TodosDispatchContext.Provider value={dispatch}>
{children}
</TodosDispatchContext.Provider>
</TodosContext.Provider>
)
}

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
}
Loading