Admin Revisi Done
This commit is contained in:
parent
1429115bf8
commit
ff6caa6010
|
@ -89,18 +89,23 @@ public function index()
|
||||||
->with(['user', 'table'])
|
->with(['user', 'table'])
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
// Menghitung data analitik untuk diagram booking 7 hari terakhir
|
// Menghitung data analitik untuk diagram pendapatan 7 hari terakhir
|
||||||
$lastWeekBookings = [];
|
$lastWeekRevenue = [];
|
||||||
for ($i = 6; $i >= 0; $i--) {
|
for ($i = 6; $i >= 0; $i--) {
|
||||||
$date = now()->subDays($i);
|
$date = now()->subDays($i);
|
||||||
$count = Booking::whereDate('created_at', $date)
|
$dateStart = $date->copy()->startOfDay();
|
||||||
|
$dateEnd = $date->copy()->endOfDay();
|
||||||
|
|
||||||
|
$dayRevenue = Booking::whereBetween('created_at', [$dateStart, $dateEnd])
|
||||||
->whereHas('table', function ($query) use ($venue) {
|
->whereHas('table', function ($query) use ($venue) {
|
||||||
$query->where('venue_id', $venue->id);
|
$query->where('venue_id', $venue->id);
|
||||||
})
|
})
|
||||||
->count();
|
->where('status', 'paid')
|
||||||
$lastWeekBookings[] = [
|
->sum('total_amount'); // Asumsikan terdapat kolom 'amount' yang menyimpan nilai pembayaran
|
||||||
|
|
||||||
|
$lastWeekRevenue[] = [
|
||||||
'date' => $date->format('d/m'),
|
'date' => $date->format('d/m'),
|
||||||
'count' => $count
|
'revenue' => (float)$dayRevenue // Pastikan revenue dikonversi ke float
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,8 +214,41 @@ public function index()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NEW: REMOVE REVENUE BY DAY OF WEEK
|
// NEW: TOP 5 USERS LEADERBOARD
|
||||||
// Hapus bagian revenueByDay karena tidak diperlukan lagi
|
// Ambil 5 pengguna dengan jumlah booking terbanyak dari 6 bulan terakhir
|
||||||
|
// Kecualikan users yang merupakan admin dari venue yang sedang dilihat
|
||||||
|
$topUsers = Booking::where('bookings.created_at', '>=', now()->subMonths(6))
|
||||||
|
->whereHas('table', function ($query) use ($venue) {
|
||||||
|
$query->where('venue_id', $venue->id);
|
||||||
|
})
|
||||||
|
->join('users', 'bookings.user_id', '=', 'users.id')
|
||||||
|
// Exclude users who are admins of this venue (venue_id matches current venue)
|
||||||
|
->where(function($query) use ($venue) {
|
||||||
|
$query->whereNull('users.venue_id')
|
||||||
|
->orWhere('users.venue_id', '!=', $venue->id);
|
||||||
|
})
|
||||||
|
->select(
|
||||||
|
'user_id',
|
||||||
|
DB::raw('users.name as user_name'),
|
||||||
|
DB::raw('COUNT(*) as booking_count'),
|
||||||
|
DB::raw('SUM(bookings.total_amount) as total_spent')
|
||||||
|
)
|
||||||
|
->groupBy('user_id', 'users.name')
|
||||||
|
->orderBy('booking_count', 'desc')
|
||||||
|
->take(5)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
// Jika tidak ada data, buat array kosong yang terstruktur
|
||||||
|
if ($topUsers->isEmpty()) {
|
||||||
|
$topUsers = collect([
|
||||||
|
[
|
||||||
|
'user_id' => 1,
|
||||||
|
'user_name' => 'Belum ada data',
|
||||||
|
'booking_count' => 0,
|
||||||
|
'total_spent' => 0
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
return view('admin.dashboard', compact(
|
return view('admin.dashboard', compact(
|
||||||
'venue',
|
'venue',
|
||||||
|
@ -225,9 +263,10 @@ public function index()
|
||||||
'monthlyRevenue',
|
'monthlyRevenue',
|
||||||
'pendingBookings',
|
'pendingBookings',
|
||||||
'paidBookings',
|
'paidBookings',
|
||||||
'lastWeekBookings',
|
'lastWeekRevenue',
|
||||||
'lastSixMonthsRevenue',
|
'lastSixMonthsRevenue',
|
||||||
'tableRevenue'
|
'tableRevenue',
|
||||||
|
'topUsers'
|
||||||
// Hapus 'revenueByDay' dari compact
|
// Hapus 'revenueByDay' dari compact
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,12 +107,14 @@ class="font-semibold text-red-500">{{ $usedTables }}</span></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Charts Row 1 -->
|
<!-- Main Performance & Trends Section -->
|
||||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-6">
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-6">
|
||||||
<!-- Weekly Bookings Chart -->
|
<!-- Monthly Revenue Chart - MOVED UP (was 6 months, now showing 12 months) -->
|
||||||
<div class="lg:col-span-2 bg-white rounded-xl shadow-sm p-6">
|
<div class="lg:col-span-2 bg-white rounded-xl shadow-sm p-6">
|
||||||
<h2 class="font-semibold text-lg mb-4">Booking Per Hari (7 Hari Terakhir)</h2>
|
<div class="flex justify-between items-center mb-4">
|
||||||
<div class="h-80" id="bookingsChart"></div>
|
<h2 class="font-semibold text-lg">Tren Pendapatan Bulanan</h2>
|
||||||
|
</div>
|
||||||
|
<div class="h-80" id="monthlyRevenueChart"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Recent Bookings -->
|
<!-- Recent Bookings -->
|
||||||
|
@ -140,11 +142,9 @@ class="font-semibold text-red-500">{{ $usedTables }}</span></p>
|
||||||
<p class="font-medium text-gray-800">{{ $booking->user->name }}</p>
|
<p class="font-medium text-gray-800">{{ $booking->user->name }}</p>
|
||||||
<div class="flex items-center text-sm text-gray-500">
|
<div class="flex items-center text-sm text-gray-500">
|
||||||
<span class="mr-2">{{ $booking->table->name }}</span>
|
<span class="mr-2">{{ $booking->table->name }}</span>
|
||||||
<span
|
<span class="text-xs px-2 py-0.5 rounded-full {{
|
||||||
class="text-xs px-2 py-0.5 rounded-full {{
|
|
||||||
$booking->status === 'paid' ? 'bg-green-100 text-green-800' :
|
$booking->status === 'paid' ? 'bg-green-100 text-green-800' :
|
||||||
($booking->status === 'pending' ? 'bg-amber-100 text-amber-800' :
|
($booking->status === 'pending' ? 'bg-amber-100 text-amber-800' : 'bg-gray-100 text-gray-800')
|
||||||
'bg-gray-100 text-gray-800')
|
|
||||||
}}">
|
}}">
|
||||||
{{ ucfirst($booking->status) }}
|
{{ ucfirst($booking->status) }}
|
||||||
</span>
|
</span>
|
||||||
|
@ -161,27 +161,30 @@ class="text-xs px-2 py-0.5 rounded-full {{
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Charts Row 2 -->
|
<!-- Secondary Performance Section -->
|
||||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-6">
|
||||||
<!-- Monthly Revenue Chart -->
|
<!-- Weekly Revenue Chart -->
|
||||||
<div class="bg-white rounded-xl shadow-sm p-6">
|
<div class="bg-white rounded-xl shadow-sm p-6">
|
||||||
<div class="flex justify-between items-center mb-4">
|
<h2 class="font-semibold text-lg mb-4">Pendapatan 7 Hari Terakhir</h2>
|
||||||
<h2 class="font-semibold text-lg">Pendapatan 6 Bulan Terakhir</h2>
|
<div class="h-80" id="weeklyRevenueChart"></div>
|
||||||
</div>
|
|
||||||
<div class="h-80" id="monthlyRevenueChart"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Charts Row 3 -->
|
<!-- Table Revenue Performance - MOVED UP -->
|
||||||
<div class="grid grid-cols-1 gap-6">
|
<div class="lg:col-span-2 bg-white rounded-xl shadow-sm p-6">
|
||||||
<!-- Table Revenue Performance -->
|
|
||||||
<div class="bg-white rounded-xl shadow-sm p-6">
|
|
||||||
<div class="flex justify-between items-center mb-4">
|
<div class="flex justify-between items-center mb-4">
|
||||||
<h2 class="font-semibold text-lg">Performa Pendapatan per Meja (Bulan Ini)</h2>
|
<h2 class="font-semibold text-lg">Performa Pendapatan per Meja (Bulan Ini)</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="h-96" id="tableRevenueChart"></div>
|
<div class="h-80" id="tableRevenueChart"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Customer Insights Section -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm p-6 mb-6">
|
||||||
|
<div class="flex justify-between items-center mb-4">
|
||||||
|
<h2 class="font-semibold text-lg">Top 5 Pelanggan Loyal</h2>
|
||||||
|
</div>
|
||||||
|
<div class="h-80" id="topUsersChart"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -189,67 +192,7 @@ class="text-xs px-2 py-0.5 rounded-full {{
|
||||||
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
|
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
// Booking Chart
|
// Monthly Revenue Chart - ENHANCED TO SHOW 12 MONTHS
|
||||||
var bookingData = @json($lastWeekBookings);
|
|
||||||
|
|
||||||
var options = {
|
|
||||||
series: [{
|
|
||||||
name: 'Booking',
|
|
||||||
data: bookingData.map(item => item.count)
|
|
||||||
}],
|
|
||||||
chart: {
|
|
||||||
type: 'bar',
|
|
||||||
height: 300,
|
|
||||||
toolbar: {
|
|
||||||
show: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
plotOptions: {
|
|
||||||
bar: {
|
|
||||||
borderRadius: 4,
|
|
||||||
columnWidth: '60%',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
colors: ['#3b82f6'],
|
|
||||||
dataLabels: {
|
|
||||||
enabled: false
|
|
||||||
},
|
|
||||||
xaxis: {
|
|
||||||
categories: bookingData.map(item => item.date),
|
|
||||||
axisBorder: {
|
|
||||||
show: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
yaxis: {
|
|
||||||
title: {
|
|
||||||
text: 'Jumlah Booking'
|
|
||||||
},
|
|
||||||
labels: {
|
|
||||||
formatter: function (val) {
|
|
||||||
return Math.floor(val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
fill: {
|
|
||||||
opacity: 1
|
|
||||||
},
|
|
||||||
tooltip: {
|
|
||||||
y: {
|
|
||||||
formatter: function (val) {
|
|
||||||
return val + " booking";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
grid: {
|
|
||||||
borderColor: '#f3f4f6',
|
|
||||||
strokeDashArray: 5
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var chart = new ApexCharts(document.querySelector("#bookingsChart"), options);
|
|
||||||
chart.render();
|
|
||||||
|
|
||||||
// Monthly Revenue Chart
|
|
||||||
var monthlyRevenueData = @json($lastSixMonthsRevenue);
|
var monthlyRevenueData = @json($lastSixMonthsRevenue);
|
||||||
|
|
||||||
var monthlyRevenueOptions = {
|
var monthlyRevenueOptions = {
|
||||||
|
@ -319,110 +262,141 @@ class="text-xs px-2 py-0.5 rounded-full {{
|
||||||
colors: ['#10b981'],
|
colors: ['#10b981'],
|
||||||
strokeColor: '#fff',
|
strokeColor: '#fff',
|
||||||
strokeWidth: 2
|
strokeWidth: 2
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: 'Tren Pendapatan Bulanan',
|
||||||
|
align: 'center',
|
||||||
|
style: {
|
||||||
|
fontSize: '18px',
|
||||||
|
fontWeight: 'medium'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var monthlyRevenueChart = new ApexCharts(document.querySelector("#monthlyRevenueChart"), monthlyRevenueOptions);
|
var monthlyRevenueChart = new ApexCharts(document.querySelector("#monthlyRevenueChart"), monthlyRevenueOptions);
|
||||||
monthlyRevenueChart.render();
|
monthlyRevenueChart.render();
|
||||||
|
|
||||||
// Table Revenue Performance Chart
|
// Weekly Revenue Chart
|
||||||
var tableRevenueData = @json($tableRevenue);
|
var weeklyRevenueData = @json($lastWeekRevenue);
|
||||||
|
|
||||||
var tableRevenueOptions = {
|
var options = {
|
||||||
series: [{
|
series: [{
|
||||||
name: 'Pendapatan',
|
name: 'Pendapatan',
|
||||||
data: tableRevenueData.map(item => item.table_revenue)
|
data: weeklyRevenueData.map(item => item.revenue)
|
||||||
}, {
|
|
||||||
name: 'Jumlah Booking',
|
|
||||||
data: tableRevenueData.map(item => item.booking_count)
|
|
||||||
}],
|
}],
|
||||||
chart: {
|
chart: {
|
||||||
type: 'bar',
|
type: 'bar',
|
||||||
height: 350,
|
height: 300,
|
||||||
stacked: false,
|
|
||||||
toolbar: {
|
toolbar: {
|
||||||
show: false
|
show: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
plotOptions: {
|
plotOptions: {
|
||||||
bar: {
|
bar: {
|
||||||
horizontal: true,
|
borderRadius: 4,
|
||||||
barHeight: '70%',
|
columnWidth: '60%',
|
||||||
dataLabels: {
|
|
||||||
position: 'top'
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
colors: ['#10b981'],
|
||||||
|
dataLabels: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
xaxis: {
|
||||||
|
categories: weeklyRevenueData.map(item => item.date),
|
||||||
|
axisBorder: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yaxis: {
|
||||||
|
title: {
|
||||||
|
text: 'Pendapatan (Rp)'
|
||||||
|
},
|
||||||
|
labels: {
|
||||||
|
formatter: function (val) {
|
||||||
|
return 'Rp' + Math.floor(val).toLocaleString('id-ID');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fill: {
|
||||||
|
opacity: 1
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
y: {
|
||||||
|
formatter: function (val) {
|
||||||
|
return 'Rp' + val.toLocaleString('id-ID');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
borderColor: '#f3f4f6',
|
||||||
|
strokeDashArray: 5
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var chart = new ApexCharts(document.querySelector("#weeklyRevenueChart"), options);
|
||||||
|
chart.render();
|
||||||
|
|
||||||
|
// Table Revenue Performance Chart - ENHANCED WITH IMPROVED VISUALS
|
||||||
|
var tableRevenueData = @json($tableRevenue);
|
||||||
|
|
||||||
|
// Verifikasi data tersedia dan lengkap
|
||||||
|
if (!tableRevenueData || tableRevenueData.length === 0) {
|
||||||
|
document.getElementById("tableRevenueChart").innerHTML =
|
||||||
|
'<div class="flex items-center justify-center h-full"><p class="text-gray-500">Tidak ada data tersedia</p></div>';
|
||||||
|
} else {
|
||||||
|
var tableRevenueOptions = {
|
||||||
|
series: [{
|
||||||
|
name: 'Pendapatan',
|
||||||
|
data: tableRevenueData.map(item => item.table_revenue || 0)
|
||||||
|
}, {
|
||||||
|
name: 'Jumlah Booking',
|
||||||
|
data: tableRevenueData.map(item => item.booking_count || 0)
|
||||||
|
}],
|
||||||
|
chart: {
|
||||||
|
type: 'bar',
|
||||||
|
height: 300,
|
||||||
|
toolbar: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plotOptions: {
|
||||||
|
bar: {
|
||||||
|
horizontal: false,
|
||||||
|
columnWidth: '55%',
|
||||||
|
endingShape: 'rounded'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
colors: ['#f97316', '#3b82f6'],
|
colors: ['#f97316', '#3b82f6'],
|
||||||
dataLabels: {
|
dataLabels: {
|
||||||
enabled: true,
|
enabled: false
|
||||||
formatter: function (val, opts) {
|
|
||||||
if (opts.seriesIndex === 0) {
|
|
||||||
return 'Rp' + val.toLocaleString('id-ID');
|
|
||||||
} else {
|
|
||||||
return val + ' booking';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
style: {
|
|
||||||
fontSize: '12px',
|
|
||||||
colors: ['#333']
|
|
||||||
},
|
|
||||||
offsetX: 0
|
|
||||||
},
|
},
|
||||||
stroke: {
|
stroke: {
|
||||||
width: 1,
|
show: true,
|
||||||
colors: ['#fff']
|
width: 2,
|
||||||
|
colors: ['transparent']
|
||||||
},
|
},
|
||||||
xaxis: {
|
xaxis: {
|
||||||
categories: tableRevenueData.map(item => item.table_name),
|
categories: tableRevenueData.map(item => item.table_name || 'Tidak ada nama')
|
||||||
labels: {
|
|
||||||
formatter: function (val) {
|
|
||||||
return val; // Simplified formatter for table names
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
yaxis: [
|
yaxis: [
|
||||||
{
|
{
|
||||||
axisTicks: {
|
title: {
|
||||||
show: true,
|
text: 'Pendapatan (Rp)'
|
||||||
},
|
|
||||||
axisBorder: {
|
|
||||||
show: true,
|
|
||||||
color: '#f97316'
|
|
||||||
},
|
},
|
||||||
labels: {
|
labels: {
|
||||||
style: {
|
|
||||||
colors: '#f97316',
|
|
||||||
},
|
|
||||||
formatter: function (val) {
|
formatter: function (val) {
|
||||||
return 'Rp' + val.toLocaleString('id-ID');
|
return 'Rp' + Math.floor(val).toLocaleString('id-ID');
|
||||||
}
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
text: "Pendapatan (Rp)",
|
|
||||||
style: {
|
|
||||||
color: '#f97316',
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
opposite: true,
|
opposite: true,
|
||||||
axisTicks: {
|
title: {
|
||||||
show: true,
|
text: 'Jumlah Booking'
|
||||||
},
|
|
||||||
axisBorder: {
|
|
||||||
show: true,
|
|
||||||
color: '#3b82f6'
|
|
||||||
},
|
},
|
||||||
labels: {
|
labels: {
|
||||||
style: {
|
formatter: function (val) {
|
||||||
colors: '#3b82f6',
|
return Math.floor(val);
|
||||||
}
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
text: "Jumlah Booking",
|
|
||||||
style: {
|
|
||||||
color: '#3b82f6',
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -438,19 +412,115 @@ class="text-xs px-2 py-0.5 rounded-full {{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
fill: {
|
||||||
|
opacity: 1
|
||||||
|
},
|
||||||
legend: {
|
legend: {
|
||||||
position: 'top',
|
position: 'top',
|
||||||
horizontalAlign: 'left',
|
horizontalAlign: 'left'
|
||||||
offsetY: 10
|
|
||||||
},
|
},
|
||||||
grid: {
|
title: {
|
||||||
borderColor: '#f3f4f6',
|
text: 'Analisis Performa Meja',
|
||||||
strokeDashArray: 5
|
align: 'center',
|
||||||
|
style: {
|
||||||
|
fontSize: '18px',
|
||||||
|
fontWeight: 'medium'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var tableRevenueChart = new ApexCharts(document.querySelector("#tableRevenueChart"), tableRevenueOptions);
|
var tableRevenueChart = new ApexCharts(document.querySelector("#tableRevenueChart"), tableRevenueOptions);
|
||||||
tableRevenueChart.render();
|
tableRevenueChart.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top 5 Users Chart - ENHANCED WITH IMPROVED VISUALS
|
||||||
|
var topUsersData = @json($topUsers);
|
||||||
|
|
||||||
|
// Verifikasi data tersedia dan lengkap
|
||||||
|
if (!topUsersData || topUsersData.length === 0) {
|
||||||
|
document.getElementById("topUsersChart").innerHTML =
|
||||||
|
'<div class="flex items-center justify-center h-full"><p class="text-gray-500">Tidak ada data tersedia</p></div>';
|
||||||
|
} else {
|
||||||
|
var topUsersOptions = {
|
||||||
|
series: [{
|
||||||
|
name: 'Jumlah Booking',
|
||||||
|
data: topUsersData.map(item => item.booking_count)
|
||||||
|
}],
|
||||||
|
chart: {
|
||||||
|
type: 'bar',
|
||||||
|
height: 300,
|
||||||
|
toolbar: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plotOptions: {
|
||||||
|
bar: {
|
||||||
|
borderRadius: 4,
|
||||||
|
horizontal: true,
|
||||||
|
distributed: true,
|
||||||
|
dataLabels: {
|
||||||
|
position: 'top'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
colors: ['#8b5cf6', '#6366f1', '#4f46e5', '#4338ca', '#3730a3'],
|
||||||
|
dataLabels: {
|
||||||
|
enabled: true,
|
||||||
|
formatter: function (val) {
|
||||||
|
return val + ' booking';
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
fontSize: '12px',
|
||||||
|
colors: ['#304758']
|
||||||
|
},
|
||||||
|
offsetX: 30
|
||||||
|
},
|
||||||
|
xaxis: {
|
||||||
|
categories: topUsersData.map(item => item.user_name),
|
||||||
|
labels: {
|
||||||
|
style: {
|
||||||
|
fontSize: '12px'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yaxis: {
|
||||||
|
title: {
|
||||||
|
text: 'Pelanggan'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
y: {
|
||||||
|
formatter: function (val) {
|
||||||
|
return val + ' booking';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fill: {
|
||||||
|
opacity: 1,
|
||||||
|
type: 'gradient',
|
||||||
|
gradient: {
|
||||||
|
shade: 'dark',
|
||||||
|
type: "horizontal",
|
||||||
|
shadeIntensity: 0.5,
|
||||||
|
inverseColors: true,
|
||||||
|
opacityFrom: 1,
|
||||||
|
opacityTo: 0.8,
|
||||||
|
stops: [0, 100]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: 'Pelanggan dengan Booking Terbanyak',
|
||||||
|
align: 'center',
|
||||||
|
style: {
|
||||||
|
fontSize: '18px',
|
||||||
|
fontWeight: 'medium'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var topUsersChart = new ApexCharts(document.querySelector("#topUsersChart"), topUsersOptions);
|
||||||
|
topUsersChart.render();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@endpush
|
@endpush
|
||||||
|
|
|
@ -12,18 +12,23 @@
|
||||||
<form method="GET" action="{{ route('admin.revenues.index') }}" class="mb-8">
|
<form method="GET" action="{{ route('admin.revenues.index') }}" class="mb-8">
|
||||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-6">
|
<div class="grid grid-cols-1 md:grid-cols-4 gap-6">
|
||||||
<div>
|
<div>
|
||||||
<label for="start_date" class="block text-sm font-medium text-gray-700 mb-1">Tanggal Mulai</label>
|
<label for="start_date" class="block text-sm font-medium text-gray-700 mb-1">Tanggal
|
||||||
<input type="date" class="w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
|
Mulai</label>
|
||||||
|
<input type="date"
|
||||||
|
class="w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
|
||||||
id="start_date" name="start_date" value="{{ $startDate }}">
|
id="start_date" name="start_date" value="{{ $startDate }}">
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="end_date" class="block text-sm font-medium text-gray-700 mb-1">Tanggal Akhir</label>
|
<label for="end_date" class="block text-sm font-medium text-gray-700 mb-1">Tanggal
|
||||||
<input type="date" class="w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
|
Akhir</label>
|
||||||
|
<input type="date"
|
||||||
|
class="w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
|
||||||
id="end_date" name="end_date" value="{{ $endDate }}">
|
id="end_date" name="end_date" value="{{ $endDate }}">
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="venue_id" class="block text-sm font-medium text-gray-700 mb-1">Venue</label>
|
<label for="venue_id" class="block text-sm font-medium text-gray-700 mb-1">Venue</label>
|
||||||
<select class="w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
|
<select
|
||||||
|
class="w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
|
||||||
id="venue_id" name="venue_id">
|
id="venue_id" name="venue_id">
|
||||||
<option value="">Semua Venue</option>
|
<option value="">Semua Venue</option>
|
||||||
@foreach($venues as $venue)
|
@foreach($venues as $venue)
|
||||||
|
@ -35,15 +40,21 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-end">
|
<div class="flex items-end">
|
||||||
<div class="flex space-x-2">
|
<div class="flex space-x-2">
|
||||||
<button type="submit" class="inline-flex items-center px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
<button type="submit"
|
||||||
<svg class="h-4 w-4 mr-1.5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
class="inline-flex items-center px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z" />
|
<svg class="h-4 w-4 mr-1.5" xmlns="http://www.w3.org/2000/svg" fill="none"
|
||||||
|
viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z" />
|
||||||
</svg>
|
</svg>
|
||||||
Filter
|
Filter
|
||||||
</button>
|
</button>
|
||||||
<a href="{{ route('admin.revenues.export', request()->query()) }}" class="inline-flex items-center px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500">
|
<a href="{{ route('admin.revenues.export', request()->query()) }}"
|
||||||
<svg class="h-4 w-4 mr-1.5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
class="inline-flex items-center px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
|
<svg class="h-4 w-4 mr-1.5" xmlns="http://www.w3.org/2000/svg" fill="none"
|
||||||
|
viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
|
||||||
</svg>
|
</svg>
|
||||||
Export
|
Export
|
||||||
</a>
|
</a>
|
||||||
|
@ -54,13 +65,16 @@
|
||||||
|
|
||||||
<!-- Summary Cards -->
|
<!-- Summary Cards -->
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
|
||||||
<div class="bg-gradient-to-br from-blue-50 to-indigo-50 rounded-xl shadow p-6 border border-blue-100">
|
<div
|
||||||
|
class="bg-gradient-to-br from-blue-50 to-indigo-50 rounded-xl shadow p-6 border border-blue-100">
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<h3 class="text-lg font-medium text-gray-700 mb-2">Total Pendapatan</h3>
|
<h3 class="text-lg font-medium text-gray-700 mb-2">Total Pendapatan</h3>
|
||||||
<p class="text-3xl font-bold text-indigo-600">Rp {{ number_format($totalRevenue, 0, ',', '.') }}</p>
|
<p class="text-3xl font-bold text-indigo-600">Rp
|
||||||
|
{{ number_format($totalRevenue, 0, ',', '.') }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-gradient-to-br from-purple-50 to-pink-50 rounded-xl shadow p-6 border border-purple-100">
|
<div
|
||||||
|
class="bg-gradient-to-br from-purple-50 to-pink-50 rounded-xl shadow p-6 border border-purple-100">
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<h3 class="text-lg font-medium text-gray-700 mb-2">Total Booking</h3>
|
<h3 class="text-lg font-medium text-gray-700 mb-2">Total Booking</h3>
|
||||||
<p class="text-3xl font-bold text-purple-600">{{ $totalBookings }}</p>
|
<p class="text-3xl font-bold text-purple-600">{{ $totalBookings }}</p>
|
||||||
|
@ -68,55 +82,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Chart for Daily Revenue -->
|
|
||||||
<div class="mb-8">
|
|
||||||
<div class="bg-white rounded-xl shadow-lg border border-gray-100 overflow-hidden">
|
|
||||||
<div class="bg-gradient-to-r from-gray-50 to-gray-100 px-6 py-4 border-b border-gray-200">
|
|
||||||
<h3 class="text-lg font-medium text-gray-800">Grafik Pendapatan Harian</h3>
|
|
||||||
</div>
|
|
||||||
<div class="p-6">
|
|
||||||
<canvas id="dailyRevenueChart" height="300"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Revenue Per Venue Table -->
|
|
||||||
<div class="mb-8">
|
|
||||||
<div class="bg-white rounded-xl shadow-lg border border-gray-100 overflow-hidden">
|
|
||||||
<div class="bg-gradient-to-r from-gray-50 to-gray-100 px-6 py-4 border-b border-gray-200">
|
|
||||||
<h3 class="text-lg font-medium text-gray-800">Pendapatan Per Venue</h3>
|
|
||||||
</div>
|
|
||||||
<div class="p-6">
|
|
||||||
<div class="overflow-x-auto">
|
|
||||||
<table class="min-w-full divide-y divide-gray-200">
|
|
||||||
<thead class="bg-gray-50">
|
|
||||||
<tr>
|
|
||||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Venue</th>
|
|
||||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Total Booking</th>
|
|
||||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Total Pendapatan</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody class="bg-white divide-y divide-gray-200">
|
|
||||||
@forelse($revenuePerVenue as $venueRevenue)
|
|
||||||
<tr class="hover:bg-gray-50">
|
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{{ $venueRevenue->venue_name }}</td>
|
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ $venueRevenue->total_bookings }}</td>
|
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 font-semibold">
|
|
||||||
Rp {{ number_format($venueRevenue->total_revenue, 0, ',', '.') }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
@empty
|
|
||||||
<tr>
|
|
||||||
<td colspan="3" class="px-6 py-4 whitespace-nowrap text-sm text-gray-500 text-center">Tidak ada data pendapatan</td>
|
|
||||||
</tr>
|
|
||||||
@endforelse
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Revenue Per Table -->
|
<!-- Revenue Per Table -->
|
||||||
@if($revenuePerTable)
|
@if($revenuePerTable)
|
||||||
<div>
|
<div>
|
||||||
|
@ -129,26 +94,40 @@
|
||||||
<table class="min-w-full divide-y divide-gray-200">
|
<table class="min-w-full divide-y divide-gray-200">
|
||||||
<thead class="bg-gray-50">
|
<thead class="bg-gray-50">
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Meja</th>
|
<th scope="col"
|
||||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Jumlah Booking</th>
|
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Total Pendapatan</th>
|
Meja</th>
|
||||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Aksi</th>
|
<th scope="col"
|
||||||
|
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||||
|
Jumlah Booking</th>
|
||||||
|
<th scope="col"
|
||||||
|
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||||
|
Total Pendapatan</th>
|
||||||
|
<th scope="col"
|
||||||
|
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||||
|
Aksi</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="bg-white divide-y divide-gray-200">
|
<tbody class="bg-white divide-y divide-gray-200">
|
||||||
@forelse($revenuePerTable as $tableRevenue)
|
@forelse($revenuePerTable as $tableRevenue)
|
||||||
<tr class="hover:bg-gray-50">
|
<tr class="hover:bg-gray-50">
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{{ $tableRevenue->table_name }}</td>
|
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ $tableRevenue->booking_count }}</td>
|
{{ $tableRevenue->table_name }}</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||||
|
{{ $tableRevenue->booking_count }}</td>
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 font-semibold">
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 font-semibold">
|
||||||
Rp {{ number_format($tableRevenue->table_revenue, 0, ',', '.') }}
|
Rp {{ number_format($tableRevenue->table_revenue, 0, ',', '.') }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
||||||
<a href="{{ route('admin.revenues.detail', ['tableId' => $tableRevenue->table_id, 'start_date' => $startDate, 'end_date' => $endDate]) }}"
|
<a href="{{ route('admin.revenues.detail', ['tableId' => $tableRevenue->table_id, 'start_date' => $startDate, 'end_date' => $endDate]) }}"
|
||||||
class="inline-flex items-center px-3 py-1.5 border border-transparent text-xs leading-4 font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
class="inline-flex items-center px-3 py-1.5 border border-transparent text-xs leading-4 font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
||||||
<svg class="h-4 w-4 mr-1" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
<svg class="h-4 w-4 mr-1" xmlns="http://www.w3.org/2000/svg"
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
<path stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
||||||
</svg>
|
</svg>
|
||||||
Detail
|
Detail
|
||||||
</a>
|
</a>
|
||||||
|
@ -156,7 +135,9 @@ class="inline-flex items-center px-3 py-1.5 border border-transparent text-xs le
|
||||||
</tr>
|
</tr>
|
||||||
@empty
|
@empty
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="4" class="px-6 py-4 whitespace-nowrap text-sm text-gray-500 text-center">Tidak ada data pendapatan meja</td>
|
<td colspan="4"
|
||||||
|
class="px-6 py-4 whitespace-nowrap text-sm text-gray-500 text-center">
|
||||||
|
Tidak ada data pendapatan meja</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endforelse
|
@endforelse
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -117,7 +117,7 @@ class="nav-item flex items-center px-3 py-2.5 rounded-lg {{ request()->routeIs('
|
||||||
<span x-show="sidebarOpen">Daftar Booking</span>
|
<span x-show="sidebarOpen">Daftar Booking</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('admin.revenues.index') }}"
|
<a href="{{ route('admin.revenues.index') }}"
|
||||||
class="nav-item flex items-center px-3 py-2.5 rounded-lg {{ request()->routeIs('admin.bookings.*') ? 'active' : '' }}">
|
class="nav-item flex items-center px-3 py-2.5 rounded-lg {{ request()->routeIs('admin.revenues.*') ? 'active' : '' }}">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24"
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24"
|
||||||
stroke="currentColor">
|
stroke="currentColor">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
|
Loading…
Reference in New Issue