2025-08-27 06:21:40 -04:00

742 lines
26 KiB
PHP

<?php
// Database configuration (adjust with your NRP)
$host = '202.46.28.160';
$port = '45432';
$username = '5803024009'; // your NRP
$password = 'pw5803024009';
$database = 'tgs01_5803024009';
try {
// Create PDO connection for PostgreSQL
$conn = new PDO("pgsql:host=$host;port=$port;dbname=$database", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Connection failed: " . $e->getMessage());
}
// Create tables if they don't exist
$create_groups_table = "CREATE TABLE IF NOT EXISTS groups (
group_id SERIAL PRIMARY KEY,
group_name VARCHAR(255) NOT NULL UNIQUE
)";
$create_tasks_table = "CREATE TABLE IF NOT EXISTS tasks (
task_id SERIAL PRIMARY KEY,
group_id INT NOT NULL,
task VARCHAR(255) NOT NULL,
isdone BOOLEAN DEFAULT FALSE,
task_desc VARCHAR(255) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (group_id) REFERENCES groups(group_id) ON DELETE CASCADE
)";
$conn->exec($create_groups_table);
$conn->exec($create_tasks_table);
// Handle form submissions
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['add_group'])) {
$group_name = trim($_POST['group_name']);
if (!empty($group_name)) {
try {
$stmt = $conn->prepare("INSERT INTO groups (group_name) VALUES (?)");
$stmt->execute([$group_name]);
} catch (PDOException $e) {
$error_message = "Error adding group: Group name might already exist.";
}
}
}
if (isset($_POST['add_task'])) {
$group_id = $_POST['group_id'];
$task = trim($_POST['task']);
$task_desc = trim($_POST['task_desc']);
if (!empty($task) && !empty($group_id)) {
// If task_desc is empty, provide a default value since it's NOT NULL
if (empty($task_desc)) {
$task_desc = "No description provided";
}
$stmt = $conn->prepare("INSERT INTO tasks (group_id, task, task_desc, isdone) VALUES (?, ?, ?, FALSE)");
$stmt->execute([$group_id, $task, $task_desc]);
}
}
if (isset($_POST['toggle_task'])) {
$task_id = $_POST['task_id'];
$stmt = $conn->prepare("UPDATE tasks SET isdone = NOT isdone WHERE task_id = ?");
$stmt->execute([$task_id]);
}
if (isset($_POST['delete_task'])) {
$task_id = $_POST['task_id'];
$stmt = $conn->prepare("DELETE FROM tasks WHERE task_id = ?");
$stmt->execute([$task_id]);
}
if (isset($_POST['delete_group'])) {
$group_id = $_POST['group_id'];
$stmt = $conn->prepare("DELETE FROM groups WHERE group_id = ?");
$stmt->execute([$group_id]);
}
if (isset($_POST['edit_task'])) {
$task_id = $_POST['task_id'];
$task = trim($_POST['task']);
$task_desc = trim($_POST['task_desc']);
if (!empty($task)) {
// If task_desc is empty, provide a default value since it's NOT NULL
if (empty($task_desc)) {
$task_desc = "No description provided";
}
$stmt = $conn->prepare("UPDATE tasks SET task = ?, task_desc = ? WHERE task_id = ?");
$stmt->execute([$task, $task_desc, $task_id]);
}
}
}
// Fetch all groups
$groups_result = $conn->query("SELECT * FROM groups ORDER BY group_name");
$groups = $groups_result->fetchAll(PDO::FETCH_ASSOC);
// Fetch all tasks with group names and creation date
$tasks_result = $conn->query("
SELECT t.task_id, t.group_id, t.task, t.isdone, t.task_desc, t.created_at, g.group_name
FROM tasks t
JOIN groups g ON t.group_id = g.group_id
ORDER BY g.group_name, t.created_at DESC
");
$tasks_data = $tasks_result->fetchAll(PDO::FETCH_ASSOC);
// Group tasks by group name
$tasks = [];
foreach ($tasks_data as $row) {
$tasks[$row['group_name']][] = $row;
}
// Get task statistics
$stats_result = $conn->query("
SELECT
g.group_name,
COUNT(t.task_id) as total_tasks,
COUNT(CASE WHEN t.isdone = TRUE THEN 1 END) as completed_tasks,
COUNT(CASE WHEN t.isdone = FALSE THEN 1 END) as pending_tasks
FROM groups g
LEFT JOIN tasks t ON g.group_id = t.group_id
GROUP BY g.group_id, g.group_name
ORDER BY g.group_name
");
$stats = $stats_result->fetchAll(PDO::FETCH_ASSOC);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Enhanced Task Manager</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
position: relative;
overflow-x: hidden;
}
body::before {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background:
radial-gradient(circle at 20% 80%, rgba(120, 119, 198, 0.3) 0%, transparent 50%),
radial-gradient(circle at 80% 20%, rgba(255, 119, 198, 0.3) 0%, transparent 50%);
pointer-events: none;
z-index: -1;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 24px;
padding: 40px;
box-shadow:
0 20px 40px rgba(0, 0, 0, 0.1),
0 8px 32px rgba(31, 38, 135, 0.37);
animation: slideUp 0.6s ease-out;
}
@keyframes slideUp {
from { opacity: 0; transform: translateY(30px); }
to { opacity: 1; transform: translateY(0); }
}
h1 {
font-size: 3.5rem;
font-weight: 800;
background: linear-gradient(135deg, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
text-align: center;
margin-bottom: 40px;
position: relative;
}
h1::after {
content: '';
position: absolute;
bottom: -10px;
left: 50%;
transform: translateX(-50%);
width: 100px;
height: 4px;
background: linear-gradient(135deg, #667eea, #764ba2);
border-radius: 2px;
}
h2 {
font-size: 1.8rem;
font-weight: 700;
color: #2d3748;
margin-bottom: 24px;
display: flex;
align-items: center;
}
h2::before {
content: '';
width: 4px;
height: 24px;
background: linear-gradient(135deg, #667eea, #764ba2);
border-radius: 2px;
margin-right: 12px;
}
.error-message {
background: linear-gradient(135deg, #ff6b6b, #ee5a24);
color: white;
padding: 16px;
border-radius: 12px;
margin-bottom: 20px;
text-align: center;
font-weight: 600;
}
.stats-section {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-bottom: 32px;
}
.stat-card {
background: linear-gradient(145deg, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.6));
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 16px;
padding: 24px;
text-align: center;
transition: all 0.3s ease;
}
.stat-card:hover {
transform: translateY(-4px);
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.1);
}
.stat-card h4 {
font-size: 1rem;
color: #718096;
margin-bottom: 8px;
}
.stat-card .stat-number {
font-size: 2rem;
font-weight: 800;
background: linear-gradient(135deg, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.forms-section {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 32px;
margin-bottom: 48px;
}
.form-container {
background: linear-gradient(145deg, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.6));
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 20px;
padding: 32px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
transition: all 0.3s ease;
}
.form-container:hover {
transform: translateY(-4px);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.12);
}
.form-group {
margin-bottom: 24px;
}
label {
display: block;
margin-bottom: 8px;
font-weight: 600;
color: #4a5568;
font-size: 0.95rem;
}
input[type="text"], select, textarea {
width: 100%;
padding: 16px 20px;
border: 2px solid rgba(102, 126, 234, 0.1);
border-radius: 12px;
font-size: 1rem;
background: rgba(255, 255, 255, 0.8);
transition: all 0.3s ease;
color: #2d3748;
font-family: inherit;
}
textarea {
resize: vertical;
min-height: 80px;
}
input[type="text"]:focus, select:focus, textarea:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.1);
background: rgba(255, 255, 255, 0.95);
transform: translateY(-1px);
}
button {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 14px 28px;
border: none;
border-radius: 12px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
}
button:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
}
.delete-btn {
background: linear-gradient(135deg, #ff6b6b 0%, #ee5a24 100%);
box-shadow: 0 4px 15px rgba(255, 107, 107, 0.3);
}
.delete-btn:hover {
box-shadow: 0 8px 25px rgba(255, 107, 107, 0.4);
}
.edit-btn {
background: linear-gradient(135deg, #ffa726 0%, #fb8c00 100%);
box-shadow: 0 4px 15px rgba(255, 167, 38, 0.3);
padding: 8px 16px;
font-size: 0.9rem;
}
.edit-btn:hover {
box-shadow: 0 8px 25px rgba(255, 167, 38, 0.4);
}
.task-group {
margin-bottom: 32px;
background: linear-gradient(145deg, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.6));
backdrop-filter: blur(15px);
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 20px;
padding: 32px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
transition: all 0.3s ease;
position: relative;
}
.task-group::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 4px;
background: linear-gradient(135deg, #667eea, #764ba2);
}
.task-group:hover {
transform: translateY(-2px);
box-shadow: 0 15px 40px rgba(0, 0, 0, 0.12);
}
.task-group h3 {
font-size: 1.5rem;
font-weight: 700;
color: #2d3748;
margin-bottom: 24px;
display: flex;
justify-content: space-between;
align-items: center;
}
.task-item {
background: rgba(255, 255, 255, 0.7);
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 12px;
padding: 20px;
margin: 16px 0;
transition: all 0.3s ease;
position: relative;
}
.task-item:hover {
transform: translateX(8px);
background: rgba(255, 255, 255, 0.9);
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1);
}
.task-item.completed {
opacity: 0.6;
background: rgba(255, 255, 255, 0.5);
}
.task-header {
display: flex;
align-items: flex-start;
gap: 15px;
margin-bottom: 12px;
}
.checkbox-btn {
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.2rem;
padding: 0;
flex-shrink: 0;
margin-top: 2px;
}
.checkbox-btn.completed {
background: linear-gradient(135deg, #48bb78, #38a169);
}
.task-content {
flex-grow: 1;
}
.task-title {
font-size: 1.2rem;
font-weight: 600;
color: #2d3748;
margin-bottom: 8px;
transition: all 0.3s ease;
}
.completed .task-title {
text-decoration: line-through;
color: #a0aec0;
}
.task-description {
font-size: 1rem;
color: #718096;
margin-bottom: 8px;
line-height: 1.5;
}
.completed .task-description {
color: #a0aec0;
}
.task-meta {
font-size: 0.85rem;
color: #a0aec0;
font-style: italic;
}
.task-actions {
display: flex;
gap: 8px;
flex-shrink: 0;
flex-direction: column;
}
.edit-form {
display: none;
background: rgba(255, 255, 255, 0.9);
border-radius: 12px;
padding: 20px;
margin-top: 16px;
border: 2px solid rgba(102, 126, 234, 0.2);
}
.edit-form.show {
display: block;
animation: slideDown 0.3s ease-out;
}
@keyframes slideDown {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}
.empty-state {
text-align: center;
padding: 60px 20px;
color: #718096;
font-size: 1.2rem;
background: rgba(255, 255, 255, 0.5);
border-radius: 20px;
border: 2px dashed rgba(102, 126, 234, 0.3);
}
.empty-state::before {
content: '✨';
display: block;
font-size: 3rem;
margin-bottom: 16px;
opacity: 0.7;
}
.group-stats {
font-size: 0.9rem;
color: #718096;
display: flex;
gap: 16px;
margin-top: 8px;
}
.group-stats span {
background: rgba(102, 126, 234, 0.1);
padding: 4px 12px;
border-radius: 20px;
}
@media (max-width: 768px) {
.forms-section { grid-template-columns: 1fr; }
.task-group h3 { flex-direction: column; align-items: flex-start; gap: 16px; }
.task-header { flex-direction: column; }
.task-actions { justify-content: flex-end; flex-direction: row; }
.stats-section { grid-template-columns: 1fr; }
}
</style>
<script>
function toggleEditForm(taskId) {
const form = document.getElementById('edit-form-' + taskId);
const isVisible = form.classList.contains('show');
// Hide all other edit forms
document.querySelectorAll('.edit-form').forEach(f => f.classList.remove('show'));
// Toggle current form
if (!isVisible) {
form.classList.add('show');
}
}
</script>
</head>
<body>
<div class="container">
<h1>Enhanced Task Manager</h1>
<?php if (isset($error_message)): ?>
<div class="error-message"><?php echo $error_message; ?></div>
<?php endif; ?>
<!-- Statistics Section -->
<?php if (!empty($stats)): ?>
<div class="stats-section">
<?php
$total_all_tasks = array_sum(array_column($stats, 'total_tasks'));
$total_completed = array_sum(array_column($stats, 'completed_tasks'));
$total_pending = array_sum(array_column($stats, 'pending_tasks'));
?>
<div class="stat-card">
<h4>Total Tasks</h4>
<div class="stat-number"><?php echo $total_all_tasks; ?></div>
</div>
<div class="stat-card">
<h4>Completed</h4>
<div class="stat-number"><?php echo $total_completed; ?></div>
</div>
<div class="stat-card">
<h4>Pending</h4>
<div class="stat-number"><?php echo $total_pending; ?></div>
</div>
<div class="stat-card">
<h4>Groups</h4>
<div class="stat-number"><?php echo count($groups); ?></div>
</div>
</div>
<?php endif; ?>
<div class="forms-section">
<!-- Add Group Form -->
<div class="form-container">
<h2>Add New Group</h2>
<form method="POST">
<div class="form-group">
<label for="group_name">Group Name:</label>
<input type="text" id="group_name" name="group_name" required>
</div>
<button type="submit" name="add_group">Add Group</button>
</form>
</div>
<!-- Add Task Form -->
<div class="form-container">
<h2>Add New Task</h2>
<form method="POST">
<div class="form-group">
<label for="group_id">Group:</label>
<select id="group_id" name="group_id" required>
<option value="">Select a group</option>
<?php foreach ($groups as $group): ?>
<option value="<?php echo $group['group_id']; ?>">
<?php echo htmlspecialchars($group['group_name']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="form-group">
<label for="task">Task Title:</label>
<input type="text" id="task" name="task" required>
</div>
<div class="form-group">
<label for="task_desc">Description:</label>
<textarea id="task_desc" name="task_desc" placeholder="Add details about this task..." required></textarea>
</div>
<button type="submit" name="add_task">Add Task</button>
</form>
</div>
</div>
<!-- Display Groups and Tasks -->
<div class="tasks-section">
<h2>Your Task Lists</h2>
<?php if (empty($tasks)): ?>
<div class="empty-state">
<p>No tasks yet. Create a group and add some tasks to get started!</p>
</div>
<?php else: ?>
<?php foreach ($tasks as $group_name => $group_tasks): ?>
<?php
$group_stats = array_filter($stats, function($s) use ($group_name) {
return $s['group_name'] === $group_name;
});
$group_stat = reset($group_stats);
?>
<div class="task-group">
<h3>
<div>
<span><?php echo htmlspecialchars($group_name); ?></span>
<div class="group-stats">
<span>Total: <?php echo $group_stat['total_tasks']; ?></span>
<span>Completed: <?php echo $group_stat['completed_tasks']; ?></span>
<span>Pending: <?php echo $group_stat['pending_tasks']; ?></span>
</div>
</div>
<form method="POST" style="display: inline;">
<input type="hidden" name="group_id" value="<?php echo $group_tasks[0]['group_id']; ?>">
<button type="submit" name="delete_group" class="delete-btn"
onclick="return confirm('Are you sure? This will delete all tasks in this group!')">
🗑️ Delete Group
</button>
</form>
</h3>
<?php foreach ($group_tasks as $task): ?>
<div class="task-item <?php echo $task['isdone'] ? 'completed' : ''; ?>">
<div class="task-header">
<form method="POST" style="display: inline;">
<input type="hidden" name="task_id" value="<?php echo $task['task_id']; ?>">
<button type="submit" name="toggle_task" class="checkbox-btn <?php echo $task['isdone'] ? 'completed' : ''; ?>">
<?php echo $task['isdone'] ? '✓' : '○'; ?>
</button>
</form>
<div class="task-content">
<div class="task-title">
<?php echo htmlspecialchars($task['task']); ?>
</div>
<div class="task-description">
<?php echo htmlspecialchars($task['task_desc']); ?>
</div>
<div class="task-meta">
Created: <?php echo date('M j, Y g:i A', strtotime($task['created_at'])); ?>
</div>
</div>
<div class="task-actions">
<button type="button" class="edit-btn" onclick="toggleEditForm(<?php echo $task['task_id']; ?>)">
✏️ Edit
</button>
<form method="POST" style="display: inline;">
<input type="hidden" name="task_id" value="<?php echo $task['task_id']; ?>">
<button type="submit" name="delete_task" class="delete-btn"
onclick="return confirm('Are you sure you want to delete this task?')">
🗑️ Delete
</button>
</form>
</div>
</div>
<!-- Edit Form -->
<div id="edit-form-<?php echo $task['task_id']; ?>" class="edit-form">
<h4>Edit Task</h4>
<form method="POST">
<input type="hidden" name="task_id" value="<?php echo $task['task_id']; ?>">
<div class="form-group">
<label>Task Title:</label>
<input type="text" name="task" value="<?php echo htmlspecialchars($task['task']); ?>" required>
</div>
<div class="form-group">
<label>Description:</label>
<textarea name="task_desc" required><?php echo htmlspecialchars($task['task_desc']); ?></textarea>
</div>
<button type="submit" name="edit_task">Save Changes</button>
<button type="button" onclick="toggleEditForm(<?php echo $task['task_id']; ?>)" style="background: #718096; margin-left: 10px;">Cancel</button>
</form>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
</body>
</html>
<?php
$conn = null;
?>