SuperAdmin Grafik
This commit is contained in:
parent
ac9d47071e
commit
50accc8a00
|
@ -5,8 +5,11 @@
|
|||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\User;
|
||||
use App\Models\Booking;
|
||||
use App\Models\Venue;
|
||||
use App\Models\Table;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class SuperAdminController extends Controller
|
||||
{
|
||||
|
@ -17,19 +20,63 @@ class SuperAdminController extends Controller
|
|||
*/
|
||||
public function index()
|
||||
{
|
||||
// Menghitung jumlah admin, venue, user, venue aktif, dan meja
|
||||
// Basic counts
|
||||
$adminCount = User::where('role', 'admin')->count();
|
||||
$venueCount = Venue::count();
|
||||
$userCount = User::where('role', 'user')->count();
|
||||
// $activeVenueCount = Venue::where('status', 'active')->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(
|
||||
'adminCount',
|
||||
'venueCount',
|
||||
'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">
|
||||
<!-- Alpine.js -->
|
||||
<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>
|
||||
|
||||
<body class="bg-gray-100">
|
||||
<body class="bg-gray-50">
|
||||
<div x-data="{ sidebarOpen: true }">
|
||||
<!-- Sidebar -->
|
||||
<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">
|
||||
<div class="flex items-center justify-between p-4 border-b border-blue-700">
|
||||
<h2 class="text-2xl font-bold">Venue System</h2>
|
||||
<button @click="sidebarOpen = !sidebarOpen" class="lg:hidden">
|
||||
<i class="fas fa-times"></i>
|
||||
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">
|
||||
|
||||
<!-- Header -->
|
||||
<div class="flex items-center justify-between p-6 border-b border-slate-600/30">
|
||||
<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>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<div class="mb-8">
|
||||
<div class="flex items-center mb-4">
|
||||
<div class="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center">
|
||||
<i class="fas fa-user-shield"></i>
|
||||
|
||||
<!-- Profile Section -->
|
||||
<div class="p-6">
|
||||
<div class="profile-section rounded-xl p-4 mb-6">
|
||||
<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 class="ml-3">
|
||||
<p class="text-sm font-medium">Super Admin</p>
|
||||
<p class="text-xs opacity-75">{{ auth()->user()->name ?? 'Admin' }}</p>
|
||||
<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>
|
||||
<nav>
|
||||
<ul>
|
||||
<li class="mb-2">
|
||||
<a href="{{ route('superadmin.dashboard') }}"
|
||||
class="flex items-center p-3 rounded-lg hover:bg-blue-700 {{ request()->routeIs('superadmin.dashboard') ? 'bg-blue-700' : '' }}">
|
||||
<i class="fas fa-tachometer-alt w-5"></i>
|
||||
<span class="ml-3">Dashboard</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="mb-2">
|
||||
<a href="{{ route('superadmin.venue.index') }}"
|
||||
class="flex items-center p-3 rounded-lg hover:bg-blue-700 {{ request()->routeIs('superadmin.venue.*') ? 'bg-blue-700' : '' }}">
|
||||
<i class="fas fa-building w-5"></i>
|
||||
<span class="ml-3">Manajemen Venue</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mb-2">
|
||||
<a href="{{ route('superadmin.admin.index') }}"
|
||||
class="flex items-center p-3 rounded-lg hover:bg-blue-700 {{ request()->routeIs('superadmin.admin.*') ? 'bg-blue-700' : '' }}">
|
||||
<i class="fas fa-users-cog w-5"></i>
|
||||
<span class="ml-3">Manajemen Admin</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mb-2">
|
||||
<a href="{{ route('logout') }}"
|
||||
<!-- 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') }}"
|
||||
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>
|
||||
|
||||
<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">
|
||||
<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 text-emerald-400 group-hover:text-emerald-300"></i>
|
||||
</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 href="{{ route('logout') }}"
|
||||
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>
|
||||
<span class="ml-3">Logout</span>
|
||||
<form id="logout-form" action="{{ route('logout') }}" method="POST" class="hidden">
|
||||
@csrf
|
||||
</form>
|
||||
</a>
|
||||
<form id="logout-form" action="{{ route('logout') }}" method="POST" class="hidden">
|
||||
@csrf
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- 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 -->
|
||||
<header class="bg-white border-b border-gray-200 sticky top-0 z-30">
|
||||
<div class="px-4 py-3 flex items-center justify-between">
|
||||
<button @click="sidebarOpen = !sidebarOpen" class="text-gray-600 focus:outline-none">
|
||||
<i class="fas fa-bars"></i>
|
||||
</button>
|
||||
<header class="bg-white/80 backdrop-blur-md border-b border-gray-200/50 sticky top-0 z-30 shadow-sm">
|
||||
<div class="px-6 py-4 flex items-center justify-between">
|
||||
<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 }">
|
||||
<button @click="open = !open" class="flex items-center text-gray-600 focus:outline-none">
|
||||
<span class="mr-2">{{ auth()->user()->name ?? 'Admin' }}</span>
|
||||
<i class="fas fa-chevron-down text-xs"></i>
|
||||
<button @click="open = !open"
|
||||
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">
|
||||
<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>
|
||||
<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">
|
||||
<a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Profile</a>
|
||||
<a href="{{ route('logout') }}"
|
||||
|
||||
<div x-show="open"
|
||||
@click.away="open = false"
|
||||
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();"
|
||||
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Logout</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,120 +1,282 @@
|
|||
@extends('layouts.super-admin')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-6">
|
||||
<h1 class="text-3xl font-bold text-gray-800">Dashboard Super Admin</h1>
|
||||
<p class="text-gray-600">Selamat datang di panel kontrol Super Admin</p>
|
||||
<div class="mb-8">
|
||||
<h1 class="text-4xl font-bold bg-gradient-to-r from-purple-600 to-pink-600 bg-clip-text text-transparent">
|
||||
Dashboard Super Admin
|
||||
</h1>
|
||||
<p class="text-gray-600 text-lg">Analytics & Overview dari seluruh venue</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="text-xl font-semibold text-gray-800">
|
||||
<i class="fas fa-users-cog mr-2 text-blue-600"></i>Admin
|
||||
</h2>
|
||||
<span class="bg-blue-100 text-blue-800 text-xs font-medium px-3 py-1 rounded-full">
|
||||
Total: {{ $adminCount ?? 0 }}
|
||||
</span>
|
||||
<!-- 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>
|
||||
<p class="text-blue-100 text-sm font-medium">Total Admin</p>
|
||||
<p class="text-3xl font-bold">{{ $adminCount ?? 0 }}</p>
|
||||
</div>
|
||||
<div class="bg-blue-400 bg-opacity-30 rounded-full p-3">
|
||||
<i class="fas fa-users-cog text-2xl"></i>
|
||||
</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 class="bg-white rounded-lg shadow p-6">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="text-xl font-semibold text-gray-800">
|
||||
<i class="fas fa-building mr-2 text-green-600"></i>Venue
|
||||
</h2>
|
||||
<span class="bg-green-100 text-green-800 text-xs font-medium px-3 py-1 rounded-full">
|
||||
Total: {{ $venueCount ?? 0 }}
|
||||
</span>
|
||||
<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">
|
||||
<div>
|
||||
<p class="text-emerald-100 text-sm font-medium">Total Venue</p>
|
||||
<p class="text-3xl font-bold">{{ $venueCount ?? 0 }}</p>
|
||||
</div>
|
||||
<div class="bg-emerald-400 bg-opacity-30 rounded-full p-3">
|
||||
<i class="fas fa-building text-2xl"></i>
|
||||
</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>
|
||||
|
||||
<!-- Recent Activity Section -->
|
||||
<div class="bg-white rounded-lg shadow overflow-hidden mb-6">
|
||||
<div class="border-b border-gray-200 px-6 py-4">
|
||||
<h3 class="text-lg font-semibold text-gray-800">Aktivitas Terbaru</h3>
|
||||
<div class="bg-gradient-to-br from-amber-500 to-orange-500 rounded-xl shadow-lg p-6 text-white">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<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 class="p-6">
|
||||
<div class="space-y-4">
|
||||
<!-- Sample activity items - in production, these would come from database -->
|
||||
<div class="flex items-center">
|
||||
<div class="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center text-blue-600">
|
||||
<i class="fas fa-user-plus"></i>
|
||||
</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 class="bg-gradient-to-br from-purple-500 to-pink-500 rounded-xl shadow-lg p-6 text-white">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<p class="text-purple-100 text-sm font-medium">Total Meja</p>
|
||||
<p class="text-3xl font-bold">{{ $tableCount ?? 0 }}</p>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<div class="w-10 h-10 rounded-full bg-green-100 flex items-center justify-center text-green-600">
|
||||
<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 class="bg-purple-400 bg-opacity-30 rounded-full p-3">
|
||||
<i class="fas fa-table text-2xl"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Stats -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<div class="flex items-center">
|
||||
<div class="rounded-full bg-blue-100 p-3">
|
||||
<i class="fas fa-users text-blue-600 text-xl"></i>
|
||||
</div>
|
||||
<div class="ml-4">
|
||||
<h4 class="text-gray-500 text-sm">Total Pengguna</h4>
|
||||
<p class="text-2xl font-bold text-gray-800">{{ $userCount ?? 0 }}</p>
|
||||
</div>
|
||||
<!-- Charts Section -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
<!-- Revenue Comparison Chart -->
|
||||
<div class="bg-white rounded-xl shadow-lg overflow-hidden">
|
||||
<div class="bg-gradient-to-r from-indigo-500 to-purple-600 px-6 py-4">
|
||||
<h3 class="text-xl font-bold text-white flex items-center">
|
||||
<i class="fas fa-chart-bar mr-3"></i>
|
||||
Revenue Bulan Ini
|
||||
</h3>
|
||||
<p class="text-indigo-100 text-sm">Per venue - {{ Carbon\Carbon::now()->format('F Y') }}</p>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<canvas id="revenueChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<div class="flex items-center">
|
||||
<div class="rounded-full bg-green-100 p-3">
|
||||
<i class="fas fa-check-circle text-green-600 text-xl"></i>
|
||||
</div>
|
||||
<div class="ml-4">
|
||||
<h4 class="text-gray-500 text-sm">Venue Aktif</h4>
|
||||
<p class="text-2xl font-bold text-gray-800">{{ $activeVenueCount ?? 0 }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Popular Venues Ranking -->
|
||||
<div class="bg-white rounded-xl shadow-lg overflow-hidden">
|
||||
<div class="bg-gradient-to-r from-pink-500 to-rose-600 px-6 py-4">
|
||||
<h3 class="text-xl font-bold text-white flex items-center">
|
||||
<i class="fas fa-trophy mr-3"></i>
|
||||
Ranking Popularitas
|
||||
</h3>
|
||||
<p class="text-pink-100 text-sm">Venue terpopuler bulan ini</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<div class="flex items-center">
|
||||
<div class="rounded-full bg-purple-100 p-3">
|
||||
<i class="fas fa-table text-purple-600 text-xl"></i>
|
||||
</div>
|
||||
<div class="ml-4">
|
||||
<h4 class="text-gray-500 text-sm">Total Meja</h4>
|
||||
<p class="text-2xl font-bold text-gray-800">{{ $tableCount ?? 0 }}</p>
|
||||
<div class="p-6">
|
||||
<!-- Filter Toggle -->
|
||||
<div class="mb-4">
|
||||
<div class="bg-gray-100 rounded-lg p-1 flex">
|
||||
<button
|
||||
id="rankingByBookings"
|
||||
class="flex-1 py-2 px-4 rounded-md text-sm font-medium transition-all duration-200 bg-rose-500 text-white"
|
||||
onclick="toggleRanking('bookings')">
|
||||
<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>
|
||||
<canvas id="popularVenuesChart" width="400" height="300"></canvas>
|
||||
</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
|
Loading…
Reference in New Issue