106 lines
11 KiB
HTML
106 lines
11 KiB
HTML
{% extends "ui/templates/base/layout.html" %}
|
||
{% block content %}
|
||
{% include "modules/managers/templates/managers/_manager_tabs.html" %}
|
||
<div class="space-y-6">
|
||
<div class="flex flex-wrap items-start justify-between gap-3">
|
||
<div>
|
||
<h2 class="text-xl font-semibold text-slate-900">Employee Work Allocation</h2>
|
||
<p class="mt-1 text-sm text-slate-500">Assign and review engagement/service tasks grouped by priority, client and engagement.</p>
|
||
</div>
|
||
<a href="/employees/dashboard" class="rounded-xl border border-slate-300 px-4 py-2 text-sm font-semibold text-slate-700 hover:bg-slate-50">Back to HR Dashboard</a>
|
||
</div>
|
||
|
||
<div class="grid gap-4 md:grid-cols-5">
|
||
<div class="rounded-2xl border border-slate-200 bg-white p-4 shadow-soft"><div class="text-xs font-semibold uppercase text-slate-500">Total</div><div class="mt-1 text-2xl font-semibold">{{ work_payload.summary.total }}</div></div>
|
||
<div class="rounded-2xl border border-slate-200 bg-white p-4 shadow-soft"><div class="text-xs font-semibold uppercase text-slate-500">Open</div><div class="mt-1 text-2xl font-semibold">{{ work_payload.summary.open }}</div></div>
|
||
<div class="rounded-2xl border border-orange-200 bg-orange-50 p-4 shadow-soft"><div class="text-xs font-semibold uppercase text-orange-600">Unassigned</div><div class="mt-1 text-2xl font-semibold text-orange-700">{{ work_payload.summary.unassigned }}</div></div>
|
||
<div class="rounded-2xl border border-red-200 bg-red-50 p-4 shadow-soft"><div class="text-xs font-semibold uppercase text-red-600">Overdue</div><div class="mt-1 text-2xl font-semibold text-red-700">{{ work_payload.summary.overdue }}</div></div>
|
||
<div class="rounded-2xl border border-emerald-200 bg-emerald-50 p-4 shadow-soft"><div class="text-xs font-semibold uppercase text-emerald-600">Completed</div><div class="mt-1 text-2xl font-semibold text-emerald-700">{{ work_payload.summary.completed }}</div></div>
|
||
</div>
|
||
|
||
<form method="get" action="/employees/work" class="rounded-2xl border border-slate-200 bg-white p-4 shadow-soft">
|
||
<div class="grid gap-3 md:grid-cols-[1fr_180px_240px_auto]">
|
||
<input type="search" name="q" value="{{ q or '' }}" placeholder="Search task, client or engagement" class="rounded-xl border border-slate-300 px-3 py-2 text-sm focus:border-brand-500 focus:outline-none focus:ring-2 focus:ring-brand-100">
|
||
<select name="status" class="rounded-xl border border-slate-300 px-3 py-2 text-sm">
|
||
<option value="open" {% if status == 'open' %}selected{% endif %}>Open tasks</option>
|
||
<option value="unassigned" {% if status == 'unassigned' %}selected{% endif %}>Unassigned</option>
|
||
<option value="closed" {% if status == 'closed' %}selected{% endif %}>Closed tasks</option>
|
||
<option value="pending" {% if status == 'pending' %}selected{% endif %}>Pending</option>
|
||
<option value="in_progress" {% if status == 'in_progress' %}selected{% endif %}>In Progress</option>
|
||
<option value="blocked" {% if status == 'blocked' %}selected{% endif %}>Blocked</option>
|
||
<option value="completed" {% if status == 'completed' %}selected{% endif %}>Completed</option>
|
||
</select>
|
||
<select name="assigned_to_user_id" class="rounded-xl border border-slate-300 px-3 py-2 text-sm">
|
||
<option value="0">All assignees</option>
|
||
{% for user in assignable_users %}
|
||
<option value="{{ user.id }}" {% if selected_assigned_to_user_id == user.id %}selected{% endif %}>{{ user.full_name or user.email }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
<button type="submit" class="rounded-xl bg-brand-600 px-4 py-2 text-sm font-semibold text-white hover:bg-brand-700">Filter</button>
|
||
</div>
|
||
</form>
|
||
|
||
<div class="space-y-4">
|
||
{% for priority_group in work_payload.groups %}
|
||
<details class="group rounded-2xl border border-slate-200 bg-white shadow-soft" {% if loop.first %}open{% endif %}>
|
||
<summary class="flex cursor-pointer list-none items-center justify-between gap-3 rounded-2xl px-5 py-4 hover:bg-slate-50">
|
||
<div><div class="text-sm font-semibold uppercase tracking-wide text-slate-500">Priority</div><div class="text-lg font-semibold text-slate-900">{{ priority_group.label }}</div></div>
|
||
<div class="flex items-center gap-3 text-sm text-slate-500"><span>{{ priority_group.task_count }} task{{ '' if priority_group.task_count == 1 else 's' }}</span><span class="text-lg transition group-open:rotate-90">›</span></div>
|
||
</summary>
|
||
<div class="space-y-3 border-t border-slate-100 p-4">
|
||
{% for client_group in priority_group.clients %}
|
||
<details class="group/client rounded-xl border border-slate-200 bg-slate-50" {% if loop.first %}open{% endif %}>
|
||
<summary class="flex cursor-pointer list-none items-center justify-between gap-3 px-4 py-3 hover:bg-slate-100">
|
||
<div><div class="font-semibold text-slate-900">{{ client_group.client_name }}</div><div class="text-xs text-slate-500">{{ client_group.client_code or 'No client code' }}</div></div>
|
||
<div class="flex items-center gap-3 text-sm text-slate-500"><span>{{ client_group.task_count }} task{{ '' if client_group.task_count == 1 else 's' }}</span><span class="transition group-open/client:rotate-90">›</span></div>
|
||
</summary>
|
||
<div class="space-y-3 border-t border-slate-200 p-3">
|
||
{% for engagement_group in client_group.engagements %}
|
||
<details class="group/eng rounded-xl border border-slate-200 bg-white" {% if loop.first %}open{% endif %}>
|
||
<summary class="flex cursor-pointer list-none items-center justify-between gap-3 px-4 py-3 hover:bg-slate-50">
|
||
<div><div class="font-semibold text-slate-900">{{ engagement_group.label }}</div><div class="text-xs text-slate-500">Open: {{ engagement_group.open_count }} · Completed: {{ engagement_group.completed_count }} · Status: {{ engagement_group.status.replace('_',' ').title() }}</div></div>
|
||
<div class="flex items-center gap-3 text-sm text-slate-500"><span>{{ engagement_group.task_count }} task{{ '' if engagement_group.task_count == 1 else 's' }}</span><span class="transition group-open/eng:rotate-90">›</span></div>
|
||
</summary>
|
||
<div class="overflow-x-auto border-t border-slate-100">
|
||
<table class="min-w-full divide-y divide-slate-200 text-sm">
|
||
<thead class="bg-slate-50 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">
|
||
<tr><th class="px-4 py-3">Task</th><th class="px-4 py-3">Current</th><th class="px-4 py-3">Assign / Review</th></tr>
|
||
</thead>
|
||
<tbody class="divide-y divide-slate-100 bg-white">
|
||
{% for task in engagement_group.tasks %}
|
||
<tr class="align-top {% if task.is_overdue %}bg-red-50{% elif task.is_due_today %}bg-amber-50{% endif %}">
|
||
<td class="px-4 py-3 min-w-[260px]"><div class="font-medium text-slate-900">{{ task.task_name }}</div>{% if task.description %}<div class="mt-1 max-w-xl text-xs text-slate-500">{{ task.description }}</div>{% endif %}<div class="mt-2 text-xs text-slate-500">Target: {{ task.internal_target_date or '-' }} · {{ task.date_bucket }}</div></td>
|
||
<td class="px-4 py-3 min-w-[180px]"><div><span class="rounded-full bg-slate-100 px-2.5 py-1 text-xs font-semibold text-slate-700">{{ task.status_label }}</span></div><div class="mt-2 text-xs text-slate-600">Assigned: {{ task.assigned_to.full_name if task.assigned_to else 'Unassigned' }}</div><div class="mt-1 text-xs text-slate-600">Priority: {{ task.priority_label }}</div>
|
||
<div class="mt-2"><a href="/employees/work/tasks/{{ task.id }}/communication" class="inline-flex rounded-lg border border-slate-300 px-2.5 py-1 text-xs font-semibold text-slate-700 hover:bg-slate-50">Timeline{% if task.comment_count %} · {{ task.comment_count }}{% endif %}</a></div>
|
||
{% if task.latest_comment %}<div class="mt-1 max-w-xs truncate text-xs text-slate-500">{{ task.latest_comment.message }}</div>{% endif %}
|
||
</td>
|
||
<td class="px-4 py-3 min-w-[520px]">
|
||
<form method="post" action="/employees/work/tasks/{{ task.id }}/assign" class="grid gap-2 md:grid-cols-5">
|
||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||
<select name="assigned_to_user_id" class="rounded-lg border border-slate-300 px-2 py-1 text-xs"><option value="">Unassigned</option>{% for user in assignable_users %}<option value="{{ user.id }}" {% if task.assigned_to_user_id == user.id %}selected{% endif %}>{{ user.full_name or user.email }}</option>{% endfor %}</select>
|
||
<select name="status" class="rounded-lg border border-slate-300 px-2 py-1 text-xs"><option value="pending" {% if task.status == 'pending' %}selected{% endif %}>Pending</option><option value="in_progress" {% if task.status == 'in_progress' %}selected{% endif %}>In Progress</option><option value="blocked" {% if task.status == 'blocked' %}selected{% endif %}>Blocked</option><option value="completed" {% if task.status == 'completed' %}selected{% endif %}>Completed</option><option value="not_applicable" {% if task.status == 'not_applicable' %}selected{% endif %}>Not Applicable</option><option value="cancelled" {% if task.status == 'cancelled' %}selected{% endif %}>Cancelled</option></select>
|
||
<select name="priority" class="rounded-lg border border-slate-300 px-2 py-1 text-xs"><option value="low" {% if task.priority == 'low' %}selected{% endif %}>Low</option><option value="normal" {% if task.priority == 'normal' %}selected{% endif %}>Normal</option><option value="high" {% if task.priority == 'high' %}selected{% endif %}>High</option><option value="urgent" {% if task.priority == 'urgent' %}selected{% endif %}>Urgent</option></select>
|
||
<input type="date" name="internal_target_date" value="{{ task.internal_target_date or '' }}" class="rounded-lg border border-slate-300 px-2 py-1 text-xs">
|
||
<button type="submit" class="rounded-lg bg-brand-600 px-3 py-1 text-xs font-semibold text-white hover:bg-brand-700">Save</button>
|
||
<input type="text" name="remarks" value="{{ task.remarks or '' }}" placeholder="Remarks" class="md:col-span-5 rounded-lg border border-slate-300 px-2 py-1 text-xs">
|
||
</form>
|
||
</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</details>
|
||
{% endfor %}
|
||
</div>
|
||
</details>
|
||
{% endfor %}
|
||
</div>
|
||
</details>
|
||
{% else %}
|
||
<div class="rounded-2xl border border-slate-200 bg-white p-8 text-center shadow-soft"><h3 class="font-semibold text-slate-900">No work items found</h3><p class="mt-1 text-sm text-slate-500">No engagement task matches the selected filter.</p></div>
|
||
{% endfor %}
|
||
</div>
|
||
</div>
|
||
{% endblock %}
|