https://docs.google.com/spreadsheets/d/1Xga5ntrruM1PC3bCCH_kJjp6XcMielI2ISVZqrkHsKE/edit?gid=0#gid=0
Code.gs
/*************************
* KONFIGURASI
*************************/
const SPREADSHEET_ID = '1Xga5ntrruM1PC3bCCH_kJjp6XcMielI2ISVZqrkHsKE';
const SHEET_NAME = 'Peserta';
/*************************
* ENTRY POINT WEB APP
*************************/
function doGet() {
return HtmlService.createHtmlOutputFromFile('index')
.setTitle('Manajemen Peserta Pelatihan')
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
/*************************
* HELPER
*************************/
function getSheet() {
const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
const sheet = ss.getSheetByName(SHEET_NAME);
if (!sheet) throw new Error('Sheet "Peserta" tidak ditemukan');
return sheet;
}
/*************************
* READ
*************************/
function getPeserta() {
const sheet = getSheet();
const lastRow = sheet.getLastRow();
if (lastRow < 2) return [];
const data = sheet.getRange(2, 1, lastRow - 1, 4).getValues();
return data.map(r => ({
id: r[0],
nama: r[1],
email: r[2],
kelas: r[3]
}));
}
/*************************
* CREATE
*************************/
function addPeserta(p) {
const sheet = getSheet();
sheet.appendRow([
Date.now(),
p.nama,
p.email,
p.kelas
]);
return true;
}
/*************************
* UPDATE
*************************/
function updatePeserta(p) {
const sheet = getSheet();
const ids = sheet.getRange(2, 1, sheet.getLastRow() - 1, 1).getValues();
for (let i = 0; i < ids.length; i++) {
if (ids[i][0] == p.id) {
sheet.getRange(i + 2, 2, 1, 3).setValues([[
p.nama,
p.email,
p.kelas
]]);
return true;
}
}
return false;
}
/*************************
* DELETE
*************************/
function deletePeserta(id) {
const sheet = getSheet();
const ids = sheet.getRange(2, 1, sheet.getLastRow() - 1, 1).getValues();
for (let i = 0; i < ids.length; i++) {
if (ids[i][0] == id) {
sheet.deleteRow(i + 2);
return true;
}
}
return false;
}
Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap 5 -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
background-color: #f8f9fa;
}
.hero {
background: linear-gradient(120deg, #0d6efd, #6610f2);
color: white;
padding: 80px 20px;
border-radius: 0 0 40px 40px;
}
.card {
border-radius: 16px;
}
.btn {
border-radius: 30px;
}
</style>
</head>
<body>
<!-- HERO -->
<section class="hero text-center">
<div class="container">
<h1 class="display-5 fw-bold">Manajemen Peserta Pelatihan</h1>
<p class="lead mt-3">
Web App SPA berbasis Google Apps Script & Google Sheet
</p>
</div>
</section>
<!-- CONTENT -->
<div class="container mt-5">
<div class="row">
<!-- FORM -->
<div class="col-md-4 mb-4">
<div class="card shadow-sm">
<div class="card-body">
<h5 class="card-title mb-3">Form Peserta</h5>
<input type="hidden" id="id">
<div class="mb-2">
<label class="form-label">Nama</label>
<input id="nama" class="form-control">
</div>
<div class="mb-2">
<label class="form-label">Email</label>
<input id="email" class="form-control">
</div>
<div class="mb-3">
<label class="form-label">Kelas</label>
<input id="kelas" class="form-control">
</div>
<div class="d-grid gap-2">
<button class="btn btn-primary" onclick="simpan()">Simpan</button>
<button class="btn btn-outline-secondary" onclick="resetForm()">Batal</button>
</div>
</div>
</div>
</div>
<!-- TABLE -->
<div class="col-md-8">
<div class="card shadow-sm">
<div class="card-body">
<h5 class="card-title mb-3">Daftar Peserta</h5>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead class="table-light">
<tr>
<th>Nama</th>
<th>Email</th>
<th>Kelas</th>
<th width="140">Aksi</th>
</tr>
</thead>
<tbody id="dataPeserta"></tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- SCRIPT -->
<script>
let peserta = [];
let modeEdit = false;
document.addEventListener('DOMContentLoaded', loadPeserta);
function loadPeserta() {
google.script.run
.withSuccessHandler(data => {
peserta = data || [];
render();
})
.withFailureHandler(err => {
alert('Gagal memuat data: ' + err.message);
})
.getPeserta();
}
function render() {
const tbody = document.getElementById('dataPeserta');
tbody.innerHTML = '';
if (peserta.length === 0) {
tbody.innerHTML = `
<tr>
<td colspan="4" class="text-center text-muted">
Belum ada data
</td>
</tr>`;
return;
}
peserta.forEach(p => {
tbody.innerHTML += `
<tr>
<td>${p.nama}</td>
<td>${p.email}</td>
<td>${p.kelas}</td>
<td>
<button class="btn btn-sm btn-warning me-1"
onclick="editPeserta(${p.id})">Edit</button>
<button class="btn btn-sm btn-danger"
onclick="hapusPeserta(${p.id})">Hapus</button>
</td>
</tr>`;
});
}
function simpan() {
const data = {
id: document.getElementById('id').value,
nama: document.getElementById('nama').value,
email: document.getElementById('email').value,
kelas: document.getElementById('kelas').value
};
const callback = () => {
resetForm();
loadPeserta();
};
if (modeEdit) {
google.script.run.withSuccessHandler(callback).updatePeserta(data);
} else {
google.script.run.withSuccessHandler(callback).addPeserta(data);
}
}
function editPeserta(id) {
const p = peserta.find(x => x.id == id);
if (!p) return;
document.getElementById('id').value = p.id;
document.getElementById('nama').value = p.nama;
document.getElementById('email').value = p.email;
document.getElementById('kelas').value = p.kelas;
modeEdit = true;
}
function hapusPeserta(id) {
if (!confirm('Hapus data ini?')) return;
google.script.run.withSuccessHandler(loadPeserta).deletePeserta(id);
}
function resetForm() {
document.getElementById('id').value = '';
document.getElementById('nama').value = '';
document.getElementById('email').value = '';
document.getElementById('kelas').value = '';
modeEdit = false;
}
</script>
</body>
</html>


Tidak ada komentar:
Posting Komentar