|
1 | | - let tasks = []; |
2 | | - let subjects = ['Personal', 'School', 'Work']; |
3 | | - let currentTab = 'personal'; |
4 | | - let userName = ''; |
| 1 | +let tasks = []; |
| 2 | + let username = ''; |
| 3 | + let tags = ['work', 'personal', 'urgent', 'longterm']; |
5 | 4 |
|
6 | | - function init() { |
| 5 | + function initApp() { |
7 | 6 | loadData(); |
8 | | - if (!userName) { |
9 | | - userName = prompt("Please enter your name:"); |
10 | | - if (userName) { |
11 | | - localStorage.setItem('userName', userName); |
12 | | - } |
| 7 | + if (!username) { |
| 8 | + username = prompt("Welcome! Please enter your name:"); |
| 9 | + localStorage.setItem('username', username); |
13 | 10 | } |
14 | 11 | updateGreeting(); |
15 | | - updateSubjectSelect(); |
16 | 12 | renderTasks(); |
17 | 13 | updateCharts(); |
| 14 | + setupEventListeners(); |
18 | 15 | } |
19 | 16 |
|
20 | 17 | function updateGreeting() { |
21 | | - document.getElementById('greeting').textContent = `Hi, ${userName}!`; |
| 18 | + document.getElementById('greeting').textContent = `Hi, ${username}! Let's get things done.`; |
22 | 19 | } |
23 | 20 |
|
24 | | - function switchTab(tab) { |
25 | | - currentTab = tab; |
26 | | - renderTasks(); |
| 21 | + function loadData() { |
| 22 | + const storedTasks = localStorage.getItem('tasks'); |
| 23 | + if (storedTasks) { |
| 24 | + tasks = JSON.parse(storedTasks); |
| 25 | + } |
| 26 | + username = localStorage.getItem('username') || ''; |
| 27 | + const storedTags = localStorage.getItem('tags'); |
| 28 | + if (storedTags) { |
| 29 | + tags = JSON.parse(storedTags); |
| 30 | + } |
| 31 | + updateTagDropdown(); |
| 32 | + } |
| 33 | + |
| 34 | + function saveData() { |
| 35 | + localStorage.setItem('tasks', JSON.stringify(tasks)); |
| 36 | + localStorage.setItem('tags', JSON.stringify(tags)); |
| 37 | + } |
| 38 | + |
| 39 | + function updateTagDropdown() { |
| 40 | + const tagSelect = document.getElementById('taskTags'); |
| 41 | + tagSelect.innerHTML = ''; |
| 42 | + tags.forEach(tag => { |
| 43 | + const option = document.createElement('option'); |
| 44 | + option.value = tag; |
| 45 | + option.textContent = tag; |
| 46 | + tagSelect.appendChild(option); |
| 47 | + }); |
27 | 48 | } |
28 | 49 |
|
29 | 50 | function addTask() { |
30 | | - const taskText = document.getElementById('taskInput').value; |
31 | | - const subject = document.getElementById('subjectSelect').value; |
32 | | - const priority = document.getElementById('prioritySelect').value; |
33 | | - const dueDate = document.getElementById('dueDateInput').value; |
34 | | - if (taskText) { |
35 | | - tasks.push({ |
36 | | - text: taskText, |
| 51 | + const name = document.getElementById('taskName').value; |
| 52 | + const priority = document.getElementById('taskPriority').value; |
| 53 | + const dueDate = document.getElementById('taskDueDate').value; |
| 54 | + const selectedTags = Array.from(document.getElementById('taskTags').selectedOptions).map(option => option.value); |
| 55 | + |
| 56 | + if (name) { |
| 57 | + const newTask = { |
| 58 | + id: Date.now(), |
| 59 | + name, |
| 60 | + priority, |
| 61 | + dueDate, |
| 62 | + tags: selectedTags, |
37 | 63 | completed: false, |
38 | | - subject: subject, |
39 | | - priority: priority, |
40 | | - dueDate: dueDate, |
41 | | - subtasks: [], |
42 | | - tab: currentTab |
43 | | - }); |
44 | | - document.getElementById('taskInput').value = ''; |
| 64 | + category: document.querySelector('.custom-tab.active').dataset.tab |
| 65 | + }; |
| 66 | + tasks.push(newTask); |
45 | 67 | saveData(); |
46 | 68 | renderTasks(); |
47 | 69 | updateCharts(); |
| 70 | + clearForm(); |
48 | 71 | } |
49 | 72 | } |
50 | 73 |
|
51 | | - function addSubject() { |
52 | | - const subject = document.getElementById('subjectInput').value; |
53 | | - if (subject && !subjects.includes(subject)) { |
54 | | - subjects.push(subject); |
55 | | - document.getElementById('subjectInput').value = ''; |
56 | | - updateSubjectSelect(); |
57 | | - saveData(); |
58 | | - } |
59 | | - } |
| 74 | + function renderTasks() { |
| 75 | + const taskList = document.getElementById('taskList'); |
| 76 | + taskList.innerHTML = ''; |
60 | 77 |
|
61 | | - function updateSubjectSelect() { |
62 | | - const select = document.getElementById('subjectSelect'); |
63 | | - select.innerHTML = ''; |
64 | | - subjects.forEach(subject => { |
65 | | - const option = document.createElement('option'); |
66 | | - option.value = subject; |
67 | | - option.textContent = subject; |
68 | | - select.appendChild(option); |
| 78 | + const activeTab = document.querySelector('.custom-tab.active').dataset.tab; |
| 79 | + const filteredTasks = tasks.filter(task => task.category === activeTab); |
| 80 | + |
| 81 | + filteredTasks.forEach(task => { |
| 82 | + const taskElement = createTaskElement(task); |
| 83 | + taskList.appendChild(taskElement); |
69 | 84 | }); |
70 | 85 | } |
71 | 86 |
|
72 | | - function addSubtask(taskIndex) { |
73 | | - const subtaskText = prompt("Enter subtask:"); |
74 | | - if (subtaskText) { |
75 | | - tasks[taskIndex].subtasks.push({ text: subtaskText, completed: false }); |
| 87 | + function createTaskElement(task) { |
| 88 | + const taskElement = document.createElement('div'); |
| 89 | + taskElement.classList.add('task-item', `${task.priority}-priority`); |
| 90 | + taskElement.innerHTML = ` |
| 91 | + <h3 class="text-lg font-semibold">${task.name}</h3> |
| 92 | + <p class="text-sm text-gray-400 mb-2">Due: ${task.dueDate}</p> |
| 93 | + <div class="flex flex-wrap gap-2 mb-2"> |
| 94 | + ${task.tags.map(tag => `<span class="px-2 py-1 bg-blue-600 text-white rounded-full text-sm">${tag}</span>`).join('')} |
| 95 | + </div> |
| 96 | + <div class="mt-2"> |
| 97 | + <button class="edit-task-btn px-2 py-1 bg-yellow-600 text-white rounded hover:bg-yellow-700 transition-colors">Edit</button> |
| 98 | + <button class="delete-task-btn px-2 py-1 bg-red-600 text-white rounded hover:bg-red-700 transition-colors">Delete</button> |
| 99 | + <button class="toggle-complete-btn px-2 py-1 bg-green-600 text-white rounded hover:bg-green-700 transition-colors"> |
| 100 | + ${task.completed ? 'Mark Incomplete' : 'Mark Complete'} |
| 101 | + </button> |
| 102 | + </div> |
| 103 | + `; |
| 104 | + |
| 105 | + const editBtn = taskElement.querySelector('.edit-task-btn'); |
| 106 | + editBtn.addEventListener('click', () => editTask(task)); |
| 107 | + |
| 108 | + const deleteBtn = taskElement.querySelector('.delete-task-btn'); |
| 109 | + deleteBtn.addEventListener('click', () => deleteTask(task.id)); |
| 110 | + |
| 111 | + const toggleCompleteBtn = taskElement.querySelector('.toggle-complete-btn'); |
| 112 | + toggleCompleteBtn.addEventListener('click', () => toggleTaskComplete(task)); |
| 113 | + |
| 114 | + return taskElement; |
| 115 | + } |
| 116 | + |
| 117 | + function editTask(task) { |
| 118 | + const newName = prompt('Enter new task name:', task.name); |
| 119 | + if (newName) { |
| 120 | + task.name = newName; |
76 | 121 | saveData(); |
77 | 122 | renderTasks(); |
| 123 | + updateCharts(); |
78 | 124 | } |
79 | 125 | } |
80 | 126 |
|
81 | | - function toggleTaskCompletion(taskIndex) { |
82 | | - tasks[taskIndex].completed = !tasks[taskIndex].completed; |
| 127 | + function deleteTask(taskId) { |
| 128 | + tasks = tasks.filter(task => task.id !== taskId); |
83 | 129 | saveData(); |
84 | 130 | renderTasks(); |
85 | 131 | updateCharts(); |
86 | 132 | } |
87 | 133 |
|
88 | | - function toggleSubtaskCompletion(taskIndex, subtaskIndex) { |
89 | | - tasks[taskIndex].subtasks[subtaskIndex].completed = !tasks[taskIndex].subtasks[subtaskIndex].completed; |
90 | | - saveData(); |
91 | | - renderTasks(); |
92 | | - } |
93 | | - |
94 | | - function deleteTask(taskIndex) { |
95 | | - tasks.splice(taskIndex, 1); |
| 134 | + function toggleTaskComplete(task) { |
| 135 | + task.completed = !task.completed; |
96 | 136 | saveData(); |
97 | 137 | renderTasks(); |
98 | 138 | updateCharts(); |
99 | 139 | } |
100 | 140 |
|
101 | | - function editTask(taskIndex) { |
102 | | - const newText = prompt("Edit task:", tasks[taskIndex].text); |
103 | | - if (newText !== null) { |
104 | | - tasks[taskIndex].text = newText; |
105 | | - saveData(); |
106 | | - renderTasks(); |
107 | | - } |
108 | | - } |
109 | | - |
110 | | - function renderTasks() { |
111 | | - const taskList = document.getElementById('taskList'); |
112 | | - taskList.innerHTML = ''; |
113 | | - tasks.filter(task => task.tab === currentTab).forEach((task, index) => { |
114 | | - const li = document.createElement('li'); |
115 | | - li.innerHTML = ` |
116 | | - <input type="checkbox" ${task.completed ? 'checked' : ''} onchange="toggleTaskCompletion(${index})"> |
117 | | - <span class="${task.completed ? 'completed' : ''} priority-${task.priority}">${task.text}</span> |
118 | | - <span>(${task.subject})</span> |
119 | | - <span>Due: ${task.dueDate}</span> |
120 | | - <button onclick="editTask(${index})">Edit</button> |
121 | | - <button onclick="deleteTask(${index})">Delete</button> |
122 | | - <button onclick="addSubtask(${index})">Add Subtask</button> |
123 | | - `; |
124 | | - const subtaskList = document.createElement('ul'); |
125 | | - task.subtasks.forEach((subtask, subtaskIndex) => { |
126 | | - const subtaskLi = document.createElement('li'); |
127 | | - subtaskLi.className = 'subtask'; |
128 | | - subtaskLi.innerHTML = ` |
129 | | - <input type="checkbox" ${subtask.completed ? 'checked' : ''} onchange="toggleSubtaskCompletion(${index}, ${subtaskIndex})"> |
130 | | - <span class="${subtask.completed ? 'completed' : ''}">${subtask.text}</span> |
131 | | - `; |
132 | | - subtaskList.appendChild(subtaskLi); |
133 | | - }); |
134 | | - li.appendChild(subtaskList); |
135 | | - taskList.appendChild(li); |
136 | | - }); |
| 141 | + function clearForm() { |
| 142 | + document.getElementById('taskName').value = ''; |
| 143 | + document.getElementById('taskPriority').value = 'low'; |
| 144 | + document.getElementById('taskDueDate').value = ''; |
| 145 | + document.getElementById('taskTags').selectedIndex = -1; |
137 | 146 | } |
138 | 147 |
|
139 | 148 | function updateCharts() { |
140 | 149 | updatePriorityChart(); |
141 | | - updateSubjectChart(); |
| 150 | + updateTagChart(); |
142 | 151 | } |
143 | 152 |
|
144 | 153 | function updatePriorityChart() { |
145 | | - const ctx = document.getElementById('priorityChart').getContext('2d'); |
146 | 154 | const priorityCounts = { |
147 | 155 | low: tasks.filter(task => task.priority === 'low').length, |
148 | 156 | medium: tasks.filter(task => task.priority === 'medium').length, |
149 | 157 | high: tasks.filter(task => task.priority === 'high').length |
150 | 158 | }; |
| 159 | + |
| 160 | + const ctx = document.getElementById('priorityChart').getContext('2d'); |
151 | 161 | new Chart(ctx, { |
152 | 162 | type: 'pie', |
153 | 163 | data: { |
154 | 164 | labels: ['Low', 'Medium', 'High'], |
155 | 165 | datasets: [{ |
156 | 166 | data: [priorityCounts.low, priorityCounts.medium, priorityCounts.high], |
157 | | - backgroundColor: ['#00C851', '#ffbb33', '#ff4444'] |
| 167 | + backgroundColor: ['#10B981', '#F59E0B', '#EF4444'] |
158 | 168 | }] |
159 | 169 | }, |
160 | 170 | options: { |
161 | 171 | responsive: true, |
162 | | - title: { |
163 | | - display: true, |
164 | | - text: 'Tasks by Priority' |
| 172 | + plugins: { |
| 173 | + title: { |
| 174 | + display: true, |
| 175 | + text: 'Tasks by Priority', |
| 176 | + color: '#fff' |
| 177 | + }, |
| 178 | + legend: { |
| 179 | + labels: { |
| 180 | + color: '#fff' |
| 181 | + } |
| 182 | + } |
165 | 183 | } |
166 | 184 | } |
167 | 185 | }); |
168 | 186 | } |
169 | 187 |
|
170 | | - function updateSubjectChart() { |
171 | | - const ctx = document.getElementById('subjectChart').getContext('2d'); |
172 | | - const subjectCounts = {}; |
173 | | - tasks.forEach(task => { |
174 | | - subjectCounts[task.subject] = (subjectCounts[task.subject] || 0) + 1; |
| 188 | + function updateTagChart() { |
| 189 | + const tagCounts = {}; |
| 190 | + tags.forEach(tag => { |
| 191 | + tagCounts[tag] = tasks.filter(task => task.tags.includes(tag)).length; |
175 | 192 | }); |
| 193 | + |
| 194 | + const ctx = document.getElementById('tagChart').getContext('2d'); |
176 | 195 | new Chart(ctx, { |
177 | 196 | type: 'bar', |
178 | 197 | data: { |
179 | | - labels: Object.keys(subjectCounts), |
| 198 | + labels: Object.keys(tagCounts), |
180 | 199 | datasets: [{ |
181 | | - label: 'Tasks per Subject', |
182 | | - data: Object.values(subjectCounts), |
183 | | - backgroundColor: '#4CAF50' |
| 200 | + label: 'Tasks per Tag', |
| 201 | + data: Object.values(tagCounts), |
| 202 | + backgroundColor: '#3B82F6' |
184 | 203 | }] |
185 | 204 | }, |
186 | 205 | options: { |
187 | 206 | responsive: true, |
| 207 | + plugins: { |
| 208 | + title: { |
| 209 | + display: true, |
| 210 | + text: 'Tasks by Tag', |
| 211 | + color: '#fff' |
| 212 | + }, |
| 213 | + legend: { |
| 214 | + labels: { |
| 215 | + color: '#fff' |
| 216 | + } |
| 217 | + } |
| 218 | + }, |
188 | 219 | scales: { |
| 220 | + x: { |
| 221 | + ticks: { color: '#fff' } |
| 222 | + }, |
189 | 223 | y: { |
190 | | - beginAtZero: true, |
191 | | - ticks: { |
192 | | - stepSize: 1 |
193 | | - } |
| 224 | + ticks: { color: '#fff' } |
194 | 225 | } |
195 | 226 | } |
196 | 227 | } |
197 | 228 | }); |
198 | 229 | } |
199 | 230 |
|
200 | | - function saveData() { |
201 | | - localStorage.setItem('tasks', JSON.stringify(tasks)); |
202 | | - localStorage.setItem('subjects', JSON.stringify(subjects)); |
| 231 | + function setupEventListeners() { |
| 232 | + document.getElementById('addTaskBtn').addEventListener('click', addTask); |
| 233 | + document.getElementById('clearCompletedBtn').addEventListener('click', clearCompletedTasks); |
| 234 | + document.getElementById('exportDataBtn').addEventListener('click', exportData); |
| 235 | + document.getElementById('addTabBtn').addEventListener('click', addNewTab); |
| 236 | + document.getElementById('newTag').addEventListener('keypress', function(e) { |
| 237 | + if (e.key === 'Enter') { |
| 238 | + addNewTag(); |
| 239 | + } |
| 240 | + }); |
| 241 | + document.querySelectorAll('.custom-tab').forEach(tab => { |
| 242 | + tab.addEventListener('click', () => switchTab(tab.dataset.tab)); |
| 243 | + }); |
203 | 244 | } |
204 | 245 |
|
205 | | - function loadData() { |
206 | | - const savedTasks = localStorage.getItem('tasks'); |
207 | | - const savedSubjects = localStorage.getItem('subjects'); |
208 | | - userName = localStorage.getItem('userName'); |
209 | | - if (savedTasks) tasks = JSON.parse(savedTasks); |
210 | | - if (savedSubjects) subjects = JSON.parse(savedSubjects); |
| 246 | + function clearCompletedTasks() { |
| 247 | + tasks = tasks.filter(task => !task.completed); |
| 248 | + saveData(); |
| 249 | + renderTasks(); |
| 250 | + updateCharts(); |
| 251 | + } |
| 252 | + |
| 253 | + function exportData() { |
| 254 | + const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(tasks)); |
| 255 | + const downloadAnchorNode = document.createElement('a'); |
| 256 | + downloadAnchorNode.setAttribute("href", dataStr); |
| 257 | + downloadAnchorNode.setAttribute("download", "tasks.json"); |
| 258 | + document.body.appendChild(downloadAnchorNode); |
| 259 | + downloadAnchorNode.click(); |
| 260 | + downloadAnchorNode.remove(); |
211 | 261 | } |
212 | 262 |
|
213 | | - window.onload = init; |
| 263 | + function addNewTab() { |
| 264 | + const tabName = prompt("Enter new tab name:"); |
| 265 | + if (tabName) { |
| 266 | + const tabList = document.getElementById('tabList'); |
| 267 | + const newTab = document.createElement('button'); |
| 268 | + newTab.classList.add('custom-tab'); |
| 269 | + newTab.dataset.tab = tabName.toLowerCase(); |
| 270 | + newTab.textContent = |
0 commit comments