-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
424 lines (368 loc) · 26.4 KB
/
Copy pathindex.html
File metadata and controls
424 lines (368 loc) · 26.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ManTasker - Dashboard</title>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- html2canvas library for saving as image -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
<!-- Google Fonts: Inter -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Inter', sans-serif;
background-color: #05080f; /* New close-to-black blue */
color: #e2e8f0;
}
#logo-header {
background-color: #0d1117; /* Lighter shade for header */
border-bottom: 1px solid #334155;
}
.page-container {
padding-top: 60px; /* Height of logo header */
padding-bottom: 80px; /* Height of bottom nav */
}
.page { display: none; }
.page.active { display: block; }
.form-input, .form-select {
background-color: #0d1117; border: 1px solid #334155; color: #e2e8f0;
padding: 12px; border-radius: 8px; width: 100%; font-size: 16px;
}
.form-input:focus, .form-select:focus {
outline: none; border-color: #6366f1; box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.5);
}
.btn-primary {
background-color: #6366f1; color: #ffffff; font-weight: 600; padding: 12px;
border-radius: 8px; width: 100%; transition: background-color 0.2s ease-in-out;
}
.btn-primary:hover { background-color: #4f46e5; }
#bottom-nav { background-color: #0d1117; border-top: 1px solid #334155; }
.nav-btn.active { color: #818cf8; }
.task-card { background-color: #0d1117; border-left-width: 4px; }
#save-image-fab { position: fixed; bottom: 90px; right: 20px; z-index: 40; }
.tabs-container { overflow-x: auto; scrollbar-width: none; }
.tabs-container::-webkit-scrollbar { display: none; }
.subject-tab {
background-color: #0d1117; color: #94a3b8;
transition: all 0.2s ease-in-out;
}
.subject-tab.active { background-color: #6366f1; color: white; font-weight: 600; }
.custom-scrollbar::-webkit-scrollbar { width: 6px; }
.custom-scrollbar::-webkit-scrollbar-track { background: transparent; }
.custom-scrollbar::-webkit-scrollbar-thumb { background: #4f46e5; border-radius: 3px; }
.task-category-box {
background-color: #0d1117; /* Lighter shade for content boxes */
border-radius: 8px;
padding: 16px;
min-height: 150px;
}
/* Loading Screen Styles */
#loading-screen {
position: fixed;
inset: 0;
background-color: #05080f;
z-index: 9999;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
transition: opacity 0.5s ease-out;
}
.loader {
--c:no-repeat linear-gradient(orange 0 0);
background:
var(--c),var(--c),var(--c),
var(--c),var(--c),var(--c),
var(--c),var(--c),var(--c);
background-size: 16px 16px;
animation:
l32-1 1s infinite,
l32-2 1s infinite;
}
@keyframes l32-1 {
0%,100% {width:45px;height: 45px}
35%,65% {width:65px;height: 65px}
}
@keyframes l32-2 {
0%,40% {background-position: 0 0,0 50%, 0 100%,50% 100%,100% 100%,100% 50%,100% 0,50% 0, 50% 50% }
60%,100%{background-position: 0 50%, 0 100%,50% 100%,100% 100%,100% 50%,100% 0,50% 0,0 0, 50% 50% }
}
</style>
</head>
<body class="antialiased">
<!-- Loading Screen -->
<div id="loading-screen">
<div class="text-slate-400 text-2xl font-bold tracking-wider mb-8">YOUR LOGO HERE</div>
<div class="loader"></div>
</div>
<div id="app">
<header id="logo-header" class="h-[60px] fixed top-0 left-0 right-0 z-50 flex items-center justify-center">
<div class="text-slate-500 text-lg font-bold tracking-wider">YOUR LOGO HERE</div>
</header>
<div class="page-container">
<!-- Dashboard/Tasks Page -->
<div id="dashboard-page" class="page active">
<div class="p-4 md:p-6 mb-0">
<h1 class="text-3xl font-bold text-white">Dashboard</h1>
<p class="text-slate-400">Select a subject to view your tasks.</p>
</div>
<div id="subject-tabs-container" class="tabs-container p-4 pt-0 md:px-6"><div id="subject-tabs" class="flex items-center space-x-3"></div></div>
<div id="task-list-container" class="px-4 md:px-6 custom-scrollbar" style="height: calc(100vh - 280px); overflow-y: auto;">
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div class="task-category-box"><h2 class="text-lg font-semibold text-red-400 mb-3">Overdue</h2><div id="overdue-tasks" class="space-y-3"></div></div>
<div class="task-category-box"><h2 class="text-lg font-semibold text-yellow-400 mb-3">Today</h2><div id="today-tasks" class="space-y-3"></div></div>
<div class="task-category-box"><h2 class="text-lg font-semibold text-blue-400 mb-3">Upcoming</h2><div id="upcoming-tasks" class="space-y-3"></div></div>
</div>
<div id="quote-box" class="mt-6">
<div class="bg-slate-800 p-4 rounded-lg text-center">
<p id="quote-text" class="text-sm italic text-slate-400"></p>
<p id="quote-author" class="text-xs text-slate-500 mt-1"></p>
</div>
</div>
</div>
</div>
<!-- Add Task Page -->
<div id="add-task-page" class="page p-4 md:p-6">
<header class="mb-6"><h1 class="text-3xl font-bold text-white">Add a New Task</h1><p class="text-slate-400">Fill out the details below.</p></header>
<form id="add-task-form" class="space-y-4">
<div><label for="task-subject" class="block text-sm font-medium text-slate-300 mb-1">Subject</label><select id="task-subject" class="form-select" required></select></div>
<div><label for="task-description" class="block text-sm font-medium text-slate-300 mb-1">Task Description</label><input type="text" id="task-description" class="form-input" placeholder="e.g., Complete calculus homework" required></div>
<div><label for="task-deadline" class="block text-sm font-medium text-slate-300 mb-1">Deadline</label><input type="date" id="task-deadline" class="form-input" required></div>
<div class="grid grid-cols-2 gap-4">
<div><label for="task-necessity" class="block text-sm font-medium text-slate-300 mb-1">Necessity</label><select id="task-necessity" class="form-select" required><option value="High">High</option><option value="Medium" selected>Medium</option><option value="Low">Low</option></select></div>
<div><label for="task-type" class="block text-sm font-medium text-slate-300 mb-1">Type</label><select id="task-type" class="form-select" required><option>Assignment</option><option>Exam Prep</option><option>Project</option><option>Reading</option><option>Quiz</option><option>Other</option></select></div>
</div>
<div class="pt-4"><button type="submit" class="btn-primary">Add Task</button></div>
</form>
</div>
<!-- Add Subject Page -->
<div id="add-subject-page" class="page p-4 md:p-6">
<header class="mb-6"><h1 class="text-3xl font-bold text-white">Add a New Subject</h1><p class="text-slate-400">Create a category for your tasks.</p></header>
<form id="add-subject-form" class="space-y-4">
<div><label for="subject-code" class="block text-sm font-medium text-slate-300 mb-1">Subject Code</label><input type="text" id="subject-code" class="form-input" placeholder="e.g., CS101" required></div>
<div><label for="subject-name" class="block text-sm font-medium text-slate-300 mb-1">Subject Name</label><input type="text" id="subject-name" class="form-input" placeholder="e.g., Introduction to Computer Science" required></div>
<div class="pt-4"><button type="submit" class="btn-primary">Create Subject</button></div>
</form>
</div>
</div>
<button id="save-image-fab" class="bg-indigo-600 hover:bg-indigo-700 text-white rounded-full p-4 shadow-lg transition"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 16 16"><path d="M15 12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1h1.172a3 3 0 0 0 2.12-.879l.83-.828A1 1 0 0 1 6.827 3h2.344a1 1 0 0 1 .707.293l.828.828A3 3 0 0 0 12.828 5H14a1 1 0 0 1 1 1v6zM2 4a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2h-1.172a2 2 0 0 1-1.414-.586l-.828-.828A2 2 0 0 0 9.172 2H6.828a2 2 0 0 0-1.414.586l-.828.828A2 2 0 0 1 3.172 4H2z"/><path d="M8 11a2.5 2.5 0 1 1 0-5 2.5 2.5 0 0 1 0 5zm0 1a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7zM3 6.5a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0z"/></svg></button>
<nav id="bottom-nav" class="fixed bottom-0 left-0 right-0 h-20 flex justify-around items-center z-50">
<button class="nav-btn flex flex-col items-center text-slate-400 active" data-page="dashboard-page"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 13.37V2.63A2 2 0 0 1 4 1h16a2 2 0 0 1 2 2v10.74"/><path d="M22 17H2a2 2 0 0 0-2 2v2a2 2 0 0 0 2 2h20a2 2 0 0 0 2-2v-2a2 2 0 0 0-2-2Z"/><path d="M12 17v-4"/></svg><span class="text-xs mt-1">Dashboard</span></button>
<button class="nav-btn flex flex-col items-center text-slate-400" data-page="add-task-page"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="M12 5v14"/></svg><span class="text-xs mt-1">Add Task</span></button>
<button class="nav-btn flex flex-col items-center text-slate-400" data-page="add-subject-page"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2Z"/></svg><span class="text-xs mt-1">Add Subject</span></button>
</nav>
<div id="custom-modal" class="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center hidden z-50 p-4"><div class="bg-slate-800 text-white rounded-lg shadow-xl p-6 w-full max-w-sm text-center"><p id="modal-message" class="mb-4 text-lg"></p><button id="modal-close-btn" class="btn-primary py-2">Close</button></div></div>
</div>
<script type="module">
// This application uses Firebase's Firestore database.
// All your subjects and tasks are automatically saved online.
const firebaseConfig = typeof __firebase_config !== 'undefined'
? JSON.parse(__firebase_config)
: { apiKey: "DEMO_KEY", authDomain: "demo.firebaseapp.com", projectId: "demo-project" };
const appId = typeof __app_id !== 'undefined' ? __app_id : 'mantasker-app-demo';
import { initializeApp } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-app.js";
import { getAuth, signInAnonymously, signInWithCustomToken, onAuthStateChanged } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-auth.js";
import { getFirestore, collection, doc, addDoc, onSnapshot, deleteDoc, setLogLevel } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-firestore.js";
// --- App State ---
let app, auth, db, userId;
let subjectsUnsubscribe = null, tasksUnsubscribe = null;
let subjectsCache = [], tasksCache = [];
let activeSubjectId = 'all';
// --- DOM Elements ---
const loadingScreen = document.getElementById('loading-screen');
const pages = document.querySelectorAll('.page');
const navButtons = document.querySelectorAll('.nav-btn');
const addSubjectForm = document.getElementById('add-subject-form');
const subjectCodeInput = document.getElementById('subject-code');
const subjectNameInput = document.getElementById('subject-name');
const addTaskForm = document.getElementById('add-task-form');
const taskSubjectSelect = document.getElementById('task-subject');
const taskDescriptionInput = document.getElementById('task-description');
const taskDeadlineInput = document.getElementById('task-deadline');
const taskNecessitySelect = document.getElementById('task-necessity');
const taskTypeSelect = document.getElementById('task-type');
const subjectTabs = document.getElementById('subject-tabs');
const overdueTasks = document.getElementById('overdue-tasks');
const todayTasks = document.getElementById('today-tasks');
const upcomingTasks = document.getElementById('upcoming-tasks');
const quoteText = document.getElementById('quote-text');
const quoteAuthor = document.getElementById('quote-author');
const saveImageFab = document.getElementById('save-image-fab');
const dashboardPage = document.getElementById('dashboard-page');
const modal = document.getElementById('custom-modal');
const modalMessage = document.getElementById('modal-message');
const modalCloseBtn = document.getElementById('modal-close-btn');
// --- Utility Functions ---
function showModal(message) { modalMessage.textContent = message; modal.classList.remove('hidden'); }
function closeModal() { modal.classList.add('hidden'); }
function switchPage(pageId) {
pages.forEach(page => page.classList.remove('active'));
document.getElementById(pageId).classList.add('active');
navButtons.forEach(btn => btn.classList.toggle('active', btn.dataset.page === pageId));
saveImageFab.style.display = (pageId === 'dashboard-page') ? 'block' : 'none';
}
// --- Firestore Path Builders ---
const getSubjectsCollection = (uid) => collection(db, 'artifacts', appId, 'users', uid, 'subjects');
const getTasksCollection = (uid) => collection(db, 'artifacts', appId, 'users', uid, 'tasks');
// --- Daily Quote Feature ---
const quotes = [
{ text: "The secret of getting ahead is getting started.", author: "Mark Twain" },
{ text: "It’s not whether you get knocked down, it’s whether you get up.", author: "Vince Lombardi" },
{ text: "The expert in anything was once a beginner.", author: "Helen Hayes" },
{ text: "The beautiful thing about learning is that no one can take it away from you.", author: "B.B. King" },
{ text: "Strive for progress, not perfection.", author: "Unknown" },
{ text: "The only way to do great work is to love what you do.", author: "Steve Jobs" },
{ text: "Education is the most powerful weapon which you can use to change the world.", author: "Nelson Mandela" }
];
function displayDailyQuote() {
const dayOfYear = Math.floor((new Date() - new Date(new Date().getFullYear(), 0, 0)) / (1000 * 60 * 60 * 24));
const quote = quotes[dayOfYear % quotes.length];
quoteText.textContent = `"${quote.text}"`;
quoteAuthor.textContent = `– ${quote.author}`;
}
// --- Data Rendering ---
function renderSubjectTabs() {
subjectTabs.innerHTML = '';
// Create a map to find the earliest deadline for each subject
const earliestDeadlines = {};
tasksCache.forEach(task => {
if (!earliestDeadlines[task.subjectId] || new Date(task.deadline) < new Date(earliestDeadlines[task.subjectId])) {
earliestDeadlines[task.subjectId] = task.deadline;
}
});
// Sort subjects based on the earliest deadline
const sortedSubjects = [...subjectsCache].sort((a, b) => {
const deadlineA = earliestDeadlines[a.id] ? new Date(earliestDeadlines[a.id]) : new Date('9999-12-31');
const deadlineB = earliestDeadlines[b.id] ? new Date(earliestDeadlines[b.id]) : new Date('9999-12-31');
return deadlineA - deadlineB;
});
// Render "All Subjects" tab first
const allTab = document.createElement('button');
allTab.className = `subject-tab py-2 px-4 rounded-full text-sm whitespace-nowrap ${activeSubjectId === 'all' ? 'active' : ''}`;
allTab.textContent = 'All Subjects';
allTab.dataset.subjectId = 'all';
subjectTabs.appendChild(allTab);
// Render sorted subject tabs
sortedSubjects.forEach(subject => {
const tab = document.createElement('button');
tab.className = `subject-tab py-2 px-4 rounded-full text-sm whitespace-nowrap ${activeSubjectId === subject.id ? 'active' : ''}`;
tab.textContent = subject.code;
tab.dataset.subjectId = subject.id;
subjectTabs.appendChild(tab);
});
}
function createTaskCard(task) {
const necessityColors = { 'High': 'border-red-500', 'Medium': 'border-yellow-500', 'Low': 'border-blue-500' };
const card = document.createElement('div');
card.className = `task-card p-3 rounded-lg shadow-md flex justify-between items-start ${necessityColors[task.necessity] || 'border-slate-600'}`;
card.innerHTML = `
<div class="flex-grow">
<h3 class="font-semibold text-white">${task.description}</h3>
<p class="text-xs text-slate-400">${task.type}</p>
</div>
<button data-id="${task.id}" class="delete-task-btn text-slate-500 hover:text-red-400 transition-colors ml-2 p-1">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" viewBox="0 0 16 16"><path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z"/><path fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"/></svg>
</button>
`;
return card;
}
function renderTasks() {
overdueTasks.innerHTML = ''; todayTasks.innerHTML = ''; upcomingTasks.innerHTML = '';
const filteredTasks = activeSubjectId === 'all' ? tasksCache : tasksCache.filter(t => t.subjectId === activeSubjectId);
filteredTasks.sort((a,b) => new Date(a.deadline) - new Date(b.deadline));
let overdueCount = 0, todayCount = 0, upcomingCount = 0;
const today = new Date(); today.setHours(0, 0, 0, 0);
filteredTasks.forEach(task => {
const taskDeadline = new Date(task.deadline + 'T00:00:00');
const card = createTaskCard(task);
if (taskDeadline < today) { overdueTasks.appendChild(card); overdueCount++; }
else if (taskDeadline.getTime() === today.getTime()) { todayTasks.appendChild(card); todayCount++; }
else { upcomingTasks.appendChild(card); upcomingCount++; }
});
const placeholder = `<div class="flex items-center justify-center h-24"><p class="text-slate-500 text-sm">No tasks here.</p></div>`;
if (overdueCount === 0) overdueTasks.innerHTML = placeholder;
if (todayCount === 0) todayTasks.innerHTML = placeholder;
if (upcomingCount === 0) upcomingTasks.innerHTML = placeholder;
}
function renderSubjectsForDropdown(subjects) {
taskSubjectSelect.innerHTML = '<option value="" disabled selected>Select a subject...</option>';
if (subjects.length === 0) taskSubjectSelect.innerHTML = '<option value="" disabled>Create a subject first...</option>';
subjects.forEach(subject => { taskSubjectSelect.innerHTML += `<option value="${subject.id}">[${subject.code}] ${subject.name}</option>`; });
}
// --- Firestore Logic & Listeners ---
function setupFirestoreListeners() {
if (!userId) return;
if (subjectsUnsubscribe) subjectsUnsubscribe();
if (tasksUnsubscribe) tasksUnsubscribe();
let isInitialLoad = true;
subjectsUnsubscribe = onSnapshot(getSubjectsCollection(userId), (snapshot) => {
subjectsCache = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
tasksUnsubscribe = onSnapshot(getTasksCollection(userId), (taskSnapshot) => {
tasksCache = taskSnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
renderSubjectsForDropdown(subjectsCache);
renderSubjectTabs();
renderTasks();
if(isInitialLoad) {
setTimeout(() => {
loadingScreen.style.opacity = '0';
loadingScreen.addEventListener('transitionend', () => loadingScreen.style.display = 'none', { once: true });
}, 500); // Ensure loader shows for a minimum time
isInitialLoad = false;
}
});
});
}
// --- Event Handlers ---
navButtons.forEach(button => button.addEventListener('click', () => switchPage(button.dataset.page)));
subjectTabs.addEventListener('click', (e) => {
if (e.target.matches('.subject-tab')) {
activeSubjectId = e.target.dataset.subjectId;
renderSubjectTabs();
renderTasks();
}
});
addSubjectForm.addEventListener('submit', async (e) => {
e.preventDefault(); if (!userId) return showModal("Auth Error.");
const name = subjectNameInput.value.trim(); const code = subjectCodeInput.value.trim().toUpperCase();
if (name && code) { try { await addDoc(getSubjectsCollection(userId), { name, code }); addSubjectForm.reset(); showModal(`Subject '${code}' created.`); switchPage('dashboard-page'); } catch { showModal("Error creating subject."); }
} else { showModal("Please provide both a subject code and a name."); }
});
addTaskForm.addEventListener('submit', async (e) => { e.preventDefault();
if (!userId) return showModal("Auth Error.");
const taskData = { subjectId: taskSubjectSelect.value, description: taskDescriptionInput.value.trim(), deadline: taskDeadlineInput.value, necessity: taskNecessitySelect.value, type: taskTypeSelect.value, completed: false };
if (taskData.subjectId && taskData.description && taskData.deadline) { try { await addDoc(getTasksCollection(userId), taskData); addTaskForm.reset(); showModal('Task created successfully.'); switchPage('dashboard-page'); } catch { showModal("Error creating task."); }
} else { showModal("Please fill out all fields."); }
});
dashboardPage.addEventListener('click', async (e) => {
const deleteButton = e.target.closest('.delete-task-btn');
if (deleteButton && deleteButton.dataset.id && userId) { try { await deleteDoc(doc(db, 'artifacts', appId, 'users', userId, 'tasks', deleteButton.dataset.id)); } catch { showModal('Error deleting task.'); } }
});
saveImageFab.addEventListener('click', () => {
const elementToCapture = document.getElementById('dashboard-page');
elementToCapture.scrollTo(0, 0);
html2canvas(elementToCapture, { backgroundColor: "#05080f", scale: 2 }).then(canvas => {
const link = document.createElement('a'); link.download = 'ManTasker_Dashboard.png';
link.href = canvas.toDataURL('image/png'); link.click();
}).catch(() => showModal("Failed to create image."));
});
modalCloseBtn.addEventListener('click', closeModal);
// --- App Entry Point ---
document.addEventListener('DOMContentLoaded', () => {
try {
app = initializeApp(firebaseConfig); auth = getAuth(app); db = getFirestore(app);
setLogLevel('error');
displayDailyQuote();
onAuthStateChanged(auth, async (user) => {
if (user) { userId = user.uid; setupFirestoreListeners(); }
else { userId = null; try { if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) { await signInWithCustomToken(auth, __initial_auth_token); } else { await signInAnonymously(auth); } } catch { showModal("Authentication Failed. Data cannot be saved."); } }
});
switchPage('dashboard-page');
} catch(e) { showModal("Application failed to initialize."); }
});
</script>
</body>
</html>