Mengintegrasikan Firebase dengan aplikasi Next.js

1. Sebelum memulai

Dalam codelab ini, Anda akan mempelajari cara mengintegrasikan Firebase dengan aplikasi web Next.js yang disebut Friendly Eats, yaitu situs yang menyediakan ulasan restoran.

Aplikasi web Friendly Eats

Aplikasi web yang sudah selesai menawarkan fitur berguna yang menunjukkan bagaimana Firebase dapat membantu Anda membangun aplikasi Next.js. Fitur tersebut mencakup:

  • Build dan deployment otomatis: Codelab ini menggunakan Firebase App Hosting untuk otomatis mem-build dan men-deploy kode Next.js Anda setiap kali Anda melakukan push ke cabang yang dikonfigurasi.
  • Login dan logout: Dengan aplikasi web yang sudah selesai, Anda dapat login dengan Google dan logout. Login dan persistensi pengguna dikelola sepenuhnya melalui Firebase Authentication.
  • Gambar: Aplikasi web yang sudah selesai memungkinkan pengguna yang login mengupload gambar restoran. Aset gambar disimpan di Cloud Storage for Firebase. Firebase JavaScript SDK menyediakan URL publik untuk gambar yang diupload. URL publik ini kemudian disimpan di dokumen restoran yang relevan di Cloud Firestore.
  • Ulasan: Dengan aplikasi web yang sudah selesai, pengguna yang login dapat memposting ulasan tentang restoran yang terdiri dari rating bintang dan pesan berbasis teks. Informasi ulasan disimpan di Cloud Firestore.
  • Filter: Dengan aplikasi web yang sudah selesai, pengguna yang login dapat memfilter daftar restoran berdasarkan kategori, lokasi, dan harga. Anda juga dapat menyesuaikan metode pengurutan yang digunakan. Data diakses dari Cloud Firestore, dan kueri Firestore diterapkan berdasarkan filter yang digunakan.

Prasyarat

  • Akun GitHub
  • Pengetahuan tentang Next.js dan JavaScript

Yang akan Anda pelajari

Yang Anda butuhkan

  • Git
  • Node.js versi stabil terbaru
  • Browser pilihan Anda, seperti Google Chrome
  • Lingkungan pengembangan dengan editor kode dan terminal
  • Akun Google untuk pembuatan dan pengelolaan project Firebase Anda
  • Kemampuan untuk mengupgrade project Firebase ke paket harga Blaze

2. Menyiapkan lingkungan pengembangan dan repositori GitHub Anda

Codelab ini menyediakan codebase awal aplikasi dan mengandalkan Firebase CLI.

Membuat repositori GitHub

Sumber codelab dapat ditemukan di https://github.com/firebase/friendlyeats-web. Repositori ini berisi project contoh untuk beberapa platform. Namun, codelab ini hanya menggunakan direktori nextjs-start. Perhatikan direktori berikut:

* `nextjs-start`: contains the starter code upon which you build.
* `nextjs-end`: contains the solution code for the finished web app.

Salin folder nextjs-start ke repositori Anda sendiri:

  1. Dengan menggunakan terminal, buat folder baru di komputer Anda dan pindah ke direktori baru:
    mkdir codelab-friendlyeats-web
    
    cd codelab-friendlyeats-web
    
  2. Gunakan paket npm giget untuk mengambil hanya folder nextjs-start:
    npx giget@latest "gh:firebase/friendlyeats-web/nextjs-start#master" . --install
    
  3. Melacak perubahan secara lokal dengan git:
    git init
    
    git add .
    
    git commit -m "Codelab starting point"
    
    git branch -M main
    
  4. Buat repositori GitHub baru: https://github.com/new. Beri nama sesuai keinginan Anda.
  5. Bergantung pada cara Anda mengautentikasi ke GitHub (HTTPS atau SSH), salin URL baru yang dibuat GitHub untuk Anda:
    • https://github.com/<USER_NAME>/<REPOSITORY_NAME>.git atau
    • git@github.com:<USER_NAME>/<REPOSITORY_NAME>.git
  6. Kirim perubahan lokal ke repositori GitHub baru Anda dengan menjalankan perintah berikut. Ganti placeholder <REPOSITORY_URL> dengan URL repositori Anda yang sebenarnya.
    git remote add origin <REPOSITORY_URL>
    
    git push -u origin main
    
  7. Sekarang Anda akan melihat kode awal di repositori GitHub Anda.

Menginstal atau mengupdate Firebase CLI

Jalankan perintah berikut untuk memverifikasi bahwa Anda telah menginstal Firebase CLI dan menggunakan v14.1.0 atau yang lebih tinggi:

firebase --version

Jika Anda melihat versi yang lebih rendah atau Anda belum menginstal Firebase CLI, jalankan perintah penginstalan:

npm install -g firebase-tools@latest

Jika Anda tidak dapat menginstal Firebase CLI karena error izin, lihat dokumentasi npm atau gunakan opsi penginstalan lainnya.

Login ke Firebase

  1. Jalankan perintah berikut untuk login ke Firebase CLI:
    firebase login
    
  2. Bergantung pada apakah Anda ingin Firebase mengumpulkan data, masukkan Y atau N.
  3. Di browser, pilih akun Google Anda, lalu klik Allow.

3. Menyiapkan project Firebase

Di bagian ini, Anda akan menyiapkan project Firebase dan mengaitkan aplikasi web Firebase dengan project tersebut. Anda juga akan menyiapkan layanan Firebase yang digunakan oleh aplikasi web contoh.

Membuat project Firebase

  1. Login ke konsol Firebase menggunakan Akun Google yang sama dengan yang Anda gunakan pada langkah sebelumnya.
  2. Klik tombol untuk membuat project baru, lalu masukkan nama project (misalnya, FriendlyEats Codelab).
  3. Klik Lanjutkan.
  4. Jika diminta, tinjau dan setujui persyaratan Firebase, lalu klik Continue.
  5. (Opsional) Aktifkan bantuan AI di Firebase console (disebut "Gemini di Firebase").
  6. Untuk codelab ini, Anda tidak memerlukan Google Analytics, jadi nonaktifkan opsi Google Analytics.
  7. Klik Buat project, tunggu hingga project Anda disediakan, lalu klik Lanjutkan.

Mengupgrade paket harga Firebase Anda

Untuk menggunakan Firebase App Hosting dan Cloud Storage for Firebase, project Firebase Anda harus menggunakan paket harga bayar sesuai penggunaan (Blaze), yang berarti project tersebut ditautkan ke akun Penagihan Cloud.

  • Akun Penagihan Cloud memerlukan metode pembayaran, seperti kartu kredit.
  • Jika Anda baru menggunakan Firebase dan Google Cloud, periksa apakah Anda memenuhi syarat untuk mendapatkan kredit sebesar$300 dan akun Penagihan Cloud Uji Coba Gratis.
  • Jika Anda melakukan codelab ini sebagai bagian dari acara, tanyakan kepada penyelenggara apakah ada kredit Cloud yang tersedia.

Untuk mengupgrade project Anda ke paket Blaze, ikuti langkah-langkah berikut:

  1. Di Firebase console, pilih upgrade your plan.
  2. Pilih paket Blaze. Ikuti petunjuk di layar untuk menautkan akun Penagihan Cloud ke project Anda.
    Jika perlu membuat akun Penagihan Cloud sebagai bagian dari upgrade ini, Anda mungkin perlu kembali ke alur upgrade di Firebase console untuk menyelesaikan upgrade.

Menambahkan aplikasi web ke project Firebase

  1. Buka Project overview di project Firebase Anda, klik Add app, lalu klik Web.
  2. Di kotak teks App nickname, masukkan nama panggilan aplikasi yang mudah diingat, seperti My Next.js app.
  3. Biarkan kotak Also set up Firebase Hosting for this app tidak dicentang.
  4. Klik Register app > Continue to console.

Menyiapkan layanan Firebase di Firebase console

Menyiapkan Authentication

  1. Di panel kiri Firebase console, luaskan Build, lalu pilih Authentication.
  2. Klik Get started.
  3. Di kolom Sign-in providers, klik Google > Enable.
  4. Di kotak teks Public-facing name for project, masukkan nama yang mudah diingat, seperti My Next.js app.
  5. Dari drop-down Support email for project, pilih alamat email Anda.
  6. Klik Save.

Menyiapkan Cloud Firestore

  1. Di panel kiri Firebase console, luaskan Build, lalu pilih Firestore Database.
  2. Klik Create database.
  3. Pilih Edisi standar, lalu klik Berikutnya.
  4. Jangan mengubah ID Database, biarkan ditetapkan ke (default).
  5. Pilih lokasi untuk database Anda, lalu klik Berikutnya.
    Untuk aplikasi yang sebenarnya, Anda harus memilih lokasi yang dekat dengan pengguna.
  6. Klik Mulai dalam mode pengujian. Baca pernyataan penyangkalan tentang aturan keamanan.
    Di codelab ini, Anda akan menambahkan Aturan Keamanan untuk mengamankan data. Jangan mendistribusikan atau mengekspos aplikasi ke publik tanpa menambahkan Aturan Keamanan untuk database Anda.
  7. Klik Buat.

Menyiapkan Cloud Storage for Firebase

  1. Di panel kiri Firebase console, luaskan Build, lalu pilih Storage.
  2. Klik Get started.
  3. Pilih lokasi untuk bucket Storage default Anda.
    Bucket di US-WEST1, US-CENTRAL1, dan US-EAST1 dapat memanfaatkan paket"Selalu Gratis" untuk Google Cloud Storage. Bucket di semua lokasi lainnya mengikuti harga dan penggunaan Google Cloud Storage.
  4. Klik Mulai dalam mode pengujian. Baca pernyataan penyangkalan tentang aturan keamanan.
    Di codelab ini, Anda akan menambahkan aturan keamanan untuk mengamankan data. Jangan mendistribusikan atau mengekspos aplikasi ke publik tanpa menambahkan Aturan Keamanan untuk bucket Storage Anda.
  5. Klik Buat.

Men-deploy Aturan Keamanan

Kode ini sudah memiliki kumpulan aturan keamanan untuk Firestore dan Cloud Storage for Firebase. Setelah Anda men-deploy Aturan Keamanan, data dalam database dan bucket akan lebih terlindungi dari penyalahgunaan.

  1. Di terminal, konfigurasi CLI untuk menggunakan project Firebase yang Anda buat sebelumnya:
    firebase use --add
    
    Saat diminta memasukkan alias, masukkan friendlyeats-codelab.
  2. Untuk men-deploy Aturan Keamanan ini (serta indeks yang akan diperlukan nanti), jalankan perintah ini di terminal Anda:
    firebase deploy --only firestore,storage
    
  3. Jika ditanya: "Cloud Storage for Firebase needs an IAM Role to use cross-service rules. Grant the new role?", tekan Enter untuk memilih Ya.

4. Meninjau codebase awal

Di bagian ini, Anda akan meninjau beberapa area codebase awal aplikasi yang akan ditambahi fungsi dalam codelab ini.

Struktur folder dan file

Tabel berikut berisi ringkasan struktur folder dan file aplikasi:

Folder dan file

Deskripsi

src/components

Komponen React untuk filter, header, detail restoran, dan ulasan

src/lib

Fungsi utilitas yang tidak harus terikat dengan React atau Next.js

src/lib/firebase

Kode khusus Firebase dan konfigurasi Firebase

public

Aset statis di aplikasi web, seperti ikon

src/app

Memilih rute dengan Router Aplikasi Next.js

package.json dan package-lock.json

Dependensi project dengan npm

next.config.js

Konfigurasi khusus Next.js (tindakan server diaktifkan)

jsconfig.json

Konfigurasi layanan bahasa JavaScript

Komponen server dan klien

Aplikasi ini adalah aplikasi web Next.js yang menggunakan Router Aplikasi. Rendering server digunakan di seluruh aplikasi. Misalnya, file src/app/page.js adalah komponen server yang bertanggung jawab atas halaman utama. File src/components/RestaurantListings.jsx adalah komponen klien yang ditunjukkan oleh perintah "use client" di awal file.

Pernyataan impor

Anda mungkin melihat pernyataan impor seperti berikut:

import RatingPicker from "@/src/components/RatingPicker.jsx";

Aplikasi menggunakan simbol @ untuk menghindari jalur impor relatif yang kaku dan dimungkinkan oleh alias jalur.

API khusus Firebase

Semua kode Firebase API digabungkan dalam direktori src/lib/firebase. Setiap komponen React kemudian mengimpor fungsi yang digabungkan dari direktori src/lib/firebase, bukan mengimpor fungsi Firebase secara langsung.

Data tiruan

Data restoran dan ulasan tiruan terdapat dalam file src/lib/randomData.js. Data dari file tersebut disusun dalam kode di file src/lib/fakeRestaurants.js.

5. Membuat backend App Hosting

Di bagian ini, Anda akan menyiapkan backend App Hosting untuk memantau cabang di repositori git Anda.

Di akhir bagian ini, Anda akan memiliki backend App Hosting yang terhubung ke repositori Anda di GitHub yang akan otomatis membangun ulang dan meluncurkan versi baru aplikasi Anda setiap kali Anda mengirim commit baru ke cabang main.

Membuat backend

  1. Buka halaman App Hosting di Firebase console.
  2. Klik Mulai untuk memulai alur pembuatan backend.
  3. Pilih region. Untuk aplikasi yang sebenarnya, Anda harus memilih region yang paling dekat dengan pengguna.
  4. Ikuti perintah di langkah Impor repositori GitHub untuk menyiapkan Autentikasi GitHub.
  5. Dari Repository, pilih Grant access to a new repository in GitHub, lalu ikuti perintah untuk mengaktifkan akses ke repositori GitHub yang Anda buat sebelumnya.
  6. Klik Refresh list untuk memuat ulang daftar, lalu pilih repositori Anda dan klik Next.
  7. Tetapkan setelan deployment:
    1. Tetapkan cabang aktif ke main.
    2. Pertahankan direktori root sebagai /.
    3. Aktifkan peluncuran otomatis.
  8. Beri nama backend Anda friendlyeats-codelab, lalu klik Berikutnya.
  9. Dari Tautkan aplikasi web Firebase, pilih Pilih aplikasi web Firebase yang ada dan pilih aplikasi yang Anda tambahkan dari daftar
  10. Klik Selesaikan dan deploy. Anda akan dialihkan ke halaman baru tempat Anda dapat melihat status backend App Hosting baru.
  11. Klik Lihat untuk melihat informasi selengkapnya tentang deployment App Hosting Anda, termasuk status peluncuran, log, dan detail penggunaan.
  12. Setelah peluncuran selesai, klik untuk membuka URL situs Anda di bagian Domain. Mungkin perlu waktu beberapa menit agar mulai berfungsi karena propagasi DNS.
  13. Maaf. Saat memuat halaman, Anda akan melihat pesan error yang bertuliskan "Error aplikasi: telah terjadi pengecualian sisi server (lihat log server untuk mengetahui informasi selengkapnya)."
  14. Di Firebase console, periksa tab Logs backend App Hosting Anda. Anda akan melihat log "Error: not implemented". Kita akan memperbaikinya di langkah berikutnya saat menambahkan autentikasi.

Anda telah men-deploy aplikasi web awal. Setiap kali Anda mengirim commit baru ke cabang main repositori GitHub, Anda akan melihat build dan peluncuran baru dimulai di konsol Firebase, dan situs Anda akan otomatis diupdate setelah peluncuran selesai.

6. Menambahkan autentikasi ke aplikasi web

Di bagian ini, Anda akan menambahkan autentikasi ke aplikasi web sehingga Anda dapat login ke aplikasi tersebut.

Tambahkan domain resmi

Firebase Authentication hanya akan menerima permintaan login dari domain yang Anda izinkan. Di sini, kita akan menambahkan domain backend App Hosting Anda ke daftar domain yang disetujui di project Anda.

  1. Buka halaman App Hosting dan klik View di bawah situs yang di-deploy untuk mengakses halaman Overview. Salin nama domain backend App Hosting Anda.
  2. Buka tab Setelan Auth dan pilih project yang ingin Anda tambahi domain resmi. Kemudian, temukan bagian Authorized Domains, lalu klik bagian tersebut.
  3. Klik tombol Tambahkan domain.
  4. Masukkan domain backend App Hosting Anda.
  5. Klik Tambahkan.

Mengimplementasikan fungsi login dan logout

Di file src/lib/firebase/auth.js, ganti fungsi onAuthStateChanged, onIdTokenChanged, signInWithGoogle, dan signOut dengan kode berikut:

export function onAuthStateChanged(cb) {
  return _onAuthStateChanged(auth, cb);
}

export function onIdTokenChanged(cb) {
  return _onIdTokenChanged(auth, cb);
}

export async function signInWithGoogle() {
  const provider = new GoogleAuthProvider();

  try {
    await signInWithPopup(auth, provider);
  } catch (error) {
    console.error("Error signing in with Google", error);
  }
}

export async function signOut() {
  try {
    return auth.signOut();
  } catch (error) {
    console.error("Error signing out with Google", error);
  }
}

Kode ini menggunakan Firebase API berikut:

Firebase API

Deskripsi

auth.onAuthStateChanged

Menambahkan observer untuk perubahan pada status login pengguna.

auth.onIdTokenChanged

Menambahkan observer untuk perubahan pada token ID pengguna.

GoogleAuthProvider

Membuat instance penyedia autentikasi Google.

signInWithPopup

Memulai alur autentikasi berbasis dialog.

auth.signOut

Memproses logout pengguna.

Dalam file src/components/Header.jsx, kode sudah memanggil fungsi signInWithGoogle dan signOut.

Mengirim status autentikasi ke server

Untuk meneruskan status autentikasi ke server, kita akan menggunakan cookie. Setiap kali status autentikasi berubah di klien, kami akan memperbarui cookie __session.

Di src/components/Header.jsx, ganti fungsi useUserSession dengan kode berikut:

function useUserSession(initialUser) {
  useEffect(() => {
    return onIdTokenChanged(async (user) => {
      if (user) {
        const idToken = await user.getIdToken();
        await setCookie("__session", idToken);
      } else {
        await deleteCookie("__session");
      }
      if (initialUser?.uid === user?.uid) {
        return;
      }
      window.location.reload();
    });
  }, [initialUser]);

  return initialUser;
}

Membaca status autentikasi di server

Kita akan menggunakan FirebaseServerApp untuk mencerminkan status autentikasi klien di server.

Buka src/lib/firebase/serverApp.js, dan ganti fungsi getAuthenticatedAppForUser:

export async function getAuthenticatedAppForUser() {
  const authIdToken = (await cookies()).get("__session")?.value;

  // Firebase Server App is a new feature in the JS SDK that allows you to
  // instantiate the SDK with credentials retrieved from the client & has
  // other affordances for use in server environments.
  const firebaseServerApp = initializeServerApp(
    // https://github.com/firebase/firebase-js-sdk/issues/8863#issuecomment-2751401913
    initializeApp(),
    {
      authIdToken,
    }
  );

  const auth = getAuth(firebaseServerApp);
  await auth.authStateReady();

  return { firebaseServerApp, currentUser: auth.currentUser };
}

Memverifikasi perubahan

Tata letak root di file src/app/layout.js merender header dan meneruskan pengguna, jika tersedia, sebagai properti.

<Header initialUser={currentUser?.toJSON()} />

Ini berarti komponen <Header> akan merender data pengguna, jika tersedia, selama waktu proses server. Jika ada update autentikasi selama siklus proses halaman setelah pemuatan halaman awal, pengendali onAuthStateChanged akan menanganinya.

Sekarang saatnya men-deploy build baru dan memverifikasi apa yang telah Anda buat.

  1. Buat commit dengan pesan commit "Add authentication" dan kirim ke repositori GitHub Anda.
    git add .
    
    git commit -m "Add authentication"
    
    git push
    
  2. Buka halaman App Hosting, lalu setelah peluncuran baru Anda selesai, klik URL situs untuk membukanya.
  3. Menguji autentikasi:
    1. Login dengan Akun Google Anda dan verifikasi bahwa nama tampilan Anda muncul di header setelah Anda login.
    2. Logout dan login lagi. Anda dapat mengulangi langkah ini dengan pengguna lain.
    3. Opsional: Klik kanan aplikasi web, pilih View page source, lalu telusuri nama tampilan. Nama tampilan akan muncul di sumber HTML mentah yang ditampilkan dari server.

7. Melihat informasi restoran

Aplikasi web menyertakan data tiruan untuk restoran dan ulasan.

Menambahkan satu atau beberapa restoran

Untuk memasukkan data restoran tiruan ke database Cloud Firestore lokal Anda, ikuti langkah-langkah berikut:

  1. Login ke aplikasi web jika Anda belum melakukannya. Kemudian, pilih 2cf67d488d8e6332.png> Tambahkan restoran contoh. Perhatikan bahwa kita tidak melihat restoran apa pun muncul di aplikasi web Friendly Eats karena kita belum menyiapkan kode pengambilan data. Kami akan memperbaikinya di langkah berikutnya.
  2. Di Firebase console di halaman Firestore Database, pilih restaurants. Anda akan melihat dokumen tingkat teratas dalam koleksi restoran, yang masing-masing mewakili restoran.
  3. Klik beberapa dokumen untuk menjelajahi properti dokumen restoran.

Menampilkan daftar restoran

Database Cloud Firestore Anda sekarang memiliki restoran yang dapat ditampilkan oleh aplikasi web Next.js.

Untuk menentukan kode pengambilan data, ikuti langkah-langkah berikut:

  1. Dalam file src/app/page.js, temukan komponen server <Home />, dan tinjau panggilan ke fungsi getRestaurants, yang mengambil daftar restoran pada waktu proses server. Anda akan menerapkan fungsi getRestaurants dalam langkah-langkah berikut.
  2. Di file src/lib/firebase/firestore.js, ganti fungsi applyQueryFilters dan getRestaurants dengan kode berikut:
function applyQueryFilters(q, { category, city, price, sort }) {
  if (category) {
    q = query(q, where("category", "==", category));
  }
  if (city) {
    q = query(q, where("city", "==", city));
  }
  if (price) {
    q = query(q, where("price", "==", price.length));
  }
  if (sort === "Rating" || !sort) {
    q = query(q, orderBy("avgRating", "desc"));
  } else if (sort === "Review") {
    q = query(q, orderBy("numRatings", "desc"));
  }
  return q;
}

export async function getRestaurants(db = db, filters = {}) {
  let q = query(collection(db, "restaurants"));

  q = applyQueryFilters(q, filters);
  const results = await getDocs(q);
  return results.docs.map((doc) => {
    return {
      id: doc.id,
      ...doc.data(),
      // Only plain objects can be passed to Client Components from Server Components
      timestamp: doc.data().timestamp.toDate(),
    };
  });
}
  1. Buat commit dengan pesan commit "Read the list of restaurants from Firestore" dan kirimkan ke repositori GitHub Anda.
    git add .
    
    git commit -m "Read the list of restaurants from Firestore"
    
    git push
    
  2. Buka halaman App Hosting di Firebase console dan tunggu hingga peluncuran baru Anda selesai.
  3. Di aplikasi web, muat ulang halaman. Gambar restoran muncul sebagai kartu di halaman.

Memastikan listingan restoran dimuat pada waktu proses server

Dengan menggunakan framework Next.js, mungkin akan sulit untuk mengetahui kapan data dimuat pada waktu proses server atau waktu proses sisi klien.

Untuk memverifikasi bahwa listingan restoran dimuat pada waktu proses server, ikuti langkah-langkah berikut:

  1. Di aplikasi web, buka DevTools dan nonaktifkan JavaScript.

Menonaktifkan JavaScipt di DevTools

  1. Muat ulang aplikasi web. Listingan restoran masih dimuat. Informasi restoran ditampilkan di respons server. Jika JavaScript diaktifkan, informasi restoran dihidrasi melalui kode JavaScript sisi klien.
  2. Di DevTools, aktifkan kembali JavaScript.

Memproses update restoran dengan pemroses snapshot Cloud Firestore

Di bagian sebelumnya, Anda telah melihat cara kumpulan restoran awal dimuat dari file src/app/page.js. File src/app/page.js adalah komponen server dan dirender di server, termasuk kode pengambilan data Firebase.

File src/components/RestaurantListings.jsx adalah komponen klien dan dapat dikonfigurasi untuk menghidrasi markup yang dirender server.

Untuk mengonfigurasi file src/components/RestaurantListings.jsx guna menghidrasi markup yang dirender server, ikuti langkah-langkah berikut:

  1. Dalam file src/components/RestaurantListings.jsx, amati kode berikut, yang sudah ditulis untuk Anda:
useEffect(() => {
    return getRestaurantsSnapshot((data) => {
      setRestaurants(data);
    }, filters);
  }, [filters]);

Kode ini memanggil fungsi getRestaurantsSnapshot(), yang mirip dengan fungsi getRestaurants() yang Anda implementasikan di langkah sebelumnya. Namun, fungsi snapshot ini menyediakan mekanisme callback sehingga callback dipanggil setiap kali perubahan dilakukan pada koleksi restoran.

  1. Di file src/lib/firebase/firestore.js, ganti fungsi getRestaurantsSnapshot() dengan kode berikut:
export function getRestaurantsSnapshot(cb, filters = {}) {
  if (typeof cb !== "function") {
    console.log("Error: The callback parameter is not a function");
    return;
  }

  let q = query(collection(db, "restaurants"));
  q = applyQueryFilters(q, filters);

  return onSnapshot(q, (querySnapshot) => {
    const results = querySnapshot.docs.map((doc) => {
      return {
        id: doc.id,
        ...doc.data(),
        // Only plain objects can be passed to Client Components from Server Components
        timestamp: doc.data().timestamp.toDate(),
      };
    });

    cb(results);
  });
}
  1. Di file src/lib/firebase/firestore.js, ganti fungsi getRestaurantSnapshotById() dengan kode berikut:
export function getRestaurantSnapshotById(restaurantId, cb) {
  if (!restaurantId) {
    console.log("Error: Invalid ID received: ", restaurantId);
    return;
  }

  if (typeof cb !== "function") {
    console.log("Error: The callback parameter is not a function");
    return;
  }

  const docRef = doc(db, "restaurants", restaurantId);
  return onSnapshot(docRef, (docSnap) => {
    cb({
      ...docSnap.data(),
      timestamp: docSnap.data().timestamp.toDate(),
    });
  });
}

Perubahan yang dilakukan melalui halaman Database Firestore kini tercermin di aplikasi web secara real time.

  1. Buat commit dengan pesan commit "Listen for realtime restaurant updates" dan kirimkan ke repositori GitHub Anda.
    git add .
    
    git commit -m "Listen for realtime restaurant updates"
    
    git push
    
  2. Buka halaman App Hosting di Firebase console dan tunggu hingga peluncuran baru Anda selesai.
  3. Di aplikasi web, pilih 27ca5d1e8ed8adfe.png> Tambahkan restoran contoh. Jika fungsi snapshot Anda diterapkan dengan benar, restoran akan muncul secara real time tanpa memuat ulang halaman.

8. Menyimpan ulasan yang dikirimkan pengguna dari aplikasi web

  1. Di file src/lib/firebase/firestore.js, ganti fungsi updateWithRating() dengan kode berikut:
const updateWithRating = async (
  transaction,
  docRef,
  newRatingDocument,
  review
) => {
  const restaurant = await transaction.get(docRef);
  const data = restaurant.data();
  const newNumRatings = data?.numRatings ? data.numRatings + 1 : 1;
  const newSumRating = (data?.sumRating || 0) + Number(review.rating);
  const newAverage = newSumRating / newNumRatings;

  transaction.update(docRef, {
    numRatings: newNumRatings,
    sumRating: newSumRating,
    avgRating: newAverage,
  });

  transaction.set(newRatingDocument, {
    ...review,
    timestamp: Timestamp.fromDate(new Date()),
  });
};

Kode ini menyisipkan dokumen Firestore baru yang mewakili ulasan baru. Kode ini juga mengupdate dokumen Firestore yang ada yang mewakili restoran dengan angka yang diperbarui untuk jumlah rating dan rata-rata rating yang dihitung.

  1. Ganti fungsi addReviewToRestaurant() dengan kode berikut:
export async function addReviewToRestaurant(db, restaurantId, review) {
  if (!restaurantId) {
    throw new Error("No restaurant ID has been provided.");
  }

  if (!review) {
    throw new Error("A valid review has not been provided.");
  }

  try {
    const docRef = doc(collection(db, "restaurants"), restaurantId);
    const newRatingDocument = doc(
      collection(db, `restaurants/${restaurantId}/ratings`),
    );

    // corrected line
    await runTransaction(db, (transaction) =>
      updateWithRating(transaction, docRef, newRatingDocument, review),
    );
  } catch (error) {
    console.error(
      "There was an error adding the rating to the restaurant",
      error,
    );
    throw error;
  }
}

Mengimplementasikan Tindakan Server Next.js

Tindakan Server Next.js menyediakan API yang mudah digunakan untuk mengakses data formulir, seperti data.get("text") untuk mendapatkan nilai teks dari payload pengiriman formulir.

Untuk menggunakan Tindakan Server Next.js guna memproses pengiriman formulir peninjauan, ikuti langkah-langkah berikut:

  1. Dalam file src/components/ReviewDialog.jsx, temukan atribut action di elemen <form>.
<form
  action={handleReviewFormSubmission}
  onSubmit={() => {
    handleClose();
  }}
>

Nilai atribut action mengacu pada fungsi yang Anda implementasikan di langkah berikutnya.

  1. Di file src/app/actions.js, ganti fungsi handleReviewFormSubmission() dengan kode berikut:
export async function handleReviewFormSubmission(data) {
  const { firebaseServerApp } = await getAuthenticatedAppForUser();
  const db = getFirestore(firebaseServerApp);

  await addReviewToRestaurant(db, data.get("restaurantId"), {
    text: data.get("text"),
    rating: data.get("rating"),

    // This came from a hidden form field.
    userId: data.get("userId"),
  });
}

Menambahkan ulasan restoran

Anda telah menerapkan dukungan untuk pengiriman ulasan, jadi sekarang Anda dapat memverifikasi bahwa ulasan Anda disisipkan ke Cloud Firestore dengan benar.

Untuk menambahkan ulasan dan memverifikasi bahwa ulasan tersebut disisipkan ke Cloud Firestore, ikuti langkah-langkah berikut:

  1. Buat commit dengan pesan commit "Allow users to submit restaurant reviews" dan kirimkan ke repositori GitHub Anda.
    git add .
    
    git commit -m "Allow users to submit restaurant reviews"
    
    git push
    
  2. Buka halaman App Hosting di Firebase console dan tunggu hingga peluncuran baru Anda selesai.
  3. Muat ulang aplikasi web, lalu pilih restoran dari halaman beranda.
  4. Di halaman restoran, klik 3e19beef78bb0d0e.png.
  5. Pilih rating bintang.
  6. Tulis ulasan.
  7. Klik Submit. Ulasan Anda akan muncul di bagian atas daftar ulasan.
  8. Di Cloud Firestore, telusuri panel Add document untuk dokumen restoran yang telah Anda ulas dan pilih dokumen tersebut.
  9. Di panel Start collection, pilih ratings.
  10. Di panel Add document, temukan dokumen untuk ulasan Anda guna memverifikasi bahwa dokumen tersebut disisipkan seperti yang diharapkan.

9. Menyimpan file yang diupload pengguna dari aplikasi web

Di bagian ini, Anda menambahkan fungsi sehingga Anda dapat mengganti gambar yang terkait dengan restoran saat Anda login. Anda mengupload gambar ke Firebase Storage, dan mengupdate URL gambar di dokumen Cloud Firestore yang mewakili restoran.

Untuk menyimpan file yang diupload pengguna dari aplikasi web, ikuti langkah-langkah berikut:

  1. Di file src/components/Restaurant.jsx, amati kode yang berjalan saat pengguna mengupload file:
async function handleRestaurantImage(target) {
  const image = target.files ? target.files[0] : null;
  if (!image) {
    return;
  }

  const imageURL = await updateRestaurantImage(id, image);
  setRestaurantDetails({ ...restaurantDetails, photo: imageURL });
}

Tidak ada perubahan yang diperlukan pada fungsi ini, tetapi Anda menerapkan perilaku fungsi updateRestaurantImage() dalam langkah-langkah berikut.

  1. Di file src/lib/firebase/storage.js, ganti fungsi updateRestaurantImage() dan uploadImage() dengan kode berikut:
export async function updateRestaurantImage(restaurantId, image) {
  try {
    if (!restaurantId) {
      throw new Error("No restaurant ID has been provided.");
    }

    if (!image || !image.name) {
      throw new Error("A valid image has not been provided.");
    }

    const publicImageUrl = await uploadImage(restaurantId, image);
    await updateRestaurantImageReference(restaurantId, publicImageUrl);

    return publicImageUrl;
  } catch (error) {
    console.error("Error processing request:", error);
  }
}

async function uploadImage(restaurantId, image) {
  const filePath = `images/${restaurantId}/${image.name}`;
  const newImageRef = ref(storage, filePath);
  await uploadBytesResumable(newImageRef, image);

  return await getDownloadURL(newImageRef);
}

Fungsi updateRestaurantImageReference() sudah diimplementasikan untuk Anda. Fungsi ini mengupdate dokumen restoran yang ada di Cloud Firestore dengan URL gambar yang diupdate.

Memverifikasi fungsi upload gambar

Untuk memastikan bahwa gambar diupload seperti yang diharapkan, ikuti langkah-langkah berikut:

  1. Buat commit dengan pesan commit "Izinkan pengguna mengubah foto setiap restoran" dan kirimkan ke repositori GitHub Anda.
    git add .
    
    git commit -m "Allow users to change each restaurants' photo"
    
    git push
    
  2. Buka halaman App Hosting di Firebase console dan tunggu hingga peluncuran baru Anda selesai.
  3. Di aplikasi web, pastikan Anda login dan pilih restoran.
  4. Klik 7067eb41fea41ff0.png lalu upload gambar dari sistem file Anda. Gambar Anda meninggalkan lingkungan lokal dan diupload ke Cloud Storage. Gambar akan langsung muncul setelah Anda menguploadnya.
  5. Buka Cloud Storage for Firebase.
  6. Buka folder yang mewakili restoran. Gambar yang Anda upload ada di folder.

6cf3f9e2303c931c.png

10. Meringkas ulasan restoran dengan AI generatif

Di bagian ini, Anda akan menambahkan fitur ringkasan ulasan sehingga pengguna dapat dengan cepat memahami pendapat semua orang tentang restoran tanpa harus membaca setiap ulasan.

Menyimpan kunci Gemini API di Cloud Secret Manager

  1. Untuk menggunakan Gemini API, Anda memerlukan kunci API. Buka Google AI Studio dan klik Create API Key.
  2. Beri nama kunci sesuai keinginan Anda. Jika project Anda tidak tercantum di bagian Pilih project yang diimpor, klik Impor project, centang project Anda dalam daftar, lalu klik Impor. Terakhir, pilih project tersebut di bagian Pilih project yang diimpor, lalu klik Buat kunci.
  3. App Hosting terintegrasi dengan Cloud Secret Manager untuk memungkinkan Anda menyimpan nilai sensitif seperti kunci API secara aman:
    1. Di terminal, jalankan perintah untuk membuat secret baru:
    firebase apphosting:secrets:set GEMINI_API_KEY
    
    1. Saat diminta memasukkan nilai rahasia, salin dan tempel kunci Gemini API Anda dari Google AI Studio.
    2. Saat ditanya apakah secret baru ditujukan untuk produksi atau pengujian lokal, pilih "Produksi".
    3. Saat ditanya apakah Anda ingin memberikan akses agar akun layanan backend Anda dapat mengakses secret, pilih "Ya".
    4. Saat ditanya apakah rahasia baru harus ditambahkan ke apphosting.yaml, masukkan Y untuk menyetujui.

Kunci Gemini API Anda kini disimpan dengan aman di Cloud Secret Manager, dan dapat diakses oleh backend App Hosting Anda.

Menerapkan komponen ringkasan ulasan

  1. Di src/components/Reviews/ReviewSummary.jsx, ganti fungsi GeminiSummary dengan kode berikut:
    export async function GeminiSummary({ restaurantId }) {
      const { firebaseServerApp } = await getAuthenticatedAppForUser();
      const reviews = await getReviewsByRestaurantId(
        getFirestore(firebaseServerApp),
        restaurantId
      );
    
      const reviewSeparator = "@";
      const prompt = `
        Based on the following restaurant reviews, 
        where each review is separated by a '${reviewSeparator}' character, 
        create a one-sentence summary of what people think of the restaurant. 
    
        Here are the reviews: ${reviews.map((review) => review.text).join(reviewSeparator)}
      `;
    
      try {
        if (!process.env.GEMINI_API_KEY) {
          // Make sure GEMINI_API_KEY environment variable is set:
          // https://firebase.google.com/docs/genkit/get-started
          throw new Error(
            'GEMINI_API_KEY not set. Set it with "firebase apphosting:secrets:set GEMINI_API_KEY"'
          );
        }
    
        // Configure a Genkit instance.
        const ai = genkit({
          plugins: [googleAI()],
          model: gemini20Flash, // set default model
        });
        const { text } = await ai.generate(prompt);
    
        return (
          <div className="restaurant__review_summary">
            <p>{text}</p>
            <p> Summarized with Gemini</p>
          </div>
        );
      } catch (e) {
        console.error(e);
        return <p>Error summarizing reviews.</p>;
      }
    }
    
  2. Buat commit dengan pesan commit "Use AI to summarize reviews" dan kirimkan ke repositori GitHub Anda.
    git add .
    
    git commit -m "Use AI to summarize reviews"
    
    git push
    
  3. Buka halaman App Hosting di Firebase console dan tunggu hingga peluncuran baru Anda selesai.
  4. Buka halaman restoran. Di bagian atas, Anda akan melihat ringkasan satu kalimat dari semua ulasan di halaman.
  5. Tambahkan ulasan baru dan muat ulang halaman. Anda akan melihat perubahan ringkasan.

11. Membatalkan publikasi situs App Hosting

Setelah menyelesaikan codelab ini, jika Anda tidak akan terus menggunakan aplikasi, Anda dapat membatalkan publikasinya untuk memastikan tidak ada yang mengakses resource Firestore, Storage, dan Gemini Anda. Anda dapat memublikasikan ulang kapan saja.

Untuk membatalkan publikasi situs App Hosting:

  1. Buka App Hosting di Firebase console.
  2. Temukan backend aplikasi Anda, lalu klik View.
  3. Di bagian Backend information, di samping Domains, klik Manage. Tindakan ini akan memuat halaman Domains.
  4. Di samping domain Anda, klik ikon Lainnya (tiga titik vertikal), pilih Nonaktifkan domain, lalu klik Nonaktifkan untuk mengonfirmasi.

12. Kesimpulan

Selamat! Anda telah mempelajari cara menggunakan Firebase untuk menambahkan fitur dan fungsi ke aplikasi Next.js. Secara khusus, Anda telah menggunakan hal berikut:

Pelajari lebih lanjut