tambah waktu 20 menit saat melakukan checkout + validasi waktu makan

This commit is contained in:
JokoPrasetio 2025-10-15 14:23:23 +07:00
parent accb93dac2
commit f0df828334
4 changed files with 496 additions and 420 deletions

View File

@ -2,7 +2,7 @@
async function submitOrderToServer(){
const totalHarga = hitungTotalHarga();
if (sessionStorage.getItem('order_id')) {
if (sessionStorage.getItem('order_id')) {
currentStep = 2;
showStep(currentStep);
return;
@ -33,7 +33,12 @@ async function submitOrderToServer(){
}
} catch (error) {
console.error('message '+error);
alert('Terdapat kesalahan coba lagi nanti!')
Swal.fire({
title: 'Gagal!',
text: 'Terdapat kesalahan coba lagi nanti!',
icon: 'error',
confirmButtonText: 'Tutup!'
})
}
}
@ -119,7 +124,7 @@ async function submitOrderToServer(){
});
} else {
clearSession()
Swal.fire({
Swal.fire({
title: 'Gagal!',
text: result.message,
icon: 'error',
@ -130,8 +135,12 @@ async function submitOrderToServer(){
}
} catch (err) {
clearSession()
console.error(err);
alert("Terjadi kesalahan saat mengirim data.");
Swal.fire({
title: 'Gagal!',
text: "Terjadi kesalahan saat mengirim data.",
icon: 'error',
confirmButtonText: 'Tutup!'
})
}finally{
buttonSubmit.prop('disabled', false).html('Selesaikan Pesanan');
}

View File

@ -93,7 +93,7 @@ document.addEventListener('DOMContentLoaded', () => {
time_order = sessionStorage.getItem('time_order')
orderDate = new Date(time_order);
deadline = new Date(orderDate.getTime() + 10 * 60 * 1000)
deadline = new Date(orderDate.getTime() + 20 * 60 * 1000)
updateCountdown()
currentStep++;
showStep(currentStep)
@ -152,7 +152,7 @@ document.addEventListener('DOMContentLoaded', () => {
const selisihMs = now.getTime() - orderTime.getTime();
const selisihMenit = selisihMs / 1000 / 60;
if (selisihMenit > 10) {
if (selisihMenit > 20) {
// Bersihkan session
sessionStorage.removeItem('cart');
sessionStorage.removeItem('checkout_biodata');
@ -177,7 +177,7 @@ document.addEventListener('DOMContentLoaded', () => {
function updateCountdown(){
const now = new Date();
orderDate = new Date(time_order);
deadline = new Date(orderDate.getTime() + 10 * 60 * 1000)
deadline = new Date(orderDate.getTime() + 20 * 60 * 1000)
const distance = deadline - now
if(distance <= 0){
@ -266,340 +266,407 @@ function toggleCustomerFields() {
$('input[name="jenis_customer"]').on('change', toggleCustomerFields);
toggleCustomerFields();
if (typeof checkout_biodata === 'object') {
if (checkout_biodata.jenis_customer) {
$(`input[name="jenis_customer"][value="${checkout_biodata.jenis_customer}"]`).prop('checked', true);
}
if(checkout_biodata.jenis_kelamin){
$(`input[name="jenis_kelamin"][value="${checkout_biodata.jenis_kelamin}"]`).prop('checked', true);
}
if(checkout_biodata.jenis_customer !== 'Karyawan RSAB Harapan Kita'){
$('#nama_pemesan').val(checkout_biodata.nama_pemesan);
}
// $('#tanggal_lahir').val(checkout_biodata.tanggal_lahir);
$('#tinggi_badan').val(checkout_biodata.tinggi_badan);
$('#berat_badan').val(checkout_biodata.berat_badan);
$('#no_whatsapp').val(checkout_biodata.no_whatsapp);
$('#nama_pasien').val(checkout_biodata.nama_pasien);
$('#ruang_perawatan').val(checkout_biodata.ruang_perawatan);
$('#no_kamar').val(checkout_biodata.no_kamar);
$('#kelas_perawatan').val(checkout_biodata.kelas_perawatan);
$('#bagian_instalasi').val(checkout_biodata.bagian_instalasi);
$('#no_ekstensien').val(checkout_biodata.no_ekstensien);
$('#email').val(checkout_biodata.email);
$('#alamat').val(checkout_biodata.alamat);
}
function isiKonfirmasi() {
const biodata = {
jenis_customer: $('input[name="jenis_customer"]:checked').val(),
nama_pemesan: $('#nama_pemesan').val(),
jenis_kelamin: $('input[name="jenis_kelamin"]:checked').val(),
id_karyawan: $('#id_karyawan').val(),
tinggi_badan: $('#tinggi_badan').val(),
berat_badan: $('#berat_badan').val(),
no_whatsapp: $('#no_whatsapp').val(),
nama_pasien: $('#nama_pasien').val(),
ruang_perawatan: $('#ruang_perawatan').val(),
no_kamar: $('#no_kamar').val(),
kelas_perawatan: $('#kelas_perawatan').val(),
bagian_instalasi: $('#bagian_instalasi').val(),
no_ekstensien: $('#no_ekstensien').val(),
email: $('#email').val(),
alamat: $('#alamat').val(),
};
sessionStorage.setItem('checkout_biodata', JSON.stringify(biodata));
checkout_biodata = biodata;
renderCartSummary();
}
// =======================
// FUNGSI CART / PESANAN
// =======================
function renderCartSummary() {
const container = document.getElementById('checkout_cart_summary');
container.innerHTML = '';
let totalKeseluruhan = 0;
const carts = JSON.parse(sessionStorage.getItem('cart') || '[]');
const checkout_biodata = JSON.parse(sessionStorage.getItem('checkout_biodata') || '[]');
carts.forEach((item) => {
const pesananList = Array.isArray(item.pesanan) ? item.pesanan : [];
let pesananHTML = '';
const harga = checkout_biodata.jenis_customer === 'Karyawan RSAB Harapan Kita'
? item.harga_karyawan || 0
: item.harga_public || 0;
const itemTotal = pesananList.reduce((sum, p) => sum + (p.jumlah * harga), 0);
if (checkout_biodata.jenis_customer === "Karyawan RSAB Harapan Kita") {
$('#karyawan').removeClass('d-none');
$('#pasien').addClass('d-none');
} else if (checkout_biodata.jenis_customer === "Keluarga Pasien / Penunggu Pasien") {
$('#karyawan').addClass('d-none');
$('#pasien').removeClass('d-none');
} else {
$('#karyawan').addClass('d-none');
$('#pasien').addClass('d-none');
if (typeof checkout_biodata === 'object') {
if (checkout_biodata.jenis_customer) {
$(`input[name="jenis_customer"][value="${checkout_biodata.jenis_customer}"]`).prop('checked', true);
}
if(checkout_biodata.jenis_kelamin){
$(`input[name="jenis_kelamin"][value="${checkout_biodata.jenis_kelamin}"]`).prop('checked', true);
}
if(checkout_biodata.jenis_customer !== 'Karyawan RSAB Harapan Kita'){
$('#nama_pemesan').val(checkout_biodata.nama_pemesan);
}
// $('#tanggal_lahir').val(checkout_biodata.tanggal_lahir);
$('#tinggi_badan').val(checkout_biodata.tinggi_badan);
$('#berat_badan').val(checkout_biodata.berat_badan);
$('#no_whatsapp').val(checkout_biodata.no_whatsapp);
$('#nama_pasien').val(checkout_biodata.nama_pasien);
$('#ruang_perawatan').val(checkout_biodata.ruang_perawatan);
$('#no_kamar').val(checkout_biodata.no_kamar);
$('#kelas_perawatan').val(checkout_biodata.kelas_perawatan);
$('#bagian_instalasi').val(checkout_biodata.bagian_instalasi);
$('#no_ekstensien').val(checkout_biodata.no_ekstensien);
$('#email').val(checkout_biodata.email);
$('#alamat').val(checkout_biodata.alamat);
}
totalKeseluruhan += itemTotal;
pesananList.forEach((p, i) => {
const selectedDate = new Date(p.tgl);
const now = new Date();
const isToday = selectedDate.toDateString() === now.toDateString();
const jam = now.getHours();
const disableSiang = isToday && jam >= 10;
const disableSore = isToday && jam >= 13;
const countDate = pesananList.length;
function isiKonfirmasi() {
const biodata = {
jenis_customer: $('input[name="jenis_customer"]:checked').val(),
nama_pemesan: $('#nama_pemesan').val(),
jenis_kelamin: $('input[name="jenis_kelamin"]:checked').val(),
id_karyawan: $('#id_karyawan').val(),
tinggi_badan: $('#tinggi_badan').val(),
berat_badan: $('#berat_badan').val(),
no_whatsapp: $('#no_whatsapp').val(),
nama_pasien: $('#nama_pasien').val(),
ruang_perawatan: $('#ruang_perawatan').val(),
no_kamar: $('#no_kamar').val(),
kelas_perawatan: $('#kelas_perawatan').val(),
bagian_instalasi: $('#bagian_instalasi').val(),
no_ekstensien: $('#no_ekstensien').val(),
email: $('#email').val(),
alamat: $('#alamat').val(),
};
sessionStorage.setItem('checkout_biodata', JSON.stringify(biodata));
checkout_biodata = biodata;
renderCartSummary();
}
async function getServerTime() {
const res = await fetch('/server-time');
const data = await res.json();
return new Date(data.now);
}
pesananHTML += `
<div class="rounded border p-3 mb-3 shadow-sm" data-item-id="${item.id}" data-index="${i}">
<div class="row g-3 align-items-center">
// =======================
// FUNGSI CART / PESANAN
// =======================
function renderCartSummary() {
const container = document.getElementById('checkout_cart_summary');
container.innerHTML = '';
let totalKeseluruhan = 0;
const carts = JSON.parse(sessionStorage.getItem('cart') || '[]');
const checkout_biodata = JSON.parse(sessionStorage.getItem('checkout_biodata') || '[]');
<!-- Note -->
<div class="col-12 col-md-2">
<button type="button" class="btn btn-outline-success" onclick="notedOrder(${item.id}, ${i})" title="Catatan">
<i class="fa-solid fa-note-sticky"></i> Catatan
</button>
</div>
carts.forEach((item) => {
const pesananList = Array.isArray(item.pesanan) ? item.pesanan : [];
let pesananHTML = '';
const harga = checkout_biodata.jenis_customer === 'Karyawan RSAB Harapan Kita'
? item.harga_karyawan || 0
: item.harga_public || 0;
const itemTotal = pesananList.reduce((sum, p) => sum + (p.jumlah * harga), 0);
<!-- Tanggal -->
<div class="col-12 col-md-2">
<input type="text" class="form-control form-control-sm tanggal-input" id="tanggal-${item.id}-${i}" readonly placeholder="Pilih Tanggal">
</div>
if (checkout_biodata.jenis_customer === "Karyawan RSAB Harapan Kita") {
$('#karyawan').removeClass('d-none');
$('#pasien').addClass('d-none');
} else if (checkout_biodata.jenis_customer === "Keluarga Pasien / Penunggu Pasien") {
$('#karyawan').addClass('d-none');
$('#pasien').removeClass('d-none');
} else {
$('#karyawan').addClass('d-none');
$('#pasien').addClass('d-none');
}
<!-- Karbohidrat -->
${item.apakah_someday ? `` : `
<div class="col-12 col-md-3">
<select class="form-select form-select-sm karbohidrat-input" onChange="onKarbohidratChange(${item.id}, ${i}, this, ${item.kalori})">
<option disabled selected>Pilih Karbohidrat</option>
${(karhohidrats || []).map(k => `
<option value="${k.karbohidrat_id}" ${p.karbohidrat_id === k.karbohidrat_id ? 'selected' : ''} data-kalori=${k.nilai_kalori}>
${k.nama_karbohidrat} ${k.nilai_kalori ? `(${k.nilai_kalori} kal)` : ''}
</option>
`).join('')}
</select>
</div>`}
<!-- Waktu Makan -->
<div class="col-12 col-md-2">
<select class="form-select form-select-sm kategori-pemesanan-input"
data-item-id="${item.id}" data-index="${i}"
onchange="onKategoriChange(${item.id}, ${i}, ${isToday})"
onfocus="this.dataset.previousValue = this.value"
${item.apakah_menu_siang || item.apakah_menu_sore ? '' : 'disabled'}>
${
item.apakah_someday
? (
item.apakah_menu_siang && item.apakah_menu_sore
? `
<option value="Makan Siang" ${p.kategoriPemesanan === 'Makan Siang' ? 'selected' : ''} ${disableSiang ? 'disabled' : ''}>Makan Siang</option>
<option value="Makan Sore" ${p.kategoriPemesanan === 'Makan Sore' ? 'selected' : ''} ${disableSore ? 'disabled' : ''}>Makan Sore</option>
`
: item.apakah_menu_siang
? `<option value="Makan Siang" selected ${disableSiang ? 'disabled' : ''}>Makan Siang</option>`
: item.apakah_menu_sore
? `<option value="Makan Sore" selected ${disableSore ? 'disabled' : ''}>Makan Sore</option>`
: `<option value="" disabled selected>Tidak tersedia</option>`
)
: (
item.apakah_menu_siang && item.apakah_menu_sore
? `
<option value="Makan Siang" ${p.kategoriPemesanan === 'Makan Siang' ? 'selected' : ''}>Makan Siang</option>
<option value="Makan Sore" ${p.kategoriPemesanan === 'Makan Sore' ? 'selected' : ''}>Makan Sore</option>
`
: item.apakah_menu_siang
? `<option value="Makan Siang" selected>Makan Siang</option>`
: item.apakah_menu_sore
? `<option value="Makan Sore" selected>Makan Sore</option>`
: `<option value="" disabled selected>Tidak tersedia</option>`
)
totalKeseluruhan += itemTotal;
pesananList.forEach((p, i) => {
const selectedDate = new Date(p.tgl);
const now = new Date();
const isToday = selectedDate.toDateString() === now.toDateString();
const jam = now.getHours();
const disableSiang = isToday && jam >= 10;
const disableSore = isToday && jam >= 13;
const countDate = pesananList.length;
pesananHTML += `
<div class="rounded border p-3 mb-3 shadow-sm" data-item-id="${item.id}" data-index="${i}">
<div class="row g-3 align-items-center">
<!-- Note -->
<div class="col-12 col-md-2">
<button type="button" class="btn btn-outline-success" onclick="notedOrder(${item.id}, ${i})" title="Catatan">
<i class="fa-solid fa-note-sticky"></i> Catatan
</button>
</div>
<!-- Tanggal -->
<div class="col-12 col-md-2">
<input type="text" class="form-control form-control-sm tanggal-input" id="tanggal-${item.id}-${i}" readonly placeholder="Pilih Tanggal">
</div>
<!-- Karbohidrat -->
${item.apakah_someday ? `` : `
<div class="col-12 col-md-3">
<select class="form-select form-select-sm karbohidrat-input" onChange="onKarbohidratChange(${item.id}, ${i}, this, ${item.kalori})">
<option disabled selected>Pilih Karbohidrat</option>
${(karhohidrats || []).map(k => `
<option value="${k.karbohidrat_id}" ${p.karbohidrat_id === k.karbohidrat_id ? 'selected' : ''} data-kalori=${k.nilai_kalori}>
${k.nama_karbohidrat} ${k.nilai_kalori ? `(${k.nilai_kalori} kal)` : ''}
</option>
`).join('')}
</select>
</div>`}
<!-- Waktu Makan -->
<div class="col-12 col-md-2">
<select class="form-select form-select-sm kategori-pemesanan-input"
data-item-id="${item.id}" data-index="${i}"
onchange="onKategoriChange(${item.id}, ${i}, ${isToday})"
onfocus="this.dataset.previousValue = this.value"
${item.apakah_menu_siang || item.apakah_menu_sore ? '' : 'disabled'}>
${
item.apakah_someday
? (
item.apakah_menu_siang && item.apakah_menu_sore
? `
<option value="">Select Choose</option>
<option value="Makan Siang" ${p.kategoriPemesanan === 'Makan Siang' ? 'selected' : ''} ${disableSiang ? 'disabled' : ''}>Makan Siang</option>
<option value="Makan Sore" ${p.kategoriPemesanan === 'Makan Sore' ? 'selected' : ''} ${disableSore ? 'disabled' : ''}>Makan Sore</option>
`
: item.apakah_menu_siang
? `<option value="Makan Siang" ${disableSiang ? 'disabled' : 'selected'}>Makan Siang</option>`
: item.apakah_menu_sore
? `<option value="Makan Sore" ${disableSore ? 'disabled' : 'selected'}>Makan Sore</option>`
: `<option value="" disabled selected>Tidak tersedia</option>`
)
: (
item.apakah_menu_siang && item.apakah_menu_sore
? `
<option value="Makan Siang" ${p.kategoriPemesanan === 'Makan Siang' ? 'selected' : ''}>Makan Siang</option>
<option value="Makan Sore" ${p.kategoriPemesanan === 'Makan Sore' ? 'selected' : ''}>Makan Sore</option>
`
: item.apakah_menu_siang
? `<option value="Makan Siang" selected>Makan Siang</option>`
: item.apakah_menu_sore
? `<option value="Makan Sore" selected>Makan Sore</option>`
: `<option value="" disabled selected>Tidak tersedia</option>`
)
}
</select>
</div>
<!-- Jumlah -->
<div class="col-6 col-md-2">
<div class="d-flex align-items-center justify-content-between">
<button class="btn btn-sm btn-outline-success" onclick="decrement(${item.id}, ${i})" ${p.jumlah > 1 ? '' : 'disabled'}>
<i class="fa fa-minus"></i>
</button>
<input type="text" class="form-control form-control-sm text-center mx-2 jumlah-input"
value="${p.jumlah}" readonly style="width: 60px;" id="jumlah-${item.id}-${i}">
<button class="btn btn-sm btn-outline-success" onclick="increment(${item.id}, ${i})">
<i class="fa fa-plus"></i>
</button>
</div>
</div>
<!-- Tombol Hapus -->
<div class="col-6 col-md-1 text-end">
${countDate > 1
? `<button class="btn btn-sm btn-danger" onclick="removeOrderDate(${item.id}, ${i}, ${countDate})" title="Hapus">
<i class="fa fa-trash"></i>
</button>`
: ''
}
</select>
</div>
${item.kalori
? `<div class="mb-2 small text-muted">Total Kalori: <strong id="kalori_${item.id}_${i}">${p?.resultKalori ? p?.resultKalori : item?.kalori}</strong> kal</div>`
: ''}
</div>
</div>
`;
});
const itemHTML = `
<div class="card mb-3 shadow-sm position-relative">
<button type="button" class="btn btn-sm btn-danger position-absolute top-0 end-0 m-2" onClick="removeCartItem(${item.id})" style="z-index:1;">
Hapus
</button>
<div class="d-flex flex-column flex-md-row">
<div class="p-2 d-flex justify-content-center align-items-center" style="flex: 0 0 300px;">
<img src="gambar/${item.foto || 'default.jpg'}" alt="${item.nama_menu}"
class="img-fluid rounded" style="max-height: 280px; width: 100%; object-fit: cover;">
</div>
<div class="flex-grow-1 position-relative">
<div class="card-body">
<!-- Judul menu -->
<h4 class="card-title mb-2 fw-bold text-primary">${item.nama_menu}</h4>
<!-- Harga -->
<div class="badge bg-success-subtle text-success fw-bold fs-6 mb-2">
${checkout_biodata?.jenis_customer === "Karyawan RSAB Harapan Kita"
? '<span class="me-1">Harga Karyawan</span>'
: '<span class="me-1">Harga</span>'
}
Rp ${parseInt(harga).toLocaleString('id-ID')}
</div>
<!-- Jumlah -->
<div class="col-6 col-md-2">
<div class="d-flex align-items-center justify-content-between">
<!-- Kalori -->
${item?.kalori ? `<div class="text-muted small mb-1"><i class="fas fa-fire me-1"></i>Kalori: ${item.kalori} kal</div>` : ''}
<button class="btn btn-sm btn-outline-success" onclick="decrement(${item.id}, ${i})" ${p.jumlah > 1 ? '' : 'disabled'}>
<i class="fa fa-minus"></i>
</button>
<input type="text" class="form-control form-control-sm text-center mx-2 jumlah-input"
value="${p.jumlah}" readonly style="width: 60px;" id="jumlah-${item.id}-${i}">
<button class="btn btn-sm btn-outline-success" onclick="increment(${item.id}, ${i})">
<i class="fa fa-plus"></i>
</button>
<!-- Deskripsi -->
${item.deskripsi ? `<p class="card-text text-muted small mb-2">${item.deskripsi}</p>` : ''}
<!-- Info tanggal & jenis menu -->
<div class="d-flex flex-column gap-1 mb-2">
<div class="small text-muted">
<i class="fas fa-calendar-check me-1"></i>
${item.apakah_someday
? 'Tersedia setiap hari (Senin Minggu)'
: (item.tgl_tersedia ? `Tersedia pada tanggal: ${item.tgl_tersedia}` : 'Tidak ada info tanggal tersedia')
}
</div>
<div class="small text-muted">
<i class="fas fa-utensils me-1"></i>
<strong>${item.apakah_someday ? 'Sameday' : 'Menu Normal'}</strong>
</div>
</div>
<!-- Tombol Hapus -->
<div class="col-6 col-md-1 text-end">
${countDate > 1
? `<button class="btn btn-sm btn-danger" onclick="removeOrderDate(${item.id}, ${i}, ${countDate})" title="Hapus">
<i class="fa fa-trash"></i>
</button>`
: ''
}
<!-- Petunjuk -->
<div class="alert alert-info small p-2 mb-2">
<strong>Petunjuk:</strong> Isi tanggal pemesanan, pilih karbohidrat, dan catatan tambahan (opsional).
</div>
<!-- Form pesanan -->
${pesananHTML}
<!-- Tombol & total -->
<div class="d-flex justify-content-between align-items-center flex-wrap gap-2 mt-3">
<button class="btn btn-sm btn-success" onclick="addOrderDate(${item.id}, ${item.apakah_menu_sore})">
<i class="fas fa-plus me-1"></i>Tambah Tanggal
</button>
<div class="fw-bold">
Total: <span class="text-success">Rp ${itemTotal.toLocaleString('id-ID')}</span>
</div>
</div>
${item.kalori
? `<div class="mb-2 small text-muted">Total Kalori: <strong id="kalori_${item.id}_${i}">${p?.resultKalori ? p?.resultKalori : item?.kalori}</strong> kal</div>`
: ''}
</div>
</div>
</div>
</div>
`;
`;
container.insertAdjacentHTML('beforeend', itemHTML);
pesananList.forEach((p, i) => initFlatpickrTersedia(item, i));
});
const itemHTML = `
<div class="card mb-3 shadow-sm position-relative">
<button type="button" class="btn btn-sm btn-danger position-absolute top-0 end-0 m-2" onClick="removeCartItem(${item.id})" style="z-index:1;">
Hapus
</button>
<div class="d-flex flex-column flex-md-row">
<div class="p-2 d-flex justify-content-center align-items-center" style="flex: 0 0 300px;">
<img src="gambar/${item.foto || 'default.jpg'}" alt="${item.nama_menu}"
class="img-fluid rounded" style="max-height: 280px; width: 100%; object-fit: cover;">
container.insertAdjacentHTML('beforeend', `
<div class="text-end mt-4">
<hr>
<h5><strong>Total Keseluruhan:</strong> <span class="text-success">Rp ${totalKeseluruhan.toLocaleString('id-ID')}</span></h5>
</div>
`);
<div class="flex-grow-1 position-relative">
document.getElementById('no_order_price').textContent = 'Rp ' + totalKeseluruhan.toLocaleString('id-ID');
}
<div class="card-body">
<!-- Judul menu -->
<h4 class="card-title mb-2 fw-bold text-primary">${item.nama_menu}</h4>
// =======================
// EVENT HANDLER FIELD
// =======================
function onJumlahChange(itemId, index) {
let cart = JSON.parse(sessionStorage.getItem('cart') || '[]');
const input = document.querySelector(`div[data-item-id='${itemId}'][data-index='${index}'] .jumlah-input`);
if (!isNaN(input.value)) {
cart.find(item => item.id === itemId).pesanan[index].jumlah = parseInt(input.value);
sessionStorage.setItem('cart', JSON.stringify(cart));
isiKonfirmasi();
}
}
function ymdLocal(date) {
const y = date.getFullYear();
const m = String(date.getMonth() + 1).padStart(2, "0");
const d = String(date.getDate()).padStart(2, "0");
return `${y}-${m}-${d}`;
}
<!-- Harga -->
<div class="badge bg-success-subtle text-success fw-bold fs-6 mb-2">
${checkout_biodata?.jenis_customer === "Karyawan RSAB Harapan Kita"
? '<span class="me-1">Harga Karyawan</span>'
: '<span class="me-1">Harga</span>'
}
Rp ${parseInt(harga).toLocaleString('id-ID')}
</div>
<!-- Kalori -->
${item?.kalori ? `<div class="text-muted small mb-1"><i class="fas fa-fire me-1"></i>Kalori: ${item.kalori} kal</div>` : ''}
async function onTanggalChange(itemId, index) {
let cart = JSON.parse(sessionStorage.getItem('cart') || '[]');
const input = document.querySelector(`div[data-item-id='${itemId}'][data-index='${index}'] .tanggal-input`);
const serverDate = await getServerTime();
const year = serverDate.getFullYear();
const month = String(serverDate.getMonth() + 1).padStart(2, '0');
const day = String(serverDate.getDate()).padStart(2, '0');
<!-- Deskripsi -->
${item.deskripsi ? `<p class="card-text text-muted small mb-2">${item.deskripsi}</p>` : ''}
// const todayStr = ymdLocal(new Date());
const todayStr = `${year}-${month}-${day}`
const isToday = input.value === todayStr;
<!-- Info tanggal & jenis menu -->
<div class="d-flex flex-column gap-1 mb-2">
<div class="small text-muted">
<i class="fas fa-calendar-check me-1"></i>
${item.apakah_someday
? 'Tersedia setiap hari (Senin Minggu)'
: (item.tgl_tersedia ? `Tersedia pada tanggal: ${item.tgl_tersedia}` : 'Tidak ada info tanggal tersedia')
}
</div>
<div class="small text-muted">
<i class="fas fa-utensils me-1"></i>
<strong>${item.apakah_someday ? 'Sameday' : 'Menu Normal'}</strong>
</div>
</div>
<!-- Petunjuk -->
<div class="alert alert-info small p-2 mb-2">
<strong>Petunjuk:</strong> Isi tanggal pemesanan, pilih karbohidrat, dan catatan tambahan (opsional).
</div>
<!-- Form pesanan -->
${pesananHTML}
<!-- Tombol & total -->
<div class="d-flex justify-content-between align-items-center flex-wrap gap-2 mt-3">
<button class="btn btn-sm btn-success" onclick="addOrderDate(${item.id}, ${item.apakah_menu_sore})">
<i class="fas fa-plus me-1"></i>Tambah Tanggal
</button>
<div class="fw-bold">
Total: <span class="text-success">Rp ${itemTotal.toLocaleString('id-ID')}</span>
</div>
</div>
</div>
</div>
</div>
</div>
`;
container.insertAdjacentHTML('beforeend', itemHTML);
pesananList.forEach((p, i) => initFlatpickrTersedia(item, i));
});
container.insertAdjacentHTML('beforeend', `
<div class="text-end mt-4">
<hr>
<h5><strong>Total Keseluruhan:</strong> <span class="text-success">Rp ${totalKeseluruhan.toLocaleString('id-ID')}</span></h5>
</div>
`);
document.getElementById('no_order_price').textContent = 'Rp ' + totalKeseluruhan.toLocaleString('id-ID');
}
// =======================
// EVENT HANDLER FIELD
// =======================
function onJumlahChange(itemId, index) {
let cart = JSON.parse(sessionStorage.getItem('cart') || '[]');
const input = document.querySelector(`div[data-item-id='${itemId}'][data-index='${index}'] .jumlah-input`);
if (!isNaN(input.value)) {
cart.find(item => item.id === itemId).pesanan[index].jumlah = parseInt(input.value);
cart.find(item => item.id === itemId).pesanan[index].tgl = input.value;
sessionStorage.setItem('cart', JSON.stringify(cart));
isiKonfirmasi();
}
}
const selectEl = document.querySelector(
`.kategori-pemesanan-input[data-item-id='${itemId}'][data-index='${index}']`
);
if (!selectEl) return;
const next = selectEl.value;
if (!isKategoriMasihDibuka(next, isToday)) {
cart.find(item => item.id === itemId).pesanan[index].kategoriPemesanan = null;
sessionStorage.setItem("cart", JSON.stringify(cart));
// Tampilkan alert & revert ke sebelumnya
const msg =
next === "Makan Siang"
? "Pemesanan Makan Siang hanya bisa dilakukan sebelum jam 10:00."
: "Pemesanan Makan Sore hanya bisa dilakukan sebelum jam 13:00.";
function onTanggalChange(itemId, index) {
let cart = JSON.parse(sessionStorage.getItem('cart') || '[]');
const input = document.querySelector(`div[data-item-id='${itemId}'][data-index='${index}'] .tanggal-input`);
cart.find(item => item.id === itemId).pesanan[index].tgl = input.value;
sessionStorage.setItem('cart', JSON.stringify(cart));
renderCartSummary();
}
function onKarbohidratChange(itemId, index, el, kalori){
const selectedOption = el.options[el.selectedIndex];
const kaloriOption = parseInt(selectedOption.getAttribute('data-kalori')) || 0;
const kaloriMenuInt = kalori || 0;
const totalKalori = kaloriOption + kaloriMenuInt;
const kaloriEl = document.getElementById(`kalori_${itemId}_${index}`);
if (kaloriEl) {
kaloriEl.textContent = totalKalori ;
}
let cart = JSON.parse(sessionStorage.getItem('cart') || '[]');
const input = document.querySelector(`div[data-item-id='${itemId}'][data-index='${index}'] .karbohidrat-input`);
cart.find(item => item.id === itemId).pesanan[index].karbohidrat_id = parseInt(input.value);
cart.find(item => item.id === itemId).pesanan[index].resultKalori = totalKalori;
sessionStorage.setItem('cart', JSON.stringify(cart));
}
function onKategoriChange(itemId, index, isToday) {
let cart = JSON.parse(sessionStorage.getItem('cart') || '[]');
const selectEl = document.querySelector(`.kategori-pemesanan-input[data-item-id='${itemId}'][data-index='${index}']`);
const kategori = selectEl.value;
let now = new Date();
let jam = now.getHours();
if (kategori === "Makan Siang" && isToday && jam >= 10) {
alert("Pemesanan Makan Siang hanya bisa dilakukan sebelum jam 10:00.");
} else if (kategori === "Makan Sore" && isToday && jam >= 13) {
alert("Pemesanan Makan Sore hanya bisa dilakukan sebelum jam 13:00.");
Swal.fire({ title: "Perhatian!", text: msg, icon: "warning" }).then(() => {
selectEl.value = "";
});
}
renderCartSummary();
}
const item = cart.find(item => item.id === itemId);
if (item && item.pesanan && item.pesanan[index]) {
item.pesanan[index].kategoriPemesanan = kategori;
function onKarbohidratChange(itemId, index, el, kalori){
const selectedOption = el.options[el.selectedIndex];
const kaloriOption = parseInt(selectedOption.getAttribute('data-kalori')) || 0;
const kaloriMenuInt = kalori || 0;
const totalKalori = kaloriOption + kaloriMenuInt;
const kaloriEl = document.getElementById(`kalori_${itemId}_${index}`);
if (kaloriEl) {
kaloriEl.textContent = totalKalori ;
}
let cart = JSON.parse(sessionStorage.getItem('cart') || '[]');
const input = document.querySelector(`div[data-item-id='${itemId}'][data-index='${index}'] .karbohidrat-input`);
cart.find(item => item.id === itemId).pesanan[index].karbohidrat_id = parseInt(input.value);
cart.find(item => item.id === itemId).pesanan[index].resultKalori = totalKalori;
sessionStorage.setItem('cart', JSON.stringify(cart));
// renderCartSummary();
}
}
function onKategoriChange(itemId, index, isToday) {
const selectEl = document.querySelector(
`.kategori-pemesanan-input[data-item-id='${itemId}'][data-index='${index}']`
);
if (!selectEl) return;
const next = selectEl.value;
// Validasi batas waktu
let cart = JSON.parse(sessionStorage.getItem("cart") || "[]");
const item = cart.find((it) => it.id === itemId);
if (!isKategoriMasihDibuka(next, isToday)) {
item.pesanan[index].kategoriPemesanan = null;
sessionStorage.setItem("cart", JSON.stringify(cart));
// Tampilkan alert & revert ke sebelumnya
const msg =
next === "Makan Siang"
? "Pemesanan Makan Siang hanya bisa dilakukan sebelum jam 10:00."
: "Pemesanan Makan Sore hanya bisa dilakukan sebelum jam 13:00.";
Swal.fire({ title: "Perhatian!", text: msg, icon: "warning" }).then(() => {
selectEl.value = "";
});
return;
}else{
if (item && item.pesanan && item.pesanan[index]) {
item.pesanan[index].kategoriPemesanan = next;
sessionStorage.setItem("cart", JSON.stringify(cart));
// update nilai previous
selectEl.dataset.previousValue = next;
// rerender ringkasan
if (typeof renderCartSummary === "function") renderCartSummary();
}
}
}
function isKategoriMasihDibuka(kategori, isToday) {
if (!isToday) return true; // pesanan untuk hari lain bebas
const jam = new Date().getHours();
const cutoff = { "Makan Siang": 10, "Makan Sore": 15 };
return cutoff[kategori] ? jam < cutoff[kategori] : true;
}
// =======================
@ -619,19 +686,19 @@ function addOrderDate(itemId, sore) {
}
}
function removeOrderDate(itemId, index, count) {
let cart = JSON.parse(sessionStorage.getItem('cart') || '[]');
const item = cart.find(i => i.id === itemId);
function removeOrderDate(itemId, index, count) {
let cart = JSON.parse(sessionStorage.getItem('cart') || '[]');
const item = cart.find(i => i.id === itemId);
if(count == 1){
cart = cart.filter(i => i.id !== itemId);
sessionStorage.setItem('cart', JSON.stringify(cart));
}else if(item && Array.isArray(item.pesanan) && item.pesanan.length > index) {
item.pesanan.splice(index, 1);
sessionStorage.setItem('cart', JSON.stringify(cart));
if(count == 1){
cart = cart.filter(i => i.id !== itemId);
sessionStorage.setItem('cart', JSON.stringify(cart));
}else if(item && Array.isArray(item.pesanan) && item.pesanan.length > index) {
item.pesanan.splice(index, 1);
sessionStorage.setItem('cart', JSON.stringify(cart));
}
renderCartSummary();
}
renderCartSummary();
}
function removeCartItem(itemId){
@ -641,105 +708,105 @@ function removeOrderDate(itemId, index, count) {
renderCartSummary()
}
// validasi step one dan sebelum submit
function validateStepOne() {
const jenisCustomer = document.querySelector('input[name="jenis_customer"]:checked');
const jenisKelamin = document.querySelector('input[name="jenis_kelamin"]:checked');
const namaPemesan = document.getElementById('nama_pemesan').value.trim();
const noWA = document.getElementById('no_whatsapp').value.trim();
const email = document.getElementById('email').value.trim();
// validasi step one dan sebelum submit
function validateStepOne() {
const jenisCustomer = document.querySelector('input[name="jenis_customer"]:checked');
const jenisKelamin = document.querySelector('input[name="jenis_kelamin"]:checked');
const namaPemesan = document.getElementById('nama_pemesan').value.trim();
const noWA = document.getElementById('no_whatsapp').value.trim();
const email = document.getElementById('email').value.trim();
if (!jenisCustomer) {
Swal.fire({
title: 'Perhatian!',
text: 'Silakan pilih jenis customer.',
icon: 'warning',
confirmButtonText: 'Oke'
})
return false;
}
if (!namaPemesan) {
Swal.fire({
title: 'Perhatian!',
text: 'Silakan isi nama pemesan.',
icon: 'warning',
confirmButtonText: 'Oke'
})
return false;
}
if (!jenisKelamin) {
Swal.fire({
title: 'Perhatian!',
text: 'Silakan pilih jenis kelamin.',
icon: 'warning',
confirmButtonText: 'Oke'
})
return false;
}
if (!noWA) {
Swal.fire({
title: 'Perhatian!',
text: 'Silakan isi nomor WhatsApp.',
icon: 'warning',
confirmButtonText: 'Oke'
})
return false;
}
if (!email) {
Swal.fire({
title: 'Perhatian!',
text: 'Silakan isi email terlebih dahulu.',
icon: 'warning',
confirmButtonText: 'Oke'
})
return false;
}
// Validasi tambahan sesuai jenis customer
const selected = jenisCustomer.value;
if (selected === 'Karyawan RSAB Harapan Kita') {
const bagian = document.getElementById('bagian_instalasi').value.trim();
if (!bagian) {
Swal.fire({
title: 'Perhatian!',
text: 'Silakan lengkapi data karyawan.',
icon: 'warning',
confirmButtonText: 'Oke'
})
return false;
}
} else if (selected === 'Keluarga Pasien / Penunggu Pasien') {
const namaPasien = document.getElementById('nama_pasien').value.trim();
const ruang = document.getElementById('ruang_perawatan').value;
const noKamar = document.getElementById('no_kamar').value.trim();
const kelas = document.getElementById('kelas_perawatan').value;
if (!namaPasien || !ruang || !noKamar || !kelas) {
if (!jenisCustomer) {
Swal.fire({
title: 'Perhatian!',
text: 'Silakan lengkapi data pasien.',
icon: 'warning',
confirmButtonText: 'Oke'
})
title: 'Perhatian!',
text: 'Silakan pilih jenis customer.',
icon: 'warning',
confirmButtonText: 'Oke'
})
return false;
}
}else if(selected === "Masyarakat Umum"){
const alamat = document.getElementById('alamat').value;
if(!alamat){
Swal.fire({
title: 'Perhatian!',
text: 'Silahkan lengkapi alamat.',
icon: 'warning',
confirmButtonText: 'Oke'
})
return false
}
}
return true;
}
if (!namaPemesan) {
Swal.fire({
title: 'Perhatian!',
text: 'Silakan isi nama pemesan.',
icon: 'warning',
confirmButtonText: 'Oke'
})
return false;
}
if (!jenisKelamin) {
Swal.fire({
title: 'Perhatian!',
text: 'Silakan pilih jenis kelamin.',
icon: 'warning',
confirmButtonText: 'Oke'
})
return false;
}
if (!noWA) {
Swal.fire({
title: 'Perhatian!',
text: 'Silakan isi nomor WhatsApp.',
icon: 'warning',
confirmButtonText: 'Oke'
})
return false;
}
if (!email) {
Swal.fire({
title: 'Perhatian!',
text: 'Silakan isi email terlebih dahulu.',
icon: 'warning',
confirmButtonText: 'Oke'
})
return false;
}
// Validasi tambahan sesuai jenis customer
const selected = jenisCustomer.value;
if (selected === 'Karyawan RSAB Harapan Kita') {
const bagian = document.getElementById('bagian_instalasi').value.trim();
if (!bagian) {
Swal.fire({
title: 'Perhatian!',
text: 'Silakan lengkapi data karyawan.',
icon: 'warning',
confirmButtonText: 'Oke'
})
return false;
}
} else if (selected === 'Keluarga Pasien / Penunggu Pasien') {
const namaPasien = document.getElementById('nama_pasien').value.trim();
const ruang = document.getElementById('ruang_perawatan').value;
const noKamar = document.getElementById('no_kamar').value.trim();
const kelas = document.getElementById('kelas_perawatan').value;
if (!namaPasien || !ruang || !noKamar || !kelas) {
Swal.fire({
title: 'Perhatian!',
text: 'Silakan lengkapi data pasien.',
icon: 'warning',
confirmButtonText: 'Oke'
})
return false;
}
}else if(selected === "Masyarakat Umum"){
const alamat = document.getElementById('alamat').value;
if(!alamat){
Swal.fire({
title: 'Perhatian!',
text: 'Silahkan lengkapi alamat.',
icon: 'warning',
confirmButtonText: 'Oke'
})
return false
}
}
return true;
}
function validateCartBeforeSubmit() {
@ -777,7 +844,6 @@ function hitungTotalHarga(){
cart.forEach(item => {
const harga = biodata.jenis_customer === "Karyawan RSAB Harapan Kita" ? item.harga_karyawan : item.harga_public || 0
const itemTotal = item.pesanan?.reduce((sum, p) => sum + (p.jumlah * harga), 0);
total += itemTotal
})
@ -880,7 +946,7 @@ function initFlatpickrTersedia(item, i) {
let minTanggal = 'today';
// Jika item adalah someday dan waktu sekarang sudah lewat 13:00
// Jika item adalah someday dan waktu sekarang sudah lewat 13:00
if (item?.apakah_someday && totalMenitFlatSekarang >= 13 * 60) {
const besok = new Date(now);
besok.setDate(now.getDate() + 1);
@ -896,7 +962,7 @@ function initFlatpickrTersedia(item, i) {
onChange: function(selectedDates, dateStr) {
onTanggalChange(item.id, i, dateStr);
}
});
});
}
@ -914,7 +980,7 @@ function decrement(itemId, index) {
input.value = current - 1;
onJumlahChange(itemId, index);
}else{
return
return;
}
}

View File

@ -28,14 +28,14 @@
<li>
Waktu pengambilan makanan:
<ul class="ps-3 mt-1">
<li>Siang: <strong>12.00 13.00 WIB</strong></li>
<li>Sore: <strong>16.00 17.00 WIB</strong></li>
<li>Siang: <strong>12.00 - 13.00 WIB</strong></li>
<li>Sore: <strong>16.00 - 17.00 WIB</strong></li>
</ul>
</li>
<li>
Butuh bantuan? Hubungi WhatsApp <strong>Instalasi Gizi</strong>:
<a href="https://wa.me/08815611382" target="_blank">08815611382</a><br>
<small class="text-muted">Jam kerja: 08.00 15.00 WIB</small>
<small class="text-muted">Jam kerja: 08.00 - 15.00 WIB</small>
</li>
</ul>
</div>
@ -55,7 +55,7 @@
<li>
Butuh bantuan? Hubungi WhatsApp <strong>Instalasi Gizi</strong>:
<a href="https://wa.me/08815611382 " target="_blank">08815611382 </a> <br>
<small class="text-muted">Jam kerja: 08.00 15.00 WIB</small>
<small class="text-muted">Jam kerja: 08.00 - 15.00 WIB</small>
</li>
</ul>
</div>

View File

@ -102,6 +102,7 @@ Route::post('/order-mcu', [CustomerController::class, 'storeMcu']);
Route::get('/success-mcu', [CustomerController::class, 'successMcu']);
Route::get('/karyawan', [CustomerController::class, 'karyawan']);
Route::get('/unit-instalasi', [CustomerController::class, 'unitInstalasi']);
Route::get('/server-time', fn()=> response()->json(['now' => now()]));
// Route::get('/send-mail', function(){
// Mail::to('skyjok14@gmail.com')->queue(new NotifikasiCustomer('Test'));