257 lines
15 KiB
PHP
257 lines
15 KiB
PHP
<!DOCTYPE html>
|
|
<html lang="id">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>@yield('title', 'INUFA Admin')</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
@stack('styles')
|
|
</head>
|
|
<body class="bg-gray-100">
|
|
<div class="flex h-screen">
|
|
<!-- Admin Sidebar -->
|
|
<div class="w-64 h-full bg-white shadow-md">
|
|
<!-- Logo -->
|
|
<div class="p-4 flex justify-center">
|
|
<img src="{{ asset('assets/images/logo.png') }}" alt="INUFA Logo" class="w-28 h-28 object-contain">
|
|
</div>
|
|
|
|
<!-- Admin Menu -->
|
|
<nav class="mt-4">
|
|
<a href="{{ route('admin.dashboard') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('admin.dashboard') ? 'bg-blue-800 text-white' : '' }}">
|
|
<div class="flex items-center">
|
|
<svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2H5a2 2 0 00-2-2z" />
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 5a2 2 0 012-2h4a2 2 0 012 2v2H8V5z" />
|
|
</svg>
|
|
Dashboard
|
|
</div>
|
|
</a>
|
|
<a href="{{ route('pengguna') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('pengguna*') ? 'bg-blue-800 text-white' : '' }}">
|
|
<div class="flex items-center">
|
|
<svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z" />
|
|
</svg>
|
|
Manajemen User
|
|
</div>
|
|
</a>
|
|
<a href="{{ route('paket.index') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('paket*') ? 'bg-blue-800 text-white' : '' }}">
|
|
<div class="flex items-center">
|
|
<svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4" />
|
|
</svg>
|
|
Manajemen Paket
|
|
</div>
|
|
</a>
|
|
<a href="{{ route('input-stock') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('input-stock*') ? 'bg-blue-800 text-white' : '' }}">
|
|
<div class="flex items-center">
|
|
<svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" />
|
|
</svg>
|
|
Manajemen Stock
|
|
</div>
|
|
</a>
|
|
<a href="{{ route('sewa.index') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('sewa.*') ? 'bg-blue-800 text-white' : '' }}">
|
|
<div class="flex items-center">
|
|
<svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
|
|
</svg>
|
|
Manajemen Sewa
|
|
</div>
|
|
</a>
|
|
<a href="{{ route('riwayat') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('riwayat') ? 'bg-blue-800 text-white' : '' }}">
|
|
<div class="flex items-center">
|
|
<svg class="w-5 h-5 mr-3" 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" />
|
|
</svg>
|
|
Laporan
|
|
</div>
|
|
</a>
|
|
<a href="{{ route('admin.verifikasi.index') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('admin.verifikasi.*') ? 'bg-blue-800 text-white' : '' }}">
|
|
<div class="flex items-center">
|
|
<svg class="w-5 h-5 mr-3" 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" />
|
|
</svg>
|
|
Verifikasi Pembayaran
|
|
</div>
|
|
</a>
|
|
|
|
<!-- Menu Pesanan Dibatalkan dengan styling khusus -->
|
|
<div class="border-t border-gray-200 my-2"></div>
|
|
<a href="{{ route('admin.cancelled-orders') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-red-50 hover:text-red-700 {{ request()->routeIs('admin.cancelled-orders*') ? 'bg-red-100 text-red-700 border-r-4 border-red-500' : '' }}">
|
|
<div class="flex items-center justify-between">
|
|
<div class="flex items-center">
|
|
<svg class="w-5 h-5 mr-3" 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" />
|
|
</svg>
|
|
<span>Pesanan Dibatalkan</span>
|
|
</div>
|
|
<span id="cancelled-orders-badge" class="hidden bg-red-500 text-white text-xs rounded-full px-2 py-1 font-bold">0</span>
|
|
</div>
|
|
</a>
|
|
|
|
<a href="{{ route('contact.index') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('contact.*') ? 'bg-blue-800 text-white' : '' }}">
|
|
<div class="flex items-center">
|
|
<svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 4.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
|
</svg>
|
|
Kelola Kontak
|
|
</div>
|
|
</a>
|
|
</nav>
|
|
</div>
|
|
|
|
<!-- Main Content -->
|
|
<div class="flex-1 flex flex-col">
|
|
<!-- Header -->
|
|
<header class="bg-white shadow-sm py-4 px-6 flex justify-between items-center">
|
|
<div class="flex space-x-8">
|
|
<h1 class="text-xl font-bold text-gray-800">@yield('header', 'Admin Dashboard')</h1>
|
|
</div>
|
|
<div class="flex items-center space-x-4">
|
|
<!-- Notifikasi Pembatalan di Header -->
|
|
<a href="{{ route('admin.cancelled-orders') }}" class="relative flex items-center space-x-2 px-3 py-2 bg-red-50 hover:bg-red-100 rounded-lg transition-colors">
|
|
<svg class="w-5 h-5 text-red-600" 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" />
|
|
</svg>
|
|
<span class="text-red-700 font-medium">Pesanan Dibatalkan</span>
|
|
<span id="header-cancelled-badge" class="hidden absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full px-2 py-1 font-bold">0</span>
|
|
</a>
|
|
|
|
<a href="{{ route('profile.index') }}" class="font-semibold text-gray-600 flex items-center space-x-2">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clip-rule="evenodd" />
|
|
</svg>
|
|
<span>Profile</span>
|
|
</a>
|
|
<form action="{{ route('logout') }}" method="POST" class="inline">
|
|
@csrf
|
|
<button type="submit" class="font-semibold text-gray-600 flex items-center space-x-2 hover:text-gray-800">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M3 3a1 1 0 00-1 1v12a1 1 0 102 0V4a1 1 0 00-1-1zm10.293 9.293a1 1 0 001.414 1.414l3-3a1 1 0 000-1.414l-3-3a1 1 0 10-1.414 1.414L14.586 9H7a1 1 0 100 2h7.586l-1.293 1.293z" clip-rule="evenodd" />
|
|
</svg>
|
|
<span>Logout</span>
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Content -->
|
|
<main class="flex-1 p-6 bg-gray-100 overflow-auto">
|
|
@if(session('success'))
|
|
<div class="bg-green-100 border-l-4 border-green-500 text-green-700 p-4 mb-4 rounded" role="alert">
|
|
<p>{{ session('success') }}</p>
|
|
</div>
|
|
@endif
|
|
|
|
@if(session('warning'))
|
|
<div class="bg-yellow-100 border-l-4 border-yellow-500 text-yellow-700 p-4 mb-4 rounded" role="alert">
|
|
<p>{{ session('warning') }}</p>
|
|
</div>
|
|
@endif
|
|
|
|
@if(session('error'))
|
|
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4 mb-4 rounded" role="alert">
|
|
<p>{{ session('error') }}</p>
|
|
</div>
|
|
@endif
|
|
|
|
@yield('content')
|
|
</main>
|
|
</div>
|
|
</div>
|
|
|
|
@stack('scripts')
|
|
|
|
<script>
|
|
// Notifikasi real-time untuk pesanan yang dibatalkan
|
|
function updateCancelledOrdersBadge() {
|
|
fetch('{{ route("admin.cancelled-orders.count") }}')
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
const badge = document.getElementById('cancelled-orders-badge');
|
|
if (data.count > 0) {
|
|
badge.textContent = data.count;
|
|
badge.classList.remove('hidden');
|
|
} else {
|
|
badge.classList.add('hidden');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error fetching cancelled orders count:', error);
|
|
});
|
|
}
|
|
|
|
// Update badge setiap 30 detik
|
|
setInterval(updateCancelledOrdersBadge, 30000);
|
|
|
|
// Update badge saat halaman dimuat
|
|
document.addEventListener('DOMContentLoaded', updateCancelledOrdersBadge);
|
|
</script>
|
|
|
|
<script>
|
|
// Notifikasi toast untuk pembatalan pesanan
|
|
let lastCancellationCount = 0;
|
|
|
|
function checkNewCancellations() {
|
|
fetch('{{ route("admin.recent-cancellations") }}')
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.cancellations && data.cancellations.length > 0) {
|
|
const latestCancellation = data.cancellations[0];
|
|
|
|
// Tampilkan toast notifikasi
|
|
showToast(
|
|
'Pesanan Dibatalkan',
|
|
`${latestCancellation.user_name} membatalkan pesanan #${latestCancellation.id} (${latestCancellation.paket_name})`
|
|
);
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error checking cancellations:', error);
|
|
});
|
|
}
|
|
|
|
function showToast(title, message) {
|
|
document.getElementById('toast-title').textContent = title;
|
|
document.getElementById('toast-message').textContent = message;
|
|
document.getElementById('toast').classList.remove('hidden');
|
|
|
|
// Auto hide setelah 5 detik
|
|
setTimeout(hideToast, 5000);
|
|
}
|
|
|
|
function hideToast() {
|
|
document.getElementById('toast').classList.add('hidden');
|
|
}
|
|
|
|
// Check pembatalan baru setiap 60 detik
|
|
setInterval(checkNewCancellations, 60000);
|
|
|
|
// Check saat halaman dimuat
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
setTimeout(checkNewCancellations, 5000); // Check setelah 5 detik
|
|
});
|
|
</script>
|
|
|
|
<!-- Toast Notification -->
|
|
<div id="toast" class="fixed top-4 right-4 z-50 hidden">
|
|
<div class="bg-red-500 text-white px-6 py-4 rounded-lg shadow-lg max-w-sm">
|
|
<div class="flex items-center">
|
|
<svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
|
|
</svg>
|
|
<div>
|
|
<h4 class="font-semibold" id="toast-title">Pesanan Dibatalkan</h4>
|
|
<p class="text-sm" id="toast-message">Ada pesanan baru yang dibatalkan oleh customer.</p>
|
|
</div>
|
|
<button onclick="hideToast()" class="ml-4 text-white hover:text-gray-200">
|
|
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|