From 2231c3e874e8cb821c3232280414ba820a4d19d3 Mon Sep 17 00:00:00 2001 From: Stephen Gesityan Date: Thu, 15 May 2025 05:01:28 +0700 Subject: [PATCH] Reschedule --- .../Controllers/pages/BookingController.php | 130 ++++++++++ ...d_reschedule_columns_to_bookings_table.php | 25 ++ .../views/pages/booking-history.blade.php | 24 +- resources/views/pages/reschedule.blade.php | 238 ++++++++++++++++++ routes/web.php | 5 + 5 files changed, 418 insertions(+), 4 deletions(-) create mode 100644 database/migrations/2025_05_15_035617_add_reschedule_columns_to_bookings_table.php create mode 100644 resources/views/pages/reschedule.blade.php diff --git a/app/Http/Controllers/pages/BookingController.php b/app/Http/Controllers/pages/BookingController.php index cff93b9..57af560 100644 --- a/app/Http/Controllers/pages/BookingController.php +++ b/app/Http/Controllers/pages/BookingController.php @@ -480,4 +480,134 @@ public function deletePendingBooking($id) ], 500); } } + + public function showReschedule($id) +{ + $booking = Booking::with(['table.venue', 'table.venue.tables'])->findOrFail($id); + + // Check if user owns this booking + if ($booking->user_id !== auth()->id()) { + return redirect()->route('booking.history')->with('error', 'Anda tidak memiliki akses ke booking ini.'); + } + + // Check if booking is upcoming and paid + if ($booking->start_time <= now() || $booking->status !== 'paid') { + return redirect()->route('booking.history')->with('error', 'Booking ini tidak dapat di-reschedule.'); + } + + // Check if already rescheduled + if ($booking->has_rescheduled) { + return redirect()->route('booking.history')->with('error', 'Booking ini sudah pernah di-reschedule sebelumnya.'); + } + + // Check if it's within the time limit (at least 1 hour before start) + $rescheduleDeadline = Carbon::parse($booking->start_time)->subHour(); + if (now() > $rescheduleDeadline) { + return redirect()->route('booking.history')->with('error', 'Batas waktu reschedule telah berakhir (1 jam sebelum mulai).'); + } + + // Get venue and tables data + $venue = $booking->table->venue; + + // Duration in hours + $duration = Carbon::parse($booking->start_time)->diffInHours($booking->end_time); + + return view('pages.reschedule', compact('booking', 'venue', 'duration')); +} + +/** + * Process a reschedule request. + */ +public function processReschedule(Request $request, $id) +{ + $request->validate([ + 'table_id' => 'required|exists:tables,id', + 'start_time' => 'required|date_format:Y-m-d H:i:s', + 'end_time' => 'required|date_format:Y-m-d H:i:s|after:start_time', + ]); + + $booking = Booking::findOrFail($id); + + // Perform the same validation as in showReschedule + if ($booking->user_id !== auth()->id() || + $booking->start_time <= now() || + $booking->status !== 'paid' || + $booking->has_rescheduled || + now() > Carbon::parse($booking->start_time)->subHour()) { + return response()->json([ + 'success' => false, + 'message' => 'Booking ini tidak dapat di-reschedule.' + ], 422); + } + + // Check if the selected time is available (except for this booking) + $existingBookings = Booking::where('table_id', $request->table_id) + ->where('id', '!=', $booking->id) + ->where('status', 'paid') + ->where(function ($query) use ($request) { + $query->where(function ($q) use ($request) { + $q->where('start_time', '<', $request->end_time) + ->where('end_time', '>', $request->start_time); + }); + })->count(); + + if ($existingBookings > 0) { + return response()->json([ + 'success' => false, + 'message' => 'Jam yang dipilih sudah dibooking oleh orang lain.' + ], 422); + } + + // Store original booking details + $originalStartTime = $booking->start_time; + $originalEndTime = $booking->end_time; + $originalTableId = $booking->table_id; + + // Update the booking + $booking->original_start_time = $originalStartTime; + $booking->original_end_time = $originalEndTime; + $booking->original_table_id = $originalTableId; + $booking->start_time = $request->start_time; + $booking->end_time = $request->end_time; + $booking->table_id = $request->table_id; + $booking->has_rescheduled = true; + $booking->save(); + + return response()->json([ + 'success' => true, + 'message' => 'Booking berhasil di-reschedule.', + 'redirect' => route('booking.history') + ]); +} + +/** + * Check availability for reschedule. + */ +public function checkRescheduleAvailability(Request $request) +{ + $request->validate([ + 'table_id' => 'required|exists:tables,id', + 'date' => 'required|date_format:Y-m-d', + 'booking_id' => 'required|exists:bookings,id' + ]); + + $date = $request->date; + $tableId = $request->table_id; + $bookingId = $request->booking_id; + + // Get all bookings for this table on this date (excluding the current booking) + $bookings = Booking::where('table_id', $tableId) + ->where('id', '!=', $bookingId) + ->where('status', 'paid') + ->whereDate('start_time', $date) + ->get(['start_time', 'end_time']) + ->map(function ($booking) { + return [ + 'start' => Carbon::parse($booking->start_time)->format('H:i'), + 'end' => Carbon::parse($booking->end_time)->format('H:i'), + ]; + }); + + return response()->json($bookings); +} } \ No newline at end of file diff --git a/database/migrations/2025_05_15_035617_add_reschedule_columns_to_bookings_table.php b/database/migrations/2025_05_15_035617_add_reschedule_columns_to_bookings_table.php new file mode 100644 index 0000000..7f0eb75 --- /dev/null +++ b/database/migrations/2025_05_15_035617_add_reschedule_columns_to_bookings_table.php @@ -0,0 +1,25 @@ +boolean('has_rescheduled')->default(false); + $table->timestamp('original_start_time')->nullable(); + $table->timestamp('original_end_time')->nullable(); + $table->unsignedBigInteger('original_table_id')->nullable(); + }); + } + + public function down() + { + Schema::table('bookings', function (Blueprint $table) { + $table->dropColumn(['has_rescheduled', 'original_start_time', 'original_end_time', 'original_table_id']); + }); + } +} \ No newline at end of file diff --git a/resources/views/pages/booking-history.blade.php b/resources/views/pages/booking-history.blade.php index 91eca17..6cd007f 100644 --- a/resources/views/pages/booking-history.blade.php +++ b/resources/views/pages/booking-history.blade.php @@ -1,6 +1,4 @@ -@extends('layouts.main') -@section('content') -
+@extends('layouts.main') @section('content')

Riwayat Booking

@if($bookings->isEmpty()) @@ -53,12 +51,30 @@ class="px-3 py-1 rounded-full text-sm {{ $booking->start_time > now() ? 'bg-gree

Metode Pembayaran

{{ $booking->payment_method ?? '-' }}

+ @if($booking->has_rescheduled) +
+

Informasi Reschedule

+

+ Booking ini telah di-reschedule dari tanggal + {{ \Carbon\Carbon::parse($booking->original_start_time)->format('d M Y') }} jam + {{ \Carbon\Carbon::parse($booking->original_start_time)->format('H:i') }} - + {{ \Carbon\Carbon::parse($booking->original_end_time)->format('H:i') }} +

+
+ @endif
@if($booking->start_time > now() && $booking->status == 'paid') -
+
Lihat Venue + + @if(!$booking->has_rescheduled && \Carbon\Carbon::parse($booking->start_time)->subHour() > now()) + + Reschedule + + @endif
@endif
diff --git a/resources/views/pages/reschedule.blade.php b/resources/views/pages/reschedule.blade.php new file mode 100644 index 0000000..a633aab --- /dev/null +++ b/resources/views/pages/reschedule.blade.php @@ -0,0 +1,238 @@ +@extends('layouts.main') +@section('content') +
+

Reschedule Booking

+
+

Detail Booking Saat Ini

+
+
+

Venue

+

{{ $booking->table->venue->name }}

+
+
+

Meja

+

{{ $booking->table->name }} ({{ $booking->table->brand }})

+
+
+

Tanggal & Waktu

+

+ {{ \Carbon\Carbon::parse($booking->start_time)->format('d M Y') }}, + {{ \Carbon\Carbon::parse($booking->start_time)->format('H:i') }} - + {{ \Carbon\Carbon::parse($booking->end_time)->format('H:i') }} +

+
+
+

Durasi

+

{{ $duration }} Jam

+
+
+ +
+
+
+ +
+
+

Perhatian

+

+ • Reschedule hanya dapat dilakukan 1x untuk setiap booking
+ • Batas waktu reschedule adalah 1 jam sebelum jadwal booking
+ • Durasi booking akan tetap sama ({{ $duration }} jam) +

+
+
+
+
+ +
+

Pilih Jadwal Baru

+ +
+
+ + +
+ +
+ + +
+
+ +
+ +
+ +
+ +
+

+ Jadwal reschedule: +

+
+
+ +
+ + Batal + + +
+
+
+ + +@endsection \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index 0d0cc36..50d8197 100644 --- a/routes/web.php +++ b/routes/web.php @@ -57,6 +57,11 @@ Route::get('/booking/pending/{id}/resume', [BookingController::class, 'resumeBooking'])->name('booking.resume'); Route::delete('/booking/pending/{id}', [BookingController::class, 'deletePendingBooking'])->name('booking.pending.delete'); + // Route Reschedule + Route::get('/booking/{id}/reschedule', [BookingController::class, 'showReschedule'])->name('booking.reschedule.form'); + Route::post('/booking/{id}/reschedule', [BookingController::class, 'processReschedule'])->name('booking.reschedule.process'); + Route::get('/booking/reschedule/check-availability', [BookingController::class, 'checkRescheduleAvailability'])->name('booking.reschedule.check-availability'); + // Routes that require password confirmation - moved account settings out of this group Route::middleware(['password.confirm'])->group(function () { // Any sensitive operations that should still require password confirmation can go here