commit c5b628f17da1bfa17251ecf82fcb146751954b72
parent f3852c1f5bea14e72e200389759f123b880ccfec
Author: Adrián Oliva <[email protected]>
Date:   Sun, 21 May 2023 19:09:15 -0600

First attempt at filtering to do's.

We have a separate list from the original `todos_list`. It saves all currently
filtered to do's for the listing to be as easy as possible.

Diffstat:
Msrc/App.jsx | 2++
Msrc/ToDo-UI/ListToDo.jsx | 15+++++++++++----
Msrc/ToDo-UI/NewToDo.jsx | 2++
Msrc/ToDo-UI/Search.jsx | 62+++++++++++++++++++++++++++++++++++++++++++++++++-------------
Msrc/features/todo/reducer.js | 47+++++++++++++++++++++++++++++++++++++++++++++--
5 files changed, 109 insertions(+), 19 deletions(-)

diff --git a/src/App.jsx b/src/App.jsx @@ -1,10 +1,12 @@ import React from "react"; +import { Search } from "./ToDo-UI/Search"; import { NewToDo } from "./ToDo-UI/NewToDo"; import { ListToDos } from "./ToDo-UI/ListToDo"; function App() { return ( <div> + <Search /> <NewToDo /> <ListToDos /> </div> diff --git a/src/ToDo-UI/ListToDo.jsx b/src/ToDo-UI/ListToDo.jsx @@ -6,6 +6,7 @@ import { edit_todo, set_sort_todo, sort_todo, + refresh_filtered_todos, select_todos, select_current_sorting, } from "../features/todo/reducer"; @@ -50,6 +51,7 @@ function list_of_todos(edit_button, delete_button) { }) ); dispatch(sort_todo()); + dispatch(refresh_filtered_todos()); } // Table contents @@ -85,14 +87,15 @@ function list_of_todos(edit_button, delete_button) { type="checkbox" checked={item.done} id={"list-todo-done-" + item.id} - onChange={(e) => + onChange={(e) => { dispatch( change_done({ id: item.id, done: e.target.checked, }) - ) - } + ), + dispatch(refresh_filtered_todos()); + }} ></input> </div> </th> @@ -170,6 +173,7 @@ export function ListToDos() { }) ); dispatch(sort_todo()); + dispatch(refresh_filtered_todos()); handle_exit_modal(); } @@ -200,7 +204,10 @@ export function ListToDos() { <button type="button" className="btn btn-outline-dark" - onClick={(e) => dispatch(remove_todo(item.id))} + onClick={(e) => { + dispatch(remove_todo(item.id)), + dispatch(refresh_filtered_todos()); + }} > Delete </button> diff --git a/src/ToDo-UI/NewToDo.jsx b/src/ToDo-UI/NewToDo.jsx @@ -3,6 +3,7 @@ import { useSelector, useDispatch } from "react-redux"; import { add_todo, sort_todo, + refresh_filtered_todos, select_last_index, } from "../features/todo/reducer"; @@ -64,6 +65,7 @@ export function NewToDo() { }) ); dispatch(sort_todo()); + dispatch(refresh_filtered_todos()); handle_exit_modal(); } diff --git a/src/ToDo-UI/Search.jsx b/src/ToDo-UI/Search.jsx @@ -1,6 +1,25 @@ -import React from "react"; +import React, { useState } from "react"; +import { useSelector, useDispatch } from "react-redux"; +import { set_filters, refresh_filtered_todos } from "../features/todo/reducer"; export function Search() { + const dispatch = useDispatch(); + + const [search_name, set_search_name] = useState(""); + const [search_priority, set_search_priority] = useState("All"); + const [search_state, set_search_state] = useState("All"); + + function handle_search() { + dispatch( + set_filters({ + name: search_name, + priority: search_priority, + state: search_state, + }) + ); + dispatch(refresh_filtered_todos()); + } + return ( <div className="container mt-3" style={{ border: "2px solid black" }}> <div className="row"> @@ -9,10 +28,9 @@ export function Search() { Name </span> <input - type="text" className="form-control" - aria-label="Name" - aria-describedby="search-name" + type="text" + onChange={(e) => set_search_name(e.target.value)} ></input> </div> </div> @@ -21,11 +39,19 @@ export function Search() { <div className="col-sm-7"> <div className="input-group mb-3 mt-3"> <label className="input-group-text">Priority</label> - <select className="form-select" id="search-priority"> - <option defaultValue>All</option> - <option value="1">High</option> - <option value="2">Medium</option> - <option value="3">Low</option> + <select + className="form-select" + id="search-priority" + onChange={(e) => + set_search_priority(e.target.value) + } + > + <option value="All" defaultValue> + All + </option> + <option value="High">High</option> + <option value="Medium">Medium</option> + <option value="Low">Low</option> </select> </div> </div> @@ -35,17 +61,27 @@ export function Search() { <div className="col-sm-7"> <div className="input-group mb-3 mt-3"> <label className="input-group-text">State</label> - <select className="form-select" id="search-priority"> - <option defaultValue>All</option> + <select + className="form-select" + id="search-priority" + onChange={(e) => set_search_state(e.target.value)} + > + <option value="All" defaultValue> + All + </option> <option value="1">Done</option> - <option value="2">Undone</option> + <option value="0">Undone</option> </select> </div> </div> <div className="col-sm-2"> <div className="d-grid gap-2 d-md-flex justify-content-md-end"> - <button type="button" className="btn btn-outline-dark"> + <button + type="button" + className="btn btn-outline-dark" + onClick={handle_search} + > Search </button> </div> diff --git a/src/features/todo/reducer.js b/src/features/todo/reducer.js @@ -3,9 +3,17 @@ import { createSlice } from "@reduxjs/toolkit"; export const todo_slice = createSlice({ name: "todo_list", initialState: { - todos: [], last_id: 0, + todos: [], + current_sorting: "created_time", + + filtered_todos: [], + current_filters: { + name: "", + priority: "All", + state: "All", + }, }, reducers: { @@ -127,6 +135,39 @@ export const todo_slice = createSlice({ break; } }, + + set_filters: (state, action) => { + state.current_filters = { + name: action.payload.name, + priority: action.payload.priority, + state: action.payload.state, // True is "1" and False is "0". + }; + }, + + refresh_filtered_todos: (state) => { + state.filtered_todos = [...state.todos]; + + // If name, filter by names. + if (state.current_filters.name.length != 0) { + state.filtered_todos = state.filtered_todos.filter((todo) => + todo.text.includes(state.current_filters.name) + ); + } + + // If priority != all, filter by priorities. + if (state.current_filters.priority != "All") { + state.filtered_todos = state.filtered_todos.filter( + (todo) => todo.priority === state.current_filters.priority + ); + } + + // If state != All, filter by current state. + if (state.current_filters.state != "All") { + state.filtered_todos = state.filtered_todos.filter( + (todo) => todo.done == state.current_filters.state + ); + } + }, }, }); @@ -137,9 +178,11 @@ export const { edit_todo, set_sort_todo, sort_todo, + set_filters, + refresh_filtered_todos, } = todo_slice.actions; -export const select_todos = (state) => state.todo_list.todos; +export const select_todos = (state) => state.todo_list.filtered_todos; export const select_last_index = (state) => state.todo_list.last_id; export const select_current_sorting = (state) => state.todo_list.current_sorting;