Bertindaklah sebagai Web Developer & System Analyst yang berpengalaman membangun aplikasi pemesanan makanan berbasis web menggunakan Google Apps Script dan Google Spreadsheet sebagai backend.
๐งฉ TUJUAN APLIKASI
Buat Aplikasi Form Pemesanan Makanan Online Modern yang:
-
Digunakan oleh pelanggan untuk memesan makanan
-
Terintegrasi langsung dengan Google Spreadsheet
-
Dapat dipasang di Google Sites
-
Aman, responsif, dan mudah digunakan
๐ ️ TEKNOLOGI YANG WAJIB DIGUNAKAN
Frontend
-
HTML5
-
CSS modern (inline style / Tailwind-like style)
-
JavaScript (Vanilla JS)
-
Fetch API
-
FormData
-
Desain card modern (rounded, shadow, gradient)
-
Mobile-friendly
Backend
-
Google Apps Script (Web App)
-
Fungsi doGet(e) dan doPost(e)
-
Google Spreadsheet sebagai database
๐งพ FITUR WAJIB FORM PEMESANAN
1️⃣ Identitas Pemesan
-
Nama Pemesan (input text, required)
-
Nomor WhatsApp (input tel, required, validasi angka)
-
Alamat Pengiriman (textarea, required)
2️⃣ Pemilihan Menu (AUTO-FILL)
3️⃣ Detail Pesanan
4️⃣ Validasi & Keamanan
-
Validasi HTML5 (required)
-
Validasi JavaScript (jumlah tidak boleh 0)
-
Validasi harga sesuai menu (anti manipulasi)
-
SECRET TOKEN dikirim bersama form
-
Token diverifikasi di Apps Script
5️⃣ Pengiriman Data
๐ STRUKTUR GOOGLE SPREADSHEET
Sheet: Menu
| nama_menu | harga |
|---|
| Ayam Geprek | 15000 |
| Nasi Goreng | 13000 |
Sheet: Pesanan
| waktu | nama | whatsapp | alamat | menu | harga | qty | total | catatan |
๐ ALUR APLIKASI
-
Halaman dibuka
-
Menu di-load dari Spreadsheet
-
User memilih menu → harga otomatis muncul
-
User mengisi jumlah → total otomatis dihitung
-
User klik Pesan Sekarang
-
Data dikirim ke Apps Script
-
Data masuk ke Spreadsheet
-
Pesan sukses ditampilkan
๐ง OUTPUT YANG HARUS DIHASILKAN AI
Buatkan secara lengkap:
-
Kode HTML + CSS + JavaScript (Frontend)
-
Kode Google Apps Script
-
Contoh validasi token
-
Contoh struktur Spreadsheet
Code.gs
const SPREADSHEET_ID = "GANTI_DENGAN_ID_SPREADSHEET";
const SECRET_TOKEN = "TOKEN_RAHASIA_12345";
function doGet(e) {
const action = e.parameter.action;
const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
// ===== AMBIL MENU =====
if (action === "menu") {
const sheet = ss.getSheetByName("Menu");
const data = sheet.getDataRange().getValues();
data.shift(); // hapus header
const menu = data.map(r => ({
nama: r[0],
harga: r[1]
}));
return jsonOutput({
status: "ok",
menu: menu
});
}
return jsonOutput({ status: "error", message: "Invalid action" });
}
function doPost(e) {
const params = e.parameter;
// ===== VALIDASI TOKEN =====
if (params.token !== SECRET_TOKEN) {
return jsonOutput({ status: "error", message: "Token tidak valid" });
}
const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
const sheetMenu = ss.getSheetByName("Menu");
const sheetPesanan = ss.getSheetByName("Pesanan");
// ===== CEK MENU & HARGA (ANTI MANIPULASI) =====
const menuData = sheetMenu.getDataRange().getValues();
menuData.shift();
const found = menuData.find(r => r[0] === params.menu);
if (!found) {
return jsonOutput({ status: "error", message: "Menu tidak ditemukan" });
}
const hargaValid = Number(found[1]);
const qty = Number(params.qty);
const totalValid = hargaValid * qty;
if (Number(params.total) !== totalValid) {
return jsonOutput({ status: "error", message: "Total tidak valid" });
}
// ===== SIMPAN PESANAN =====
sheetPesanan.appendRow([
new Date(),
params.nama,
params.whatsapp,
params.alamat,
params.menu,
hargaValid,
qty,
totalValid,
params.catatan || ""
]);
return jsonOutput({ status: "success" });
}
function jsonOutput(obj) {
return ContentService
.createTextOutput(JSON.stringify(obj))
.setMimeType(ContentService.MimeType.JSON);
}
HTML Google Site Embedded
<div style="max-width:720px;margin:auto;font-family:Inter,Arial;padding:18px;
background:linear-gradient(180deg,#f7fcff,#fff);border-radius:14px;
box-shadow:0 10px 30px rgba(0,0,0,.08)">
<h2 style="text-align:center;color:#0b6e99">๐ฝ️ Pemesanan Makanan Online</h2>
<form id="orderForm" style="display:grid;gap:10px">
<input name="nama" placeholder="Nama Pemesan" required
style="padding:10px;border-radius:8px;border:1px solid #ccc">
<input name="whatsapp" type="tel" placeholder="No WhatsApp" required
pattern="[0-9]+" style="padding:10px;border-radius:8px;border:1px solid #ccc">
<textarea name="alamat" placeholder="Alamat Pengiriman" required
style="padding:10px;border-radius:8px;border:1px solid #ccc"></textarea>
<select id="menuSelect" name="menu" required
style="padding:10px;border-radius:8px">
<option value="">-- Pilih Menu --</option>
</select>
<input id="harga" name="harga" readonly placeholder="Harga"
style="padding:10px;border-radius:8px;background:#f3f4f6">
<input id="qty" name="qty" type="number" min="1" value="1" required
style="padding:10px;border-radius:8px">
<input id="total" name="total" readonly placeholder="Total"
style="padding:10px;border-radius:8px;background:#f3f4f6">
<textarea name="catatan" placeholder="Catatan (opsional)"
style="padding:10px;border-radius:8px"></textarea>
<button type="button" id="btnOrder"
style="padding:12px;background:#0b6e99;color:white;
border:none;border-radius:10px;font-size:16px">
๐ Pesan Sekarang
</button>
<div id="msg" style="text-align:center;font-weight:600"></div>
</form>
</div>
<script>
(() => {
const WEB_APP = "GANTI_URL_WEB_APP";
const TOKEN = "TOKEN_RAHASIA_12345";
const menuSelect = document.getElementById("menuSelect");
const harga = document.getElementById("harga");
const qty = document.getElementById("qty");
const total = document.getElementById("total");
const msg = document.getElementById("msg");
const form = document.getElementById("orderForm");
let menuData = [];
// ===== LOAD MENU =====
fetch(WEB_APP + "?action=menu")
.then(r => r.json())
.then(d => {
menuData = d.menu;
menuData.forEach((m,i)=>{
let o = document.createElement("option");
o.value = i;
o.textContent = `${m.nama} - Rp${m.harga}`;
menuSelect.appendChild(o);
});
});
// ===== AUTO FILL =====
function hitung(){
const i = menuSelect.value;
if(i==="") return;
harga.value = menuData[i].harga;
total.value = menuData[i].harga * qty.value;
}
menuSelect.onchange = hitung;
qty.oninput = hitung;
// ===== KIRIM PESANAN =====
document.getElementById("btnOrder").onclick = () => {
if(!form.reportValidity()) return;
msg.innerText = "⏳ Mengirim...";
const i = menuSelect.value;
const fd = new FormData(form);
fd.set("menu", menuData[i].nama);
fd.set("harga", menuData[i].harga);
fd.set("total", total.value);
fd.append("token", TOKEN);
const body = new URLSearchParams(fd).toString();
fetch(WEB_APP,{
method:"POST",
headers:{ "Content-Type":"application/x-www-form-urlencoded" },
body
})
.then(r=>r.json())
.then(res=>{
if(res.status==="success"){
msg.innerText="✅ Pesanan berhasil!";
form.reset();
}else{
msg.innerText="❌ "+res.message;
}
})
.catch(()=>msg.innerText="❌ Koneksi gagal");
};
})();
</script>
Tidak ada komentar:
Posting Komentar