From 1f94e5945900b40b0e3f17a6889256424320db6b Mon Sep 17 00:00:00 2001 From: LailaWulandarii Date: Sun, 28 Dec 2025 19:23:42 +0700 Subject: [PATCH] Refactor booking and payment flow for photo packages - Updated booking-foto.blade.php to use forelse for displaying photo packages and added SweetAlert notifications for successful and error sessions. - Created a new calendar-grid component for better date selection in detail-foto.blade.php. - Enhanced detail-foto.blade.php to include a booking form with additional options and a calendar for selecting dates and times. - Improved pembayaran-foto.blade.php to handle errors, include hidden fields for previous selections, and add file upload preview functionality. - Updated web.php routes to better organize user and admin routes, including AJAX endpoints for calendar loading and slot checking. --- .../user/BookingFotoController.php | 238 ++++++++- ...2_26_150621_create_booking_fotos_table.php | 2 +- database/seeders/PaketFotoSeeder.php | 65 ++- resources/views/user/booking-foto.blade.php | 60 ++- .../user/components/calendar-grid.blade.php | 44 ++ resources/views/user/detail-foto.blade.php | 484 +++++++++++------- .../views/user/pembayaran-foto.blade.php | 173 +++++-- routes/web.php | 110 ++-- 8 files changed, 885 insertions(+), 291 deletions(-) create mode 100644 resources/views/user/components/calendar-grid.blade.php diff --git a/app/Http/Controllers/user/BookingFotoController.php b/app/Http/Controllers/user/BookingFotoController.php index 487b348..c4b6ad8 100644 --- a/app/Http/Controllers/user/BookingFotoController.php +++ b/app/Http/Controllers/user/BookingFotoController.php @@ -3,20 +3,248 @@ namespace App\Http\Controllers\User; use App\Http\Controllers\Controller; +use App\Models\Additional; +use App\Models\BookingFoto; +use App\Models\DetailAdditional; +use App\Models\PaketFoto; +use App\Models\Pelanggan; use Illuminate\Http\Request; +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Str; class BookingFotoController extends Controller { public function index() { - return view('user/booking-foto'); + $foto = PaketFoto::latest()->get(); + + return view('user/booking-foto', compact('foto')); } - public function detail() + public function detail($id) { - return view('user/detail-foto'); + $foto = PaketFoto::findOrFail($id); + + // Jika add-ons disimpan di DB, ambil juga: + $additionals = Additional::all(); + // Logika Tanggal + $start = \Carbon\Carbon::now(); // Mulai hari ini + $end = \Carbon\Carbon::now()->addMonth(); // Maksimal 1 bulan ke depan + // Untuk navigasi panah + $prevMonth = $start->copy()->subMonth(); + $nextMonth = $start->copy()->addMonth(); + + $currentMonthLabel = $start->format('F Y'); + return view('user.detail-foto', compact('foto', 'additionals', 'start', 'end', 'currentMonthLabel', 'prevMonth', 'nextMonth')); } - public function formulir() + public function loadCalendar(Request $request) { - return view('user/pembayaran-foto'); + // Ambil bulan & tahun dari request AJAX, atau default sekarang + $month = $request->month ?? date('m'); + $year = $request->year ?? date('Y'); + + $start = \Carbon\Carbon::createFromDate($year, $month, 1); + + // Data Navigasi + $prevMonth = $start->copy()->subMonth(); + $nextMonth = $start->copy()->addMonth(); + $currentMonthLabel = $start->format('F Y'); + + // Return hanya potongan HTML (Partial), bukan halaman full + $html = view('user.components.calendar-grid', compact( + 'start', + 'prevMonth', + 'nextMonth', + 'currentMonthLabel' + ))->render(); + + // Return JSON agar JavaScript bisa membacanya sebagai data.html + return response()->json(['html' => $html]); + } + public function cekSlot(Request $request) + { + // Cari booking yang statusnya valid (bukan dibatalkan/ditolak) + // Sesuaikan status dengan logic bisnis kamu + $booked = BookingFoto::where('tgl_booking', $request->tanggal) + ->whereIn('status_booking', ['menunggu_verifikasi', 'diterima', 'selesai']) + ->get(['jam_mulai']); + + return response()->json($booked); + } + public function formulir(Request $request) + { + // 1. Ambil Data Paket + $foto = PaketFoto::findOrFail($request->id_paket); + + // 2. Hitung Total Add-ons (Jika ada) + $addonsDetails = []; + $totalAddon = 0; + + if ($request->has('addons')) { + foreach ($request->addons as $id => $qty) { + if ($qty > 0) { + $add = Additional::find($id); + $subtotal = $add->harga * $qty; + $totalAddon += $subtotal; + + $addonsDetails[] = [ + 'nama' => $add->nama, + 'qty' => $qty, + 'subtotal' => $subtotal, + 'id' => $id // Simpan ID untuk dikirim lagi nanti + ]; + } + } + } + + // 3. Hitung Grand Total + $grandTotal = $foto->harga + $totalAddon; + // 1. Cek apakah sudah ada deadline di session? Kalau belum, buat baru (2 jam dari sekarang) + if (!session()->has('payment_deadline')) { + $deadline = now()->addHours(2); + session()->put('payment_deadline', $deadline); + } else { + $deadline = session('payment_deadline'); + } + + // 2. Hitung sisa waktu dalam detik + $sisaWaktu = now()->diffInSeconds($deadline, false); // false = biar bisa negatif kalau lewat + + // 3. Jika waktu habis (negatif), hapus session dan tendang user + if ($sisaWaktu <= 0) { + session()->forget(['payment_deadline', 'addons']); // Bersihkan session + return redirect()->route('booking.foto')->with('error', 'Waktu pembayaran telah habis. Silakan ulang pemesanan.'); + } + // 4. Kirim semua data ke View Pembayaran untuk ditampilkan + return view('user.pembayaran-foto', compact( + 'foto', + 'request', // Kirim request agar tgl & jam bisa diakses di blade + 'addonsDetails', + 'grandTotal', + 'sisaWaktu' + )); + } + public function cancelBooking() + { + session()->forget(['payment_deadline', 'addons']); // Hapus session timer & data + return redirect()->route('booking.foto'); // Kembali ke katalog utama + } + public function store(Request $request) + { + + // 1. Validasi Input + $request->validate([ + 'id_paket' => 'required|exists:paket_fotos,id_paket', + 'tgl_booking' => 'required|date|after_or_equal:today', + 'jam_mulai' => 'required', + 'nama' => 'required|string|max:255', + 'no_wa' => 'required|numeric', + 'bukti_bayar' => 'required|image|mimes:jpeg,png,jpg|max:2048', + ]); + + DB::beginTransaction(); // Mulai Transaksi Database + + try { + // 2. Ambil Data Paket & Hitung Waktu + $paket = PaketFoto::findOrFail($request->id_paket); + + // Asumsi durasi default 20 menit (atau ambil dari database jika ada kolom durasi) + $durasiMenit = $paket->durasi; + $jamMulai = \Carbon\Carbon::createFromFormat('H:i', $request->jam_mulai); + $jamSelesai = $jamMulai->copy()->addMinutes($durasiMenit); + + // 3. Cek Slot Sekali Lagi (Mencegah Race Condition) + $isTaken = BookingFoto::where('tgl_booking', $request->tgl_booking) + ->where('jam_mulai', $request->jam_mulai) + ->whereIn('status_booking', ['menunggu_verifikasi', 'diterima', 'selesai']) + ->exists(); + + if ($isTaken) { + return back()->with('error', 'Mohon maaf, slot waktu ini baru saja diambil orang lain.'); + } + + // 4. Simpan/Update Data Pelanggan + $pelanggan = Pelanggan::firstOrCreate( + ['no_wa' => $request->no_wa], + ['nama' => $request->nama] + ); + + // 5. Upload Bukti Bayar + $pathBukti = null; + if ($request->hasFile('bukti_bayar')) { + $file = $request->file('bukti_bayar'); + $namaFile = 'bukti_' . time() . '_' . Str::random(5) . '.' . $file->getClientOriginalExtension(); + $file->move(public_path('img/payment'), $namaFile); + $pathBukti = 'img/payment/' . $namaFile; + } + + // 6. Hitung Grand Total (Paket + Additional) + // Kita hitung ulang di server agar aman dari manipulasi inspect element + $grandTotal = $paket->harga; + $listAdditional = []; + + if ($request->has('addons')) { + foreach ($request->addons as $idAddon => $qty) { + if ($qty > 0) { + $add = \App\Models\Additional::find($idAddon); + if ($add) { + $subtotal = $add->harga * $qty; + $grandTotal += $subtotal; + + $listAdditional[] = [ + 'id_additional' => $idAddon, + 'qty' => $qty, + 'subtotal' => $subtotal + ]; + } + } + } + } + + // 7. Simpan Booking Utama + $booking = BookingFoto::create([ + 'no_invoice' => 'INV-FOTO-' . strtoupper(Str::random(6)), + 'id_pelanggan' => $pelanggan->id_pelanggan, + 'id_paket' => $paket->id_paket, + 'tgl_booking' => $request->tgl_booking, + 'jam_mulai' => $request->jam_mulai, // Format "09:00" + 'jam_selesai' => $jamSelesai->format('H:i'), + 'total_bayar' => $grandTotal, + 'bukti_bayar' => $pathBukti, + 'status_booking' => 'menunggu_verifikasi' + ]); + + // 8. Simpan Detail Additional (Jika ada) + foreach ($listAdditional as $item) { + DetailAdditional::create([ + 'id_booking' => $booking->id_booking, + 'id_additional' => $item['id_additional'], + 'qty' => $item['qty'], + 'subtotal' => $item['subtotal'] + ]); + } + + DB::commit(); + // 9. Redirect ke WhatsApp atau Halaman Sukses + $pesan = "Halo Admin Flo.do! Saya pesan foto paket *{$paket->nama}*.\n" . + "Tanggal: {$request->tgl_booking}\n" . + "Jam: {$request->jam_mulai}\n" . + "Total: Rp " . number_format($grandTotal, 0, ',', '.') . "\n" . + "Mohon diverifikasi ya."; + + $urlWA = "https://wa.me/6289673668516?text=" . urlencode($pesan); + session()->forget('payment_deadline'); + + return redirect()->route('booking.foto')->with([ + 'success' => 'Pesanan Berhasil Dibuat!', + 'waUrl' => $urlWA + ]); + } catch (\Exception $e) { + DB::rollBack(); + // Teks Debugging Lengkap + $errorMsg = "Error: " . $e->getMessage() . " | Baris: " . $e->getLine() . " | File: " . basename($e->getFile()); + + // Kirim pesan error lengkap ke layar + return back()->with('error', $errorMsg)->withInput(); + } } } diff --git a/database/migrations/2025_12_26_150621_create_booking_fotos_table.php b/database/migrations/2025_12_26_150621_create_booking_fotos_table.php index 17d9b56..fa6ab07 100644 --- a/database/migrations/2025_12_26_150621_create_booking_fotos_table.php +++ b/database/migrations/2025_12_26_150621_create_booking_fotos_table.php @@ -26,7 +26,7 @@ public function up(): void $table->string('bukti_bayar')->nullable(); // Enum Status Final - $table->enum('status_booking', ['menunggu_verifikasi', 'diproses', 'selesai', 'dibatalkan'])->default('menunggu_verifikasi'); + $table->enum('status_booking', ['menunggu_verifikasi', 'diterima', 'ditolak', 'selesai', 'dibatalkan'])->default('menunggu_verifikasi'); $table->timestamps(); }); diff --git a/database/seeders/PaketFotoSeeder.php b/database/seeders/PaketFotoSeeder.php index 6852029..8270d5c 100644 --- a/database/seeders/PaketFotoSeeder.php +++ b/database/seeders/PaketFotoSeeder.php @@ -11,25 +11,60 @@ public function run(): void { $data = [ [ - 'nama' => 'Wisuda Basic', - 'harga' => 250000, - 'deskripsi' => 'Foto wisuda outdoor 1 jam, 10 edit file, all file mentah.', - 'foto' => 'img/foto/foto1.jpeg', - 'durasi' => '60', + 'nama' => 'Single', + 'harga' => 20000, + 'deskripsi' => 'Untuk 1 orang, 10 menit sesi foto sepuasnya, 5 menit sesi pilih foto (jika ada yang di print).', + 'foto' => 'img/foto/single.jpeg', + 'durasi' => '10', ], [ - 'nama' => 'Couple Studio Session', - 'harga' => 350000, - 'deskripsi' => 'Foto studio couple 45 menit, 2 cetak 10R, 5 edit file.', - 'foto' => 'img/foto/foto2.jpeg', - 'durasi' => '45', + 'nama' => 'Couple', + 'harga' => 45000, + 'deskripsi' => 'Untuk 2 orang, 15 menit sesi foto sepuasnya, 5 menit sesi pilih foto, 1 lembar print out foto ukutan 4R.', + 'foto' => 'img/foto/grup.jpeg', + 'durasi' => '15', ], [ - 'nama' => 'Group Photoshoot (Max 10 Orang)', - 'harga' => 500000, - 'deskripsi' => 'Foto grup, cocok untuk angkatan atau keluarga besar. Durasi 2 jam.', - 'foto' => 'img/foto/foto3.jpeg', - 'durasi' => '120', + 'nama' => 'Group', + 'harga' => 80000, + 'deskripsi' => 'Untuk 3-5 orang, 15 menit sesi foto sepuasnya, 5 menit sesi pilih foto, 3 lembar print out foto ukutan 4R.', + 'foto' => 'img/foto/pas-foto.jpg', + 'durasi' => '15', + ], + [ + 'nama' => 'Pas Foto Paket 1', + 'harga' => 25000, + 'deskripsi' => 'Sesi pas foto untuk 1 orang dengan 8x shoot fotografer. Termasuk 1 file foto edit dan bebas request warna background. Paket cetak: ukuran 2x3 (12 lembar).', + 'foto' => 'img/foto/pas-foto.jpg', + 'durasi' => '0', + ], + [ + 'nama' => 'Pas Foto Paket 2', + 'harga' => 25000, + 'deskripsi' => 'Sesi pas foto untuk 1 orang dengan 8x shoot fotografer. Termasuk 1 file foto edit dan bebas request warna background. Paket cetak: ukuran 3x4 (8 lembar).', + 'foto' => 'img/foto/pas-foto.jpg', + 'durasi' => '0', + ], + [ + 'nama' => 'Pas Foto Paket 3', + 'harga' => 25000, + 'deskripsi' => 'Sesi pas foto untuk 1 orang dengan 8x shoot fotografer. Termasuk 1 file foto edit dan bebas request warna background. Paket cetak: ukuran 4x6 (4 lembar).', + 'foto' => 'img/foto/pas-foto.jpg', + 'durasi' => '0', + ], + [ + 'nama' => 'Pas Foto Paket 4', + 'harga' => 25000, + 'deskripsi' => 'Sesi pas foto untuk 1 orang dengan 8x shoot fotografer. Termasuk 1 file foto edit dan bebas request warna background. Paket cetak campur: ukuran 4x6 (2 lembar), 3x4 (3 lembar), dan 2x3 (4 lembar).', + 'foto' => 'img/foto/pas-foto.jpg', + 'durasi' => '0', + ], + [ + 'nama' => 'Background Biru', + 'harga' => 95000, + 'deskripsi' => 'Paket foto untuk 2 orang. Termasuk: Max 10x shoot fotografer (formal), 10 menit self-photo (bebas), dan semua file dikirim via Google Drive. Cetak 2 Foto (4R) terdiri dari: (2x3) 8 lembar, (3x4) 6 lembar, dan (4x6) 4 lembar.', + 'foto' => 'img/foto/latar-biru.jpeg', + 'durasi' => '20', ], ]; diff --git a/resources/views/user/booking-foto.blade.php b/resources/views/user/booking-foto.blade.php index b72f6e0..b9231cc 100644 --- a/resources/views/user/booking-foto.blade.php +++ b/resources/views/user/booking-foto.blade.php @@ -16,27 +16,67 @@
- - @for ($i = 1; $i <= 8; $i++) + @forelse ($foto as $f)
-
+
- Paket Foto + {{ $f->nama }}
-
Paket Self Photo {{ $i }}
-

Rp 85.000

+
{{ $f->nama }}
+

Rp {{ number_format($f->harga, 0, ',', '.') }} +

- +
- @endfor - + @empty +
+

Paket foto tidak ditemukan

+
+ @endforelse
+
+
+ {{-- Cek session waUrl agar sama dengan pola buket --}} + @if (session('waUrl')) + {{-- Panggil library SweetAlert2 secara lokal di sini untuk memastikan ia ada --}} + + + + @endif + + {{-- Pisahkan handler error --}} + @if (session('error')) + + + @endif @endsection diff --git a/resources/views/user/components/calendar-grid.blade.php b/resources/views/user/components/calendar-grid.blade.php new file mode 100644 index 0000000..c4d6bd2 --- /dev/null +++ b/resources/views/user/components/calendar-grid.blade.php @@ -0,0 +1,44 @@ +
+ + + {{ $currentMonthLabel }} + + +
+ +
+
Su
+
Mo
+
Tu
+
We
+
Th
+
Fr
+
Sa
+ + {{-- Offset Spasi --}} + @for ($i = 0; $i < $start->copy()->startOfMonth()->dayOfWeek; $i++) +
+ @endfor + + {{-- Loop Tanggal --}} + @php $daysInMonth = $start->copy()->daysInMonth; @endphp + @for ($day = 1; $day <= $daysInMonth; $day++) + @php + $dateFull = $start->copy()->day($day); + // Logic Disabled: Lewat hari ini ATAU lebih dari 30 hari ke depan + $isPast = $dateFull->isPast() && !$dateFull->isToday(); + $isTooFar = $dateFull->diffInDays(\Carbon\Carbon::now()) > 30; + $isDisabled = $isPast || $isTooFar; + @endphp + +
+ {{ $day }} +
+ @endfor +
diff --git a/resources/views/user/detail-foto.blade.php b/resources/views/user/detail-foto.blade.php index 7898183..c34f257 100644 --- a/resources/views/user/detail-foto.blade.php +++ b/resources/views/user/detail-foto.blade.php @@ -12,204 +12,338 @@ -
-
+ {{-- Seluruh Konten dalam Form agar data Add-ons & Slot terkirim --}} +
+ @csrf + {{-- Kotak simpan data sementara di dalam form --}} + + + +
+
+
+ -
-
-
- Paket Single -
-
-
-
-
-

Single

-

Rp 20.000

-

Untuk 1 menit • 10 menit sesi foto sepuasnya • - 5 menit sesi pilih foto (jika ada yang diprint) -

+
+
+
+ {{ $foto->nama }}
-
-
- -
Additional
-
-
-
- Tambah orang untuk paket grup - Rp 15.000 -
-
- - - -
-
- -
-
- Kostum boneka (onesize)/orang - Rp 10.000 -
-
- - - -
-
- -
-
- Tambah print out foto 4R/lembar - Rp 7.000 -
-
- - - -
-
-
- -
- -
- -
- -
-
-
- -
- Slot Anda akan dibatalkan otomatis dalam - 09:58 -
- -

Pilih Tanggal dan Waktu Pemotretan

- -

- Slot abu-abu berarti jadwal sudah penuh. Silakan pilih waktu lain yang tersedia. -

- -
-
- -
- -
- - - - June 2025 - - - -
- -
-
Su
-
Mo
-
Tu
-
We
-
Th
-
Fr
-
Sa
- -
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
-
- -
-
Jam Tersedia
- -
- - - - - - - - +
+
+

{{ $foto->nama }}

+

Rp {{ number_format($foto->harga, 0, ',', '.') }} +

+

{{ $foto->deskripsi }}

-
+
Additional
+
+ @foreach ($additionals as $add) +
+
+ {{ $add->nama }} + Rp + {{ number_format($add->harga, 0, ',', '.') }} +
+
+ + + +
+
+ @endforeach +
- +
+
- - Pesan Sekarang - +
+
+
+
+ Slot Anda akan dibatalkan otomatis dalam + 10:00 +
+

Pilih Tanggal dan Waktu

+
+
+
+ @include('user.components.calendar-grid') +
+ +
+
Jam Tersedia
+
+ @for ($hour = 9; $hour <= 20; $hour++) + + + @endfor +
+
+
+ +
+ + +
- -
+
@endsection diff --git a/resources/views/user/pembayaran-foto.blade.php b/resources/views/user/pembayaran-foto.blade.php index 4acb313..6db5fb3 100644 --- a/resources/views/user/pembayaran-foto.blade.php +++ b/resources/views/user/pembayaran-foto.blade.php @@ -11,9 +11,28 @@

Formulir Pemesanan

- -
+ @if ($errors->any()) +
+
    + @foreach ($errors->all() as $error) +
  • {{ $error }}
  • + @endforeach +
+
+ @endif + @csrf + {{-- DATA DARI HALAMAN SEBELUMNYA (WAJIB ADA) --}} + + + + + {{-- Loop untuk mengirim ulang data Add-ons yang dipilih --}} + @if (!empty($addonsDetails)) + @foreach ($addonsDetails as $add) + + @endforeach + @endif
@@ -22,14 +41,14 @@
- +
- +
@@ -45,30 +64,38 @@
Jadwal Booking:
- Thursday, June 10, 2025 - 10:00 PM + {{ \Carbon\Carbon::parse($request->tgl_booking)->translatedFormat('l, d F Y') }} + {{ $request->jam_mulai }}
Paket Foto:
- Single - Rp 20.000 + {{ $foto->nama }} + Rp {{ number_format($foto->harga, 0, ',', '.') }}
Additional: -
-
- Kostum boneka (onesize) - x1 + @forelse($addonsDetails as $add) +
+
+ {{ $add['nama'] }} + x{{ $add['qty'] }} +
+ Rp + {{ number_format($add['subtotal'], 0, ',', '.') }}
- Rp 20.000 -
+ @empty +
+ - Tidak ada tambahan - +
+ @endforelse
Total Pembayaran -
Rp 150.000
+
Rp {{ number_format($grandTotal, 0, ',', '.') }}

Transfer ke Rekening Berikut:

@@ -110,8 +137,8 @@ class="btn btn-sm btn-outline-secondary py-1 px-3 x-small btn-copy"
-
+ name="bukti_bayar" accept="image/*" id="fileUpload"> +

Upload Bukti Pembayaran

Max. 2 MB

@@ -123,9 +150,12 @@ class="position-absolute w-100 h-100 opacity-0 start-0 top-0 cursor-pointer"

- Batalkan - + {{-- Batalkan --}} +
@@ -137,41 +167,74 @@ class="btn formulirfoto-btn-cancel flex-fill">Batalkan @endsection diff --git a/routes/web.php b/routes/web.php index 262d536..9271e17 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,45 +1,95 @@ name('beranda'); - Route::get('/login', [App\Http\Controllers\Admin\AuthController::class, 'login'])->name('login'); - Route::get('/pesan-buket', [App\Http\Controllers\User\PesanBuketController::class, 'index'])->name('pesan.buket'); - Route::get('/detail-buket', [App\Http\Controllers\User\PesanBuketController::class, 'detail'])->name('detail.buket'); - Route::get('/formulir-pemesanan-buket', [App\Http\Controllers\User\PesanBuketController::class, 'formulir'])->name('formulir.buket'); - Route::get('/booking-foto', [App\Http\Controllers\User\BookingFotoController::class, 'index'])->name('booking.foto'); - Route::get('/detail-paket-foto', [App\Http\Controllers\User\BookingFotoController::class, 'detail'])->name('detail.foto'); - Route::get('/formulir-pemesanan-foto', [App\Http\Controllers\User\BookingFotoController::class, 'formulir'])->name('formulir.foto'); + Route::get('/', [User\BerandaController::class, 'index'])->name('beranda'); + + // Fitur Buket + Route::get('/pesan-buket', [User\PesanBuketController::class, 'index'])->name('pesan.buket'); + Route::get('/pesan-buket/{id}', [User\PesanBuketController::class, 'detail'])->name('detail.buket'); + Route::get('/formulir-buket/{id}', [User\PesanBuketController::class, 'formulir'])->name('formulir.buket'); + Route::post('/formulir-buket/store', [User\PesanBuketController::class, 'store'])->name('transaksi.buket.store'); + // Fitur Foto + Route::get('/booking-foto', [User\BookingFotoController::class, 'index'])->name('booking.foto'); + Route::get('/detail-paket-foto/{id}', [User\BookingFotoController::class, 'detail'])->name('detail.foto'); // Tambah {id} + Route::get('/formulir-pemesanan-foto', [User\BookingFotoController::class, 'formulir'])->name('formulir.foto'); + + Route::get('/load-calendar', [User\BookingFotoController::class, 'loadCalendar'])->name('ajax.load-calendar'); + Route::get('/cek-slot-foto', [User\BookingFotoController::class, 'cekSlot'])->name('ajax.check-slot'); + + Route::post('/simpan-booking-foto', [User\BookingFotoController::class, 'store'])->name('transaksi.foto.store'); + Route::get('/cancel-booking', [User\BookingFotoController::class, 'cancelBooking'])->name('booking.cancel'); + + Route::get('/test-flow', [User\TestBookingController::class, 'index']); + Route::get('/cek-slot-foto', [User\TestBookingController::class, 'cekSlot']); + Route::post('/test-flow-simpan', [User\TestBookingController::class, 'store'])->name('test.simpan.foto'); }); -Route::prefix('admin')->name('admin.')->group(function () { + +/* +|-------------------------------------------------------------------------- +| 2. AUTENTIKASI (Login/Logout) +|-------------------------------------------------------------------------- +*/ +// Menampilkan form login +Route::get('/login', [Admin\AuthController::class, 'login'])->name('login')->middleware('guest'); +// Memproses data login (YANG SEBELUMNYA KURANG) +Route::post('/login', [Admin\AuthController::class, 'authenticate'])->name('login.proses'); +// Logout +Route::post('/logout', [Admin\AuthController::class, 'logout'])->name('logout'); + + +/* +|-------------------------------------------------------------------------- +| 3. ADMIN & OWNER PANEL +|-------------------------------------------------------------------------- +| +*/ +Route::prefix('admin')->name('admin.')->middleware(['auth'])->group(function () { Route::redirect('/', '/admin/beranda'); - Route::get('/beranda', [Admin\BerandaController::class, 'admin'])->name('beranda'); - Route::get('/beranda-pemilik', [Admin\BerandaController::class, 'pemilik'])->name('beranda.pemilik'); - Route::resource('pesanan-buket', Admin\PesananBuketController::class); - Route::resource('pesanan-foto', Admin\PesananFotoController::class); + // Dashboard + Route::get('/beranda', [Admin\BerandaController::class, 'index'])->name('beranda'); + + Route::get('/pesanan-buket', [Admin\PesananBuketController::class, 'index']) + ->name('pesanan-buket.index'); + + // Rute Update Status (Put) - Pastikan nama ini unik + Route::put('/pesanan-buket/update-status/{id}', [Admin\PesananBuketController::class, 'updateStatus']) + ->name('pesanan-buket.update-status'); + + Route::get('/pesanan-foto', [Admin\PesananFotoController::class, 'index']) + ->name('pesanan-foto.index'); + + // Rute Update Status (Put) - Pastikan nama ini unik + Route::put('/pesanan-foto/update-status/{id}', [Admin\PesananFotoController::class, 'updateStatus']) + ->name('pesanan-foto.update-status'); Route::get('/riwayat-pesanan', [Admin\HistoriPesananController::class, 'index'])->name('riwayat'); - Route::resource('produk-buket', App\Http\Controllers\Admin\BuketController::class); - Route::resource('paket-foto', App\Http\Controllers\Admin\FotoController::class); - - // --- 2. OWNER ONLY ROUTES (Khusus Pemilik) --- - // Kita bungkus dengan logic middleware sederhana atau Gate - // Route::group(['middleware' => function ($request, $next) { - // // Cek: Kalau bukan pemilik, lempar error 403 (Forbidden) - // if (auth()->user()->role !== 'pemilik') { - // abort(403, 'Akses Ditolak. Halaman ini khusus Pemilik.'); - // } - // return $next($request); - // }], function () { - - // // Menu ini hanya bisa dibuka Pemilik - // Route::resource('kelola-admin', Admin\ManajemenAdminController::class); - // }); + // Manajemen Produk (Master Data) + Route::resource('produk-buket', Admin\BuketController::class); // Perbaiki namespace jika perlu + Route::resource('paket-foto', Admin\FotoController::class); // Perbaiki namespace jika perlu + Route::resource('additional', Admin\AdditionalController::class)->except(['index', 'show']); + // Manajemen User (Khusus Owner) Route::resource('kelola-admin', Admin\ManajemenAdminController::class); + + // Profil Diri Route::resource('profil', Admin\ProfilController::class); + Route::put('/profil/update', [Admin\ProfilController::class, 'update'])->name('profil.simpan'); + + Route::put('/profil/password', [Admin\ProfilController::class, 'updatePassword'])->name('profil.password'); });