From cbbd272b1572873a5f5e1ff79727bbfdd2787ce2 Mon Sep 17 00:00:00 2001
From: Stephen Gesityan
Date: Thu, 5 Jun 2025 02:48:00 +0700
Subject: [PATCH] Admin bisa tutup buka venue
---
app/Console/Commands/ReopenVenuesCommand.php | 55 +++
app/Console/Kernel.php | 8 +-
.../Controllers/admin/VenueController.php | 86 ++++-
app/Models/Venue.php | 75 +++-
...tatus_and_closure_info_to_venues_table.php | 32 ++
resources/views/admin/venues/index.blade.php | 346 +++++++++++++++++-
resources/views/pages/home.blade.php | 31 +-
resources/views/pages/venue.blade.php | 93 ++---
routes/web.php | 1 +
9 files changed, 653 insertions(+), 74 deletions(-)
create mode 100644 app/Console/Commands/ReopenVenuesCommand.php
create mode 100644 database/migrations/2025_06_05_015857_add_status_and_closure_info_to_venues_table.php
diff --git a/app/Console/Commands/ReopenVenuesCommand.php b/app/Console/Commands/ReopenVenuesCommand.php
new file mode 100644
index 0000000..b7bdbf0
--- /dev/null
+++ b/app/Console/Commands/ReopenVenuesCommand.php
@@ -0,0 +1,55 @@
+info('Checking for venues to reopen...');
+
+ $venuesReopened = 0;
+
+ // Get all closed venues that should be reopened today
+ $venues = Venue::where('status', 'close')
+ ->whereNotNull('reopen_date')
+ ->whereDate('reopen_date', '<=', Carbon::today())
+ ->get();
+
+ foreach ($venues as $venue) {
+ if ($venue->checkAutoReopen()) {
+ $this->info("Venue '{$venue->name}' has been automatically reopened.");
+ $venuesReopened++;
+ }
+ }
+
+ if ($venuesReopened > 0) {
+ $this->info("Successfully reopened {$venuesReopened} venue(s).");
+ } else {
+ $this->info('No venues to reopen today.');
+ }
+
+ return Command::SUCCESS;
+ }
+}
\ No newline at end of file
diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php
index e6b9960..bce8705 100644
--- a/app/Console/Kernel.php
+++ b/app/Console/Kernel.php
@@ -12,7 +12,11 @@ class Kernel extends ConsoleKernel
*/
protected function schedule(Schedule $schedule): void
{
- // $schedule->command('inspire')->hourly();
+ // Run venue reopen check every day at 00:01
+ $schedule->command('venues:reopen')
+ ->dailyAt('00:01')
+ ->withoutOverlapping()
+ ->runInBackground();
}
/**
@@ -24,4 +28,4 @@ protected function commands(): void
require base_path('routes/console.php');
}
-}
+}
\ No newline at end of file
diff --git a/app/Http/Controllers/admin/VenueController.php b/app/Http/Controllers/admin/VenueController.php
index c56cf88..1b5c41c 100644
--- a/app/Http/Controllers/admin/VenueController.php
+++ b/app/Http/Controllers/admin/VenueController.php
@@ -7,6 +7,7 @@
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
+use Carbon\Carbon;
class VenueController extends Controller
{
@@ -21,6 +22,11 @@ public function index()
if (!$venue) {
return redirect()->route('admin.dashboard')->with('error', 'Anda belum memiliki venue yang ditugaskan.');
}
+
+ // Check for auto reopen
+ if ($venue->checkAutoReopen()) {
+ session()->flash('success', 'Venue telah dibuka kembali secara otomatis!');
+ }
return view('admin.venues.index', compact('venue'));
}
@@ -91,16 +97,27 @@ public function update(Request $request)
$imagePath = $request->file('image')->store('venues', 'public');
}
- // Update venue data
- $venue->update([
+ // Prepare update data
+ $updateData = [
'name' => $request->name,
'address' => $request->address,
'phone' => $request->phone,
'description' => $request->description,
- 'open_time' => $request->open_time,
- 'close_time' => $request->close_time,
'image' => $imagePath,
- ]);
+ ];
+
+ // Only update operating hours if venue is open
+ if ($venue->status === 'open') {
+ $updateData['open_time'] = $request->open_time;
+ $updateData['close_time'] = $request->close_time;
+ } else {
+ // If venue is closed, update original times
+ $updateData['original_open_time'] = $request->open_time;
+ $updateData['original_close_time'] = $request->close_time;
+ }
+
+ // Update venue data
+ $venue->update($updateData);
return redirect()->route('admin.venue.index')
->with('success', 'Informasi venue berhasil diperbarui!');
@@ -111,4 +128,63 @@ public function update(Request $request)
->withInput();
}
}
+
+ /**
+ * Toggle venue status (open/close)
+ */
+ public function toggleStatus(Request $request)
+ {
+ $venue = auth()->user()->venue;
+
+ if (!$venue) {
+ return response()->json(['error' => 'Venue tidak ditemukan'], 404);
+ }
+
+ try {
+ if ($venue->status === 'open') {
+ // Closing venue - validate required fields
+ $validator = Validator::make($request->all(), [
+ 'close_reason' => 'required|string|max:500',
+ 'reopen_date' => 'required|date|after:today',
+ ], [
+ 'close_reason.required' => 'Alasan penutupan harus diisi.',
+ 'reopen_date.required' => 'Tanggal buka kembali harus diisi.',
+ 'reopen_date.date' => 'Format tanggal tidak valid.',
+ 'reopen_date.after' => 'Tanggal buka kembali harus setelah hari ini.',
+ ]);
+
+ if ($validator->fails()) {
+ return response()->json([
+ 'error' => 'Validasi gagal',
+ 'errors' => $validator->errors()
+ ], 422);
+ }
+
+ $venue->closeVenue($request->close_reason, $request->reopen_date);
+ $message = 'Venue berhasil ditutup!';
+ } else {
+ // Opening venue
+ $venue->openVenue();
+ $message = 'Venue berhasil dibuka!';
+ }
+
+ return response()->json([
+ 'success' => true,
+ 'message' => $message,
+ 'status' => $venue->status,
+ 'venue' => [
+ 'status' => $venue->status,
+ 'close_reason' => $venue->close_reason,
+ 'reopen_date' => $venue->reopen_date ? $venue->reopen_date->format('d M Y') : null,
+ 'open_time' => $venue->open_time ? Carbon::parse($venue->open_time)->format('H:i') : null,
+ 'close_time' => $venue->close_time ? Carbon::parse($venue->close_time)->format('H:i') : null,
+ ]
+ ]);
+
+ } catch (\Exception $e) {
+ return response()->json([
+ 'error' => 'Terjadi kesalahan: ' . $e->getMessage()
+ ], 500);
+ }
+ }
}
\ No newline at end of file
diff --git a/app/Models/Venue.php b/app/Models/Venue.php
index cb2b831..13840f0 100644
--- a/app/Models/Venue.php
+++ b/app/Models/Venue.php
@@ -4,6 +4,7 @@
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
+use Carbon\Carbon;
class Venue extends Model
{
@@ -13,15 +14,79 @@ class Venue extends Model
'name',
'address',
'image',
- 'phone', // Pastikan field ini ada
- 'description', // Pastikan field ini ada
- 'open_time', // Pastikan field ini ada
- 'close_time', // Pastikan field ini ada
+ 'phone',
+ 'description',
+ 'open_time',
+ 'close_time',
+ 'status',
+ 'close_reason',
+ 'reopen_date',
+ 'original_open_time',
+ 'original_close_time',
];
+ protected $dates = [
+ 'reopen_date',
+ ];
public function tables()
{
return $this->hasMany(Table::class);
}
-}
+
+ /**
+ * Check if venue should automatically reopen
+ */
+ public function checkAutoReopen()
+ {
+ if ($this->status === 'close' && $this->reopen_date && Carbon::today()->gte($this->reopen_date)) {
+ $this->update([
+ 'status' => 'open',
+ 'open_time' => $this->original_open_time,
+ 'close_time' => $this->original_close_time,
+ 'close_reason' => null,
+ 'reopen_date' => null,
+ 'original_open_time' => null,
+ 'original_close_time' => null,
+ ]);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Close venue with reason and reopen date
+ */
+ public function closeVenue($reason, $reopenDate)
+ {
+ // Simpan jam operasional saat ini sebelum mengubahnya
+ $currentOpenTime = $this->open_time;
+ $currentCloseTime = $this->close_time;
+
+ $this->update([
+ 'status' => 'close',
+ 'close_reason' => $reason,
+ 'reopen_date' => $reopenDate,
+ 'original_open_time' => $currentOpenTime, // Simpan jam asli
+ 'original_close_time' => $currentCloseTime, // Simpan jam asli
+ 'open_time' => '00:00', // Set ke 00:00 setelah menyimpan original
+ 'close_time' => '00:00', // Set ke 00:00 setelah menyimpan original
+ ]);
+ }
+
+ /**
+ * Open venue manually
+ */
+ public function openVenue()
+ {
+ $this->update([
+ 'status' => 'open',
+ 'open_time' => $this->original_open_time ?: $this->open_time,
+ 'close_time' => $this->original_close_time ?: $this->close_time,
+ 'close_reason' => null,
+ 'reopen_date' => null,
+ 'original_open_time' => null,
+ 'original_close_time' => null,
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/database/migrations/2025_06_05_015857_add_status_and_closure_info_to_venues_table.php b/database/migrations/2025_06_05_015857_add_status_and_closure_info_to_venues_table.php
new file mode 100644
index 0000000..17141d1
--- /dev/null
+++ b/database/migrations/2025_06_05_015857_add_status_and_closure_info_to_venues_table.php
@@ -0,0 +1,32 @@
+enum('status', ['open', 'close'])->default('open')->after('close_time');
+ $table->text('close_reason')->nullable()->after('status');
+ $table->date('reopen_date')->nullable()->after('close_reason');
+ $table->time('original_open_time')->nullable()->after('reopen_date');
+ $table->time('original_close_time')->nullable()->after('original_open_time');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('venues', function (Blueprint $table) {
+ $table->dropColumn(['status', 'close_reason', 'reopen_date', 'original_open_time', 'original_close_time']);
+ });
+ }
+};
\ No newline at end of file
diff --git a/resources/views/admin/venues/index.blade.php b/resources/views/admin/venues/index.blade.php
index 5c337f5..2f44c91 100644
--- a/resources/views/admin/venues/index.blade.php
+++ b/resources/views/admin/venues/index.blade.php
@@ -9,15 +9,35 @@
Kelola Venue
Kelola informasi venue Anda
-
-
- Edit Venue
-
+
+
+
+
Status Venue:
+
+
+
+
+ {{ $venue->status === 'open' ? 'Buka' : 'Tutup' }}
+
+
+
+
+
+ Edit Venue
+
+
@@ -34,6 +54,31 @@ class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg font-medium
@endif
+
+ {{-- @if($venue->status === 'close')
+
+
+
+
+
Venue Sedang Tutup
+
+
Alasan: {{ $venue->close_reason }}
+ @if($venue->reopen_date)
+
Akan buka kembali pada: {{ $venue->reopen_date->format('d M Y') }}
+ @endif
+
+
+
+
+ @endif --}}
+
@@ -92,17 +137,40 @@ class="w-full h-48 object-cover rounded-lg">
+
+
+
+ Status:
+
+
+
+ {{ $venue->status === 'open' ? 'Buka' : 'Tutup' }}
+
+
+
+
Jam Operasional:
-
- {{ $venue->open_time ? \Carbon\Carbon::parse($venue->open_time)->format('H:i') : '-' }}
- -
- {{ $venue->close_time ? \Carbon\Carbon::parse($venue->close_time)->format('H:i') : '-' }}
-
+ @if($venue->status === 'open')
+
+ {{ $venue->open_time ? \Carbon\Carbon::parse($venue->open_time)->format('H:i') : '-' }}
+ -
+ {{ $venue->close_time ? \Carbon\Carbon::parse($venue->close_time)->format('H:i') : '-' }}
+
+ @else
+
Tutup Sementara
+ @if($venue->original_open_time && $venue->original_close_time)
+
+ Jam normal: {{ \Carbon\Carbon::parse($venue->original_open_time)->format('H:i') }} -
+ {{ \Carbon\Carbon::parse($venue->original_close_time)->format('H:i') }}
+
+ @endif
+ @endif
@@ -168,7 +236,8 @@ class="text-sm text-gray-900">{{ $venue->updated_at->format('d M Y, H:i') }}
Meja Tersedia
- {{ $venue->tables->where('status', 'available')->count() }}
+ {{ $venue->tables->where('status', 'available')->count() }}
+
@@ -188,10 +257,255 @@ class="text-sm text-gray-900">{{ $venue->updated_at->format('d M Y, H:i') }}
Meja Terpakai
- {{ $venue->tables->where('status', 'occupied')->count() }}
+ {{ $venue->tables->where('status', 'occupied')->count() }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@endsection
\ No newline at end of file
diff --git a/resources/views/pages/home.blade.php b/resources/views/pages/home.blade.php
index 39bbaa4..096bcaa 100644
--- a/resources/views/pages/home.blade.php
+++ b/resources/views/pages/home.blade.php
@@ -58,11 +58,32 @@ class="flex flex-col h-full border border-gray-400 rounded-lg overflow-hidden">
Venue
{{ $venue->name }}
-
-
- Buka: {{ date('H:i', strtotime($venue['open_time'])) }} -
- {{ date('H:i', strtotime($venue['close_time'])) }}
-
+ @if($venue['status'] === 'open')
+ {{-- Venue sedang buka - tampilkan jam operasional --}}
+
+
+ Buka: {{ date('H:i', strtotime($venue['open_time'])) }} -
+ {{ date('H:i', strtotime($venue['close_time'])) }}
+
+ @else
+ {{-- Venue sedang tutup - tampilkan informasi penutupan --}}
+
+
+
+ Tutup Sementara - {{ $venue['close_reason'] }}
+
+
+
+ @if(!empty($venue['reopen_date']))
+
+
+ Buka kembali:
+ {{ \Carbon\Carbon::parse($venue['reopen_date'])->format('d M Y') }} - Jam
+ {{ date('H:i', strtotime($venue['original_open_time'])) }}
+
+ @endif
+
+ @endif
Mulai:
Rp30,000
/ jam
diff --git a/resources/views/pages/venue.blade.php b/resources/views/pages/venue.blade.php
index c61e412..6be2b2e 100644
--- a/resources/views/pages/venue.blade.php
+++ b/resources/views/pages/venue.blade.php
@@ -22,11 +22,22 @@ class="w-full h-full object-cover rounded-lg mb-4 mt-8" />
{{ $venue['name'] }}
{{ $venue['location'] ?? 'Lokasi tidak tersedia' }}
-
-
- Jam Operasional: {{ date('H:i', strtotime($venue['open_time'])) }} -
- {{ date('H:i', strtotime($venue['close_time'])) }}
-
+ @if($venue['status'] === 'open')
+ {{-- Venue sedang buka - tampilkan jam operasional --}}
+
+
+ Jam Operasional: {{ date('H:i', strtotime($venue['open_time'])) }} -
+ {{ date('H:i', strtotime($venue['close_time'])) }}
+
+ @else
+ {{-- Venue sedang tutup - tampilkan informasi penutupan --}}
+
+
+
+ Tutup Sementara - {{ $venue['close_reason'] }}
+
+
+ @endif
@@ -183,12 +194,12 @@ function showToast(message, type = 'info', duration = 5000) {
toast.className = `${bgColor} text-white px-6 py-4 rounded-lg shadow-lg flex items-center space-x-3 min-w-80 transform transition-all duration-300 translate-x-full opacity-0`;
toast.innerHTML = `
-
- ${message}
-
- `;
+
+ ${message}
+
+ `;
toastContainer.appendChild(toast);
@@ -224,20 +235,20 @@ function showModal(title, message, type = 'info', callback = null) {
}[type] || 'fa-info-circle';
modal.innerHTML = `
-
- `;
+
+ `;
document.body.appendChild(modal);
@@ -256,22 +267,22 @@ function showConfirmModal(title, message, onConfirm, onCancel = null) {
modal.className = 'fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4';
modal.innerHTML = `
-
- `;
+
+ `;
document.body.appendChild(modal);
diff --git a/routes/web.php b/routes/web.php
index dd97719..0339960 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -100,6 +100,7 @@
Route::get('/venue', [AdminVenueController::class, 'index'])->name('admin.venue.index');
Route::get('/venue/edit', [AdminVenueController::class, 'edit'])->name('admin.venue.edit');
Route::put('/venue/update', [AdminVenueController::class, 'update'])->name('admin.venue.update');
+ Route::post('/venue/toggle-status', [AdminVenueController::class, 'toggleStatus'])->name('admin.venue.toggle-status');
// Revenue management routes
Route::get('/revenues', [RevenueController::class, 'index'])->name('admin.revenues.index');