diff --git a/assets/css/custom.css b/assets/css/custom.css index d15692f..27bafc2 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -148,3 +148,29 @@ body.dark-mode { width: 1.25rem; height: 1.25rem; } + +.card { + border-radius: var(--border-radius); + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); +} + +.card-title { + font-size: 1.25rem; + font-weight: 600; + margin-bottom: 0.5rem; +} + +.card-text { + font-size: 0.9rem; + color: #6B7280; /* Neutral gray for description */ +} + +.dark-mode .card-text { + color: #9CA3AF; +} + +.card-footer { + font-size: 0.8rem; + background-color: transparent; + border-top: none; +} diff --git a/assets/js/main.js b/assets/js/main.js index 4b11284..7b49a6e 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -1,4 +1,5 @@ document.addEventListener('DOMContentLoaded', function () { + console.log('main.js: DOMContentLoaded event fired.'); const themeToggle = document.getElementById('theme-toggle'); const sidebarToggle = document.getElementById('sidebar-toggle'); const sidebar = document.querySelector('.sidebar'); @@ -31,4 +32,86 @@ document.addEventListener('DOMContentLoaded', function () { mainContent.classList.toggle('expanded'); } }); + + const addTaskForm = document.getElementById('addTaskForm'); + if (addTaskForm) { + addTaskForm.addEventListener('submit', async function (e) { + console.log('main.js: addTaskForm submitted.'); + e.preventDefault(); + + const formData = new FormData(this); + formData.append('action', 'addTask'); + + try { + const response = await fetch('index.php', { + method: 'POST', + body: formData + }); + const result = await response.json(); + + if (result.success) { + alert(result.message); + this.reset(); // Clear form fields + // Close modal + const addTaskModal = bootstrap.Modal.getInstance(document.getElementById('addTaskModal')); + if (addTaskModal) { + addTaskModal.hide(); + } + loadTasks(); // Refresh tasks list + } else { + alert('Error: ' + result.message); + } + } catch (error) { + console.error('Error adding task:', error); + alert('An unexpected error occurred while adding the task. Check console for details.'); + } + }); + } + + // Function to load and display tasks + async function loadTasks() { + console.log('main.js: loadTasks() called.'); + const tasksListDiv = document.getElementById('tasksList'); + if (!tasksListDiv) return; + + tasksListDiv.innerHTML = '
Loading tasks...
'; // Loading indicator + + try { + const response = await fetch('index.php?action=getTasks'); + const result = await response.json(); + + if (result.success && result.tasks) { + tasksListDiv.innerHTML = ''; // Clear loading indicator + if (result.tasks.length === 0) { + tasksListDiv.innerHTML = '

No tasks yet. Add one!

'; + return; + } + result.tasks.forEach(task => { + const taskCard = ` +
+
+
+
${task.title}
+

${task.description}

+ ${task.status} +
+ +
+
+ `; + tasksListDiv.innerHTML += taskCard; + }); + } else { + tasksListDiv.innerHTML = '

Error loading tasks: ' + (result.message || 'Unknown error') + '

'; + } + } catch (error) { + console.error('Error fetching tasks:', error); + tasksListDiv.innerHTML = '

An unexpected error occurred while fetching tasks. Check console for details.

'; + } + } + + // Initial load of tasks + loadTasks(); }); diff --git a/db/.applied_migrations b/db/.applied_migrations new file mode 100644 index 0000000..0dbc99d --- /dev/null +++ b/db/.applied_migrations @@ -0,0 +1 @@ +["001_create_tasks_table.sql"] \ No newline at end of file diff --git a/db/migrate.php b/db/migrate.php new file mode 100644 index 0000000..de0cf49 --- /dev/null +++ b/db/migrate.php @@ -0,0 +1,52 @@ +exec($sql); + $appliedMigrations[] = $fileName; + } catch (PDOException $e) { + echo "Error applying migration {$fileName}: " . $e->getMessage() . "\n"; + return false; // Stop on first error + } + } else { + echo "Migration already applied: {$fileName}\n"; + } + } + + file_put_contents($appliedMigrationsFile, json_encode($appliedMigrations)); + echo "Migrations finished.\n"; + return true; +} + +// Run migrations if this script is executed directly +if (realpath($argv[0]) === realpath(__FILE__)) { + try { + $pdo = db(); // Get PDO connection from config.php + runMigrations($pdo); + } catch (PDOException $e) { + echo "Database connection error: " . $e->getMessage() . "\n"; + } +} + diff --git a/db/migrations/001_create_tasks_table.sql b/db/migrations/001_create_tasks_table.sql new file mode 100644 index 0000000..9a17310 --- /dev/null +++ b/db/migrations/001_create_tasks_table.sql @@ -0,0 +1,9 @@ +-- Create the tasks table +CREATE TABLE IF NOT EXISTS tasks ( + id INT AUTO_INCREMENT PRIMARY KEY, + title VARCHAR(255) NOT NULL, + description TEXT, + status ENUM('pending', 'in-progress', 'completed') DEFAULT 'pending', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +); diff --git a/index.php b/index.php index 2558a2e..d1234c0 100644 --- a/index.php +++ b/index.php @@ -1,3 +1,49 @@ + false, 'message' => 'Task title cannot be empty.']); + exit; + } + + try { + $pdo = db(); + $stmt = $pdo->prepare("INSERT INTO tasks (title, description) VALUES (:title, :description)"); + $stmt->bindParam(':title', $title); + $stmt->bindParam(':description', $description); + + if ($stmt->execute()) { + echo json_encode(['success' => true, 'message' => 'Task added successfully.', 'id' => $pdo->lastInsertId()]); + } else { + echo json_encode(['success' => false, 'message' => 'Failed to add task.']); + } + } catch (PDOException $e) { + echo json_encode(['success' => false, 'message' => 'Database error: ' . $e->getMessage()]); + } + exit; +} + +if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['action']) && $_GET['action'] === 'getTasks') { + header('Content-Type: application/json'); + try { + $pdo = db(); + $stmt = $pdo->query("SELECT id, title, description, status, created_at FROM tasks ORDER BY created_at DESC"); + $tasks = $stmt->fetchAll(PDO::FETCH_ASSOC); + echo json_encode(['success' => true, 'tasks' => $tasks]); + } catch (PDOException $e) { + echo json_encode(['success' => false, 'message' => 'Database error: ' . $e->getMessage()]); + } + exit; +} + + @@ -64,7 +110,7 @@ - + @@ -75,6 +121,40 @@

This is your personal productivity dashboard. Let's get things done.

+ + + + +
+

Your Tasks

+
+
+