HH/templates/projects/partials/task_row.html
ismail badb6a9ebf
All checks were successful
Build and Push Docker Image / build (push) Successful in 2m41s
feat: QI Projects — team-member task management + My Tasks + notifications
Fixed 3 gaps in the QI Projects module:

Gap 1 (critical): team members couldn't manage their own tasks — the toggle
checkbox/edit/delete were gated behind admin-only can_edit. Now:
- _can_manage_task() helper: admins OR the task assignee OR project team members
- task_toggle_status + htmx_task_toggle_status use the new helper
- task_row.html shows the toggle for assignees (task.assigned_to.user_id check)

Gap 2: no "My QI Tasks" view — added /projects/my-tasks/ showing tasks assigned
to the current user across all projects, with toggle links + stats. Sidebar link.

Gap 3: no notification on task assignment — added apps/projects/signals.py
(post_save on QIProjectTask → create_in_app_notification). apps.py ready() wired.

Tested (headed, 11 PASS / 1 FAIL):
- Cross-department team members (Contact Center + different dept) can VIEW the
  project AND toggle their assigned tasks (both PASS)
- My Tasks view loads for team members
- Excel export returns 500 (real bug, reported)
- Project close via edit form needs correct hospital UUID (test harness issue)

Also bundles accumulated in-progress work across complaints, observations,
organizations, templates, and other modules.

Harness: seed_e2e_project + get_e2e_project_state CLI + qi-projects-workflow.spec.ts
2026-06-16 23:55:58 +03:00

109 lines
4.4 KiB
HTML

{% load i18n %}
<tr id="task-{{ task.pk }}">
<!-- Toggle -->
<td class="text-center">
{% if can_edit or can_toggle or task.assigned_to.user_id == request.user.id %}
<form method="post"
action="{% url 'projects:htmx_task_toggle' project_pk=project.pk task_pk=task.pk %}"
hx-post="{% url 'projects:htmx_task_toggle' project_pk=project.pk task_pk=task.pk %}"
hx-target="#task-{{ task.pk }}"
hx-swap="outerHTML"
class="inline">
{% csrf_token %}
<button type="submit" class="p-1 bg-transparent border-none cursor-pointer">
{% if task.status == 'completed' %}
<i data-lucide="check-square" class="w-5 h-5 text-green-600"></i>
{% else %}
<i data-lucide="square" class="w-5 h-5 text-slate-300 hover:text-blue-500"></i>
{% endif %}
</button>
</form>
{% else %}
<span class="inline-block p-1">
{% if task.status == 'completed' %}
<i data-lucide="check-square" class="w-5 h-5 text-green-600"></i>
{% else %}
<i data-lucide="square" class="w-5 h-5 text-slate-300"></i>
{% endif %}
</span>
{% endif %}
</td>
<!-- Drag Handle -->
<td class="text-center">
<div class="text-slate-300 hover:text-slate-500 cursor-grab active:cursor-grabbing">
<i data-lucide="grip-vertical" class="w-4 h-4"></i>
</div>
</td>
<!-- Task Title & Description -->
<td>
<div class="flex flex-col">
<span class="text-sm font-semibold text-navy {% if task.status == 'completed' %}line-through text-slate-400{% endif %} cursor-pointer hover:text-blue-600"
hx-get="{% url 'projects:htmx_task_edit_form' project_pk=project.pk task_pk=task.pk %}"
hx-target="#taskModalContent"
onclick="openTaskModal('{% trans "Edit Task" %}')">
{{ task.title }}
</span>
{% if task.description %}
<span class="text-xs text-slate-500 mt-0.5 truncate max-w-md">{{ task.description }}</span>
{% endif %}
</div>
</td>
<!-- Assigned To -->
<td>
{% if task.assigned_to %}
<div class="flex items-center gap-1.5">
<div class="w-6 h-6 rounded-full bg-blue-100 text-blue-700 flex items-center justify-center text-xs font-bold">
{{ task.assigned_to.get_full_name|first }}
</div>
<span class="text-sm text-slate-700">{{ task.assigned_to.get_full_name }}</span>
</div>
{% else %}
<span class="text-sm text-slate-400"></span>
{% endif %}
</td>
<!-- Due Date -->
<td>
{% if task.due_date %}
<span class="text-sm {% if task.due_date < today and task.status != 'completed' %}text-red-600 font-semibold{% else %}text-slate-700{% endif %}">
{{ task.due_date|date:"M d, Y" }}
</span>
{% else %}
<span class="text-sm text-slate-400"></span>
{% endif %}
</td>
<!-- Status -->
<td>
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-[10px] font-bold uppercase task-status-{{ task.status }}">
{{ task.get_status_display }}
</span>
</td>
{% if can_edit %}
<!-- Actions -->
<td>
<div class="flex items-center gap-1">
<button hx-get="{% url 'projects:htmx_task_edit_form' project_pk=project.pk task_pk=task.pk %}"
hx-target="#taskModalContent"
onclick="openTaskModal('{% trans "Edit Task" %}')"
class="p-1.5 text-blue hover:bg-blue-50 rounded-lg transition"
title="{% trans 'Edit' %}">
<i data-lucide="pencil" class="w-4 h-4"></i>
</button>
<button hx-post="{% url 'projects:htmx_task_delete' project_pk=project.pk task_pk=task.pk %}"
hx-confirm="{% trans 'Are you sure you want to delete this task?' %}"
hx-target="closest tr"
hx-swap="delete"
class="p-1.5 text-red-600 hover:bg-red-50 rounded-lg transition"
title="{% trans 'Delete' %}">
<i data-lucide="trash-2" class="w-4 h-4"></i>
</button>
</div>
</td>
{% endif %}
</tr>