From 652bd8cc454a5507f5341dc244496bbb29741ba2 Mon Sep 17 00:00:00 2001 From: JokoPrasetio Date: Mon, 21 Jul 2025 01:45:59 +0700 Subject: [PATCH] on progress --- app/Http/Controllers/CustomerController.php | 102 +++--- public/asset_guests/css/main.css | 29 +- .../js/order_guest/{_init.js => functions.js} | 11 +- public/js/order_guest/index.js | 335 ++++++++++++++++-- public/js/order_guest/register.js | 24 ++ .../views/guest/checkout_order.blade.php | 43 +++ resources/views/guest/index.blade.php | 30 +- resources/views/guest/keranjang.blade.php | 22 ++ .../guest/layout/partials/header.blade.php | 7 +- resources/views/guest/register.blade.php | 67 ++++ routes/web.php | 2 - 11 files changed, 582 insertions(+), 90 deletions(-) rename public/js/order_guest/{_init.js => functions.js} (86%) create mode 100644 public/js/order_guest/register.js create mode 100644 resources/views/guest/keranjang.blade.php diff --git a/app/Http/Controllers/CustomerController.php b/app/Http/Controllers/CustomerController.php index 2afd6d7..d53a1e0 100644 --- a/app/Http/Controllers/CustomerController.php +++ b/app/Http/Controllers/CustomerController.php @@ -18,7 +18,7 @@ class CustomerController extends Controller public function dataOrder(){ $search = request('search'); $jenis_menu = request('jenis_menu'); - $perPage = request()->get('perPage', 1); + $perPage = request()->get('per_page', 6); if($jenis_menu === "paket"){ return self::dataPaketMenuOrder($search, $perPage); } @@ -102,53 +102,65 @@ class CustomerController extends Controller - private static function dataPaketMenuOrder($search = null){ - $query = DB::connection('dbOrderGizi')->table('public.master_paket_menu as mpn') - ->leftJoin('public.master_paket_menu_detail as mpd', 'mpd.master_paket_menu_id', '=', 'mpn.master_paket_menu_id') - ->leftJoin('public.master_menu as mn', 'mpd.master_menu_id', '=', 'mn.master_menu_id') - ->leftJoin('public.klasifikasi_menu_diet as kmd', 'kmd.master_paket_menu_id', '=', 'mpn.master_paket_menu_id') - ->leftJoin('public.kategori_diet as kd', 'kd.kategori_diet_id', '=', 'kmd.kategori_diet_id') - ->select('mpn.*', 'mpd.master_paket_menu_detail_id', 'mn.master_menu_id', 'kmd.klasifikasi_menu_diet', 'kd.*') - ->where('mpn.statusenabled', true); + private static function dataPaketMenuOrder($search = null, $perPage){ + $query = DB::connection('dbOrderGizi')->table('public.master_paket_menu as mpn')->where('mpn.statusenabled', true); + + if(!empty($search)){ + $query->where('mpn.nama_paket', 'ILIKE', '%' . $search . '%'); + } - if(!empty($search)){ - $query->where(function($q) use($search){ - $q->where('mpn.nama_paket', 'ILIKE', '%' . $search . '%') - ->orWhere('kd.nama_kategori_diet', 'ILIKE', '%'. $search . '%'); - }); - } + $paginated = $query->select( + 'mpn.master_paket_menu_id', + 'mpn.nama_paket', + 'mpn.foto', + 'mpn.harga_public', + 'mpn.harga_karyawan', + 'mpn.harga_keluarga_pasien', + 'mpn.deskripsi', + 'mpn.status' + )->paginate($perPage); + + $paketMenuIds = collect($paginated->items())->pluck('master_paket_menu_id')->toArray(); + + $klasifikasi = DB::connection('dbOrderGizi') + ->table('public.klasifikasi_menu_diet as kmd') + ->join('public.kategori_diet as kd', 'kd.kategori_diet_id', '=', 'kmd.kategori_diet_id') + ->whereIn('kmd.master_paket_menu_id', $paketMenuIds) + ->select('kmd.master_paket_menu_id', 'kd.kategori_diet_id', 'kd.nama_kategori_diet') + ->get() + ->groupBy('master_paket_menu_id'); - $paketMenu = $query->get(); - - - $grouped = $paketMenu->groupBy('master_paket_menu_id')->map(function($items){ - $first = $items->first(); - $klasifikasiMenu = $items->filter(fn($d) => $d->kategori_diet_id !== null) - ->unique('kategori_diet_id') - ->map(function($items) { - return [ - 'kategori_diet_id' => $items->kategori_diet_id, - 'nama_kategori_diet'=> $items->nama_kategori_diet - ]; - })->values(); - return [ - 'master_paket_menu_id' => $first->master_paket_menu_id, - 'nama' => $first->nama_paket, - 'foto' => $first->foto, - 'jenis_menu' => "paket", - 'harga_public' => $first->harga_public, - 'harga_karyawan' => $first->harga_karyawan, - 'harga_keluarga_pasien' => $first->harga_keluarga_pasien, - 'status' => $first->status, - 'deskripsi' => $first->deskripsi, - 'klasifikasiMenu' => $klasifikasiMenu - ]; - })->values(); + $result = collect($paginated->items())->map(function ($paketMenu) use ($klasifikasi) { + return [ + 'master_paket_menu_id' => $paketMenu->master_paket_menu_id, + 'nama' => $paketMenu->nama_paket, + 'foto' => $paketMenu->foto, + 'jenis_menu' => "paket", + 'harga_public' => $paketMenu->harga_public, + 'harga_karyawan' => $paketMenu->harga_karyawan, + 'harga_keluarga_pasien' => $paketMenu->harga_keluarga_pasien, + 'status' => $paketMenu->status, + 'deskripsi' => $paketMenu->deskripsi, + 'klasifikasiMenu' => isset($klasifikasi[$paketMenu->master_paket_menu_id]) ? $klasifikasi[$paketMenu->master_paket_menu_id]->map(function ($item) { + return [ + 'kategori_diet_id' => $item->kategori_diet_id, + 'nama_kategori_diet' => $item->nama_kategori_diet, + ]; + })->values() : [], + ]; + }); + return response()->json([ - 'status' => true, - 'message' => 'Berhasil mendapatkan data', - 'data' => $grouped - ], 200); + 'status' => true, + 'message' => 'Berhasil mendapatkan data', + 'data' => [ + 'data' => $result, + 'current_page' => $paginated->currentPage(), + 'last_page' => $paginated->lastPage(), + 'per_page' => $paginated->perPage(), + 'total' => $paginated->total(), + ] + ]); } } diff --git a/public/asset_guests/css/main.css b/public/asset_guests/css/main.css index 3791bc1..b51efa3 100644 --- a/public/asset_guests/css/main.css +++ b/public/asset_guests/css/main.css @@ -65,6 +65,24 @@ body { color: var(--default-color); background-color: var(--background-color); font-family: var(--default-font); + +} + +html, body { + height: 100%; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; +} + +main { + flex: 1; +} + +#order_guest_id { + flex: 1; + min-height: 920px; /* supaya tetap tinggi walau data kosong */ } a { @@ -612,7 +630,6 @@ h6 { background-color: var(--background-color); border-top: 1px solid color-mix(in srgb, var(--accent-color), transparent 75%); font-size: 14px; - position: relative; } .footer .footer-top { @@ -1729,3 +1746,13 @@ section, .starter-section { /* Add your styles here */ } + +.cart-floating { + position: fixed; + bottom: 0; + left: 0; + right: 0; + z-index: 1055; + border-radius: 12px 12px 0 0; + box-shadow: 0 -2px 8px rgba(0,0,0,0.1); +} diff --git a/public/js/order_guest/_init.js b/public/js/order_guest/functions.js similarity index 86% rename from public/js/order_guest/_init.js rename to public/js/order_guest/functions.js index 1daead8..e705c8f 100644 --- a/public/js/order_guest/_init.js +++ b/public/js/order_guest/functions.js @@ -1,8 +1,10 @@ +let filterState = {}; $(document).ready(function(){ const jenisMenuAwal = $("#tabJenisMenu .nav-link.active").data("filter") - let filterState ={ + filterState ={ jenis_menu: jenisMenuAwal, - search:'' + search:'', + per_page: 6, } fetchMenu(filterState) @@ -33,7 +35,8 @@ $(document).ready(function(){ function changePerPage(select) { const newPerPage = parseInt(select.value); - console.log(newPerPage); - + filterState.per_page = newPerPage + fetchMenu(filterState) } + diff --git a/public/js/order_guest/index.js b/public/js/order_guest/index.js index e2dfe8c..359f5d2 100644 --- a/public/js/order_guest/index.js +++ b/public/js/order_guest/index.js @@ -1,3 +1,16 @@ +$(document).ready(function () { + // Auto render setiap buka offcanvas + const cartSidebar = document.getElementById('cartSidebar'); + cartSidebar.addEventListener('shown.bs.offcanvas', renderCartList); + cartSidebar.addEventListener('hidden.bs.offcanvas', function () { + const cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); + if (cart.length > 0) { + $('#floatingCartButton').removeClass('d-none'); + } + }); +}); + + function fetchMenu(filter = {}) { const containerGuest = $("#order_guest_id"); @@ -7,31 +20,38 @@ function fetchMenu(filter = {}) { search: filter.search || '', jenis_menu: filter.jenis_menu || '' }).toString(); - + containerGuest.html('

Memuat data....

'); fetch(`/datamenu?${params}`) .then(res => res.json()) .then(res => { - if (!res.status) + if (!res.status){ return containerGuest.html('

Gagal Memuat Data...

'); - - const menus = res.data.data || []; - - if (menus.length === 0) - return containerGuest.html('

Pencarian tidak ditemukan.

'); - - let html = '
'; - if (res.data.last_page > 1) { - html += `
`; - for (let i = 1; i <= res.data.last_page; i++) { - html += ` - `; - } - html += `
`; } + const session = JSON.parse(sessionStorage.getItem('customerData') || '{}') + let cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); + if(cart.length > 0){ + updateCartCount(cart.length) + } + if(session.nama_customer){ + $("#welcomeMessage").html(`Selamat Datang, ${session.nama_customer} !`) + } + const menus = res.data.data || []; + + if (menus.length === 0){ + return containerGuest.html('

Pencarian tidak ditemukan.

'); + } + let html = '
'; menus.forEach(menu => { + let hargaResult = 0; + if(session.jenis_customer === "Karyawan RSAB Harapan Kita"){ + hargaResult = menu.harga_karyawan + }else if(session.jenis_customer === "Keluarga Pasien / Penunggu Pasien"){ + hargaResult = menu.harga_keluarga_pasien + }else{ + hargaResult = menu.harga_public + } html += `
@@ -45,7 +65,7 @@ function fetchMenu(filter = {}) {
${menu.nama}
-

Rp ${parseInt(menu.harga_public).toLocaleString('id-ID')}

+

Rp ${parseInt(hargaResult).toLocaleString('id-ID')}

${menu.deskripsi || ''}

${(menu.klasifikasiMenu || []).map(tag => `${tag.nama_kategori_diet}`).join('')} @@ -55,9 +75,11 @@ function fetchMenu(filter = {}) {
@@ -65,22 +87,20 @@ function fetchMenu(filter = {}) {
`; }); - - - - html += '
'; - - // Pagination buttons - if (res.data.last_page > 1) { - html += `
+ + html += '
'; + html += `
-
+
` + // Pagination buttons + if (res.data.last_page > 1) { + html += `
`; for (let i = 1; i <= res.data.last_page; i++) { html += ` @@ -98,7 +118,250 @@ function fetchMenu(filter = {}) { } - -function orderMenu(data){ - +const modalCheckout = $("#checkoutModal") +function orderMenu(e){ + const klasifikasiStr = $(e).data('klasifikasi_menu') || ''; + const tags = klasifikasiStr.split(',').map(tag => tag.trim()).filter(tag => tag !== '') + + const klasifikasiMenu =tags.map(tag => ` + ${tag} + `).join(''); + + modalCheckout.modal("show") + $('#cathering_order_photo').attr('src', `/gambar/${$(e).data('foto')}`) + $('#cathering_order_name').text($(e).data('nama_menu')) + $('#cathering_order_price').text("Rp " + parseInt($(e).data('harga')).toLocaleString('id-ID')) + $("#tag_klasifikasi_menu").html(klasifikasiMenu) + $('#order_input_wrapper').empty(); + addOrderRow(); } + + +let orderIndex = 0; +function addOrderRow(data = {}) { + orderIndex++; + + const html = ` +
+
+ +
+
+ +
+
+ +
+
+ `; + $('#order_input_wrapper').append(html); +} + +function removeOrderRow(index) { + $(`#order_input_wrapper [data-row="${index}"]`).remove(); +} + + +function updateCartCount(count) { + const $cartCount = $('#cartCount'); + if (count > 0) { + $cartCount.text(count).show(); + let cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); + let totalHarga = cart.reduce((total, item) => { + const harga = parseInt(item.harga.replace(/[^\d]/g, '')) || 0; + const subtotal = item.pesanan.reduce((sum, p) => sum + (p.jumlah * harga), 0); + return total + subtotal; + }, 0); + $('#floatingCartButton').removeClass('d-none'); + $('#floatingCartCount').text(count); + $('#floatingCartTotal').text('Rp ' + totalHarga.toLocaleString('id-ID')); + $('#floatingCartDesc').text(cart[0].nama_menu); + + } else { + $cartCount.hide(); + $('#floatingCartButton').addClass('d-none'); + } +} + + $("#checkoutForm").on('submit', function(e){ + e.preventDefault(); + const orders = []; + let cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); + $("#order_input_wrapper .row").each(function(){ + const tgl = $(this).find('input[type="date"]').val(); + const jumlah = $(this).find('input[type="number"]').val(); + if(tgl && jumlah > 0){ + orders.push({ tgl, jumlah}) + } + }) + let existingItem = cart.find(item => item.nama_menu === $("#cathering_order_name").text()); + if(existingItem){ + orders.forEach(newOrder => { + const existingOrder =existingItem.pesanan.find(p => p.tgl === newOrder.tgl) + if(existingOrder){ + existingOrder.jumlah += newOrder.jumlah; + }else{ + existingItem.pesanan.push(newOrder) + } + }) + }else{ + const orderItem ={ + id:Date.now(), + nama_menu : $("#cathering_order_name").text(), + harga : $("#cathering_order_price").text(), + foto: $('#cathering_order_photo').attr('src'), + pesanan : orders + } + cart.push(orderItem) + } + + sessionStorage.setItem('cart', JSON.stringify(cart)) + updateCartCount(cart.length) + modalCheckout.modal('hide') + }) + + function renderCartList() { + $("#cartSidebar").offcanvas('show') + $('#floatingCartButton').addClass('d-none'); + const cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); + let total = 0; + + const html = cart.map(item => { + const hargaNum = parseInt(item.harga.replace(/[^\d]/g, '')); + let pesananHTML = ''; + + item.pesanan.forEach((p, i) => { + pesananHTML += ` +
+
+ +
+
+ +
+
+ +
+
+ `; + }); + + const itemTotal = item.pesanan.reduce((sum, p) => sum + (p.jumlah * hargaNum), 0); + total += itemTotal; + + return ` +
+
+ +
+
${item.nama_menu}
+
${item.harga}
+
+
+ +
+ ${pesananHTML} + +
+ +
+
Total: Rp ${itemTotal.toLocaleString('id-ID')}
+ +
+
+ `; + }).join(''); + + $('#cartListContainer').html(html); + $('#cartTotal').text('Rp ' + total.toLocaleString('id-ID')); + } + + + function addOrderDate(itemId) { + const cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); + const item = cart.find(i => i.id === itemId); + if (item) { + item.pesanan.push({ tgl: '', jumlah: 1 }); + sessionStorage.setItem('cart', JSON.stringify(cart)); + renderCartList(); + + } + } + + function removeOrderDate(itemId, index) { + const cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); + const item = cart.find(i => i.id === itemId); + if (item && item.pesanan.length > index) { + item.pesanan.splice(index, 1); + sessionStorage.setItem('cart', JSON.stringify(cart)); + renderCartList(); + } + } + + function removeCartItem(itemId){ + let cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); + cart = cart.filter(i => i.id !== itemId); + sessionStorage.setItem('cart', JSON.stringify(cart)); + updateCartCount(cart.length); + renderCartList() + } + + function onJumlahChange(itemId, index) { + const cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); + const jumlahInput = document.querySelector(`div[data-item-id='${itemId}'][data-index='${index}'] .jumlah-input`).value; + if (!isNaN(jumlahInput)) { + cart.forEach(item => { + if (item.id === itemId) { + item.pesanan[index].jumlah = parseInt(jumlahInput); + } + }); + sessionStorage.setItem('cart', JSON.stringify(cart)); + renderCartList(); + } + } + + function onTanggalChange(itemId, index) { + const cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); + const tanggalInput = document.querySelector(`div[data-item-id='${itemId}'][data-index='${index}'] .tanggal-input`).value; + cart.forEach(item => { + if (item.id === itemId) { + item.pesanan[index].tgl = tanggalInput; + } + }); + sessionStorage.setItem('cart', JSON.stringify(cart)); + validateCheckoutButton(); + } + + function renderCartTotalOnly() { + const cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); + let total = 0; + cart.forEach(item => { + const hargaNum = parseInt(item.harga.replace(/[^\d]/g, '')); + const itemTotal = item.pesanan.reduce((sum, p) => sum + (p.jumlah * hargaNum), 0); + total += itemTotal; + }); + $('#cartTotal').text('Rp ' + total.toLocaleString('id-ID')); + } + + function updateFloatingCartButton() { + const cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); + const totalItem = cart.reduce((sum, item) => { + return sum + item.pesanan.reduce((s, p) => s + p.jumlah, 0); + }, 0); + + const totalHarga = cart.reduce((sum, item) => { + const harga = parseInt(item.harga.replace(/[^\d]/g, '')); + return sum + item.pesanan.reduce((s, p) => s + (p.jumlah * harga), 0); + }, 0); + + if (cart.length > 0) { + $('#floatingCartButton').removeClass('d-none'); + $('#floatingCartCount').text(totalItem); + $('#floatingCartTotal').text('Rp ' + totalHarga.toLocaleString('id-ID')); + $('#floatingCartDesc').text(`Total pesanan dari ${cart[0].nama_menu}`); + } else { + $('#floatingCartButton').addClass('d-none'); + } + } diff --git a/public/js/order_guest/register.js b/public/js/order_guest/register.js new file mode 100644 index 0000000..bf77ebd --- /dev/null +++ b/public/js/order_guest/register.js @@ -0,0 +1,24 @@ +$(document).ready(function(){ + const modal = new bootstrap.Modal(document.getElementById('registerModal'), { + backdrop: 'static', // Tidak bisa klik luar + keyboard: false // Tidak bisa ESC + }); + if(!sessionStorage.getItem('customerData')){ + modal.show(); + } + + $("#formRegister").on('submit', function(e){ + e.preventDefault() + if(this.checkValidity()){ + const formData =Object.fromEntries(new FormData(this).entries()) + sessionStorage.setItem('customerData', JSON.stringify(formData)) + + modal.hide() + if(formData.nama_customer){ + $("#welcomeMessage").html(`Selamat Datang, ${formData.nama_customer} !`) + } + }else{ + this.reportValidity() + } + }) +}) \ No newline at end of file diff --git a/resources/views/guest/checkout_order.blade.php b/resources/views/guest/checkout_order.blade.php index e69de29..044b097 100644 --- a/resources/views/guest/checkout_order.blade.php +++ b/resources/views/guest/checkout_order.blade.php @@ -0,0 +1,43 @@ + \ No newline at end of file diff --git a/resources/views/guest/index.blade.php b/resources/views/guest/index.blade.php index abdf49d..45793c6 100644 --- a/resources/views/guest/index.blade.php +++ b/resources/views/guest/index.blade.php @@ -4,6 +4,9 @@
+
+
+
+
+
+
+ 0 item
+ Isi keranjang anda +
+
+ Rp 0 +
+ +
+
+
+
+ + +
- +@include('guest.register') +@include('guest.checkout_order') +@include('guest.keranjang') + + + @endsection diff --git a/resources/views/guest/keranjang.blade.php b/resources/views/guest/keranjang.blade.php new file mode 100644 index 0000000..992749c --- /dev/null +++ b/resources/views/guest/keranjang.blade.php @@ -0,0 +1,22 @@ +
+
+
Keranjang Saya
+ +
+
+ +
+
+ Total: + Rp 0 +
+
+
+
+
+ Total Bayar: + Rp 0 +
+ +
+
diff --git a/resources/views/guest/layout/partials/header.blade.php b/resources/views/guest/layout/partials/header.blade.php index 7a21583..b6bf4fb 100644 --- a/resources/views/guest/layout/partials/header.blade.php +++ b/resources/views/guest/layout/partials/header.blade.php @@ -12,7 +12,12 @@ diff --git a/resources/views/guest/register.blade.php b/resources/views/guest/register.blade.php index e69de29..c8a93ff 100644 --- a/resources/views/guest/register.blade.php +++ b/resources/views/guest/register.blade.php @@ -0,0 +1,67 @@ + \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index 03f4b3f..3ea3d87 100644 --- a/routes/web.php +++ b/routes/web.php @@ -3,8 +3,6 @@ use App\Http\Controllers\CustomerController; use App\Http\Controllers\KlasifikasiMenuController; use App\Http\Controllers\MenuController; -use App\Models\Menu; -use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Support\Facades\Route;