This commit is contained in:
Stephen Gesityan 2025-06-15 15:17:49 +07:00
parent 2d82a9489e
commit f5cf7a4f8a
14 changed files with 480 additions and 472 deletions

View File

@ -162,6 +162,7 @@ public function createPaymentIntent(Request $request) {
// Validasi waktu booking dalam jam operasional venue
$venueOpenTime = Carbon::createFromFormat('H:i:s', $table->venue->open_time)->format('H:i');
$venueCloseTime = Carbon::createFromFormat('H:i:s', $table->venue->close_time)->format('H:i');
$venueCloseDateTime = Carbon::createFromFormat('Y-m-d H:i', $bookingDate . ' ' . $venueCloseTime, 'Asia/Jakarta');
if ($startTime < $venueOpenTime || $startTime >= $venueCloseTime) {
return response()->json([
@ -171,7 +172,7 @@ public function createPaymentIntent(Request $request) {
}
// Validasi bahwa end time tidak melebihi jam tutup venue
if ($endDateTime->format('H:i') > $venueCloseTime) {
if ($endDateTime->gt($venueCloseDateTime)) {
return response()->json([
'success' => false,
'message' => 'Durasi booking melebihi jam tutup venue'

View File

@ -2,6 +2,7 @@
namespace App\Providers;
use Carbon\Carbon;
use Illuminate\Support\ServiceProvider;
use App\Services\MidtransService;
@ -20,8 +21,8 @@ public function register(): void
/**
* Bootstrap any application services.
*/
public function boot(): void
{
//
}
public function boot()
{
Carbon::setLocale('id');
}
}

View File

@ -3,19 +3,22 @@
@section('content')
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
<div class="flex flex-col md:flex-row justify-between items-center mb-6">
<h1 class="text-3xl font-bold text-gray-800 mb-4 md:mb-0">
<i class="fas fa-calendar-check mr-2"></i>Daftar Booking
</h1>
<h1 class="text-3xl font-bold text-gray-800 mb-4 md:mb-0">
<i class="fas fa-calendar-check mr-2"></i>Daftar Booking
</h1>
<div class="flex flex-col md:flex-row gap-3 w-full md:w-auto">
<a href="{{ route('admin.dashboard') }}" class="btn btn-secondary">
<i class="fas fa-arrow-left mr-1"></i> Kembali
</a>
{{-- <a href="{{ route('admin.bookings.export') }}" class="btn btn-success">
<i class="fas fa-file-excel mr-1"></i> Export Excel
</a> --}}
</div>
</div>
<div class="flex flex-col md:flex-row gap-3 w-full md:w-auto">
<a href="/"
class="inline-flex items-center justify-center px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-lg shadow transition duration-300 w-full md:w-auto text-center">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd"
d="M10 5a1 1 0 011 1v3h3a1 1 0 110 2h-3v3a1 1 0 11-2 0v-3H6a1 1 0 110-2h3V6a1 1 0 011-1z"
clip-rule="evenodd" />
</svg>
Buat Booking
</a>
</div>
</div>
<!-- Search and Filter Card -->
<div class="bg-white rounded-lg shadow-md p-4 mb-6">

View File

@ -4,17 +4,18 @@
<div class="bg-gray-50 min-h-screen">
<div class="p-6">
<!-- Header and Welcome -->
<div class="flex justify-between items-center mb-6">
<div class="flex flex-col sm:flex-row sm:justify-between sm:items-center mb-6 space-y-4 sm:space-y-0">
<div>
<h1 class="text-3xl font-bold text-gray-800">Dashboard {{ $venue->name }}</h1>
<h1 class="text-2xl sm:text-3xl font-bold text-gray-800">Dashboard {{ $venue->name }}</h1>
<p class="text-gray-600 mt-1">Selamat datang, {{ auth()->user()->name }}!</p>
</div>
<div class="text-right">
<p class="text-sm text-gray-500">{{ now()->format('l, d F Y') }}</p>
<p class="text-2xl font-semibold text-gray-800">{{ now()->format('H:i') }}</p>
<div class="text-left sm:text-right">
<p class="text-sm text-gray-500">{{ now()->translatedFormat('l, d F Y') }}</p>
<p class="text-xl sm:text-2xl font-semibold text-gray-800">{{ now()->translatedFormat('H:i') }}</p>
</div>
</div>
<!-- Stats Cards - Row 1: Revenue and Booking Cards -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
<!-- Today's Revenue -->
@ -53,8 +54,8 @@
</div>
</div>
<div class="flex mt-2 space-x-4">
<p class="text-xs text-gray-500">Pending: <span
class="font-semibold text-amber-500">{{ $pendingBookings }}</span></p>
{{-- <p class="text-xs text-gray-500">Pending: <span class="font-semibold text-amber-500">{{
$pendingBookings }}</span></p> --}}
<p class="text-xs text-gray-500">Paid: <span
class="font-semibold text-green-500">{{ $paidBookings }}</span></p>
</div>
@ -158,9 +159,9 @@ class="flex items-center justify-center w-12 h-12 bg-gradient-to-br from-orange-
<span class="mr-2">{{ $booking->table->name }}</span>
<span
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' : 'bg-gray-100 text-gray-800')
}}">
}}">
{{ ucfirst($booking->status) }}
</span>
</div>

View File

@ -3,10 +3,10 @@
@section('content')
<div class="p-6 bg-gray-50">
<!-- Header dengan Action Button -->
<div class="flex justify-between items-center mb-6">
<div class="flex flex-col sm:flex-row sm:justify-between sm:items-center gap-4 mb-6">
<h1 class="text-3xl font-bold text-gray-800">Kelola Meja</h1>
<a href="{{ route('admin.tables.create') }}"
class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg flex items-center transition-colors duration-300">
class="w-full sm:w-auto bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg flex items-center justify-center transition-colors duration-300">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd"
d="M10 5a1 1 0 011 1v3h3a1 1 0 110 2h-3v3a1 1 0 11-2 0v-3H6a1 1 0 110-2h3V6a1 1 0 011-1z"
@ -16,6 +16,7 @@ class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg flex items-
</a>
</div>
<!-- Flash Message -->
@if(session('success'))
<div class="bg-green-100 border-l-4 border-green-500 text-green-700 p-4 mb-6 rounded shadow-md" role="alert">
@ -38,16 +39,16 @@ class="md:flex items-center space-y-4 md:space-y-0 md:space-x-4">
<input type="text" name="search" value="{{ request('search') }}" placeholder="Cari nama meja..."
class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
<div class="md:w-1/4">
{{-- <div class="md:w-1/4">
<select name="status"
class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
<option value="">Semua Status</option>
<option value="Available" {{ request('status') == 'Available' ? 'selected' : '' }}>Available</option>
<option value="Booked" {{ request('status') == 'Booked' ? 'selected' : '' }}>Booked</option>
<option value="Unavailable" {{ request('status') == 'Unavailable' ? 'selected' : '' }}>Unavailable
<option value="Available" {{ request('status')=='Available' ? 'selected' : '' }}>Available</option>
<option value="Booked" {{ request('status')=='Booked' ? 'selected' : '' }}>Booked</option>
<option value="Unavailable" {{ request('status')=='Unavailable' ? 'selected' : '' }}>Unavailable
</option>
</select>
</div>
</div> --}}
<div class="flex space-x-2">
<button type="submit"
class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors duration-300">

View File

@ -4,15 +4,18 @@
<div class="p-6">
<!-- Header -->
<div class="mb-6">
<div class="flex items-center justify-between">
<div class="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
<!-- Judul -->
<div>
<h1 class="text-2xl font-bold text-gray-900">Kelola Venue</h1>
<p class="text-gray-600 mt-1">Kelola informasi venue Anda</p>
</div>
<div class="flex space-x-3">
<!-- Venue Status Toggle -->
<!-- Aksi -->
<div class="flex flex-col sm:flex-row sm:items-center gap-4">
<!-- Status Venue -->
<div class="flex items-center space-x-3">
<span class="text-sm font-medium text-gray-700">Status Venue:</span>
<span class="text-sm font-medium text-gray-700 whitespace-nowrap">Status Venue:</span>
<div class="relative">
<button id="statusToggle"
class="relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 {{ $venue->status === 'open' ? 'bg-green-600' : 'bg-red-600' }}"
@ -28,9 +31,10 @@ class="text-sm font-medium {{ $venue->status === 'open' ? 'text-green-600' : 'te
</span>
</div>
<!-- Tombol Edit -->
<a href="{{ route('admin.venue.edit') }}"
class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg font-medium transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 inline mr-2" fill="none" viewBox="0 0 24 24"
class="flex items-center justify-center bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium px-4 py-2 rounded-lg shadow transition duration-300 w-full sm:w-auto">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
@ -54,31 +58,6 @@ class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg font-medium
</div>
@endif
<!-- Venue Status Alert -->
{{-- @if($venue->status === 'close')
<div class="mb-6 bg-red-50 border border-red-200 rounded-lg p-4">
<div class="flex">
<div class="flex-shrink-0">
<svg class="h-5 w-5 text-red-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
fill="currentColor">
<path fill-rule="evenodd"
d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z"
clip-rule="evenodd" />
</svg>
</div>
<div class="ml-3">
<h3 class="text-sm font-medium text-red-800">Venue Sedang Tutup</h3>
<div class="mt-2 text-sm text-red-700">
<p><strong>Alasan:</strong> {{ $venue->close_reason }}</p>
@if($venue->reopen_date)
<p><strong>Akan buka kembali pada:</strong> {{ $venue->reopen_date->format('d M Y') }}</p>
@endif
</div>
</div>
</div>
</div>
@endif --}}
<!-- Venue Information Card -->
<div class="bg-white rounded-lg shadow-sm border border-gray-200">
<div class="p-6">
@ -200,312 +179,249 @@ class="text-sm text-gray-900">{{ $venue->updated_at->format('d M Y, H:i') }}</sp
</div>
</div>
<!-- Statistics Cards -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mt-6">
<!-- Total Tables -->
<div class="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
<div class="flex items-center">
<div class="flex-shrink-0">
<div class="w-8 h-8 bg-blue-100 rounded-full flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-blue-600" fill="none"
<!-- Close Venue Modal -->
<div id="closeVenueModal" class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full hidden">
<div class="relative top-20 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white">
<div class="mt-3">
<div class="flex items-center">
<div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100">
<svg class="h-6 w-6 text-red-600" 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="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4" />
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z" />
</svg>
</div>
</div>
<div class="ml-4">
<p class="text-sm font-medium text-gray-500">Total Meja</p>
<p class="text-2xl font-semibold text-gray-900">{{ $venue->tables->count() }}</p>
</div>
</div>
</div>
<!-- Available Tables -->
<div class="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
<div class="flex items-center">
<div class="flex-shrink-0">
<div class="w-8 h-8 bg-green-100 rounded-full flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-green-600" fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<div class="mt-2 text-center">
<h3 class="text-lg leading-6 font-medium text-gray-900">Tutup Venue</h3>
<div class="mt-4 text-left">
<form id="closeVenueForm">
<div class="mb-4">
<label for="closeReason" class="block text-sm font-medium text-gray-700 mb-2">Alasan
Penutupan *</label>
<textarea id="closeReason" name="close_reason" rows="3"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-blue-500 focus:border-blue-500"
placeholder="Masukkan alasan penutupan venue..." required></textarea>
<div id="closeReasonError" class="text-red-500 text-sm mt-1 hidden"></div>
</div>
<div class="mb-4">
<label for="reopenDate" class="block text-sm font-medium text-gray-700 mb-2">Tanggal
Buka
Kembali *</label>
<input type="date" id="reopenDate" name="reopen_date"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-blue-500 focus:border-blue-500"
min="{{ date('Y-m-d', strtotime('+1 day')) }}" required>
<div id="reopenDateError" class="text-red-500 text-sm mt-1 hidden"></div>
</div>
</form>
</div>
</div>
<div class="ml-4">
<p class="text-sm font-medium text-gray-500">Meja Tersedia</p>
<p class="text-2xl font-semibold text-gray-900">
{{ $venue->tables->where('status', 'available')->count() }}
</p>
</div>
</div>
</div>
<!-- Occupied Tables -->
<div class="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
<div class="flex items-center">
<div class="flex-shrink-0">
<div class="w-8 h-8 bg-red-100 rounded-full flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-red-600" fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
</div>
<div class="ml-4">
<p class="text-sm font-medium text-gray-500">Meja Terpakai</p>
<p class="text-2xl font-semibold text-gray-900">
{{ $venue->tables->where('status', 'occupied')->count() }}
</p>
<div class="flex justify-end space-x-3 mt-4">
<button type="button" onclick="closeModal()"
class="px-4 py-2 bg-gray-300 text-gray-700 rounded-md hover:bg-gray-400 transition-colors">
Batal
</button>
<button type="button" onclick="confirmCloseVenue()"
class="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 transition-colors">
Tutup Venue
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Close Venue Modal -->
<div id="closeVenueModal" class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full hidden">
<div class="relative top-20 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white">
<div class="mt-3">
<div class="flex items-center">
<div class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100">
<svg class="h-6 w-6 text-red-600" 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="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z" />
</svg>
</div>
</div>
<div class="mt-2 text-center">
<h3 class="text-lg leading-6 font-medium text-gray-900">Tutup Venue</h3>
<div class="mt-4 text-left">
<form id="closeVenueForm">
<div class="mb-4">
<label for="closeReason" class="block text-sm font-medium text-gray-700 mb-2">Alasan
Penutupan *</label>
<textarea id="closeReason" name="close_reason" rows="3"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-blue-500 focus:border-blue-500"
placeholder="Masukkan alasan penutupan venue..." required></textarea>
<div id="closeReasonError" class="text-red-500 text-sm mt-1 hidden"></div>
</div>
<div class="mb-4">
<label for="reopenDate" class="block text-sm font-medium text-gray-700 mb-2">Tanggal Buka
Kembali *</label>
<input type="date" id="reopenDate" name="reopen_date"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-blue-500 focus:border-blue-500"
min="{{ date('Y-m-d', strtotime('+1 day')) }}" required>
<div id="reopenDateError" class="text-red-500 text-sm mt-1 hidden"></div>
</div>
</form>
</div>
</div>
<div class="flex justify-end space-x-3 mt-4">
<button type="button" onclick="closeModal()"
class="px-4 py-2 bg-gray-300 text-gray-700 rounded-md hover:bg-gray-400 transition-colors">
Batal
</button>
<button type="button" onclick="confirmCloseVenue()"
class="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 transition-colors">
Tutup Venue
</button>
<!-- Loading Spinner -->
<div id="loadingSpinner" class="fixed inset-0 bg-gray-600 bg-opacity-50 flex items-center justify-center hidden">
<div class="bg-white p-4 rounded-lg">
<div class="flex items-center space-x-3">
<div class="animate-spin rounded-full h-6 w-6 border-b-2 border-blue-600"></div>
<span class="text-gray-700">Memproses...</span>
</div>
</div>
</div>
</div>
<!-- Loading Spinner -->
<div id="loadingSpinner" class="fixed inset-0 bg-gray-600 bg-opacity-50 flex items-center justify-center hidden">
<div class="bg-white p-4 rounded-lg">
<div class="flex items-center space-x-3">
<div class="animate-spin rounded-full h-6 w-6 border-b-2 border-blue-600"></div>
<span class="text-gray-700">Memproses...</span>
</div>
</div>
</div>
<script>
let currentVenueStatus = '{{ $venue->status }}';
<script>
let currentVenueStatus = '{{ $venue->status }}';
function toggleVenueStatus() {
if (currentVenueStatus === 'open') {
// Show close venue modal
document.getElementById('closeVenueModal').classList.remove('hidden');
} else {
// Open venue directly
confirmToggleStatus();
}
}
function closeModal() {
document.getElementById('closeVenueModal').classList.add('hidden');
// Clear form
document.getElementById('closeVenueForm').reset();
clearErrors();
}
function clearErrors() {
document.getElementById('closeReasonError').classList.add('hidden');
document.getElementById('reopenDateError').classList.add('hidden');
}
function confirmCloseVenue() {
const closeReason = document.getElementById('closeReason').value.trim();
const reopenDate = document.getElementById('reopenDate').value;
// Clear previous errors
clearErrors();
// Validate form
let hasError = false;
if (!closeReason) {
document.getElementById('closeReasonError').textContent = 'Alasan penutupan harus diisi.';
document.getElementById('closeReasonError').classList.remove('hidden');
hasError = true;
}
if (!reopenDate) {
document.getElementById('reopenDateError').textContent = 'Tanggal buka kembali harus diisi.';
document.getElementById('reopenDateError').classList.remove('hidden');
hasError = true;
} else {
const today = new Date();
const selectedDate = new Date(reopenDate);
if (selectedDate <= today) {
document.getElementById('reopenDateError').textContent = 'Tanggal buka kembali harus setelah hari ini.';
document.getElementById('reopenDateError').classList.remove('hidden');
hasError = true;
function toggleVenueStatus() {
if (currentVenueStatus === 'open') {
// Show close venue modal
document.getElementById('closeVenueModal').classList.remove('hidden');
} else {
// Open venue directly
confirmToggleStatus();
}
}
if (hasError) {
return;
function closeModal() {
document.getElementById('closeVenueModal').classList.add('hidden');
// Clear form
document.getElementById('closeVenueForm').reset();
clearErrors();
}
// Close modal and proceed with toggle
closeModal();
confirmToggleStatus({
close_reason: closeReason,
reopen_date: reopenDate
});
}
function clearErrors() {
document.getElementById('closeReasonError').classList.add('hidden');
document.getElementById('reopenDateError').classList.add('hidden');
}
function confirmToggleStatus(data = {}) {
// Show loading spinner
document.getElementById('loadingSpinner').classList.remove('hidden');
function confirmCloseVenue() {
const closeReason = document.getElementById('closeReason').value.trim();
const reopenDate = document.getElementById('reopenDate').value;
// Prepare request data
const requestData = {
_token: '{{ csrf_token() }}',
...data
};
// Clear previous errors
clearErrors();
fetch('{{ route("admin.venue.toggle-status") }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
body: JSON.stringify(requestData)
})
.then(response => response.json())
.then(data => {
// Hide loading spinner
document.getElementById('loadingSpinner').classList.add('hidden');
// Validate form
let hasError = false;
if (data.success) {
// Update UI
updateVenueStatusUI(data.venue);
if (!closeReason) {
document.getElementById('closeReasonError').textContent = 'Alasan penutupan harus diisi.';
document.getElementById('closeReasonError').classList.remove('hidden');
hasError = true;
}
// Show success message
showAlert(data.message, 'success');
// Update current status
currentVenueStatus = data.status;
// Reload page after 2 seconds to refresh all data
setTimeout(() => {
window.location.reload();
}, 2000);
} else {
if (data.errors) {
// Handle validation errors
let errorMessage = 'Terjadi kesalahan validasi:\n';
Object.values(data.errors).forEach(error => {
errorMessage += '- ' + error[0] + '\n';
});
showAlert(errorMessage, 'error');
} else {
showAlert(data.error || 'Terjadi kesalahan yang tidak diketahui', 'error');
}
if (!reopenDate) {
document.getElementById('reopenDateError').textContent = 'Tanggal buka kembali harus diisi.';
document.getElementById('reopenDateError').classList.remove('hidden');
hasError = true;
} else {
const today = new Date();
const selectedDate = new Date(reopenDate);
if (selectedDate <= today) {
document.getElementById('reopenDateError').textContent = 'Tanggal buka kembali harus setelah hari ini.';
document.getElementById('reopenDateError').classList.remove('hidden');
hasError = true;
}
})
.catch(error => {
// Hide loading spinner
document.getElementById('loadingSpinner').classList.add('hidden');
}
console.error('Error:', error);
showAlert('Venue ditutup sementara!', 'error');
if (hasError) {
return;
}
setTimeout(() => {
location.reload();
}, 1000);
// Close modal and proceed with toggle
closeModal();
confirmToggleStatus({
close_reason: closeReason,
reopen_date: reopenDate
});
}
function updateVenueStatusUI(venue) {
const toggle = document.getElementById('statusToggle');
const statusText = document.getElementById('statusText');
const toggleButton = toggle.querySelector('span:last-child');
if (venue.status === 'open') {
toggle.classList.remove('bg-red-600');
toggle.classList.add('bg-green-600');
toggleButton.classList.remove('translate-x-1');
toggleButton.classList.add('translate-x-6');
statusText.textContent = 'Buka';
statusText.classList.remove('text-red-600');
statusText.classList.add('text-green-600');
} else {
toggle.classList.remove('bg-green-600');
toggle.classList.add('bg-red-600');
toggleButton.classList.remove('translate-x-6');
toggleButton.classList.add('translate-x-1');
statusText.textContent = 'Tutup';
statusText.classList.remove('text-green-600');
statusText.classList.add('text-red-600');
}
}
function showAlert(message, type) {
// Remove existing alerts
const existingAlerts = document.querySelectorAll('.alert-message');
existingAlerts.forEach(alert => alert.remove());
function confirmToggleStatus(data = {}) {
// Show loading spinner
document.getElementById('loadingSpinner').classList.remove('hidden');
// Create new alert
const alertDiv = document.createElement('div');
alertDiv.className = `alert-message mb-6 px-4 py-3 rounded-lg ${type === 'success' ? 'bg-green-100 border border-green-400 text-green-700' : 'bg-red-100 border border-red-400 text-red-700'
}`;
alertDiv.textContent = message;
// Prepare request data
const requestData = {
_token: '{{ csrf_token() }}',
...data
};
// Insert alert after header
const header = document.querySelector('.mb-6');
header.parentNode.insertBefore(alertDiv, header.nextSibling);
fetch('{{ route("admin.venue.toggle-status") }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
body: JSON.stringify(requestData)
})
.then(response => response.json())
.then(data => {
// Hide loading spinner
document.getElementById('loadingSpinner').classList.add('hidden');
// Auto remove after 5 seconds
setTimeout(() => {
alertDiv.remove();
}, 5000);
}
if (data.success) {
// Update UI
updateVenueStatusUI(data.venue);
// Set minimum date for reopen date input
document.addEventListener('DOMContentLoaded', function () {
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
const minDate = tomorrow.toISOString().split('T')[0];
document.getElementById('reopenDate').setAttribute('min', minDate);
});
</script>
// Show success message
showAlert(data.message, 'success');
// Update current status
currentVenueStatus = data.status;
// Reload page after 2 seconds to refresh all data
setTimeout(() => {
window.location.reload();
}, 2000);
} else {
if (data.errors) {
// Handle validation errors
let errorMessage = 'Terjadi kesalahan validasi:\n';
Object.values(data.errors).forEach(error => {
errorMessage += '- ' + error[0] + '\n';
});
showAlert(errorMessage, 'error');
} else {
showAlert(data.error || 'Terjadi kesalahan yang tidak diketahui', 'error');
}
}
})
.catch(error => {
// Hide loading spinner
document.getElementById('loadingSpinner').classList.add('hidden');
console.error('Error:', error);
showAlert('Venue ditutup sementara!', 'error');
setTimeout(() => {
location.reload();
}, 1000);
});
}
function updateVenueStatusUI(venue) {
const toggle = document.getElementById('statusToggle');
const statusText = document.getElementById('statusText');
const toggleButton = toggle.querySelector('span:last-child');
if (venue.status === 'open') {
toggle.classList.remove('bg-red-600');
toggle.classList.add('bg-green-600');
toggleButton.classList.remove('translate-x-1');
toggleButton.classList.add('translate-x-6');
statusText.textContent = 'Buka';
statusText.classList.remove('text-red-600');
statusText.classList.add('text-green-600');
} else {
toggle.classList.remove('bg-green-600');
toggle.classList.add('bg-red-600');
toggleButton.classList.remove('translate-x-6');
toggleButton.classList.add('translate-x-1');
statusText.textContent = 'Tutup';
statusText.classList.remove('text-green-600');
statusText.classList.add('text-red-600');
}
}
function showAlert(message, type) {
// Remove existing alerts
const existingAlerts = document.querySelectorAll('.alert-message');
existingAlerts.forEach(alert => alert.remove());
// Create new alert
const alertDiv = document.createElement('div');
alertDiv.className = `alert-message mb-6 px-4 py-3 rounded-lg ${type === 'success' ? 'bg-green-100 border border-green-400 text-green-700' : 'bg-red-100 border border-red-400 text-red-700'
}`;
alertDiv.textContent = message;
// Insert alert after header
const header = document.querySelector('.mb-6');
header.parentNode.insertBefore(alertDiv, header.nextSibling);
// Auto remove after 5 seconds
setTimeout(() => {
alertDiv.remove();
}, 5000);
}
// Set minimum date for reopen date input
document.addEventListener('DOMContentLoaded', function () {
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
const minDate = tomorrow.toISOString().split('T')[0];
document.getElementById('reopenDate').setAttribute('min', minDate);
});
</script>
@endsection

View File

@ -46,11 +46,50 @@
</style>
</head>
<body x-data="{ sidebarOpen: true, userDropdownOpen: false }" class="bg-gray-50">
<body x-data="{
sidebarOpen: getSidebarState(),
userDropdownOpen: false,
toggleSidebar() {
this.sidebarOpen = !this.sidebarOpen;
saveSidebarState(this.sidebarOpen);
}
}" x-init="
// Watch for sidebar changes and save to localStorage
$watch('sidebarOpen', value => saveSidebarState(value))
" class="bg-gray-50">
<script>
// Function to get sidebar state from localStorage
function getSidebarState() {
const saved = localStorage.getItem('admin_sidebar_open');
// Default to true for desktop, false for mobile
if (saved === null) {
return window.innerWidth >= 1024; // lg breakpoint
}
return saved === 'true';
}
// Function to save sidebar state to localStorage
function saveSidebarState(isOpen) {
localStorage.setItem('admin_sidebar_open', isOpen.toString());
}
// Handle responsive behavior on window resize
window.addEventListener('resize', function () {
// Only auto-adjust if no explicit state has been saved
const saved = localStorage.getItem('admin_sidebar_open');
if (saved === null) {
// Auto close on mobile, open on desktop
const shouldOpen = window.innerWidth >= 1024;
Alpine.store('sidebar', { open: shouldOpen });
}
});
</script>
<div class="flex h-screen overflow-hidden">
<!-- Sidebar Overlay -->
<div x-show="sidebarOpen" @click="sidebarOpen = false"
class="fixed inset-0 z-20 bg-black bg-opacity-50 lg:hidden"></div>
<div x-show="sidebarOpen" @click="toggleSidebar()" class="fixed inset-0 z-20 bg-black bg-opacity-50 lg:hidden">
</div>
<!-- Sidebar -->
<div :class="sidebarOpen ? 'translate-x-0' : '-translate-x-full lg:translate-x-0 lg:w-20'"
@ -66,7 +105,7 @@ class="fixed inset-y-0 left-0 z-30 w-64 bg-white shadow-lg transition-all durati
</a>
</div> --}}
</div>
<button @click="sidebarOpen = !sidebarOpen" class="p-1 rounded-md hover:bg-gray-100 focus:outline-none">
<button @click="toggleSidebar()" class="p-1 rounded-md hover:bg-gray-100 focus:outline-none">
<svg x-show="sidebarOpen" xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-500"
fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
@ -92,7 +131,7 @@ class="nav-item flex items-center px-3 py-2.5 rounded-lg {{ request()->routeIs('
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
d="M3 3h7v7H3V3zm11 0h7v7h-7V3zM3 14h7v7H3v-7zm11 0h7v7h-7v-7z" />
</svg>
<span x-show="sidebarOpen">Dashboard</span>
</a>
@ -102,7 +141,7 @@ class="nav-item flex items-center px-3 py-2.5 rounded-lg {{ request()->routeIs('
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4" />
d="M3 10l9-7 9 7v10a2 2 0 01-2 2h-2a2 2 0 01-2-2V14H9v6a2 2 0 01-2 2H5a2 2 0 01-2-2V10z" />
</svg>
<span x-show="sidebarOpen">Kelola Venue</span>
</a>
@ -111,8 +150,9 @@ class="nav-item flex items-center px-3 py-2.5 rounded-lg {{ request()->routeIs('
class="nav-item flex items-center px-3 py-2.5 rounded-lg {{ request()->routeIs('admin.tables.*') ? 'active' : '' }}">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4" />
<rect width="18" height="10" x="3" y="7" rx="2" ry="2" stroke-width="2"
stroke="currentColor" fill="none" />
<circle cx="12" cy="12" r="1.5" fill="currentColor" />
</svg>
<span x-show="sidebarOpen">Kelola Meja</span>
</a>
@ -122,18 +162,18 @@ class="nav-item flex items-center px-3 py-2.5 rounded-lg {{ request()->routeIs('
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
d="M8 7V3m8 4V3M5 11h14M5 5h14a2 2 0 012 2v12a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2z" />
</svg>
<span x-show="sidebarOpen">Daftar Booking</span>
<span x-show="sidebarOpen">Kelola Booking</span>
</a>
<a href="{{ route('admin.revenues.index') }}"
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"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
d="M12 8c-1.5 0-3 .75-3 2s1.5 2 3 2 3 .75 3 2-1.5 2-3 2m0-10v10m-6 4h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
<span x-show="sidebarOpen">Revenues</span>
<span x-show="sidebarOpen">Laporan Pendapatan</span>
</a>
</nav>
@ -211,7 +251,7 @@ class="block w-full text-left px-4 py-2 text-sm text-red-600 hover:bg-gray-100">
<!-- Top Header -->
<header class="bg-white shadow-sm lg:hidden">
<div class="px-4 sm:px-6 lg:px-8 py-4 flex items-center justify-between">
<button @click="sidebarOpen = !sidebarOpen"
<button @click="toggleSidebar()"
class="p-1 rounded-md text-gray-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 lg:hidden">
<svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">

View File

@ -281,7 +281,7 @@
<hr class="dropdown-divider">
<a class="dropdown-item text-danger" href="{{ route('logout') }}"
onclick="event.preventDefault();
document.getElementById('logout-form').submit();">
document.getElementById('logout-form').submit();">
<i class="fas fa-sign-out-alt me-2"></i> {{ __('Logout') }}
</a>

View File

@ -6,7 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>Document</title>
<title>Cari Meja</title>
@vite('resources/css/app.css')
{{-- Font | Google Fonts --}}
<link rel="preconnect" href="https://fonts.googleapis.com">
@ -108,10 +108,22 @@ class="absolute top-full left-0 right-0 bg-white shadow-md mt-1 p-4 z-50">
class="block w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
Riwayat Booking
</a>
<a href="{{ route('account.settings') }}"
class="block w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
Pengaturan Akun
</a>
@if (Auth::user()->role === 'user')
<a href="{{ route('account.settings') }}"
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
Pengaturan Akun
</a>
@elseif (Auth::user()->role === 'admin')
<a href="{{ url('/admin') }}"
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
Halaman Admin
</a>
@elseif (Auth::user()->role === 'superadmin')
<a href="{{ url('/superadmin') }}"
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
Halaman Superadmin
</a>
@endif
@if (Auth::user()->email_verified_at === null)
<a href="{{ route('verification.notice') }}"
class="block w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
@ -157,7 +169,7 @@ class="absolute top-3 right-4 text-gray-500 hover:text-gray-700 text-xl">
<!-- Error message for login errors -->
@if(session('login_error') || ($errors->any() && old('email') && !old('name')))
<div class="bg-green-100 border-l-4 border-green-500 text-green-700 p-4 mb-4" role="alert">
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4 mb-4" role="alert">
@if(session('login_error'))
<p>{{ session('login_error') }}</p>
@if(str_contains(session('login_error'), 'belum diverifikasi'))

View File

@ -51,11 +51,62 @@
</style>
</head>
<body x-data="{ sidebarOpen: true, userDropdownOpen: false }" class="bg-gray-50">
<body x-data="{
sidebarOpen: getSuperAdminSidebarState(),
userDropdownOpen: false,
toggleSidebar() {
this.sidebarOpen = !this.sidebarOpen;
saveSuperAdminSidebarState(this.sidebarOpen);
}
}" x-init="
// Watch for sidebar changes and save to localStorage
$watch('sidebarOpen', value => saveSuperAdminSidebarState(value))
" class="bg-gray-50">
<script>
// Function to get sidebar state from localStorage (separate key for super admin)
function getSuperAdminSidebarState() {
const saved = localStorage.getItem('superadmin_sidebar_open');
// Default to true for desktop, false for mobile
if (saved === null) {
return window.innerWidth >= 1024; // lg breakpoint
}
return saved === 'true';
}
// Function to save sidebar state to localStorage (separate key for super admin)
function saveSuperAdminSidebarState(isOpen) {
localStorage.setItem('superadmin_sidebar_open', isOpen.toString());
}
// Handle responsive behavior on window resize
window.addEventListener('resize', function () {
// Only auto-adjust if no explicit state has been saved
const saved = localStorage.getItem('superadmin_sidebar_open');
if (saved === null) {
// Auto close on mobile, open on desktop
const shouldOpen = window.innerWidth >= 1024;
Alpine.store('sidebar', { open: shouldOpen });
}
});
</script>
<div class="flex h-screen overflow-hidden">
<!-- Mobile Menu Button - Always visible on mobile when sidebar is closed -->
<div x-show="!sidebarOpen" class="fixed top-4 left-4 z-50 lg:hidden">
<button @click="toggleSidebar()"
class="p-2 bg-white rounded-lg shadow-lg hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 border border-gray-200">
<svg class="w-6 h-6 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16m-7 6h7">
</path>
</svg>
</button>
</div>
<!-- Sidebar Overlay -->
<div x-show="sidebarOpen" @click="sidebarOpen = false"
class="fixed inset-0 z-20 bg-black bg-opacity-50 lg:hidden"></div>
<div x-show="sidebarOpen" @click="toggleSidebar()" class="fixed inset-0 z-20 bg-black bg-opacity-50 lg:hidden">
</div>
<!-- Sidebar -->
<div :class="sidebarOpen ? 'translate-x-0' : '-translate-x-full lg:translate-x-0 lg:w-20'"
@ -66,7 +117,7 @@ class="fixed inset-y-0 left-0 z-30 w-64 bg-white shadow-lg transition-all durati
<div class="flex items-center space-x-2">
<span class="font-bold text-lg text-gray-800" x-show="sidebarOpen">Super Admin</span>
</div>
<button @click="sidebarOpen = !sidebarOpen" class="p-1 rounded-md hover:bg-gray-100 focus:outline-none">
<button @click="toggleSidebar()" class="p-1 rounded-md hover:bg-gray-100 focus:outline-none">
<svg x-show="sidebarOpen" xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-500"
fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
@ -119,7 +170,8 @@ class="w-8 h-8 bg-blue-600 rounded-full flex items-center justify-center text-wh
</div>
<div x-show="sidebarOpen" class="ml-3">
<p class="text-sm font-medium text-gray-800 truncate">
{{ auth()->user()->name ?? 'Super Admin' }}</p>
{{ auth()->user()->name ?? 'Super Admin' }}
</p>
<p class="text-xs text-gray-500 truncate">{{ auth()->user()->email ??
'superadmin@example.com' }}</p>
</div>
@ -147,78 +199,55 @@ class="block w-full text-left px-4 py-2 text-sm text-red-600 hover:bg-gray-100">
<!-- Main Content -->
<div class="flex-1 flex flex-col overflow-hidden">
<!-- Top Header -->
{{-- <header class="bg-white shadow-sm">
<div class="px-4 sm:px-6 lg:px-8 py-4 flex items-center justify-between">
<div class="flex items-center space-x-4">
<button @click="sidebarOpen = !sidebarOpen"
class="p-1 rounded-md text-gray-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 lg:inline-block">
<svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 6h16M4 12h16M4 18h16"></path>
</svg>
<!-- Top Header with Mobile Menu Button Alternative -->
<header class="bg-white shadow-sm lg:hidden">
<div class="px-4 py-3 flex items-center justify-between">
<button @click="toggleSidebar()" x-show="!sidebarOpen"
class="p-2 rounded-md text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
<svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 6h16M4 12h16M4 18h16"></path>
</svg>
</button>
<h1 class="text-lg font-semibold text-gray-900">Super Admin</h1>
<!-- Mobile Profile -->
<div class="relative" x-data="{ open: false }">
<button @click="open = !open"
class="flex items-center p-1 rounded-full hover:bg-gray-100 transition-colors">
<div
class="w-8 h-8 rounded-full bg-blue-600 flex items-center justify-center text-white font-semibold text-sm">
{{ substr(auth()->user()->name ?? 'SA', 0, 1) }}
</div>
</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 p-2 rounded-md text-gray-500 hover:bg-gray-100 focus:outline-none">
<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 space-x-3 p-2 rounded-lg hover:bg-gray-100 transition-colors">
<div
class="w-8 h-8 rounded-full bg-blue-600 flex items-center justify-center text-white font-semibold">
{{ substr(auth()->user()->name ?? 'SA', 0, 1) }}
</div>
<div class="text-left hidden md:block">
<p class="text-sm font-medium text-gray-900">{{ auth()->user()->name ?? 'Super
Admin' }}</p>
<p class="text-xs text-gray-500">Super Admin</p>
</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"
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 ?? 'Super
Admin' }}</p>
<p class="text-xs text-gray-500">{{ auth()->user()->email ??
'superadmin@example.com' }}</p>
</div>
<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>
<form id="logout-form" action="{{ route('logout') }}" method="POST" class="hidden">
@csrf
</form>
</div>
<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-48 bg-white rounded-lg 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 ?? 'Super Admin' }}
</p>
<p class="text-xs text-gray-500">{{ auth()->user()->email ?? 'superadmin@example.com' }}
</p>
</div>
<div class="pt-2">
<form method="POST" action="{{ route('logout') }}">
@csrf
<button type="submit"
class="block w-full text-left px-4 py-2 text-sm text-red-600 hover:bg-gray-100">
Logout
</button>
</form>
</div>
</div>
</div>
</div>
</header> --}}
</header>
<!-- Page Content -->
<main class="flex-1 overflow-x-hidden overflow-y-auto">

View File

@ -1,5 +1,5 @@
@extends('layouts.main') @section('content') <div class="min-h-96 mx-4 md:w-3/4 md:mx-auto py-8">
<h1 class="text-2xl font-bold mb-6">Riwayat Booking</h1>
<h1 class="text-2xl font-bold mb-6">Riwayat Bookingg</h1>
@if($bookings->isEmpty())
<div class="bg-white rounded-lg shadow-md p-6 text-center">

View File

@ -56,7 +56,7 @@
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Pilih Tanggal:</label>
<input type="date" x-model="selectedDate" class="w-full border p-2 rounded-lg"
:min="today" @change="dateChanged">
:min="today" @change="dateChanged" disabled>
</div>
<div>

View File

@ -7,7 +7,7 @@
style="backdrop-filter: blur(20px); background-color: rgba(255, 255, 255, 0.8);">
<div class="p-6 sm:p-10">
<h2 class="text-center text-4xl font-semibold text-gray-900 mb-8">
{{ __('Edit Venue') }}
{{ __('Detail Venue') }}
</h2>
@if ($errors->any())
@ -41,7 +41,7 @@
<input type="text" id="name" name="name" value="{{ old('name', $venue->name) }}" required
autocomplete="name" autofocus
class="block w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 transition duration-300 ease-in-out"
placeholder="Masukkan nama venue">
placeholder="Masukkan nama venue" disabled>
</div>
{{-- Nomor Telepon --}}
@ -51,7 +51,7 @@ class="block w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm focus:
</label>
<input type="tel" id="phone" name="phone" value="{{ old('phone', $venue->phone) }}" required
class="block w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 transition duration-300 ease-in-out"
placeholder="Masukkan nomor telepon">
placeholder="Masukkan nomor telepon" disabled>
</div>
</div>
@ -62,7 +62,8 @@ class="block w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm focus:
</label>
<textarea id="address" name="address" required rows="3"
class="block w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 transition duration-300 ease-in-out"
placeholder="Masukkan alamat lengkap venue">{{ old('address', $venue->address) }}</textarea>
placeholder="Masukkan alamat lengkap venue"
disabled>{{ old('address', $venue->address) }}</textarea>
</div>
{{-- Deskripsi --}}
@ -72,7 +73,8 @@ class="block w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm focus:
</label>
<textarea id="description" name="description" rows="4" required
class="block w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 transition duration-300 ease-in-out"
placeholder="Berikan deskripsi venue">{{ old('description', $venue->description) }}</textarea>
placeholder="Berikan deskripsi venue"
disabled>{{ old('description', $venue->description) }}</textarea>
</div>
{{-- Jam Operasional --}}
@ -83,6 +85,7 @@ class="block w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm focus:
</label>
<input type="time" id="open_time" name="open_time"
value="{{ old('open_time', date('H:i', strtotime($venue->open_time))) }}" required
disabled
class="block w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 transition duration-300 ease-in-out">
</div>
<div>
@ -91,6 +94,7 @@ class="block w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm focus:
</label>
<input type="time" id="close_time" name="close_time"
value="{{ old('close_time', date('H:i', strtotime($venue->close_time))) }}" required
disabled
class="block w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 transition duration-300 ease-in-out">
</div>
</div>
@ -100,13 +104,13 @@ class="block w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm focus:
<label for="status" class="block text-sm font-medium text-gray-700 mb-2">
{{ __('Status') }}
</label>
<select id="status" name="status" required
<select id="status" name="status" required disabled
class="block w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 transition duration-300 ease-in-out">
<option value="active" {{ old('status', $venue->status) == 'active' ? 'selected' : '' }}>
{{ __('Aktif') }}
<option value="open" {{ old('status', $venue->status) == 'open' ? 'selected' : '' }}>
{{ __('Open') }}
</option>
<option value="inactive" {{ old('status', $venue->status) == 'inactive' ? 'selected' : '' }}>
{{ __('Tidak Aktif') }}
<option value="close" {{ old('status', $venue->status) == 'close' ? 'selected' : '' }}>
{{ __('Close') }}
</option>
</select>
</div>
@ -126,8 +130,8 @@ class="h-32 w-auto object-cover rounded-lg border border-gray-200 shadow-sm">
</div>
@endif
<div x-ref="dropzone" @dragover.prevent="dragover = true" @dragleave.prevent="dragover = false"
@drop.prevent="handleDrop($event)"
{{-- <div x-ref="dropzone" @dragover.prevent="dragover = true"
@dragleave.prevent="dragover = false" @drop.prevent="handleDrop($event)"
class="mt-1 flex justify-center px-6 pt-5 pb-6 border-2 border-gray-300 border-dashed rounded-lg transition duration-300 ease-in-out"
:class="dragover ? 'border-blue-500 bg-blue-50' : 'hover:border-blue-500'">
<div class="space-y-1 text-center">
@ -154,19 +158,19 @@ class="relative cursor-pointer rounded-md font-medium text-blue-600 hover:text-b
</p>
<p x-text="fileName" class="text-sm text-gray-600 mt-2"></p>
</div>
</div>
</div> --}}
</div>
{{-- Tombol Aksi --}}
<div class="flex justify-end space-x-4 pt-6">
<a href="{{ route('superadmin.venue.index') }}"
class="px-6 py-3 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg font-medium transition duration-300 ease-in-out">
{{ __('Batal') }}
{{ __('Kembali') }}
</a>
<button type="submit"
{{-- <button type="submit"
class="px-6 py-3 bg-blue-500 text-white rounded-lg font-medium hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition duration-300 ease-in-out">
{{ __('Perbarui') }}
</button>
</button> --}}
</div>
</form>
</div>

View File

@ -28,7 +28,7 @@ class="px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 flex item
@endif
<!-- Filter and Search -->
<div class="bg-white rounded-lg shadow mb-6 p-4">
{{-- <div class="bg-white rounded-lg shadow mb-6 p-4">
<form action="{{ route('superadmin.venue.index') }}" method="GET">
<div class="flex flex-col md:flex-row gap-4">
<div class="flex-grow">
@ -41,18 +41,18 @@ class="px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 flex item
class="pl-10 block w-full rounded-md border-gray-300 shadow-sm focus:border-green-500 focus:ring-green-500"
placeholder="Cari nama venue atau lokasi">
</div>
</div>
<div>
</div> --}}
{{-- <div>
<label for="status" class="block text-sm font-medium text-gray-700 mb-1">Status</label>
<select id="status" name="status"
class="block w-full rounded-md border-gray-300 shadow-sm focus:border-green-500 focus:ring-green-500">
<option value="">Semua Status</option>
<option value="active" {{ request('status') == 'active' ? 'selected' : '' }}>Aktif</option>
<option value="inactive" {{ request('status') == 'inactive' ? 'selected' : '' }}>Tidak Aktif
<option value="open" {{ request('status')=='open' ? 'selected' : '' }}>Open</option>
<option value="close" {{ request('status')=='close' ? 'selected' : '' }}>Close
</option>
</select>
</div>
<div class="self-end">
</div> --}}
{{-- <div class="self-end">
<button type="submit"
class="px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 text-sm">
Filter
@ -64,7 +64,7 @@ class="px-4 py-2 border border-gray-300 rounded-md bg-white hover:bg-gray-50 tex
</div>
</div>
</form>
</div>
</div> --}}
<!-- Venue Grid -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
@ -100,10 +100,10 @@ class="px-4 py-2 border border-gray-300 rounded-md bg-white hover:bg-gray-50 tex
onerror="this.src='{{ asset('images/venue-placeholder.jpg') }}'; this.onerror=null;">
<div class="absolute top-3 right-3 flex gap-2">
<a href="{{ route('superadmin.venue.edit', $venue->id) }}"
{{-- <a href="{{ route('superadmin.venue.edit', $venue->id) }}"
class="p-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors duration-200">
<i class="fas fa-edit"></i>
</a>
</a> --}}
<button type="button" onclick="confirmDelete({{ $venue->id }})"
class="p-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors duration-200">
<i class="fas fa-trash-alt"></i>
@ -112,13 +112,17 @@ class="p-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors d
</div>
<div class="p-5">
<h3 class="text-xl font-semibold text-gray-900 mb-2">{{ $venue->name }}</h3>
<div class="flex items-center mb-2">
{{-- <div class="flex items-center mb-2">
<i class="fas fa-map-marker-alt text-gray-500 mr-2"></i>
<span class="text-gray-600 truncate" title="{{ $venue->address }}">{{ $venue->address }}</span>
</div>
<div class="flex items-center mb-2">
<i class="fas fa-phone text-gray-500 mr-2"></i>
<span class="text-gray-600">{{ $venue->phone }}</span>
</div> --}}
<div class="flex items-center mb-4">
<i
class="fas fa-circle {{ $venue->status == 'open' ? 'text-green-500' : 'text-red-500' }} mr-2"></i>
<span
class="text-sm font-medium {{ $venue->status == 'open' ? 'text-green-700' : 'text-red-700' }}">
{{ $venue->status == 'open' ? 'Open' : 'Close' }}
</span>
</div>
<div class="flex items-center mb-2">
<i class="fas fa-clock text-gray-500 mr-2"></i>
@ -126,25 +130,21 @@ class="p-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors d
{{ $venue->open_time ?? '00:00' }} - {{ $venue->close_time ?? '23:59' }}
</span>
</div>
<div class="flex items-center mb-4">
<i
class="fas fa-circle {{ $venue->status == 'active' ? 'text-green-500' : 'text-red-500' }} mr-2"></i>
<span
class="text-sm font-medium {{ $venue->status == 'active' ? 'text-green-700' : 'text-red-700' }}">
{{ $venue->status == 'active' ? 'Aktif' : 'Tidak Aktif' }}
</span>
<div class="flex items-center mb-2">
<i class="fas fa-phone text-gray-500 mr-2"></i>
<span class="text-gray-600">{{ $venue->phone }}</span>
</div>
@if($venue->description)
<div class="mb-4">
<p class="text-gray-600 text-sm line-clamp-2">{{ Str::limit($venue->description, 100) }}</p>
</div>
@endif
{{-- @if($venue->description)
<div class="mb-4">
<p class="text-gray-600 text-sm line-clamp-2">{{ Str::limit($venue->description, 100) }}</p>
</div>
@endif --}}
<div class="border-t pt-4">
<div class="flex justify-between items-center">
<div class="text-sm text-gray-500">
<span class="font-medium">{{ $venue->created_at->format('d M Y') }}</span>
Dibuat: <span class="font-medium">{{ $venue->created_at->format('d M Y') }}</span>
</div>
<a href="{{ route('superadmin.venue.edit', $venue->id) }}"
class="text-green-600 hover:text-green-800 flex items-center text-sm transition-colors duration-200">