Style client service subscription screens
This commit is contained in:
@@ -1,4 +1,115 @@
|
|||||||
{% extends "ui/templates/base/layout.html" %}
|
{% 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>
|
{% block content %}
|
||||||
<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="space-y-6">
|
||||||
<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 %}
|
{% 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" %}
|
{% extends "ui/templates/base/layout.html" %}
|
||||||
{% block content %}
|
{% 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="space-y-6">
|
||||||
<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>
|
{% set _uiux_partner_role_text = (current_user_roles or [])|join('|')|lower %}
|
||||||
<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>
|
{% 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 %}
|
{% endblock %}
|
||||||
|
|||||||
Reference in New Issue
Block a user