taskmail-reminders / script.js
AnySue's picture
I don't know what the "Tasks Calendar Analytics" with the "Profile" buttons do. You can delete those. The "set reminder" circle at the bottom of the task doesn't do anything. I'm not sure what the square check box at the top of the task does.
817573b verified
raw
history blame
9.98 kB
// Task Manager Class
class TaskManager {
constructor() {
this.tasks = this.loadTasks();
this.currentFilter = 'all';
this.init();
}
init() {
this.setupEventListeners();
this.renderTasks();
this.updateStats();
this.startReminderScheduler();
}
setupEventListeners() {
// Add task
document.getElementById('addTaskBtn').addEventListener('click', () => this.addTask());
document.getElementById('taskInput').addEventListener('keypress', (e) => {
if (e.key === 'Enter') this.addTask();
});
// Filter buttons
document.querySelectorAll('.filter-btn').forEach(btn => {
btn.addEventListener('click', (e) => {
this.setFilter(e.target.dataset.filter);
});
});
// Email modal
document.getElementById('closeEmailModal').addEventListener('click', () => {
document.getElementById('emailModal').classList.add('hidden');
});
// Close modal on outside click
document.getElementById('emailModal').addEventListener('click', (e) => {
if (e.target.id === 'emailModal') {
document.getElementById('emailModal').classList.add('hidden');
}
});
}
addTask() {
const taskInput = document.getElementById('taskInput');
const emailInput = document.getElementById('emailInput');
const taskText = taskInput.value.trim();
const email = emailInput.value.trim();
if (!taskText) {
this.showToast('Please enter a task', 'error');
return;
}
if (!email || !this.isValidEmail(email)) {
this.showToast('Please enter a valid email address', 'error');
return;
}
const task = {
id: Date.now(),
text: taskText,
email: email,
completed: false,
hasReminder: false,
reminderStopped: false,
createdAt: new Date().toISOString(),
completedAt: null
};
this.tasks.push(task);
this.saveTasks();
this.renderTasks();
this.updateStats();
// Clear inputs
taskInput.value = '';
emailInput.value = '';
this.showToast('Task added successfully!', 'success');
}
toggleTask(id) {
const task = this.tasks.find(t => t.id === id);
if (task) {
task.completed = !task.completed;
task.completedAt = task.completed ? new Date().toISOString() : null;
// When task is completed, automatically stop reminders
if (task.completed) {
task.hasReminder = false;
task.reminderStopped = true;
}
this.saveTasks();
this.renderTasks();
this.updateStats();
if (task.completed) {
this.showToast('Task completed! Great job! πŸŽ‰', 'success');
} else {
// If unchecking a completed task, reset reminder status
task.reminderStopped = false;
this.showToast('Task marked as incomplete', 'info');
}
}
}
toggleReminder(id) {
const task = this.tasks.find(t => t.id === id);
if (task) {
if (task.completed) {
this.showToast('Cannot set reminder for completed task', 'error');
return;
}
if (task.hasReminder && !task.reminderStopped) {
// Stop reminder
task.hasReminder = false;
task.reminderStopped = true;
this.showToast('Reminder stopped', 'info');
} else {
// Start reminder
task.hasReminder = true;
task.reminderStopped = false;
this.showToast('Reminder started! You\'ll receive email notifications every 30 seconds', 'success');
this.showEmailPreview(task);
}
this.saveTasks();
this.renderTasks();
this.updateStats();
}
}
deleteTask(id) {
if (confirm('Are you sure you want to delete this task?')) {
this.tasks = this.tasks.filter(t => t.id !== id);
this.saveTasks();
this.renderTasks();
this.updateStats();
this.showToast('Task deleted', 'info');
}
}
setFilter(filter) {
this.currentFilter = filter;
// Update button styles
document.querySelectorAll('.filter-btn').forEach(btn => {
if (btn.dataset.filter === filter) {
btn.className = 'filter-btn px-4 py-2 bg-primary-500 text-white rounded-lg transition-colors';
} else {
btn.className = 'filter-btn px-4 py-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition-colors';
}
});
this.renderTasks();
}
getFilteredTasks() {
switch (this.currentFilter) {
case 'pending':
return this.tasks.filter(t => !t.completed);
case 'completed':
return this.tasks.filter(t => t.completed);
case 'reminders':
return this.tasks.filter(t => t.hasReminder && !t.reminderStopped && !t.completed);
default:
return this.tasks;
}
}
renderTasks() {
const container = document.getElementById('tasksContainer');
const emptyState = document.getElementById('emptyState');
const filteredTasks = this.getFilteredTasks();
if (filteredTasks.length === 0) {
container.innerHTML = '';
emptyState.style.display = 'block';
return;
}
emptyState.style.display = 'none';
container.innerHTML = filteredTasks.map(task => `
<task-card
id="${task.id}"
text="${this.escapeHtml(task.text)}"
email="${this.escapeHtml(task.email)}"
completed="${task.completed}"
has-reminder="${task.hasReminder}"
reminder-stopped="${task.reminderStopped}"
created-at="${task.createdAt}"
></task-card>
`).join('');
// Re-initialize feather icons for new elements
feather.replace();
}
updateStats() {
const total = this.tasks.length;
const completed = this.tasks.filter(t => t.completed).length;
const pending = total - completed;
const reminders = this.tasks.filter(t => t.hasReminder && !t.reminderStopped && !t.completed).length;
document.getElementById('totalTasks').textContent = total;
document.getElementById('completedTasks').textContent = completed;
document.getElementById('pendingTasks').textContent = pending;
document.getElementById('activeReminders').textContent = reminders;
}
showEmailPreview(task) {
document.getElementById('emailTo').textContent = task.email;
document.getElementById('emailSubject').textContent = task.text;
document.getElementById('emailTask').textContent = task.text;
document.getElementById('emailModal').classList.remove('hidden');
}
startReminderScheduler() {
// Simulate sending reminders every 30 seconds for demo
setInterval(() => {
this.tasks.forEach(task => {
if (task.hasReminder && !task.reminderStopped && !task.completed) {
// In a real app, this would send an email
console.log(`Sending reminder for task: ${task.text} to ${task.email}`);
// Show a notification in the browser for demo purposes
this.showToast(`Reminder: ${task.text}`, 'info');
}
});
}, 30000); // 30 seconds
}
showToast(message, type = 'info') {
const toast = document.createElement('div');
const bgColor = type === 'success' ? 'bg-green-500' : type === 'error' ? 'bg-red-500' : 'bg-blue-500';
toast.className = `fixed bottom-4 right-4 ${bgColor} text-white px-6 py-3 rounded-lg shadow-lg z-50 flex items-center gap-2 task-card-enter`;
const icon = type === 'success' ? 'check-circle' : type === 'error' ? 'alert-circle' : 'info';
toast.innerHTML = `
<i data-feather="${icon}" class="w-5 h-5"></i>
<span>${message}</span>
`;
document.body.appendChild(toast);
feather.replace();
setTimeout(() => {
toast.style.opacity = '0';
setTimeout(() => toast.remove(), 300);
}, 3000);
}
isValidEmail(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
saveTasks() {
localStorage.setItem('tasks', JSON.stringify(this.tasks));
}
loadTasks() {
const saved = localStorage.getItem('tasks');
return saved ? JSON.parse(saved) : [];
}
}
// Custom event delegation for dynamic task cards
document.addEventListener('click', (e) => {
if (e.target.closest('[data-action="toggle"]')) {
const card = e.target.closest('task-card');
taskManager.toggleTask(parseInt(card.id));
} else if (e.target.closest('[data-action="reminder"]')) {
const card = e.target.closest('task-card');
taskManager.toggleReminder(parseInt(card.id));
} else if (e.target.closest('[data-action="delete"]')) {
const card = e.target.closest('task-card');
taskManager.deleteTask(parseInt(card.id));
}
});
// Initialize the app
const taskManager = new TaskManager();