From 7d1f855392876fab0c75514551fe04cded62ce46 Mon Sep 17 00:00:00 2001 From: mirsydfchrynto Date: Thu, 7 Aug 2025 00:53:18 +0700 Subject: [PATCH] revisi-2 --- .../Admin/AdminBookingController.php | 48 +- .../BookingAvailabilityController.php | 50 + app/Http/Controllers/BookingController.php | 32 +- app/Models/Booking.php | 10 + ...025_08_01_174811_create_bookings_table.php | 2 + resources/views/admin/bookings/show.blade.php | 286 ++++-- .../components/layouts/app/sidebar.blade.php | 4 +- resources/views/info.blade.php | 12 + resources/views/kategori/baby.blade.php | 922 ++++++++++-------- resources/views/kategori/group.blade.php | 101 +- resources/views/kategori/prewed.blade.php | 239 +++-- routes/web.php | 3 + 12 files changed, 1077 insertions(+), 632 deletions(-) create mode 100644 app/Http/Controllers/BookingAvailabilityController.php diff --git a/app/Http/Controllers/Admin/AdminBookingController.php b/app/Http/Controllers/Admin/AdminBookingController.php index 321626b..cd8027f 100644 --- a/app/Http/Controllers/Admin/AdminBookingController.php +++ b/app/Http/Controllers/Admin/AdminBookingController.php @@ -11,7 +11,7 @@ class AdminBookingController extends Controller { /** - * Tampilkan daftar pesanan. + * Tampilkan daftar semua pesanan. */ public function index() { @@ -29,85 +29,103 @@ public function show(string $id) } /** - * Konfirmasi pembayaran DP dan arahkan ke WhatsApp. + * Konfirmasi DP: simpan bukti, ubah status ke 'booked', lalu arahkan ke WhatsApp. */ public function confirmDp(Request $request, $id) { $booking = Booking::findOrFail($id); + // Validasi input $request->validate([ 'dp_amount' => 'required|numeric|min:0', 'dp_proof' => 'required|image|max:2048', ]); + // Simpan bukti DP $path = $request->file('dp_proof')->store('bukti_dp', 'public'); + // Update data booking $booking->update([ 'dp_amount' => $request->dp_amount, 'dp_proof' => $path, 'status' => 'booked', ]); - // Pesan sukses + // Set pesan sukses session()->flash('success', 'DP berhasil dikonfirmasi. Silakan kirim pesan ke pelanggan.'); - // Pesan WhatsApp + // Buat pesan WhatsApp $message = "Halo kak {$booking->contact_name},\n\n" . "Terima kasih, DP kamu untuk sesi {$booking->session_name} pada tanggal " - . Carbon::parse($booking->booking_date)->format('d F Y') . " pukul {$booking->booking_time} telah kami terima.\n" - . "Pesananmu sudah dikonfirmasi. Sampai jumpa di hari H!"; + . Carbon::parse($booking->booking_date)->translatedFormat('d F Y') . " pukul {$booking->booking_time} telah kami terima.\n" + . "Pesananmu sudah dikonfirmasi ✅ Sampai jumpa di hari H!"; + // Format nomor WhatsApp (08xx → 628xx) $whatsappNumber = preg_replace('/[^0-9]/', '', $booking->whatsapp_number); + if (str_starts_with($whatsappNumber, '0')) { + $whatsappNumber = '62' . substr($whatsappNumber, 1); + } + + // ✅ URL BENAR: TANPA SPASI EKSTRA $url = 'https://wa.me/' . $whatsappNumber . '?text=' . urlencode($message); return redirect()->away($url); } /** - * Selesaikan pesanan (pelunasan) dan arahkan ke WhatsApp. + * Selesaikan pesanan: simpan bukti pelunasan, ubah status ke 'completed', lalu arahkan ke WhatsApp. */ public function completeBooking(Request $request, $id) { $booking = Booking::findOrFail($id); + // Validasi input $request->validate([ 'final_payment_amount' => 'required|numeric|min:0', 'final_payment_proof' => 'required|image|max:2048', ]); + // Simpan bukti pelunasan $path = $request->file('final_payment_proof')->store('bukti_pelunasan', 'public'); + // Update data booking $booking->update([ 'final_payment_amount' => $request->final_payment_amount, 'final_payment_proof' => $path, 'status' => 'completed', ]); - // Pesan sukses - session()->flash('success', 'Pelunasan berhasil dikonfirmasi. Silakan kirim konfirmasi ke pelanggan.'); + // Set pesan sukses + session()->flash('success', 'Pelunasan berhasil dikonfirmasi.'); - // Pesan WhatsApp + // Buat pesan WhatsApp $message = "Halo kak {$booking->contact_name},\n\n" . "Kami telah menerima pelunasan untuk sesi {$booking->session_name} pada tanggal " - . Carbon::parse($booking->booking_date)->format('d F Y') . ".\n" - . "Terima kasih telah mempercayakan layanan kami. See you next time!"; + . Carbon::parse($booking->booking_date)->translatedFormat('d F Y') . ".\n" + . "Terima kasih telah mempercayakan layanan kami. See you next time! ❤️"; + // Format nomor WhatsApp $whatsappNumber = preg_replace('/[^0-9]/', '', $booking->whatsapp_number); + if (str_starts_with($whatsappNumber, '0')) { + $whatsappNumber = '62' . substr($whatsappNumber, 1); + } + + // ✅ URL BENAR: TANPA SPASI EKSTRA $url = 'https://wa.me/' . $whatsappNumber . '?text=' . urlencode($message); return redirect()->away($url); } /** - * Hapus pesanan dan hapus file bukti pembayaran. + * Hapus pesanan dan file bukti pembayaran. */ public function destroy(Booking $booking) { // Hapus file bukti jika ada - if ($booking->dp_proof) { + if ($booking->dp_proof && Storage::disk('public')->exists($booking->dp_proof)) { Storage::disk('public')->delete($booking->dp_proof); } - if ($booking->final_payment_proof) { + if ($booking->final_payment_proof && Storage::disk('public')->exists($booking->final_payment_proof)) { Storage::disk('public')->delete($booking->final_payment_proof); } diff --git a/app/Http/Controllers/BookingAvailabilityController.php b/app/Http/Controllers/BookingAvailabilityController.php new file mode 100644 index 0000000..e6fea01 --- /dev/null +++ b/app/Http/Controllers/BookingAvailabilityController.php @@ -0,0 +1,50 @@ +validate([ + 'booking_date' => 'required|date', + ]); + + $date = $request->booking_date; + + // Daftar waktu yang tersedia (bisa Anda sesuaikan) + $allTimes = [ + '10:00', '11:00', '12:00', '13:00', + '14:00', '15:00', '16:00' + ]; + + // Ambil semua booking untuk tanggal tersebut + $bookedTimes = Booking::where('booking_date', $date) + ->pluck('booking_time') + ->toArray(); + + // Waktu yang tersedia = semua waktu - yang sudah booked + $availableTimes = array_values(array_diff($allTimes, $bookedTimes)); + + // Tentukan status hari: tersedia, sebagian, atau full + $status = 'available'; + if (empty($availableTimes)) { + $status = 'full'; + } elseif (count($availableTimes) < 3) { + $status = 'limited'; + } + + return response()->json([ + 'available_times' => $availableTimes, + 'booked_times' => $bookedTimes, + 'status' => $status, + 'date' => $date, + ]); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/BookingController.php b/app/Http/Controllers/BookingController.php index 4213cee..c72a977 100644 --- a/app/Http/Controllers/BookingController.php +++ b/app/Http/Controllers/BookingController.php @@ -1,48 +1,52 @@ validate([ + $request->validate([ 'contact_name' => 'required|string|max:255', 'whatsapp_number' => 'required|string|max:20', 'booking_date' => 'required|date|after_or_equal:today', - 'booking_time' => 'required|string', + 'booking_time' => 'required|string|in:10:00,11:00,12:00,13:00,14:00,15:00,16:00', 'session_name' => 'required|string|max:255', 'package_name' => 'required|string|max:255', 'selected_backgrounds' => 'nullable|array', 'selected_extra_items' => 'nullable|array', 'total_price' => 'required|integer|min:0', 'notes' => 'nullable|string', + 'baby_name' => 'nullable|string|max:255', // tambahkan + 'baby_age' => 'nullable|string|in:1-year,2-years,3-years,4-years,5-years,6-years', // tambahkan ]); - // 2. Buat pesanan baru di database - // Data yang disimpan adalah yang sudah divalidasi - try { - $booking = Booking::create($validatedData); + // 🔒 Cek apakah waktu sudah diambil + $exists = Booking::where('booking_date', $request->booking_date) + ->where('booking_time', $request->booking_time) + ->exists(); - // 3. Kirim notifikasi (opsional, bisa ke WhatsApp, email, dll) - // Di sini kita bisa menambahkan logika untuk notifikasi - // misalnya mengirim notifikasi ke admin + if ($exists) { + return response()->json([ + 'message' => 'Maaf, waktu yang Anda pilih sudah tidak tersedia. Silakan pilih waktu lain.', + ], 409); // 409 Conflict + } + + try { + $booking = Booking::create($request->all()); - // 4. Berikan respon sukses ke frontend return response()->json([ 'message' => 'Pesanan Anda berhasil disimpan!', 'booking_id' => $booking->id ], 201); - } catch (\Exception $e) { - // Tangani error jika terjadi return response()->json([ 'message' => 'Terjadi kesalahan saat menyimpan pesanan.', 'error' => $e->getMessage() diff --git a/app/Models/Booking.php b/app/Models/Booking.php index eb4cb56..9fa5cba 100644 --- a/app/Models/Booking.php +++ b/app/Models/Booking.php @@ -22,6 +22,8 @@ class Booking extends Model 'dp_proof', 'final_payment_amount', 'final_payment_proof', + 'baby_name', // tambahkan + 'baby_age', // tambahkan ]; @@ -30,4 +32,12 @@ class Booking extends Model 'selected_backgrounds' => 'array', 'selected_extra_items' => 'array', ]; + + + public static function getAvailableTimes($date) + { + $booked = self::where('booking_date', $date)->pluck('booking_time')->toArray(); + $all = ['10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00']; + return array_values(array_diff($all, $booked)); + } } diff --git a/database/migrations/2025_08_01_174811_create_bookings_table.php b/database/migrations/2025_08_01_174811_create_bookings_table.php index 9579d9d..769a807 100644 --- a/database/migrations/2025_08_01_174811_create_bookings_table.php +++ b/database/migrations/2025_08_01_174811_create_bookings_table.php @@ -24,6 +24,8 @@ public function up(): void $table->integer('total_price'); $table->text('notes')->nullable(); $table->enum('status', ['waiting', 'booked', 'completed', 'cancelled'])->default('waiting'); + $table->string('baby_name')->nullable(); + $table->string('baby_age')->nullable(); $table->timestamps(); }); } diff --git a/resources/views/admin/bookings/show.blade.php b/resources/views/admin/bookings/show.blade.php index f166ab8..c500b04 100644 --- a/resources/views/admin/bookings/show.blade.php +++ b/resources/views/admin/bookings/show.blade.php @@ -1,62 +1,103 @@
-
+

Detail Pesanan #{{ $booking->id }}

Kembali + class="inline-flex items-center gap-2 bg-gray-200 hover:bg-gray-300 text-gray-800 font-semibold py-2 px-4 rounded-lg transition"> + + + + Kembali +
- + @if (session('success')) -
+
{{ session('success') }}
@endif -
- -
- -
-

Informasi Pesanan

-
-

Nama: {{ $booking->contact_name }}

+
+ +
+ +
+

Informasi Pesanan

+
+

Nama Kontak: {{ $booking->contact_name }}

WhatsApp: {{ $booking->whatsapp_number }}

Tanggal: {{ \Carbon\Carbon::parse($booking->booking_date)->translatedFormat('d F Y') }}

Jam: {{ $booking->booking_time }}

-

Sesi: {{ $booking->session_name }}

+

Sesi: + @if($booking->session_name === 'baby-smash-cake') + Baby Smash Cake + @elseif($booking->session_name === 'pre-wedding') + Pre-Wedding + @elseif($booking->session_name === 'group-photography') + Group Photography + @else + {{ $booking->session_name }} + @endif +

+ + + @if($booking->session_name === 'baby-smash-cake') +

Nama Bayi: {{ $booking->baby_name ?? '-' }}

+

Usia Bayi: + @php + $ageLabels = [ + '1-year' => '1 Tahun', + '2-years' => '2 Tahun', + '3-years' => '3 Tahun', + '4-years' => '4 Tahun', + '5-years' => '5 Tahun', + '6-years' => '6 Tahun', + ]; + echo $ageLabels[$booking->baby_age] ?? $booking->baby_age ?? '-'; + @endphp +

+ @endif + + + @if($booking->session_name === 'group-photography') +

Jumlah Orang: {{ $booking->group_size ?? '-' }}

+ @endif +

Paket: {{ $booking->package_name }}

-

Total: Rp{{ number_format($booking->total_price, 0, ',', '.') }}

-

Catatan: {{ $booking->notes ?? '-' }}

+

Total: Rp{{ number_format($booking->total_price, 0, ',', '.') }}

+

Catatan: {{ $booking->notes ?? '—' }}

- -
-

Tambahan & Background

- @if ($booking->selected_backgrounds) -

Background:

-
    - @foreach ($booking->selected_backgrounds as $bg) + + +
    +

    Tambahan & Background

    + @if($booking->selected_backgrounds) +

    Background:

    +
      + @foreach($booking->selected_backgrounds as $bg)
    • {{ $bg['name'] }}
    • @endforeach
    @endif - @if ($booking->selected_extra_items) -

    Extra Item:

    -
      - @foreach ($booking->selected_extra_items as $extra) + + @if($booking->selected_extra_items) +

      Extra Item:

      +
        + @foreach($booking->selected_extra_items as $extra)
      • {{ $extra['name'] }} (Rp{{ number_format($extra['price'], 0, ',', '.') }})
      • @endforeach
      @else -

      Tidak ada extra item.

      +

      Tidak ada extra item.

      @endif
- +
@@ -72,113 +113,160 @@ class="inline-flex items-center gap-2 bg-gray-600 hover:bg-gray-700 text-white f

Klik untuk memperbarui status terbaru

- -
-

Status Pesanan

+ +
+

Status Pesanan

@php - $badge = match ($booking->status) { - 'waiting' => 'bg-yellow-200 text-yellow-800', - 'booked' => 'bg-green-200 text-green-800', - 'completed' => 'bg-blue-200 text-blue-800', - default => 'bg-gray-200 text-gray-800' + $badgeColor = match ($booking->status) { + 'waiting' => 'bg-yellow-100 text-yellow-800 border-yellow-200', + 'booked' => 'bg-green-100 text-green-800 border-green-200', + 'completed' => 'bg-blue-100 text-blue-800 border-blue-200', + default => 'bg-gray-100 text-gray-800 border-gray-200' }; @endphp - + {{ ucfirst($booking->status === 'waiting' ? 'Menunggu DP' : ($booking->status === 'booked' ? 'Sudah Dibooking' : 'Selesai')) }}
- - @if ($booking->status === 'waiting') + + @if($booking->status === 'waiting') @php $dpAmount = number_format($booking->total_price / 2, 0, ',', '.'); - $message = "Halo kak {$booking->contact_name}, pesananmu untuk tanggal {$booking->booking_date->format('d M Y')} jam {$booking->booking_time} telah kami terima. Mohon transfer DP Rp{$dpAmount} untuk mengamankan jadwal. Balas dengan bukti transfer ya. Terima kasih."; - $whatsappLink = "https://wa.me/" . preg_replace('/[^0-9]/', '', $booking->whatsapp_number) . "?text=" . urlencode($message); + $message = "Halo kak {$booking->contact_name},\n\n" + . "Terima kasih, pesanan untuk sesi {$booking->session_name} pada tanggal " + . \Carbon\Carbon::parse($booking->booking_date)->translatedFormat('d F Y') . " pukul {$booking->booking_time} telah kami terima.\n" + . "Mohon transfer DP Rp{$dpAmount} untuk mengamankan jadwal.\n" + . "Balas dengan bukti transfer ya. Terima kasih!"; + $whatsappNumber = preg_replace('/[^0-9]/', '', $booking->whatsapp_number); + $url = 'https://wa.me/' . $whatsappNumber . '?text=' . urlencode($message); @endphp - + + + + + Kirim Konfirmasi via WhatsApp + @endif - - @if ($booking->status === 'waiting') -
-

Konfirmasi DP

-
+ + @if($booking->status === 'waiting') +
+

Konfirmasi DP

+ @csrf -
- - +
+
+ + +
+
+ + +
+
-
- - -
-
@endif - - @if ($booking->status === 'booked') -
-

DP Telah Diterima

-

Nominal: Rp{{ number_format($booking->dp_amount, 0, ',', '.') }}

-

Bukti Transfer:

- + + @if($booking->status === 'booked') +
+

DP Diterima

+

Nominal: Rp{{ number_format($booking->dp_amount, 0, ',', '.') }}

+

Bukti Transfer:

+ Bukti DP
@endif - - @if ($booking->status === 'booked') -
-

Pelunasan

-
+ + @if($booking->status === 'booked') +
+

Pelunasan

+ @csrf -
- - -
-
- - +
+
+ + +
+
+ + +
+
-
@endif - - @if ($booking->status === 'completed') -
-

Laporan Pembayaran

-

Nominal DP: Rp{{ number_format($booking->dp_amount, 0, ',', '.') }}

-

Nominal Pelunasan: Rp{{ number_format($booking->final_payment_amount, 0, ',', '.') }}

-
-

Bukti DP:

- -

Bukti Pelunasan:

- + + @if($booking->status === 'completed') +
+

Laporan Pembayaran

+
+

DP: Rp{{ number_format($booking->dp_amount, 0, ',', '.') }}

+

Pelunasan: Rp{{ number_format($booking->final_payment_amount, 0, ',', '.') }}

+
+
+
+

Bukti DP

+ Bukti DP +
+
+

Bukti Pelunasan

+ Bukti Pelunasan +
@endif - -
-
+ +
+ @csrf @method('DELETE') - +
+ + + \ No newline at end of file diff --git a/resources/views/components/layouts/app/sidebar.blade.php b/resources/views/components/layouts/app/sidebar.blade.php index 2963782..bcc69f1 100644 --- a/resources/views/components/layouts/app/sidebar.blade.php +++ b/resources/views/components/layouts/app/sidebar.blade.php @@ -44,7 +44,7 @@ - + {{-- {{ __('Repository') }} @@ -54,7 +54,7 @@ target="_blank"> {{ __('Documentation') }} - + --}}
+
+
+ + + +
+
+
Instagram
+
@babypeacepicture
+
+
+
diff --git a/resources/views/kategori/baby.blade.php b/resources/views/kategori/baby.blade.php index f2a02ff..c87bc99 100644 --- a/resources/views/kategori/baby.blade.php +++ b/resources/views/kategori/baby.blade.php @@ -65,6 +65,7 @@ z-index: 1; } + /* Content Wrapper - Clean */ .content-wrapper { position: relative; @@ -371,9 +372,7 @@ } /* Firefox fallback - hilangkan tampilan default */ - @supports - (-moz - appearance) - { + @supports (-moz - appearance) { .form-input[type="date"] { -moz-appearance: none; appearance: none; @@ -1164,6 +1163,87 @@ transition-duration: 0.01ms !important; } } + + /* ======================== + NOTIFIKASI KETERSEDIAAN WAKTU - PREMIUM (TEKS PUTIH) + ======================== */ + .availability-notice { + @apply relative overflow-hidden rounded-xl border px-5 py-4 text-sm font-medium shadow-sm transition-all duration-300; + @apply backdrop-blur-lg; + background: linear-gradient(135deg, rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0.06)); + border: 1px solid rgba(255, 255, 255, 0.2); + box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4); + transform: translateY(10px); + opacity: 0; + visibility: hidden; + } + + .availability-notice.show { + transform: translateY(0); + opacity: 1; + visibility: visible; + animation: fadeInUp 0.4s ease-out; + } + + .availability-notice::before { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient(135deg, rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.02)); + pointer-events: none; + z-index: 0; + } + + .availability-notice span { + position: relative; + z-index: 1; + display: block; + text-align: center; + line-height: 1.5; + color: white; + /* ✅ Teks PUTIH */ + font-weight: 500; + text-shadow: 0 1px 6px rgba(0, 0, 0, 0.8); + /* Bayangan agar lebih tajam */ + } + + /* Status: Tersedia */ + .availability-notice.available { + @apply border-blue-300/50; + background: linear-gradient(135deg, rgba(59, 130, 246, 0.25), rgba(37, 99, 235, 0.15)); + } + + /* Status: Terbatas (Limited) */ + .availability-notice.limited { + @apply border-yellow-300/50; + background: linear-gradient(135deg, rgba(234, 179, 8, 0.25), rgba(202, 138, 4, 0.15)); + } + + /* Status: Penuh (Full) */ + .availability-notice.full { + @apply border-red-300/50; + background: linear-gradient(135deg, rgba(239, 68, 68, 0.25), rgba(185, 28, 28, 0.15)); + } + + /* Animasi Masuk */ + @keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(30px); + } + + to { + opacity: 1; + transform: translateY(0); + } + } + + /* Responsif */ + @media (max-width: 640px) { + .availability-notice { + @apply px-4 py-3 text-xs; + } + } @endpush @@ -1254,40 +1334,41 @@
- + + @for ($age = 1; $age <= 6; $age++) + + @endfor
+
-
+
- +
+ + + +
+ +
@@ -1458,451 +1539,464 @@ class="extra-price">Rp{{ number_format($item['price']) }}{{ $item['unit'] ?? '' @endsection @push('scripts') @endpush \ No newline at end of file diff --git a/resources/views/kategori/group.blade.php b/resources/views/kategori/group.blade.php index 62dba82..738a11b 100644 --- a/resources/views/kategori/group.blade.php +++ b/resources/views/kategori/group.blade.php @@ -1690,28 +1690,31 @@
+
-
+
- + -
+ + +
+ +
{{-- Dynamic Background Selection --}} @@ -1900,6 +1903,80 @@ class="extra-price">Rp{{ number_format($item['price']) }}{{ $item['unit'] ?? '' @push('scripts') @endpush \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index 5c39dab..3148269 100644 --- a/routes/web.php +++ b/routes/web.php @@ -7,6 +7,7 @@ use App\Http\Controllers\Admin\AdminBookingController; use App\Http\Controllers\Admin\BackgroundController; use App\Http\Controllers\Admin\ExtraItemsController; +use App\Http\Controllers\BookingAvailabilityController; use App\Models\Background; use App\Models\ExtraItem; use App\Models\TermsAndCondition; @@ -75,5 +76,7 @@ Volt::route('settings/appearance', 'settings.appearance')->name('settings.appearance'); }); +Route::get('/api/available-times', [BookingAvailabilityController::class, 'getAvailableTimes'])->name('api.available.times'); + // Auth Routes (Login, Logout, Register) — note: register dapat dimatikan di file auth.php require __DIR__ . '/auth.php';