I am building a To Do list project using React and TypeScript. In the process of refactoring my code and breaking up different divs (Active tasks, Done tasks, All tasks) into separate files within my component folder, my project is no longer able to filter out tasks that are "Done" or "Active" (this is determined by the checkbox value that is in my ToDoItem file, it has been condensed to a prop: onUpdateToDo) I am confused and stuck over where to filter out my ToDoItem within my "Done" file as I believe that it should be mapped out within the visibleTodos function. The visibleToDos function is in my App.tsx file.
App.tsx
const initialTodosString = localStorage.getItem("toDoList");
const initialTodos = initialTodosString
? JSON.parse(initialTodosString)
: [myToDo1, myToDo2];
export function App(): JSX.Element {
const [toDos, setToDos] = useState<ToDo[]>(initialTodos);
const [addingToDo, setAddingToDo] = useState(false);
const [showingDoneTasks, setShowDoneTasks] = useState(false); // show true if not
const [showingActiveTasks, setShowActiveTasks] = useState(false); // show true if not
const [showingAllTasks, setShowAllTasks] = useState(false);
const [filterTodosCompleted, setFilterTodosCompleted] = useState<any | null>(
null
);
// VISIBLE TO DOS FUNCTION BELOW //
const visibleTodos = useMemo(
() =>
toDos.filter((toDo) => {
if (filterTodosCompleted === null) {
return true;
}
return filterTodosCompleted === toDo.checked;
}),
[filterTodosCompleted, toDos]
);
useEffect(
function () {
localStorage.setItem("toDoList", JSON.stringify(toDos));
},
[toDos]
);
// Showing Active Tasks function //
function showAllTasks(){
setShowAllTasks(true)
setShowDoneTasks(false);
setShowActiveTasks(false);
}
if (showingAllTasks) return (
<AllTasks newTask={newTask}
showActive={showActive}
toDos={toDos}
showDone={showDone}
visibleTodos={toDos}
setToDos={setToDos}/>
)
function showActive() {
setShowActiveTasks(true);
setFilterTodosCompleted(false);
setShowDoneTasks(false);
}
function newTask() {
setAddingToDo(true);
}
if (showingActiveTasks) {
return (
<ActiveTasks
newTask={newTask}
showActive={showActive}
toDos={toDos}
showDone={showDone}
visibleTodos={toDos}
/>
);
}
/// showing Done Tasks function and jsx component with props being passed within
function showDone() {
setShowDoneTasks(true);
setFilterTodosCompleted(true);
setShowActiveTasks(false);
}
if (showingDoneTasks) {
return (
<DoneTasks
newTask={newTask}
showActive={showActive}
toDos={toDos}
showDone={showDone}
visibleTodos={toDos}
setToDos={setToDos}
showAllTasks={showAllTasks}
/>
);
}
if (addingToDo) {
return (
<NewTask
newTask={newTask}
showActive={showActive}
toDos={toDos}
showDone={showDone}
visibleTodos={toDos}
handleFormSubmit={handleFormSubmit}
/>
);
}
function handleFormSubmit(event: FormEvent<HTMLFormElement>) {
const data = Object.fromEntries(
new FormData(event.target as HTMLFormElement)
);
const newDueDate = new Date(data.Date as string);
const timeZoneCorrectedDate = new Date(
newDueDate.getTime() + newDueDate.getTimezoneOffset() * 60 * 1000
); //
debugger;
setToDos([
...toDos,
{
title: data.Title as string,
priority: parseInt(data.Priority as string) as 2 | 1,
description: data.Description as string,
checked: false,
duedate: data.Date ? timeZoneCorrectedDate.getTime() : undefined,
},
]);
}
return (
<div className="App">
<div className="greeting-container">
<div className="greeting">
<Greeting />
</div>
<button className="task-button" onClick={newTask}>
New Task
</button>
<div className="date-container">
Today is {new Date().toLocaleString("en-US", { weekday: "long" })}
<br />
<div className="current-date">
{new Date().toLocaleString("en-US", {
month: "long",
day: "2-digit",
})}
, {new Date().getFullYear()}
</div>
</div>
</div>
<div className="task-container">
<div className="task-counter">
{toDos.length} {toDos.length === 1 ? "Task" : "Tasks"}
</div>
<div className="status-container">
<button id="allButton" onClick={showAllTasks}>
All
</button>
<button id="activeButton" onClick={showActive}>
Active
</button>
<button id="doneButton" onClick={showDone}>
Done
</button>
</div>
</div>
<hr />
{showingDoneTasks ? (
<DoneTasks
newTask={newTask}
showActive={showActive}
toDos={toDos}
showDone={showDone}
visibleTodos={toDos}
setToDos={setToDos}
showAllTasks={showAllTasks}/>) : null}
{visibleTodos.map((toDoItem: ToDo) => (
<ToDoItem
onDeleteToDo={function () {
const updatedToDos = toDos.filter((x) => x !== toDoItem);
setToDos(updatedToDos);
}}
onUpdateTodo={function (updates: any) {
const updatedToDos = toDos.map((x) =>
x === toDoItem ? ({ ...x, ...updates } as any) : x
);
console.log(updates);
setToDos(updatedToDos);
}}
toDo={toDoItem}
/>
))}
</div>
);
}
Done.tsx
import { ToDo } from "../types/ToDo";
import { Greeting } from "./Greeting";
import { ToDoItem } from "./ToDoItem";
export const DoneTasks = (props:{
newTask: () => void
showActive: () => void
toDos: ToDo[];
showDone: () => void
visibleTodos: ToDo[];
setToDos: (value: React.SetStateAction<ToDo[]>) => void
showAllTasks: () => void
}) => (
<div className="App">
<div className="greeting-container">
<div className="greeting">
<Greeting />
</div>
<button className="task-button" onClick={props.newTask}>
New Task
</button>
<div className="date-container">
Today is {new Date().toLocaleString("en-US", { weekday: "long" })}
<br />
<div className="current-date">
{new Date().toLocaleString("en-US", {
month: "long",
day: "2-digit",
})}
, {new Date().getFullYear()}
</div>
</div>
</div>
<div className="task-container">
<div id="completed-task-counter">
{props.toDos.length}{" "}
{props.toDos.length === 1 ? "Completed Task" : "Completed Tasks"}
</div>
<div className="status-container">
<button id="allButton" onClick={props.showAllTasks}>
All
</button>
<button className="activeButton" onClick={props.showActive}>
Active
</button>
<button className="doneButton" onClick={props.showDone}>
Done
</button>
</div>
</div>
<hr />
{props.visibleTodos.map((toDoItem: ToDo) => (
<ToDoItem
onDeleteToDo={function () {
const updatedToDos = props.toDos.filter((x) => x !== toDoItem);
props.setToDos(updatedToDos);
}}
onUpdateTodo={function (updates: any) {
const updatedToDos = props.toDos.map((x) =>
x === toDoItem ? ({ ...x, ...updates } as any) : x
);
console.log(updates);
props.setToDos(updatedToDos);
}}
toDo={toDoItem}
/>
))}
</div>
);
ToDoItem.tsx
export function ToDoItem(props: {
toDo: ToDo;
onDeleteToDo: any;
onUpdateTodo: any;
}) {
const handleOptionsChange = (event: any) => {
const selectBox = event.target;
const newValue = selectBox.value;
const newPriority = parseInt(newValue);
props.onUpdateTodo({ priority: newPriority })
};
const checkBoxCheck = (event: any) => {
const checkBox = event.currentTarget.checked;
const newCheckBoxValue = checkBox;
props.onUpdateTodo({ checked: newCheckBoxValue })
console.log(newCheckBoxValue)
};
const handleDateChange =(event: any) => {
const newDate = event.target.value;
props.onUpdateTodo({ duedate: newDate })
console.log(newDate)
}
if (!props.toDo) {
return <p>Missing To Do</p>;
}
return (
<div
className="to-do-item"
data-priority={props.toDo.priority}
id="to-do-item"
>
<div className="checkbox-title-container">
<div className="check-title-div">
<div>
<input
type="checkbox"
id="checkbox"
onChange={checkBoxCheck}
checked={props.toDo.checked}
/>
</div>
<h2 className="to-do-title">{props.toDo.title}</h2>
</div>
<div id="delete-div">
<select
name="Priority"
className="select-field"
value={props.toDo.priority}
onChange={handleOptionsChange}
>
<option value="1">Important</option>
<option value="2">Normal</option>
</select>
<button id="delete" onClick={props.onDeleteToDo}>
Delete
</button>
</div>
<span className="to-do-date-container">
<input name="Date" type="date" className="to-do-date-input" value={props.toDo.duedate
? new Date(props.toDo.duedate).toISOString().split('T')[0]
: undefined} onChange={handleDateChange}/>
</span>
<div className="description-box">
<span className="description">{props.toDo.description}</span>
</div>
</div>
<br />
</div>
);
}
I am unsure if I am passing the wrong props into DoneTasks? Before I refactored my code, my ShowDone() function worked fine, for some reason the conditions within the showDone function are not being called and I am getting a duplicate of my App.tsx file when it should be returning my ToDoItems that are checked.
The answer is in the line below, each toDo item is being filtered through the condition that it is checked or not, then the map function displays each one:
{props.toDos
.filter((x) => x.checked === true)
.map((toDoItem: ToDo) => (
Rest of code below:
<ToDoItem
onDeleteToDo={function () {
const updatedToDos = props.toDos.filter((x) => x !== toDoItem);
props.setToDos(updatedToDos);
}}
onUpdateTodo={function (updates: any) {
const updatedToDos = props.toDos.map((x) =>
x === toDoItem ? ({ ...x, ...updates } as any) : x
);
props.setToDos(updatedToDos);
}}
toDo={toDoItem}
/>
))}