Cara bayar QRIS:
1. Buka app dompet digital atau m-banking kamu
2. Pilih menu bayar / scan QR
3. Scan kode di atas & pastikan nominal sesuai
4. Konfirmasi bayar, lalu klik tombol di bawah
✓
Booking berhasil!
Pembayaran kamu sedang kami verifikasi. Konfirmasi dikirim via WhatsApp dalam 5–15 menit.
focale.lab
Admin Dashboard
Username atau password salah.
f.lab admin
Selamat datang 👋
FOCALE LAB ADMIN
Total Booking
0
semua waktu
Menunggu Konfirmasi
0
perlu tindakan
Dikonfirmasi
0
sesi terjadwal
Pendapatan Est.
0
dari booking confirm
Booking Terbaru 5 terakhir
Manajemen Booking
Belum ada booking masuk.
Kelola Slot Waktu
Klik slot untuk toggle Tersedia / Penuh
🟢 Tersedia 🔴 Penuh
Kelola Galeri
Klik foto untuk ganti gambar
5 Foto Galeri Website
Label Foto
Kelola Paket
Preview di Website
Pengaturan Admin
🔗 Integrasi Google Sheets
Setup (ikuti urutan ini):
1. Buka sheets.google.com → buat spreadsheet baru → beri nama Focale Lab Booking
2. Copy ID dari URL spreadsheet: docs.google.com/spreadsheets/d/INI-ID-NYA/edit
3. Buka script.google.com → New Project → hapus semua kode → paste kode di bawah
4. Ganti SPREADSHEET_ID_KAMU dengan ID yang dicopy tadi
5. Klik Deploy → New deployment → Web app
6. Execute as: Me · Who has access: Anyone → Deploy
7. Copy URL deployment → paste di kolom webhook di bawah → Simpan
Kode Google Apps Script
// FOCALE LAB — Google Sheets Webhook v2
// Ganti SPREADSHEET_ID_KAMU dengan ID spreadsheet kamu
// Deploy: Web App | Execute as: Me | Access: Anyone
var SHEET_ID = 'SPREADSHEET_ID_KAMU';
var SHEET_NAME = 'Booking';
function doPost(e) {
try {
var ss = SpreadsheetApp.openById(SHEET_ID);
var sheet = ss.getSheetByName(SHEET_NAME) || ss.insertSheet(SHEET_NAME);
var data = JSON.parse(e.postData.contents);
// Setup header jika sheet kosong
if (sheet.getLastRow() === 0) {
var headers = ['ID','Nama','WhatsApp','Paket','Durasi','Harga',
'Tanggal','Waktu','Jumlah','Catatan','Status','Dibuat','Dikonfirmasi'];
sheet.appendRow(headers);
sheet.getRange(1,1,1,13)
.setBackground('#3d3db6').setFontColor('#defd7f')
.setFontWeight('bold').setHorizontalAlignment('center');
sheet.setFrozenRows(1);
sheet.setColumnWidths(1,13,130);
}
// MODE: confirm → cari baris yg ada, update status & tanggal konfirmasi
if (data.mode === 'confirm') {
var lastRow = sheet.getLastRow();
var found = false;
for (var r = 2; r <= lastRow; r++) {
if (sheet.getRange(r, 1).getValue() == data.id) {
sheet.getRange(r, 11).setValue('✅ Dikonfirmasi');
sheet.getRange(r, 13).setValue(data.dikonfirmasi);
sheet.getRange(r, 1, 1, 13).setBackground('#dcfce7');
found = true;
break;
}
}
// Jika belum ada di sheet, insert sebagai baris baru
if (!found) {
sheet.appendRow([data.id, data.nama, data.whatsapp, data.paket,
data.durasi, data.harga, data.tanggal, data.waktu,
data.jumlah, data.catatan, '✅ Dikonfirmasi', data.dibuat, data.dikonfirmasi]);
sheet.getRange(sheet.getLastRow(),1,1,13).setBackground('#dcfce7');
}
// MODE: insert → tambah baris baru saat booking masuk
} else {
sheet.appendRow([data.id, data.nama, data.whatsapp, data.paket,
data.durasi, data.harga, data.tanggal, data.waktu,
data.jumlah, data.catatan, '⏳ Menunggu', data.dibuat, '-']);
sheet.getRange(sheet.getLastRow(),1,1,13).setBackground('#fef9c3');
}
SpreadsheetApp.flush();
return ContentService
.createTextOutput(JSON.stringify({status:'ok'}))
.setMimeType(ContentService.MimeType.JSON);
} catch(err) {
return ContentService
.createTextOutput(JSON.stringify({status:'error',msg:err.toString()}))
.setMimeType(ContentService.MimeType.JSON);
}
}