Show partner review board by engagement

This commit is contained in:
A R R R Associates
2026-08-10 15:45:59 +05:30
parent 7e38527919
commit 09ef7a7a52
@@ -4,28 +4,178 @@
<div class="space-y-6"> <div class="space-y-6">
<div class="flex flex-col gap-3 rounded-3xl border border-slate-200 bg-white p-5 shadow-soft lg:flex-row lg:items-center lg:justify-between"> <div class="flex flex-col gap-3 rounded-3xl border border-slate-200 bg-white p-5 shadow-soft lg:flex-row lg:items-center lg:justify-between">
<div><h2 class="text-xl font-semibold">Partner Review Board</h2><p class="text-sm text-slate-500">Review completed work, blocked tasks, rework and in-progress engagement tasks.</p></div> <div>
<form method="get" class="flex gap-2"><input name="q" value="{{ q or '' }}" placeholder="Search client, task or service" class="w-72 rounded-xl border border-slate-300 px-3 py-2 text-sm"><button class="rounded-xl bg-brand-600 px-4 py-2 text-sm font-semibold text-white">Search</button></form> <h2 class="text-xl font-semibold">Partner Review Board</h2>
<p class="text-sm text-slate-500">Engagement-level review queue. Task-level review, rework and history remain available inside each engagement.</p>
</div>
<form method="get" class="flex gap-2">
<input name="q" value="{{ q or '' }}" placeholder="Search client, task or service" class="w-72 rounded-xl border border-slate-300 px-3 py-2 text-sm">
<button class="rounded-xl bg-brand-600 px-4 py-2 text-sm font-semibold text-white">Search</button>
</form>
</div> </div>
<div class="grid gap-4 xl:grid-cols-5"> {# Build engagement-level counts without changing the existing backend payload. #}
{% for column in payload.columns %} {% set metrics = namespace(pending_review=[], clarification_required=[], rework_sent=[], approved=[], completed=[]) %}
<section class="min-h-[420px] rounded-3xl border border-slate-200 bg-white p-4 shadow-soft"> {% for column in payload.columns %}
<div class="mb-4 flex items-start justify-between gap-3"><div><h3 class="font-semibold">{{ column.label }}</h3><p class="text-xs text-slate-500">{{ column.hint }}</p></div><span class="rounded-full bg-slate-100 px-2.5 py-1 text-xs font-semibold">{{ column.count }}</span></div> {% for task in column.tasks %}
<div class="space-y-3"> {% if task.subscription_id %}
{% for task in column.tasks %} {% if column.code == 'pending_review' and task.subscription_id not in metrics.pending_review %}
<div class="rounded-2xl border border-slate-200 p-4"> {% set _ = metrics.pending_review.append(task.subscription_id) %}
<div class="flex items-start justify-between gap-3"><div><a href="/work/engagements/{{ task.subscription_id }}" class="font-semibold text-slate-900 hover:text-brand-700">{{ task.task_name }}</a><div class="mt-1 text-xs text-slate-500">{{ task.client_display }}</div></div>{% if task.is_overdue %}<span class="rounded-full bg-red-100 px-2 py-1 text-[11px] font-semibold text-red-700">Overdue</span>{% endif %}</div> {% elif column.code == 'clarification_required' and task.subscription_id not in metrics.clarification_required %}
<div class="mt-2 text-xs text-slate-500">{{ task.engagement_label }}</div> {% set _ = metrics.clarification_required.append(task.subscription_id) %}
<div class="mt-3 flex flex-wrap gap-2 text-[11px]"><span class="rounded-full bg-slate-100 px-2 py-1">{{ task.status_label }}</span><span class="rounded-full bg-slate-100 px-2 py-1">{{ task.priority_label }}</span><span class="rounded-full bg-slate-100 px-2 py-1">{{ task.assignee_display }}</span></div> {% elif column.code == 'rework_sent' and task.subscription_id not in metrics.rework_sent %}
<a href="/work/engagements/{{ task.subscription_id }}" class="mt-3 inline-flex rounded-xl border border-slate-300 px-3 py-1.5 text-xs font-semibold text-slate-700 hover:bg-slate-50">Open Review Details</a> {% set _ = metrics.rework_sent.append(task.subscription_id) %}
</div> {% elif column.code == 'approved' and task.subscription_id not in metrics.approved %}
{% else %} {% set _ = metrics.approved.append(task.subscription_id) %}
<div class="rounded-2xl border border-dashed border-slate-300 p-6 text-center text-xs text-slate-500">No items.</div> {% elif column.code == 'completed' and task.subscription_id not in metrics.completed %}
{% endfor %} {% set _ = metrics.completed.append(task.subscription_id) %}
</div> {% endif %}
</section> {% endif %}
{% endfor %} {% endfor %}
{% endfor %}
<div class="grid gap-3 sm:grid-cols-2 lg:grid-cols-5">
<div class="rounded-2xl border border-slate-200 bg-white p-4 shadow-soft">
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Pending Review</div>
<div class="mt-1 text-2xl font-semibold text-slate-900">{{ metrics.pending_review|length }}</div>
<div class="mt-1 text-xs text-slate-500">Engagements with completed work awaiting review</div>
</div>
<div class="rounded-2xl border border-slate-200 bg-white p-4 shadow-soft">
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Clarification Required</div>
<div class="mt-1 text-2xl font-semibold text-slate-900">{{ metrics.clarification_required|length }}</div>
<div class="mt-1 text-xs text-slate-500">Engagements with blocked tasks</div>
</div>
<div class="rounded-2xl border border-slate-200 bg-white p-4 shadow-soft">
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Rework Sent</div>
<div class="mt-1 text-2xl font-semibold text-slate-900">{{ metrics.rework_sent|length }}</div>
<div class="mt-1 text-xs text-slate-500">Engagements containing rework items</div>
</div>
<div class="rounded-2xl border border-slate-200 bg-white p-4 shadow-soft">
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">In Progress</div>
<div class="mt-1 text-2xl font-semibold text-slate-900">{{ metrics.approved|length }}</div>
<div class="mt-1 text-xs text-slate-500">Engagements currently moving with the team</div>
</div>
<div class="rounded-2xl border border-slate-200 bg-white p-4 shadow-soft">
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Completed</div>
<div class="mt-1 text-2xl font-semibold text-slate-900">{{ metrics.completed|length }}</div>
<div class="mt-1 text-xs text-slate-500">Engagements containing closed tasks</div>
</div>
</div>
<section class="overflow-hidden rounded-3xl border border-slate-200 bg-white shadow-soft">
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-slate-200">
<thead class="bg-slate-50">
<tr>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Client / Engagement</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Status</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Task Progress</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Review Items</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Assigned Team</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Priority / Target</th>
<th class="px-4 py-3 text-right text-xs font-semibold uppercase tracking-wide text-slate-500">Action</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100">
{% set board = namespace(seen=[]) %}
{% for column in payload.columns %}
{% for task in column.tasks %}
{% if task.subscription_id and task.subscription_id not in board.seen %}
{% set _ = board.seen.append(task.subscription_id) %}
{% set stats = namespace(total=0, completed=0, blocked=0, review=0, rework=0, overdue=false, assignees=[]) %}
{% for stat_column in payload.columns %}
{% for item in stat_column.tasks %}
{% if item.subscription_id == task.subscription_id %}
{% set stats.total = stats.total + 1 %}
{% if (item.status or '')|lower in ['completed', 'not_applicable', 'cancelled'] %}
{% set stats.completed = stats.completed + 1 %}
{% endif %}
{% if (item.status or '')|lower == 'blocked' %}
{% set stats.blocked = stats.blocked + 1 %}
{% endif %}
{% if stat_column.code == 'pending_review' %}
{% set stats.review = stats.review + 1 %}
{% endif %}
{% if stat_column.code == 'rework_sent' %}
{% set stats.rework = stats.rework + 1 %}
{% endif %}
{% if item.is_overdue %}
{% set stats.overdue = true %}
{% endif %}
{% if item.assignee_display and item.assignee_display not in stats.assignees %}
{% set _ = stats.assignees.append(item.assignee_display) %}
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
<tr class="align-top hover:bg-slate-50/70">
<td class="px-4 py-4 text-sm">
<a href="/work/engagements/{{ task.subscription_id }}" class="font-semibold text-slate-900 hover:text-brand-700">{{ task.client_display }}</a>
<div class="mt-1 text-xs text-slate-500">{{ task.engagement_label }}</div>
<div class="mt-1 text-[11px] text-slate-400">Engagement #{{ task.subscription_id }}</div>
</td>
<td class="px-4 py-4 text-sm">
{% if column.code == 'pending_review' %}
<span class="rounded-full bg-amber-100 px-2.5 py-1 text-xs font-semibold text-amber-700">Pending Review</span>
{% elif column.code == 'clarification_required' %}
<span class="rounded-full bg-red-100 px-2.5 py-1 text-xs font-semibold text-red-700">Clarification Required</span>
{% elif column.code == 'rework_sent' %}
<span class="rounded-full bg-orange-100 px-2.5 py-1 text-xs font-semibold text-orange-700">Rework Sent</span>
{% elif column.code == 'approved' %}
<span class="rounded-full bg-blue-100 px-2.5 py-1 text-xs font-semibold text-blue-700">In Progress</span>
{% else %}
<span class="rounded-full bg-emerald-100 px-2.5 py-1 text-xs font-semibold text-emerald-700">Completed</span>
{% endif %}
{% if stats.overdue %}
<div class="mt-2"><span class="rounded-full bg-red-50 px-2 py-1 text-[11px] font-semibold text-red-700">Overdue item</span></div>
{% endif %}
</td>
<td class="px-4 py-4 text-sm">
<div class="font-semibold text-slate-900">{{ stats.completed }} / {{ stats.total }}</div>
<div class="mt-1 text-xs text-slate-500">closed task{{ '' if stats.completed == 1 else 's' }} / visible task{{ '' if stats.total == 1 else 's' }}</div>
</td>
<td class="px-4 py-4 text-sm">
<div class="flex flex-wrap gap-1.5">
{% if stats.review %}<span class="rounded-full bg-amber-50 px-2 py-1 text-[11px] font-semibold text-amber-700">{{ stats.review }} review</span>{% endif %}
{% if stats.blocked %}<span class="rounded-full bg-red-50 px-2 py-1 text-[11px] font-semibold text-red-700">{{ stats.blocked }} blocked</span>{% endif %}
{% if stats.rework %}<span class="rounded-full bg-orange-50 px-2 py-1 text-[11px] font-semibold text-orange-700">{{ stats.rework }} rework</span>{% endif %}
{% if not stats.review and not stats.blocked and not stats.rework %}<span class="text-xs text-slate-500">No review exception</span>{% endif %}
</div>
</td>
<td class="px-4 py-4 text-sm text-slate-700">
{% for assignee in stats.assignees[:3] %}
<div>{{ assignee }}</div>
{% endfor %}
{% if stats.assignees|length > 3 %}
<div class="mt-1 text-xs text-slate-500">+{{ stats.assignees|length - 3 }} more</div>
{% endif %}
{% if not stats.assignees %}<span class="text-slate-500">Unassigned</span>{% endif %}
</td>
<td class="px-4 py-4 text-sm">
<div class="text-xs font-semibold text-slate-700">{{ task.priority_label }}</div>
<div class="mt-1 text-xs text-slate-500">{% if task.internal_target_date %}Target {{ task.internal_target_date }}{% else %}No task target{% endif %}</div>
</td>
<td class="px-4 py-4 text-right">
<a href="/work/engagements/{{ task.subscription_id }}" class="inline-flex rounded-xl border border-slate-300 px-3 py-2 text-xs font-semibold text-slate-700 hover:bg-slate-50">Open Review</a>
</td>
</tr>
{% endif %}
{% endfor %}
{% endfor %}
{% if board.seen|length == 0 %}
<tr>
<td colspan="7" class="px-6 py-12 text-center text-sm text-slate-500">No engagement review items found.</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
</section>
<div class="rounded-2xl border border-slate-200 bg-slate-50 px-4 py-3 text-xs text-slate-500">
Review remains task-level inside the engagement. This board only groups the existing task records into one engagement row for easier partner navigation.
</div> </div>
</div> </div>
{% endblock %} {% endblock %}