Upgrade employee portal staff dashboard to v2
This commit is contained in:
@@ -7,12 +7,12 @@
|
||||
<div>
|
||||
<p class="text-xs font-semibold uppercase tracking-[0.22em] text-brand-100">My Workspace</p>
|
||||
<h2 class="mt-2 text-2xl font-semibold">Employee Portal</h2>
|
||||
<p class="mt-2 max-w-3xl text-sm text-brand-100">Use this dashboard for your assigned work, attendance, leave, documents, payslips, profile and alerts.</p>
|
||||
<p class="mt-2 max-w-3xl text-sm text-brand-100">Punch attendance, view priority work, track documents, leave, payslips and alerts from one staff workspace.</p>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
{% if employee %}
|
||||
<a href="/employee/work" class="rounded-xl bg-white px-4 py-2 text-sm font-semibold text-brand-700 hover:bg-brand-50">Open My Work Board</a>
|
||||
<a href="/employee/attendance" class="rounded-xl border border-white/40 px-4 py-2 text-sm font-semibold text-white hover:bg-white/10">Full Attendance</a>
|
||||
<a href="/employee/attendance" class="rounded-xl bg-white px-4 py-2 text-sm font-semibold text-brand-700 hover:bg-brand-50">Punch / Attendance</a>
|
||||
<a href="/employee/work" class="rounded-xl border border-white/40 px-4 py-2 text-sm font-semibold text-white hover:bg-white/10">Open Work Board</a>
|
||||
{% else %}
|
||||
<a href="/employee/register" class="rounded-xl bg-white px-4 py-2 text-sm font-semibold text-brand-700 hover:bg-brand-50">Request Employee Linkage</a>
|
||||
{% endif %}
|
||||
@@ -24,13 +24,18 @@
|
||||
{% set tabs = [
|
||||
('overview','Overview'),
|
||||
('work','My Work Board'),
|
||||
('due-today','Due Today'),
|
||||
('overdue','Overdue'),
|
||||
('client-pending','Client Pending'),
|
||||
('returned','Returned / Blocked'),
|
||||
('attendance','My Attendance'),
|
||||
('profile','My Profile'),
|
||||
('leave','My Leave'),
|
||||
('documents','My Documents'),
|
||||
('payslips','My Payslips'),
|
||||
('offboarding','My Offboarding'),
|
||||
('alerts','My Alert')
|
||||
('alerts','My Alert'),
|
||||
('reports','My Reports')
|
||||
] %}
|
||||
|
||||
<section class="rounded-2xl border border-slate-200 bg-white p-3 shadow-soft">
|
||||
@@ -93,11 +98,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
tabs.forEach(function (button) {
|
||||
button.addEventListener('click', function () {
|
||||
document.addEventListener('click', function (event) {
|
||||
const button = event.target.closest('.employee-portal-tab');
|
||||
if (!button || !button.dataset.tab) return;
|
||||
event.preventDefault();
|
||||
loadTab(button.dataset.tab || 'overview', true);
|
||||
});
|
||||
});
|
||||
|
||||
window.addEventListener('popstate', function (event) {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
{% if not employee %}
|
||||
<div class="rounded-2xl border border-amber-200 bg-amber-50 p-6 text-sm text-amber-900 shadow-soft">Your login is not linked to an employee profile yet.</div>
|
||||
{% else %}
|
||||
<div class="flex flex-wrap items-center justify-between gap-3">
|
||||
<div><h3 class="text-lg font-semibold text-slate-900">Client Pending / Blocked Work</h3><p class="mt-1 text-sm text-slate-600">Tasks marked blocked usually need client documents, clarification, manager input or correction before continuation.</p></div>
|
||||
<a href="/employee/work?status=blocked" class="af-btn af-btn-primary">Open Blocked Work</a>
|
||||
</div>
|
||||
<div class="grid gap-4 lg:grid-cols-2">
|
||||
{% set ns = namespace(count=0) %}
|
||||
{% if work_payload %}
|
||||
{% for column in work_payload.columns if column.code == 'blocked' %}
|
||||
{% for card in column.cards %}
|
||||
{% set ns.count = ns.count + 1 %}
|
||||
<article class="rounded-2xl border border-amber-200 bg-amber-50 p-5 shadow-soft">
|
||||
<div class="text-xs font-semibold uppercase tracking-wide text-amber-700">Blocked / Waiting</div>
|
||||
<h4 class="mt-1 text-base font-semibold text-slate-900">{{ card.client_name }}</h4>
|
||||
<p class="mt-1 text-sm text-slate-700">{{ card.service_name }} · FY {{ card.financial_year }}</p>
|
||||
<div class="mt-3 rounded-xl bg-white/80 p-3 text-xs text-slate-700">{{ card.blocked_count }} blocked task(s). Latest note: {{ card.latest_comment.comment_text if card.latest_comment and card.latest_comment.comment_text is defined else '-' }}</div>
|
||||
<a href="/employee/work/engagements/{{ card.engagement_id }}" class="mt-4 inline-flex w-full justify-center rounded-xl bg-amber-600 px-4 py-2 text-sm font-semibold text-white hover:bg-amber-700">Open / Follow Up</a>
|
||||
</article>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if ns.count == 0 %}
|
||||
<div class="rounded-2xl border border-dashed border-slate-300 bg-white p-8 text-center text-sm text-slate-500 lg:col-span-2">No blocked or client-pending work is pending.</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -0,0 +1,34 @@
|
||||
{% if not employee %}
|
||||
<div class="rounded-2xl border border-amber-200 bg-amber-50 p-6 text-sm text-amber-900 shadow-soft">Your login is not linked to an employee profile yet.</div>
|
||||
{% else %}
|
||||
<div class="flex flex-wrap items-center justify-between gap-3">
|
||||
<div><h3 class="text-lg font-semibold text-slate-900">Due Today</h3><p class="mt-1 text-sm text-slate-600">Assigned work that needs action today.</p></div>
|
||||
<a href="/employee/work?date_bucket=today" class="af-btn af-btn-primary">Open Full Board</a>
|
||||
</div>
|
||||
<div class="grid gap-4 lg:grid-cols-2">
|
||||
{% set ns = namespace(count=0) %}
|
||||
{% if work_payload %}
|
||||
{% for column in work_payload.columns %}
|
||||
{% for card in column.cards %}
|
||||
{% if card.due_today_count %}
|
||||
{% set ns.count = ns.count + 1 %}
|
||||
<article class="rounded-2xl border border-amber-200 bg-amber-50 p-5 shadow-soft">
|
||||
<div class="text-xs font-semibold uppercase tracking-wide text-amber-700">Due Today</div>
|
||||
<h4 class="mt-1 text-base font-semibold text-slate-900">{{ card.client_name }}</h4>
|
||||
<p class="mt-1 text-sm text-slate-700">{{ card.service_name }} · FY {{ card.financial_year }}</p>
|
||||
<div class="mt-3 grid gap-2 text-xs text-slate-700 sm:grid-cols-3">
|
||||
<div class="rounded-xl bg-white/80 p-3"><strong class="block text-slate-900">{{ card.open_count }}</strong>Open</div>
|
||||
<div class="rounded-xl bg-white/80 p-3"><strong class="block text-slate-900">{{ card.due_today_count }}</strong>Due today</div>
|
||||
<div class="rounded-xl bg-white/80 p-3"><strong class="block text-slate-900">{{ card.completed_count }}</strong>Completed</div>
|
||||
</div>
|
||||
<a href="/employee/work/engagements/{{ card.engagement_id }}" class="mt-4 inline-flex w-full justify-center rounded-xl bg-brand-600 px-4 py-2 text-sm font-semibold text-white hover:bg-brand-700">Open Work Details</a>
|
||||
</article>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if ns.count == 0 %}
|
||||
<div class="rounded-2xl border border-dashed border-slate-300 bg-white p-8 text-center text-sm text-slate-500 lg:col-span-2">No work is due today.</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -0,0 +1,34 @@
|
||||
{% if not employee %}
|
||||
<div class="rounded-2xl border border-amber-200 bg-amber-50 p-6 text-sm text-amber-900 shadow-soft">Your login is not linked to an employee profile yet.</div>
|
||||
{% else %}
|
||||
<div class="flex flex-wrap items-center justify-between gap-3">
|
||||
<div><h3 class="text-lg font-semibold text-slate-900">Overdue Work</h3><p class="mt-1 text-sm text-slate-600">These assigned engagements have overdue task items. Clear these first.</p></div>
|
||||
<a href="/employee/work?date_bucket=overdue" class="af-btn af-btn-primary">Open Full Board</a>
|
||||
</div>
|
||||
<div class="grid gap-4 lg:grid-cols-2">
|
||||
{% set ns = namespace(count=0) %}
|
||||
{% if work_payload %}
|
||||
{% for column in work_payload.columns %}
|
||||
{% for card in column.cards %}
|
||||
{% if card.overdue_count %}
|
||||
{% set ns.count = ns.count + 1 %}
|
||||
<article class="rounded-2xl border border-red-200 bg-red-50 p-5 shadow-soft">
|
||||
<div class="text-xs font-semibold uppercase tracking-wide text-red-700">Overdue</div>
|
||||
<h4 class="mt-1 text-base font-semibold text-slate-900">{{ card.client_name }}</h4>
|
||||
<p class="mt-1 text-sm text-slate-700">{{ card.service_name }} · FY {{ card.financial_year }} · Due {{ card.due_date or '-' }}</p>
|
||||
<div class="mt-3 grid gap-2 text-xs text-slate-700 sm:grid-cols-3">
|
||||
<div class="rounded-xl bg-white/80 p-3"><strong class="block text-red-700">{{ card.overdue_count }}</strong>Overdue</div>
|
||||
<div class="rounded-xl bg-white/80 p-3"><strong class="block text-slate-900">{{ card.open_count }}</strong>Open</div>
|
||||
<div class="rounded-xl bg-white/80 p-3"><strong class="block text-slate-900">{{ card.blocked_count }}</strong>Blocked</div>
|
||||
</div>
|
||||
<a href="/employee/work/engagements/{{ card.engagement_id }}" class="mt-4 inline-flex w-full justify-center rounded-xl bg-red-600 px-4 py-2 text-sm font-semibold text-white hover:bg-red-700">Open Overdue Work</a>
|
||||
</article>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if ns.count == 0 %}
|
||||
<div class="rounded-2xl border border-dashed border-slate-300 bg-white p-8 text-center text-sm text-slate-500 lg:col-span-2">No overdue work is pending.</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -1,59 +1,97 @@
|
||||
{% if employee %}
|
||||
<section class="grid gap-4 md:grid-cols-2 xl:grid-cols-6">
|
||||
<a href="/employee/work" class="af-metric-card hover:border-brand-200">
|
||||
<div class="text-xs font-semibold uppercase text-slate-500">Open Work</div>
|
||||
<div class="mt-2 text-3xl font-semibold text-slate-900">{{ work_payload.summary.open if work_payload else 0 }}</div>
|
||||
<div class="mt-1 text-xs text-slate-500">Assigned to me</div>
|
||||
</a>
|
||||
<a href="/employee/work?status=in_progress" class="af-metric-card hover:border-brand-200">
|
||||
<div class="text-xs font-semibold uppercase text-slate-500">In Progress</div>
|
||||
<div class="mt-2 text-3xl font-semibold text-brand-700">{{ work_payload.summary.in_progress if work_payload else 0 }}</div>
|
||||
<div class="mt-1 text-xs text-slate-500">Currently active</div>
|
||||
</a>
|
||||
<a href="/employee/work?status=blocked" class="af-metric-card border-amber-200 bg-amber-50 hover:border-amber-300">
|
||||
<div class="text-xs font-semibold uppercase text-amber-700">Blocked</div>
|
||||
<div class="mt-2 text-3xl font-semibold text-amber-700">{{ work_payload.summary.blocked if work_payload else 0 }}</div>
|
||||
<div class="mt-1 text-xs text-amber-700">Need clarification</div>
|
||||
</a>
|
||||
<a href="/employee/work?date_bucket=overdue" class="af-metric-card border-red-200 bg-red-50 hover:border-red-300">
|
||||
<div class="text-xs font-semibold uppercase text-red-700">Overdue</div>
|
||||
<div class="mt-2 text-3xl font-semibold text-red-700">{{ work_payload.summary.overdue if work_payload else 0 }}</div>
|
||||
<div class="mt-1 text-xs text-red-700">Immediate action</div>
|
||||
</a>
|
||||
<a href="/employee/attendance" class="af-metric-card hover:border-brand-200">
|
||||
<button type="button" data-tab="attendance" class="employee-portal-tab af-metric-card text-left hover:border-brand-200">
|
||||
<div class="text-xs font-semibold uppercase text-slate-500">Attendance</div>
|
||||
<div class="mt-2 text-lg font-semibold text-slate-900">{% if today_attendance %}{% if today_attendance.punch_out_utc %}Completed{% elif today_attendance.punch_in_utc %}Punched In{% else %}Marked{% endif %}{% else %}Not Marked{% endif %}</div>
|
||||
<div class="mt-1 text-xs text-slate-500">Today</div>
|
||||
</a>
|
||||
<a href="/employee/payslips" class="af-metric-card hover:border-brand-200">
|
||||
<div class="text-xs font-semibold uppercase text-slate-500">Payslips</div>
|
||||
<div class="mt-2 text-3xl font-semibold text-slate-900">{{ payslips|length }}</div>
|
||||
<div class="mt-1 text-xs text-slate-500">Available slips</div>
|
||||
</a>
|
||||
</button>
|
||||
<button type="button" data-tab="due-today" class="employee-portal-tab af-metric-card text-left hover:border-brand-200">
|
||||
<div class="text-xs font-semibold uppercase text-slate-500">Due Today</div>
|
||||
<div class="mt-2 text-3xl font-semibold text-brand-700">{{ work_payload.summary.due_today if work_payload else 0 }}</div>
|
||||
<div class="mt-1 text-xs text-slate-500">Need action today</div>
|
||||
</button>
|
||||
<button type="button" data-tab="overdue" class="employee-portal-tab af-metric-card border-red-200 bg-red-50 text-left hover:border-red-300">
|
||||
<div class="text-xs font-semibold uppercase text-red-700">Overdue</div>
|
||||
<div class="mt-2 text-3xl font-semibold text-red-700">{{ work_payload.summary.overdue if work_payload else 0 }}</div>
|
||||
<div class="mt-1 text-xs text-red-700">Immediate attention</div>
|
||||
</button>
|
||||
<button type="button" data-tab="client-pending" class="employee-portal-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">Client Pending</div>
|
||||
<div class="mt-2 text-3xl font-semibold text-amber-700">{{ work_payload.summary.blocked if work_payload else 0 }}</div>
|
||||
<div class="mt-1 text-xs text-amber-700">Blocked / clarification</div>
|
||||
</button>
|
||||
<button type="button" data-tab="work" class="employee-portal-tab af-metric-card text-left hover:border-brand-200">
|
||||
<div class="text-xs font-semibold uppercase text-slate-500">Open Work</div>
|
||||
<div class="mt-2 text-3xl font-semibold text-slate-900">{{ work_payload.summary.open if work_payload else 0 }}</div>
|
||||
<div class="mt-1 text-xs text-slate-500">Assigned to me</div>
|
||||
</button>
|
||||
<button type="button" data-tab="documents" class="employee-portal-tab af-metric-card text-left 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">{{ own_documents|length }}</div>
|
||||
<div class="mt-1 text-xs text-slate-500">Recent records</div>
|
||||
</button>
|
||||
</section>
|
||||
|
||||
<section class="grid gap-6 xl:grid-cols-[minmax(0,1fr)_400px]">
|
||||
<section class="grid gap-6 xl:grid-cols-[minmax(0,1fr)_420px]">
|
||||
<div class="space-y-6">
|
||||
<div class="af-card">
|
||||
<div class="flex flex-wrap items-center justify-between gap-3">
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold text-slate-900">My Assignment Board Snapshot</h3>
|
||||
<p class="mt-1 text-sm text-slate-600">Your work is grouped by practical status. Open the full board for detailed updates.</p>
|
||||
<h3 class="text-lg font-semibold text-slate-900">Today’s Priority Work</h3>
|
||||
<p class="mt-1 text-sm text-slate-600">Overdue and due-today work appears first. Open the engagement to continue, add remarks, upload documents or submit work.</p>
|
||||
</div>
|
||||
<a href="/employee/work" class="af-btn af-btn-primary">Open My Work Board</a>
|
||||
<a href="/employee/work" class="af-btn af-btn-primary">Open Full Work Board</a>
|
||||
</div>
|
||||
<div class="mt-5 grid gap-3 md:grid-cols-4">
|
||||
<div class="mt-5 space-y-3">
|
||||
{% set ns = namespace(count=0) %}
|
||||
{% if work_payload %}
|
||||
{% for column in work_payload.columns %}
|
||||
<a href="/employee/work?status={{ column.code }}" class="rounded-2xl border border-slate-200 bg-slate-50 p-4 transition hover:border-brand-300 hover:bg-brand-50/50">
|
||||
<div class="text-sm font-semibold text-slate-900">{{ column.label }}</div>
|
||||
<div class="mt-2 text-2xl font-semibold text-slate-900">{{ column.cards|length }}</div>
|
||||
<div class="mt-1 text-xs text-slate-500">assignment card(s)</div>
|
||||
{% for card in column.cards %}
|
||||
{% if ns.count < 6 and (card.overdue_count or card.due_today_count) %}
|
||||
{% set ns.count = ns.count + 1 %}
|
||||
<article class="rounded-2xl border {% if card.overdue_count %}border-red-200 bg-red-50{% elif card.due_today_count %}border-amber-200 bg-amber-50{% else %}border-slate-200 bg-white{% endif %} p-4">
|
||||
<div class="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
|
||||
<div>
|
||||
<div class="text-xs font-semibold uppercase tracking-wide {% if card.overdue_count %}text-red-700{% elif card.due_today_count %}text-amber-700{% else %}text-slate-500{% endif %}">{{ card.client_code or 'Client' }}</div>
|
||||
<h4 class="mt-1 text-sm font-semibold text-slate-900">{{ card.client_name }} · {{ card.service_name }}</h4>
|
||||
<p class="mt-1 text-xs text-slate-600">FY {{ card.financial_year }} · Due {{ card.due_date or '-' }} · {{ card.open_count }} open · {{ card.overdue_count }} overdue · {{ card.due_today_count }} due today</p>
|
||||
</div>
|
||||
<a href="/employee/work/engagements/{{ card.engagement_id }}" class="inline-flex justify-center rounded-xl bg-brand-600 px-4 py-2 text-sm font-semibold text-white hover:bg-brand-700">Open</a>
|
||||
</div>
|
||||
</article>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if ns.count == 0 %}
|
||||
<div class="rounded-2xl border border-dashed border-slate-300 bg-slate-50 p-6 text-sm text-slate-500">No overdue or due-today work is pending.</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-6 lg:grid-cols-2">
|
||||
<div class="af-card">
|
||||
<div class="flex flex-wrap items-center justify-between gap-3">
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold text-slate-900">Returned / Blocked Work</h3>
|
||||
<p class="mt-1 text-sm text-slate-600">Items marked blocked require clarification, correction or client/manager input.</p>
|
||||
</div>
|
||||
<button type="button" data-tab="returned" class="employee-portal-tab af-btn af-btn-secondary">View</button>
|
||||
</div>
|
||||
<div class="mt-4 space-y-3">
|
||||
{% set blocked = namespace(count=0) %}
|
||||
{% if work_payload %}
|
||||
{% for column in work_payload.columns if column.code == 'blocked' %}
|
||||
{% for card in column.cards[:4] %}
|
||||
{% set blocked.count = blocked.count + 1 %}
|
||||
<a href="/employee/work/engagements/{{ card.engagement_id }}" class="block rounded-2xl border border-amber-200 bg-amber-50 p-4 hover:border-amber-300">
|
||||
<div class="text-sm font-semibold text-slate-900">{{ card.client_name }}</div>
|
||||
<div class="mt-1 text-xs text-amber-700">{{ card.service_name }} · {{ card.blocked_count }} blocked task(s)</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="rounded-2xl border border-dashed border-slate-300 p-6 text-sm text-slate-500 md:col-span-4">No work board data available yet.</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if blocked.count == 0 %}<div class="rounded-2xl border border-dashed border-slate-300 p-5 text-sm text-slate-500">No blocked work pending.</div>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -61,46 +99,47 @@
|
||||
<div class="flex flex-wrap items-center justify-between gap-3">
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold text-slate-900">Leave & Availability</h3>
|
||||
<p class="mt-1 text-sm text-slate-600">Balances and recent leave requests for your profile.</p>
|
||||
<p class="mt-1 text-sm text-slate-600">Balances and recent leave requests.</p>
|
||||
</div>
|
||||
<a href="/employee/leave" class="af-btn af-btn-secondary">Open Leave</a>
|
||||
</div>
|
||||
<div class="mt-5 grid gap-3 md:grid-cols-3">
|
||||
{% for bal in leave_balances %}
|
||||
<div class="mt-4 grid gap-3 md:grid-cols-2">
|
||||
{% for bal in leave_balances[:4] %}
|
||||
<div class="rounded-2xl border border-slate-200 bg-slate-50 p-4">
|
||||
<div class="text-xs font-semibold uppercase text-slate-500">{{ bal.leave_type.name if bal.leave_type else bal.leave_type_id }}</div>
|
||||
<div class="mt-2 text-2xl font-semibold text-slate-900">{{ bal.balance_days }}</div>
|
||||
<div class="text-xs text-slate-500">days balance</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="rounded-2xl border border-dashed border-slate-300 p-6 text-sm text-slate-500 md:col-span-3">No leave balance available yet.</div>
|
||||
<div class="rounded-2xl border border-dashed border-slate-300 p-6 text-sm text-slate-500 md:col-span-2">No leave balance available yet.</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<aside class="space-y-6">
|
||||
{% include "modules/employees/templates/employees/portal_partials/attendance_punch_card.html" %}
|
||||
|
||||
<div class="af-card">
|
||||
<h3 class="font-semibold text-slate-900">Today’s Attendance Summary</h3>
|
||||
<dl class="mt-4 grid gap-3 text-sm">
|
||||
<div class="flex justify-between gap-3"><dt class="text-slate-500">Status</dt><dd class="font-medium text-slate-900">{% if today_attendance %}{{ today_attendance.status.replace('_',' ').title() }}{% else %}Not Marked{% endif %}</dd></div>
|
||||
<div class="flex justify-between gap-3"><dt class="text-slate-500">Punch In</dt><dd class="font-medium text-slate-900">{{ today_attendance.punch_in_local_at.strftime('%H:%M') if today_attendance and today_attendance.punch_in_local_at else (today_attendance.punch_in_utc.strftime('%H:%M UTC') if today_attendance and today_attendance.punch_in_utc else '-') }}</dd></div>
|
||||
<div class="flex justify-between gap-3"><dt class="text-slate-500">Punch Out</dt><dd class="font-medium text-slate-900">{{ today_attendance.punch_out_local_at.strftime('%H:%M') if today_attendance and today_attendance.punch_out_local_at else (today_attendance.punch_out_utc.strftime('%H:%M UTC') if today_attendance and today_attendance.punch_out_utc else '-') }}</dd></div>
|
||||
<div class="flex justify-between gap-3"><dt class="text-slate-500">Duration</dt><dd class="font-medium text-slate-900">{{ (today_attendance.work_duration_minutes ~ ' min') if today_attendance and today_attendance.work_duration_minutes else '-' }}</dd></div>
|
||||
</dl>
|
||||
<button type="button" data-tab="attendance" class="employee-portal-tab mt-5 inline-flex af-btn af-btn-secondary">View Attendance Details</button>
|
||||
</div>
|
||||
|
||||
<div class="af-card">
|
||||
<h3 class="font-semibold text-slate-900">Profile Summary</h3>
|
||||
<dl class="mt-4 grid gap-4 text-sm">
|
||||
<div><dt class="text-slate-500">Name</dt><dd class="font-medium text-slate-900">{{ employee.full_name }}</dd></div>
|
||||
<div><dt class="text-slate-500">Code / Status</dt><dd class="font-medium text-slate-900">{{ employee.employee_code }} · {{ employee.status.replace('_',' ').title() }}</dd></div>
|
||||
<div><dt class="text-slate-500">Designation</dt><dd class="font-medium text-slate-900">{{ employee.designation or '-' }}</dd></div>
|
||||
<div><dt class="text-slate-500">Email</dt><dd class="font-medium text-slate-900">{{ employee.email or current_user.email }}</dd></div>
|
||||
<div><dt class="text-slate-500">Mobile</dt><dd class="font-medium text-slate-900">{{ employee.mobile or current_user.mobile or '-' }}</dd></div>
|
||||
</dl>
|
||||
<a href="/employee/profile" class="mt-5 inline-flex af-btn af-btn-secondary">Update My Profile</a>
|
||||
</div>
|
||||
|
||||
<div class="af-card">
|
||||
<h3 class="font-semibold text-slate-900">Quick Links</h3>
|
||||
<div class="mt-4 grid gap-2 text-sm">
|
||||
<a href="/employee/documents" class="rounded-xl border border-slate-200 px-4 py-3 font-semibold text-slate-700 hover:bg-slate-50">My Documents</a>
|
||||
<a href="/employee/payslips" class="rounded-xl border border-slate-200 px-4 py-3 font-semibold text-slate-700 hover:bg-slate-50">My Payslips</a>
|
||||
<a href="/alerts" class="rounded-xl border border-slate-200 px-4 py-3 font-semibold text-slate-700 hover:bg-slate-50">My Alert</a>
|
||||
</div>
|
||||
<button type="button" data-tab="profile" class="employee-portal-tab mt-5 inline-flex af-btn af-btn-secondary">Update My Profile</button>
|
||||
</div>
|
||||
</aside>
|
||||
</section>
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<div class="flex flex-wrap items-center justify-between gap-3">
|
||||
<div><h3 class="text-lg font-semibold text-slate-900">My Reports</h3><p class="mt-1 text-sm text-slate-600">Quick self-service report shortcuts for your own work, attendance, leave, documents and payslips.</p></div>
|
||||
</div>
|
||||
<div class="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
|
||||
<a href="/employee/work" class="rounded-2xl border border-slate-200 bg-white p-5 shadow-soft hover:border-brand-200"><div class="text-xs font-semibold uppercase text-slate-500">Work Report</div><h4 class="mt-2 text-base font-semibold text-slate-900">My Pending / Completed Work</h4><p class="mt-1 text-sm text-slate-600">Open your work board and filter by status or due date.</p></a>
|
||||
<a href="/employee/attendance" class="rounded-2xl border border-slate-200 bg-white p-5 shadow-soft hover:border-brand-200"><div class="text-xs font-semibold uppercase text-slate-500">Attendance Report</div><h4 class="mt-2 text-base font-semibold text-slate-900">My Attendance History</h4><p class="mt-1 text-sm text-slate-600">View punch records, approval status and attendance remarks.</p></a>
|
||||
<a href="/employee/leave" class="rounded-2xl border border-slate-200 bg-white p-5 shadow-soft hover:border-brand-200"><div class="text-xs font-semibold uppercase text-slate-500">Leave Report</div><h4 class="mt-2 text-base font-semibold text-slate-900">My Leave Balances</h4><p class="mt-1 text-sm text-slate-600">Review balances and leave request history.</p></a>
|
||||
<a href="/employee/documents" class="rounded-2xl border border-slate-200 bg-white p-5 shadow-soft hover:border-brand-200"><div class="text-xs font-semibold uppercase text-slate-500">Document Report</div><h4 class="mt-2 text-base font-semibold text-slate-900">My Documents</h4><p class="mt-1 text-sm text-slate-600">View uploaded documents and verification status.</p></a>
|
||||
<a href="/employee/payslips" class="rounded-2xl border border-slate-200 bg-white p-5 shadow-soft hover:border-brand-200"><div class="text-xs font-semibold uppercase text-slate-500">Payroll Report</div><h4 class="mt-2 text-base font-semibold text-slate-900">My Payslips</h4><p class="mt-1 text-sm text-slate-600">Open available payslips and payment status.</p></a>
|
||||
<a href="/alerts" class="rounded-2xl border border-slate-200 bg-white p-5 shadow-soft hover:border-brand-200"><div class="text-xs font-semibold uppercase text-slate-500">Alert Report</div><h4 class="mt-2 text-base font-semibold text-slate-900">My Alerts</h4><p class="mt-1 text-sm text-slate-600">View task, attendance, leave and system alerts.</p></a>
|
||||
</div>
|
||||
@@ -0,0 +1,25 @@
|
||||
{% if not employee %}
|
||||
<div class="rounded-2xl border border-amber-200 bg-amber-50 p-6 text-sm text-amber-900 shadow-soft">Your login is not linked to an employee profile yet.</div>
|
||||
{% else %}
|
||||
<div class="flex flex-wrap items-center justify-between gap-3">
|
||||
<div><h3 class="text-lg font-semibold text-slate-900">Returned / Correction Work</h3><p class="mt-1 text-sm text-slate-600">Your current workflow uses blocked status for correction, clarification and returned work. Use this page to clear them.</p></div>
|
||||
<a href="/employee/work?status=blocked" class="af-btn af-btn-primary">Open Full Board</a>
|
||||
</div>
|
||||
<div class="rounded-2xl border border-slate-200 bg-white shadow-soft overflow-hidden">
|
||||
<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">Client</th><th class="px-4 py-3">Service</th><th class="px-4 py-3">FY</th><th class="px-4 py-3">Blocked</th><th class="px-4 py-3">Overdue</th><th class="px-4 py-3">Action</th></tr></thead>
|
||||
<tbody class="divide-y divide-slate-100">
|
||||
{% set ns = namespace(count=0) %}
|
||||
{% if work_payload %}
|
||||
{% for column in work_payload.columns if column.code == 'blocked' %}
|
||||
{% for card in column.cards %}
|
||||
{% set ns.count = ns.count + 1 %}
|
||||
<tr class="hover:bg-slate-50"><td class="px-4 py-3 font-medium text-slate-900">{{ card.client_name }}</td><td class="px-4 py-3 text-slate-600">{{ card.service_name }}</td><td class="px-4 py-3 text-slate-600">{{ card.financial_year }}</td><td class="px-4 py-3 text-amber-700 font-semibold">{{ card.blocked_count }}</td><td class="px-4 py-3 text-red-700 font-semibold">{{ card.overdue_count }}</td><td class="px-4 py-3"><a href="/employee/work/engagements/{{ card.engagement_id }}" class="rounded-xl bg-brand-600 px-3 py-2 text-xs font-semibold text-white hover:bg-brand-700">Open</a></td></tr>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if ns.count == 0 %}<tr><td colspan="6" class="px-4 py-8 text-center text-slate-500">No returned or blocked work is pending.</td></tr>{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -40,7 +40,7 @@
|
||||
<div class="text-sm font-semibold text-slate-900">{{ card.service_name }}</div>
|
||||
<div class="mt-1 text-xs text-slate-500">FY {{ card.financial_year }} · Due {{ card.due_date or '-' }}</div>
|
||||
</div>
|
||||
<a href="/work/engagements/{{ card.engagement_id }}" class="mt-4 inline-flex w-full justify-center rounded-xl bg-brand-600 px-4 py-2 text-sm font-semibold text-white hover:bg-brand-700">Open Work Details</a>
|
||||
<a href="/employee/work/engagements/{{ card.engagement_id }}" class="mt-4 inline-flex w-full justify-center rounded-xl bg-brand-600 px-4 py-2 text-sm font-semibold text-white hover:bg-brand-700">Open Work Details</a>
|
||||
</article>
|
||||
{% else %}
|
||||
<div class="rounded-2xl border border-dashed border-slate-300 bg-white p-6 text-center text-sm text-slate-500">No cards in this column.</div>
|
||||
|
||||
@@ -2473,9 +2473,14 @@ def employee_status_submit(
|
||||
|
||||
|
||||
|
||||
|
||||
EMPLOYEE_PORTAL_TABS = {
|
||||
"overview": "modules/employees/templates/employees/portal_partials/overview.html",
|
||||
"work": "modules/employees/templates/employees/portal_partials/work.html",
|
||||
"due-today": "modules/employees/templates/employees/portal_partials/due_today.html",
|
||||
"overdue": "modules/employees/templates/employees/portal_partials/overdue.html",
|
||||
"client-pending": "modules/employees/templates/employees/portal_partials/client_pending.html",
|
||||
"returned": "modules/employees/templates/employees/portal_partials/returned.html",
|
||||
"attendance": "modules/employees/templates/employees/portal_partials/attendance.html",
|
||||
"profile": "modules/employees/templates/employees/portal_partials/profile.html",
|
||||
"leave": "modules/employees/templates/employees/portal_partials/leave.html",
|
||||
@@ -2483,6 +2488,7 @@ EMPLOYEE_PORTAL_TABS = {
|
||||
"payslips": "modules/employees/templates/employees/portal_partials/payslips.html",
|
||||
"offboarding": "modules/employees/templates/employees/portal_partials/offboarding.html",
|
||||
"alerts": "modules/employees/templates/employees/portal_partials/alerts.html",
|
||||
"reports": "modules/employees/templates/employees/portal_partials/reports.html",
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user