Upgrade client dashboard to v2 grouped ajax portal
This commit is contained in:
@@ -6,13 +6,14 @@
|
||||
<div class="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
|
||||
<div>
|
||||
<p class="text-xs font-semibold uppercase tracking-[0.22em] text-brand-100">Client Portal</p>
|
||||
<h2 class="mt-2 text-2xl font-semibold">My Compliance & Firm Communication</h2>
|
||||
<p class="mt-2 max-w-3xl text-sm text-brand-100">Track pending actions, service status, documents, messages, bills and firm updates from one place.</p>
|
||||
<h2 class="mt-2 text-2xl font-semibold">My Compliance Workspace</h2>
|
||||
<p class="mt-2 max-w-3xl text-sm text-brand-100">View pending actions, service progress, documents, invoices, payments and firm messages from one clean dashboard.</p>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
{% if client_row %}
|
||||
<a href="/client/profile" class="rounded-xl bg-white px-4 py-2 text-sm font-semibold text-brand-700 hover:bg-brand-50">Update My Profile</a>
|
||||
<a href="/client/documents" class="rounded-xl border border-white/30 px-4 py-2 text-sm font-semibold text-white hover:bg-white/10">Upload Documents</a>
|
||||
<a href="/client/documents" class="rounded-xl bg-white px-4 py-2 text-sm font-semibold text-brand-700 hover:bg-brand-50">Upload Documents</a>
|
||||
<a href="/client/messages" class="rounded-xl border border-white/30 px-4 py-2 text-sm font-semibold text-white hover:bg-white/10">Messages</a>
|
||||
<a href="/client/profile" class="rounded-xl border border-white/30 px-4 py-2 text-sm font-semibold text-white hover:bg-white/10">Profile</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -25,11 +26,9 @@
|
||||
{% else %}
|
||||
{% set client_tabs = [
|
||||
('overview','Overview'),
|
||||
('pending','Pending From Me'),
|
||||
('services','Services'),
|
||||
('documents','Documents'),
|
||||
('billing','Invoices & Payments'),
|
||||
('messages','Messages'),
|
||||
('action-centre','Action Centre'),
|
||||
('services-documents','Services & Documents'),
|
||||
('billing-messages','Billing & Messages'),
|
||||
('reports','Reports')
|
||||
] %}
|
||||
|
||||
@@ -76,6 +75,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
window.loadClientDashboardTab = loadTab;
|
||||
buttons.forEach((btn) => btn.addEventListener('click', () => loadTab(btn.dataset.tab || 'overview')));
|
||||
})();
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<div class="space-y-6">
|
||||
<div class="grid gap-4 md:grid-cols-3">
|
||||
<button type="button" onclick="window.loadClientDashboardTab && window.loadClientDashboardTab('pending')" class="af-metric-card border-amber-200 bg-amber-50 text-left hover:border-amber-300"><div class="text-xs font-semibold uppercase text-amber-700">Pending From Me</div><div class="mt-2 text-3xl font-semibold text-amber-700">{{ pending_from_client or 0 }}</div><div class="mt-1 text-xs text-amber-700">Documents / replies required</div></button>
|
||||
<button type="button" onclick="window.loadClientDashboardTab && window.loadClientDashboardTab('messages')" class="af-metric-card text-left hover:border-brand-200"><div class="text-xs font-semibold uppercase text-slate-500">Firm Messages</div><div class="mt-2 text-3xl font-semibold text-slate-900">{{ client_visible_comments|length if client_visible_comments else 0 }}</div><div class="mt-1 text-xs text-slate-500">Recent messages</div></button>
|
||||
<a href="/client/documents" class="af-metric-card hover:border-brand-200"><div class="text-xs font-semibold uppercase text-slate-500">Documents</div><div class="mt-2 text-3xl font-semibold text-slate-900">{{ recent_documents|length if recent_documents else 0 }}</div><div class="mt-1 text-xs text-slate-500">Recent uploads / shared files</div></a>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-6 xl:grid-cols-2">
|
||||
<div>{% include "modules/clients/templates/clients/portal_partials/pending.html" %}</div>
|
||||
<div>{% include "modules/clients/templates/clients/portal_partials/messages.html" %}</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,11 @@
|
||||
<div class="space-y-6">
|
||||
<section class="grid gap-4 md:grid-cols-3">
|
||||
<button type="button" onclick="window.loadClientDashboardTab && window.loadClientDashboardTab('billing')" class="af-metric-card border-amber-200 bg-amber-50 text-left hover:border-amber-300"><div class="text-xs font-semibold uppercase text-amber-700">Outstanding</div><div class="mt-2 text-2xl font-semibold text-amber-700">₹ {{ '%.2f'|format(billing_outstanding_amount or 0) }}</div><div class="mt-1 text-xs text-amber-700">{{ billing_open_count or 0 }} open bill(s)</div></button>
|
||||
<a href="/client/billing" class="af-metric-card hover:border-brand-200"><div class="text-xs font-semibold uppercase text-slate-500">Total Bills</div><div class="mt-2 text-3xl font-semibold text-slate-900">{{ billing_total_count or 0 }}</div><div class="mt-1 text-xs text-slate-500">Invoices & receipts</div></a>
|
||||
<button type="button" onclick="window.loadClientDashboardTab && window.loadClientDashboardTab('messages')" class="af-metric-card text-left hover:border-brand-200"><div class="text-xs font-semibold uppercase text-slate-500">Messages</div><div class="mt-2 text-3xl font-semibold text-slate-900">{{ client_visible_comments|length if client_visible_comments else 0 }}</div><div class="mt-1 text-xs text-slate-500">Firm communication</div></button>
|
||||
</section>
|
||||
<div class="grid gap-6 xl:grid-cols-2">
|
||||
<div>{% include "modules/clients/templates/clients/portal_partials/billing.html" %}</div>
|
||||
<div>{% include "modules/clients/templates/clients/portal_partials/messages.html" %}</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,16 +1,19 @@
|
||||
<div class="space-y-6">
|
||||
<section class="grid gap-4 md:grid-cols-2 xl:grid-cols-5">
|
||||
<a href="/client/compliance" class="af-metric-card hover:border-brand-200"><div class="text-xs font-semibold uppercase text-slate-500">Active Services</div><div class="mt-2 text-3xl font-semibold text-slate-900">{{ total_engagements or 0 }}</div><div class="mt-1 text-xs text-slate-500">Services / filings</div></a>
|
||||
<button type="button" data-tab="pending" class="client-dashboard-tab af-metric-card border-amber-200 bg-amber-50 text-left hover:border-amber-300"><div class="text-xs font-semibold uppercase text-amber-700">Pending From Me</div><div class="mt-2 text-3xl font-semibold text-amber-700">{{ pending_from_client or 0 }}</div><div class="mt-1 text-xs text-amber-700">Action required</div></button>
|
||||
<a href="/client/compliance" class="af-metric-card hover:border-brand-200"><div class="text-xs font-semibold uppercase text-slate-500">With Firm</div><div class="mt-2 text-3xl font-semibold text-brand-700">{{ with_firm or 0 }}</div><div class="mt-1 text-xs text-slate-500">Being handled</div></a>
|
||||
<a href="/client/documents" class="af-metric-card hover:border-brand-200"><div class="text-xs font-semibold uppercase text-slate-500">Recent Documents</div><div class="mt-2 text-3xl font-semibold text-slate-900">{{ recent_documents|length if recent_documents else 0 }}</div><div class="mt-1 text-xs text-slate-500">Latest documents</div></a>
|
||||
<a href="/client/billing" class="af-metric-card border-amber-200 bg-amber-50 hover:border-amber-300"><div class="text-xs font-semibold uppercase text-amber-700">Outstanding Bills</div><div class="mt-2 text-2xl font-semibold text-amber-700">₹ {{ '%.2f'|format(billing_outstanding_amount or 0) }}</div><div class="mt-1 text-xs text-amber-700">{{ billing_open_count or 0 }} open bill(s)</div></a>
|
||||
<a href="/client/compliance" class="af-metric-card hover:border-brand-200"><div class="text-xs font-semibold uppercase text-slate-500">Active Services</div><div class="mt-2 text-3xl font-semibold text-slate-900">{{ total_engagements or 0 }}</div><div class="mt-1 text-xs text-slate-500">Services handled by firm</div></a>
|
||||
<button type="button" onclick="window.loadClientDashboardTab && window.loadClientDashboardTab('action-centre')" class="af-metric-card border-amber-200 bg-amber-50 text-left hover:border-amber-300"><div class="text-xs font-semibold uppercase text-amber-700">Pending From Me</div><div class="mt-2 text-3xl font-semibold text-amber-700">{{ pending_from_client or 0 }}</div><div class="mt-1 text-xs text-amber-700">Action required</div></button>
|
||||
<a href="/client/compliance" class="af-metric-card hover:border-brand-200"><div class="text-xs font-semibold uppercase text-slate-500">With Firm</div><div class="mt-2 text-3xl font-semibold text-brand-700">{{ with_firm or 0 }}</div><div class="mt-1 text-xs text-slate-500">Being processed</div></a>
|
||||
<button type="button" onclick="window.loadClientDashboardTab && window.loadClientDashboardTab('services-documents')" class="af-metric-card text-left hover:border-brand-200"><div class="text-xs font-semibold uppercase text-slate-500">Recent Documents</div><div class="mt-2 text-3xl font-semibold text-slate-900">{{ recent_documents|length if recent_documents else 0 }}</div><div class="mt-1 text-xs text-slate-500">Latest files</div></button>
|
||||
<button type="button" onclick="window.loadClientDashboardTab && window.loadClientDashboardTab('billing-messages')" class="af-metric-card border-amber-200 bg-amber-50 text-left hover:border-amber-300"><div class="text-xs font-semibold uppercase text-amber-700">Outstanding</div><div class="mt-2 text-2xl font-semibold text-amber-700">₹ {{ '%.2f'|format(billing_outstanding_amount or 0) }}</div><div class="mt-1 text-xs text-amber-700">{{ billing_open_count or 0 }} open bill(s)</div></button>
|
||||
</section>
|
||||
|
||||
<section class="grid gap-6 xl:grid-cols-[minmax(0,1fr)_380px]">
|
||||
<div class="space-y-6">
|
||||
<div class="af-card">
|
||||
<div class="flex items-center justify-between gap-3"><div><h3 class="text-lg font-semibold text-slate-900">Needs Your Attention</h3><p class="mt-1 text-sm text-slate-500">Open items where the firm may need documents, replies or confirmation from you.</p></div><a href="/client/compliance" class="af-btn af-btn-primary">View Services</a></div>
|
||||
<div class="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
|
||||
<div><h3 class="text-lg font-semibold text-slate-900">Needs Your Attention</h3><p class="mt-1 text-sm text-slate-500">Documents, replies or confirmations currently expected from you.</p></div>
|
||||
<button type="button" onclick="window.loadClientDashboardTab && window.loadClientDashboardTab('pending')" class="af-btn af-btn-primary">View Pending Items</button>
|
||||
</div>
|
||||
<div class="mt-5 space-y-3">
|
||||
{% set shown = namespace(count=0) %}
|
||||
{% for task in task_rows or [] %}
|
||||
@@ -25,15 +28,18 @@
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if shown.count == 0 %}
|
||||
<div class="rounded-2xl border border-dashed border-slate-300 p-6 text-sm text-slate-500">No urgent action is pending from you.</div>
|
||||
<div class="rounded-2xl border border-dashed border-slate-300 p-6 text-sm text-slate-500">No immediate action is pending from you.</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="af-card">
|
||||
<div class="flex items-center justify-between gap-3"><div><h3 class="text-lg font-semibold text-slate-900">Upcoming Compliance</h3><p class="mt-1 text-sm text-slate-500">Nearest active service due dates.</p></div><a href="/client/compliance" class="text-sm font-semibold text-brand-700 hover:underline">Open Compliance</a></div>
|
||||
<div class="mt-4 space-y-3">
|
||||
{% for row in due_soon_engagements[:6] %}
|
||||
<div class="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
|
||||
<div><h3 class="text-lg font-semibold text-slate-900">Upcoming Services & Due Dates</h3><p class="mt-1 text-sm text-slate-500">Important service deadlines visible to your client login.</p></div>
|
||||
<a href="/client/compliance" class="af-btn af-btn-secondary">Full Compliance Page</a>
|
||||
</div>
|
||||
<div class="mt-5 space-y-3">
|
||||
{% for row in engagements[:6] if engagements is defined %}
|
||||
<a href="/client/engagements/{{ row.id }}" class="block rounded-2xl border border-slate-200 p-4 hover:bg-slate-50">
|
||||
<div class="flex flex-col gap-2 md:flex-row md:items-center md:justify-between">
|
||||
<div><div class="font-semibold text-slate-900">{{ row.catalogue.service_name if row.catalogue else 'Service' }}</div><div class="text-xs text-slate-500">FY {{ row.financial_year }}{% if row.assessment_year %} • AY {{ row.assessment_year }}{% endif %}</div></div>
|
||||
@@ -41,7 +47,7 @@
|
||||
</div>
|
||||
</a>
|
||||
{% else %}
|
||||
<div class="rounded-2xl border border-dashed border-slate-300 p-6 text-sm text-slate-500">No upcoming compliance due dates found.</div>
|
||||
<div class="rounded-2xl border border-dashed border-slate-300 p-6 text-sm text-slate-500">No upcoming service due dates found.</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -62,7 +68,7 @@
|
||||
<div class="af-card">
|
||||
<h3 class="font-semibold text-slate-900">Quick Actions</h3>
|
||||
<div class="mt-4 grid gap-2 text-sm">
|
||||
<a href="/client/compliance" class="rounded-xl border border-slate-200 px-4 py-3 font-semibold text-slate-700 hover:bg-slate-50">View My Services</a>
|
||||
<button type="button" onclick="window.loadClientDashboardTab && window.loadClientDashboardTab('action-centre')" class="rounded-xl border border-slate-200 px-4 py-3 text-left font-semibold text-slate-700 hover:bg-slate-50">Pending From Me</button>
|
||||
<a href="/client/documents" class="rounded-xl border border-slate-200 px-4 py-3 font-semibold text-slate-700 hover:bg-slate-50">Upload / View Documents</a>
|
||||
<a href="/client/messages" class="rounded-xl border border-slate-200 px-4 py-3 font-semibold text-slate-700 hover:bg-slate-50">Messages from Firm</a>
|
||||
<a href="/client/billing" class="rounded-xl border border-slate-200 px-4 py-3 font-semibold text-slate-700 hover:bg-slate-50">View Bills & Receipts</a>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<div class="space-y-6">
|
||||
<section class="rounded-3xl border border-slate-200 bg-white p-5 shadow-soft">
|
||||
<div class="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
|
||||
<div><h3 class="text-lg font-semibold text-slate-900">Services & Documents</h3><p class="mt-1 text-sm text-slate-500">Track services handled by the firm and documents visible to you.</p></div>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<button type="button" onclick="window.loadClientDashboardTab && window.loadClientDashboardTab('services')" class="af-btn af-btn-secondary">Services</button>
|
||||
<button type="button" onclick="window.loadClientDashboardTab && window.loadClientDashboardTab('documents')" class="af-btn af-btn-secondary">Documents</button>
|
||||
<a href="/client/documents" class="af-btn af-btn-primary">Upload Documents</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% include "modules/clients/templates/clients/portal_partials/services.html" %}
|
||||
{% include "modules/clients/templates/clients/portal_partials/documents.html" %}
|
||||
</div>
|
||||
@@ -916,15 +916,17 @@ def _active_financial_year(request: Request) -> str | None:
|
||||
|
||||
CLIENT_PORTAL_TABS = {
|
||||
"overview": "modules/clients/templates/clients/portal_partials/overview.html",
|
||||
"action-centre": "modules/clients/templates/clients/portal_partials/action_centre.html",
|
||||
"services-documents": "modules/clients/templates/clients/portal_partials/services_documents.html",
|
||||
"billing-messages": "modules/clients/templates/clients/portal_partials/billing_messages.html",
|
||||
"reports": "modules/clients/templates/clients/portal_partials/reports.html",
|
||||
"pending": "modules/clients/templates/clients/portal_partials/pending.html",
|
||||
"services": "modules/clients/templates/clients/portal_partials/services.html",
|
||||
"documents": "modules/clients/templates/clients/portal_partials/documents.html",
|
||||
"billing": "modules/clients/templates/clients/portal_partials/billing.html",
|
||||
"messages": "modules/clients/templates/clients/portal_partials/messages.html",
|
||||
"reports": "modules/clients/templates/clients/portal_partials/reports.html",
|
||||
}
|
||||
|
||||
|
||||
def _client_dashboard_payload(db, client_row, financial_year: str | None = None) -> dict:
|
||||
summary = build_client_portal_summary(db, client_row, financial_year=financial_year)
|
||||
billing_summary = build_client_billing_summary(db, client_row, financial_year=financial_year)
|
||||
|
||||
Reference in New Issue
Block a user