Initial commit

This commit is contained in:
sas.fajri
2026-04-30 14:27:01 +07:00
commit e29e943c27
70 changed files with 8909 additions and 0 deletions

View File

@@ -0,0 +1,37 @@
{{define "arrivals"}}
<div class="flex items-center justify-between border-b border-slate-100 px-5 py-3">
<h2 class="text-sm font-semibold text-slate-700">Arrival List</h2>
<div class="flex items-center gap-3">
{{if .IsLive}}
<span class="flex items-center gap-1.5 text-xs font-medium text-emerald-600">
<span class="live-dot h-1.5 w-1.5 rounded-full bg-emerald-500"></span> Live
</span>
{{end}}
<button onclick="openPatientsModal()"
class="text-xs font-medium text-brand-500 hover:text-brand-700 transition-colors">
Lihat selengkapnya
</button>
</div>
</div>
{{if .Rows}}
<ul class="divide-y divide-slate-50 px-3 py-2">
{{range .Rows}}
<li class="flex items-center gap-3 rounded-xl px-2 py-2.5 transition-colors hover:bg-slate-50">
<div class="flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-brand-50 text-xs font-bold text-brand-600">
{{.Name | initials}}
</div>
<div class="min-w-0 flex-1">
<p class="truncate text-sm font-medium text-slate-800">{{.Name}}</p>
<p class="text-xs text-slate-400">
<span class="num">{{fmtDateTime .Date .InTime}}</span> &bull; {{.Station | stationShort}}
</p>
</div>
</li>
{{end}}
</ul>
{{else}}
<div class="px-5 py-8 text-center text-sm text-slate-400">
Belum ada arrival pada tanggal ini.
</div>
{{end}}
{{end}}

View File

@@ -0,0 +1,43 @@
{{define "kpi"}}
<!-- Total Staff -->
<article class="card border-l-4 border-l-brand-300 p-4">
<div class="flex items-start justify-between">
<p class="text-xs font-semibold uppercase tracking-widest text-slate-400">Total Staff</p>
<svg class="h-4 w-4 text-brand-300" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z"/>
</svg>
</div>
<p class="num mt-3 text-3xl font-semibold text-slate-900">{{.TotalStaff}}</p>
{{if gt .InvitedStaff 0}}
<p class="mt-1 text-xs font-medium text-emerald-600">{{printf "%.1f%%" (pct .TotalStaff .InvitedStaff)}} dari invited</p>
{{else}}
<p class="mt-1 text-xs text-slate-400">Yang benar-benar datang</p>
{{end}}
</article>
<!-- Checked In -->
<article class="card border-l-4 border-l-brand-500 p-4">
<div class="flex items-start justify-between">
<p class="text-xs font-semibold uppercase tracking-widest text-slate-400">In Progress</p>
<svg class="h-4 w-4 text-brand-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
</div>
<p class="num mt-3 text-3xl font-semibold text-slate-900">{{.CheckedIn}}</p>
<p class="mt-1 text-xs text-slate-400">Masih dalam proses</p>
</article>
<!-- Checked Out -->
<article class="card border-l-4 border-l-emerald-500 p-4">
<div class="flex items-start justify-between">
<p class="text-xs font-semibold uppercase tracking-widest text-slate-400">Checked Out</p>
<svg class="h-4 w-4 text-emerald-500" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"/>
</svg>
</div>
<p class="num mt-3 text-3xl font-semibold text-slate-900">{{.CheckedOut}}</p>
{{if gt .CheckedIn 0}}
<p class="mt-1 text-xs text-slate-400">{{printf "%.1f%%" (pct .CheckedOut .CheckedIn)}} selesai</p>
{{end}}
</article>
{{end}}

View File

@@ -0,0 +1,80 @@
{{define "patients"}}
{{if not .Patients}}
<div class="flex flex-col items-center justify-center py-16 text-slate-400">
<svg class="mb-3 h-10 w-10 text-slate-300" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
<path stroke-linecap="round" stroke-linejoin="round" d="M15 19.128a9.38 9.38 0 002.625.372 9.337 9.337 0 004.121-.952 4.125 4.125 0 00-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 018.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0111.964-3.07M12 6.375a3.375 3.375 0 11-6.75 0 3.375 3.375 0 016.75 0zm8.25 2.25a2.625 2.625 0 11-5.25 0 2.625 2.625 0 015.25 0z"/>
</svg>
<p class="text-sm font-medium">Belum ada data pasien pada tanggal ini.</p>
</div>
{{else}}
<div class="divide-y divide-slate-100">
{{range .Patients}}
{{if and (gt .DoneCount 0) (eq .DoneCount (len .Stations))}}
<div class="px-5 py-4 bg-emerald-50/60 transition-colors hover:bg-emerald-50">
{{else}}
<div class="px-5 py-4 hover:bg-slate-50 transition-colors">
{{end}}
<!-- Row atas: nama + waktu -->
<div class="flex flex-wrap items-center justify-between gap-3">
<div class="flex items-center gap-2.5">
<div class="flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-brand-50 text-xs font-bold text-brand-600">
{{.Name | initials}}
</div>
<div>
<p class="font-semibold text-slate-800">{{.Name}}</p>
{{if $.IsRange}}<p class="text-xs text-slate-400 num">{{.Date | fmtDate}}</p>{{end}}
</div>
</div>
<div class="flex items-center gap-3 text-xs">
<span class="num text-slate-500">
Masuk: <span class="font-semibold text-slate-700">{{.InTime}}</span>
</span>
{{if .HasOut}}
<span class="inline-flex items-center gap-1 rounded-full bg-emerald-50 px-2.5 py-1 font-semibold text-emerald-700 num">
<svg class="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/></svg>
Keluar: {{.OutTime}}
</span>
{{else}}
<span class="inline-flex items-center gap-1 rounded-full bg-amber-50 px-2.5 py-1 font-semibold text-amber-600">
<span class="h-1.5 w-1.5 rounded-full bg-amber-400 animate-pulse"></span>
Dalam proses
</span>
{{end}}
<span class="text-slate-400">
<span class="font-semibold text-brand-600">{{.DoneCount}}</span>/{{len .Stations}} station selesai
</span>
</div>
</div>
<!-- Row bawah: station badges -->
{{if .Stations}}
<div class="mt-2.5 flex flex-wrap gap-1.5 pl-10">
{{range .Stations}}
{{if .Done}}
<span class="inline-flex max-w-full flex-col gap-0.5 rounded-full bg-emerald-100 px-2.5 py-1 text-xs font-medium text-emerald-800 cursor-default">
<span class="inline-flex items-center gap-1">
<svg class="h-3 w-3 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/></svg>
{{.Station}}
</span>
<span class="num pl-4 text-[10px] font-semibold text-emerald-700/80">
Proses: {{if .ProcessAt}}{{.ProcessAt}}{{else}}-{{end}} | Selesai: {{if .DoneAt}}{{.DoneAt}}{{else}}-{{end}}
</span>
</span>
{{else}}
<span class="inline-flex max-w-full flex-col gap-0.5 rounded-full bg-slate-100 px-2.5 py-1 text-xs font-medium text-slate-500 cursor-default">
<span class="inline-flex items-center gap-1">
<svg class="h-3 w-3 flex-shrink-0 text-slate-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6h4.5m4.5 0a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
{{.Station}}
</span>
<span class="num pl-4 text-[10px] font-semibold text-slate-400">
Proses: {{if .ProcessAt}}{{.ProcessAt}}{{else}}-{{end}} | Selesai: {{if .DoneAt}}{{.DoneAt}}{{else}}-{{end}}
</span>
</span>
{{end}}
{{end}}
</div>
{{end}}
</div>
{{end}}
</div>
{{end}}
{{end}}

View File

@@ -0,0 +1,53 @@
{{define "stations"}}
<div class="flex items-center justify-between border-b border-slate-100 px-5 py-3">
<h2 class="text-sm font-semibold text-slate-700">Station Status</h2>
{{if .IsLive}}
<span class="flex items-center gap-1.5 text-xs font-medium text-emerald-600">
<span class="live-dot h-1.5 w-1.5 rounded-full bg-emerald-500"></span> Live
</span>
{{end}}
</div>
{{if .Rows}}
<div class="p-3">
<table class="min-w-full text-sm">
<thead>
<tr class="text-left text-xs font-semibold uppercase tracking-wide text-slate-400">
<th class="px-3 py-2">Station</th>
<th class="px-3 py-2 text-right">Sudah</th>
<th class="px-3 py-2 text-right">Belum</th>
<th class="px-3 py-2 text-right">Total</th>
<th class="px-3 py-2 w-40">Progress</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-50">
{{range .Rows}}
<tr class="hover:bg-slate-50 transition-colors">
<td class="px-3 py-2.5 font-medium text-slate-700">
{{.Station | stationShort}}
</td>
<td class="num px-3 py-2.5 text-right font-semibold text-slate-900">{{.Processed}}</td>
<td class="num px-3 py-2.5 text-right text-amber-600">{{.Pending}}</td>
<td class="num px-3 py-2.5 text-right text-slate-400">{{.Total}}</td>
<td class="px-3 py-2.5">
<div class="flex items-center gap-2">
<div class="h-1.5 flex-1 overflow-hidden rounded-full bg-slate-100">
<div class="h-full rounded-full transition-all"
style="width: {{printf "%.1f" .Pct}}%; background: {{if ge .Pct 90.0}}#10b981{{else if ge .Pct 60.0}}#3b50a0{{else}}#f59e0b{{end}}">
</div>
</div>
<span class="num text-xs font-semibold {{if ge .Pct 90.0}}text-emerald-600{{else if ge .Pct 60.0}}text-brand-600{{else}}text-amber-600{{end}}">
{{printf "%.0f%%" .Pct}}
</span>
</div>
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
{{else}}
<div class="px-5 py-8 text-center text-sm text-slate-400">
Belum ada data station pada tanggal ini.
</div>
{{end}}
{{end}}