Style client service subscription screens

This commit is contained in:
A R R R Associates
2026-08-05 13:54:26 +05:30
parent 05d1c3ebd0
commit 956560850d
2 changed files with 222 additions and 6 deletions
@@ -1,4 +1,115 @@
{% extends "ui/templates/base/layout.html" %}
{% block content %}<div class="page-shell"><div class="page-header"><div><h1>{{ plan.client.client_name }} — {{ plan.catalogue.service_name }}</h1><p>Client service subscription master and its period-wise engagements.</p></div><div><a class="btn" href="/services/subscriptions">Back</a> <a class="btn btn-primary" href="/services/engagements/new?client_id={{ plan.client_id }}">Create Engagement</a></div></div>
<div class="card"><h2>Subscription defaults</h2><div class="detail-grid"><div><b>Recurrence</b><br>{{ plan.recurrence_type|replace('_',' ')|title }}</div><div><b>Status</b><br>{{ plan.status|title }}</div><div><b>Engagement Partner</b><br>{{ plan.default_partner.full_name if plan.default_partner else '-' }}</div><div><b>Performing Partner</b><br>{{ plan.default_performing_partner.full_name if plan.default_performing_partner else '-' }}</div><div><b>Manager</b><br>{{ plan.default_manager.full_name if plan.default_manager else '-' }}</div><div><b>Staff</b><br>{{ plan.default_staff.full_name if plan.default_staff else '-' }}</div><div><b>Review Partner</b><br>{{ plan.default_review_partner.full_name if plan.default_review_partner else '-' }}</div><div><b>Auto-generate periods</b><br>{{ 'Yes' if plan.auto_generate_periods else 'No' }}</div></div></div>
<div class="card table-wrap"><h2>Engagement instances</h2><table><thead><tr><th>FY</th><th>Period</th><th>Due date</th><th>Status</th><th></th></tr></thead><tbody>{% for row in engagements %}<tr><td>{{ row.financial_year }}</td><td>{{ row.period_label or '-' }}</td><td>{{ row.current_due_date or '-' }}</td><td>{{ row.status|title }}</td><td><a href="/services/engagements/{{ row.id }}">View</a></td></tr>{% else %}<tr><td colspan="5">No engagement instances generated.</td></tr>{% endfor %}</tbody></table></div></div>{% endblock %}
{% block content %}
<div class="space-y-6">
{% set _uiux_partner_role_text = (current_user_roles or [])|join('|')|lower %}
{% if 'partner' in _uiux_partner_role_text %}
{% include "ui/templates/components/partner_navigation_v2.html" %}
{% endif %}
<div class="flex flex-wrap items-center justify-between gap-3">
<div>
<h2 class="text-xl font-semibold text-slate-900">
{{ plan.client.client_name }} — {{ plan.catalogue.service_name }}
</h2>
<p class="text-sm text-slate-500">
Client service subscription master and its period-wise engagements.
</p>
</div>
<div class="flex flex-wrap gap-2">
<a href="/services/subscriptions"
class="rounded-xl border border-slate-300 px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">
Back
</a>
<a href="/services/engagements/new?client_id={{ plan.client_id }}"
class="rounded-xl bg-brand-600 px-4 py-2 text-sm font-medium text-white hover:bg-brand-700">
Create Engagement
</a>
</div>
</div>
<section class="rounded-2xl bg-white p-5 shadow-soft">
<h3 class="text-base font-semibold text-slate-900">Subscription Defaults</h3>
<div class="mt-4 grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
<div class="rounded-xl border border-slate-200 p-4">
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Recurrence</div>
<div class="mt-1 text-sm font-medium text-slate-900">{{ plan.recurrence_type|replace('_', ' ')|title }}</div>
</div>
<div class="rounded-xl border border-slate-200 p-4">
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Status</div>
<div class="mt-1 text-sm font-medium text-slate-900">{{ plan.status|replace('_', ' ')|title }}</div>
</div>
<div class="rounded-xl border border-slate-200 p-4">
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Engagement Partner</div>
<div class="mt-1 text-sm font-medium text-slate-900">{{ plan.default_partner.full_name if plan.default_partner else '-' }}</div>
</div>
<div class="rounded-xl border border-slate-200 p-4">
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Performing Partner</div>
<div class="mt-1 text-sm font-medium text-slate-900">{{ plan.default_performing_partner.full_name if plan.default_performing_partner else '-' }}</div>
</div>
<div class="rounded-xl border border-slate-200 p-4">
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Manager</div>
<div class="mt-1 text-sm font-medium text-slate-900">{{ plan.default_manager.full_name if plan.default_manager else '-' }}</div>
</div>
<div class="rounded-xl border border-slate-200 p-4">
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Staff</div>
<div class="mt-1 text-sm font-medium text-slate-900">{{ plan.default_staff.full_name if plan.default_staff else '-' }}</div>
</div>
<div class="rounded-xl border border-slate-200 p-4">
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Review Partner</div>
<div class="mt-1 text-sm font-medium text-slate-900">{{ plan.default_review_partner.full_name if plan.default_review_partner else '-' }}</div>
</div>
<div class="rounded-xl border border-slate-200 p-4">
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Auto-generate Periods</div>
<div class="mt-1 text-sm font-medium text-slate-900">{{ 'Yes' if plan.auto_generate_periods else 'No' }}</div>
</div>
</div>
</section>
<section class="overflow-hidden rounded-2xl bg-white shadow-soft">
<div class="border-b border-slate-200 px-5 py-4">
<h3 class="text-base font-semibold text-slate-900">Engagement Instances</h3>
</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">FY</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Period</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Due Date</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-right text-xs font-semibold uppercase tracking-wide text-slate-500">Action</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100">
{% for row in engagements %}
<tr>
<td class="px-4 py-3 text-sm text-slate-700">{{ row.financial_year or '-' }}</td>
<td class="px-4 py-3 text-sm text-slate-700">{{ row.period_label or '-' }}</td>
<td class="px-4 py-3 text-sm text-slate-700">{{ row.current_due_date or '-' }}</td>
<td class="px-4 py-3 text-sm">
<span class="rounded-full px-2 py-1 text-xs font-medium
{% if row.status == 'active' %}bg-emerald-100 text-emerald-700
{% else %}bg-slate-200 text-slate-700{% endif %}">
{{ row.status|replace('_', ' ')|title }}
</span>
</td>
<td class="px-4 py-3 text-right text-sm">
<a href="/services/engagements/{{ row.id }}"
class="font-medium text-brand-700 hover:underline">
View
</a>
</td>
</tr>
{% else %}
<tr>
<td colspan="5" class="px-4 py-10 text-center text-sm text-slate-500">
No engagement instances generated.
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</section>
</div>
{% endblock %}
@@ -1,6 +1,111 @@
{% extends "ui/templates/base/layout.html" %}
{% block content %}
<div class="page-shell"><div class="page-header"><div><h1>Client Service Subscriptions</h1><p>Persistent client-level services. Period-wise engagements are generated and tracked separately.</p></div><a class="btn btn-primary" href="/services/engagements/new">Assign Service</a></div>
<div class="card"><form method="get" class="filter-row"><input name="q" value="{{ q }}" placeholder="Client or service"><label><input type="checkbox" name="include_inactive" value="true" {% if include_inactive %}checked{% endif %}> Include inactive</label><button class="btn" type="submit">Filter</button></form></div>
<div class="card table-wrap"><table><thead><tr><th>Client</th><th>Service</th><th>Recurrence</th><th>Default Team</th><th>Engagements</th><th>Status</th><th></th></tr></thead><tbody>{% for plan,count,latest_due in rows %}<tr><td><strong>{{ plan.client.client_name }}</strong><div class="muted">{{ plan.client.client_code or '' }}</div></td><td><strong>{{ plan.catalogue.service_name }}</strong><div class="muted">{{ plan.catalogue.service_code }}</div></td><td>{{ plan.recurrence_type|replace('_',' ')|title }}</td><td>Partner: {{ plan.default_partner.full_name if plan.default_partner else '-' }}<br>Performing: {{ plan.default_performing_partner.full_name if plan.default_performing_partner else '-' }}<br>Manager: {{ plan.default_manager.full_name if plan.default_manager else '-' }}<br>Staff: {{ plan.default_staff.full_name if plan.default_staff else '-' }}</td><td>{{ count or 0 }}{% if latest_due %}<div class="muted">Latest due: {{ latest_due }}</div>{% endif %}</td><td>{{ plan.status|title }}</td><td><a href="/services/subscriptions/{{ plan.id }}">View</a></td></tr>{% else %}<tr><td colspan="7">No client service subscriptions found.</td></tr>{% endfor %}</tbody></table></div></div>
<div class="space-y-6">
{% set _uiux_partner_role_text = (current_user_roles or [])|join('|')|lower %}
{% if 'partner' in _uiux_partner_role_text %}
{% include "ui/templates/components/partner_navigation_v2.html" %}
{% endif %}
<div class="flex flex-wrap items-center justify-between gap-3">
<div>
<h2 class="text-xl font-semibold text-slate-900">Client Service Subscriptions</h2>
<p class="text-sm text-slate-500">
Persistent client-level services. Period-wise engagements are generated and tracked separately.
</p>
</div>
<a href="/services/engagements/new"
class="rounded-xl bg-brand-600 px-4 py-2 text-sm font-medium text-white hover:bg-brand-700">
Assign Service
</a>
</div>
<form method="get" class="flex flex-wrap items-end gap-3 rounded-2xl bg-white p-4 shadow-soft">
<div>
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Search</label>
<input type="text"
name="q"
value="{{ q or '' }}"
placeholder="Client or service"
class="w-72 rounded-xl border border-slate-300 px-3 py-2 text-sm">
</div>
<label class="inline-flex items-center gap-2 pb-2 text-sm text-slate-700">
<input type="checkbox"
name="include_inactive"
value="true"
{% if include_inactive %}checked{% endif %}
class="rounded border-slate-300">
Include inactive
</label>
<button type="submit"
class="rounded-xl border border-slate-300 px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">
Filter
</button>
</form>
<div class="overflow-hidden rounded-2xl 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</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Service</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Recurrence</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Default Team</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Engagements</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-right text-xs font-semibold uppercase tracking-wide text-slate-500">Action</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100">
{% for plan, count, latest_due in rows %}
<tr class="align-top">
<td class="px-4 py-3 text-sm">
<div class="font-medium text-slate-900">{{ plan.client.client_name }}</div>
<div class="text-xs text-slate-500">{{ plan.client.client_code or '' }}</div>
</td>
<td class="px-4 py-3 text-sm">
<div class="font-medium text-slate-900">{{ plan.catalogue.service_name }}</div>
<div class="text-xs text-slate-500">{{ plan.catalogue.service_code }}</div>
</td>
<td class="px-4 py-3 text-sm text-slate-700">
{{ plan.recurrence_type|replace('_', ' ')|title }}
</td>
<td class="px-4 py-3 text-xs leading-5 text-slate-600">
<div><span class="font-medium text-slate-700">Partner:</span> {{ plan.default_partner.full_name if plan.default_partner else '-' }}</div>
<div><span class="font-medium text-slate-700">Performing:</span> {{ plan.default_performing_partner.full_name if plan.default_performing_partner else '-' }}</div>
<div><span class="font-medium text-slate-700">Manager:</span> {{ plan.default_manager.full_name if plan.default_manager else '-' }}</div>
<div><span class="font-medium text-slate-700">Staff:</span> {{ plan.default_staff.full_name if plan.default_staff else '-' }}</div>
</td>
<td class="px-4 py-3 text-sm text-slate-700">
<div class="font-medium text-slate-900">{{ count or 0 }}</div>
{% if latest_due %}
<div class="mt-1 text-xs text-slate-500">Latest due: {{ latest_due }}</div>
{% endif %}
</td>
<td class="px-4 py-3 text-sm">
<span class="rounded-full px-2 py-1 text-xs font-medium
{% if plan.status == 'active' %}bg-emerald-100 text-emerald-700
{% else %}bg-slate-200 text-slate-700{% endif %}">
{{ plan.status|replace('_', ' ')|title }}
</span>
</td>
<td class="px-4 py-3 text-right text-sm">
<a href="/services/subscriptions/{{ plan.id }}"
class="font-medium text-brand-700 hover:underline">
View
</a>
</td>
</tr>
{% else %}
<tr>
<td colspan="7" class="px-4 py-10 text-center text-sm text-slate-500">
No client service subscriptions found.
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}