ux(colors): unify badge colours across all payroll tabs

Replaces the 4-branch Bootstrap-state conditional on the Pending
and History tabs with the semantic .badge-type-{{ adj.type|type_slug }}
palette that the Adjustments tab has been using. Now "Loan" badges
are the same colour in every tab instead of Pending=yellow /
Adjustments=amber.

Also recolours the Pending-tab "Loan" worker flag to the same amber
(.loan-flag-badge class). "Overdue" flag stays red - it's an urgency
signal, not a type signal, and we deliberately keep transactional
state colours (Bootstrap bg-success/bg-warning/bg-danger) separate
from the type palette so a green badge can only mean "Bonus" and
never ambiguously "Paid".

Threads 'additive_types' (list(ADDITIVE_TYPES)) into the base
payroll_dashboard context so the +/- sign logic works on Pending
and History too (was previously only set in the Adjustments-tab
branch).

Tests: 69/69.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Konrad du Plessis 2026-04-24 10:09:10 +02:00
parent f70342f825
commit e932b3c3a7
3 changed files with 20 additions and 8 deletions

View File

@ -342,7 +342,7 @@
<span class="badge bg-danger" style="font-size: 0.6rem;" title="Has unpaid work from a completed pay period (since {{ wd.earliest_unpaid|date:'d M Y' }})">Overdue</span>
{% endif %}
{% if wd.has_loan %}
<span class="badge bg-warning" style="font-size: 0.6rem;" title="Has active loan or advance">Loan</span>
<span class="badge loan-flag-badge" style="font-size: 0.6rem;" title="Has active loan or advance">Loan</span>
{% endif %}
</div>
{% endif %}
@ -353,11 +353,9 @@
<td class="align-middle d-none d-lg-table-cell">
{# Show each pending adjustment as a badge #}
{% for adj in wd.adjustments %}
{# Badge colour logic: #}
{# GREEN = earned money (Bonus, Overtime) or debt recovery (Loan/Advance Repayment) #}
{# YELLOW = loan-related outflow (New Loan, Advance Payment) — matches the Loan tag #}
{# RED = deductions (Deduction) #}
<span class="badge {% if adj.type == 'Bonus' or adj.type == 'Overtime' or adj.type == 'Loan Repayment' or adj.type == 'Advance Repayment' %}bg-success{% elif adj.type == 'New Loan' or adj.type == 'Advance Payment' %}bg-warning{% else %}bg-danger{% endif %} mb-1 me-1 adjustment-badge"
{# Type badge uses the semantic palette: colour = type (Bonus, Loan, etc.). #}
{# Sign + / - reflects additive-vs-deductive (orthogonal to the colour). #}
<span class="badge badge-type-{{ adj.type|type_slug }} mb-1 me-1 adjustment-badge"
style="cursor: pointer;"
data-adj-id="{{ adj.id }}"
data-adj-type="{{ adj.type }}"
@ -366,7 +364,7 @@
data-adj-description="{{ adj.description }}"
data-adj-project="{{ adj.project_id|default:'' }}"
data-adj-worker="{{ adj.worker.name }}">
{% if adj.type == 'Bonus' or adj.type == 'Overtime' or adj.type == 'New Loan' or adj.type == 'Advance Payment' %}+{% else %}-{% endif %}R{{ adj.amount|floatformat:2 }}
{% if adj.type in additive_types %}+{% else %}-{% endif %}R{{ adj.amount|floatformat:2 }}
{{ adj.get_type_display }}
{% if adj.project %}({{ adj.project.name }}){% endif %}
</span>
@ -450,7 +448,7 @@
</td>
<td class="align-middle d-none d-lg-table-cell">
{% for adj in record.adjustments.all %}
<span class="badge {% if adj.type == 'Bonus' or adj.type == 'Overtime' or adj.type == 'Loan Repayment' or adj.type == 'Advance Repayment' %}bg-success{% elif adj.type == 'New Loan' or adj.type == 'Advance Payment' %}bg-warning{% else %}bg-danger{% endif %} me-1">
<span class="badge badge-type-{{ adj.type|type_slug }} me-1">
{{ adj.get_type_display }}: R {{ adj.amount|floatformat:2 }}
</span>
{% empty %}

View File

@ -3080,6 +3080,10 @@ def payroll_dashboard(request):
'all_teams': all_teams,
'team_workers_map_json': team_workers_map,
'adjustment_types': PayrollAdjustment.TYPE_CHOICES,
# List of type labels that ADD to a worker's pay (Bonus, Overtime,
# New Loan, Advance Payment). Used by the Pending and History tabs'
# adjustment badges to show a + or - sign next to the amount.
'additive_types': list(ADDITIVE_TYPES),
'active_projects': active_projects,
'loans': loans,
'loan_filter': loan_filter,

View File

@ -1940,6 +1940,16 @@ body, .card, .modal-content, .form-control, .form-select,
.badge-type-advance-payment { background: var(--badge-advance-bg); color: var(--badge-advance-fg); }
.badge-type-advance-repayment { background: var(--badge-advance-rep-bg); color: var(--badge-advance-rep-fg); }
/* --- Status flags that borrow a type's colour for semantic consistency.
"Has an active loan or advance" -> Loan-type amber/yellow, so the
worker flag on the Pending tab visually matches the Adjustments
type badge for Loan. Keeps the Loan colour family unified across
the app regardless of which tab you're looking at. --- */
.loan-flag-badge {
background: var(--badge-loan-bg);
color: var(--badge-loan-fg);
}
/* --- Sticky filter bar (keeps filters visible as the table scrolls) --- */
.adjustments-filter-bar {
position: sticky;