diff --git a/app/Http/Controllers/Admin/HistoriPesananController.php b/app/Http/Controllers/Admin/HistoriPesananController.php index 53ea3c0..bfae0c5 100755 --- a/app/Http/Controllers/Admin/HistoriPesananController.php +++ b/app/Http/Controllers/Admin/HistoriPesananController.php @@ -11,17 +11,49 @@ class HistoriPesananController extends Controller { public function index() { - $riwayatBuket = TransaksiBuket::with(['pelanggan', 'buket']) - ->where('status_transaksi', '!=', 'menunggu_verifikasi') - ->latest() - ->get(); + $riwayatBuket = TransaksiBuket::whereIn('status_transaksi', ['selesai', 'ditolak']) + ->latest()->get(); - // Ambil riwayat foto (selain status menunggu) - $riwayatFoto = BookingFoto::with(['pelanggan', 'paketFoto']) - ->where('status_booking', '!=', 'menunggu_verifikasi') - ->latest() - ->get(); + $riwayatFoto = BookingFoto::whereIn('status_booking', ['selesai', 'ditolak']) + ->latest()->get(); return view('admin.pesanan.riwayat', compact('riwayatBuket', 'riwayatFoto')); } + public function updateStatus(Request $request, $id) + { + // Cek Kategori: Apakah ini Buket atau Foto? + $kategori = $request->kategori; // 'buket' atau 'foto' + + $transaksi = null; + $noInvoice = ""; + + // LOGIKA PEMILIHAN TABEL + if ($kategori == 'buket') { + // --- CASE BUKET --- + $transaksi = \App\Models\TransaksiBuket::findOrFail($id); + + if ($request->jenis == 'selesai') { + $transaksi->status_transaksi = 'selesai'; // Nama kolom: status_transaksi + $noInvoice = $transaksi->no_invoice; + } + } elseif ($kategori == 'foto') { + // --- CASE FOTO --- + $transaksi = \App\Models\BookingFoto::findOrFail($id); + + if ($request->jenis == 'selesai') { + $transaksi->status_booking = 'selesai'; // Nama kolom: status_booking + $noInvoice = $transaksi->no_invoice; + } + } + + // SIMPAN PERUBAHAN + if ($transaksi) { + $transaksi->save(); + session()->flash('success', "Pesanan {$noInvoice} berhasil diselesaikan!"); + + return response()->json(['success' => true]); + } + + return response()->json(['success' => false, 'message' => 'Data tidak ditemukan'], 404); + } } diff --git a/app/Http/Controllers/Admin/PesananBuketController.php b/app/Http/Controllers/Admin/PesananBuketController.php index 28c5a66..be6ed10 100755 --- a/app/Http/Controllers/Admin/PesananBuketController.php +++ b/app/Http/Controllers/Admin/PesananBuketController.php @@ -10,9 +10,8 @@ class PesananBuketController extends Controller { public function index() { - $pesanan = TransaksiBuket::with(['pelanggan']) - ->where('status_transaksi', 'menunggu_verifikasi') - ->latest() + $pesanan = TransaksiBuket::whereIn('status_transaksi', ['menunggu_verifikasi', 'diterima']) + ->orderBy('created_at', 'ASC') ->get(); return view('admin.pesanan.buket', compact('pesanan')); @@ -27,10 +26,13 @@ public function updateStatus(Request $request, $id) // 2. Tentukan status & session flash sekaligus agar tidak dobel if ($request->jenis === 'terima') { $status = 'diterima'; - session()->flash('success', "Pesanan #{$pesanan->no_invoice} telah diterima!"); // Alert Hijau + session()->flash('success', "Pesanan {$pesanan->no_invoice} telah diterima!"); // Alert Hijau + } elseif ($request->jenis === 'selesai') { + $status = 'selesai'; + session()->flash('success', "Pesanan {$pesanan->no_invoice} berhasil diselesaikan!"); } else { $status = 'ditolak'; - session()->flash('error', "Pesanan #{$pesanan->no_invoice} telah ditolak!"); // Alert Merah + session()->flash('error', "Pesanan {$pesanan->no_invoice} telah ditolak!"); // Alert Merah } // 3. Update database @@ -51,7 +53,7 @@ public function updateStatus(Request $request, $id) // 5. Susun Pesan berdasarkan kondisi if ($status === 'diterima') { $msg = "Halo Kak *{$nama}*,\n\n" . - "Pesanan Anda dengan Nomor Invoice: *#{$invoice}* telah kami *TERIMA* dan masuk dalam daftar proses pengerjaan.\n\n" . + "Pesanan Anda dengan Nomor Invoice: *{$invoice}* telah kami *TERIMA* dan masuk dalam daftar proses pengerjaan.\n\n" . "*Rincian Pesanan:*\n" . "- *Produk:* {$produk}\n" . "- *Total Bayar:* Rp {$total}\n" . @@ -61,7 +63,7 @@ public function updateStatus(Request $request, $id) "Mohon simpan rincian ini dan ditunggu info selanjutnya ya Kak. Terima kasih! ✨"; } else { $msg = "Halo Kak *{$nama}*,\n\n" . - "Mengenai pesanan Anda dengan Nomor Invoice: *#{$invoice}* terpaksa kami *TOLAK* dikarenakan:\n\n" . + "Mengenai pesanan Anda dengan Nomor Invoice: *{$invoice}* terpaksa kami *TOLAK* dikarenakan:\n\n" . "*[TULIS ALASAN DI SINI]*\n\n" . "*Rincian Pesanan:*\n" . "- *Produk:* {$produk}\n" . diff --git a/app/Http/Controllers/Admin/PesananFotoController.php b/app/Http/Controllers/Admin/PesananFotoController.php index a4d6bb7..2c4be67 100755 --- a/app/Http/Controllers/Admin/PesananFotoController.php +++ b/app/Http/Controllers/Admin/PesananFotoController.php @@ -11,11 +11,11 @@ class PesananFotoController extends Controller public function index() { $pesanan = BookingFoto::with([ - 'pelanggan', // Untuk ambil Nama & No HP - 'paketFoto', // Untuk ambil Nama Paket (misal: Paket Wisuda) - 'detailAdditional.additional' // Lanjut ambil Nama Additional (misal: Background, Orang Tambahan) + 'pelanggan', + 'paketFoto', + 'detailAdditional.additional' ]) - ->where('status_booking', 'menunggu_verifikasi') + ->whereIn('status_booking', ['menunggu_verifikasi', 'diterima']) ->latest() ->get(); @@ -31,10 +31,13 @@ public function updateStatus(Request $request, $id) // 2. Tentukan status & session flash if ($request->jenis === 'terima') { $status = 'diterima'; - session()->flash('success', "Booking #{$pesanan->no_invoice} telah diterima!"); + session()->flash('success', "Booking {$pesanan->no_invoice} telah diterima!"); + } elseif ($request->jenis === 'selesai') { + $status = 'selesai'; + session()->flash('success', "Pesanan {$pesanan->no_invoice} berhasil diselesaikan!"); } else { $status = 'ditolak'; - session()->flash('error', "Booking #{$pesanan->no_invoice} telah ditolak!"); + session()->flash('error', "Booking {$pesanan->no_invoice} telah ditolak!"); } // 3. Update database (Pastikan nama kolom status_booking sesuai migrasimu) @@ -60,16 +63,16 @@ public function updateStatus(Request $request, $id) $list_additional .= "- " . $item->additional->nama . " (x" . $item->qty . ")\n"; } } else { - $list_additional = "- Tidak ada tambahan\n"; + $list_additional = "- Tidak ada additional\n"; } // 6. Susun Pesan WA if ($status === 'diterima') { $msg = "Halo Kak *{$nama}* ,\n\n" . - "Booking foto Anda dengan Invoice: *#{$invoice}* telah kami *TERIMA*. \n\n" . + "Booking foto Anda dengan Invoice: *{$invoice}* telah kami *TERIMA*. \n\n" . "*Rincian Booking:*\n" . "- *Paket:* {$paket}\n" . - "*Tambahan:*\n{$list_additional}" . + "*Additional:*\n{$list_additional}" . "- *Total Bayar:* Rp {$total}\n\n" . "*Jadwal Sesi Foto:*\n" . " Tanggal: {$tanggal}\n" . @@ -77,13 +80,15 @@ public function updateStatus(Request $request, $id) "Mohon datang 15 menit sebelum jadwal dimulai ya Kak. Sampai jumpa di studio! "; } else { $msg = "Halo Kak *{$nama}*,\n\n" . - "Mohon maaf, booking foto Anda dengan Invoice *#{$invoice}* terpaksa kami *TOLAK* dikarenakan:\n\n" . + "Mohon maaf, booking foto Anda dengan Invoice *{$invoice}* terpaksa kami *TOLAK* dikarenakan:\n\n" . "*[TULIS ALASAN DI SINI]*\n\n" . "*Rincian Booking:*\n" . "- *Paket:* {$paket}\n" . - "*Tambahan:*\n{$list_additional}" . + "*Additional:*\n{$list_additional}" . "- *Total Bayar:* Rp {$total}\n" . - "- *Jadwal Sesi:* {$tanggal} ({$jam_mulai} - {$jam_selesai} WIB)\n\n" . + "*Jadwal Sesi Foto:*\n" . + " Tanggal: {$tanggal}\n" . + " Jam: {$jam_mulai} - {$jam_selesai} WIB\n\n" . "Admin kami akan segera menghubungi Kakak untuk info pengembalian dana atau penjadwalan ulang. Terima kasih. "; } diff --git a/app/Http/Controllers/User/BookingFotoController.php b/app/Http/Controllers/User/BookingFotoController.php index 3f10a5b..1365543 100755 --- a/app/Http/Controllers/User/BookingFotoController.php +++ b/app/Http/Controllers/User/BookingFotoController.php @@ -11,6 +11,9 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; use Illuminate\Support\Str; +use Illuminate\Support\Facades\Storage; +use Illuminate\Support\Facades\Validator; + class BookingFotoController extends Controller { @@ -40,9 +43,6 @@ public function detail($id) public function loadCalendar(Request $request) { \Carbon\Carbon::setLocale('id'); - // Ambil bulan & tahun dari request AJAX, atau default sekarang - // $month = $request->month ?? date('m'); - // $year = $request->year ?? date('Y'); $month = $request->month ?? date('m'); $year = $request->year ?? date('Y'); $start = \Carbon\Carbon::createFromDate($year, $month, 1); @@ -50,8 +50,7 @@ public function loadCalendar(Request $request) // Data Navigasi $prevMonth = $start->copy()->subMonth(); $nextMonth = $start->copy()->addMonth(); - // translatedFormat akan mengikuti locale 'id' di config Anda - $currentMonthLabel = $start->isoFormat('MMMM YYYY'); // Return hanya potongan HTML (Partial), bukan halaman full + $currentMonthLabel = $start->isoFormat('MMMM YYYY'); $html = view('user.components.calendar-grid', compact( 'start', 'prevMonth', @@ -64,8 +63,7 @@ public function loadCalendar(Request $request) } 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']); @@ -149,8 +147,7 @@ public function cancelBooking() } public function store(Request $request) { - // 1. Validasi Input menggunakan Format Validator - $validator = \Illuminate\Support\Facades\Validator::make($request->all(), [ + $validator = Validator::make($request->all(), [ 'id_paket' => 'required|exists:paket_fotos,id_paket', 'tgl_booking' => 'required|date|after_or_equal:today', 'jam_mulai' => 'required', @@ -171,28 +168,42 @@ public function store(Request $request) 'mimes' => 'Format :attribute harus jpeg, png, atau jpg.', 'max.file' => 'Ukuran :attribute maksimal adalah 2MB.', ], [ - // Alias Atribut agar lebih ramah - 'id_paket' => 'paket foto', 'nama' => 'nama pemesan', 'no_wa' => 'nomor WhatsApp', - 'tgl_booking' => 'tanggal booking', - 'jam_mulai' => 'jam mulai', 'bukti_bayar' => 'bukti pembayaran', ]); - if ($validator->fails()) { - return back()->withErrors($validator)->withInput(); - } - - \Illuminate\Support\Facades\DB::beginTransaction(); // Mulai Transaksi Database + DB::beginTransaction(); // Mulai Transaksi Database try { - // 2. Ambil Data Paket & Hitung Waktu (Termasuk Tambahan Menit dari Addons) - $paket = \App\Models\PaketFoto::findOrFail($request->id_paket); - $totalDurasi = $paket->durasi; + // 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] + ); + // 6. Hitung Grand Total (Paket + Additional) + // Kita hitung ulang di server agar aman dari manipulasi inspect element $grandTotal = $paket->harga; $listAdditional = []; - + $totalDurasi = $durasiMenit; if ($request->has('addons')) { foreach ($request->addons as $idAddon => $qty) { if ($qty > 0) { @@ -222,26 +233,25 @@ public function store(Request $request) // 3. Cek Slot Sekali Lagi (Mencegah Race Condition) $isTaken = \App\Models\BookingFoto::where('tgl_booking', $request->tgl_booking) ->where('jam_mulai', $request->jam_mulai) - ->whereIn('status_booking', ['menunggu_verifikasi', 'diterima', 'selesai']) + ->whereIn('status_booking', ['menunggu_verifikasi', 'diterima']) ->exists(); if ($isTaken) { return back()->with('error', 'Mohon maaf, slot waktu ini baru saja diambil orang lain.'); } - // 4. Simpan/Update Data Pelanggan - $pelanggan = \App\Models\Pelanggan::firstOrCreate( - ['no_wa' => $request->no_wa], - ['nama' => $request->nama] - ); + // 4. Simpan Data Pelanggan + $pelanggan = \App\Models\Pelanggan::create([ + 'nama' => $request->nama, + 'no_wa' => $request->no_wa + ]); // 5. Upload Bukti Bayar $pathBukti = null; if ($request->hasFile('bukti_bayar')) { $file = $request->file('bukti_bayar'); - $namaFile = 'bukti_' . time() . $file->getClientOriginalExtension(); - $file->move(public_path('img/payment'), $namaFile); - $pathBukti = 'img/payment/foto' . $namaFile; + $namaFile = 'bukti_' . time() . '.' . $file->getClientOriginalExtension(); + $pathBukti = $file->storeAs('img/payment/foto', $namaFile, 'public'); } // 6. Simpan Booking Utama @@ -278,19 +288,19 @@ public function store(Request $request) $txtAddons .= "\n"; // Kasih jarak baris } // 8. Redirect ke WhatsApp - $pesan = "Halo Admin Flo.do! Saya sudah melakukan pembayaran untuk invoice {$booking->no_invoice}:" . + $pesan = "Halo Admin Flo.do! Saya sudah melakukan pembayaran untuk invoice {$booking->no_invoice}:\n\n" . "*Data Pemesan:*\n" . - "Nama: {$pelanggan->nama}\n" . - "WA: {$pelanggan->no_wa}\n\n" . + "Nama: {$request->nama}\n" . + "WA: {$request->no_wa}\n\n" . "*Detail Booking:*\n" . - "Nama Paket: {$request->nama}\n" . + "Nama Paket: {$paket->nama}\n" . $txtAddons . "Tanggal: " . \Carbon\Carbon::parse($request->tgl_booking)->translatedFormat('l, d F Y') . "\n" . "Jam: {$request->jam_mulai} - {$jamSelesai->format('H:i')} WIB\n" . - "Total: Rp " . number_format($grandTotal, 0, ',', '.') . "\n" . + "Total: Rp " . number_format($grandTotal, 0, ',', '.') . "\n\n" . "Mohon segera diproses, ya! Terima kasih."; - $urlWA = "https://wa.me/6289673668516?text=" . urlencode($pesan); + $urlWA = "https://wa.me/6282337687878?text=" . urlencode($pesan); session()->forget('payment_deadline'); return redirect()->route('booking.foto')->with([ diff --git a/app/Http/Controllers/User/PesanBuketController.php b/app/Http/Controllers/User/PesanBuketController.php index 02d9069..f7243bf 100755 --- a/app/Http/Controllers/User/PesanBuketController.php +++ b/app/Http/Controllers/User/PesanBuketController.php @@ -114,22 +114,20 @@ public function store(Request $request) $namaFile = null; if ($request->hasFile('bukti_bayar')) { $file = $request->file('bukti_bayar'); - // Membuat nama file unik berdasarkan waktu agar tidak tertimpa - $namaFile = 'bukti_' . time() . $file->getClientOriginalExtension(); - // Pindahkan ke folder public/img/payment - $file->move(public_path('img/payment/buket'), $namaFile); + $namaFile = 'bukti_' . time() . '.' . $file->getClientOriginalExtension(); + $pathBukti = $file->storeAs('img/payment/buket', $namaFile, 'public'); } $transaksi = TransaksiBuket::create([ 'id_pelanggan' => $pelanggan->id_pelanggan, 'id_buket' => $request->id_buket, 'tgl_ambil' => $request->tgl_ambil . ' ' . $request->waktu_ambil, - 'request' => $request->request_khusus, // Ubah dari request_khusus ke request + 'request' => $request->request_khusus, 'ucapan' => $request->ucapan, - 'bukti_bayar' => 'img/payment/' . $namaFile, - 'status_transaksi' => 'menunggu_verifikasi', // Ubah dari status ke status_transaksi - 'total_bayar' => $buket->harga, // Tambahkan ini karena total_bayar wajib di fillable - 'no_invoice' => 'INV-BUKET-' . strtoupper(\Illuminate\Support\Str::random(6)), // Tambahkan invoice sederhana + 'bukti_bayar' => $pathBukti, + 'status_transaksi' => 'menunggu_verifikasi', + 'total_bayar' => $buket->harga, + 'no_invoice' => 'INV-BUKET-' . strtoupper(\Illuminate\Support\Str::random(6)), ]); DB::commit(); @@ -144,7 +142,7 @@ public function store(Request $request) "Total: Rp " . number_format($transaksi->buket->harga, 0, ',', '.') . "\n\n" . "Mohon segera diproses, ya! Terima kasih."; - $urlWA = "https://wa.me/6289673668516?text=" . urlencode($pesan); + $urlWA = "https://wa.me/6282337687878?text=" . urlencode($pesan); return redirect()->route('pesan.buket')->with([ 'success' => 'Pesanan Berhasil Dibuat!', diff --git a/public/css/app.css b/public/css/app.css index b3294ee..8d99823 100755 --- a/public/css/app.css +++ b/public/css/app.css @@ -7233,6 +7233,22 @@ .login-logo { margin-right: auto; } +/* Sembunyikan mata bawaan browser (Edge/IE) */ +input[type="password"]::-ms-reveal, +input[type="password"]::-ms-clear { + display: none; +} + +/* Sembunyikan mata bawaan browser (Chrome/Opera/Safari) - jarang muncul tapi buat jaga-jaga */ +input[type="password"]::-webkit-contacts-auto-fill-button, +input[type="password"]::-webkit-credentials-auto-fill-button { + visibility: hidden; + display: none !important; + pointer-events: none; + position: absolute; + right: 0; +} + .offcanvas, .offcanvas-xxl, .offcanvas-xl, diff --git a/resources/views/admin/beranda/index.blade.php b/resources/views/admin/beranda/index.blade.php index 9e1b571..93eca82 100755 --- a/resources/views/admin/beranda/index.blade.php +++ b/resources/views/admin/beranda/index.blade.php @@ -285,7 +285,7 @@ class="btn icon btn-primary btn-action" data-bs-toggle="modal" @include('admin.pesanan.partials.modal-buket') @empty - Tidak ada pesanan buket yang + Tidak ada pesanan buket yang pending. @@ -338,7 +338,7 @@ class="btn icon btn-primary btn-action" data-bs-toggle="modal" @include('admin.pesanan.partials.modal-foto') @empty - Tidak ada pesanan + Tidak ada pesanan foto yang pending. @endforelse diff --git a/resources/views/admin/kelola-admin/index.blade.php b/resources/views/admin/kelola-admin/index.blade.php index a66f840..629d057 100755 --- a/resources/views/admin/kelola-admin/index.blade.php +++ b/resources/views/admin/kelola-admin/index.blade.php @@ -74,7 +74,7 @@ class="badge rounded-pill px-3 py-2 @include('admin.kelola-admin.partials.modal-delete') @empty - Belum ada data admin. + Belum ada data admin. @endforelse diff --git a/resources/views/admin/paket-foto/index.blade.php b/resources/views/admin/paket-foto/index.blade.php index f6344a4..e7fdb7e 100755 --- a/resources/views/admin/paket-foto/index.blade.php +++ b/resources/views/admin/paket-foto/index.blade.php @@ -75,7 +75,7 @@ Rp {{ number_format($f->harga, 0, ',', '.') }} - Foto Produk @@ -100,7 +100,7 @@ @include('admin.paket-foto.partials.modal-delete-foto') @empty - Belum ada data paket foto. + Belum ada data paket foto. @endforelse diff --git a/resources/views/admin/paket-foto/partials/modal-edit-foto.blade.php b/resources/views/admin/paket-foto/partials/modal-edit-foto.blade.php index 760118a..803d5c1 100755 --- a/resources/views/admin/paket-foto/partials/modal-edit-foto.blade.php +++ b/resources/views/admin/paket-foto/partials/modal-edit-foto.blade.php @@ -100,8 +100,8 @@ class="text-center text-muted d-none"> sini

- diff --git a/resources/views/admin/paket-foto/partials/modal-show-foto.blade.php b/resources/views/admin/paket-foto/partials/modal-show-foto.blade.php index 1b08041..fbb3579 100755 --- a/resources/views/admin/paket-foto/partials/modal-show-foto.blade.php +++ b/resources/views/admin/paket-foto/partials/modal-show-foto.blade.php @@ -12,8 +12,8 @@
@if ($f->foto) {{-- Langsung img tanpa wrapper --}} - + @else {{-- Div pengganti kalau tidak ada foto --}}