MIF_E31222851/resources/views/admin/dashboard.blade.php

385 lines
25 KiB
PHP

@extends('layouts.app')
@section('title', 'Admin Dashboard - Sistem Antrian Puskesmas')
@section('content')
<div class="min-h-screen bg-gray-50">
@include('admin.partials.top-nav')
<div class="flex">
@include('admin.partials.sidebar')
<!-- Main Content -->
<div class="flex-1 lg:ml-0">
<div class="px-4 sm:px-6 lg:px-8 py-6 md:py-8">
<!-- Header -->
<div class="mb-8 animate-fade-in">
<h1 class="text-3xl md:text-4xl font-bold text-gray-900 mb-2">Admin Dashboard</h1>
<p class="text-gray-600 text-lg">Kelola sistem antrian Puskesmas</p>
</div>
<!-- Poli Summary -->
<div class="grid grid-cols-2 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
<div class="bg-white rounded-2xl shadow-xl p-6 flex flex-col lg:flex-row items-center lg:items-start justify-center lg:justify-start text-center lg:text-left"
data-poli-count="umum">
<div class="p-3 rounded-full bg-blue-100 text-blue-600 mb-2 lg:mb-0 lg:mr-4">
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path>
</svg>
</div>
<div>
<p class="text-sm text-gray-500">Poli Umum</p>
<p class="text-2xl font-bold text-gray-900">{{ $poliUmumCount ?? 0 }}</p>
<p class="text-xs text-gray-400">Antrian menunggu</p>
</div>
</div>
<div class="bg-white rounded-2xl shadow-xl p-6 flex flex-col lg:flex-row items-center lg:items-start justify-center lg:justify-start text-center lg:text-left"
data-poli-count="gigi">
<div class="p-3 rounded-full bg-green-100 text-green-600 mb-2 lg:mb-0 lg:mr-4">
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path>
</svg>
</div>
<div>
<p class="text-sm text-gray-500">Poli Gigi</p>
<p class="text-2xl font-bold text-gray-900">{{ $poliGigiCount ?? 0 }}</p>
<p class="text-xs text-gray-400">Antrian menunggu</p>
</div>
</div>
<div class="bg-white rounded-2xl shadow-xl p-6 flex flex-col lg:flex-row items-center lg:items-start justify-center lg:justify-start text-center lg:text-left"
data-poli-count="jiwa">
<div class="p-3 rounded-full bg-purple-100 text-purple-600 mb-2 lg:mb-0 lg:mr-4">
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path>
</svg>
</div>
<div>
<p class="text-sm text-gray-500">Poli Jiwa</p>
<p class="text-2xl font-bold text-gray-900">{{ $poliJiwaCount ?? 0 }}</p>
<p class="text-xs text-gray-400">Antrian menunggu</p>
</div>
</div>
<div class="bg-white rounded-2xl shadow-xl p-6 flex flex-col lg:flex-row items-center lg:items-start justify-center lg:justify-start text-center lg:text-left"
data-poli-count="tradisional">
<div class="p-3 rounded-full bg-yellow-100 text-yellow-600 mb-2 lg:mb-0 lg:mr-4">
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path>
</svg>
</div>
<div>
<p class="text-sm text-gray-500">Poli Tradisional</p>
<p class="text-2xl font-bold text-gray-900">{{ $poliTradisionalCount ?? 0 }}</p>
<p class="text-xs text-gray-400">Antrian menunggu</p>
</div>
</div>
</div>
<!-- Quick Actions -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-8">
<div class="bg-white rounded-2xl shadow-xl p-6">
<div class="flex items-center mb-4">
<div class="p-3 rounded-full bg-blue-100 text-blue-600">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
</svg>
</div>
<h3 class="text-lg font-semibold text-gray-900 ml-3">Tambah Antrian</h3>
</div>
<p class="text-gray-600 mb-4">Bantu pasien yang tidak bisa antri online</p>
<a href="{{ route('admin.antrian.tambah') }}"
class="inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition duration-200">
Tambah Antrian
<svg class="w-4 h-4 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7">
</path>
</svg>
</a>
</div>
<div class="bg-white rounded-2xl shadow-xl p-6">
<div class="flex items-center mb-4">
<div class="p-3 rounded-full bg-green-100 text-green-600">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z">
</path>
</svg>
</div>
<h3 class="text-lg font-semibold text-gray-900 ml-3">Display Antrian</h3>
</div>
<p class="text-gray-600 mb-4">Lihat display antrian untuk pasien</p>
<a href="{{ route('display') }}"
class="inline-flex items-center px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition duration-200">
Lihat Display
<svg class="w-4 h-4 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 5l7 7-7 7"></path>
</svg>
</a>
</div>
<div class="bg-white rounded-2xl shadow-xl p-6">
<div class="flex items-center mb-4">
<div class="p-3 rounded-full bg-purple-100 text-purple-600">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 17v-2m3 2v-4m3 4v-6m2 10H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z">
</path>
</svg>
</div>
<h3 class="text-lg font-semibold text-gray-900 ml-3">Laporan</h3>
</div>
<p class="text-gray-600 mb-4">Lihat laporan dan statistik antrian</p>
<a href="{{ route('admin.laporan.index') }}"
class="inline-flex items-center px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition duration-200">
Lihat Laporan
<svg class="w-4 h-4 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 5l7 7-7 7"></path>
</svg>
</a>
</div>
</div>
<!-- Recent Activity -->
<div class="bg-white rounded-2xl shadow-xl p-6">
<h3 class="text-lg font-semibold text-gray-900 mb-4">Aktivitas Terbaru</h3>
<div class="space-y-4" data-recent-activity>
@if (isset($antrianTerbaru) && $antrianTerbaru->count() > 0)
@foreach ($antrianTerbaru as $antrian)
<div class="flex items-center p-4 bg-gray-50 rounded-lg">
@if ($antrian->status == 'menunggu')
<div class="p-2 rounded-full bg-blue-100 text-blue-600">
<svg class="w-4 h-4" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
</svg>
</div>
<div class="ml-3">
<p class="text-sm font-medium text-gray-900">Antrian baru ditambahkan</p>
<p class="text-xs text-gray-500">{{ $antrian->poli->nama_poli }} -
{{ $antrian->created_at->diffForHumans() }}</p>
</div>
@elseif($antrian->status == 'dipanggil')
<div class="p-2 rounded-full bg-yellow-100 text-yellow-600">
<svg class="w-4 h-4" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
</div>
<div class="ml-3">
<p class="text-sm font-medium text-gray-900">Antrian dipanggil</p>
<p class="text-xs text-gray-500">{{ $antrian->poli->nama_poli }} -
{{ $antrian->updated_at->diffForHumans() }}</p>
</div>
@elseif($antrian->status == 'selesai')
<div class="p-2 rounded-full bg-green-100 text-green-600">
<svg class="w-4 h-4" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M5 13l4 4L19 7"></path>
</svg>
</div>
<div class="ml-3">
<p class="text-sm font-medium text-gray-900">Antrian selesai</p>
<p class="text-xs text-gray-500">{{ $antrian->poli->nama_poli }} -
{{ $antrian->updated_at->diffForHumans() }}</p>
</div>
@elseif($antrian->status == 'sedang_diperiksa')
<div class="p-2 rounded-full bg-purple-100 text-purple-600">
<svg class="w-4 h-4" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
</div>
<div class="ml-3">
<p class="text-sm font-medium text-gray-900">Sedang diperiksa</p>
<p class="text-xs text-gray-500">{{ $antrian->poli->nama_poli }} -
{{ $antrian->updated_at->diffForHumans() }}</p>
</div>
@elseif($antrian->status == 'batal')
<div class="p-2 rounded-full bg-red-100 text-red-600">
<svg class="w-4 h-4" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M6 18L18 6M6 6l12 12"></path>
</svg>
</div>
<div class="ml-3">
<p class="text-sm font-medium text-gray-900">Antrian dibatalkan</p>
<p class="text-xs text-gray-500">{{ $antrian->poli->nama_poli }} -
{{ $antrian->updated_at->diffForHumans() }}</p>
</div>
@else
<div class="p-2 rounded-full bg-gray-100 text-gray-600">
<svg class="w-4 h-4" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z">
</path>
</svg>
</div>
<div class="ml-3">
<p class="text-sm font-medium text-gray-900">Status tidak dikenal</p>
<p class="text-xs text-gray-500">{{ $antrian->poli->nama_poli }} -
{{ $antrian->updated_at->diffForHumans() }}</p>
</div>
@endif
</div>
@endforeach
@else
<div class="flex items-center justify-center p-6 bg-gray-50 rounded-lg">
<div class="text-center">
<svg class="w-8 h-8 mx-auto text-gray-400 mb-2" fill="none"
stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z">
</path>
</svg>
<p class="text-gray-500 text-sm">Belum ada aktivitas hari ini</p>
</div>
</div>
@endif
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Logout Form -->
<form id="logout-form" method="POST" action="{{ route('logout') }}" class="hidden">
@csrf
</form>
@include('admin.partials.sidebar-script')
@push('scripts')
<script>
// Auto refresh dashboard data every 30 seconds
function refreshDashboard() {
fetch('{{ route('admin.dashboard.api') }}', {
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'application/json'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Update poli counts
updatePoliCount('umum', data.data.poliUmumCount);
updatePoliCount('gigi', data.data.poliGigiCount);
updatePoliCount('jiwa', data.data.poliJiwaCount);
updatePoliCount('tradisional', data.data.poliTradisionalCount);
// Update recent activities
updateRecentActivities(data.data.antrianTerbaru);
}
})
.catch(error => {
console.log('Dashboard refresh error:', error);
});
}
function updatePoliCount(poliType, count) {
const countElement = document.querySelector(`[data-poli-count="${poliType}"] .text-2xl`);
if (countElement) {
countElement.textContent = count;
}
}
function updateRecentActivities(activities) {
const container = document.querySelector('[data-recent-activity]');
if (!container) return;
if (activities && activities.length > 0) {
container.innerHTML = activities.map(antrian => {
let iconColor, iconPath, statusText;
switch (antrian.status) {
case 'menunggu':
iconColor = 'bg-blue-100 text-blue-600';
iconPath = 'M12 6v6m0 0v6m0-6h6m-6 0H6';
statusText = 'Antrian baru ditambahkan';
break;
case 'dipanggil':
iconColor = 'bg-yellow-100 text-yellow-600';
iconPath = 'M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z';
statusText = 'Antrian dipanggil';
break;
case 'sedang_diperiksa':
iconColor = 'bg-purple-100 text-purple-600';
iconPath = 'M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z';
statusText = 'Sedang diperiksa';
break;
case 'selesai':
iconColor = 'bg-green-100 text-green-600';
iconPath = 'M5 13l4 4L19 7';
statusText = 'Antrian selesai';
break;
case 'batal':
iconColor = 'bg-red-100 text-red-600';
iconPath = 'M6 18L18 6M6 6l12 12';
statusText = 'Antrian dibatalkan';
break;
default:
iconColor = 'bg-gray-100 text-gray-600';
iconPath =
'M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z';
statusText = 'Status tidak dikenal';
}
return `
<div class="flex items-center p-4 bg-gray-50 rounded-lg">
<div class="p-2 rounded-full ${iconColor}">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="${iconPath}"></path>
</svg>
</div>
<div class="ml-3">
<p class="text-sm font-medium text-gray-900">${statusText}</p>
<p class="text-xs text-gray-500">${antrian.poli_name} - ${antrian.created_at}</p>
</div>
</div>
`;
}).join('');
} else {
container.innerHTML = `
<div class="flex items-center justify-center p-6 bg-gray-50 rounded-lg">
<div class="text-center">
<svg class="w-8 h-8 mx-auto text-gray-400 mb-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
</svg>
<p class="text-gray-500 text-sm">Belum ada aktivitas hari ini</p>
</div>
</div>
`;
}
}
// Start auto refresh
setInterval(refreshDashboard, 30000); // Refresh every 30 seconds
// Also refresh when page becomes visible (user switches back to tab)
document.addEventListener('visibilitychange', function() {
if (!document.hidden) {
refreshDashboard();
}
});
</script>
@endpush
@endsection