Add settings/task management template

This commit is contained in:
2025-12-10 10:44:48 +11:00
parent 2414123c78
commit eef41cedf1

206
templates/settings.html Normal file
View File

@@ -0,0 +1,206 @@
{% extends "base.html" %}
{% block title %}Tasks - Raccoon Timekeeper{% endblock %}
{% block tagline %}Manage your tasks{% endblock %}
{% block content %}
<section class="card">
<div class="card-header">
<h2>Your Tasks</h2>
<button class="btn btn-primary" onclick="openAddTaskModal()">
<span class="btn-icon">+</span>
Add Task
</button>
</div>
<div id="tasksList" class="tasks-list">
<div class="loading">Loading tasks...</div>
</div>
</section>
<!-- Add Task Modal -->
<div id="addTaskModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h3>Add New Task</h3>
<button class="modal-close" onclick="closeModal('addTaskModal')">×</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="newTaskName">Task Name</label>
<input type="text" id="newTaskName" placeholder="Enter task name...">
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" onclick="closeModal('addTaskModal')">Cancel</button>
<button class="btn btn-primary" onclick="saveNewTask()">Add Task</button>
</div>
</div>
</div>
<!-- Edit Task Modal -->
<div id="editTaskModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h3>Edit Task</h3>
<button class="modal-close" onclick="closeModal('editTaskModal')">×</button>
</div>
<div class="modal-body">
<input type="hidden" id="editTaskId">
<div class="form-group">
<label for="editTaskName">Task Name</label>
<input type="text" id="editTaskName" placeholder="Enter task name...">
</div>
<div class="form-group checkbox-group">
<label class="checkbox-label">
<input type="checkbox" id="editTaskActive">
<span>Active</span>
</label>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-danger" onclick="deleteTask()">Delete</button>
<button class="btn btn-secondary" onclick="closeModal('editTaskModal')">Cancel</button>
<button class="btn btn-primary" onclick="saveEditTask()">Save</button>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script>
document.addEventListener('DOMContentLoaded', loadTasks);
async function loadTasks() {
try {
const response = await fetch('/api/tasks?include_inactive=true');
const tasks = await response.json();
renderTasks(tasks);
} catch (error) {
showToast('Error loading tasks', 'error');
}
}
function renderTasks(tasks) {
const container = document.getElementById('tasksList');
if (!tasks.length) {
container.innerHTML = '<div class="empty-state">📋 No tasks yet. Create one!</div>';
return;
}
let html = '';
tasks.forEach(task => {
html += `
<div class="task-item ${task.active ? '' : 'inactive'}" data-id="${task.id}">
<div class="task-info">
<span class="task-name">${task.name}</span>
${!task.active ? '<span class="task-badge inactive-badge">Inactive</span>' : ''}
</div>
<button class="btn btn-icon" onclick="openEditTaskModal(${task.id}, '${task.name.replace(/'/g, "\\'")}', ${task.active})">
✏️
</button>
</div>
`;
});
container.innerHTML = html;
}
function openAddTaskModal() {
document.getElementById('addTaskModal').classList.add('active');
document.getElementById('newTaskName').value = '';
document.getElementById('newTaskName').focus();
}
function openEditTaskModal(id, name, active) {
document.getElementById('editTaskId').value = id;
document.getElementById('editTaskName').value = name;
document.getElementById('editTaskActive').checked = active;
document.getElementById('editTaskModal').classList.add('active');
}
function closeModal(modalId) {
document.getElementById(modalId).classList.remove('active');
}
async function saveNewTask() {
const name = document.getElementById('newTaskName').value.trim();
if (!name) { showToast('Enter a task name', 'error'); return; }
try {
const response = await fetch('/api/tasks', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name })
});
const result = await response.json();
if (result.success) {
showToast('Task added!', 'success');
closeModal('addTaskModal');
loadTasks();
} else {
showToast(result.message, 'error');
}
} catch (error) {
showToast('Error adding task', 'error');
}
}
async function saveEditTask() {
const id = document.getElementById('editTaskId').value;
const name = document.getElementById('editTaskName').value.trim();
const active = document.getElementById('editTaskActive').checked;
if (!name) { showToast('Enter a task name', 'error'); return; }
try {
const response = await fetch(`/api/tasks/${id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, active })
});
const result = await response.json();
if (result.success) {
showToast('Task updated!', 'success');
closeModal('editTaskModal');
loadTasks();
} else {
showToast(result.message, 'error');
}
} catch (error) {
showToast('Error updating task', 'error');
}
}
async function deleteTask() {
if (!confirm('Delete this task? This will also delete all time entries for this task.')) return;
const id = document.getElementById('editTaskId').value;
try {
const response = await fetch(`/api/tasks/${id}`, { method: 'DELETE' });
const result = await response.json();
if (result.success) {
showToast('Task deleted', 'success');
closeModal('editTaskModal');
loadTasks();
} else {
showToast(result.message, 'error');
}
} catch (error) {
showToast('Error deleting task', 'error');
}
}
document.getElementById('newTaskName').addEventListener('keypress', e => {
if (e.key === 'Enter') { e.preventDefault(); saveNewTask(); }
});
document.getElementById('editTaskName').addEventListener('keypress', e => {
if (e.key === 'Enter') { e.preventDefault(); saveEditTask(); }
});
</script>
{% endblock %}