Checkpoint
This commit is contained in:
parent
73b264107e
commit
6873f94b83
|
@ -0,0 +1,73 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\admin;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
class AdminProfileController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Display the admin profile page.
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$user = Auth::user();
|
||||||
|
return view('admin.profile.index', compact('user'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the admin profile information.
|
||||||
|
*/
|
||||||
|
public function updateProfile(Request $request)
|
||||||
|
{
|
||||||
|
$user = Auth::user();
|
||||||
|
|
||||||
|
$request->validate([
|
||||||
|
'name' => 'required|string|max:255',
|
||||||
|
'email' => [
|
||||||
|
'required',
|
||||||
|
'string',
|
||||||
|
'email',
|
||||||
|
'max:255',
|
||||||
|
Rule::unique('users')->ignore($user->id),
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user->update([
|
||||||
|
'name' => $request->name,
|
||||||
|
'email' => $request->email,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return redirect()->route('admin.profile.index')
|
||||||
|
->with('success', 'Profile berhasil diperbarui.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the admin password.
|
||||||
|
*/
|
||||||
|
public function updatePassword(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'current_password' => 'required',
|
||||||
|
'password' => 'required|string|min:8|confirmed',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user = Auth::user();
|
||||||
|
|
||||||
|
// Check if current password is correct
|
||||||
|
if (!Hash::check($request->current_password, $user->password)) {
|
||||||
|
return back()->withErrors(['current_password' => 'Password saat ini tidak sesuai.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->update([
|
||||||
|
'password' => Hash::make($request->password),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return redirect()->route('admin.profile.index')
|
||||||
|
->with('success', 'Password berhasil diperbarui.');
|
||||||
|
}
|
||||||
|
}
|
|
@ -63,7 +63,7 @@ public function index(Request $request)
|
||||||
$query->orderBy($sortColumn, $sortDirection);
|
$query->orderBy($sortColumn, $sortDirection);
|
||||||
}
|
}
|
||||||
|
|
||||||
$bookings = $query->paginate(10)->withQueryString();
|
$bookings = $query->paginate(20)->withQueryString();
|
||||||
|
|
||||||
return view('admin.bookings.index', compact('bookings'));
|
return view('admin.bookings.index', compact('bookings'));
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ public function index(Request $request)
|
||||||
$query->where('status', $request->status);
|
$query->where('status', $request->status);
|
||||||
}
|
}
|
||||||
|
|
||||||
$tables = $query->latest()->paginate(10);
|
$tables = $query->orderBy('created_at', 'asc')->paginate(10);
|
||||||
|
|
||||||
return view('admin.tables.index', compact('tables'));
|
return view('admin.tables.index', compact('tables'));
|
||||||
}
|
}
|
||||||
|
|
|
@ -251,13 +251,13 @@ class="inline">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="px-4 py-3 bg-gray-50 border-t border-gray-200">
|
<div class="px-4 py-3 bg-gray-50 border-t border-gray-200">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex flex-col md:flex-row items-center justify-between space-y-2 md:space-y-0">
|
||||||
<div class="text-sm text-gray-500">
|
<div class="text-sm text-gray-500">
|
||||||
Menampilkan {{ $bookings->firstItem() ?? 0 }} - {{ $bookings->lastItem() ?? 0 }} dari
|
Menampilkan {{ $bookings->firstItem() ?? 0 }} - {{ $bookings->lastItem() ?? 0 }} dari
|
||||||
{{ $bookings->total() }} data
|
{{ $bookings->total() }} data
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="flex justify-center">
|
||||||
{{ $bookings->appends(request()->query())->links() }}
|
{{ $bookings->appends(request()->query())->onEachSide(1)->links() }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,177 @@
|
||||||
|
@extends('layouts.admin')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="p-6">
|
||||||
|
<!-- Page Header -->
|
||||||
|
<div class="mb-8">
|
||||||
|
<h1 class="text-2xl font-bold text-gray-900">Pengaturan Profile</h1>
|
||||||
|
<p class="text-gray-600 mt-1">Kelola informasi akun dan keamanan Anda</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Flash Messages -->
|
||||||
|
@if(session('success'))
|
||||||
|
<div class="mb-6 bg-green-50 border border-green-200 text-green-700 px-4 py-3 rounded-lg">
|
||||||
|
{{ session('success') }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||||
|
<!-- Profile Information Card -->
|
||||||
|
<div class="bg-white rounded-lg shadow-sm border border-gray-200">
|
||||||
|
<div class="p-6 border-b border-gray-200">
|
||||||
|
<h2 class="text-lg font-semibold text-gray-900">Informasi Profile</h2>
|
||||||
|
<p class="text-sm text-gray-600 mt-1">Perbarui informasi dasar akun Anda</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form action="{{ route('admin.profile.update') }}" method="POST" class="p-6">
|
||||||
|
@csrf
|
||||||
|
@method('PUT')
|
||||||
|
|
||||||
|
<!-- Profile Avatar -->
|
||||||
|
<div class="flex items-center space-x-4 mb-6">
|
||||||
|
<div
|
||||||
|
class="w-16 h-16 bg-blue-600 rounded-full flex items-center justify-center text-white font-bold text-xl">
|
||||||
|
{{ substr($user->name, 0, 1) }}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="font-medium text-gray-900">{{ $user->name }}</h3>
|
||||||
|
<p class="text-sm text-gray-500">{{ ucfirst($user->role) }}</p>
|
||||||
|
@if($user->venue)
|
||||||
|
<p class="text-sm text-blue-600">{{ $user->venue->name }}</p>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Name Field -->
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="name" class="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Nama Lengkap
|
||||||
|
</label>
|
||||||
|
<input type="text" id="name" name="name" value="{{ old('name', $user->name) }}"
|
||||||
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent @error('name') border-red-500 @enderror">
|
||||||
|
@error('name')
|
||||||
|
<p class="text-red-500 text-sm mt-1">{{ $message }}</p>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Email Field -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<label for="email" class="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Email
|
||||||
|
</label>
|
||||||
|
<input type="email" id="email" name="email" value="{{ old('email', $user->email) }}"
|
||||||
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent @error('email') border-red-500 @enderror"
|
||||||
|
readonly>
|
||||||
|
@error('email')
|
||||||
|
<p class="text-red-500 text-sm mt-1">{{ $message }}</p>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Account Info -->
|
||||||
|
<div class="mb-6 p-4 bg-gray-50 rounded-lg">
|
||||||
|
<h4 class="font-medium text-gray-900 mb-2">Informasi Akun</h4>
|
||||||
|
<div class="text-sm text-gray-600 space-y-1">
|
||||||
|
<p><span class="font-medium">Role:</span> {{ ucfirst($user->role) }}</p>
|
||||||
|
<p><span class="font-medium">Bergabung:</span> {{ $user->created_at->format('d M Y') }}</p>
|
||||||
|
@if($user->email_verified_at)
|
||||||
|
<p><span class="font-medium">Status Email:</span>
|
||||||
|
<span class="text-green-600">✓ Terverifikasi</span>
|
||||||
|
</p>
|
||||||
|
@else
|
||||||
|
<p><span class="font-medium">Status Email:</span>
|
||||||
|
<span class="text-red-600">✗ Belum Terverifikasi</span>
|
||||||
|
</p>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Submit Button -->
|
||||||
|
<button type="submit"
|
||||||
|
class="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-lg transition duration-200">
|
||||||
|
Perbarui Profile
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Change Password Card -->
|
||||||
|
<div class="bg-white rounded-lg shadow-sm border border-gray-200">
|
||||||
|
<div class="p-6 border-b border-gray-200">
|
||||||
|
<h2 class="text-lg font-semibold text-gray-900">Ubah Password</h2>
|
||||||
|
<p class="text-sm text-gray-600 mt-1">Pastikan akun Anda menggunakan password yang kuat</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form action="{{ route('admin.profile.password') }}" method="POST" class="p-6">
|
||||||
|
@csrf
|
||||||
|
@method('PUT')
|
||||||
|
|
||||||
|
<!-- Current Password -->
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="current_password" class="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Password Saat Ini
|
||||||
|
</label>
|
||||||
|
<input type="password" id="current_password" name="current_password"
|
||||||
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent @error('current_password') border-red-500 @enderror">
|
||||||
|
@error('current_password')
|
||||||
|
<p class="text-red-500 text-sm mt-1">{{ $message }}</p>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- New Password -->
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="password" class="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Password Baru
|
||||||
|
</label>
|
||||||
|
<input type="password" id="password" name="password"
|
||||||
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent @error('password') border-red-500 @enderror">
|
||||||
|
@error('password')
|
||||||
|
<p class="text-red-500 text-sm mt-1">{{ $message }}</p>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Confirm Password -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<label for="password_confirmation" class="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Konfirmasi Password Baru
|
||||||
|
</label>
|
||||||
|
<input type="password" id="password_confirmation" name="password_confirmation"
|
||||||
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Password Requirements -->
|
||||||
|
<div class="mb-6 p-4 bg-yellow-50 border border-yellow-200 rounded-lg">
|
||||||
|
<h4 class="font-medium text-yellow-800 mb-2">Persyaratan Password:</h4>
|
||||||
|
<ul class="text-sm text-yellow-700 space-y-1">
|
||||||
|
<li>• Minimal 8 karakter</li>
|
||||||
|
<li>• Kombinasi huruf besar dan kecil</li>
|
||||||
|
<li>• Minimal satu angka</li>
|
||||||
|
<li>• Minimal satu karakter khusus</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Submit Button -->
|
||||||
|
<button type="submit"
|
||||||
|
class="w-full bg-red-600 hover:bg-red-700 text-white font-medium py-2 px-4 rounded-lg transition duration-200">
|
||||||
|
Ubah Password
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Security Notice -->
|
||||||
|
<div class="mt-8 bg-blue-50 border border-blue-200 rounded-lg p-6">
|
||||||
|
<div class="flex items-start space-x-3">
|
||||||
|
<svg class="w-5 h-5 text-blue-600 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||||
|
</svg>
|
||||||
|
<div>
|
||||||
|
<h3 class="font-medium text-blue-900">Tips Keamanan</h3>
|
||||||
|
<p class="text-sm text-blue-700 mt-1">
|
||||||
|
Selalu gunakan password yang unik dan kuat. Jangan bagikan informasi login Anda kepada siapa pun.
|
||||||
|
Jika Anda mencurigai adanya aktivitas yang tidak biasa, segera ubah password Anda.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
|
@ -189,8 +189,10 @@ class="ml-auto h-4 w-4 text-gray-500" fill="none" viewBox="0 0 24 24" stroke="cu
|
||||||
<!-- Dropdown -->
|
<!-- Dropdown -->
|
||||||
<div x-show="open" @click.outside="open = false"
|
<div x-show="open" @click.outside="open = false"
|
||||||
class="absolute bottom-full left-0 mb-1 w-full bg-white rounded-lg shadow-lg border border-gray-200 py-1 dropdown-transition">
|
class="absolute bottom-full left-0 mb-1 w-full bg-white rounded-lg shadow-lg border border-gray-200 py-1 dropdown-transition">
|
||||||
{{-- <a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Profile</a>
|
<a href="{{ route('admin.profile.index') }}"
|
||||||
<a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Settings</a> --}}
|
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Profile</a>
|
||||||
|
{{-- <a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Settings</a>
|
||||||
|
--}}
|
||||||
<div class="border-t border-gray-200 my-1"></div>
|
<div class="border-t border-gray-200 my-1"></div>
|
||||||
<form method="POST" action="{{ route('logout') }}">
|
<form method="POST" action="{{ route('logout') }}">
|
||||||
@csrf
|
@csrf
|
||||||
|
|
|
@ -7,178 +7,159 @@
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
<title>Super Admin Dashboard</title>
|
<title>Super Admin Dashboard</title>
|
||||||
<!-- Tailwind CSS via CDN -->
|
<!-- Tailwind CSS via CDN -->
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||||
<!-- FontAwesome Icons -->
|
<!-- FontAwesome Icons -->
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||||
<!-- Alpine.js -->
|
|
||||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/alpinejs/3.12.0/cdn.min.js"></script>
|
|
||||||
<!-- Google Fonts -->
|
<!-- Google Fonts -->
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||||
<style>
|
<style>
|
||||||
body { font-family: 'Inter', sans-serif; }
|
body {
|
||||||
|
font-family: 'Inter', sans-serif;
|
||||||
/* Custom scrollbar for sidebar */
|
|
||||||
.sidebar-scroll::-webkit-scrollbar {
|
|
||||||
width: 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-scroll::-webkit-scrollbar-track {
|
|
||||||
background: rgba(255, 255, 255, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-scroll::-webkit-scrollbar-thumb {
|
|
||||||
background: rgba(255, 255, 255, 0.3);
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hover effects */
|
|
||||||
.nav-item {
|
.nav-item {
|
||||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
transition: all 0.3s ease;
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item::before {
|
.nav-item.active {
|
||||||
|
position: relative;
|
||||||
|
background-color: rgb(239, 246, 255);
|
||||||
|
color: rgb(37, 99, 235);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item.active::before {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: -100%;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);
|
width: 4px;
|
||||||
transition: left 0.5s;
|
background-color: rgb(37, 99, 235);
|
||||||
|
border-radius: 0 4px 4px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item:hover::before {
|
.nav-item:hover:not(.active) {
|
||||||
left: 100%;
|
background-color: rgb(249, 250, 251);
|
||||||
|
color: rgb(55, 65, 81);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Active nav indicator */
|
.dropdown-transition {
|
||||||
.nav-active {
|
transition: all 0.2s ease-out;
|
||||||
background: rgba(255, 255, 255, 0.15);
|
|
||||||
border-right: 3px solid white;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Profile section gradient */
|
|
||||||
.profile-section {
|
|
||||||
background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.05));
|
|
||||||
backdrop-filter: blur(10px);
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="bg-gray-50">
|
<body x-data="{ sidebarOpen: true, userDropdownOpen: false }" class="bg-gray-50">
|
||||||
<div x-data="{ sidebarOpen: true }">
|
<div class="flex h-screen overflow-hidden">
|
||||||
|
<!-- Sidebar Overlay -->
|
||||||
|
<div x-show="sidebarOpen" @click="sidebarOpen = false"
|
||||||
|
class="fixed inset-0 z-20 bg-black bg-opacity-50 lg:hidden"></div>
|
||||||
|
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
<aside :class="sidebarOpen ? 'translate-x-0' : '-translate-x-full'"
|
<div :class="sidebarOpen ? 'translate-x-0' : '-translate-x-full lg:translate-x-0 lg:w-20'"
|
||||||
class="fixed top-0 left-0 z-40 w-72 h-screen transition-transform duration-300 ease-in-out bg-gradient-to-br from-slate-800 via-slate-700 to-slate-900 text-white shadow-2xl">
|
class="fixed inset-y-0 left-0 z-30 w-64 bg-white shadow-lg transition-all duration-300 transform lg:relative lg:translate-x-0">
|
||||||
|
|
||||||
<!-- Header -->
|
<!-- Sidebar Header -->
|
||||||
<div class="flex items-center justify-between p-6 border-b border-slate-600/30">
|
<div class="flex items-center justify-between h-16 px-4 border-b">
|
||||||
<div class="flex items-center space-x-3">
|
<div class="flex items-center space-x-2">
|
||||||
<div class="w-10 h-10 rounded-xl bg-gradient-to-br from-indigo-500 to-purple-600 flex items-center justify-center shadow-lg">
|
<span class="font-bold text-lg text-gray-800" x-show="sidebarOpen">Super Admin</span>
|
||||||
<i class="fas fa-cubes text-white text-lg"></i>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h2 class="text-xl font-bold bg-gradient-to-r from-white to-slate-300 bg-clip-text text-transparent">
|
|
||||||
VenueSystem
|
|
||||||
</h2>
|
|
||||||
<p class="text-xs text-slate-400 font-medium">Super Admin Panel</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<button @click="sidebarOpen = !sidebarOpen"
|
<button @click="sidebarOpen = !sidebarOpen" class="p-1 rounded-md hover:bg-gray-100 focus:outline-none">
|
||||||
class="lg:hidden w-8 h-8 rounded-lg bg-slate-600/50 hover:bg-slate-600 transition-colors flex items-center justify-center">
|
<svg x-show="sidebarOpen" xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-500"
|
||||||
<i class="fas fa-times text-sm"></i>
|
fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M11 19l-7-7 7-7m8 14l-7-7 7-7" />
|
||||||
|
</svg>
|
||||||
|
<svg x-show="!sidebarOpen" class="w-6 h-6 text-gray-500" fill="none" stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M4 6h16M4 12h16m-7 6h7"></path>
|
||||||
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Profile Section -->
|
<!-- Navigation -->
|
||||||
<div class="p-6">
|
<div class="px-2 py-4">
|
||||||
<div class="profile-section rounded-xl p-4 mb-6">
|
<div x-show="sidebarOpen"
|
||||||
<div class="flex items-center space-x-4">
|
class="text-xs font-semibold text-gray-400 uppercase tracking-wider px-3 mb-2">
|
||||||
<div class="relative">
|
Menu Utama
|
||||||
<div class="w-12 h-12 rounded-full bg-gradient-to-br from-emerald-400 to-cyan-500 flex items-center justify-center shadow-lg">
|
|
||||||
<i class="fas fa-user-shield text-white text-lg"></i>
|
|
||||||
</div>
|
|
||||||
<div class="absolute -bottom-1 -right-1 w-4 h-4 bg-green-400 rounded-full border-2 border-slate-800"></div>
|
|
||||||
</div>
|
|
||||||
<div class="flex-1">
|
|
||||||
<p class="font-semibold text-white">{{ auth()->user()->name ?? 'Admin' }}</p>
|
|
||||||
<p class="text-sm text-slate-300">Super Administrator</p>
|
|
||||||
<div class="mt-1">
|
|
||||||
<span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs bg-emerald-500/20 text-emerald-300 border border-emerald-500/30">
|
|
||||||
<span class="w-1.5 h-1.5 rounded-full bg-emerald-400 mr-1"></span>
|
|
||||||
Online
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<nav class="space-y-1">
|
||||||
<!-- Navigation -->
|
|
||||||
<nav class="space-y-2">
|
|
||||||
<div class="text-xs font-semibold text-slate-400 uppercase tracking-wider mb-4 px-3">
|
|
||||||
Main Navigation
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a href="{{ route('superadmin.dashboard') }}"
|
<a href="{{ route('superadmin.dashboard') }}"
|
||||||
class="nav-item flex items-center p-3 rounded-lg hover:bg-slate-600/30 {{ request()->routeIs('superadmin.dashboard') ? 'nav-active' : '' }} group">
|
class="nav-item flex items-center px-3 py-2.5 rounded-lg {{ request()->routeIs('superadmin.dashboard') ? 'active' : '' }}">
|
||||||
<div class="w-10 h-10 rounded-lg bg-gradient-to-br from-blue-500/20 to-blue-600/20 flex items-center justify-center group-hover:from-blue-500/30 group-hover:to-blue-600/30 transition-all">
|
<i class="fas fa-chart-line w-5 h-5 mr-2 text-sm"></i>
|
||||||
<i class="fas fa-chart-line text-blue-400 group-hover:text-blue-300"></i>
|
<span x-show="sidebarOpen">Dashboard</span>
|
||||||
</div>
|
|
||||||
<div class="ml-4">
|
|
||||||
<span class="font-medium text-slate-200 group-hover:text-white transition-colors">Dashboard</span>
|
|
||||||
<p class="text-xs text-slate-400 group-hover:text-slate-300">Analytics & Overview</p>
|
|
||||||
</div>
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('superadmin.venue.index') }}"
|
<a href="{{ route('superadmin.venue.index') }}"
|
||||||
class="nav-item flex items-center p-3 rounded-lg hover:bg-slate-600/30 {{ request()->routeIs('superadmin.venue.*') ? 'nav-active' : '' }} group">
|
class="nav-item flex items-center px-3 py-2.5 rounded-lg {{ request()->routeIs('superadmin.venue.*') ? 'active' : '' }}">
|
||||||
<div class="w-10 h-10 rounded-lg bg-gradient-to-br from-emerald-500/20 to-emerald-600/20 flex items-center justify-center group-hover:from-emerald-500/30 group-hover:to-emerald-600/30 transition-all">
|
<i class="fas fa-building w-5 h-5 mr-2 text-sm"></i>
|
||||||
<i class="fas fa-building text-emerald-400 group-hover:text-emerald-300"></i>
|
<span x-show="sidebarOpen">Manajemen Venue</span>
|
||||||
</div>
|
|
||||||
<div class="ml-4">
|
|
||||||
<span class="font-medium text-slate-200 group-hover:text-white transition-colors">Manajemen Venue</span>
|
|
||||||
<p class="text-xs text-slate-400 group-hover:text-slate-300">Kelola semua venue</p>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a href="{{ route('superadmin.admin.index') }}"
|
|
||||||
class="nav-item flex items-center p-3 rounded-lg hover:bg-slate-600/30 {{ request()->routeIs('superadmin.admin.*') ? 'nav-active' : '' }} group">
|
|
||||||
<div class="w-10 h-10 rounded-lg bg-gradient-to-br from-purple-500/20 to-purple-600/20 flex items-center justify-center group-hover:from-purple-500/30 group-hover:to-purple-600/30 transition-all">
|
|
||||||
<i class="fas fa-users-cog text-purple-400 group-hover:text-purple-300"></i>
|
|
||||||
</div>
|
|
||||||
<div class="ml-4">
|
|
||||||
<span class="font-medium text-slate-200 group-hover:text-white transition-colors">Manajemen Admin</span>
|
|
||||||
<p class="text-xs text-slate-400 group-hover:text-slate-300">Kelola admin venue</p>
|
|
||||||
</div>
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('logout') }}"
|
<a href="{{ route('superadmin.admin.index') }}"
|
||||||
onclick="event.preventDefault(); document.getElementById('logout-form').submit();"
|
class="nav-item flex items-center px-3 py-2.5 rounded-lg {{ request()->routeIs('superadmin.admin.*') ? 'active' : '' }}">
|
||||||
class="flex items-center p-3 rounded-lg hover:bg-red-700">
|
<i class="fas fa-users-cog w-5 h-5 mr-2 text-sm"></i>
|
||||||
<i class="fas fa-sign-out-alt w-5"></i>
|
<span x-show="sidebarOpen">Manajemen Admin</span>
|
||||||
<span class="ml-3">Logout</span>
|
</a>
|
||||||
<form id="logout-form" action="{{ route('logout') }}" method="POST" class="hidden">
|
|
||||||
@csrf
|
|
||||||
</form>
|
|
||||||
</a>
|
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
|
||||||
|
|
||||||
<!-- Content -->
|
<!-- User Profile -->
|
||||||
<div :class="sidebarOpen ? 'lg:ml-72' : ''" class="transition-all duration-300">
|
<div class="absolute bottom-0 w-full border-t border-gray-200">
|
||||||
<!-- Top bar -->
|
<div x-data="{ open: false }" class="relative p-4">
|
||||||
<header class="bg-white/80 backdrop-blur-md border-b border-gray-200/50 sticky top-0 z-30 shadow-sm">
|
<button @click="open = !open" class="flex items-center w-full text-left focus:outline-none">
|
||||||
<div class="px-6 py-4 flex items-center justify-between">
|
<div class="flex-shrink-0">
|
||||||
|
<div
|
||||||
|
class="w-8 h-8 bg-blue-600 rounded-full flex items-center justify-center text-white font-semibold">
|
||||||
|
{{ substr(auth()->user()->name ?? 'SA', 0, 1) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div x-show="sidebarOpen" class="ml-3">
|
||||||
|
<p class="text-sm font-medium text-gray-800 truncate">
|
||||||
|
{{ auth()->user()->name ?? 'Super Admin' }}</p>
|
||||||
|
<p class="text-xs text-gray-500 truncate">{{ auth()->user()->email ??
|
||||||
|
'superadmin@example.com' }}</p>
|
||||||
|
</div>
|
||||||
|
<svg x-show="sidebarOpen" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="ml-auto h-4 w-4 text-gray-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Dropdown -->
|
||||||
|
<div x-show="open" @click.outside="open = false"
|
||||||
|
class="absolute bottom-full left-0 mb-1 w-full bg-white rounded-lg shadow-lg border border-gray-200 py-1 dropdown-transition">
|
||||||
|
<div class="border-t border-gray-200 my-1"></div>
|
||||||
|
<form method="POST" action="{{ route('logout') }}">
|
||||||
|
@csrf
|
||||||
|
<button type="submit"
|
||||||
|
class="block w-full text-left px-4 py-2 text-sm text-red-600 hover:bg-gray-100">
|
||||||
|
Logout
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<div class="flex-1 flex flex-col overflow-hidden">
|
||||||
|
<!-- Top Header -->
|
||||||
|
{{-- <header class="bg-white shadow-sm">
|
||||||
|
<div class="px-4 sm:px-6 lg:px-8 py-4 flex items-center justify-between">
|
||||||
<div class="flex items-center space-x-4">
|
<div class="flex items-center space-x-4">
|
||||||
<button @click="sidebarOpen = !sidebarOpen"
|
<button @click="sidebarOpen = !sidebarOpen"
|
||||||
class="w-10 h-10 rounded-lg bg-gray-100 hover:bg-gray-200 transition-colors flex items-center justify-center text-gray-600 hover:text-gray-800">
|
class="p-1 rounded-md text-gray-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 lg:inline-block">
|
||||||
<i class="fas fa-bars text-sm"></i>
|
<svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M4 6h16M4 12h16M4 18h16"></path>
|
||||||
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- Breadcrumb -->
|
<!-- Breadcrumb -->
|
||||||
<nav class="flex items-center space-x-2 text-sm text-gray-500">
|
<nav class="flex items-center space-x-2 text-sm text-gray-500">
|
||||||
<span class="font-medium text-gray-900">Super Admin</span>
|
<span class="font-medium text-gray-900">Super Admin</span>
|
||||||
|
@ -186,68 +167,67 @@ class="w-10 h-10 rounded-lg bg-gray-100 hover:bg-gray-200 transition-colors flex
|
||||||
<span>Dashboard</span>
|
<span>Dashboard</span>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center space-x-4">
|
<div class="flex items-center space-x-4">
|
||||||
<!-- Notifications -->
|
<!-- Notifications -->
|
||||||
<button class="relative w-10 h-10 rounded-lg bg-gray-100 hover:bg-gray-200 transition-colors flex items-center justify-center text-gray-600 hover:text-gray-800">
|
<button class="relative p-2 rounded-md text-gray-500 hover:bg-gray-100 focus:outline-none">
|
||||||
<i class="fas fa-bell text-sm"></i>
|
<i class="fas fa-bell text-sm"></i>
|
||||||
<span class="absolute -top-1 -right-1 w-3 h-3 bg-red-500 rounded-full"></span>
|
<span class="absolute -top-1 -right-1 w-3 h-3 bg-red-500 rounded-full"></span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- Profile Dropdown -->
|
<!-- Profile Dropdown -->
|
||||||
<div class="relative" x-data="{ open: false }">
|
<div class="relative" x-data="{ open: false }">
|
||||||
<button @click="open = !open"
|
<button @click="open = !open"
|
||||||
class="flex items-center space-x-3 p-2 rounded-lg hover:bg-gray-100 transition-colors">
|
class="flex items-center space-x-3 p-2 rounded-lg hover:bg-gray-100 transition-colors">
|
||||||
<div class="w-8 h-8 rounded-full bg-gradient-to-br from-emerald-400 to-cyan-500 flex items-center justify-center">
|
<div
|
||||||
<i class="fas fa-user text-white text-sm"></i>
|
class="w-8 h-8 rounded-full bg-blue-600 flex items-center justify-center text-white font-semibold">
|
||||||
|
{{ substr(auth()->user()->name ?? 'SA', 0, 1) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-left hidden md:block">
|
<div class="text-left hidden md:block">
|
||||||
<p class="text-sm font-medium text-gray-900">{{ auth()->user()->name ?? 'Admin' }}</p>
|
<p class="text-sm font-medium text-gray-900">{{ auth()->user()->name ?? 'Super
|
||||||
|
Admin' }}</p>
|
||||||
<p class="text-xs text-gray-500">Super Admin</p>
|
<p class="text-xs text-gray-500">Super Admin</p>
|
||||||
</div>
|
</div>
|
||||||
<i class="fas fa-chevron-down text-xs text-gray-400"
|
<i class="fas fa-chevron-down text-xs text-gray-400" :class="{ 'rotate-180': open }"
|
||||||
:class="{ 'rotate-180': open }"
|
style="transition: transform 0.2s"></i>
|
||||||
style="transition: transform 0.2s"></i>
|
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div x-show="open"
|
<div x-show="open" @click.away="open = false"
|
||||||
@click.away="open = false"
|
x-transition:enter="transition ease-out duration-200"
|
||||||
x-transition:enter="transition ease-out duration-200"
|
x-transition:enter-start="opacity-0 scale-95"
|
||||||
x-transition:enter-start="opacity-0 scale-95"
|
x-transition:enter-end="opacity-100 scale-100"
|
||||||
x-transition:enter-end="opacity-100 scale-100"
|
x-transition:leave="transition ease-in duration-150"
|
||||||
x-transition:leave="transition ease-in duration-150"
|
x-transition:leave-start="opacity-100 scale-100"
|
||||||
x-transition:leave-start="opacity-100 scale-100"
|
x-transition:leave-end="opacity-0 scale-95"
|
||||||
x-transition:leave-end="opacity-0 scale-95"
|
class="absolute right-0 mt-2 w-56 bg-white rounded-xl shadow-lg border border-gray-200 py-2 z-50">
|
||||||
class="absolute right-0 mt-2 w-56 bg-white rounded-xl shadow-lg border border-gray-200 py-2 z-50">
|
|
||||||
<div class="px-4 py-3 border-b border-gray-100">
|
<div class="px-4 py-3 border-b border-gray-100">
|
||||||
<p class="text-sm font-medium text-gray-900">{{ auth()->user()->name ?? 'Admin' }}</p>
|
<p class="text-sm font-medium text-gray-900">{{ auth()->user()->name ?? 'Super
|
||||||
<p class="text-xs text-gray-500">{{ auth()->user()->email ?? 'admin@example.com' }}</p>
|
Admin' }}</p>
|
||||||
|
<p class="text-xs text-gray-500">{{ auth()->user()->email ??
|
||||||
|
'superadmin@example.com' }}</p>
|
||||||
</div>
|
</div>
|
||||||
{{-- <a href="#" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-50">
|
|
||||||
<i class="fas fa-user mr-3 text-gray-400"></i>
|
|
||||||
Profile Settings
|
|
||||||
</a>
|
|
||||||
<a href="#" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-50">
|
|
||||||
<i class="fas fa-cog mr-3 text-gray-400"></i>
|
|
||||||
Account Settings
|
|
||||||
</a> --}}
|
|
||||||
<div class="border-t border-gray-100 mt-2 pt-2">
|
<div class="border-t border-gray-100 mt-2 pt-2">
|
||||||
<a href="{{ route('logout') }}"
|
<a href="{{ route('logout') }}"
|
||||||
onclick="event.preventDefault(); document.getElementById('logout-form').submit();"
|
onclick="event.preventDefault(); document.getElementById('logout-form').submit();"
|
||||||
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Logout</a>
|
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Logout</a>
|
||||||
|
<form id="logout-form" action="{{ route('logout') }}" method="POST" class="hidden">
|
||||||
|
@csrf
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header> --}}
|
||||||
|
|
||||||
<!-- Main content -->
|
<!-- Page Content -->
|
||||||
<main class="p-6">
|
<main class="flex-1 overflow-x-hidden overflow-y-auto">
|
||||||
@yield('content')
|
@yield('content')
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@stack('scripts')
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
|
@ -1,235 +1,206 @@
|
||||||
@extends('layouts.super-admin')
|
@extends('layouts.super-admin')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="mb-8">
|
<div class="bg-gray-50 min-h-screen">
|
||||||
<h1 class="text-4xl font-bold bg-gradient-to-r from-purple-600 to-pink-600 bg-clip-text text-transparent">
|
<div class="p-6">
|
||||||
Dashboard Super Admin
|
<!-- Header and Welcome -->
|
||||||
</h1>
|
<div class="flex justify-between items-center mb-6">
|
||||||
<p class="text-gray-600 text-lg">Analytics & Overview dari seluruh venue</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Main Stats Cards -->
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
|
|
||||||
<div class="bg-gradient-to-br from-blue-500 to-blue-600 rounded-xl shadow-lg p-6 text-white">
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<div>
|
<div>
|
||||||
<p class="text-blue-100 text-sm font-medium">Total Admin</p>
|
<h1 class="text-3xl font-bold text-gray-800">Dashboard Super Admin</h1>
|
||||||
<p class="text-3xl font-bold">{{ $adminCount ?? 0 }}</p>
|
<p class="text-gray-600 mt-1">Analytics & Overview dari seluruh venue</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-blue-400 bg-opacity-30 rounded-full p-3">
|
<div class="text-right">
|
||||||
<i class="fas fa-users-cog text-2xl"></i>
|
<p class="text-sm text-gray-500">{{ now()->format('l, d F Y') }}</p>
|
||||||
|
<p class="text-2xl font-semibold text-gray-800">{{ now()->format('H:i') }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="bg-gradient-to-br from-emerald-500 to-emerald-600 rounded-xl shadow-lg p-6 text-white">
|
<!-- Main Stats Cards -->
|
||||||
<div class="flex items-center justify-between">
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
|
||||||
<div>
|
<!-- Total Admin Card -->
|
||||||
<p class="text-emerald-100 text-sm font-medium">Total Venue</p>
|
<div class="bg-white rounded-xl shadow-sm p-6 border-l-4 border-blue-500 hover:shadow-md transition">
|
||||||
<p class="text-3xl font-bold">{{ $venueCount ?? 0 }}</p>
|
<div class="flex justify-between items-start">
|
||||||
|
<div>
|
||||||
|
<p class="text-sm font-medium text-gray-500">Total Admin</p>
|
||||||
|
<p class="text-2xl font-bold text-gray-800">{{ $adminCount ?? 0 }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="text-blue-500 p-2 bg-blue-50 rounded-lg">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<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.5-9a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="text-xs text-gray-500 mt-2">Administrator aktif</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-emerald-400 bg-opacity-30 rounded-full p-3">
|
|
||||||
<i class="fas fa-building text-2xl"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="bg-gradient-to-br from-amber-500 to-orange-500 rounded-xl shadow-lg p-6 text-white">
|
<!-- Total Venue Card -->
|
||||||
<div class="flex items-center justify-between">
|
<div class="bg-white rounded-xl shadow-sm p-6 border-l-4 border-green-500 hover:shadow-md transition">
|
||||||
<div>
|
<div class="flex justify-between items-start">
|
||||||
<p class="text-amber-100 text-sm font-medium">Total User</p>
|
<div>
|
||||||
<p class="text-3xl font-bold">{{ $userCount ?? 0 }}</p>
|
<p class="text-sm font-medium text-gray-500">Total Venue</p>
|
||||||
|
<p class="text-2xl font-bold text-gray-800">{{ $venueCount ?? 0 }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="text-green-500 p-2 bg-green-50 rounded-lg">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="text-xs text-gray-500 mt-2">Venue terdaftar</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-amber-400 bg-opacity-30 rounded-full p-3">
|
|
||||||
<i class="fas fa-users text-2xl"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="bg-gradient-to-br from-purple-500 to-pink-500 rounded-xl shadow-lg p-6 text-white">
|
<!-- Total User Card -->
|
||||||
<div class="flex items-center justify-between">
|
<div class="bg-white rounded-xl shadow-sm p-6 border-l-4 border-amber-500 hover:shadow-md transition">
|
||||||
<div>
|
<div class="flex justify-between items-start">
|
||||||
<p class="text-purple-100 text-sm font-medium">Total Meja</p>
|
<div>
|
||||||
<p class="text-3xl font-bold">{{ $tableCount ?? 0 }}</p>
|
<p class="text-sm font-medium text-gray-500">Total User</p>
|
||||||
|
<p class="text-2xl font-bold text-gray-800">{{ $userCount ?? 0 }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="text-amber-500 p-2 bg-amber-50 rounded-lg">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<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.5-9a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="text-xs text-gray-500 mt-2">Pengguna terdaftar</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-purple-400 bg-opacity-30 rounded-full p-3">
|
|
||||||
<i class="fas fa-table text-2xl"></i>
|
<!-- Total Meja Card -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm p-6 border-l-4 border-purple-500 hover:shadow-md transition">
|
||||||
|
<div class="flex justify-between items-start">
|
||||||
|
<div>
|
||||||
|
<p class="text-sm font-medium text-gray-500">Total Meja</p>
|
||||||
|
<p class="text-2xl font-bold text-gray-800">{{ $tableCount ?? 0 }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="text-purple-500 p-2 bg-purple-50 rounded-lg">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M3 14h18m-9-4v8m-7 0h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="text-xs text-gray-500 mt-2">Meja tersedia</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Charts Section -->
|
<!-- Charts Section -->
|
||||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||||
<!-- Revenue Comparison Chart -->
|
<!-- Revenue Comparison Chart -->
|
||||||
<div class="bg-white rounded-xl shadow-lg overflow-hidden">
|
<div class="bg-white rounded-xl shadow-sm">
|
||||||
<div class="bg-gradient-to-r from-indigo-500 to-purple-600 px-6 py-4">
|
<div class="px-6 py-4 border-b border-gray-200">
|
||||||
<h3 class="text-xl font-bold text-white flex items-center">
|
<h3 class="text-lg font-semibold text-gray-800 flex items-center">
|
||||||
<i class="fas fa-chart-bar mr-3"></i>
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3 text-gray-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
Revenue Bulan Ini
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
|
||||||
</h3>
|
</svg>
|
||||||
<p class="text-indigo-100 text-sm">Per venue - {{ Carbon\Carbon::now()->format('F Y') }}</p>
|
Revenue Bulan Ini
|
||||||
</div>
|
</h3>
|
||||||
<div class="p-6">
|
<p class="text-gray-500 text-sm">Per venue - {{ Carbon\Carbon::now()->format('F Y') }}</p>
|
||||||
<canvas id="revenueChart" width="400" height="300"></canvas>
|
</div>
|
||||||
</div>
|
<div class="p-6">
|
||||||
</div>
|
<div style="height: 300px;">
|
||||||
|
<canvas id="revenueChart"></canvas>
|
||||||
<!-- Popular Venues Ranking -->
|
</div>
|
||||||
<div class="bg-white rounded-xl shadow-lg overflow-hidden">
|
</div>
|
||||||
<div class="bg-gradient-to-r from-pink-500 to-rose-600 px-6 py-4">
|
</div>
|
||||||
<h3 class="text-xl font-bold text-white flex items-center">
|
|
||||||
<i class="fas fa-trophy mr-3"></i>
|
<!-- Popular Venues Ranking -->
|
||||||
Ranking Popularitas
|
<div class="bg-white rounded-xl shadow-sm">
|
||||||
</h3>
|
<div class="px-6 py-4 border-b border-gray-200">
|
||||||
<p class="text-pink-100 text-sm">Venue terpopuler bulan ini</p>
|
<h3 class="text-lg font-semibold text-gray-800 flex items-center">
|
||||||
</div>
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3 text-gray-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
<div class="p-6">
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4M7.835 4.697a3.42 3.42 0 001.946-.806 3.42 3.42 0 014.438 0 3.42 3.42 0 001.946.806 3.42 3.42 0 013.138 3.138 3.42 3.42 0 00.806 1.946 3.42 3.42 0 010 4.438 3.42 3.42 0 00-.806 1.946 3.42 3.42 0 01-3.138 3.138 3.42 3.42 0 00-1.946.806 3.42 3.42 0 01-4.438 0 3.42 3.42 0 00-1.946-.806 3.42 3.42 0 01-3.138-3.138 3.42 3.42 0 00-.806-1.946 3.42 3.42 0 010-4.438 3.42 3.42 0 00.806-1.946 3.42 3.42 0 013.138-3.138z" />
|
||||||
<!-- Filter Toggle -->
|
</svg>
|
||||||
<div class="mb-4">
|
Ranking Popularitas
|
||||||
<div class="bg-gray-100 rounded-lg p-1 flex">
|
</h3>
|
||||||
<button
|
<p class="text-gray-500 text-sm">Venue terpopuler bulan ini</p>
|
||||||
id="rankingByBookings"
|
</div>
|
||||||
class="flex-1 py-2 px-4 rounded-md text-sm font-medium transition-all duration-200 bg-rose-500 text-white"
|
<div class="p-6">
|
||||||
onclick="toggleRanking('bookings')">
|
<!-- Filter Toggle -->
|
||||||
<i class="fas fa-calendar-check mr-2"></i>
|
<div class="mb-4">
|
||||||
Total Booking
|
<div class="bg-gray-100 rounded-lg p-1 flex">
|
||||||
</button>
|
<button id="rankingByBookings"
|
||||||
<button
|
class="flex-1 py-2 px-4 rounded-md text-sm font-medium transition-all duration-200 bg-green-600 text-white"
|
||||||
id="rankingByRevenue"
|
onclick="toggleRanking('bookings')">
|
||||||
class="flex-1 py-2 px-4 rounded-md text-sm font-medium transition-all duration-200 text-gray-600 hover:text-gray-800"
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 inline mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
onclick="toggleRanking('revenue')">
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||||
<i class="fas fa-money-bill-wave mr-2"></i>
|
</svg>
|
||||||
Total Revenue
|
Total Booking
|
||||||
</button>
|
</button>
|
||||||
|
<button id="rankingByRevenue"
|
||||||
|
class="flex-1 py-2 px-4 rounded-md text-sm font-medium transition-all duration-200 text-gray-600 hover:text-gray-800"
|
||||||
|
onclick="toggleRanking('revenue')">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 inline mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
Total Revenue
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="height: 300px;">
|
||||||
|
<canvas id="popularVenuesChart"></canvas>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="popularVenuesChart" width="400" height="300"></canvas>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script>
|
@push('scripts')
|
||||||
<script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script>
|
||||||
// Revenue Chart Data
|
<script>
|
||||||
const revenueData = @json($revenueData);
|
// Revenue Chart Data
|
||||||
|
const revenueData = @json($revenueData);
|
||||||
// Popular Venues Data
|
|
||||||
const popularVenuesData = @json($popularVenuesData);
|
|
||||||
|
|
||||||
// Color Palettes
|
// Popular Venues Data
|
||||||
const revenueColors = [
|
const popularVenuesData = @json($popularVenuesData);
|
||||||
'rgba(99, 102, 241, 0.8)', // Indigo
|
|
||||||
'rgba(168, 85, 247, 0.8)', // Purple
|
|
||||||
'rgba(236, 72, 153, 0.8)', // Pink
|
|
||||||
'rgba(34, 197, 94, 0.8)', // Emerald
|
|
||||||
'rgba(251, 146, 60, 0.8)', // Orange
|
|
||||||
];
|
|
||||||
|
|
||||||
const rankingColors = [
|
// Color Palettes - More subtle and professional
|
||||||
'rgba(239, 68, 68, 0.8)', // Red
|
const revenueColors = [
|
||||||
'rgba(245, 158, 11, 0.8)', // Amber
|
'rgba(59, 130, 246, 0.8)', // Blue
|
||||||
'rgba(34, 197, 94, 0.8)', // Emerald
|
'rgba(16, 185, 129, 0.8)', // Emerald
|
||||||
'rgba(59, 130, 246, 0.8)', // Blue
|
'rgba(245, 158, 11, 0.8)', // Amber
|
||||||
'rgba(168, 85, 247, 0.8)', // Purple
|
'rgba(139, 92, 246, 0.8)', // Violet
|
||||||
];
|
'rgba(236, 72, 153, 0.8)', // Pink
|
||||||
|
];
|
||||||
|
|
||||||
// Revenue Chart
|
const rankingColors = [
|
||||||
const revenueCtx = document.getElementById('revenueChart').getContext('2d');
|
'rgba(34, 197, 94, 0.8)', // Green
|
||||||
const revenueChart = new Chart(revenueCtx, {
|
'rgba(59, 130, 246, 0.8)', // Blue
|
||||||
type: 'bar',
|
'rgba(245, 158, 11, 0.8)', // Amber
|
||||||
data: {
|
'rgba(139, 92, 246, 0.8)', // Violet
|
||||||
labels: revenueData.map(item => item.venue_name),
|
'rgba(107, 114, 128, 0.8)', // Gray
|
||||||
datasets: [{
|
];
|
||||||
label: 'Revenue (Rp)',
|
|
||||||
data: revenueData.map(item => parseFloat(item.total_revenue)),
|
|
||||||
backgroundColor: revenueColors,
|
|
||||||
borderRadius: 8,
|
|
||||||
borderSkipped: false,
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
indexAxis: 'y',
|
|
||||||
responsive: true,
|
|
||||||
plugins: {
|
|
||||||
legend: {
|
|
||||||
display: false
|
|
||||||
},
|
|
||||||
tooltip: {
|
|
||||||
callbacks: {
|
|
||||||
label: function(context) {
|
|
||||||
return 'Revenue: Rp ' + new Intl.NumberFormat('id-ID').format(context.parsed.x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
scales: {
|
|
||||||
x: {
|
|
||||||
beginAtZero: true,
|
|
||||||
ticks: {
|
|
||||||
callback: function(value) {
|
|
||||||
return 'Rp ' + new Intl.NumberFormat('id-ID', {
|
|
||||||
notation: 'compact',
|
|
||||||
maximumFractionDigits: 1
|
|
||||||
}).format(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
y: {
|
|
||||||
grid: {
|
|
||||||
display: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Popular Venues Chart
|
// Revenue Chart
|
||||||
const popularCtx = document.getElementById('popularVenuesChart').getContext('2d');
|
const revenueCtx = document.getElementById('revenueChart').getContext('2d');
|
||||||
let popularChart;
|
const revenueChart = new Chart(revenueCtx, {
|
||||||
|
|
||||||
function createPopularChart(sortBy) {
|
|
||||||
const sortedData = [...popularVenuesData].sort((a, b) => {
|
|
||||||
if (sortBy === 'revenue') {
|
|
||||||
return parseFloat(b.total_revenue) - parseFloat(a.total_revenue);
|
|
||||||
} else {
|
|
||||||
return parseInt(b.total_bookings) - parseInt(a.total_bookings);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const chartData = {
|
|
||||||
labels: sortedData.map(item => item.venue_name),
|
|
||||||
datasets: [{
|
|
||||||
label: sortBy === 'revenue' ? 'Revenue (Rp)' : 'Total Booking',
|
|
||||||
data: sortedData.map(item => sortBy === 'revenue' ? parseFloat(item.total_revenue) : parseInt(item.total_bookings)),
|
|
||||||
backgroundColor: rankingColors,
|
|
||||||
borderRadius: 8,
|
|
||||||
borderSkipped: false,
|
|
||||||
}]
|
|
||||||
};
|
|
||||||
|
|
||||||
if (popularChart) {
|
|
||||||
popularChart.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
popularChart = new Chart(popularCtx, {
|
|
||||||
type: 'bar',
|
type: 'bar',
|
||||||
data: chartData,
|
data: {
|
||||||
|
labels: revenueData.map(item => item.venue_name),
|
||||||
|
datasets: [{
|
||||||
|
label: 'Revenue (Rp)',
|
||||||
|
data: revenueData.map(item => parseFloat(item.total_revenue)),
|
||||||
|
backgroundColor: revenueColors,
|
||||||
|
borderRadius: 4,
|
||||||
|
borderSkipped: false,
|
||||||
|
}]
|
||||||
|
},
|
||||||
options: {
|
options: {
|
||||||
indexAxis: 'y',
|
indexAxis: 'y',
|
||||||
responsive: true,
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
plugins: {
|
plugins: {
|
||||||
legend: {
|
legend: {
|
||||||
display: false
|
display: false
|
||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
|
backgroundColor: 'rgba(17, 24, 39, 0.9)',
|
||||||
|
titleColor: '#fff',
|
||||||
|
bodyColor: '#fff',
|
||||||
|
borderColor: 'rgba(156, 163, 175, 0.2)',
|
||||||
|
borderWidth: 1,
|
||||||
callbacks: {
|
callbacks: {
|
||||||
label: function(context) {
|
label: function (context) {
|
||||||
if (sortBy === 'revenue') {
|
return 'Revenue: Rp ' + new Intl.NumberFormat('id-ID').format(context.parsed.x);
|
||||||
return 'Revenue: Rp ' + new Intl.NumberFormat('id-ID').format(context.parsed.x);
|
|
||||||
} else {
|
|
||||||
return 'Total Booking: ' + context.parsed.x;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,46 +208,138 @@ function createPopularChart(sortBy) {
|
||||||
scales: {
|
scales: {
|
||||||
x: {
|
x: {
|
||||||
beginAtZero: true,
|
beginAtZero: true,
|
||||||
|
grid: {
|
||||||
|
color: 'rgba(156, 163, 175, 0.1)'
|
||||||
|
},
|
||||||
ticks: {
|
ticks: {
|
||||||
callback: function(value) {
|
color: '#6B7280',
|
||||||
if (sortBy === 'revenue') {
|
callback: function (value) {
|
||||||
return 'Rp ' + new Intl.NumberFormat('id-ID', {
|
return 'Rp ' + new Intl.NumberFormat('id-ID', {
|
||||||
notation: 'compact',
|
notation: 'compact',
|
||||||
maximumFractionDigits: 1
|
maximumFractionDigits: 1
|
||||||
}).format(value);
|
}).format(value);
|
||||||
} else {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
y: {
|
y: {
|
||||||
grid: {
|
grid: {
|
||||||
display: false
|
display: false
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
color: '#6B7280'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize popular venues chart
|
// Popular Venues Chart
|
||||||
createPopularChart('bookings');
|
const popularCtx = document.getElementById('popularVenuesChart').getContext('2d');
|
||||||
|
let popularChart;
|
||||||
|
|
||||||
// Toggle function for ranking chart
|
function createPopularChart(sortBy) {
|
||||||
function toggleRanking(type) {
|
const sortedData = [...popularVenuesData].sort((a, b) => {
|
||||||
const bookingBtn = document.getElementById('rankingByBookings');
|
if (sortBy === 'revenue') {
|
||||||
const revenueBtn = document.getElementById('rankingByRevenue');
|
return parseFloat(b.total_revenue) - parseFloat(a.total_revenue);
|
||||||
|
} else {
|
||||||
|
return parseInt(b.total_bookings) - parseInt(a.total_bookings);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (type === 'bookings') {
|
const chartData = {
|
||||||
bookingBtn.className = 'flex-1 py-2 px-4 rounded-md text-sm font-medium transition-all duration-200 bg-rose-500 text-white';
|
labels: sortedData.map(item => item.venue_name),
|
||||||
revenueBtn.className = 'flex-1 py-2 px-4 rounded-md text-sm font-medium transition-all duration-200 text-gray-600 hover:text-gray-800';
|
datasets: [{
|
||||||
createPopularChart('bookings');
|
label: sortBy === 'revenue' ? 'Revenue (Rp)' : 'Total Booking',
|
||||||
} else {
|
data: sortedData.map(item => sortBy === 'revenue' ? parseFloat(item.total_revenue) : parseInt(item.total_bookings)),
|
||||||
revenueBtn.className = 'flex-1 py-2 px-4 rounded-md text-sm font-medium transition-all duration-200 bg-rose-500 text-white';
|
backgroundColor: rankingColors,
|
||||||
bookingBtn.className = 'flex-1 py-2 px-4 rounded-md text-sm font-medium transition-all duration-200 text-gray-600 hover:text-gray-800';
|
borderRadius: 4,
|
||||||
createPopularChart('revenue');
|
borderSkipped: false,
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
if (popularChart) {
|
||||||
|
popularChart.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
popularChart = new Chart(popularCtx, {
|
||||||
|
type: 'bar',
|
||||||
|
data: chartData,
|
||||||
|
options: {
|
||||||
|
indexAxis: 'y',
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
display: false
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
backgroundColor: 'rgba(17, 24, 39, 0.9)',
|
||||||
|
titleColor: '#fff',
|
||||||
|
bodyColor: '#fff',
|
||||||
|
borderColor: 'rgba(156, 163, 175, 0.2)',
|
||||||
|
borderWidth: 1,
|
||||||
|
callbacks: {
|
||||||
|
label: function (context) {
|
||||||
|
if (sortBy === 'revenue') {
|
||||||
|
return 'Revenue: Rp ' + new Intl.NumberFormat('id-ID').format(context.parsed.x);
|
||||||
|
} else {
|
||||||
|
return 'Total Booking: ' + context.parsed.x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
beginAtZero: true,
|
||||||
|
grid: {
|
||||||
|
color: 'rgba(156, 163, 175, 0.1)'
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
color: '#6B7280',
|
||||||
|
callback: function (value) {
|
||||||
|
if (sortBy === 'revenue') {
|
||||||
|
return 'Rp ' + new Intl.NumberFormat('id-ID', {
|
||||||
|
notation: 'compact',
|
||||||
|
maximumFractionDigits: 1
|
||||||
|
}).format(value);
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
grid: {
|
||||||
|
display: false
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
color: '#6B7280'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</script>
|
// Initialize popular venues chart
|
||||||
|
createPopularChart('bookings');
|
||||||
|
|
||||||
|
// Toggle function for ranking chart
|
||||||
|
function toggleRanking(type) {
|
||||||
|
const bookingBtn = document.getElementById('rankingByBookings');
|
||||||
|
const revenueBtn = document.getElementById('rankingByRevenue');
|
||||||
|
|
||||||
|
if (type === 'bookings') {
|
||||||
|
bookingBtn.className = 'flex-1 py-2 px-4 rounded-md text-sm font-medium transition-all duration-200 bg-green-600 text-white';
|
||||||
|
revenueBtn.className = 'flex-1 py-2 px-4 rounded-md text-sm font-medium transition-all duration-200 text-gray-600 hover:text-gray-800';
|
||||||
|
createPopularChart('bookings');
|
||||||
|
} else {
|
||||||
|
revenueBtn.className = 'flex-1 py-2 px-4 rounded-md text-sm font-medium transition-all duration-200 bg-green-600 text-white';
|
||||||
|
bookingBtn.className = 'flex-1 py-2 px-4 rounded-md text-sm font-medium transition-all duration-200 text-gray-600 hover:text-gray-800';
|
||||||
|
createPopularChart('revenue');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
@endpush
|
||||||
@endsection
|
@endsection
|
|
@ -74,6 +74,11 @@
|
||||||
Route::middleware(['auth', 'verified', 'is_admin'])->prefix('admin')->group(function () {
|
Route::middleware(['auth', 'verified', 'is_admin'])->prefix('admin')->group(function () {
|
||||||
Route::get('/', [AdminController::class, 'index'])->name('admin.dashboard');
|
Route::get('/', [AdminController::class, 'index'])->name('admin.dashboard');
|
||||||
|
|
||||||
|
// Admin Profile Routes
|
||||||
|
Route::get('/profile', [App\Http\Controllers\admin\AdminProfileController::class, 'index'])->name('admin.profile.index');
|
||||||
|
Route::put('/profile/update', [App\Http\Controllers\admin\AdminProfileController::class, 'updateProfile'])->name('admin.profile.update');
|
||||||
|
Route::put('/profile/password', [App\Http\Controllers\admin\AdminProfileController::class, 'updatePassword'])->name('admin.profile.password');
|
||||||
|
|
||||||
// Booking management routes
|
// Booking management routes
|
||||||
Route::get('/bookings', [BookingsController::class, 'index'])->name('admin.bookings.index');
|
Route::get('/bookings', [BookingsController::class, 'index'])->name('admin.bookings.index');
|
||||||
Route::get('/bookings/export', [BookingsController::class, 'export'])->name('admin.bookings.export');
|
Route::get('/bookings/export', [BookingsController::class, 'export'])->name('admin.bookings.export');
|
||||||
|
|
Loading…
Reference in New Issue