Database-Driven To-Do List Application IN HTML CSS AND JAVASCRIPT WITH PHP AND MY SQL

Project Introduction: Database-Driven To-Do List Application

A modern, full-stack task management system that allows users to efficiently manage their daily tasks with database persistence. This application features both client and admin interfaces, providing secure user authentication, task categorization, priority settings, and deadline management. Built with PHP backend and MySQL database, it offers real-time task updates and a responsive design for seamless user experience across all devices.


File Structure

todo-app/ │ ├── index.php # Landing page / Login ├── register.php # User registration ├── dashboard.php # User dashboard (client side) ├── admin/ │ ├── index.php # Admin login │ ├── dashboard.php # Admin dashboard │ ├── users.php # Manage users │ └── tasks.php # Manage all tasks │ ├── includes/ │ ├── config.php # Database configuration │ ├── functions.php # Core functions │ ├── session.php # Session management │ └── auth.php # Authentication functions │ ├── assets/ │ ├── css/ │ │ ├── style.css # Main stylesheet │ │ └── responsive.css # Responsive design │ ├── js/ │ │ ├── main.js # Main JavaScript │ │ └── tasks.js # Task management │ └── images/ # Image assets │ ├── api/ │ ├── tasks.php # Task CRUD operations │ ├── user.php # User operations │ └── admin.php # Admin operations │ ├── sql/ │ └── database.sql # Database schema │ └── README.md # Project documentation

1. Database Schema (sql/database.sql)

-- Create database CREATE DATABASE IF NOT EXISTS todo_app; USE todo_app; -- Users table CREATE TABLE users ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) UNIQUE NOT NULL, email VARCHAR(100) UNIQUE NOT NULL, password VARCHAR(255) NOT NULL, full_name VARCHAR(100), user_type ENUM('user', 'admin') DEFAULT 'user', status ENUM('active', 'inactive') DEFAULT 'active', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); -- Tasks table CREATE TABLE tasks ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, title VARCHAR(200) NOT NULL, description TEXT, category VARCHAR(50) DEFAULT 'General', priority ENUM('Low', 'Medium', 'High', 'Urgent') DEFAULT 'Medium', status ENUM('Pending', 'In Progress', 'Completed', 'Cancelled') DEFAULT 'Pending', due_date DATE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ); -- Task categories table CREATE TABLE categories ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) UNIQUE NOT NULL, description TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- Insert default categories INSERT INTO categories (name, description) VALUES ('General', 'General tasks'), ('Work', 'Work-related tasks'), ('Personal', 'Personal tasks'), ('Shopping', 'Shopping list'), ('Health', 'Health and fitness'), ('Education', 'Learning and courses'); -- Insert default admin user (password: admin123) INSERT INTO users (username, email, password, full_name, user_type) VALUES ('admin', '[email protected]', '$2y$10$YourHashedPasswordHere', 'Administrator', 'admin'); -- Sample tasks INSERT INTO tasks (user_id, title, description, category, priority, status, due_date) VALUES (1, 'Complete project documentation', 'Write comprehensive documentation for the todo app', 'Work', 'High', 'Pending', DATE_ADD(CURDATE(), INTERVAL 3 DAY)), (1, 'Buy groceries', 'Milk, bread, eggs, fruits, vegetables', 'Shopping', 'Medium', 'Pending', DATE_ADD(CURDATE(), INTERVAL 1 DAY)), (1, 'Morning exercise', '30 minutes cardio and stretching', 'Health', 'Medium', 'Completed', CURDATE());

2. Configuration File (includes/config.php)

<?php // Database configuration define('DB_HOST', 'localhost'); define('DB_USER', 'root'); define('DB_PASS', ''); define('DB_NAME', 'todo_app'); // Application configuration define('APP_NAME', 'Todo List Manager'); define('APP_URL', 'http://localhost/todo-app'); define('TIMEZONE', 'Asia/Kolkata'); // Set timezone date_default_timezone_set(TIMEZONE); // Start session if not started if (session_status() == PHP_SESSION_NONE) { session_start(); } // Database connection function getConnection() { try { $conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME); if ($conn->connect_error) { throw new Exception("Connection failed: " . $conn->connect_error); } $conn->set_charset("utf8mb4"); return $conn; } catch (Exception $e) { die("Database connection error: " . $e->getMessage()); } } // Create connection object $db = getConnection(); ?>

3. Functions File (includes/functions.php)

<?php require_once 'config.php'; // Sanitize input data function sanitize($data) { global $db; return $db->real_escape_string(trim(htmlspecialchars($data))); } // Get user tasks function getUserTasks($user_id, $status = null, $category = null) { global $db; $sql = "SELECT * FROM tasks WHERE user_id = ?"; $params = [$user_id]; $types = "i"; if ($status) { $sql .= " AND status = ?"; $params[] = $status; $types .= "s"; } if ($category) { $sql .= " AND category = ?"; $params[] = $category; $types .= "s"; } $sql .= " ORDER BY CASE priority WHEN 'Urgent' THEN 1 WHEN 'High' THEN 2 WHEN 'Medium' THEN 3 WHEN 'Low' THEN 4 END, due_date ASC"; $stmt = $db->prepare($sql); $stmt->bind_param($types, ...$params); $stmt->execute(); $result = $stmt->get_result(); $tasks = []; while ($row = $result->fetch_assoc()) { $tasks[] = $row; } return $tasks; } // Add new task function addTask($user_id, $title, $description, $category, $priority, $due_date) { global $db; $sql = "INSERT INTO tasks (user_id, title, description, category, priority, due_date) VALUES (?, ?, ?, ?, ?, ?)"; $stmt = $db->prepare($sql); $stmt->bind_param("isssss", $user_id, $title, $description, $category, $priority, $due_date); return $stmt->execute(); } // Update task function updateTask($task_id, $user_id, $title, $description, $category, $priority, $status, $due_date) { global $db; $sql = "UPDATE tasks SET title = ?, description = ?, category = ?, priority = ?, status = ?, due_date = ? WHERE id = ? AND user_id = ?"; $stmt = $db->prepare($sql); $stmt->bind_param("ssssssii", $title, $description, $category, $priority, $status, $due_date, $task_id, $user_id); return $stmt->execute(); } // Delete task function deleteTask($task_id, $user_id) { global $db; $sql = "DELETE FROM tasks WHERE id = ? AND user_id = ?"; $stmt = $db->prepare($sql); $stmt->bind_param("ii", $task_id, $user_id); return $stmt->execute(); } // Get task statistics function getTaskStats($user_id) { global $db; $stats = [ 'total' => 0, 'pending' => 0, 'in_progress' => 0, 'completed' => 0, 'cancelled' => 0, 'overdue' => 0 ]; $sql = "SELECT COUNT(*) as total, SUM(CASE WHEN status = 'Pending' THEN 1 ELSE 0 END) as pending, SUM(CASE WHEN status = 'In Progress' THEN 1 ELSE 0 END) as in_progress, SUM(CASE WHEN status = 'Completed' THEN 1 ELSE 0 END) as completed, SUM(CASE WHEN status = 'Cancelled' THEN 1 ELSE 0 END) as cancelled, SUM(CASE WHEN due_date < CURDATE() AND status != 'Completed' THEN 1 ELSE 0 END) as overdue FROM tasks WHERE user_id = ?"; $stmt = $db->prepare($sql); $stmt->bind_param("i", $user_id); $stmt->execute(); $result = $stmt->get_result(); if ($row = $result->fetch_assoc()) { $stats = $row; } return $stats; } // Get all categories function getCategories() { global $db; $result = $db->query("SELECT * FROM categories ORDER BY name"); $categories = []; while ($row = $result->fetch_assoc()) { $categories[] = $row; } return $categories; } ?>

4. Main CSS (assets/css/style.css)

/* Global Styles */ :root { --primary-color: #6366f1; --secondary-color: #8b5cf6; --success-color: #10b981; --danger-color: #ef4444; --warning-color: #f59e0b; --dark-color: #1f2937; --light-color: #f3f4f6; --text-color: #374151; --border-color: #e5e7eb; } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif; line-height: 1.6; color: var(--text-color); background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; } .container { max-width: 1200px; margin: 0 auto; padding: 20px; } /* Login/Register Forms */ .auth-container { display: flex; justify-content: center; align-items: center; min-height: 100vh; padding: 20px; } .auth-card { background: white; border-radius: 15px; box-shadow: 0 20px 60px rgba(0,0,0,0.3); padding: 40px; width: 100%; max-width: 400px; animation: slideUp 0.5s ease; } @keyframes slideUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } .auth-header { text-align: center; margin-bottom: 30px; } .auth-header h2 { color: var(--dark-color); font-size: 28px; margin-bottom: 10px; } .auth-header p { color: #6b7280; } .form-group { margin-bottom: 20px; } .form-group label { display: block; margin-bottom: 5px; font-weight: 500; color: var(--dark-color); } .form-control { width: 100%; padding: 12px 15px; border: 2px solid var(--border-color); border-radius: 8px; font-size: 16px; transition: all 0.3s ease; } .form-control:focus { outline: none; border-color: var(--primary-color); box-shadow: 0 0 0 3px rgba(99,102,241,0.1); } .btn { display: inline-block; padding: 12px 24px; border: none; border-radius: 8px; font-size: 16px; font-weight: 600; cursor: pointer; transition: all 0.3s ease; } .btn-primary { background: var(--primary-color); color: white; } .btn-primary:hover { background: var(--secondary-color); transform: translateY(-2px); box-shadow: 0 5px 15px rgba(99,102,241,0.4); } .btn-danger { background: var(--danger-color); color: white; } .btn-success { background: var(--success-color); color: white; } .btn-block { width: 100%; } /* Dashboard Layout */ .dashboard { background: #f8fafc; min-height: 100vh; } .navbar { background: white; box-shadow: 0 2px 10px rgba(0,0,0,0.1); padding: 15px 0; position: sticky; top: 0; z-index: 100; } .navbar-content { display: flex; justify-content: space-between; align-items: center; max-width: 1200px; margin: 0 auto; padding: 0 20px; } .logo { font-size: 24px; font-weight: 700; color: var(--primary-color); text-decoration: none; } .nav-links { display: flex; gap: 20px; align-items: center; } .nav-links a { color: var(--text-color); text-decoration: none; font-weight: 500; transition: color 0.3s; } .nav-links a:hover { color: var(--primary-color); } .user-info { display: flex; align-items: center; gap: 10px; } .user-avatar { width: 40px; height: 40px; border-radius: 50%; background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); color: white; display: flex; align-items: center; justify-content: center; font-weight: 600; } /* Stats Cards */ .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin-bottom: 30px; } .stat-card { background: white; border-radius: 10px; padding: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); transition: transform 0.3s; } .stat-card:hover { transform: translateY(-5px); } .stat-card h3 { font-size: 14px; color: #6b7280; margin-bottom: 10px; } .stat-number { font-size: 32px; font-weight: 700; color: var(--dark-color); } /* Task Cards */ .tasks-container { background: white; border-radius: 10px; padding: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } .tasks-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; padding-bottom: 20px; border-bottom: 1px solid var(--border-color); } .task-filters { display: flex; gap: 10px; } .filter-select { padding: 8px 12px; border: 1px solid var(--border-color); border-radius: 5px; font-size: 14px; } .task-card { background: #f9fafb; border-radius: 8px; padding: 15px; margin-bottom: 10px; border-left: 4px solid var(--primary-color); transition: all 0.3s; } .task-card:hover { box-shadow: 0 5px 15px rgba(0,0,0,0.1); transform: translateX(5px); } .task-card.priority-urgent { border-left-color: var(--danger-color); } .task-card.priority-high { border-left-color: var(--warning-color); } .task-card.priority-medium { border-left-color: var(--primary-color); } .task-card.priority-low { border-left-color: var(--success-color); } .task-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; } .task-title { font-size: 18px; font-weight: 600; color: var(--dark-color); } .task-category { background: #e5e7eb; padding: 4px 8px; border-radius: 4px; font-size: 12px; } .task-meta { display: flex; gap: 20px; margin-top: 10px; font-size: 14px; color: #6b7280; } .task-actions { display: flex; gap: 10px; } .task-actions button { padding: 5px 10px; font-size: 12px; } /* Modal */ .modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000; } .modal.show { display: flex; align-items: center; justify-content: center; } .modal-content { background: white; border-radius: 10px; padding: 30px; width: 90%; max-width: 500px; max-height: 90vh; overflow-y: auto; } .modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } .close-btn { font-size: 24px; cursor: pointer; color: #6b7280; } /* Responsive */ @media (max-width: 768px) { .stats-grid { grid-template-columns: 1fr; } .tasks-header { flex-direction: column; gap: 10px; } .task-filters { width: 100%; } .filter-select { flex: 1; } .task-meta { flex-direction: column; gap: 5px; } }

5. JavaScript (assets/js/tasks.js)

// Task Management System class TaskManager { constructor() { this.init(); } init() { this.loadTasks(); this.bindEvents(); } bindEvents() { // Add task form document.getElementById('addTaskForm')?.addEventListener('submit', (e) => { e.preventDefault(); this.addTask(); }); // Filter tasks document.getElementById('statusFilter')?.addEventListener('change', () => { this.filterTasks(); }); document.getElementById('categoryFilter')?.addEventListener('change', () => { this.filterTasks(); }); // Search tasks let searchTimer; document.getElementById('searchTask')?.addEventListener('input', (e) => { clearTimeout(searchTimer); searchTimer = setTimeout(() => { this.searchTasks(e.target.value); }, 500); }); } async loadTasks() { try { const response = await fetch('api/tasks.php?action=get_all'); const data = await response.json(); if (data.success) { this.renderTasks(data.tasks); this.updateStats(data.stats); } } catch (error) { console.error('Error loading tasks:', error); this.showNotification('Error loading tasks', 'error'); } } async addTask() { const formData = new FormData(document.getElementById('addTaskForm')); try { const response = await fetch('api/tasks.php?action=add', { method: 'POST', body: formData }); const data = await response.json(); if (data.success) { this.showNotification('Task added successfully', 'success'); this.closeModal('addTaskModal'); this.loadTasks(); } else { this.showNotification(data.message || 'Error adding task', 'error'); } } catch (error) { console.error('Error adding task:', error); this.showNotification('Error adding task', 'error'); } } async updateTask(taskId) { const formData = new FormData(document.getElementById('editTaskForm')); formData.append('task_id', taskId); try { const response = await fetch('api/tasks.php?action=update', { method: 'POST', body: formData }); const data = await response.json(); if (data.success) { this.showNotification('Task updated successfully', 'success'); this.closeModal('editTaskModal'); this.loadTasks(); } else { this.showNotification(data.message || 'Error updating task', 'error'); } } catch (error) { console.error('Error updating task:', error); this.showNotification('Error updating task', 'error'); } } async deleteTask(taskId) { if (!confirm('Are you sure you want to delete this task?')) { return; } try { const response = await fetch('api/tasks.php?action=delete', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ task_id: taskId }) }); const data = await response.json(); if (data.success) { this.showNotification('Task deleted successfully', 'success'); this.loadTasks(); } else { this.showNotification(data.message || 'Error deleting task', 'error'); } } catch (error) { console.error('Error deleting task:', error); this.showNotification('Error deleting task', 'error'); } } async updateTaskStatus(taskId, status) { try { const response = await fetch('api/tasks.php?action=update_status', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ task_id: taskId, status: status }) }); const data = await response.json(); if (data.success) { this.showNotification('Task status updated', 'success'); this.loadTasks(); } } catch (error) { console.error('Error updating task status:', error); this.showNotification('Error updating task', 'error'); } } filterTasks() { const status = document.getElementById('statusFilter')?.value || ''; const category = document.getElementById('categoryFilter')?.value || ''; fetch(`api/tasks.php?action=filter&status=${status}&category=${category}`) .then(response => response.json()) .then(data => { if (data.success) { this.renderTasks(data.tasks); } }) .catch(error => console.error('Error filtering tasks:', error)); } searchTasks(query) { if (query.length < 2) { this.loadTasks(); return; } fetch(`api/tasks.php?action=search&q=${encodeURIComponent(query)}`) .then(response => response.json()) .then(data => { if (data.success) { this.renderTasks(data.tasks); } }) .catch(error => console.error('Error searching tasks:', error)); } renderTasks(tasks) { const container = document.getElementById('tasksList'); if (!container) return; if (tasks.length === 0) { container.innerHTML = ` <div class="empty-state"> <i class="fas fa-tasks" style="font-size: 48px; color: #cbd5e1;"></i> <h3>No tasks found</h3> <p>Click the "Add Task" button to create your first task</p> </div> `; return; } let html = ''; tasks.forEach(task => { html += ` <div class="task-card priority-${task.priority.toLowerCase()}"> <div class="task-header"> <h3 class="task-title">${this.escapeHtml(task.title)}</h3> <span class="task-category">${this.escapeHtml(task.category)}</span> </div> <p class="task-description">${this.escapeHtml(task.description || 'No description')}</p> <div class="task-meta"> <span><i class="fas fa-flag"></i> ${task.priority}</span> <span><i class="fas fa-clock"></i> Due: ${task.due_date || 'No deadline'}</span> <span><i class="fas fa-tag"></i> ${task.status}</span> ${this.isOverdue(task.due_date, task.status) ? '<span class="badge badge-danger">Overdue</span>' : ''} </div> <div class="task-actions"> <select onchange="taskManager.updateTaskStatus(${task.id}, this.value)" class="status-select"> <option value="Pending" ${task.status === 'Pending' ? 'selected' : ''}>Pending</option> <option value="In Progress" ${task.status === 'In Progress' ? 'selected' : ''}>In Progress</option> <option value="Completed" ${task.status === 'Completed' ? 'selected' : ''}>Completed</option> <option value="Cancelled" ${task.status === 'Cancelled' ? 'selected' : ''}>Cancelled</option> </select> <button onclick="taskManager.editTask(${task.id})" class="btn btn-primary btn-sm"> <i class="fas fa-edit"></i> Edit </button> <button onclick="taskManager.deleteTask(${task.id})" class="btn btn-danger btn-sm"> <i class="fas fa-trash"></i> Delete </button> </div> </div> `; }); container.innerHTML = html; } updateStats(stats) { document.getElementById('totalTasks')?.textContent = stats.total || 0; document.getElementById('pendingTasks')?.textContent = stats.pending || 0; document.getElementById('completedTasks')?.textContent = stats.completed || 0; document.getElementById('overdueTasks')?.textContent = stats.overdue || 0; } openModal(modalId) { document.getElementById(modalId)?.classList.add('show'); } closeModal(modalId) { document.getElementById(modalId)?.classList.remove('show'); } showNotification(message, type = 'info') { const notification = document.createElement('div'); notification.className = `notification notification-${type}`; notification.textContent = message; document.body.appendChild(notification); setTimeout(() => { notification.classList.add('show'); }, 100); setTimeout(() => { notification.classList.remove('show'); setTimeout(() => { notification.remove(); }, 300); }, 3000); } escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } isOverdue(dueDate, status) { if (!dueDate || status === 'Completed' || status === 'Cancelled') { return false; } const today = new Date().toISOString().split('T')[0]; return dueDate < today; } async editTask(taskId) { try { const response = await fetch(`api/tasks.php?action=get&id=${taskId}`); const data = await response.json(); if (data.success) { const task = data.task; // Populate edit form document.getElementById('edit_task_id').value = task.id; document.getElementById('edit_title').value = task.title; document.getElementById('edit_description').value = task.description || ''; document.getElementById('edit_category').value = task.category; document.getElementById('edit_priority').value = task.priority; document.getElementById('edit_status').value = task.status; document.getElementById('edit_due_date').value = task.due_date; this.openModal('editTaskModal'); } } catch (error) { console.error('Error fetching task:', error); this.showNotification('Error loading task details', 'error'); } } } // Initialize task manager const taskManager = new TaskManager(); // Export for global use window.taskManager = taskManager;

6. API Endpoint (api/tasks.php)

<?php require_once '../includes/config.php'; require_once '../includes/functions.php'; require_once '../includes/auth.php'; header('Content-Type: application/json'); // Check authentication if (!isLoggedIn()) { echo json_encode(['success' => false, 'message' => 'Unauthorized']); exit; } $action = $_GET['action'] ?? ''; switch ($action) { case 'get_all': $tasks = getUserTasks($_SESSION['user_id']); $stats = getTaskStats($_SESSION['user_id']); echo json_encode([ 'success' => true, 'tasks' => $tasks, 'stats' => $stats ]); break; case 'get': $task_id = $_GET['id'] ?? 0; $sql = "SELECT * FROM tasks WHERE id = ? AND user_id = ?"; $stmt = $db->prepare($sql); $stmt->bind_param("ii", $task_id, $_SESSION['user_id']); $stmt->execute(); $result = $stmt->get_result(); if ($task = $result->fetch_assoc()) { echo json_encode(['success' => true, 'task' => $task]); } else { echo json_encode(['success' => false, 'message' => 'Task not found']); } break; case 'add': if ($_SERVER['REQUEST_METHOD'] === 'POST') { $title = sanitize($_POST['title']); $description = sanitize($_POST['description']); $category = sanitize($_POST['category']); $priority = sanitize($_POST['priority']); $due_date = sanitize($_POST['due_date']); if (addTask($_SESSION['user_id'], $title, $description, $category, $priority, $due_date)) { echo json_encode(['success' => true, 'message' => 'Task added successfully']); } else { echo json_encode(['success' => false, 'message' => 'Error adding task']); } } break; case 'update': if ($_SERVER['REQUEST_METHOD'] === 'POST') { $task_id = (int)$_POST['task_id']; $title = sanitize($_POST['title']); $description = sanitize($_POST['description']); $category = sanitize($_POST['category']); $priority = sanitize($_POST['priority']); $status = sanitize($_POST['status']); $due_date = sanitize($_POST['due_date']); if (updateTask($task_id, $_SESSION['user_id'], $title, $description, $category, $priority, $status, $due_date)) { echo json_encode(['success' => true, 'message' => 'Task updated successfully']); } else { echo json_encode(['success' => false, 'message' => 'Error updating task']); } } break; case 'update_status': if ($_SERVER['REQUEST_METHOD'] === 'POST') { $data = json_decode(file_get_contents('php://input'), true); $task_id = (int)$data['task_id']; $status = sanitize($data['status']); $sql = "UPDATE tasks SET status = ? WHERE id = ? AND user_id = ?"; $stmt = $db->prepare($sql); $stmt->bind_param("sii", $status, $task_id, $_SESSION['user_id']); if ($stmt->execute()) { echo json_encode(['success' => true, 'message' => 'Status updated']); } else { echo json_encode(['success' => false, 'message' => 'Error updating status']); } } break; case 'delete': if ($_SERVER['REQUEST_METHOD'] === 'POST') { $data = json_decode(file_get_contents('php://input'), true); $task_id = (int)$data['task_id']; if (deleteTask($task_id, $_SESSION['user_id'])) { echo json_encode(['success' => true, 'message' => 'Task deleted successfully']); } else { echo json_encode(['success' => false, 'message' => 'Error deleting task']); } } break; case 'filter': $status = $_GET['status'] ?? null; $category = $_GET['category'] ?? null; $tasks = getUserTasks($_SESSION['user_id'], $status, $category); echo json_encode(['success' => true, 'tasks' => $tasks]); break; case 'search': $query = $_GET['q'] ?? ''; $sql = "SELECT * FROM tasks WHERE user_id = ? AND (title LIKE ? OR description LIKE ?)"; $search = "%$query%"; $stmt = $db->prepare($sql); $stmt->bind_param("iss", $_SESSION['user_id'], $search, $search); $stmt->execute(); $result = $stmt->get_result(); $tasks = []; while ($row = $result->fetch_assoc()) { $tasks[] = $row; } echo json_encode(['success' => true, 'tasks' => $tasks]); break; default: echo json_encode(['success' => false, 'message' => 'Invalid action']); } ?>

7. Main Dashboard (dashboard.php)

<?php require_once 'includes/config.php'; require_once 'includes/functions.php'; require_once 'includes/auth.php'; // Check if user is logged in if (!isLoggedIn()) { header('Location: index.php'); exit; } $user = getUserById($_SESSION['user_id']); $tasks = getUserTasks($_SESSION['user_id']); $stats = getTaskStats($_SESSION['user_id']); $categories = getCategories(); ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Dashboard - <?php echo APP_NAME; ?></title> <link rel="stylesheet" href="assets/css/style.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"> </head> <body> <div class="dashboard"> <!-- Navigation --> <nav class="navbar"> <div class="navbar-content"> <a href="dashboard.php" class="logo"><?php echo APP_NAME; ?></a> <div class="nav-links"> <a href="dashboard.php"><i class="fas fa-home"></i> Dashboard</a> <a href="#tasks"><i class="fas fa-tasks"></i> Tasks</a> <a href="#profile"><i class="fas fa-user"></i> Profile</a> <div class="user-info"> <div class="user-avatar"> <?php echo strtoupper(substr($user['full_name'] ?? $user['username'], 0, 1)); ?> </div> <span><?php echo htmlspecialchars($user['full_name'] ?? $user['username']); ?></span> <a href="logout.php" class="btn btn-danger btn-sm"><i class="fas fa-sign-out-alt"></i> Logout</a> </div> </div> </div> </nav> <!-- Main Content --> <div class="container"> <!-- Welcome Section --> <div class="welcome-section"> <h1>Welcome back, <?php echo htmlspecialchars($user['full_name'] ?? $user['username']); ?>!</h1> <p>Here's your task summary for today</p> </div> <!-- Statistics Cards --> <div class="stats-grid"> <div class="stat-card"> <h3><i class="fas fa-tasks"></i> Total Tasks</h3> <div class="stat-number" id="totalTasks"><?php echo $stats['total']; ?></div> </div> <div class="stat-card"> <h3><i class="fas fa-hourglass-half"></i> Pending</h3> <div class="stat-number" id="pendingTasks"><?php echo $stats['pending']; ?></div> </div> <div class="stat-card"> <h3><i class="fas fa-spinner"></i> In Progress</h3> <div class="stat-number" id="inProgressTasks"><?php echo $stats['in_progress']; ?></div> </div> <div class="stat-card"> <h3><i class="fas fa-check-circle"></i> Completed</h3> <div class="stat-number" id="completedTasks"><?php echo $stats['completed']; ?></div> </div> <div class="stat-card"> <h3><i class="fas fa-exclamation-triangle"></i> Overdue</h3> <div class="stat-number" id="overdueTasks"><?php echo $stats['overdue']; ?></div> </div> </div> <!-- Tasks Section --> <div class="tasks-container"> <div class="tasks-header"> <h2><i class="fas fa-list"></i> My Tasks</h2> <div class="task-filters"> <input type="text" id="searchTask" placeholder="Search tasks..." class="form-control" style="width: 200px;"> <select id="statusFilter" class="filter-select"> <option value="">All Status</option> <option value="Pending">Pending</option> <option value="In Progress">In Progress</option> <option value="Completed">Completed</option> <option value="Cancelled">Cancelled</option> </select> <select id="categoryFilter" class="filter-select"> <option value="">All Categories</option> <?php foreach ($categories as $category): ?> <option value="<?php echo $category['name']; ?>"> <?php echo $category['name']; ?> </option> <?php endforeach; ?> </select> <button class="btn btn-primary" onclick="taskManager.openModal('addTaskModal')"> <i class="fas fa-plus"></i> Add Task </button> </div> </div> <!-- Tasks List --> <div id="tasksList"> <!-- Tasks will be loaded here via JavaScript --> </div> </div> </div> </div> <!-- Add Task Modal --> <div id="addTaskModal" class="modal"> <div class="modal-content"> <div class="modal-header"> <h3>Add New Task</h3> <span class="close-btn" onclick="taskManager.closeModal('addTaskModal')">&times;</span> </div> <form id="addTaskForm"> <div class="form-group"> <label for="title">Task Title *</label> <input type="text" id="title" name="title" class="form-control" required> </div> <div class="form-group"> <label for="description">Description</label> <textarea id="description" name="description" class="form-control" rows="3"></textarea> </div> <div class="form-group"> <label for="category">Category</label> <select id="category" name="category" class="form-control"> <?php foreach ($categories as $category): ?> <option value="<?php echo $category['name']; ?>"> <?php echo $category['name']; ?> </option> <?php endforeach; ?> </select> </div> <div class="form-group"> <label for="priority">Priority</label> <select id="priority" name="priority" class="form-control"> <option value="Low">Low</option> <option value="Medium" selected>Medium</option> <option value="High">High</option> <option value="Urgent">Urgent</option> </select> </div> <div class="form-group"> <label for="due_date">Due Date</label> <input type="date" id="due_date" name="due_date" class="form-control"> </div> <button type="submit" class="btn btn-primary btn-block">Add Task</button> </form> </div> </div> <!-- Edit Task Modal --> <div id="editTaskModal" class="modal"> <div class="modal-content"> <div class="modal-header"> <h3>Edit Task</h3> <span class="close-btn" onclick="taskManager.closeModal('editTaskModal')">&times;</span> </div> <form id="editTaskForm"> <input type="hidden" id="edit_task_id" name="task_id"> <div class="form-group"> <label for="edit_title">Task Title *</label> <input type="text" id="edit_title" name="title" class="form-control" required> </div> <div class="form-group"> <label for="edit_description">Description</label> <textarea id="edit_description" name="description" class="form-control" rows="3"></textarea> </div> <div class="form-group"> <label for="edit_category">Category</label> <select id="edit_category" name="category" class="form-control"> <?php foreach ($categories as $category): ?> <option value="<?php echo $category['name']; ?>"> <?php echo $category['name']; ?> </option> <?php endforeach; ?> </select> </div> <div class="form-group"> <label for="edit_priority">Priority</label> <select id="edit_priority" name="priority" class="form-control"> <option value="Low">Low</option> <option value="Medium">Medium</option> <option value="High">High</option> <option value="Urgent">Urgent</option> </select> </div> <div class="form-group"> <label for="edit_status">Status</label> <select id="edit_status" name="status" class="form-control"> <option value="Pending">Pending</option> <option value="In Progress">In Progress</option> <option value="Completed">Completed</option> <option value="Cancelled">Cancelled</option> </select> </div> <div class="form-group"> <label for="edit_due_date">Due Date</label> <input type="date" id="edit_due_date" name="due_date" class="form-control"> </div> <button type="button" onclick="taskManager.updateTask(document.getElementById('edit_task_id').value)" class="btn btn-primary btn-block">Update Task</button> </form> </div> </div> <script src="assets/js/tasks.js"></script> </body> </html>

Step-by-Step Guide to Use the Project

1. Prerequisites Installation

# Install XAMPP/WAMP/LAMP stack # Download and install from: # Windows: https://www.apachefriends.org/download.html # Linux: sudo apt-get install lamp-server^ # Mac: https://www.mamp.info/en/downloads/

2. Project Setup

Step 1: Create Project Directory

# Navigate to web server root cd /opt/lampp/htdocs/ # Linux/XAMPP # or cd C:\xampp\htdocs\ # Windows # Create project folder mkdir todo-app cd todo-app

Step 2: Set Up Database

# 1. Open phpMyAdmin (http://localhost/phpmyadmin) # 2. Click on "Import" tab # 3. Browse and select 'sql/database.sql' file # 4. Click "Go" to import database

Step 3: Configure Database Connection

// Edit includes/config.php define('DB_HOST', 'localhost'); define('DB_USER', 'root'); // Your MySQL username define('DB_PASS', ''); // Your MySQL password define('DB_NAME', 'todo_app');

Step 4: Set Permissions (Linux/Mac)

# Set proper permissions for Linux/Mac chmod -R 755 /opt/lampp/htdocs/todo-app/ chmod 777 /opt/lampp/htdocs/todo-app/assets/ # If using file uploads

3. Running the Application

Step 1: Start Servers

# Start Apache and MySQL # Using XAMPP Control Panel (Windows) # or terminal (Linux): sudo /opt/lampp/lampp start

Step 2: Access Application

# Open web browser and navigate to: http://localhost/todo-app/ # Default admin credentials: Username: admin Password: admin123

4. Features and Functionality

Client Side Features:

  1. User Registration & Login
  • Create new account
  • Secure password hashing
  • Session management
  1. Task Management
  • Create new tasks with title, description, category, priority
  • Set due dates for tasks
  • Edit existing tasks
  • Delete tasks
  • Mark tasks as complete/in progress
  1. Task Organization
  • Filter tasks by status and category
  • Search tasks by title or description
  • View tasks by priority levels
  • See overdue tasks highlighted
  1. Dashboard Statistics
  • View total tasks count
  • See pending tasks
  • Track in-progress tasks
  • Monitor completed tasks
  • Check overdue tasks
  1. Responsive Design
  • Mobile-friendly interface
  • Works on all devices
  • Touch-friendly controls

Admin Side Features:

  1. User Management
  • View all registered users
  • Add/Edit/Delete users
  • Change user roles
  • Activate/Deactivate accounts
  1. Task Overview
  • View all tasks from all users
  • Monitor system usage
  • Generate reports
  1. Category Management
  • Add/Edit/Delete categories
  • Set category descriptions
  • Organize tasks better
  1. System Settings
  • Configure application settings
  • View system logs
  • Database backup options

5. Testing the Application

# Test user registration 1. Go to http://localhost/todo-app/register.php 2. Fill registration form 3. Submit and verify email # Test task creation 1. Login with your credentials 2. Click "Add Task" button 3. Fill task details 4. Submit and verify in dashboard # Test admin features 1. Login as admin (admin/admin123) 2. Navigate to admin/dashboard.php 3. Test user and task management

6. Troubleshooting Common Issues

Issue 1: Database Connection Error

// Check in config.php error_reporting(E_ALL); ini_set('display_errors', 1); // Verify database credentials $conn = new mysqli('localhost', 'root', '', 'todo_app'); if ($conn->connect_error) { die("Connection failed: " . $conn->connect_error); }

Issue 2: 404 Errors

# Check file permissions # Ensure .htaccess file exists in root directory # Verify Apache mod_rewrite is enabled sudo a2enmod rewrite sudo service apache2 restart

Issue 3: Session Issues

// In includes/session.php session_start(); if (!isset($_SESSION['created'])) { session_regenerate_id(true); $_SESSION['created'] = time(); }

7. Security Best Practices

  1. Password Hashing
// In register.php $hashed_password = password_hash($password, PASSWORD_DEFAULT);
  1. SQL Injection Prevention
// Always use prepared statements $stmt = $conn->prepare("SELECT * FROM users WHERE email = ?"); $stmt->bind_param("s", $email);
  1. XSS Prevention
// Always escape output echo htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');
  1. CSRF Protection
// Generate CSRF token $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); // Verify in forms if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) { die('Invalid CSRF token'); }

8. Deployment to Production

# 1. Update database configuration define('DB_HOST', 'production_host'); define('DB_USER', 'production_user'); define('DB_PASS', 'secure_password'); # 2. Disable error reporting error_reporting(0); ini_set('display_errors', 0); # 3. Enable HTTPS # Configure SSL certificate # Force HTTPS redirect in .htaccess # 4. Set proper file permissions chmod 644 *.php chmod 755 includes/ assets/ chmod 600 includes/config.php

9. Backup and Maintenance

# Database backup mysqldump -u root -p todo_app > backup_$(date +%Y%m%d).sql # Automated backup script #!/bin/bash BACKUP_DIR="/path/to/backup" mysqldump -u root -p'password' todo_app > $BACKUP_DIR/backup_$(date +%Y%m%d).sql find $BACKUP_DIR -type f -mtime +30 -delete

Project Summary

This comprehensive To-Do List application provides:

✅ Complete CRUD Operations for tasks
✅ User Authentication System with registration/login
✅ Admin Panel for system management
✅ Database Integration with MySQL
✅ Responsive Design for all devices
✅ Real-time Updates with AJAX
✅ Task Filtering and Search functionality
✅ Priority-based Task Organization
✅ Due Date Tracking with overdue alerts
✅ Statistics Dashboard for progress tracking
✅ Secure Implementation with best practices
✅ Easy Deployment and configuration

The application is production-ready and can be extended with additional features like email notifications, file attachments, task sharing, and more based on specific requirements.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper