293 lines
22 KiB
HTML
293 lines
22 KiB
HTML
{% extends "ui/templates/base/layout.html" %}
|
|
{% block content %}
|
|
{% 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, 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.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.business_display }}</a>
|
|
{% if task.legal_client_display %}
|
|
<div class="mt-0.5 text-xs font-medium text-slate-600">{{ task.legal_client_display }}</div>
|
|
{% endif %}
|
|
{% if task.scope_context_display %}
|
|
<div class="mt-1 text-[11px] text-slate-400">{{ task.scope_context_display }}</div>
|
|
{% endif %}
|
|
<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">
|
|
<div class="font-semibold text-slate-800">{{ task.period_label_display }}</div>
|
|
{% if task.financial_year_display %}
|
|
<div class="mt-1 text-xs text-slate-500">FY {{ task.financial_year_display }}</div>
|
|
{% endif %}
|
|
{% if task.engagement_start_date or task.engagement_end_date %}
|
|
<div class="mt-1 text-[11px] text-slate-400">
|
|
{% if task.engagement_start_date %}{{ task.engagement_start_date }}{% endif %}
|
|
{% if task.engagement_start_date and task.engagement_end_date %} → {% endif %}
|
|
{% if task.engagement_end_date %}{{ task.engagement_end_date }}{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
{% if task.engagement_due_date %}
|
|
<div class="mt-2 text-xs font-semibold {% if task.due_status_code == 'overdue' %}text-red-700{% elif task.due_status_code in ['today','soon'] %}text-amber-700{% else %}text-slate-700{% endif %}">
|
|
Due {{ task.engagement_due_date }}
|
|
</div>
|
|
<div class="mt-0.5 text-[11px] {% if task.due_status_code == 'overdue' %}text-red-600{% elif task.due_status_code in ['today','soon'] %}text-amber-600{% else %}text-slate-400{% endif %}">{{ task.due_status_label }}</div>
|
|
{% else %}
|
|
<div class="mt-2 text-xs text-slate-400">No statutory due date</div>
|
|
{% endif %}
|
|
</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 %}
|
|
</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 %}Task 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, page_param, current_page, page_size, filter_query) %}
|
|
<section class="overflow-hidden rounded-3xl border border-slate-200 bg-white shadow-soft">
|
|
{% set total_items = ids|length %}
|
|
{% set total_pages = ((total_items + page_size - 1) // page_size) if total_items else 1 %}
|
|
{% set page = current_page if current_page > 0 else 1 %}
|
|
{% if page > total_pages %}{% set page = total_pages %}{% endif %}
|
|
{% set start_index = (page - 1) * page_size %}
|
|
{% set page_ids = ids[start_index:start_index + page_size] %}
|
|
|
|
<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>
|
|
{% if total_items %}<p class="mt-1 text-[11px] text-slate-400">Showing {{ start_index + 1 }}-{{ [start_index + page_ids|length, total_items]|min }} of {{ total_items }}</p>{% endif %}
|
|
</div>
|
|
{% if tone == 'review' %}
|
|
<span class="w-fit rounded-full bg-amber-100 px-3 py-1 text-xs font-semibold text-amber-700">{{ total_items }} engagement{{ '' if total_items == 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">{{ total_items }} engagement{{ '' if total_items == 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">{{ total_items }} engagement{{ '' if total_items == 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">Business / Client / Engagement</th>
|
|
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Period / Due</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 page_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 total_items == 0 %}<tr><td colspan="8" class="px-6 py-10 text-center text-sm text-slate-500">No engagements in this section.</td></tr>{% endif %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
{% if total_items > page_size %}
|
|
<div class="flex flex-col gap-3 border-t border-slate-200 px-5 py-4 text-xs text-slate-600 sm:flex-row sm:items-center sm:justify-between">
|
|
<div>Page {{ page }} of {{ total_pages }}</div>
|
|
<div class="flex items-center gap-2">
|
|
{% if page > 1 %}<a href="?{{ filter_query }}&{{ page_param }}={{ page - 1 }}" class="rounded-lg border border-slate-300 bg-white px-3 py-1.5 font-semibold text-slate-700 hover:bg-slate-50">Previous</a>{% else %}<span class="rounded-lg border border-slate-200 bg-slate-50 px-3 py-1.5 font-semibold text-slate-400">Previous</span>{% endif %}
|
|
<span class="font-semibold text-slate-700">{{ page }} / {{ total_pages }}</span>
|
|
{% if page < total_pages %}<a href="?{{ filter_query }}&{{ page_param }}={{ page + 1 }}" class="rounded-lg border border-slate-300 bg-white px-3 py-1.5 font-semibold text-slate-700 hover:bg-slate-50">Next</a>{% else %}<span class="rounded-lg border border-slate-200 bg-slate-50 px-3 py-1.5 font-semibold text-slate-400">Next</span>{% endif %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</section>
|
|
{% endmacro %}
|
|
|
|
<div class="space-y-6">
|
|
<div class="rounded-3xl border border-slate-200 bg-white p-5 shadow-soft">
|
|
<div class="flex flex-col gap-3 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">Engagement-level review queue with business identity, engagement period, statutory due date and independent pagination for each section.</p>
|
|
</div>
|
|
<div class="text-xs text-slate-500">Active FY context: <span class="font-semibold text-slate-700">{{ payload.active_financial_year or 'Not set' }}</span></div>
|
|
</div>
|
|
|
|
<form method="get" class="mt-5 grid gap-3 md:grid-cols-2 xl:grid-cols-4 2xl:grid-cols-8">
|
|
<div class="xl:col-span-2">
|
|
<label class="mb-1 block text-xs font-semibold text-slate-600">Search</label>
|
|
<input name="q" value="{{ q or '' }}" placeholder="Business, client, task or service" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
|
|
</div>
|
|
<div>
|
|
<label class="mb-1 block text-xs font-semibold text-slate-600">Financial Year</label>
|
|
<select name="fy" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
|
|
<option value="all" {% if payload.filters.financial_year == 'all' %}selected{% endif %}>All FYs</option>
|
|
{% for item in payload.filter_options.financial_years %}<option value="{{ item }}" {% if payload.filters.financial_year == item %}selected{% endif %}>FY {{ item }}</option>{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="mb-1 block text-xs font-semibold text-slate-600">Period</label>
|
|
<select name="period" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
|
|
<option value="">All periods</option>
|
|
{% for item in payload.filter_options.periods %}<option value="{{ item }}" {% if payload.filters.period == item %}selected{% endif %}>{{ item }}</option>{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="mb-1 block text-xs font-semibold text-slate-600">Service</label>
|
|
<select name="service_id" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
|
|
<option value="">All services</option>
|
|
{% for item in payload.filter_options.services %}<option value="{{ item.id }}" {% if payload.filters.service_id == item.id %}selected{% endif %}>{{ item.name }}</option>{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="mb-1 block text-xs font-semibold text-slate-600">Due Date</label>
|
|
<select name="due" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
|
|
<option value="">All due dates</option>
|
|
<option value="overdue" {% if payload.filters.due_bucket == 'overdue' %}selected{% endif %}>Overdue</option>
|
|
<option value="today" {% if payload.filters.due_bucket == 'today' %}selected{% endif %}>Due today</option>
|
|
<option value="next_7" {% if payload.filters.due_bucket == 'next_7' %}selected{% endif %}>Due in next 7 days</option>
|
|
<option value="next_15" {% if payload.filters.due_bucket == 'next_15' %}selected{% endif %}>Due in next 15 days</option>
|
|
<option value="this_month" {% if payload.filters.due_bucket == 'this_month' %}selected{% endif %}>Due this month</option>
|
|
<option value="none" {% if payload.filters.due_bucket == 'none' %}selected{% endif %}>No due date</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="mb-1 block text-xs font-semibold text-slate-600">Assigned Team</label>
|
|
<select name="assignee_id" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
|
|
<option value="">All team members</option>
|
|
{% for item in payload.filter_options.teams %}<option value="{{ item.id }}" {% if payload.filters.assignee_id == item.id %}selected{% endif %}>{{ item.name }}</option>{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="mb-1 block text-xs font-semibold text-slate-600">Priority</label>
|
|
<select name="priority" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
|
|
<option value="">All priorities</option>
|
|
{% for code, label in task_priorities %}<option value="{{ code }}" {% if payload.filters.priority == code %}selected{% endif %}>{{ label }}</option>{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="mb-1 block text-xs font-semibold text-slate-600">Rows / section</label>
|
|
<select name="page_size" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
|
|
{% for size in [10,25,50] %}<option value="{{ size }}" {% if page_size == size %}selected{% endif %}>{{ size }}</option>{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div class="flex items-end gap-2 xl:col-span-2">
|
|
<button class="rounded-xl bg-brand-600 px-4 py-2 text-sm font-semibold text-white">Apply Filters</button>
|
|
<a href="/partner/reviews" class="rounded-xl border border-slate-300 bg-white px-4 py-2 text-sm font-semibold text-slate-700 hover:bg-slate-50">Clear</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
{% set metrics = namespace(pending_review=[], clarification_required=[], rework_sent=[], approved=[], completed=[], overdue=[], due_soon=[]) %}
|
|
{% for column in payload.columns %}
|
|
{% for task in column.tasks %}
|
|
{% if task.subscription_id %}
|
|
{% if column.code == 'pending_review' and task.subscription_id not in metrics.pending_review %}{% set _ = metrics.pending_review.append(task.subscription_id) %}
|
|
{% elif column.code == 'clarification_required' and task.subscription_id not in metrics.clarification_required %}{% set _ = metrics.clarification_required.append(task.subscription_id) %}
|
|
{% elif column.code == 'rework_sent' and task.subscription_id not in metrics.rework_sent %}{% set _ = metrics.rework_sent.append(task.subscription_id) %}
|
|
{% elif column.code == 'approved' and task.subscription_id not in metrics.approved %}{% set _ = metrics.approved.append(task.subscription_id) %}
|
|
{% elif column.code == 'completed' and task.subscription_id not in metrics.completed %}{% set _ = metrics.completed.append(task.subscription_id) %}{% endif %}
|
|
{% if task.due_status_code == 'overdue' and task.subscription_id not in metrics.overdue %}{% set _ = metrics.overdue.append(task.subscription_id) %}{% endif %}
|
|
{% if task.due_status_code in ['today','soon'] and task.subscription_id not in metrics.due_soon %}{% set _ = metrics.due_soon.append(task.subscription_id) %}{% endif %}
|
|
{% endif %}
|
|
{% endfor %}
|
|
{% endfor %}
|
|
|
|
<div class="grid gap-3 sm:grid-cols-2 lg:grid-cols-7">
|
|
<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">Awaiting partner 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</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">Blocked for clarification</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</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">Rework outstanding</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">Moving with 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">Completed engagements</div></div>
|
|
<div class="rounded-2xl border border-red-200 bg-red-50 p-4"><div class="text-xs font-semibold uppercase tracking-wide text-red-600">Overdue</div><div class="mt-1 text-2xl font-semibold text-red-800">{{ metrics.overdue|length }}</div><div class="mt-1 text-xs text-red-600">Past engagement due date</div></div>
|
|
<div class="rounded-2xl border border-amber-200 bg-amber-50 p-4"><div class="text-xs font-semibold uppercase tracking-wide text-amber-700">Due ≤ 7 Days</div><div class="mt-1 text-2xl font-semibold text-amber-900">{{ metrics.due_soon|length }}</div><div class="mt-1 text-xs text-amber-700">Due today / next 7 days</div></div>
|
|
</div>
|
|
|
|
{# Exactly three board sections. Existing task-level states are preserved inside Review Required. #}
|
|
{% set groups = namespace(review=[], progress=[], completed=[]) %}
|
|
{% for column in payload.columns %}{% if column.code in ['pending_review', 'clarification_required', 'rework_sent'] %}{% for task in column.tasks %}{% if task.subscription_id and task.subscription_id not in groups.review %}{% set _ = groups.review.append(task.subscription_id) %}{% endif %}{% endfor %}{% endif %}{% endfor %}
|
|
{% for column in payload.columns %}{% if column.code == 'approved' %}{% for task in column.tasks %}{% if task.subscription_id and task.subscription_id not in groups.review and task.subscription_id not in groups.progress %}{% set _ = groups.progress.append(task.subscription_id) %}{% endif %}{% endfor %}{% endif %}{% endfor %}
|
|
{% for column in payload.columns %}{% if column.code == 'completed' %}{% for task in column.tasks %}{% 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 %}{% set _ = groups.completed.append(task.subscription_id) %}{% endif %}{% endfor %}{% endif %}{% endfor %}
|
|
|
|
{% set review_page = request.query_params.get('review_page', '1')|int %}
|
|
{% set progress_page = request.query_params.get('progress_page', '1')|int %}
|
|
{% set completed_page = request.query_params.get('completed_page', '1')|int %}
|
|
|
|
{{ panel('Review Required', 'Pending review, clarification-required and rework engagements are shown first.', groups.review, payload, 'review', 'review_page', review_page, page_size, filter_query) }}
|
|
{{ panel('In Progress', 'Engagements currently moving with the team and not presently waiting in the review queue.', groups.progress, payload, 'progress', 'progress_page', progress_page, page_size, filter_query) }}
|
|
{{ panel('Completed', 'Completed engagement rows remain available separately for review history and reference.', groups.completed, payload, 'completed', 'completed_page', completed_page, page_size, filter_query) }}
|
|
|
|
<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>
|
|
{% endblock %}
|