Thursday, 3 July 2025

Gemini - Code dan Spreadsheet




https://gemini.google.com/app/f77ddcb50af94215?hl=id

PROMPT

Buatkan sebuah aplikasi web pendaftaran sekolah sederhana berbasis HTML, CSS, dan JavaScript, dengan fitur sebagai berikut:

✅ Fitur Utama:

Formulir pendaftaran yang mencakup field berikut:

Nama Lengkap

NISN

Email

No. HP

Jenis Kelamin (Radio button: Laki-laki / Perempuan)

Pilihan Jurusan (Dropdown: RPL, TKJ, DKV, TBSM, Akuntansi)

Alamat Lengkap (Textarea)

Tombol Submit, yang jika diklik:

Validasi semua input tidak boleh kosong

Menyimpan data ke Google Spreadsheet melalui Google Apps Script Web Apps (POST ke URL)

Menampilkan notifikasi “Pendaftaran berhasil” tanpa reload halaman

Gunakan desain yang responsif dan bersih:

Styling dengan CSS sederhana (boleh pakai Bootstrap jika perlu)

Layout rapi dan ramah pengguna, gunakan font Google Fonts

Sertakan komentar dalam kode untuk memudahkan pengembangan lebih lanjut.

File yang dihasilkan:

index.html

style.css

script.js

Sertakan juga contoh Google Apps Script (Code.gs) yang menangani penyimpanan data ke Google Sheets:

Fungsi doPost(e) untuk menerima data dan menyimpannya ke spreadsheet

Spreadsheet memiliki header sesuai dengan field formulir

Sertakan instruksi singkat di dalam HTML dalam komentar:

👉 bagaimana cara menyebarkan Google Apps Script sebagai Web App agar form bisa digunakan.




PENJELASAN

Penjelasan:

  1. index.html:

    • Berisi struktur dasar formulir pendaftaran dengan semua field yang diminta.

    • Menggunakan Tailwind CSS (melalui CDN) untuk styling yang responsif dan bersih.

    • Menggunakan Google Fonts (Inter) untuk tipografi.

    • Terdapat area div dengan id="notification" yang akan digunakan untuk menampilkan pesan sukses atau error.

    • Sangat penting: Di dalam komentar HTML, saya telah menyertakan instruksi lengkap langkah demi langkah tentang cara menyebarkan (deploy) Google Apps Script sebagai Web App dan cara mendapatkan URL yang diperlukan.

  2. style.css:

    • File ini berisi gaya CSS kustom minimal, terutama untuk mengatur font body dan kelas notifikasi (.notification-success, .notification-error) yang akan digunakan oleh JavaScript. Sebagian besar styling dilakukan langsung dengan kelas Tailwind di HTML.

  3. script.js:

    • Menangani logika formulir.

    • Ketika formulir disubmit, ia akan:

      • Mencegah reload halaman (e.preventDefault()).

      • Melakukan validasi sisi klien untuk memastikan semua field yang wajib diisi tidak kosong.

      • Mengambil semua data formulir.

      • Menambahkan Tanggal Pendaftaran secara otomatis.

      • Mengirim data ke WEB_APP_URL (URL Google Apps Script Web App Anda) menggunakan fetch dengan metode POST.

      • Menampilkan notifikasi "Pendaftaran berhasil!" atau pesan error tanpa reload halaman.

      • Menonaktifkan tombol submit selama proses pengiriman data untuk mencegah pengiriman ganda.

    • Penting: Anda harus mengganti URL_WEB_APP_ANDA_DI_SINI dengan URL Web App Google Apps Script Anda setelah Anda menyebarkannya.

  4. Code.gs (Google Apps Script):

    • Ini adalah kode yang akan Anda tempelkan di editor Google Apps Script.

    • Fungsi doPost(e) adalah titik masuk utama ketika formulir mengirimkan data ke Web App.

    • Ia menerima data JSON dari permintaan POST.

    • Membuka Google Spreadsheet Anda (Anda perlu mengganti ID_SPREADSHEET_ANDA_DI_SINI atau memastikan nama spreadsheet sama).

    • Membaca header kolom dari baris pertama spreadsheet Anda.

    • Membangun baris baru berdasarkan data yang diterima dan urutan header.

    • Menambahkan baris baru ke sheet.

    • Mengembalikan respons JSON yang menunjukkan status sukses atau error.

Langkah-langkah Selanjutnya (Sesuai Instruksi di index.html):

  1. Buat Google Spreadsheet baru dan siapkan header kolomnya.

  2. Buka Google Apps Script dari Spreadsheet Anda.

  3. Salin dan tempel kode Code.gs ke editor Apps Script.

  4. Sangat penting: Ganti ID_SPREADSHEET_ANDA_DI_SINI di Code.gs dengan ID Spreadsheet Anda (dapat ditemukan di URL Spreadsheet, antara /d/ dan /edit). Atau, pastikan nama spreadsheet Anda persis sama dengan yang ada di Code.gs.

  5. Sebarkan (deploy) Apps Script sebagai Web App dengan akses "Anyone".

  6. Salin URL Web App yang dihasilkan.

  7. Tempelkan URL tersebut ke dalam script.js pada variabel WEB_APP_URL.

  8. Buka index.html di browser Anda dan uji aplikasinya!

Source Code

index.html


<!DOCTYPE html>
<html lang="id">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Pendaftaran Sekolah Online</title>
    <!-- Tailwind CSS CDN untuk styling responsif -->
    <script src="https://cdn.tailwindcss.com"></script>
    <!-- Google Fonts: Inter untuk tampilan yang bersih -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
    <!-- Link ke file CSS kustom -->
    <link rel="stylesheet" href="style.css">
    
    <!--
    INSTRUKSI PENTING UNTUK GOOGLE APPS SCRIPT:
    
    1.  BUAT SPREADSHEET BARU DI GOOGLE DRIVE:
        Buka Google Drive Anda, klik "+ Baru" > "Google Spreadsheet".
        Beri nama spreadsheet Anda, misalnya "Data Pendaftaran Sekolah".
        Di baris pertama (header), masukkan nama kolom berikut (harus persis sama):
        Nama Lengkap, NISN, Email, No. HP, Jenis Kelamin, Pilihan Jurusan, Alamat Lengkap, Tanggal Pendaftaran
        
    2.  BUKA GOOGLE APPS SCRIPT:
        Di Google Spreadsheet Anda, pergi ke menu "Ekstensi" > "Apps Script".
        Ini akan membuka editor Apps Script di tab baru.
        
    3.  SALIN KODE Code.gs:
        Hapus semua kode yang ada di editor Apps Script (biasanya ada fungsi myFunction()).
        Salin dan tempel seluruh kode dari file Code.gs yang saya berikan ke editor Apps Script.
        
    4.  SIMPAN PROYEK APPS SCRIPT:
        Klik ikon disket (Save project) di toolbar atau tekan Ctrl + S (Cmd + S di Mac).
        Beri nama proyek Anda, misalnya "PendaftaranSekolahWebApp".
        
    5.  SEBARKAN (DEPLOY) SEBAGAI WEB APP:
        Di editor Apps Script, klik menu "Deploy" (Sebarkan) > "New deployment" (Deployment baru).
        Klik ikon roda gigi (Select type) dan pilih "Web app".
        
        Konfigurasi Deployment:
        - Description: (Opsional, misalnya "Form Pendaftaran Sekolah")
        - Execute as: "Me" (alamat email Anda)
        - Who has access: "Anyone" (Siapa saja) - PENTING agar formulir bisa diakses publik.
        
        Klik "Deploy" (Sebarkan).
        
    6.  OTORISASI AKSES:
        Anda mungkin akan diminta untuk mengotorisasi proyek. Ikuti langkah-langkahnya:
        - Klik "Authorize access".
        - Pilih akun Google Anda.
        - Klik "Advanced" (Lanjutan) > "Go to [Nama Proyek Anda] (unsafe)".
        - Klik "Allow" (Izinkan).
        
    7.  SALIN URL WEB APP:
        Setelah berhasil deploy, Anda akan melihat dialog "Deployment successful".
        Salin "Web app URL" yang diberikan. Ini adalah URL yang akan Anda gunakan di file script.js.
        
    8.  TEMPEL URL DI script.js:
        Buka file script.js Anda.
        Cari baris `const WEB_APP_URL = 'URL_WEB_APP_ANDA_DI_SINI';`
        Ganti 'URL_WEB_APP_ANDA_DI_SINI' dengan URL Web App yang baru saja Anda salin.
        
    9.  SELESAI!
        Sekarang Anda bisa membuka file index.html di browser Anda, mengisi formulir, dan data akan tersimpan otomatis ke Google Spreadsheet Anda.
    -->
</head>
<body class="bg-gray-100 font-inter text-gray-800">
    <div class="min-h-screen flex items-center justify-center p-4">
        <div class="bg-white p-8 rounded-lg shadow-xl w-full max-w-2xl border border-gray-200">
            <h1 class="text-3xl font-bold text-center text-indigo-700 mb-6">Pendaftaran Siswa Baru</h1>
            <p class="text-center text-gray-600 mb-8">Isi formulir di bawah ini untuk mendaftar ke sekolah kami.</p>

            <form id="registrationForm" class="space-y-6">
                <div>
                    <label for="namaLengkap" class="block text-sm font-medium text-gray-700 mb-1">Nama Lengkap</label>
                    <input type="text" id="namaLengkap" name="Nama Lengkap" required
                           class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
                </div>

                <div>
                    <label for="nisn" class="block text-sm font-medium text-gray-700 mb-1">NISN</label>
                    <input type="text" id="nisn" name="NISN" required
                           class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
                </div>

                <div>
                    <label for="email" class="block text-sm font-medium text-gray-700 mb-1">Email</label>
                    <input type="email" id="email" name="Email" required
                           class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
                </div>

                <div>
                    <label for="noHp" class="block text-sm font-medium text-gray-700 mb-1">No. HP</label>
                    <input type="tel" id="noHp" name="No. HP" required
                           class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
                </div>

                <div>
                    <label class="block text-sm font-medium text-gray-700 mb-2">Jenis Kelamin</label>
                    <div class="mt-1 flex space-x-4">
                        <label class="inline-flex items-center">
                            <input type="radio" name="Jenis Kelamin" value="Laki-laki" required
                                   class="form-radio h-4 w-4 text-indigo-600 transition duration-150 ease-in-out">
                            <span class="ml-2 text-gray-700">Laki-laki</span>
                        </label>
                        <label class="inline-flex items-center">
                            <input type="radio" name="Jenis Kelamin" value="Perempuan" required
                                   class="form-radio h-4 w-4 text-indigo-600 transition duration-150 ease-in-out">
                            <span class="ml-2 text-gray-700">Perempuan</span>
                        </label>
                    </div>
                </div>

                <div>
                    <label for="pilihanJurusan" class="block text-sm font-medium text-gray-700 mb-1">Pilihan Jurusan</label>
                    <select id="pilihanJurusan" name="Pilihan Jurusan" required
                            class="mt-1 block w-full pl-3 pr-10 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
                        <option value="">-- Pilih Jurusan --</option>
                        <option value="RPL">Rekayasa Perangkat Lunak (RPL)</option>
                        <option value="TKJ">Teknik Komputer dan Jaringan (TKJ)</option>
                        <option value="DKV">Desain Komunikasi Visual (DKV)</option>
                        <option value="TBSM">Teknik Bisnis Sepeda Motor (TBSM)</option>
                        <option value="Akuntansi">Akuntansi</option>
                    </select>
                </div>

                <div>
                    <label for="alamatLengkap" class="block text-sm font-medium text-gray-700 mb-1">Alamat Lengkap</label>
                    <textarea id="alamatLengkap" name="Alamat Lengkap" rows="4" required
                              class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"></textarea>
                </div>

                <button type="submit"
                        class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 transition duration-150 ease-in-out">
                    Daftar Sekarang
                </button>
            </form>

            <!-- Area Notifikasi -->
            <div id="notification" class="mt-6 p-3 rounded-md text-center hidden" role="alert">
                <p id="notification-message" class="font-medium"></p>
            </div>
        </div>
    </div>

    <!-- Link ke file JavaScript kustom -->
    <script src="script.js"></script>
</body>
</html>

style.css

/* style.css */

/* Mengatur font dasar untuk seluruh body */
body {
    font-family: 'Inter', sans-serif;
}

/* Anda bisa menambahkan gaya kustom lainnya di sini jika diperlukan */
/* Contoh: */
/* .custom-button {
    background-color: #4CAF50;
    color: white;
    padding: 10px 20px;
    border-radius: 5px;
    cursor: pointer;
} */

/* Gaya untuk notifikasi sukses */
.notification-success {
    background-color: #d4edda; /* bg-green-100 */
    color: #155724; /* text-green-800 */
    border: 1px solid #c3e6cb; /* border-green-200 */
}

/* Gaya untuk notifikasi error */
.notification-error {
    background-color: #f8d7da; /* bg-red-100 */
    color: #721c24; /* text-red-800 */
    border: 1px solid #f5c6cb; /* border-red-200 */
}

script.js

// script.js

document.addEventListener('DOMContentLoaded', () => {
    // URL Web App Google Apps Script Anda
    // GANTI 'URL_WEB_APP_ANDA_DI_SINI' dengan URL yang Anda dapatkan setelah deploy Apps Script
    const WEB_APP_URL = 'URL_WEB_APP_ANDA_DI_SINI'; 

    const registrationForm = document.getElementById('registrationForm');
    const notificationDiv = document.getElementById('notification');
    const notificationMessage = document.getElementById('notification-message');

    // Fungsi untuk menampilkan notifikasi
    function showNotification(message, type) {
        notificationMessage.textContent = message;
        notificationDiv.classList.remove('hidden', 'notification-success', 'notification-error');
        if (type === 'success') {
            notificationDiv.classList.add('notification-success');
        } else if (type === 'error') {
            notificationDiv.classList.add('notification-error');
        }
        // Sembunyikan notifikasi setelah 5 detik
        setTimeout(() => {
            notificationDiv.classList.add('hidden');
        }, 5000);
    }

    // Event listener untuk submit formulir
    registrationForm.addEventListener('submit', async (e) => {
        e.preventDefault(); // Mencegah reload halaman

        // 1. Validasi Input Tidak Boleh Kosong
        let isValid = true;
        const formData = new FormData(registrationForm);
        const data = {};

        for (let [key, value] of formData.entries()) {
            // Trim whitespace dari input teks dan textarea
            if (typeof value === 'string') {
                value = value.trim();
            }
            if (!value) {
                isValid = false;
                // Anda bisa menambahkan feedback visual di sini, misalnya border merah pada input
                // console.error(`Input '${key}' tidak boleh kosong.`);
            }
            data[key] = value;
        }

        // Validasi khusus untuk radio button (Jenis Kelamin)
        const jenisKelaminSelected = document.querySelector('input[name="Jenis Kelamin"]:checked');
        if (!jenisKelaminSelected) {
            isValid = false;
            // console.error('Jenis Kelamin harus dipilih.');
        } else {
            data['Jenis Kelamin'] = jenisKelaminSelected.value;
        }

        // Validasi untuk dropdown (Pilihan Jurusan)
        if (!data['Pilihan Jurusan']) {
            isValid = false;
            // console.error('Pilihan Jurusan harus dipilih.');
        }

        if (!isValid) {
            showNotification('Mohon lengkapi semua field yang wajib diisi.', 'error');
            return; // Hentikan proses jika ada validasi yang gagal
        }

        // Tambahkan tanggal pendaftaran
        data['Tanggal Pendaftaran'] = new Date().toLocaleString('id-ID', {
            year: 'numeric',
            month: '2-digit',
            day: '2-digit',
            hour: '2-digit',
            minute: '2-digit',
            second: '2-digit'
        });

        // Tampilkan loading atau nonaktifkan tombol submit
        const submitButton = registrationForm.querySelector('button[type="submit"]');
        submitButton.textContent = 'Mengirim...';
        submitButton.disabled = true;
        submitButton.classList.add('opacity-50', 'cursor-not-allowed');

        try {
            // 2. Mengirim data ke Google Apps Script Web App
            const response = await fetch(WEB_APP_URL, {
                method: 'POST',
                mode: 'no-cors', // Penting untuk menghindari masalah CORS dengan Apps Script
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify(data),
            });

            // Karena mode 'no-cors', kita tidak bisa membaca response.ok atau response.json()
            // Kita asumsikan sukses jika tidak ada error jaringan
            showNotification('Pendaftaran berhasil!', 'success');
            registrationForm.reset(); // Reset formulir setelah sukses
        } catch (error) {
            console.error('Error saat mengirim data:', error);
            showNotification('Terjadi kesalahan saat pendaftaran. Mohon coba lagi.', 'error');
        } finally {
            // Aktifkan kembali tombol submit
            submitButton.textContent = 'Daftar Sekarang';
            submitButton.disabled = false;
            submitButton.classList.remove('opacity-50', 'cursor-not-allowed');
        }
    });
});

Code.gs

// Code.gs

/**
 * Fungsi ini akan dieksekusi ketika ada permintaan POST ke Web App.
 * Data dari formulir HTML akan diterima di sini.
 * @param {Object} e - Objek event yang berisi data permintaan.
 */
function doPost(e) {
  // Pastikan permintaan memiliki konten
  if (typeof e !== 'undefined' && typeof e.postData !== 'undefined') {
    try {
      // Parsing data JSON dari body permintaan
      var data = JSON.parse(e.postData.contents);

      // Dapatkan spreadsheet aktif berdasarkan nama atau ID
      // GANTI 'Data Pendaftaran Sekolah' dengan nama spreadsheet Anda
      var spreadsheetId = 'ID_SPREADSHEET_ANDA_DI_SINI'; // Opsional: Ganti dengan ID Spreadsheet Anda untuk akses langsung
      var ss = SpreadsheetApp.openById(spreadsheetId) || SpreadsheetApp.openByName('Data Pendaftaran Sekolah');
      
      // Dapatkan sheet pertama (atau ganti dengan nama sheet Anda jika berbeda)
      var sheet = ss.getSheets()[0]; // Atau ss.getSheetByName('Nama Sheet Anda');

      // Dapatkan header kolom dari baris pertama
      var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];

      // Buat array untuk baris baru berdasarkan header
      var newRow = [];
      for (var i = 0; i < headers.length; i++) {
        var header = headers[i];
        // Pastikan key ada di data yang diterima, jika tidak, gunakan string kosong
        newRow.push(data[header] || ''); 
      }

      // Tambahkan baris baru ke sheet
      sheet.appendRow(newRow);

      // Kembalikan respons sukses
      return ContentService.createTextOutput(JSON.stringify({
        'status': 'success',
        'message': 'Data berhasil disimpan.'
      })).setMimeType(ContentService.MimeType.JSON);

    } catch (error) {
      // Tangani kesalahan jika parsing JSON gagal atau ada masalah lain
      Logger.log(error.toString()); // Log error untuk debugging di Apps Script
      return ContentService.createTextOutput(JSON.stringify({
        'status': 'error',
        'message': 'Terjadi kesalahan saat menyimpan data: ' + error.message
      })).setMimeType(ContentService.MimeType.JSON);
    }
  } else {
    // Jika tidak ada data POST
    return ContentService.createTextOutput(JSON.stringify({
      'status': 'error',
      'message': 'Tidak ada data yang diterima.'
    })).setMimeType(ContentService.MimeType.JSON);
  }
}

// Fungsi opsional untuk menguji doPost secara manual dari editor Apps Script
// function testDoPost() {
//   var mockEvent = {
//     postData: {
//       contents: JSON.stringify({
//         "Nama Lengkap": "Nama Uji Coba",
//         "NISN": "1234567890",
//         "Email": "uji@coba.com",
//         "No. HP": "081234567890",
//         "Jenis Kelamin": "Laki-laki",
//         "Pilihan Jurusan": "RPL",
//         "Alamat Lengkap": "Jl. Uji Coba No. 1, Kota Uji",
//         "Tanggal Pendaftaran": new Date().toLocaleString('id-ID')
//       }),
//       type: "application/json"
//     }
//   };
//   var response = doPost(mockEvent);
//   Logger.log(response.getContent());
// }


No comments:

Post a Comment

Job Builder

  https://www.youtube.com/watch?v=5b15m4N1Heg