fix(absences): multi-line {# #} comments rendering as text + add Resources menu entry

CLAUDE.md gotcha #5: multi-line {# ... #} blocks render as literal text
in Django templates. Converted to {% comment %} blocks in edit.html
and list.html (also scanned log.html / log_confirm.html for safety).

Adds an 'Absences' entry to the Resources dropdown in base.html so the
feature is discoverable from the topbar.
This commit is contained in:
Konrad du Plessis 2026-05-14 21:13:53 +02:00
parent 37268801a1
commit ea94c46cb6
3 changed files with 41 additions and 30 deletions

View File

@ -70,9 +70,9 @@
<i class="fas fa-clock"></i><span>History</span>
</a>
{% if user.is_staff %}
<!-- Resources dropdown: Workers, Teams, Projects -->
<!-- Resources dropdown: Workers, Teams, Projects, Absences -->
<div class="dropdown">
<a href="#" class="topbar-nav__link dropdown-toggle {% if 'worker' in request.resolver_match.url_name|default:'' or 'team' in request.resolver_match.url_name|default:'' or 'project' in request.resolver_match.url_name|default:'' %}active{% endif %}"
<a href="#" class="topbar-nav__link dropdown-toggle {% if 'worker' in request.resolver_match.url_name|default:'' or 'team' in request.resolver_match.url_name|default:'' or 'project' in request.resolver_match.url_name|default:'' or 'absence' in request.resolver_match.url_name|default:'' %}active{% endif %}"
data-bs-toggle="dropdown" aria-expanded="false" role="button">
<i class="fas fa-hard-hat"></i><span>Resources</span>
</a>
@ -80,6 +80,7 @@
<li><a class="dropdown-item" href="{% url 'worker_list' %}"><i class="fas fa-hard-hat me-2" style="color: var(--accent);"></i>Workers</a></li>
<li><a class="dropdown-item" href="{% url 'team_list' %}"><i class="fas fa-users me-2" style="color: var(--accent);"></i>Teams</a></li>
<li><a class="dropdown-item" href="{% url 'project_list' %}"><i class="fas fa-project-diagram me-2" style="color: var(--accent);"></i>Projects</a></li>
<li><a class="dropdown-item" href="{% url 'absence_list' %}"><i class="fas fa-user-clock me-2" style="color: var(--accent);"></i>Absences</a></li>
</ul>
</div>
{% endif %}
@ -148,6 +149,9 @@
<a href="{% url 'project_list' %}" class="mobile-menu__link">
<i class="fas fa-project-diagram"></i><span>Projects</span>
</a>
<a href="{% url 'absence_list' %}" class="mobile-menu__link">
<i class="fas fa-user-clock"></i><span>Absences</span>
</a>
{% endif %}
<a href="{% url 'create_receipt' %}" class="mobile-menu__link {% if request.resolver_match.url_name == 'create_receipt' %}active{% endif %}">
<i class="fas fa-receipt"></i><span>Receipts</span>

View File

@ -3,20 +3,21 @@
{% block title %}Edit Absence | FoxFitt{% endblock %}
{% block content %}
{# === EDIT ABSENCE PAGE ===
Single form for editing one Absence row. The is_paid checkbox is
the magic field — toggling it on creates a Bonus PayrollAdjustment
at the worker's daily rate; toggling it off deletes the adjustment
(UNLESS it's already been paid, in which case the view surfaces an
error).
{% comment %}
=== EDIT ABSENCE PAGE ===
Single form for editing one Absence row. The is_paid checkbox is
the magic field — toggling it on creates a Bonus PayrollAdjustment
at the worker's daily rate; toggling it off deletes the adjustment
(UNLESS it's already been paid, in which case the view surfaces an
error).
Why two forms? HTML doesn't allow nested <form> tags. The delete
action needs its own form to POST to /absences/<id>/delete/. So
the delete form lives OUTSIDE the edit form (hidden), and the
Delete button inside the edit form uses the HTML5 `form="..."`
attribute to submit the delete form instead of its parent edit
form.
#}
Why two forms? HTML doesn't allow nested <form> tags. The delete
action needs its own form to POST to /absences/<id>/delete/. So
the delete form lives OUTSIDE the edit form (hidden), and the
Delete button inside the edit form uses the HTML5 `form="..."`
attribute to submit the delete form instead of its parent edit
form.
{% endcomment %}
<div class="container py-4">
<h1 class="page-title mb-3"><i class="fas fa-pen me-2"></i>Edit Absence</h1>
@ -24,8 +25,10 @@
{% for m in messages %}<div class="alert alert-{{ m.tags }}">{{ m }}</div>{% endfor %}
{% endif %}
{# Hidden sibling form so the Delete button can submit to its own URL.
Hidden via inline style — only the button inside the edit form is visible. #}
{% comment %}
Hidden sibling form so the Delete button can submit to its own URL.
Hidden via inline style — only the button inside the edit form is visible.
{% endcomment %}
<form method="post" action="{% url 'absence_delete' absence.id %}"
onsubmit="return confirm('Delete this absence?');"
id="absence-delete-form" style="display: none;">
@ -71,8 +74,10 @@
{% endif %}
<div class="d-flex justify-content-between mt-3">
{# `form="absence-delete-form"` makes this button submit the
hidden delete form rather than its enclosing edit form. #}
{% comment %}
`form="absence-delete-form"` makes this button submit the
hidden delete form rather than its enclosing edit form.
{% endcomment %}
<button type="submit" form="absence-delete-form" class="btn btn-outline-danger">
<i class="fas fa-trash me-1"></i>Delete
</button>

View File

@ -4,10 +4,11 @@
{% block title %}Absences | FoxFitt{% endblock %}
{% block content %}
{# === ABSENCES LIST PAGE ===
Filtered, paginated table of absences. Each row links to edit and
has an inline delete form. CSV export button only shows for admin.
#}
{% comment %}
=== ABSENCES LIST PAGE ===
Filtered, paginated table of absences. Each row links to edit and
has an inline delete form. CSV export button only shows for admin.
{% endcomment %}
<div class="container-fluid py-3">
{# === Page header — title + log/export action buttons === #}
@ -162,13 +163,14 @@
{% endif %}
</div>
{# === Reason badge colours ===
Reuses the existing semantic badge palette from custom.css so dark/
light theme switching works out of the box. Green-ish for "valid"
leave (sick/family/annual), neutral for unpaid/other, amber for IOD,
purple-ish (deduction) for the disciplinary reasons (suspension,
absconded).
#}
{% comment %}
=== Reason badge colours ===
Reuses the existing semantic badge palette from custom.css so dark/
light theme switching works out of the box. Green-ish for "valid"
leave (sick/family/annual), neutral for unpaid/other, amber for IOD,
purple-ish (deduction) for the disciplinary reasons (suspension,
absconded).
{% endcomment %}
<style>
.badge-absence-sick { background: var(--badge-bonus-bg); color: var(--badge-bonus-fg); }
.badge-absence-family { background: var(--badge-bonus-bg); color: var(--badge-bonus-fg); }