EN
Tutorial Praktis

Tutorial Apps Script Web App

Bangun portal pengiriman feedback langsung menggunakan URL Google Apps Script Web App.

Pelajari cara membangun portal pengiriman feedback full-stack menggunakan Google Apps Script tanpa kredensial GCP atau batas kuota API.


1. Setup Google Sheets & Apps Script

  1. Buat Google Sheet baru bernama Feedback Pengguna.
  2. Beri nama tab sheet feedback.
  3. Tambahkan header kolom di Baris 1: id, author, rating, comment.
  4. Buka Extensions -> Apps Script dan tempelkan skrip Code.gs:
Code.gs
function doGet(e) {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(e.parameter.sheet || 'feedback');
  const values = sheet.getRange(e.parameter.range || 'A1:Z100').getValues();
  return ContentService.createTextOutput(JSON.stringify(values)).setMimeType(ContentService.MimeType.JSON);
}

function doPost(e) {
  const data = JSON.parse(e.postData.contents);
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(data.sheet || 'feedback');
  if (data.values) {
    data.values.forEach(r => sheet.appendRow(r));
  }
  return ContentService.createTextOutput(JSON.stringify({ success: true })).setMimeType(ContentService.MimeType.JSON);
}
  1. Klik Deploy -> New Deployment -> Pilih Web App (Execute as: Me, Who has access: Anyone).
  2. Salin URL Web App ke dalam file .env:
.env
GSHEET_APPSCRIPT_URL=https://script.google.com/macros/s/AKfycb.../exec

2. Implementasi Komponen Vue

pages/feedback.vue
<script setup lang="ts">
interface FeedbackItem {
  id: string
  author: string
  rating: string
  comment: string
}

// 1. Baca Data
const { data: items, pending, refresh } = await useGSheetAsObject<FeedbackItem[]>('A1:D50', {
  sheet: 'feedback'
})

// 2. Tulis Data
const { append } = useGSheetWrite({ sheet: 'feedback' })

const author = ref('')
const rating = ref('5')
const comment = ref('')
const isSaving = ref(false)

const submitComment = async () => {
  if (!author.value || !comment.value) return
  isSaving.value = true

  try {
    await append('A1:D1', [
      [String(Date.now()), author.value, rating.value, comment.value]
    ])
    author.value = ''
    comment.value = ''
    await refresh()
  }
  finally {
    isSaving.value = false
  }
}
</script>

<template>
  <div class="feedback-page">
    <h1>Kirim Feedback Pengguna</h1>

    <form @submit.prevent="submitComment">
      <input
        v-model="author"
        placeholder="Nama Kamu"
        required
      >
      <select v-model="rating">
        <option value="5">
          5 Bintang
        </option>
        <option value="4">
          4 Bintang
        </option>
        <option value="3">
          3 Bintang
        </option>
      </select>
      <textarea
        v-model="comment"
        placeholder="Komentar / Masukan"
        required
      />
      <button
        :disabled="isSaving"
        type="submit"
      >
        {{ isSaving ? 'Sending...' : 'Kirim Feedback' }}
      </button>
    </form>

    <hr>

    <div v-if="pending">
      Memuat komentar...
    </div>
    <ul v-else>
      <li
        v-for="item in items"
        :key="item.id"
      >
        <strong>{{ item.author }}</strong> ({{ item.rating }} Bintang): {{ item.comment }}
      </li>
    </ul>
  </div>
</template>