ListToDo.jsx (10737B) - raw
1 import React, { useState } from "react"; 2 import { useSelector, useDispatch } from "react-redux"; 3 import { 4 change_done, 5 remove_todo, 6 edit_todo, 7 set_sort_todo, 8 sort_todo, 9 refresh_filtered_todos, 10 select_todos, 11 select_current_sorting, 12 } from "../features/todo/reducer"; 13 14 function sort_table_header(prefix, current_sorting) { 15 if (prefix.toLowerCase().startsWith(current_sorting.substr(0, 3))) { 16 switch (current_sorting.substr(-1)) { 17 case "^": 18 // Write Prefix and an arrow pointing up. 19 return ( 20 <> 21 {prefix} <span>↑</span> 22 </> 23 ); 24 case "v": 25 // Write Prefix and an arrow pointing down. 26 return ( 27 <> 28 {prefix} <span>↓</span> 29 </> 30 ); 31 } 32 } else { 33 // Write Prefix and four dots. No sorting. 34 return ( 35 <> 36 {prefix} <span>⁛</span> 37 </> 38 ); 39 } 40 } 41 42 function list_of_todos(edit_button, delete_button) { 43 const dispatch = useDispatch(); 44 const my_todos = useSelector(select_todos); 45 const my_sorting = useSelector(select_current_sorting); 46 47 function handle_sort_todos(where_clicked) { 48 dispatch( 49 set_sort_todo({ 50 where_clicked: where_clicked, 51 }) 52 ); 53 dispatch(sort_todo()); 54 dispatch(refresh_filtered_todos()); 55 } 56 57 // Table contents 58 var table_head = ( 59 <thead> 60 <tr> 61 <th scope="col">Done</th> 62 <th scope="col">Name</th> 63 <th scope="col" onClick={() => handle_sort_todos("priority")}> 64 {sort_table_header("Priority", my_sorting)} 65 </th> 66 <th 67 scope="col" 68 onClick={() => { 69 handle_sort_todos("due_date"); 70 }} 71 > 72 {sort_table_header("Due Date", my_sorting)} 73 </th> 74 <th scope="col">Actions</th> 75 </tr> 76 </thead> 77 ); 78 79 var table_body = ( 80 <tbody className="table-group-divider"> 81 {my_todos.map((item) => ( 82 <tr key={item.id}> 83 <th scope="row"> 84 <div className="form-check"> 85 <input 86 className="form-check-input" 87 type="checkbox" 88 checked={item.done} 89 id={"list-todo-done-" + item.id} 90 onChange={(e) => { 91 dispatch( 92 change_done({ 93 id: item.id, 94 done: e.target.checked, 95 }) 96 ), 97 dispatch(refresh_filtered_todos()); 98 }} 99 ></input> 100 </div> 101 </th> 102 <td>{item.text}</td> 103 <td>{item.priority}</td> 104 <td>{item.due_date}</td> 105 <td> 106 <div className="btn-group btn-group-sm" role="group"> 107 {edit_button(item)} 108 {delete_button(item)} 109 </div> 110 </td> 111 </tr> 112 ))} 113 </tbody> 114 ); 115 116 return ( 117 <div className="container"> 118 <table className="table align-middle"> 119 {table_head} 120 {table_body} 121 </table> 122 </div> 123 ); 124 } 125 126 function new_modal(modal_id, modal_header, modal_body, modal_footer) { 127 return ( 128 <div className="modal fade" id={modal_id} tabIndex="-1" role="dialog"> 129 <div className="modal-dialog modal-dialog-centered" role="document"> 130 <div className="modal-content"> 131 {modal_header} 132 {modal_body} 133 {modal_footer} 134 </div> 135 </div> 136 </div> 137 ); 138 } 139 140 export function ListToDos() { 141 const dispatch = useDispatch(); 142 143 const [edit_id, set_edit_id] = useState(-1); 144 const [edit_text, set_edit_text] = useState(""); 145 const [edit_due_date, set_edit_due_date] = useState(""); 146 const [edit_done, set_edit_done] = useState(false); 147 const [edit_priority, set_edit_priority] = useState("Low"); 148 149 function handle_open_modal(id, text, due_date, done, priority) { 150 set_edit_id(id); 151 set_edit_text(text); 152 set_edit_due_date(due_date); 153 set_edit_done(done); 154 set_edit_priority(priority); 155 } 156 function handle_exit_modal() { 157 // https://stackoverflow.com/questions/27826381/clearing-form-input-fields-in-bootstrap 158 $("form").get(0).reset(); // Reset form 159 160 set_edit_id(-1); 161 set_edit_text(""); 162 set_edit_done(false); 163 set_edit_priority("Low"); 164 } 165 function handle_edit_todo() { 166 dispatch( 167 edit_todo({ 168 id: edit_id, 169 text: edit_text, 170 due_date: edit_due_date, 171 done: edit_done, 172 priority: edit_priority, 173 }) 174 ); 175 dispatch(sort_todo()); 176 dispatch(refresh_filtered_todos()); 177 handle_exit_modal(); 178 } 179 180 // Define Edit and Remove buttons 181 function edit_button(item) { 182 return ( 183 <button 184 type="button" 185 className="btn btn-outline-dark" 186 data-bs-toggle="modal" 187 data-bs-target="#EditToDo" 188 onClick={() => 189 handle_open_modal( 190 item.id, 191 item.text, 192 item.due_date, 193 item.done, 194 item.priority 195 ) 196 } 197 > 198 Edit 199 </button> 200 ); 201 } 202 function delete_button(item) { 203 return ( 204 <button 205 type="button" 206 className="btn btn-outline-dark" 207 onClick={(e) => { 208 dispatch(remove_todo(item.id)), 209 dispatch(refresh_filtered_todos()); 210 }} 211 > 212 Delete 213 </button> 214 ); 215 } 216 217 // Define modal to edit a to do. 218 var modal_header = ( 219 <div className="modal-header"> 220 <h5 className="modal-title">Edit a to do</h5> 221 <button 222 type="button" 223 className="close" 224 data-bs-dismiss="modal" 225 aria-label="Close edit window" 226 onClick={handle_exit_modal} 227 > 228 <span>×</span> 229 </button> 230 </div> 231 ); 232 var modal_footer = ( 233 <div className="modal-footer"> 234 <button 235 type="button" 236 className="btn btn-secondary" 237 data-bs-dismiss="modal" 238 onClick={handle_exit_modal} 239 > 240 Cancel 241 </button> 242 <button 243 type="button" 244 className="btn btn-primary" 245 onClick={handle_edit_todo} 246 data-bs-dismiss="modal" 247 > 248 Edit 249 </button> 250 </div> 251 ); 252 var modal_body = ( 253 <div className="modal-body"> 254 <form> 255 <div className="form-floating mb-3"> 256 <input 257 className="form-control" 258 id="edit-todo-id" 259 value={edit_id} 260 disabled 261 /> 262 <label htmlFor="edit-todo-id">ID</label> 263 </div> 264 <div className="form-floating mb-3"> 265 <input 266 className="form-control" 267 placeholder="Text" 268 value={edit_text} 269 id="edit-todo-text" 270 onChange={(e) => set_edit_text(e.target.value)} 271 /> 272 <label htmlFor="edit-todo-text">Text</label> 273 </div> 274 <div className="input-group mb-3"> 275 <div className="form-floating"> 276 <input 277 className="form-control" 278 type="date" 279 id="edit-todo-due-date" 280 placeholder="Due date" 281 value={edit_due_date} 282 onChange={(e) => { 283 set_edit_due_date(e.target.value); 284 }} 285 /> 286 <label htmlFor="edit-todo-due-date">Due Date</label> 287 </div> 288 </div> 289 <div className="form-check mb-3"> 290 <input 291 className="form-check-input" 292 type="checkbox" 293 id="edit-todo-done" 294 onClick={(e) => set_edit_done(e.target.checked)} 295 checked={edit_done} 296 /> 297 <label 298 className="form-check-label" 299 htmlFor="edit-todo-done" 300 > 301 Completed 302 </label> 303 </div> 304 <div className="form-floating mb-3"> 305 <select 306 className="form-select" 307 id="edit-todo-priority" 308 value={edit_priority} 309 onChange={(e) => set_edit_priority(e.target.value)} 310 > 311 <option value="Low">Low</option> 312 <option value="Medium">Medium</option> 313 <option value="High">High</option> 314 </select> 315 <label htmlFor="edit-todo-priority">Priority</label> 316 </div> 317 </form> 318 </div> 319 ); 320 321 return ( 322 <> 323 {list_of_todos(edit_button, delete_button)} 324 {new_modal("EditToDo", modal_header, modal_body, modal_footer)} 325 </> 326 ); 327 }