SuperAdmin Grafik
This commit is contained in:
parent
ac9d47071e
commit
50accc8a00
|
@ -5,8 +5,11 @@
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use App\Models\Booking;
|
||||||
use App\Models\Venue;
|
use App\Models\Venue;
|
||||||
use App\Models\Table;
|
use App\Models\Table;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
class SuperAdminController extends Controller
|
class SuperAdminController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -17,19 +20,63 @@ class SuperAdminController extends Controller
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
// Menghitung jumlah admin, venue, user, venue aktif, dan meja
|
// Basic counts
|
||||||
$adminCount = User::where('role', 'admin')->count();
|
$adminCount = User::where('role', 'admin')->count();
|
||||||
$venueCount = Venue::count();
|
$venueCount = Venue::count();
|
||||||
$userCount = User::where('role', 'user')->count();
|
$userCount = User::where('role', 'user')->count();
|
||||||
// $activeVenueCount = Venue::where('status', 'active')->count();
|
|
||||||
$tableCount = Table::count();
|
$tableCount = Table::count();
|
||||||
|
|
||||||
|
// Revenue comparison for current month
|
||||||
|
$currentMonth = Carbon::now()->startOfMonth();
|
||||||
|
$revenueData = $this->getMonthlyRevenueByVenue($currentMonth);
|
||||||
|
|
||||||
|
// Popular venues ranking data
|
||||||
|
$popularVenuesData = $this->getPopularVenuesData($currentMonth);
|
||||||
|
|
||||||
return view('superadmin.dashboard', compact(
|
return view('superadmin.dashboard', compact(
|
||||||
'adminCount',
|
'adminCount',
|
||||||
'venueCount',
|
'venueCount',
|
||||||
'userCount',
|
'userCount',
|
||||||
// 'activeVenueCount',
|
'tableCount',
|
||||||
'tableCount'
|
'revenueData',
|
||||||
|
'popularVenuesData'
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get monthly revenue by venue for chart
|
||||||
|
*/
|
||||||
|
private function getMonthlyRevenueByVenue($startDate)
|
||||||
|
{
|
||||||
|
return Venue::leftJoin('tables', 'venues.id', '=', 'tables.venue_id')
|
||||||
|
->leftJoin('bookings', function($join) use ($startDate) {
|
||||||
|
$join->on('tables.id', '=', 'bookings.table_id')
|
||||||
|
->where('bookings.status', 'paid')
|
||||||
|
->where('bookings.created_at', '>=', $startDate)
|
||||||
|
->where('bookings.created_at', '<', $startDate->copy()->endOfMonth());
|
||||||
|
})
|
||||||
|
->select('venues.name as venue_name',
|
||||||
|
DB::raw('COALESCE(SUM(bookings.total_amount), 0) as total_revenue'))
|
||||||
|
->groupBy('venues.id', 'venues.name')
|
||||||
|
->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get popular venues data for ranking
|
||||||
|
*/
|
||||||
|
private function getPopularVenuesData($startDate)
|
||||||
|
{
|
||||||
|
return Venue::leftJoin('tables', 'venues.id', '=', 'tables.venue_id')
|
||||||
|
->leftJoin('bookings', function($join) use ($startDate) {
|
||||||
|
$join->on('tables.id', '=', 'bookings.table_id')
|
||||||
|
->where('bookings.status', 'paid')
|
||||||
|
->where('bookings.created_at', '>=', $startDate)
|
||||||
|
->where('bookings.created_at', '<', $startDate->copy()->endOfMonth());
|
||||||
|
})
|
||||||
|
->select('venues.name as venue_name',
|
||||||
|
DB::raw('COALESCE(COUNT(bookings.id), 0) as total_bookings'),
|
||||||
|
DB::raw('COALESCE(SUM(bookings.total_amount), 0) as total_revenue'))
|
||||||
|
->groupBy('venues.id', 'venues.name')
|
||||||
|
->get();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -12,91 +12,230 @@
|
||||||
<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 -->
|
<!-- Alpine.js -->
|
||||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/alpinejs/3.12.0/cdn.min.js"></script>
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/alpinejs/3.12.0/cdn.min.js"></script>
|
||||||
|
<!-- Google Fonts -->
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
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 {
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: -100%;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);
|
||||||
|
transition: left 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item:hover::before {
|
||||||
|
left: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Active nav indicator */
|
||||||
|
.nav-active {
|
||||||
|
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>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="bg-gray-100">
|
<body class="bg-gray-50">
|
||||||
<div x-data="{ sidebarOpen: true }">
|
<div x-data="{ sidebarOpen: true }">
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
<aside :class="sidebarOpen ? 'translate-x-0' : '-translate-x-full'"
|
<aside :class="sidebarOpen ? 'translate-x-0' : '-translate-x-full'"
|
||||||
class="fixed top-0 left-0 z-40 w-64 h-screen transition-transform bg-blue-800 text-white">
|
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">
|
||||||
<div class="flex items-center justify-between p-4 border-b border-blue-700">
|
|
||||||
<h2 class="text-2xl font-bold">Venue System</h2>
|
<!-- Header -->
|
||||||
<button @click="sidebarOpen = !sidebarOpen" class="lg:hidden">
|
<div class="flex items-center justify-between p-6 border-b border-slate-600/30">
|
||||||
<i class="fas fa-times"></i>
|
<div class="flex items-center space-x-3">
|
||||||
|
<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">
|
||||||
|
<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>
|
||||||
|
<button @click="sidebarOpen = !sidebarOpen"
|
||||||
|
class="lg:hidden w-8 h-8 rounded-lg bg-slate-600/50 hover:bg-slate-600 transition-colors flex items-center justify-center">
|
||||||
|
<i class="fas fa-times text-sm"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-4">
|
|
||||||
<div class="mb-8">
|
<!-- Profile Section -->
|
||||||
<div class="flex items-center mb-4">
|
<div class="p-6">
|
||||||
<div class="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center">
|
<div class="profile-section rounded-xl p-4 mb-6">
|
||||||
<i class="fas fa-user-shield"></i>
|
<div class="flex items-center space-x-4">
|
||||||
|
<div class="relative">
|
||||||
|
<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>
|
||||||
<div class="ml-3">
|
<div class="flex-1">
|
||||||
<p class="text-sm font-medium">Super Admin</p>
|
<p class="font-semibold text-white">{{ auth()->user()->name ?? 'Admin' }}</p>
|
||||||
<p class="text-xs opacity-75">{{ 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>
|
||||||
</div>
|
</div>
|
||||||
<nav>
|
|
||||||
<ul>
|
<!-- Navigation -->
|
||||||
<li class="mb-2">
|
<nav class="space-y-2">
|
||||||
<a href="{{ route('superadmin.dashboard') }}"
|
<div class="text-xs font-semibold text-slate-400 uppercase tracking-wider mb-4 px-3">
|
||||||
class="flex items-center p-3 rounded-lg hover:bg-blue-700 {{ request()->routeIs('superadmin.dashboard') ? 'bg-blue-700' : '' }}">
|
Main Navigation
|
||||||
<i class="fas fa-tachometer-alt w-5"></i>
|
</div>
|
||||||
<span class="ml-3">Dashboard</span>
|
|
||||||
</a>
|
<a href="{{ route('superadmin.dashboard') }}"
|
||||||
</li>
|
class="nav-item flex items-center p-3 rounded-lg hover:bg-slate-600/30 {{ request()->routeIs('superadmin.dashboard') ? 'nav-active' : '' }} group">
|
||||||
|
<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 text-blue-400 group-hover:text-blue-300"></i>
|
||||||
|
</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>
|
||||||
|
|
||||||
<li class="mb-2">
|
<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="flex items-center p-3 rounded-lg hover:bg-blue-700 {{ request()->routeIs('superadmin.venue.*') ? 'bg-blue-700' : '' }}">
|
<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"></i>
|
<i class="fas fa-building text-emerald-400 group-hover:text-emerald-300"></i>
|
||||||
<span class="ml-3">Manajemen Venue</span>
|
</div>
|
||||||
</a>
|
<div class="ml-4">
|
||||||
</li>
|
<span class="font-medium text-slate-200 group-hover:text-white transition-colors">Manajemen Venue</span>
|
||||||
<li class="mb-2">
|
<p class="text-xs text-slate-400 group-hover:text-slate-300">Kelola semua venue</p>
|
||||||
<a href="{{ route('superadmin.admin.index') }}"
|
</div>
|
||||||
class="flex items-center p-3 rounded-lg hover:bg-blue-700 {{ request()->routeIs('superadmin.admin.*') ? 'bg-blue-700' : '' }}">
|
</a>
|
||||||
<i class="fas fa-users-cog w-5"></i>
|
|
||||||
<span class="ml-3">Manajemen Admin</span>
|
<a href="{{ route('superadmin.admin.index') }}"
|
||||||
</a>
|
class="nav-item flex items-center p-3 rounded-lg hover:bg-slate-600/30 {{ request()->routeIs('superadmin.admin.*') ? 'nav-active' : '' }} group">
|
||||||
</li>
|
<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">
|
||||||
<li class="mb-2">
|
<i class="fas fa-users-cog text-purple-400 group-hover:text-purple-300"></i>
|
||||||
<a href="{{ route('logout') }}"
|
</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 href="{{ route('logout') }}"
|
||||||
onclick="event.preventDefault(); document.getElementById('logout-form').submit();"
|
onclick="event.preventDefault(); document.getElementById('logout-form').submit();"
|
||||||
class="flex items-center p-3 rounded-lg hover:bg-blue-700">
|
class="flex items-center p-3 rounded-lg hover:bg-red-700">
|
||||||
<i class="fas fa-sign-out-alt w-5"></i>
|
<i class="fas fa-sign-out-alt w-5"></i>
|
||||||
<span class="ml-3">Logout</span>
|
<span class="ml-3">Logout</span>
|
||||||
|
<form id="logout-form" action="{{ route('logout') }}" method="POST" class="hidden">
|
||||||
|
@csrf
|
||||||
|
</form>
|
||||||
</a>
|
</a>
|
||||||
<form id="logout-form" action="{{ route('logout') }}" method="POST" class="hidden">
|
|
||||||
@csrf
|
|
||||||
</form>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<!-- Content -->
|
<!-- Content -->
|
||||||
<div :class="sidebarOpen ? 'lg:ml-64' : ''" class="transition-all duration-300">
|
<div :class="sidebarOpen ? 'lg:ml-72' : ''" class="transition-all duration-300">
|
||||||
<!-- Top bar -->
|
<!-- Top bar -->
|
||||||
<header class="bg-white border-b border-gray-200 sticky top-0 z-30">
|
<header class="bg-white/80 backdrop-blur-md border-b border-gray-200/50 sticky top-0 z-30 shadow-sm">
|
||||||
<div class="px-4 py-3 flex items-center justify-between">
|
<div class="px-6 py-4 flex items-center justify-between">
|
||||||
<button @click="sidebarOpen = !sidebarOpen" class="text-gray-600 focus:outline-none">
|
|
||||||
<i class="fas fa-bars"></i>
|
|
||||||
</button>
|
|
||||||
<div class="flex items-center space-x-4">
|
<div class="flex items-center space-x-4">
|
||||||
|
<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">
|
||||||
|
<i class="fas fa-bars text-sm"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Breadcrumb -->
|
||||||
|
<nav class="flex items-center space-x-2 text-sm text-gray-500">
|
||||||
|
<span class="font-medium text-gray-900">Super Admin</span>
|
||||||
|
<i class="fas fa-chevron-right text-xs"></i>
|
||||||
|
<span>Dashboard</span>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center space-x-4">
|
||||||
|
<!-- 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">
|
||||||
|
<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>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Profile Dropdown -->
|
||||||
<div class="relative" x-data="{ open: false }">
|
<div class="relative" x-data="{ open: false }">
|
||||||
<button @click="open = !open" class="flex items-center text-gray-600 focus:outline-none">
|
<button @click="open = !open"
|
||||||
<span class="mr-2">{{ auth()->user()->name ?? 'Admin' }}</span>
|
class="flex items-center space-x-3 p-2 rounded-lg hover:bg-gray-100 transition-colors">
|
||||||
<i class="fas fa-chevron-down text-xs"></i>
|
<div class="w-8 h-8 rounded-full bg-gradient-to-br from-emerald-400 to-cyan-500 flex items-center justify-center">
|
||||||
|
<i class="fas fa-user text-white text-sm"></i>
|
||||||
|
</div>
|
||||||
|
<div class="text-left hidden md:block">
|
||||||
|
<p class="text-sm font-medium text-gray-900">{{ auth()->user()->name ?? 'Admin' }}</p>
|
||||||
|
<p class="text-xs text-gray-500">Super Admin</p>
|
||||||
|
</div>
|
||||||
|
<i class="fas fa-chevron-down text-xs text-gray-400"
|
||||||
|
:class="{ 'rotate-180': open }"
|
||||||
|
style="transition: transform 0.2s"></i>
|
||||||
</button>
|
</button>
|
||||||
<div x-show="open" @click.away="open = false"
|
|
||||||
class="absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg py-1 z-50">
|
<div x-show="open"
|
||||||
<a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Profile</a>
|
@click.away="open = false"
|
||||||
<a href="{{ route('logout') }}"
|
x-transition:enter="transition ease-out duration-200"
|
||||||
|
x-transition:enter-start="opacity-0 scale-95"
|
||||||
|
x-transition:enter-end="opacity-100 scale-100"
|
||||||
|
x-transition:leave="transition ease-in duration-150"
|
||||||
|
x-transition:leave-start="opacity-100 scale-100"
|
||||||
|
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">
|
||||||
|
<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-xs text-gray-500">{{ auth()->user()->email ?? 'admin@example.com' }}</p>
|
||||||
|
</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">
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,120 +1,282 @@
|
||||||
@extends('layouts.super-admin')
|
@extends('layouts.super-admin')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="mb-6">
|
<div class="mb-8">
|
||||||
<h1 class="text-3xl font-bold text-gray-800">Dashboard Super Admin</h1>
|
<h1 class="text-4xl font-bold bg-gradient-to-r from-purple-600 to-pink-600 bg-clip-text text-transparent">
|
||||||
<p class="text-gray-600">Selamat datang di panel kontrol Super Admin</p>
|
Dashboard Super Admin
|
||||||
|
</h1>
|
||||||
|
<p class="text-gray-600 text-lg">Analytics & Overview dari seluruh venue</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
|
<!-- Main Stats Cards -->
|
||||||
<div class="bg-white rounded-lg shadow p-6">
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
|
||||||
<div class="flex items-center justify-between mb-4">
|
<div class="bg-gradient-to-br from-blue-500 to-blue-600 rounded-xl shadow-lg p-6 text-white">
|
||||||
<h2 class="text-xl font-semibold text-gray-800">
|
<div class="flex items-center justify-between">
|
||||||
<i class="fas fa-users-cog mr-2 text-blue-600"></i>Admin
|
<div>
|
||||||
</h2>
|
<p class="text-blue-100 text-sm font-medium">Total Admin</p>
|
||||||
<span class="bg-blue-100 text-blue-800 text-xs font-medium px-3 py-1 rounded-full">
|
<p class="text-3xl font-bold">{{ $adminCount ?? 0 }}</p>
|
||||||
Total: {{ $adminCount ?? 0 }}
|
</div>
|
||||||
</span>
|
<div class="bg-blue-400 bg-opacity-30 rounded-full p-3">
|
||||||
|
<i class="fas fa-users-cog text-2xl"></i>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600 mb-4">Kelola semua admin venue dalam sistem</p>
|
|
||||||
<a href="{{ route('superadmin.admin.index') }}"
|
|
||||||
class="inline-flex items-center text-blue-600 hover:text-blue-800">
|
|
||||||
Lihat Detail
|
|
||||||
<i class="fas fa-arrow-right ml-2"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-white rounded-lg shadow p-6">
|
<div class="bg-gradient-to-br from-emerald-500 to-emerald-600 rounded-xl shadow-lg p-6 text-white">
|
||||||
<div class="flex items-center justify-between mb-4">
|
<div class="flex items-center justify-between">
|
||||||
<h2 class="text-xl font-semibold text-gray-800">
|
<div>
|
||||||
<i class="fas fa-building mr-2 text-green-600"></i>Venue
|
<p class="text-emerald-100 text-sm font-medium">Total Venue</p>
|
||||||
</h2>
|
<p class="text-3xl font-bold">{{ $venueCount ?? 0 }}</p>
|
||||||
<span class="bg-green-100 text-green-800 text-xs font-medium px-3 py-1 rounded-full">
|
</div>
|
||||||
Total: {{ $venueCount ?? 0 }}
|
<div class="bg-emerald-400 bg-opacity-30 rounded-full p-3">
|
||||||
</span>
|
<i class="fas fa-building text-2xl"></i>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600 mb-4">Kelola semua venue dalam sistem</p>
|
|
||||||
<a href="{{ route('superadmin.venue.index') }}"
|
|
||||||
class="inline-flex items-center text-green-600 hover:text-green-800">
|
|
||||||
Lihat Detail
|
|
||||||
<i class="fas fa-arrow-right ml-2"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Recent Activity Section -->
|
<div class="bg-gradient-to-br from-amber-500 to-orange-500 rounded-xl shadow-lg p-6 text-white">
|
||||||
<div class="bg-white rounded-lg shadow overflow-hidden mb-6">
|
<div class="flex items-center justify-between">
|
||||||
<div class="border-b border-gray-200 px-6 py-4">
|
<div>
|
||||||
<h3 class="text-lg font-semibold text-gray-800">Aktivitas Terbaru</h3>
|
<p class="text-amber-100 text-sm font-medium">Total User</p>
|
||||||
|
<p class="text-3xl font-bold">{{ $userCount ?? 0 }}</p>
|
||||||
|
</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>
|
||||||
<div class="p-6">
|
|
||||||
<div class="space-y-4">
|
<div class="bg-gradient-to-br from-purple-500 to-pink-500 rounded-xl shadow-lg p-6 text-white">
|
||||||
<!-- Sample activity items - in production, these would come from database -->
|
<div class="flex items-center justify-between">
|
||||||
<div class="flex items-center">
|
<div>
|
||||||
<div class="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center text-blue-600">
|
<p class="text-purple-100 text-sm font-medium">Total Meja</p>
|
||||||
<i class="fas fa-user-plus"></i>
|
<p class="text-3xl font-bold">{{ $tableCount ?? 0 }}</p>
|
||||||
</div>
|
|
||||||
<div class="ml-4">
|
|
||||||
<p class="text-sm font-medium text-gray-900">Admin baru ditambahkan</p>
|
|
||||||
<p class="text-xs text-gray-500">2 jam yang lalu</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center">
|
<div class="bg-purple-400 bg-opacity-30 rounded-full p-3">
|
||||||
<div class="w-10 h-10 rounded-full bg-green-100 flex items-center justify-center text-green-600">
|
<i class="fas fa-table text-2xl"></i>
|
||||||
<i class="fas fa-building"></i>
|
|
||||||
</div>
|
|
||||||
<div class="ml-4">
|
|
||||||
<p class="text-sm font-medium text-gray-900">Venue baru ditambahkan</p>
|
|
||||||
<p class="text-xs text-gray-500">1 hari yang lalu</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center">
|
|
||||||
<div class="w-10 h-10 rounded-full bg-yellow-100 flex items-center justify-center text-yellow-600">
|
|
||||||
<i class="fas fa-edit"></i>
|
|
||||||
</div>
|
|
||||||
<div class="ml-4">
|
|
||||||
<p class="text-sm font-medium text-gray-900">Venue diperbarui</p>
|
|
||||||
<p class="text-xs text-gray-500">2 hari yang lalu</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Quick Stats -->
|
<!-- Charts Section -->
|
||||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||||
<div class="bg-white rounded-lg shadow p-6">
|
<!-- Revenue Comparison Chart -->
|
||||||
<div class="flex items-center">
|
<div class="bg-white rounded-xl shadow-lg overflow-hidden">
|
||||||
<div class="rounded-full bg-blue-100 p-3">
|
<div class="bg-gradient-to-r from-indigo-500 to-purple-600 px-6 py-4">
|
||||||
<i class="fas fa-users text-blue-600 text-xl"></i>
|
<h3 class="text-xl font-bold text-white flex items-center">
|
||||||
</div>
|
<i class="fas fa-chart-bar mr-3"></i>
|
||||||
<div class="ml-4">
|
Revenue Bulan Ini
|
||||||
<h4 class="text-gray-500 text-sm">Total Pengguna</h4>
|
</h3>
|
||||||
<p class="text-2xl font-bold text-gray-800">{{ $userCount ?? 0 }}</p>
|
<p class="text-indigo-100 text-sm">Per venue - {{ Carbon\Carbon::now()->format('F Y') }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="p-6">
|
||||||
|
<canvas id="revenueChart" width="400" height="300"></canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-white rounded-lg shadow p-6">
|
|
||||||
<div class="flex items-center">
|
<!-- Popular Venues Ranking -->
|
||||||
<div class="rounded-full bg-green-100 p-3">
|
<div class="bg-white rounded-xl shadow-lg overflow-hidden">
|
||||||
<i class="fas fa-check-circle text-green-600 text-xl"></i>
|
<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">
|
||||||
<div class="ml-4">
|
<i class="fas fa-trophy mr-3"></i>
|
||||||
<h4 class="text-gray-500 text-sm">Venue Aktif</h4>
|
Ranking Popularitas
|
||||||
<p class="text-2xl font-bold text-gray-800">{{ $activeVenueCount ?? 0 }}</p>
|
</h3>
|
||||||
</div>
|
<p class="text-pink-100 text-sm">Venue terpopuler bulan ini</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="p-6">
|
||||||
<div class="bg-white rounded-lg shadow p-6">
|
<!-- Filter Toggle -->
|
||||||
<div class="flex items-center">
|
<div class="mb-4">
|
||||||
<div class="rounded-full bg-purple-100 p-3">
|
<div class="bg-gray-100 rounded-lg p-1 flex">
|
||||||
<i class="fas fa-table text-purple-600 text-xl"></i>
|
<button
|
||||||
</div>
|
id="rankingByBookings"
|
||||||
<div class="ml-4">
|
class="flex-1 py-2 px-4 rounded-md text-sm font-medium transition-all duration-200 bg-rose-500 text-white"
|
||||||
<h4 class="text-gray-500 text-sm">Total Meja</h4>
|
onclick="toggleRanking('bookings')">
|
||||||
<p class="text-2xl font-bold text-gray-800">{{ $tableCount ?? 0 }}</p>
|
<i class="fas fa-calendar-check mr-2"></i>
|
||||||
|
Total Booking
|
||||||
|
</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')">
|
||||||
|
<i class="fas fa-money-bill-wave mr-2"></i>
|
||||||
|
Total Revenue
|
||||||
|
</button>
|
||||||
|
</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>
|
||||||
|
<script>
|
||||||
|
// Revenue Chart Data
|
||||||
|
const revenueData = @json($revenueData);
|
||||||
|
|
||||||
|
// Popular Venues Data
|
||||||
|
const popularVenuesData = @json($popularVenuesData);
|
||||||
|
|
||||||
|
// Color Palettes
|
||||||
|
const revenueColors = [
|
||||||
|
'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 = [
|
||||||
|
'rgba(239, 68, 68, 0.8)', // Red
|
||||||
|
'rgba(245, 158, 11, 0.8)', // Amber
|
||||||
|
'rgba(34, 197, 94, 0.8)', // Emerald
|
||||||
|
'rgba(59, 130, 246, 0.8)', // Blue
|
||||||
|
'rgba(168, 85, 247, 0.8)', // Purple
|
||||||
|
];
|
||||||
|
|
||||||
|
// Revenue Chart
|
||||||
|
const revenueCtx = document.getElementById('revenueChart').getContext('2d');
|
||||||
|
const revenueChart = new Chart(revenueCtx, {
|
||||||
|
type: 'bar',
|
||||||
|
data: {
|
||||||
|
labels: revenueData.map(item => item.venue_name),
|
||||||
|
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
|
||||||
|
const popularCtx = document.getElementById('popularVenuesChart').getContext('2d');
|
||||||
|
let popularChart;
|
||||||
|
|
||||||
|
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',
|
||||||
|
data: chartData,
|
||||||
|
options: {
|
||||||
|
indexAxis: 'y',
|
||||||
|
responsive: true,
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
display: false
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
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,
|
||||||
|
ticks: {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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-rose-500 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-rose-500 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>
|
||||||
@endsection
|
@endsection
|
Loading…
Reference in New Issue