Split partner review board panels and add back button

This commit is contained in:
A R R R Associates
2026-08-14 14:56:53 +05:30
parent 74586d60ed
commit 9b3ea9a1c7
2 changed files with 184 additions and 110 deletions
@@ -19,6 +19,7 @@
</div> </div>
</div> </div>
<div class="flex flex-wrap gap-2"> <div class="flex flex-wrap gap-2">
<a href="/partner/reviews" class="rounded-2xl border border-slate-300 bg-white px-4 py-2 text-sm font-semibold text-slate-700 hover:bg-slate-50">← Back to Review Board</a>
<a href="{{ workspace.documents_href }}" class="rounded-2xl bg-emerald-600 px-4 py-2 text-sm font-semibold text-white">Final Documents / UDIN</a> <a href="{{ workspace.documents_href }}" class="rounded-2xl bg-emerald-600 px-4 py-2 text-sm font-semibold text-white">Final Documents / UDIN</a>
<a href="/partner/dashboard?tab=review" class="rounded-2xl border border-slate-300 px-4 py-2 text-sm font-semibold text-slate-700">Close Workspace</a> <a href="/partner/dashboard?tab=review" class="rounded-2xl border border-slate-300 px-4 py-2 text-sm font-semibold text-slate-700">Close Workspace</a>
</div> </div>
@@ -2,6 +2,136 @@
{% block content %} {% block content %}
{% include "modules/partners/templates/partners/_partner_tabs.html" %} {% include "modules/partners/templates/partners/_partner_tabs.html" %}
{% macro engagement_row(task, column, payload) %}
{% 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="/partner/reviews/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="/partner/reviews/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>
{% endmacro %}
{% macro panel(title, subtitle, ids, payload, tone) %}
<section class="overflow-hidden rounded-3xl border border-slate-200 bg-white shadow-soft">
<div class="flex flex-col gap-2 border-b border-slate-200 px-5 py-4 sm:flex-row sm:items-center sm:justify-between">
<div>
<h3 class="text-base font-semibold text-slate-900">{{ title }}</h3>
<p class="mt-1 text-xs text-slate-500">{{ subtitle }}</p>
</div>
{% if tone == 'review' %}
<span class="w-fit rounded-full bg-amber-100 px-3 py-1 text-xs font-semibold text-amber-700">{{ ids|length }} engagement{{ '' if ids|length == 1 else 's' }}</span>
{% elif tone == 'progress' %}
<span class="w-fit rounded-full bg-blue-100 px-3 py-1 text-xs font-semibold text-blue-700">{{ ids|length }} engagement{{ '' if ids|length == 1 else 's' }}</span>
{% else %}
<span class="w-fit rounded-full bg-emerald-100 px-3 py-1 text-xs font-semibold text-emerald-700">{{ ids|length }} engagement{{ '' if ids|length == 1 else 's' }}</span>
{% endif %}
</div>
<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 rendered = namespace(seen=[]) %}
{% for column in payload.columns %}
{% for task in column.tasks %}
{% if task.subscription_id and task.subscription_id in ids and task.subscription_id not in rendered.seen %}
{% set _ = rendered.seen.append(task.subscription_id) %}
{{ engagement_row(task, column, payload) }}
{% endif %}
{% endfor %}
{% endfor %}
{% if rendered.seen|length == 0 %}
<tr>
<td colspan="7" class="px-6 py-10 text-center text-sm text-slate-500">No engagements in this section.</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
</section>
{% endmacro %}
<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> <div>
@@ -14,7 +144,6 @@
</form> </form>
</div> </div>
{# Build engagement-level counts without changing the existing backend payload. #}
{% set metrics = namespace(pending_review=[], clarification_required=[], rework_sent=[], approved=[], completed=[]) %} {% set metrics = namespace(pending_review=[], clarification_required=[], rework_sent=[], approved=[], completed=[]) %}
{% for column in payload.columns %} {% for column in payload.columns %}
{% for task in column.tasks %} {% for task in column.tasks %}
@@ -62,117 +191,61 @@
</div> </div>
</div> </div>
<section class="overflow-hidden rounded-3xl border border-slate-200 bg-white shadow-soft"> {# Each engagement appears in exactly one panel: review first, then in progress, then completed. #}
<div class="overflow-x-auto"> {% set groups = namespace(review=[], progress=[], completed=[]) %}
<table class="min-w-full divide-y divide-slate-200"> {% for column in payload.columns %}
<thead class="bg-slate-50"> {% if column.code in ['pending_review', 'clarification_required', 'rework_sent'] %}
<tr> {% for task in column.tasks %}
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Client / Engagement</th> {% if task.subscription_id and task.subscription_id not in groups.review %}
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Status</th> {% set _ = groups.review.append(task.subscription_id) %}
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Task Progress</th> {% endif %}
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Review Items</th> {% endfor %}
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Assigned Team</th> {% endif %}
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Priority / Target</th> {% endfor %}
<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"> {% for column in payload.columns %}
<td class="px-4 py-4 text-sm"> {% if column.code == 'approved' %}
<a href="/partner/reviews/engagements/{{ task.subscription_id }}" class="font-semibold text-slate-900 hover:text-brand-700">{{ task.client_display }}</a> {% for task in column.tasks %}
<div class="mt-1 text-xs text-slate-500">{{ task.engagement_label }}</div> {% if task.subscription_id and task.subscription_id not in groups.review and task.subscription_id not in groups.progress %}
<div class="mt-1 text-[11px] text-slate-400">Engagement #{{ task.subscription_id }}</div> {% set _ = groups.progress.append(task.subscription_id) %}
</td> {% endif %}
<td class="px-4 py-4 text-sm"> {% endfor %}
{% if column.code == 'pending_review' %} {% endif %}
<span class="rounded-full bg-amber-100 px-2.5 py-1 text-xs font-semibold text-amber-700">Pending Review</span> {% endfor %}
{% 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="/partner/reviews/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 %} {% for column in payload.columns %}
<tr> {% if column.code == 'completed' %}
<td colspan="7" class="px-6 py-12 text-center text-sm text-slate-500">No engagement review items found.</td> {% for task in column.tasks %}
</tr> {% if task.subscription_id and task.subscription_id not in groups.review and task.subscription_id not in groups.progress and task.subscription_id not in groups.completed %}
{% endif %} {% set _ = groups.completed.append(task.subscription_id) %}
</tbody> {% endif %}
</table> {% endfor %}
</div> {% endif %}
</section> {% endfor %}
{{ panel(
'Review Required',
'Pending review, clarification-required and rework engagements are shown first.',
groups.review,
payload,
'review'
) }}
{{ panel(
'In Progress',
'Engagements currently moving with the team and not presently waiting in the review queue.',
groups.progress,
payload,
'progress'
) }}
{{ panel(
'Completed',
'Completed engagement rows remain available separately for review history and reference.',
groups.completed,
payload,
'completed'
) }}
<div class="rounded-2xl border border-slate-200 bg-slate-50 px-4 py-3 text-xs text-slate-500"> <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. Review remains task-level inside the engagement. This board only groups the existing task records into one engagement row for easier partner navigation.