Add manager dashboard and wizards v1
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
{% extends "ui/templates/base/layout.html" %}
|
||||
{% block content %}
|
||||
<div class="space-y-6">
|
||||
<section class="rounded-3xl bg-gradient-to-r from-slate-900 via-brand-700 to-brand-600 p-6 text-white shadow-soft">
|
||||
<div class="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
|
||||
<div>
|
||||
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-brand-100">Manager Execution Control</p>
|
||||
<h1 class="mt-2 text-2xl font-bold">Manager Dashboard</h1>
|
||||
<p class="mt-2 max-w-3xl text-sm text-brand-100">Control team allocation, review queue, client pending items, documents and execution reports for the active branch/team.</p>
|
||||
<p class="mt-3 text-xs text-brand-100">FY: {{ overview.financial_year or 'All' }}{% if overview.branch %} · Branch: {{ overview.branch.name or overview.branch.code }}{% endif %}</p>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<a href="/manager/work" class="rounded-xl bg-white px-4 py-2 text-sm font-semibold text-brand-700 hover:bg-brand-50">Open Work Board</a>
|
||||
<a href="/employees/progress" class="rounded-xl border border-white/40 px-4 py-2 text-sm font-semibold text-white hover:bg-white/10">Progress</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% set tabs = [
|
||||
('overview','Overview'),
|
||||
('team-work','Team Work'),
|
||||
('review-queue','Review Queue'),
|
||||
('client-pending','Client Pending'),
|
||||
('documents','Documents'),
|
||||
('reports','Reports'),
|
||||
('wizards','Wizards')
|
||||
] %}
|
||||
|
||||
<section class="rounded-3xl border border-slate-200 bg-white p-3 shadow-soft">
|
||||
<div class="flex gap-2 overflow-x-auto" id="manager-tabs">
|
||||
{% for code, label in tabs %}
|
||||
<button type="button" data-tab="{{ code }}" class="manager-tab whitespace-nowrap rounded-2xl px-4 py-2 text-sm font-semibold transition {% if active_tab == code %}bg-brand-600 text-white{% else %}text-slate-600 hover:bg-slate-100{% endif %}">{{ label }}</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="manager-dashboard-panel">
|
||||
{% include 'modules/manager_dashboard/templates/manager_dashboard/partials/' ~ (active_tab|replace('-', '_')) ~ '.html' ignore missing %}
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
const tabs = document.querySelectorAll('.manager-tab');
|
||||
const panel = document.getElementById('manager-dashboard-panel');
|
||||
async function loadTab(tab) {
|
||||
tabs.forEach(btn => {
|
||||
const active = btn.dataset.tab === tab;
|
||||
btn.classList.toggle('bg-brand-600', active);
|
||||
btn.classList.toggle('text-white', active);
|
||||
btn.classList.toggle('text-slate-600', !active);
|
||||
btn.classList.toggle('hover:bg-slate-100', !active);
|
||||
});
|
||||
panel.innerHTML = '<div class="rounded-3xl border border-slate-200 bg-white p-8 text-center text-sm text-slate-500 shadow-soft">Loading...</div>';
|
||||
try {
|
||||
const res = await fetch('/manager/dashboard/tab/' + encodeURIComponent(tab), {headers: {'X-Requested-With':'fetch'}});
|
||||
if (!res.ok) throw new Error('HTTP ' + res.status);
|
||||
panel.innerHTML = await res.text();
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.set('tab', tab);
|
||||
window.history.replaceState({}, '', url);
|
||||
} catch (err) {
|
||||
panel.innerHTML = '<div class="rounded-3xl border border-red-200 bg-red-50 p-8 text-center text-sm font-semibold text-red-700 shadow-soft">Unable to load tab. Please refresh the page.</div>';
|
||||
}
|
||||
}
|
||||
tabs.forEach(btn => btn.addEventListener('click', () => loadTab(btn.dataset.tab)));
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,30 @@
|
||||
<div class="overflow-x-auto rounded-2xl border border-slate-200 bg-white shadow-soft">
|
||||
<table class="min-w-full divide-y divide-slate-200 text-sm">
|
||||
<thead class="bg-slate-50 text-xs font-semibold uppercase tracking-wide text-slate-500">
|
||||
<tr>
|
||||
<th class="px-4 py-3 text-left">Client</th>
|
||||
<th class="px-4 py-3 text-left">Task</th>
|
||||
<th class="px-4 py-3 text-left">Service / Period</th>
|
||||
<th class="px-4 py-3 text-left">Due</th>
|
||||
<th class="px-4 py-3 text-left">Assigned</th>
|
||||
<th class="px-4 py-3 text-left">Status</th>
|
||||
<th class="px-4 py-3 text-right">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-100">
|
||||
{% for row in rows %}
|
||||
<tr class="hover:bg-slate-50">
|
||||
<td class="px-4 py-3"><div class="font-semibold text-slate-900">{{ row.client_name }}</div><div class="text-xs text-slate-500">{{ row.client_code or '-' }}</div></td>
|
||||
<td class="px-4 py-3"><div class="font-semibold text-slate-900">{{ row.task_name }}</div><div class="text-xs text-slate-500">{{ row.comment_count }} timeline item(s)</div></td>
|
||||
<td class="px-4 py-3"><div>{{ row.service_name }}</div><div class="text-xs text-slate-500">{{ row.period }}</div></td>
|
||||
<td class="px-4 py-3"><span class="{% if row.is_overdue %}text-red-700 font-semibold{% elif row.is_due_today %}text-amber-700 font-semibold{% endif %}">{{ row.due_date or '-' }}</span></td>
|
||||
<td class="px-4 py-3">{{ row.assigned_to }}</td>
|
||||
<td class="px-4 py-3"><span class="rounded-full bg-slate-100 px-2.5 py-1 text-xs font-semibold text-slate-700">{{ row.status_label }}</span></td>
|
||||
<td class="px-4 py-3 text-right"><a href="{{ row.href }}" class="rounded-lg border border-slate-300 px-3 py-1.5 text-xs font-semibold text-slate-700 hover:bg-slate-50">Open</a></td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="7" class="px-4 py-8 text-center text-sm text-slate-500">No records found for this view.</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -0,0 +1,4 @@
|
||||
<div class="space-y-6">
|
||||
<div class="af-card"><div class="mb-4 flex items-center justify-between"><div><h3 class="text-lg font-semibold text-slate-900">Client Pending / Blocked Work</h3><p class="text-sm text-slate-500">Tasks delayed due to client documents, data or clarifications.</p></div><a href="/alerts" class="af-btn af-btn-primary">Alerts</a></div>{% set rows = client_pending %}{% include 'modules/manager_dashboard/templates/manager_dashboard/partials/_task_table.html' %}</div>
|
||||
<div class="af-card"><h3 class="mb-4 text-lg font-semibold text-slate-900">Client-wise Pending View</h3><div class="overflow-x-auto"><table class="min-w-full text-sm"><thead class="bg-slate-50 text-xs uppercase text-slate-500"><tr><th class="px-4 py-3 text-left">Client</th><th class="px-4 py-3 text-right">Open</th><th class="px-4 py-3 text-right">Client Pending</th><th class="px-4 py-3 text-right">Overdue</th><th class="px-4 py-3 text-right">Action</th></tr></thead><tbody>{% for c in clients if c.client_pending or c.overdue %}<tr class="border-t"><td class="px-4 py-3 font-semibold">{{ c.client_name }}</td><td class="px-4 py-3 text-right">{{ c.open }}</td><td class="px-4 py-3 text-right">{{ c.client_pending }}</td><td class="px-4 py-3 text-right">{{ c.overdue }}</td><td class="px-4 py-3 text-right"><a href="{{ c.href }}" class="text-brand-700 font-semibold">Open</a></td></tr>{% else %}<tr><td colspan="5" class="px-4 py-8 text-center text-slate-500">No client pending clients found.</td></tr>{% endfor %}</tbody></table></div></div>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
<div class="space-y-6">
|
||||
<div class="af-card"><div class="mb-4 flex items-center justify-between"><div><h3 class="text-lg font-semibold text-slate-900">Document Checklist Control</h3><p class="text-sm text-slate-500">Document-related blocked tasks and timeline shortcuts.</p></div><a href="/documents" class="af-btn af-btn-primary">Open Documents</a></div>{% set rows = documents_pending %}{% include 'modules/manager_dashboard/templates/manager_dashboard/partials/_task_table.html' %}</div>
|
||||
</div>
|
||||
@@ -0,0 +1,25 @@
|
||||
<div class="space-y-6">
|
||||
<section class="grid gap-4 md:grid-cols-2 xl:grid-cols-6">
|
||||
<a href="/manager/dashboard?tab=team-work" class="af-metric-card"><div class="text-xs font-semibold uppercase text-slate-500">Open Tasks</div><div class="mt-2 text-3xl font-semibold text-slate-900">{{ overview.open_task_count }}</div><div class="mt-1 text-xs text-slate-500">Visible team work</div></a>
|
||||
<a href="/manager/dashboard?tab=team-work" class="af-metric-card border-orange-200 bg-orange-50"><div class="text-xs font-semibold uppercase text-orange-700">Unassigned</div><div class="mt-2 text-3xl font-semibold text-orange-700">{{ overview.unassigned_count }}</div><div class="mt-1 text-xs text-orange-700">Allocate first</div></a>
|
||||
<a href="/manager/dashboard?tab=team-work" class="af-metric-card border-blue-200 bg-blue-50"><div class="text-xs font-semibold uppercase text-blue-700">In Progress</div><div class="mt-2 text-3xl font-semibold text-blue-700">{{ overview.in_progress_count }}</div><div class="mt-1 text-xs text-blue-700">Being worked</div></a>
|
||||
<a href="/manager/dashboard?tab=client-pending" class="af-metric-card border-amber-200 bg-amber-50"><div class="text-xs font-semibold uppercase text-amber-700">Client Pending</div><div class="mt-2 text-3xl font-semibold text-amber-700">{{ overview.client_pending_count }}</div><div class="mt-1 text-xs text-amber-700">Needs follow-up</div></a>
|
||||
<a href="/manager/dashboard?tab=review-queue" class="af-metric-card border-emerald-200 bg-emerald-50"><div class="text-xs font-semibold uppercase text-emerald-700">Review Queue</div><div class="mt-2 text-3xl font-semibold text-emerald-700">{{ overview.review_pending_count }}</div><div class="mt-1 text-xs text-emerald-700">Review-ready</div></a>
|
||||
<a href="/manager/dashboard?tab=team-work" class="af-metric-card border-red-200 bg-red-50"><div class="text-xs font-semibold uppercase text-red-700">Overdue</div><div class="mt-2 text-3xl font-semibold text-red-700">{{ overview.overdue_count }}</div><div class="mt-1 text-xs text-red-700">Escalate</div></a>
|
||||
</section>
|
||||
|
||||
<section class="grid gap-6 xl:grid-cols-[minmax(0,1fr)_360px]">
|
||||
<div class="af-card">
|
||||
<div class="mb-4 flex items-center justify-between gap-3">
|
||||
<div><h3 class="text-lg font-semibold text-slate-900">Attention Required</h3><p class="text-sm text-slate-500">Unassigned, overdue and client-pending work.</p></div>
|
||||
<a href="/manager/work" class="af-btn af-btn-primary">Open Work Board</a>
|
||||
</div>
|
||||
{% set rows = (unassigned + overdue + client_pending)[:12] %}
|
||||
{% include 'modules/manager_dashboard/templates/manager_dashboard/partials/_task_table.html' %}
|
||||
</div>
|
||||
<div class="space-y-4">
|
||||
<div class="af-card"><h3 class="font-semibold text-slate-900">Team Snapshot</h3><div class="mt-4 grid grid-cols-2 gap-3 text-sm"><div class="rounded-2xl bg-slate-50 p-3"><div class="text-xs text-slate-500">Staff visible</div><div class="text-2xl font-semibold">{{ overview.staff_count }}</div></div><div class="rounded-2xl bg-slate-50 p-3"><div class="text-xs text-slate-500">Clients visible</div><div class="text-2xl font-semibold">{{ overview.client_count }}</div></div><div class="rounded-2xl bg-slate-50 p-3"><div class="text-xs text-slate-500">Due today</div><div class="text-2xl font-semibold">{{ overview.due_today_count }}</div></div><div class="rounded-2xl bg-slate-50 p-3"><div class="text-xs text-slate-500">Due week</div><div class="text-2xl font-semibold">{{ overview.due_week_count }}</div></div></div></div>
|
||||
<div class="af-card"><h3 class="font-semibold text-slate-900">Quick Actions</h3><div class="mt-4 grid gap-2"><a href="/manager/work" class="rounded-xl border border-slate-200 px-3 py-2 text-sm font-semibold hover:bg-slate-50">Task Assignment Wizard</a><a href="/manager/dashboard?tab=review-queue" class="rounded-xl border border-slate-200 px-3 py-2 text-sm font-semibold hover:bg-slate-50">Review Wizard</a><a href="/manager/dashboard?tab=client-pending" class="rounded-xl border border-slate-200 px-3 py-2 text-sm font-semibold hover:bg-slate-50">Client Query Wizard</a><a href="/documents" class="rounded-xl border border-slate-200 px-3 py-2 text-sm font-semibold hover:bg-slate-50">Document Checklist</a></div></div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
@@ -0,0 +1,8 @@
|
||||
<div class="space-y-6">
|
||||
<div><h3 class="text-lg font-semibold text-slate-900">Manager Reports</h3><p class="text-sm text-slate-500">Action reports for team execution, review, client pending and documents.</p></div>
|
||||
<div class="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
|
||||
{% for card in reports %}
|
||||
<a href="{{ card.href }}" class="rounded-3xl border border-slate-200 bg-white p-5 shadow-soft hover:border-brand-200 hover:bg-brand-50/30"><div class="text-xs font-semibold uppercase tracking-wide text-brand-600">{{ card.group }}</div><h4 class="mt-2 font-semibold text-slate-900">{{ card.title }}</h4><p class="mt-2 text-sm text-slate-500">{{ card.desc }}</p><div class="mt-4 text-sm font-semibold text-brand-700">View Report →</div></a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
<div class="space-y-6">
|
||||
<div class="af-card"><div class="mb-4 flex items-center justify-between"><div><h3 class="text-lg font-semibold text-slate-900">Manager Review Queue</h3><p class="text-sm text-slate-500">Completed or review-ready work waiting for manager action.</p></div><a href="/employees/progress" class="af-btn af-btn-primary">Progress</a></div>{% set rows = review_queue %}{% include 'modules/manager_dashboard/templates/manager_dashboard/partials/_task_table.html' %}</div>
|
||||
</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
<div class="space-y-6">
|
||||
<section class="grid gap-4 md:grid-cols-2 xl:grid-cols-5">
|
||||
<div class="af-metric-card"><div class="text-xs font-semibold uppercase text-slate-500">Total Visible</div><div class="mt-2 text-3xl font-semibold">{{ overview.total_tasks }}</div></div>
|
||||
<div class="af-metric-card"><div class="text-xs font-semibold uppercase text-orange-700">Unassigned</div><div class="mt-2 text-3xl font-semibold text-orange-700">{{ overview.unassigned_count }}</div></div>
|
||||
<div class="af-metric-card"><div class="text-xs font-semibold uppercase text-blue-700">In Progress</div><div class="mt-2 text-3xl font-semibold text-blue-700">{{ overview.in_progress_count }}</div></div>
|
||||
<div class="af-metric-card"><div class="text-xs font-semibold uppercase text-red-700">Overdue</div><div class="mt-2 text-3xl font-semibold text-red-700">{{ overview.overdue_count }}</div></div>
|
||||
<div class="af-metric-card"><div class="text-xs font-semibold uppercase text-amber-700">Due Today</div><div class="mt-2 text-3xl font-semibold text-amber-700">{{ overview.due_today_count }}</div></div>
|
||||
</section>
|
||||
<div class="af-card"><div class="mb-4 flex items-center justify-between"><div><h3 class="text-lg font-semibold text-slate-900">Team Work Board Summary</h3><p class="text-sm text-slate-500">Top 100 visible tasks. Use detailed board for assignment changes.</p></div><a href="/manager/work" class="af-btn af-btn-primary">Detailed Board</a></div>{% set rows = team_work %}{% include 'modules/manager_dashboard/templates/manager_dashboard/partials/_task_table.html' %}</div>
|
||||
</div>
|
||||
@@ -0,0 +1,8 @@
|
||||
<div class="space-y-6">
|
||||
<div><h3 class="text-lg font-semibold text-slate-900">Manager Wizards</h3><p class="text-sm text-slate-500">Guided shortcuts for assignment, review, client query, document checklist and closure.</p></div>
|
||||
<div class="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
|
||||
{% for card in wizards %}
|
||||
<a href="{{ card.href }}" class="rounded-3xl border border-slate-200 bg-white p-5 shadow-soft hover:border-brand-200 hover:bg-brand-50/30"><h4 class="font-semibold text-slate-900">{{ card.title }}</h4><p class="mt-2 text-sm text-slate-500">{{ card.desc }}</p><div class="mt-4 text-sm font-semibold text-brand-700">Open →</div></a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user