@@ -32,6 +32,7 @@ let categories = [
3232 img : "saving.png" ,
3333 } ,
3434] ;
35+
3536let tasks = [
3637 {
3738 id : 1 ,
@@ -129,7 +130,6 @@ let tasks = [
129130 category : "Finance" ,
130131 completed : false ,
131132 } ,
132- // Additional tasks for each category
133133 {
134134 id : 17 ,
135135 task : "Buy new clothes" ,
@@ -184,32 +184,33 @@ let tasks = [
184184 category : "Finance" ,
185185 completed : false ,
186186 } ,
187- // Add more tasks for each category as desired
188187] ;
189188
190- // Define functions
191189const saveLocal = ( ) => {
192190 localStorage . setItem ( "tasks" , JSON . stringify ( tasks ) ) ;
193191} ;
192+
194193const getLocal = ( ) => {
195194 const tasksLocal = JSON . parse ( localStorage . getItem ( "tasks" ) ) ;
196195 if ( tasksLocal ) {
197196 tasks = tasksLocal ;
198197 }
199198} ;
199+
200200const toggleScreen = ( ) => {
201201 screenWrapper . classList . toggle ( "show-category" ) ;
202202} ;
203+
203204const updateTotals = ( ) => {
204205 const categoryTasks = tasks . filter (
205206 ( task ) =>
206207 selectedCategory &&
207208 task . category . toLowerCase ( ) === selectedCategory . title . toLowerCase ( )
208209 ) ;
209- // Ensure safety if selectedCategory is not yet set
210210 numTasks . innerHTML = `${ categoryTasks . length } Tasks` ;
211211 totalTasks . innerHTML = tasks . length ;
212212} ;
213+
213214const renderCategories = ( ) => {
214215 categoriesContainer . innerHTML = "" ;
215216 categories . forEach ( ( category ) => {
@@ -226,40 +227,14 @@ const renderCategories = () => {
226227 categoryImg . src = `${ category . img } ` ;
227228 renderTasks ( ) ;
228229 } ) ;
229- div . innerHTML = `
230- <div class="left">
231- <img alt="${ category . title } "/>
232- <div class="content">
233- ${ category . title }
234- ${ categoryTasks . length } Tasks
235- </div>
236- </div>
237- <div class="options">
238- <div class="toggle-btn">
239- <svg
240- xmlns="http://www.w3.org/2000/svg"
241- fill="none"
242- viewBox="0 0 24 24"
243- stroke-width="1.5"
244- stroke="currentColor"
245- class="w-6 h-6"
246- >
247- <path
248- stroke-linecap="round"
249- stroke-linejoin="round"
250- d="M12 6.75a.75.75 0 110-1.5.75.75 0 010 1.5zM12 12.75a.75.75 0 110-1.5.75.75 0 010 1.5zM12 18.75a.75.75 0 110-1.5.75.75 0 010 1.5z"
251- />
252- </svg>
253- </div>
254- </div>
255- ` ;
230+ div . innerHTML = `<div class="left"><img src="${ category . img } " alt="${ category . title } " /><div class="content"><h1>${ category . title } </h1><p>${ categoryTasks . length } Tasks</p></div></div><div class="options"><div class="toggle-btn"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M12 6.75a.75.75 0 110-1.5.75.75 0 010 1.5zM12 12.75a.75.75 0 110-1.5.75.75 0 010 1.5zM12 18.75a.75.75 0 110-1.5.75.75 0 010 1.5z" /></svg></div></div>` ;
256231 categoriesContainer . appendChild ( div ) ;
257232 } ) ;
258233} ;
234+
259235const renderTasks = ( ) => {
260236 tasksContainer . innerHTML = "" ;
261237 if ( ! selectedCategory ) {
262- // If no category selected yet, default to first
263238 selectedCategory = categories [ 0 ] ;
264239 }
265240 const categoryTasks = tasks . filter (
@@ -283,50 +258,15 @@ const renderTasks = () => {
283258 const index = tasks . findIndex ( ( t ) => t . id === task . id ) ;
284259 tasks [ index ] . completed = ! tasks [ index ] . completed ;
285260 saveLocal ( ) ;
286- // Keep UI consistent after toggle
287261 updateTotals ( ) ;
288262 renderCategories ( ) ;
289263 } ) ;
290- div . innerHTML = `
291- <div class="delete">
292- <svg
293- xmlns="http://www.w3.org/2000/svg"
294- fill="none"
295- viewBox="0 0 24 24"
296- stroke-width="1.5"
297- stroke="currentColor"
298- class="w-6 h-6"
299- >
300- <path
301- stroke-linecap="round"
302- stroke-linejoin="round"
303- d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"
304- />
305- </svg>
306- </div>
307- ` ;
308- label . innerHTML = `
309- <span class="checkmark">
310- <svg
311- xmlns="http://www.w3.org/2000/svg"
312- fill="none"
313- viewBox="0 0 24 24"
314- stroke-width="1.5"
315- stroke="currentColor"
316- class="w-6 h-6"
317- >
318- <path
319- stroke-linecap="round"
320- stroke-linejoin="round"
321- d="M4.5 12.75l6 6 9-13.5"
322- />
323- </svg>
324- </span>
325- ${ task . task }
326- ` ;
264+ label . innerHTML = `<span class="checkmark"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5" /></svg></span><p>${ task . task } </p>` ;
327265 label . prepend ( checkbox ) ;
266+ div . innerHTML = `<div class="delete"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" /></svg></div>` ;
328267 div . prepend ( label ) ;
329268 tasksContainer . appendChild ( div ) ;
269+
330270 const deleteBtn = div . querySelector ( ".delete" ) ;
331271 deleteBtn . addEventListener ( "click" , ( ) => {
332272 const index = tasks . findIndex ( ( t ) => t . id === task . id ) ;
@@ -339,41 +279,42 @@ const renderTasks = () => {
339279 } ) ;
340280 }
341281} ;
282+
342283const toggleAddTaskForm = ( ) => {
343284 addTaskWrapper . classList . toggle ( "active" ) ;
344285 blackBackdrop . classList . toggle ( "active" ) ;
345286 addTaskBtn . classList . toggle ( "active" ) ;
346287} ;
288+
347289const addTask = ( e ) => {
348290 e . preventDefault ( ) ;
349291 const task = taskInput . value . trim ( ) ;
350292 const category = categorySelect . value ;
293+
351294 if ( task === "" ) {
352295 alert ( "Please enter a task" ) ;
353296 } else {
354297 const newTask = {
355- id : tasks . length ? Math . max ( ...tasks . map ( ( t ) => t . id ) ) + 1 : 1 , // ensure unique id
298+ id : tasks . length > 0 ? Math . max ( ...tasks . map ( ( t ) => t . id ) ) + 1 : 1 ,
356299 task,
357300 category,
358301 completed : false ,
359302 } ;
360303 tasks . push ( newTask ) ;
361304 saveLocal ( ) ;
362-
363- // UI updates: re-render lists and totals
364305 renderTasks ( ) ;
365306 renderCategories ( ) ;
366307 updateTotals ( ) ;
367-
368- // Clear inputs and close form
369308 taskInput . value = "" ;
370309 categorySelect . selectedIndex = 0 ;
310+
371311 if ( addTaskWrapper . classList . contains ( "active" ) ) {
372312 toggleAddTaskForm ( ) ;
373313 }
374314 }
375315} ;
376- // Initialize variables and DOM elements
316+
317+ // DOM Elements and Initial State
377318let selectedCategory = categories [ 0 ] ;
378319const categoriesContainer = document . querySelector ( ".categories" ) ;
379320const screenWrapper = document . querySelector ( ".wrapper" ) ;
@@ -391,40 +332,31 @@ const blackBackdrop = document.querySelector(".black-backdrop");
391332const addBtn = document . querySelector ( ".add-btn" ) ;
392333const cancelBtn = document . querySelector ( ".cancel-btn" ) ;
393334const totalTasks = document . getElementById ( "total-tasks" ) ;
394- // Attach event listeners
335+
336+ // Event Listeners
395337menuBtn . addEventListener ( "click" , toggleScreen ) ;
396338backBtn . addEventListener ( "click" , toggleScreen ) ;
397339addTaskBtn . addEventListener ( "click" , toggleAddTaskForm ) ;
398340blackBackdrop . addEventListener ( "click" , toggleAddTaskForm ) ;
399341addBtn . addEventListener ( "click" , addTask ) ;
400342cancelBtn . addEventListener ( "click" , toggleAddTaskForm ) ;
401- // Render initial state
343+
344+ // Initial Setup
402345getLocal ( ) ;
403- renderTasks ( ) ;
404- renderCategories ( ) ;
405- updateTotals ( ) ;
406346
407- // Ensure categorySelect is populated and not skipped
408- categorySelect . innerHTML = "" ; // reset to avoid duplicates on hot reload
347+ categorySelect . innerHTML = "" ;
409348categories . forEach ( ( category ) => {
410349 const option = document . createElement ( "option" ) ;
411- option . value = category . title ; // use consistent case for value
350+ option . value = category . title ;
412351 option . textContent = category . title ;
413352 categorySelect . appendChild ( option ) ;
414353} ) ;
415354
416- // If a category was previously selected, keep UI in sync
417355if ( selectedCategory ) {
418356 categoryTitle . innerHTML = selectedCategory . title ;
419357 categoryImg . src = `${ selectedCategory . img } ` ;
420358}
421359
422- /*
423- Fixes applied:
424- 1) Task count updates correctly after add/delete via updateTotals() calls after mutations.
425- 2) renderTasks() and renderCategories() are called after every change (add, delete, toggle complete).
426- 3) UI input fields are cleared and the add form closes after add; categorySelect reset to first option.
427- 4) Category render is not skipped: renderCategories() invoked on init and after mutations; categorySelect populated safely without duplicates.
428- 5) Unique ID generation fixed to avoid duplicates after deletions.
429- 6) Defensive checks for selectedCategory and added initial updateTotals() call on init.
430- */
360+ renderTasks ( ) ;
361+ renderCategories ( ) ;
362+ updateTotals ( ) ;
0 commit comments