Rayyan Medika Estimator

Kalkulator Estimasi Layanan

Pilih pemeriksaan medis, terapkan diskon, dan hasilkan rincian biaya instan.

Pilih Pemeriksaan / Layanan

Rincian Penjumlahan

0 Layanan
Belum ada pemeriksaan yang dipilih
Subtotal Layanan: Rp 0
Potongan Diskon: - Rp 0
Total Biaya: Rp 0
async function saveLayananSubmit(e) { e.preventDefault(); const id = document.getElementById('layanan-id').value; const nama = document.getElementById('layanan-nama').value.trim(); const kategori = document.getElementById('layanan-kategori').value; const harga = Number(document.getElementById('layanan-harga').value); const estimasiHasil = document.getElementById('layanan-estimasi').value.trim(); const ket = document.getElementById('layanan-ket').value.trim(); const itemPayload = { id: id || `LAY-${Date.now()}`, nama, kategori, harga, estimasiHasil, ket }; if (id) { const idx = masterLayanan.findIndex(l => l.id === id); if (idx > -1) masterLayanan[idx] = itemPayload; } else { masterLayanan.push(itemPayload); } closeModalLayanan(); filterCalcLayanan(); renderKatalogTable(); showToast("Menyimpan ke Google Sheets...", "info"); const res = await sendToGAS("saveLayanan", itemPayload); if (res && res.status === 'success') { showToast("Layanan berhasil disimpan ke Google Sheets", "success"); } else { showToast("Tersimpan secara lokal (Cek koneksi Apps Script)", "error"); } } function editLayanan(id) { openModalLayanan(id); } async function deleteLayanan(id) { masterLayanan = masterLayanan.filter(l => l.id !== id); cartSelected = cartSelected.filter(c => c.id !== id); filterCalcLayanan(); renderKatalogTable(); renderCartList(); showToast("Menghapus dari Google Sheets...", "info"); const res = await sendToGAS("deleteLayanan", { id: id }); if (res && res.status === 'success') { showToast("Layanan berhasil dihapus dari Google Sheets", "success"); } else { showToast("Dihapus secara lokal", "info"); } } function openModalKategori() { document.getElementById('modal-kategori').classList.remove('hidden'); renderKategoriList(); } async function closeModalKategori() { document.getElementById('modal-kategori').classList.add('hidden'); renderCategoryDropdowns(); filterCalcLayanan(); renderKatalogTable(); // Sync category list to settings in GAS appSettings.kategoriList = JSON.stringify(masterKategori); await sendToGAS("savePengaturan", appSettings); } function renderKategoriList() { const container = document.getElementById('kategori-list-container'); if (!container) return; container.innerHTML = masterKategori.map(k => `
${k}
`).join(''); } function submitTambahKategori(e) { e.preventDefault(); const input = document.getElementById('kategori-input-nama'); const val = input.value.trim(); if (val && !masterKategori.includes(val)) { masterKategori.push(val); input.value = ''; renderKategoriList(); showToast("Kategori baru ditambahkan", "success"); } } function deleteKategori(namaKat) { masterKategori = masterKategori.filter(k => k !== namaKat); renderKategoriList(); showToast("Kategori dihapus", "info"); } function populateSettingsForm() { document.getElementById('setting-nama-klinik').value = appSettings.namaKlinik; document.getElementById('setting-deskripsi').value = appSettings.deskripsi; document.getElementById('setting-judul-struk').value = appSettings.judulStruk; document.getElementById('setting-catatan-struk').value = appSettings.catatanStruk; const radios = document.getElementsByName('theme_option'); radios.forEach(r => { if (r.value === appSettings.theme) r.checked = true; }); } function handleLogoUpload(e) { const file = e.target.files[0]; if (file) { const reader = new FileReader(); reader.onload = function(evt) { const img = new Image(); img.onload = function() { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); const maxSize = 180; // Resize logo agar ukuran Base64 sangat kecil (<10KB) let width = img.width; let height = img.height; if (width > height) { if (width > maxSize) { height *= maxSize / width; width = maxSize; } } else { if (height > maxSize) { width *= maxSize / height; height = maxSize; } } canvas.width = width; canvas.height = height; ctx.drawImage(img, 0, 0, width, height); appSettings.logoUrl = canvas.toDataURL('image/png', 0.8); applyBrandingUI(); showToast("Logo diunggah & dioptimalkan untuk Google Sheets", "success"); }; img.src = evt.target.result; }; reader.readAsDataURL(file); } } function removeLogo() { appSettings.logoUrl = ""; document.getElementById('setting-logo-file').value = ""; applyBrandingUI(); showToast("Logo dikembalikan ke ikon default", "info"); } function previewTheme(themeClass) { appSettings.theme = themeClass; applyBrandingUI(); } async function savePengaturan(e) { e.preventDefault(); appSettings.namaKlinik = document.getElementById('setting-nama-klinik').value.trim(); appSettings.deskripsi = document.getElementById('setting-deskripsi').value.trim(); appSettings.judulStruk = document.getElementById('setting-judul-struk').value.trim(); appSettings.catatanStruk = document.getElementById('setting-catatan-struk').value.trim(); appSettings.kategoriList = JSON.stringify(masterKategori); applyBrandingUI(); showToast("Menyimpan pengaturan ke Google Sheets...", "info"); const res = await sendToGAS("savePengaturan", appSettings); if (res && res.status === "success") { showToast("Pengaturan klinik berhasil disimpan ke Google Sheets", "success"); } else { showToast("Gagal menyimpan ke Spreadsheet (Cek URL Deployment)", "error"); } } function showToast(msg, type = "info") { const container = document.getElementById('toast-container'); const toast = document.createElement('div'); let iconClass = "fa-circle-info text-blue-400"; if (type === "success") iconClass = "fa-circle-check text-emerald-400"; if (type === "error") iconClass = "fa-circle-xmark text-rose-400"; toast.className = "pointer-events-auto flex items-center gap-3 px-4 py-3 rounded-2xl bg-slate-900 text-white text-xs shadow-xl transition transform translate-y-5 opacity-0"; toast.innerHTML = `${msg}`; container.appendChild(toast); setTimeout(() => { toast.classList.remove('translate-y-5', 'opacity-0'); }, 10); setTimeout(() => { toast.classList.add('opacity-0'); setTimeout(() => toast.remove(), 300); }, 3000); }