diff --git a/e2e/app.spec.ts b/e2e/app.spec.ts index 19c15ef..2a2f92b 100644 --- a/e2e/app.spec.ts +++ b/e2e/app.spec.ts @@ -76,7 +76,6 @@ test.describe('Task Manager App', () => { await page.click('#addTaskBtn'); await page.fill('#taskTitle', 'Buy groceries'); await page.fill('#taskDescription', 'Milk, eggs, bread'); - await page.selectOption('#taskPriority', 'high'); await page.click('#taskForm button[type="submit"]'); await expect(page.locator('#taskModal')).not.toHaveClass(/active/); @@ -292,7 +291,6 @@ test.describe('Task Manager App', () => { id: 'overdue-test-1', title: 'Overdue Task', dueDate: dueDate, - priority: 'medium', repeatType: 'none', completed: false, createdDate: new Date().toISOString() @@ -318,7 +316,6 @@ test.describe('Task Manager App', () => { id: 'completed-overdue-1', title: 'Completed Old Task', dueDate: dueDate, - priority: 'medium', repeatType: 'none', completed: true, completedDate: dueDate, @@ -346,56 +343,6 @@ test.describe('Task Manager App', () => { }); }); - // ======================== - // Task Group By - // ======================== - test.describe('task group by', () => { - test.beforeEach(async ({ page }) => { - // Add tasks with different priorities and categories via localStorage - await page.evaluate(() => { - const data = JSON.parse(localStorage.getItem('taskManagerData') || '{}'); - data.tasks = [ - { id: 'task-high', title: 'High Task', priority: 'high', repeatType: 'none', completed: false, createdDate: new Date().toISOString(), category: 'Work' }, - { id: 'task-medium', title: 'Medium Task', priority: 'medium', repeatType: 'none', completed: false, createdDate: new Date().toISOString(), category: 'Personal' }, - { id: 'task-low', title: 'Low Task', priority: 'low', repeatType: 'none', completed: false, createdDate: new Date().toISOString() }, - ]; - localStorage.setItem('taskManagerData', JSON.stringify(data)); - }); - await page.reload(); - await page.waitForSelector('.header'); - await page.click('[data-tab="tasks"]'); - }); - - test('should show group by dropdown', async ({ page }) => { - await expect(page.locator('#groupBySelect')).toBeVisible(); - }); - - test('should group tasks by priority', async ({ page }) => { - await page.selectOption('#groupBySelect', 'priority'); - const headers = page.locator('.task-section-header'); - await expect(headers).toHaveCount(3); - await expect(headers.nth(0)).toHaveText('High Priority'); - await expect(headers.nth(1)).toHaveText('Medium Priority'); - await expect(headers.nth(2)).toHaveText('Low Priority'); - }); - - test('should group tasks by category', async ({ page }) => { - await page.selectOption('#groupBySelect', 'category'); - const headers = page.locator('.task-section-header'); - await expect(headers).toHaveCount(3); - await expect(headers.nth(0)).toHaveText('Personal'); - await expect(headers.nth(1)).toHaveText('Work'); - await expect(headers.nth(2)).toHaveText('Ungrouped'); - }); - - test('should revert to default grouping when no grouping selected', async ({ page }) => { - await page.selectOption('#groupBySelect', 'priority'); - await page.selectOption('#groupBySelect', ''); - // Default view shows no task-section-header for tasks with no due date - await expect(page.locator('.task-item')).toHaveCount(3); - }); - }); - // ======================== // Settings // ======================== @@ -445,15 +392,6 @@ test.describe('Task Manager App', () => { expect(value).toBe('completed'); }); - test('should persist groupBy filter across page reloads', async ({ page }) => { - await page.selectOption('#groupBySelect', 'priority'); - await page.reload(); - await page.waitForSelector('.header'); - await page.click('[data-tab="tasks"]'); - const value = await page.locator('#groupBySelect').inputValue(); - expect(value).toBe('priority'); - }); - test('should persist hideCompleted state across page reloads', async ({ page }) => { await page.click('#hideCompletedBtn'); await expect(page.locator('#hideCompletedBtn')).toContainText('Show Completed'); @@ -465,15 +403,12 @@ test.describe('Task Manager App', () => { test('should reset all filters when Reset Filters is clicked', async ({ page }) => { await page.selectOption('#statusFilter', 'pending'); - await page.selectOption('#groupBySelect', 'category'); await page.click('#hideCompletedBtn'); await page.click('#resetFiltersBtn'); const statusValue = await page.locator('#statusFilter').inputValue(); - const groupByValue = await page.locator('#groupBySelect').inputValue(); expect(statusValue).toBe(''); - expect(groupByValue).toBe(''); await expect(page.locator('#hideCompletedBtn')).toContainText('Hide Completed'); }); diff --git a/index.html b/index.html index 0284dce..222527a 100644 --- a/index.html +++ b/index.html @@ -129,20 +129,12 @@

Tasks

- - @@ -175,30 +167,6 @@

Task Details

-
- - - -
- -
-
- - -
diff --git a/src/app.ts b/src/app.ts index a112a84..2b9101e 100644 --- a/src/app.ts +++ b/src/app.ts @@ -83,12 +83,7 @@ class TaskManager { document.getElementById('cancelTaskBtn')!.addEventListener('click', () => this.closeTaskModal()); document.getElementById('deleteTaskBtn')!.addEventListener('click', () => this.deleteTask()); document.getElementById('taskRepeatType')!.addEventListener('change', (e) => this.updateRepeatTypeUI((e.target as HTMLSelectElement).value)); - document.getElementById('taskCategory')!.addEventListener('change', (e) => this.handleCategoryChange('task', (e.target as HTMLSelectElement).value)); - document.getElementById('taskCategorySave')!.addEventListener('click', () => this.handleAddCategory('task')); - document.getElementById('taskCategoryCancel')!.addEventListener('click', () => this.cancelAddCategory('task')); - document.getElementById('categoryFilter')!.addEventListener('change', () => { this.filterTasks(); this.saveFilterSettings(); }); document.getElementById('statusFilter')!.addEventListener('change', () => { this.filterTasks(); this.saveFilterSettings(); }); - document.getElementById('groupBySelect')!.addEventListener('change', () => { this.filterTasks(); this.saveFilterSettings(); }); document.getElementById('searchTasks')!.addEventListener('input', () => this.filterTasks()); document.getElementById('hideCompletedBtn')!.addEventListener('click', () => this.toggleHideCompleted()); document.getElementById('resetFiltersBtn')!.addEventListener('click', () => this.resetFilters()); @@ -456,10 +451,8 @@ class TaskManager { } saveFilterSettings(): void { - const categoryFilter = (document.getElementById('categoryFilter') as HTMLSelectElement).value; const statusFilter = (document.getElementById('statusFilter') as HTMLSelectElement).value; - const groupBy = (document.getElementById('groupBySelect') as HTMLSelectElement).value; - const settings = { categoryFilter, statusFilter, groupBy, hideCompleted: this.hideCompleted }; + const settings = { statusFilter, hideCompleted: this.hideCompleted }; localStorage.setItem(FILTER_SETTINGS_KEY, JSON.stringify(settings)); } @@ -468,12 +461,8 @@ class TaskManager { if (!raw) return; try { const settings = JSON.parse(raw); - const categoryFilter = document.getElementById('categoryFilter') as HTMLSelectElement; const statusFilter = document.getElementById('statusFilter') as HTMLSelectElement; - const groupBySelect = document.getElementById('groupBySelect') as HTMLSelectElement; - if (settings.categoryFilter !== undefined) categoryFilter.value = settings.categoryFilter; if (settings.statusFilter !== undefined) statusFilter.value = settings.statusFilter; - if (settings.groupBy !== undefined) groupBySelect.value = settings.groupBy; if (settings.hideCompleted) { this.hideCompleted = true; this.updateHideCompletedBtn(); @@ -484,9 +473,7 @@ class TaskManager { } resetFilters(): void { - (document.getElementById('categoryFilter') as HTMLSelectElement).value = ''; (document.getElementById('statusFilter') as HTMLSelectElement).value = ''; - (document.getElementById('groupBySelect') as HTMLSelectElement).value = ''; (document.getElementById('searchTasks') as HTMLInputElement).value = ''; this.hideCompleted = false; this.updateHideCompletedBtn(); @@ -503,16 +490,13 @@ class TaskManager { } renderTasks(): void { - this.updateCategoryFilter(); this.filterTasks(); } filterTasks(): void { const tasks = storage.getTasks(); - const categoryFilter = (document.getElementById('categoryFilter') as HTMLSelectElement).value; const statusFilter = (document.getElementById('statusFilter') as HTMLSelectElement).value; const searchTerm = (document.getElementById('searchTasks') as HTMLInputElement).value.toLowerCase(); - const groupBy = (document.getElementById('groupBySelect') as HTMLSelectElement).value; const today = this.getSelectedDateStr(); const filtersActive = statusFilter || searchTerm; @@ -520,9 +504,6 @@ class TaskManager { // Hide completed filter if (this.hideCompleted && task.completed) return false; - // Category filter - if (categoryFilter && task.category !== categoryFilter) return false; - // Status filter if (statusFilter) { if (statusFilter === 'completed' && !task.completed) return false; @@ -544,46 +525,9 @@ class TaskManager { let html = ''; - if (groupBy === 'priority') { - const priorityLabels: Record = { high: 'High Priority', medium: 'Medium Priority', low: 'Low Priority' }; - const grouped: Record = { high: [], medium: [], low: [], ungrouped: [] }; - filtered.forEach(task => { - if (task.priority && grouped[task.priority]) { - grouped[task.priority].push(task); - } else { - grouped['ungrouped'].push(task); - } - }); - (['high', 'medium', 'low'] as const).forEach(p => { - if (grouped[p].length > 0) { - html += `

${priorityLabels[p]}

`; - html += grouped[p].map(task => this.renderTaskItem(task)).join(''); - } - }); - if (grouped['ungrouped'].length > 0) { - html += `

Ungrouped

`; - html += grouped['ungrouped'].map(task => this.renderTaskItem(task)).join(''); - } - } else if (groupBy === 'category') { - const withCategory = filtered.filter(task => task.category); - const withoutCategory = filtered.filter(task => !task.category); - const categories = [...new Set(withCategory.map(task => task.category as string))].sort(); - categories.forEach(cat => { - const group = withCategory.filter(task => task.category === cat); - if (group.length > 0) { - html += `

${cat}

`; - html += group.map(task => this.renderTaskItem(task)).join(''); - } - }); - if (withoutCategory.length > 0) { - html += `

Ungrouped

`; - html += withoutCategory.map(task => this.renderTaskItem(task)).join(''); - } - } else if (filtersActive) { + if (filtersActive) { html = filtered.map(task => this.renderTaskItem(task)).join(''); } else { - const priorityOrder: Record = { high: 0, medium: 1, low: 2 }; - const overdue = filtered.filter(task => !task.completed && task.dueDate && task.dueDate < today ); @@ -602,7 +546,7 @@ class TaskManager { .sort((a, b) => { if (a.dueDate! < b.dueDate!) return -1; if (a.dueDate! > b.dueDate!) return 1; - return (priorityOrder[a.priority] ?? 1) - (priorityOrder[b.priority] ?? 1); + return a.title.localeCompare(b.title); }); const noDueDate = filtered.filter(task => !task.dueDate); @@ -671,9 +615,7 @@ class TaskManager {
${task.title}
${task.description ? `
${task.description}
` : ''}
- ${task.category ? `📂 ${task.category}` : ''} ${task.dueDate ? `📅 ${task.dueDate}` : ''} - ${task.priority} ${task.repeatType !== 'none' ? `🔁 ${task.repeatType}` : ''}
@@ -683,16 +625,6 @@ class TaskManager { `; } - updateCategoryFilter(): void { - const tasks = storage.getTasks(); - const categories = [...new Set(tasks.map(t => t.category).filter((c): c is string => !!c))]; - const select = document.getElementById('categoryFilter') as HTMLSelectElement; - const currentValue = select.value; - select.innerHTML = '' + - categories.map(cat => ``).join(''); - select.value = currentValue; - } - openTaskModal(taskId: string | null = null): void { this.currentEditingTaskId = taskId; const modal = document.getElementById('taskModal')!; @@ -716,8 +648,6 @@ class TaskManager { (document.getElementById('taskTitle') as HTMLInputElement).value = task.title; (document.getElementById('taskDescription') as HTMLTextAreaElement).value = task.description || ''; (document.getElementById('taskDueDate') as HTMLInputElement).value = task.dueDate || ''; - (document.getElementById('taskCategory') as HTMLSelectElement).value = task.category || ''; - (document.getElementById('taskPriority') as HTMLSelectElement).value = task.priority || 'medium'; (document.getElementById('taskRepeatType') as HTMLSelectElement).value = task.repeatType || 'none'; (document.getElementById('taskProject') as HTMLSelectElement).value = task.projectId || ''; (document.getElementById('taskRepeatUnit') as HTMLInputElement).value = String(task.repeatUnit || 1); @@ -747,9 +677,6 @@ class TaskManager { (document.getElementById('taskRepeatUnit') as HTMLInputElement).value = '1'; } - // Load categories - this.loadCategoryDropdown('task'); - modal.classList.add('active'); } @@ -809,8 +736,6 @@ class TaskManager { title: (document.getElementById('taskTitle') as HTMLInputElement).value, description: (document.getElementById('taskDescription') as HTMLTextAreaElement).value, dueDate: (document.getElementById('taskDueDate') as HTMLInputElement).value, - category: (document.getElementById('taskCategory') as HTMLSelectElement).value, - priority: (document.getElementById('taskPriority') as HTMLSelectElement).value as Task['priority'], repeatType: (document.getElementById('taskRepeatType') as HTMLSelectElement).value as Task['repeatType'], projectId: (document.getElementById('taskProject') as HTMLSelectElement).value || null }; @@ -929,8 +854,6 @@ class TaskManager { const newTask: Partial = { title: completedTask.title, description: completedTask.description, - category: completedTask.category, - priority: completedTask.priority, projectId: completedTask.projectId, repeatType: completedTask.repeatType, repeatUnit: completedTask.repeatUnit, @@ -1116,8 +1039,6 @@ class TaskManager {
${task.title}
${task.dueDate ? `📅 ${task.dueDate}` : ''} - ${task.priority ? `⚡ ${task.priority}` : ''} - ${task.category ? `📂 ${task.category}` : ''}
diff --git a/src/storage.ts b/src/storage.ts index 450fa81..27df0dc 100644 --- a/src/storage.ts +++ b/src/storage.ts @@ -15,8 +15,6 @@ export interface Task { title: string; description?: string; dueDate?: string; - category?: string | null; - priority: 'low' | 'medium' | 'high'; repeatType: 'none' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'custom' | 'movable'; repeatUnit?: number; customRepeatDays?: number; @@ -218,7 +216,6 @@ export class StorageManager { createdDate: new Date().toISOString(), completed: false, title: task.title || '', - priority: task.priority || 'medium', repeatType: task.repeatType || 'none', } as Task; data.tasks.push(newTask); @@ -928,7 +925,6 @@ export class StorageManager { data.categories[idx] = trimmedNew; // Propagate rename to all item types - data.tasks = data.tasks.map(t => t.category === oldName ? { ...t, category: trimmedNew } : t); data.habits = data.habits.map(h => h.category === oldName ? { ...h, category: trimmedNew } : h); data.expenses = data.expenses.map(e => e.category === oldName ? { ...e, category: trimmedNew } : e); data.revenue = data.revenue.map(r => r.category === oldName ? { ...r, category: trimmedNew } : r); @@ -950,7 +946,6 @@ export class StorageManager { data.categories.splice(idx, 1); // Clear category from all item types - data.tasks = data.tasks.map(t => t.category === categoryName ? { ...t, category: null } : t); data.habits = data.habits.map(h => h.category === categoryName ? { ...h, category: null } : h); data.expenses = data.expenses.map(e => e.category === categoryName ? { ...e, category: null } : e); data.revenue = data.revenue.map(r => r.category === categoryName ? { ...r, category: null } : r); diff --git a/tests/storage.test.ts b/tests/storage.test.ts index b8c2567..f008ad3 100644 --- a/tests/storage.test.ts +++ b/tests/storage.test.ts @@ -57,10 +57,9 @@ describe('StorageManager', () => { // ======================== describe('task management', () => { it('should add a task', () => { - const task = storage.addTask({ title: 'Buy groceries', priority: 'high' }); + const task = storage.addTask({ title: 'Buy groceries' }); expect(task.id).toBeDefined(); expect(task.title).toBe('Buy groceries'); - expect(task.priority).toBe('high'); expect(task.completed).toBe(false); expect(task.createdDate).toBeDefined(); }); @@ -91,7 +90,6 @@ describe('StorageManager', () => { it('should set default values for task fields', () => { const task = storage.addTask({ title: 'Minimal' }); - expect(task.priority).toBe('medium'); expect(task.repeatType).toBe('none'); }); }); @@ -358,13 +356,11 @@ describe('StorageManager', () => { }); it('should update a category and propagate to items', () => { - storage.addTask({ title: 'Test', category: 'Work' }); storage.addHabit({ name: 'Test', category: 'Work' }); const result = storage.updateCategory('Work', 'Career'); expect(result).toBe(true); expect(storage.getCategories()).toContain('Career'); expect(storage.getCategories()).not.toContain('Work'); - expect(storage.getTasks()[0].category).toBe('Career'); expect(storage.getHabits()[0].category).toBe('Career'); }); @@ -374,11 +370,11 @@ describe('StorageManager', () => { }); it('should delete a category and clear from items', () => { - storage.addTask({ title: 'Test', category: 'Work' }); + storage.addHabit({ name: 'Test', category: 'Work' }); const result = storage.deleteCategory('Work'); expect(result).toBe(true); expect(storage.getCategories()).not.toContain('Work'); - expect(storage.getTasks()[0].category).toBeNull(); + expect(storage.getHabits()[0].category).toBeNull(); }); });