add tasks driectly from tracker

This commit is contained in:
2026-02-11 13:29:51 +01:00
parent a5a56923ab
commit 05398bdfd6
2 changed files with 194 additions and 21 deletions

View File

@@ -184,25 +184,32 @@
<div class="timer-display" id="timer" style="margin: 1rem 0 2rem 0;">00:00:00</div>
<!-- Tasks List (Redesigned) -->
{% if tasks %}
<div style="margin-bottom: 2rem;">
<h4 style="font-size: 0.8rem; text-transform: uppercase; color: var(--text-secondary); letter-spacing: 0.05em; border-bottom: 1px solid var(--border-dim); padding-bottom: 5px;">Active Tasks</h4>
<div style="display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--border-dim); padding-bottom: 5px; margin-bottom: 10px;">
<h4 style="font-size: 0.8rem; text-transform: uppercase; color: var(--text-secondary); letter-spacing: 0.05em; margin: 0;">Active Tasks</h4>
<!-- Quick Add Button -->
<button type="button" onclick="openQuickTaskModal()" style="background: transparent; border: 1px solid var(--border-dim); cursor: pointer; border-radius: 50%; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; color: var(--text-secondary); margin-left: 10px;" title="Add Task">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg>
</button>
</div>
<div class="checklist-container" id="activeTasksList">
{% for task in tasks %}
<div class="checklist-item {% if task.status == 'completed' %}completed{% endif %}" id="task-item-{{ task._id }}">
<input type="checkbox" id="task_{{ task._id }}"
{% if task.status == 'completed' %}checked{% endif %}
onchange="toggleTask('{{ task._id }}', this)">
<label for="task_{{ task._id }}">
<a href="{{ url_for('task_detail', task_id=task._id) }}" style="text-decoration: none; color: inherit;">
{{ task.name }}
</a>
</label>
</div>
{% endfor %}
{% if tasks %}
{% for task in tasks %}
<div class="checklist-item {% if task.status == 'completed' %}completed{% endif %}" id="task-item-{{ task._id }}">
<input type="checkbox" id="task_{{ task._id }}"
{% if task.status == 'completed' %}checked{% endif %}
onchange="toggleTask('{{ task._id }}', this)">
<label for="task_{{ task._id }}">
<a href="{{ url_for('task_detail', task_id=task._id) }}" style="text-decoration: none; color: inherit;">
{{ task.name }}
</a>
</label>
</div>
{% endfor %}
{% endif %}
</div>
</div>
{% endif %}
<form action="{{ url_for('stop_timer') }}" method="POST">
<button type="submit" class="btn btn-danger" style="width: 100%; justify-content: center; padding: 12px;">Stop Activity</button>
@@ -214,6 +221,10 @@
<!-- Scripts (Timer, Tasks, Modal) -->
<script>
// Global vars - MUST be declared before any functions that use them
let currentActivityId = "{{ current_entry.activity_id if current_entry else '' }}";
let currentSubcategory = "{{ current_entry.subcategory if current_entry else '' }}";
// Timer Logic
let startTime = {% if current_entry %}{{ current_entry.start_time.timestamp() * 1000 }}{% else %}null{% endif %};
let timerInterval;
@@ -283,17 +294,30 @@
document.getElementById('startModal').classList.remove('show');
}
function closeQuickTaskModal() {
document.getElementById('quickTaskModal').classList.remove('show');
document.getElementById('quickTaskName').value = ''; // Clean up
}
// Close on backdrop click
document.getElementById('startModal').addEventListener('click', function(e) {
if (e.target === this) closeStartModal();
});
document.getElementById('quickTaskModal').addEventListener('click', function(e) {
if (e.target === this) closeQuickTaskModal();
});
// Start Activity Immediate Function
function startActivityImmediate(element) {
const id = element.getAttribute('data-id');
const name = element.getAttribute('data-name');
const color = element.getAttribute('data-color');
const subcats = JSON.parse(element.getAttribute('data-subcategories') || '[]');
// Save ID globally for quick add
currentActivityId = id;
// 1. Start Background Timer
fetch('/start_timer_bg/' + id, { method: 'POST' })
.then(res => res.json())
@@ -321,6 +345,14 @@
// Reset Note/Subcat display
document.getElementById('activeNote').style.display = 'none';
document.getElementById('activeSubcatContainer').style.display = 'none';
document.getElementById('activeSubcatDisplay').innerText = ''; // Reset text
currentSubcategory = ""; // Reset global
// Clear tasks list visually on new start (will define via sync or reload if templates exist)
// Ideally we'd fetch templates here, but sync will catch them in 2s.
// For smoother UX, we could inject template names if passed from backend.
document.getElementById('activeTasksList').innerHTML = '';
localTaskIds = []; // Reset local known tasks
// 3. Open Modal for Details
openDetailsModal(name, subcats);
@@ -328,6 +360,7 @@
});
}
// Hook into form update to set these values when modal is submitted/skipped
function openDetailsModal(name, subcats) {
document.getElementById('modalTitle').innerText = name + " Started";
@@ -353,6 +386,58 @@
document.querySelector('#startForm input[name="note"]').focus();
}
// Open Quick Task Modal
function openQuickTaskModal() {
if(!currentActivityId) {
alert("No active activity context found. Please start an activity first.");
return;
}
document.getElementById('quickTaskModal').classList.add('show');
document.getElementById('quickTaskName').focus();
}
// Quick Add Form Submit
function submitQuickTask(e) {
e.preventDefault();
const input = document.getElementById('quickTaskName');
const val = input.value.trim();
if(!val) return;
const formData = new FormData();
formData.append('name', val);
formData.append('activity_id', currentActivityId);
formData.append('subcategory', currentSubcategory);
fetch('/create_task_quick', { method: 'POST', body: formData })
.then(r => r.json())
.then(data => {
if(data.status === 'success') {
input.value = '';
closeQuickTaskModal();
// Add to DOM
const list = document.getElementById('activeTasksList');
const div = document.createElement('div');
div.className = 'checklist-item';
div.id = 'task-item-' + data.task_id;
div.innerHTML = `
<input type="checkbox" id="task_${data.task_id}"
onchange="toggleTask('${data.task_id}', this)">
<label for="task_${data.task_id}">
<a href="/task/${data.task_id}" style="text-decoration: none; color: inherit;">
${data.name}
</a>
</label>
`;
list.insertBefore(div, list.firstChild); // Add to top
// Register ID so sync doesn't reload
localTaskIds.push(data.task_id);
console.log("Quick task added. Sync updated.");
}
});
}
// New Task List Logic for Activity Creation form (Reusing existing script)
let newActivityTasks = [];
function addNewTask() {
@@ -395,15 +480,15 @@
<div id="startModal" class="modal-backdrop">
<div class="modal-card">
<h3 id="modalTitle" style="margin-bottom: 1.5rem;">Activity Started</h3>
<form id="startForm" action="{{ url_for('update_active_entry') }}" method="POST">
<div id="subcategoryContainer" style="display: none; margin-bottom: 1rem;">
<form id="startForm" onsubmit="submitDetailsForm(event)">
<div id="subcategoryContainer" style="display: none; margin-bottom: 1rem;">
<label>Subcategory / Context</label>
<select name="subcategory" id="modalSubcatSelect" style="width: 100%; padding: 0.5rem;">
<option value="">-- None --</option>
</select>
</div>
<label>Note (Optional)</label>
<input type="text" name="note" placeholder="What are you working on?" autocomplete="off">
<input type="text" name="note" id="modalNote" placeholder="What are you working on?" autocomplete="off">
<div style="margin-top: 2rem; display: flex; justify-content: space-between;">
<button type="button" class="btn" style="background: transparent; color: var(--text-secondary); border: 1px solid var(--border-dim);" onclick="closeStartModal()">Skip</button>
<button type="submit" class="btn" style="background: #27ae60;">Update Details</button>
@@ -412,6 +497,53 @@
</div>
</div>
<!-- Quick Task Modal (For adding task to active session) -->
<div id="quickTaskModal" class="modal-backdrop">
<div class="modal-card">
<h3 style="margin-bottom: 1.5rem;">Add Task</h3>
<p style="color: var(--text-secondary); margin-bottom: 1rem; font-size: 0.9rem;">
This task will be linked to the current activity.
</p>
<form onsubmit="submitQuickTask(event)">
<label>Task Name</label>
<input type="text" id="quickTaskName" required placeholder="What needs to be done?" autocomplete="off">
<div style="margin-top: 2rem; display: flex; justify-content: flex-end; gap: 10px;">
<button type="button" class="btn" style="background: transparent; color: var(--text-secondary); border: 1px solid var(--border-dim);" onclick="closeQuickTaskModal()">Cancel</button>
<button type="submit" class="btn" style="background: #27ae60;">Add Task</button>
</div>
</form>
</div>
</div>
<script>
// Replace standard form submit for details so page doesn't reload and lose state
function submitDetailsForm(e) {
e.preventDefault();
const sub = document.getElementById('modalSubcatSelect').value;
const note = document.getElementById('modalNote').value;
currentSubcategory = sub; // Update global for quick add task
// Update UI immediately
if(sub) {
document.getElementById('activeSubcatContainer').style.display = 'block';
document.getElementById('activeSubcatDisplay').innerText = sub;
}
if(note) {
document.getElementById('activeNote').style.display = 'block';
document.getElementById('activeNote').innerText = '"' + note + '"';
}
const fd = new FormData();
fd.append('subcategory', sub);
fd.append('note', note);
fetch('/update_active_entry', { method: 'POST', body: fd });
closeStartModal();
}
</script>
<!-- Live Sync Script (Optimized for Animation) -->
<script>
// Generate initial state hashes based on what Jinja rendered
@@ -431,8 +563,9 @@
// Don't poll if page is hidden to save battery/data
if (document.hidden) return;
// Don't poll or reload if the Start Modal is open (User is interacting)
if (document.getElementById('startModal').classList.contains('show')) return;
// Don't poll or reload if ANY Modal is open (User is interacting)
if (document.getElementById('startModal').classList.contains('show') ||
document.getElementById('quickTaskModal').classList.contains('show')) return;
fetch('/api/sync_check')
.then(response => {