#JP05 Cara Membuat Website Dengan Google Script




*Untuk Mendapatkan Full Script tanpa password silahkan Klik Disini*

Cara Membuat Website Dengan Google Script

1. Siapkan file yang akan ditampilkan (Contoh : Spreadsheet, GoogleDoc, dsb)

2. Copy Spreadsheets (Klik Disini)

3. Buka Apps Script , Ekstensi - Apps Script

4. Setelah lembar kerja Apps Script terbuka, maka akan terlihat beberapa file .html dan 1 file .gs
Copy Script dibawah ini untuk mengisi setiap file diatas.
Dan perhatikan ada beberapa scrip yang harus di sesuikan.

backend.gs

Copy script dibawah ini pada backend.gs
Masukkan Password Untuk Melihat Script (Password ada di dalam video)

const CONFIG = {
  INDEX: "index.html",
  NAME: "Dashboard",
  DB_ID: "1BfS6GCnVKcaXiYHcMHm79q0vjQeShxp5H4K3Qtrwt8A",
  SHEET_NAME: {
    USERS: "users"
  },
  CACHE_EXPIRED_IN_SECONDS: 21600, // 6 hours
}

class App {
  constructor() {
    this.db = SpreadsheetApp.openById(CONFIG.DB_ID)
    this.cache = CacheService.getScriptCache()
  }

  createToken(user) {
    const token = Utilities.getUuid()
    this.cache.put(token, user.email, CONFIG.CACHE_EXPIRED_IN_SECONDS)
    return token
  }

  createItemObject(keys, values) {
    const item = {}
    keys.forEach((key, index) => item[key] = values[index])
    return item
  }

  validateToken(token) {
    const email = this.cache.get(token)
    if (!email) return false
    this.cache.put(token, email, CONFIG.CACHE_EXPIRED_IN_SECONDS)
    return email
  }



  getUserByEmail(email) {
    email = email.trim().toLowerCase()
    const ws = this.db.getSheetByName(CONFIG.SHEET_NAME.USERS)
    if (!ws) throw new Error(`${CONFIG.SHEET_NAME.USERS} was not found in the database.`)
    const [keys, ...records] = ws.getDataRange().getValues()
    const indexOfEmail = keys.indexOf("User ID")
    if (indexOfEmail === -1) throw new Error(`Header 'User ID' was not found in the table.`)
    const record = records.find(v => v[indexOfEmail].toString().trim().toLocaleLowerCase() == email)
    if (!record) return
    return this.createItemObject(keys, record)
  }

  login({ email, password, token }) {
    if (token) {
      const isValidToken = this.validateToken(token)
      if (!isValidToken) throw new Error(`Token tidak valid, silahkan login ulang.`)
      return {
        user: this.getUserByEmail(isValidToken),
        token,
      }
    }
    const user = this.getUserByEmail(email)
    if (!user) throw new Error(`${email} User ID Salah.`)
    if (password !== user.password) throw new Error(`User ID and Password Salah!`)
    token = this.createToken(user)
    user.token = token
    return {
      user,
      token,
    }
  }

  logout({ token }) {
    this.cache.remove(token)
    return {
      success: true,
      message: "Anda berhasil keluar!"
    }
  }
}

const app = new App()

const login = (params) => {
  params = JSON.parse(params)
  const data = app.login(params)
  return JSON.stringify(data)
}

const logout = (params) => {
  params = JSON.parse(params)
  const data = app.logout(params)
  return JSON.stringify(data)
}

function doGet() {
  return HtmlService.createTemplateFromFile(CONFIG.INDEX)
    .evaluate()
    .setTitle(CONFIG.NAME)
    .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL)
}


function include_(filename) {
  return HtmlService.createTemplateFromFile(filename).evaluate().getContent()
}


Penjelasan!


Ganti code DB_ID diatas dengan code Spreadsheets (Perhatikan bagian gambar yang di blok dibawah)


index.html

Copy script dibawah ini pada index.html
Masukkan Password Untuk Melihat Script (Password sama dengan di atas)

<!DOCTYPE html>
<html>
  <head>
    <link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/@mdi/font@6.x/css/materialdesignicons.min.css" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css" rel="stylesheet">
    <base target="_top">
  </head>
  <body>
    <div id="app">
      <v-app>
        <my-snackbar></my-snackbar>
        <my-navbar></my-navbar>
        <v-main>
          <v-container fluid>
            <router-view></router-view>
          </v-container>
        </v-main>
        <v-footer app>
        </v-footer>
      </v-app>
    </div>

    <?!= include_("vue/index.html"); ?>
  </body>
</html>




vue/index.html

Copy script dibawah ini pada vue/index.html
Masukkan Password Untuk Melihat Script (Password sama dengan di atas)

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>

<?!= include_("utils.html"); ?>
<?!= include_("vue/vuetify.html"); ?>
<?!= include_("vue/store.html"); ?>
<?!= include_("vue/components.html"); ?>
<?!= include_("vue/router.html"); ?>

<script>
  const app = new Vue({
    el: "#app",
    vuetify,
    store,
    router,
    computed: {
      ...Vuex.mapState({
        loading: "loading",
        title: "title",
      })
    },
  })
</script>
<style>.footer,.generic-footer{margin-bottom:98px}@media (min-width:52px){.footer,.generic-footer{margin-bottom:78px}}@media (min-width:52px){.footer,.generic-footer{margin-bottom:56px}}@media (min-width:52px){.footer,.generic-footer{margin-bottom:0}}.disclaimer{position:fixed;z-index:9999999;bottom:0;right:0;border-top:2px solid #ff5c62;text-align:center;font-size:14px;font-weight:400;background-color:#fff;padding:5px 10px 5px 10px}.disclaimer a:hover{text-decoration:underline}@media (min-width:52px){.disclaimer{text-align:right;border-left:2px solid red;border-top-left-radius:10px}}@media (min-width:1920px){.disclaimer{width:20%}}</style><div class="disclaimer">Version.01.05.22 @Copyright <a title="https://www.javabitpro.com/" target="_blank" href="https://www.javabitpro.com/" style="color: black;"><b>www.javabitpro.com</b></a></div>



vue/vuetify.html

Copy script dibawah ini pada vue/vuetify.html

Masukkan Password Untuk Melihat Script (Password sama dengan di atas)

<script src="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js"></script>
<script>
  const lgith = {
    primary: '#1976D2',
    secondary: '#424242',
    accent: '#82B1FF',
    error: '#FF5252',
    info: '#2196F3',
    success: '#4CAF50',
    warning: '#FFC107',
  }
  const dark = {
    primary: '#1976D2',
    secondary: '#424242',
    accent: '#82B1FF',
    error: '#FF5252',
    info: '#2196F3',
    success: '#4CAF50',
    warning: '#FFC107',
  }
  const vuetify = new Vuetify({
    theme: {
      dark: false,
      themes: {
        lgith,
        dark,
      }
    }
  })
</script>




vue/store.html

Copy script dibawah ini pada vue/store.html

Masukkan Password Untuk Melihat Script (Password sama dengan di atas)

<script src="https://unpkg.com/vuex@3"></script>
<script>
  const store = new Vuex.Store({
    state: {
      loading: false,
      snackbar: {
        message: null,
        color: "primary",
        timeout: 3000,
        show: false,
      },
      name: "SiTE",
      title: "Online Portal",
      user: null,
    },
    getters: {
      isAuth: (state) => {
        return state.user ? true : false
      }
    },
    mutations: {
      updateState(state, {key, value}){
        state[key] = value
      },
      startLoading(state){
        state.loading = true
      },
      stopLoading(state){
        state.loading = false
      },
      showSnackbar(state, snackbar){
        snackbar.show = true
        state.snackbar = snackbar
        state.loading = false
      },
      closeSnackbar(state){
        state.snackbar.show = false
      },
    },
    actions: {
      async login({commit}, params){
        commit("startLoading")
        try{
          const { user, token} = await Utils.request("login", params)
          console.log({user})
          Utils.setToken(token)
          commit("updateState", {key: "user", value: user})
          commit("showSnackbar", {message: `Selamat Datang, ${user.name}!`, color: "success"})
          router.push("/")
        }catch(err){
          commit("showSnackbar", {message: err.message, color: "error"})
        }
      },
      async logout({commit}, params){
        commit("startLoading")
        try{
          const {success, message} = await Utils.request("logout", params)
          Utils.setToken("")
          commit("updateState", {key: "user", value: null})
          commit("showSnackbar", {message, color: "success"})
          router.push("/login")
        }catch(err){
          commit("showSnackbar", {message: err.message, color: "error"})
        }
      }
    },
  })
</script>




vue/router.html

Copy script dibawah ini pada vue/router.html

Masukkan Password Untuk Melihat Script (Password sama dengan di atas)

<script src="https://unpkg.com/vue-router@3"></script>
<script>
  const HomeView = {
    template: `
      <div>
        <h1>Home</h1>
       Welcome Dashboard V.01.05.22 
         <center><iframe src="?embedded=true"</iframe></center>

 <iframe width="560" height="315" src="https://www.youtube.com/embed/KmgCM8HZD88" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<center><iframe src="https://script.google.com/macros/s/?embedded=true" width="100%" height="300" frameborder="0" marginheight="0" marginwidth="0">Loading</iframe></center>


<center><iframe src="?embedded=true"</iframe></center>
      </div>
    `
  }

  const GoogleformView = {
    template: `
      <div>
        <h1>Google Form View</h1>
        
<center><iframe src="?embedded=true"</iframe></center>

           <center><iframe src="https://docs.google.com/forms/d/e/1FAIpQLSfCwPNLaWWR_YhyyK15OqKKEeM0pnLHwvelXIHtZvDak2R8Jg/viewform?embedded=true" width="100%" height="1500" frameborder="0" marginheight="0" marginwidth="0">Loading</iframe></center>

             

<center><iframe src="?embedded=true"</iframe></center>

      </div>
    `
  }
  const SpreadsheetView = {
    template: `
      <div>
        <h1>Spreadsheet View</h1>
        

         <center><iframe src="?embedded=true"</iframe></center>

<center><iframe src="https://docs.google.com/spreadsheets/d/1wqncKhk6ufgZ-UVryrmP9bLO1teFavxtAq9XPquRbPM/edit?usp=sharing?embedded=true" width="100%" height="800" frameborder="0" marginheight="0" marginwidth="0">Loading</iframe></center>

<center><iframe src="?embedded=true"</iframe></center>

           
      
      </div>
    `
  }
  

  const LoginView = {
    data: function(){
      return {
        form: {
          email: {
            value: null,
            label: "User ID",
            icon: "mdi-account-box",
            type: "email",
            rules: [v => !!v || "User ID harus diisi"],
          },
          password: {
            value: null,
            label: "Password",
            icon: "mdi-lock",
            type: "password",
            rules: [v => !!v || "Password harus diisi"],
          },
        },
      }
    },
    methods: {
      login(){
        const isFormValid = this.$refs.form.validate()
        if (!isFormValid) return
        const email = this.form.email.value
        const password = this.form.password.value
        this.$store.dispatch("login", {email, password})
      },
    },
    computed: {
      ...Vuex.mapState({
        loading: "loading",
      }),
    },
    template: `
      <div>
        <v-progress-linear
          :active="loading"
          :indeterminate="loading"
          absolute
          top
          color="primary"
        ></v-progress-linear>
        <v-row>
          <v-spacer></v-spacer>
          <v-col cols="12" sm="8" md="6" lg="4">
            <h1 class="mb-4 primary--text">Login</h1>
            <v-form ref="form" @submit.prevent="login">
              <my-input :item="form.email"></my-input>
              <my-input :item="form.password"></my-input>
              <v-btn type="submit" color="primary" depressed block :disabled="loading">
                <v-icon left>mdi-login</v-icon>
                Login
              </v-btn>
            </v-form>
          </v-col>
          <v-spacer></v-spacer>
        </v-row>
      </div>
    `
  }

  const routes = [
    { path: '/', component: HomeView, meta: {icon: "mdi-home", title: "Home"} },
    { path: '/Googleform', component: GoogleformView, meta: {icon: "mdi-file-document", title: "Input"} },
    { path: '/Spreadsheet', component: SpreadsheetView, meta: {icon: "mdi-file-excel", title: "Spreadsheet"} },
    { path: '/login', component: LoginView, meta: {icon: "mdi-login", title: "Login"} },
  ]

  const router = new VueRouter({
    routes
  })

  router.beforeEach( async (to, from, next) => {
    const token = Utils.getToken()
    let isAuth = store.getters.isAuth
    if (token && !isAuth) {
      await store.dispatch("login", {token})
      isAuth = store.getters.isAuth
    }
    if (to.path !== '/login' && !isAuth) return next("/login")
    return next()
  })

  router.afterEach((to, from) => {
    google.script.history.push(null, null, to.path)
  })

</script>



Penjelasan!
Silahkan ubah url yang bergaris bawah dengan link / file yang akan ditampilkan di webiste

Gambar 1. 


WARNA MERAH iframe src="url?embedded=true"
WARNA HIJAU : Ejaan teks harus sama (perhatikan gambar 1 dan gambar 2)
WARNA BIRU : Apabila ada penambahan menu, copy script di area biru dan di paste di bawahnya.
WARNA KUNING : Apabila ada penambahan menu, setelah langkah WARNA BIRU selesai, maka pada garis kuning dibawah silahkan di isi script seperti diatasnya

Gambar 2.
vue/components.html

Copy script dibawah ini pada vue/components.html

Masukkan Password Untuk Melihat Script (Password sama dengan di atas)

<script>

  const MySnackbar = Vue.component("my-snackbar", {
    computed: {
      ...Vuex.mapState({
        snackbar: "snackbar",
      }),
    },
    template: `
      <v-snackbar
        v-model="snackbar.show"
        :timeout="snackbar.timeout || 3000"
        :color="snackbar.color || 'dark'"
      >
        {{ snackbar.message }}
        <template v-slot:action="{ attrs }">
          <v-btn
            color="white"
            text
            v-bind="attrs"
            @click="$store.commit('closeSnackbar')"
          >
            Close
          </v-btn>
        </template>
      </v-snackbar>
    `
  })
  const MyInput = Vue.component("my-input", {
    props: {
      item: Object,
    },
    computed: {
      ...Vuex.mapState({
        loading: "loading",
      }),
    },
    template: `
      <v-text-field
        :outlined="item.outlined || true"
        :dense="item.dense || true"
        :label="item.label"
        :prepend-inner-icon="item.icon || null"
        :placeholder="item.placeholder"
        :type="item.type"
        :hideDetails="item.hideDetails || false"
        :rules="item.rules"
        :disabled="item.loading || loading"
        v-model="item.value"
        @change="$emit('change')"
      ></v-text-field>
    `
  })

  const MyNavbar = Vue.component('my-navbar', {
    data: function(){
      return {
        drawer: true,
      }
    },
    computed: {
      pages(){
        console.log(this.$router)
        return this.$router.options.routes
      },
      ...Vuex.mapState({
        name: "name",
        title: "title",
        loading: "loading",
        user: "user",
      }),
      ...Vuex.mapGetters({
        isAuth: "isAuth",
      }),
    },
    methods: {
      logout(){
        const token = this.user.toekn // get the token from local storage
        this.$store.dispatch("logout", {token})
      },
    },
    template: `
      <div v-if="isAuth">
        <v-navigation-drawer app v-model="drawer">
          <v-list-item>
            <v-list-item-content>
              <v-list-item-title class="text-h6">
                {{ user.name }}
              </v-list-item-title>
              <v-list-item-subtitle>
                {{ title }}
              </v-list-item-subtitle>
            </v-list-item-content>
          </v-list-item>

          <v-list
            dense
            nav
          >
            <template v-for="item in pages">
              <v-list-item
                v-if="item.path !== '/login'"
                :key="item.path"
                :to="item.path"
                link
              >
                <v-list-item-icon>
                  <v-icon>{{ item.meta.icon }}</v-icon>
                </v-list-item-icon>
                <v-list-item-content>
                  <v-list-item-title>{{ item.meta.title }}</v-list-item-title>
                </v-list-item-content>
              </v-list-item>
            </template>

            <v-list-item link @click="$vuetify.theme.dark = !$vuetify.theme.dark">
              <v-list-item-icon>
                <v-icon>{{ $vuetify.theme.dark ? 'mdi-lightbulb-on' : 'mdi-lightbulb-off' }}</v-icon>
              </v-list-item-icon>
              <v-list-item-content>
                <v-list-item-title>{{ $vuetify.theme.dark ? 'Light Mode' : 'Dark Mode' }}</v-list-item-title>
              </v-list-item-content>
            </v-list-item>

            <v-list-item link @click="logout">
              <v-list-item-icon>
                <v-icon>mdi-logout</v-icon>
              </v-list-item-icon>
              <v-list-item-content>
                <v-list-item-title>Logout</v-list-item-title>
              </v-list-item-content>
            </v-list-item>
          </v-list>

        </v-navigation-drawer>
        <v-app-bar app flat>
          <v-progress-linear
            :active="loading"
            :indeterminate="loading"
            absolute
            bottom
            color="primary"
          ></v-progress-linear>
          <v-app-bar-nav-icon @click="drawer = !drawer"></v-app-bar-nav-icon>
          <v-toolbar-title>{{ $route.meta.title}}</v-toolbar-title>
          <v-spacer></v-spacer>
        </v-app-bar>
      </div>
    `
  })
</script>




utils.html

Copy script dibawah ini pada utils.html
Masukkan Password Untuk Melihat Script (Password sama dengan di atas)

<script>
  const Utils = {
    KEY: {
      TOKEN: "_token"
    },
  }

  Utils.request = async (functionName, params={}) => {
    params = JSON.stringify(params)
    return new Promise((resolve, reject) => {
      google.script.run
        .withSuccessHandler((response) => resolve(JSON.parse(response)))
        .withFailureHandler((err) => reject(err))
        [functionName](params)
    })
  }

  Utils.setToken = (token) => {
    if (typeof token === "object") token = JSON.stringify(token)
    try{
      localStorage.setItem(Utils.KEY.TOKEN, token)
    }catch(err){
      // pass
      console.log(err)
    }
  }

  Utils.getToken = () => {
    try{
      return localStorage.getItem(Utils.KEY.TOKEN)
    }catch(err){
      // pass
      console.log(err)
    }
  }
</script>




5. Klik tombol Deploy / Terapkan - Deployment baru

6. Pastikan jenis Aplikasi Web dan hak akses ke siapa saja / anyone - Terapkan



Tampilan Halaman Depan
Dashboard Mode Normal

Dahsboard Mode Night








Previous Post Next Post

Promo