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 = ` -
-
- -

${title}

-
-

${message}

-
- -
-
- `; +
+
+ +

${title}

+
+

${message}

+
+ +
+
+ `; 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 = ` -
-
- -

${title}

-
-

${message}

-
- - -
-
- `; +
+
+ +

${title}

+
+

${message}

+
+ + +
+
+ `; 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');