From 6902ff3373bfb8b424af886ab6b7e6fcfd5a41ae Mon Sep 17 00:00:00 2001 From: calboo Date: Tue, 10 Feb 2026 19:31:57 +0100 Subject: [PATCH] subcategories and editing for tasks --- app.py | 139 ++++++++++++++++++++++--- templates/dashboard.html | 189 ++++++++++++++++++++++++---------- templates/edit_activity.html | 83 +++++++++++++++ templates/logbook.html | 9 +- templates/logbook_detail.html | 46 +++++++-- templates/task_detail.html | 2 +- templates/tasks.html | 2 +- 7 files changed, 389 insertions(+), 81 deletions(-) create mode 100644 templates/edit_activity.html diff --git a/app.py b/app.py index d6db2f8..47a8d12 100644 --- a/app.py +++ b/app.py @@ -108,7 +108,8 @@ def add_activity(): activity_id = db.activities.insert_one({ 'user_id': get_user_id(), 'name': name, - 'color': color + 'color': color, + 'subcategories': [] # Initialize empty list }).inserted_id # Add optional tasks @@ -124,11 +125,100 @@ def add_activity(): return redirect(url_for('index')) +@app.route('/edit_activity/', methods=['GET', 'POST']) +def edit_activity(activity_id): + if not is_logged_in(): return redirect(url_for('login')) + user_id = get_user_id() + + if request.method == 'POST': + name = request.form['name'] + color = request.form.get('color', '#3498db') + subcats_str = request.form.get('subcategories', '') + + # Parse comma-separated string into list + subcategories = [s.strip() for s in subcats_str.split(',') if s.strip()] + + db.activities.update_one( + {'_id': ObjectId(activity_id), 'user_id': user_id}, + {'$set': {'name': name, 'color': color, 'subcategories': subcategories}} + ) + return redirect(url_for('index')) + + activity = db.activities.find_one({'_id': ObjectId(activity_id), 'user_id': user_id}) + if not activity: return "Activity not found", 404 + + return render_template('edit_activity.html', activity=activity) + +@app.route('/start_timer_bg/', methods=['POST']) +def start_timer_bg(activity_id): + if not is_logged_in(): return jsonify({'error': 'auth'}), 401 + user_id = get_user_id() + + # Stop ANY running timer + db.time_entries.update_many( + {'user_id': user_id, 'end_time': None}, + {'$set': {'end_time': datetime.now()}} + ) + + # Start new + start_time = datetime.now() + new_entry_id = db.time_entries.insert_one({ + 'user_id': user_id, + 'activity_id': ObjectId(activity_id), + 'start_time': start_time, + 'end_time': None, + 'note': '', + 'subcategory': '' + }).inserted_id + + # Auto-add templates + templates = db.tasks.find({ + 'user_id': user_id, + 'activity_id': ObjectId(activity_id), + 'is_template': True + }) + + for t in templates: + db.tasks.insert_one({ + 'user_id': user_id, + 'name': t['name'], + 'activity_id': ObjectId(activity_id), + 'time_entry_id': new_entry_id, + 'status': 'open', + 'is_template': False, + 'created_at': datetime.now(), + 'comments': [] + }) + + activity = db.activities.find_one({'_id': ObjectId(activity_id)}) + + return jsonify({ + 'status': 'success', + 'start_time': start_time.isoformat(), + 'activity_name': activity['name'], + 'activity_color': activity.get('color', '#3498db') + }) + +@app.route('/update_active_entry', methods=['POST']) +def update_active_entry(): + if not is_logged_in(): return redirect(url_for('login')) + user_id = get_user_id() + + note = request.form.get('note', '') + subcategory = request.form.get('subcategory', '') + + db.time_entries.update_one( + {'user_id': user_id, 'end_time': None}, + {'$set': {'note': note, 'subcategory': subcategory}} + ) + return redirect(url_for('index')) + @app.route('/toggle_timer/', methods=['POST']) def toggle_timer(activity_id): if not is_logged_in(): return redirect(url_for('login')) user_id = get_user_id() note = request.form.get('note', '') + subcategory = request.form.get('subcategory', '') # Get subcategory # Check if this activity is currently running current = db.time_entries.find_one({ @@ -150,14 +240,15 @@ def toggle_timer(activity_id): {'$set': {'end_time': datetime.now()}} ) # Start new - new_entry_id = db.time_entries.insert_one({ + db.time_entries.insert_one({ 'user_id': user_id, 'activity_id': ObjectId(activity_id), 'start_time': datetime.now(), 'end_time': None, - 'note': note - }).inserted_id - + 'note': note, + 'subcategory': subcategory # Store it + }) + # Check for Task Templates and auto-add them templates = db.tasks.find({ 'user_id': user_id, @@ -345,15 +436,37 @@ def logbook(): def log_entry_detail(entry_id): if not is_logged_in(): return redirect(url_for('login')) - # Handle Note Update + # Handle Updates and Deletion if request.method == 'POST': - new_note = request.form.get('note') - db.time_entries.update_one( - {'_id': ObjectId(entry_id), 'user_id': get_user_id()}, - {'$set': {'note': new_note}} - ) - flash('Session note updated') - return redirect(url_for('log_entry_detail', entry_id=entry_id)) + action = request.form.get('action') + + if action == 'delete': + db.time_entries.delete_one({'_id': ObjectId(entry_id), 'user_id': get_user_id()}) + flash('Entry deleted') + return redirect(url_for('logbook')) + + elif action == 'update': + new_note = request.form.get('note') + start_str = request.form.get('start_time') + end_str = request.form.get('end_time') + + update_fields = {'note': new_note} + + try: + if start_str: + update_fields['start_time'] = datetime.strptime(start_str, '%Y-%m-%dT%H:%M') + if end_str: + update_fields['end_time'] = datetime.strptime(end_str, '%Y-%m-%dT%H:%M') + except ValueError: + flash('Invalid date format') + return redirect(url_for('log_entry_detail', entry_id=entry_id)) + + db.time_entries.update_one( + {'_id': ObjectId(entry_id), 'user_id': get_user_id()}, + {'$set': update_fields} + ) + flash('Entry updated') + return redirect(url_for('log_entry_detail', entry_id=entry_id)) # Fetch Entry with Activity info pipeline = [ diff --git a/templates/dashboard.html b/templates/dashboard.html index 13b7e9e..1f5a8b4 100644 --- a/templates/dashboard.html +++ b/templates/dashboard.html @@ -1,15 +1,20 @@ {% extends "layout.html" %} {% block content %} - {% if current_entry %} -
-

- Currently Tracking: {{ current_entry.activity_name }} +
+

+ Currently Tracking: {{ current_entry.activity_name if current_entry else '' }}

- {% if current_entry.note %} -

"{{ current_entry.note }}"

- {% endif %} +
+
+ {{ current_entry.subcategory if current_entry else '' }} +
+
+ +

+ "{{ current_entry.note if current_entry else '' }}" +

00:00:00
@@ -33,56 +38,58 @@
+
- + - fetch('/complete_task', { method: 'POST', body: formData }) - .then(r => r.json()) - .then(data => { - const label = checkbox.nextElementSibling; - if(checkbox.checked) { - label.style.textDecoration = "line-through"; - } else { - label.style.textDecoration = "none"; - } - }); - } - -

- {% endif %} -
+
{% for act in activities %} - -
- {{ act.name }} +
+
+ {{ act.name }} +
+ + + Edit +
{% endfor %} @@ -93,19 +100,89 @@
- + + + diff --git a/templates/edit_activity.html b/templates/edit_activity.html new file mode 100644 index 0000000..7b997d4 --- /dev/null +++ b/templates/edit_activity.html @@ -0,0 +1,83 @@ +{% extends "layout.html" %} +{% block content %} +
+

Edit Activity: {{ activity.name }}

+
+ + + + + + + +

+ Define specific contexts here (e.g. Boss, Team, Client A) +

+ +
+ + +
+ +
    + +
+ + + + +
+ + Cancel +
+
+
+ + +{% endblock %} diff --git a/templates/logbook.html b/templates/logbook.html index 0085146..a1305aa 100644 --- a/templates/logbook.html +++ b/templates/logbook.html @@ -10,7 +10,14 @@
-

{{ entry.activity.name }}

+

+ {{ entry.activity.name }} + {% if entry.subcategory %} + + {{ entry.subcategory }} + + {% endif %} +

{{ entry.start_time.strftime('%Y-%m-%d %H:%M') }} - {{ entry.end_time.strftime('%H:%M') }} diff --git a/templates/logbook_detail.html b/templates/logbook_detail.html index cb3dc0e..e12ba16 100644 --- a/templates/logbook_detail.html +++ b/templates/logbook_detail.html @@ -3,11 +3,16 @@
-

{{ entry.activity.name }}

+

+ {{ entry.activity.name }} + {% if entry.subcategory %} + + {{ entry.subcategory }} + + {% endif %} +

- {{ entry.start_time.strftime('%A, %d. %B %Y') }}
- {{ entry.start_time.strftime('%H:%M') }} - {% if entry.end_time %} - {{ entry.end_time.strftime('%H:%M') }} {% endif %} + {{ entry.start_time.strftime('%A, %d. %B %Y') }}

@@ -18,13 +23,36 @@
-

Session Notes

+

Edit Entry

- -
- + + +
+
+ + +
+
+ + + +
+
+ + + + +
+
+ +
+
+ + +
+
@@ -36,7 +64,7 @@ {% for task in tasks %}
  • - {% if task.status == 'completed' %}✅{% else %}⬜{% endif %} + {% if task.status == 'completed' %}Done{% else %}Open{% endif %}
    {{ task.name }} diff --git a/templates/task_detail.html b/templates/task_detail.html index 5204e8f..0802b8a 100644 --- a/templates/task_detail.html +++ b/templates/task_detail.html @@ -15,7 +15,7 @@
    {% else %} diff --git a/templates/tasks.html b/templates/tasks.html index 15b2c5e..b9fdd4b 100644 --- a/templates/tasks.html +++ b/templates/tasks.html @@ -55,7 +55,7 @@ {% endif %}