Firebase'i Next.js uygulamasıyla entegre etme

1. Başlamadan önce

Bu codelab'de, Firebase'i Friendly Eats adlı bir Next.js web uygulamasıyla (restoran incelemeleri için bir web sitesi) nasıl entegre edeceğinizi öğreneceksiniz.

Friendly Eats web uygulaması

Tamamlanan web uygulaması, Firebase'in Next.js uygulamaları oluşturmanıza nasıl yardımcı olabileceğini gösteren faydalı özellikler sunar. Bu özellikler şunlardır:

  • Otomatik derleme ve dağıtım: Bu codelab, yapılandırılmış bir dala her gönderim yaptığınızda Next.js kodunuzu otomatik olarak derlemek ve dağıtmak için Firebase App Hosting'i kullanır.
  • Oturum açma ve kapatma: Tamamlanan web uygulaması, Google ile oturum açmanıza ve oturumu kapatmanıza olanak tanır. Kullanıcı girişi ve kalıcılığı tamamen Firebase Authentication üzerinden yönetilir.
  • Resimler: Tamamlanan web uygulaması, oturum açmış kullanıcıların restoran resimlerini yüklemesine olanak tanır. Resim öğeleri Cloud Storage for Firebase'de depolanır. Firebase JavaScript SDK, yüklenen resimler için herkese açık bir URL sağlar. Bu herkese açık URL daha sonra Cloud Firestore'daki ilgili restoran belgesinde saklanır.
  • Yorumlar: Tamamlanan web uygulaması, oturum açmış kullanıcıların restoranlarla ilgili yorumlar yayınlamasına olanak tanır. Bu yorumlar, yıldız puanı ve metin tabanlı bir mesajdan oluşur. Yorum bilgileri Cloud Firestore'da depolanır.
  • Filtreler: Tamamlanan web uygulaması, oturum açmış kullanıcıların restoran listesini kategoriye, konuma ve fiyata göre filtrelemesine olanak tanır. Kullanılan sıralama yöntemini de özelleştirebilirsiniz. Verilere Cloud Firestore'dan erişilir ve kullanılan filtrelere göre Firestore sorguları uygulanır.

Ön koşullar

  • GitHub hesabı
  • Next.js ve JavaScript bilgisi

Neler öğreneceksiniz?

Gerekenler

  • Git
  • Node.js'nin son kararlı sürümü
  • Google Chrome gibi istediğiniz bir tarayıcı
  • Kod düzenleyici ve terminal içeren bir geliştirme ortamı
  • Firebase projenizi oluşturmak ve yönetmek için bir Google Hesabı
  • Firebase projenizi Blaze fiyatlandırma planına yükseltme

2. Geliştirme ortamınızı ve GitHub deponuzu ayarlama

Bu codelab'de uygulamanın başlangıç kod tabanı sağlanır ve Firebase CLI kullanılır.

GitHub deposu oluşturma

Codelab kaynağını https://github.com/firebase/friendlyeats-web adresinde bulabilirsiniz. Depoda birden fazla platform için örnek projeler bulunur. Ancak bu codelab'de yalnızca nextjs-start dizini kullanılır. Aşağıdaki dizinlere dikkat edin:

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

nextjs-start klasörünü kendi deponuza kopyalayın:

  1. Terminali kullanarak bilgisayarınızda yeni bir klasör oluşturun ve yeni dizine geçin:
    mkdir codelab-friendlyeats-web
    
    cd codelab-friendlyeats-web
    
  2. Yalnızca nextjs-start klasörünü getirmek için giget npm paketini kullanın:
    npx giget@latest "gh:firebase/friendlyeats-web/nextjs-start#master" . --install
    
  3. Değişiklikleri yerel olarak Git ile izleme:
    git init
    
    git add .
    
    git commit -m "Codelab starting point"
    
    git branch -M main
    
  4. Yeni bir GitHub deposu oluşturun: https://github.com/new. İstediğiniz adı verebilirsiniz.
  5. GitHub'da kimliğinizi nasıl doğruladığınıza (HTTPS veya SSH) bağlı olarak, GitHub'ın sizin için oluşturduğu yeni URL'yi kopyalayın:
    • https://github.com/<USER_NAME>/<REPOSITORY_NAME>.git veya
    • git@github.com:<USER_NAME>/<REPOSITORY_NAME>.git
  6. Aşağıdaki komutu çalıştırarak yerel değişiklikleri yeni GitHub deponuza aktarın. <REPOSITORY_URL> yer tutucusu yerine gerçek depo URL'nizi kullanın.
    git remote add origin <REPOSITORY_URL>
    
    git push -u origin main
    
  7. Başlangıç kodunu artık GitHub deponuzda görebilirsiniz.

Firebase CLI'yı yükleme veya güncelleme

Firebase CLI'nın yüklendiğini ve 14.1.0 veya sonraki bir sürüm olduğunu doğrulamak için aşağıdaki komutu çalıştırın:

firebase --version

Daha düşük bir sürüm görüyorsanız veya Firebase CLI yüklü değilse yükleme komutunu çalıştırın:

npm install -g firebase-tools@latest

İzin hataları nedeniyle Firebase CLI'yi yükleyemiyorsanız npm belgelerine bakın veya başka bir yükleme seçeneği kullanın.

Firebase'e giriş yapın.

  1. Firebase CLI'ye giriş yapmak için aşağıdaki komutu çalıştırın:
    firebase login
    
  2. Firebase'in veri toplamasını isteyip istemediğinize bağlı olarak Y veya N girin.
  3. Tarayıcınızda Google Hesabınızı seçin ve İzin ver'i tıklayın.

3. Firebase projenizi oluşturma

Bu bölümde, Firebase projesi oluşturup bir Firebase web uygulamasını bu projeyle ilişkilendireceksiniz. Ayrıca, örnek web uygulamasının kullandığı Firebase hizmetlerini de ayarlayacaksınız.

Firebase projesi oluşturma

  1. Önceki adımda kullandığınız Google Hesabı ile Firebase konsolunda oturum açın.
  2. Yeni bir proje oluşturmak için düğmeyi tıklayın ve ardından bir proje adı girin (örneğin, FriendlyEats Codelab).
  3. Devam'ı tıklayın.
  4. İstenirse Firebase şartlarını inceleyip kabul edin ve Devam'ı tıklayın.
  5. (İsteğe bağlı) Firebase konsolunda yapay zeka yardımını etkinleştirin ("Firebase'de Gemini" olarak adlandırılır).
  6. Bu codelab için Google Analytics'e ihtiyacınız yoktur. Bu nedenle, Google Analytics seçeneğini devre dışı bırakın.
  7. Proje oluştur'u tıklayın, projenizin hazırlanmasını bekleyin ve ardından Devam'ı tıklayın.

Firebase fiyatlandırma planınızı yükseltme

Firebase App Hosting ve Firebase için Cloud Storage'ı kullanmak istiyorsanız Firebase projenizin kullandıkça öde (Blaze) fiyatlandırma planında olması gerekir. Bu da projenin bir Cloud Faturalandırma Hesabı'na bağlı olduğu anlamına gelir.

Projenizi Blaze planına yükseltmek için şu adımları uygulayın:

  1. Firebase konsolunda planınızı yükseltmeyi seçin.
  2. Blaze planını seçin. Bir Cloud Faturalandırma hesabını projenize bağlamak için ekrandaki talimatları uygulayın.
    Bu yükseltme kapsamında bir Cloud Faturalandırma hesabı oluşturmanız gerekiyorsa yükseltmeyi tamamlamak için Firebase Console'daki yükseltme akışına geri dönmeniz gerekebilir.

Firebase projenize web uygulaması ekleme

  1. Firebase projenizde Proje genel bakış'a gidin, Uygulama ekle'yi ve ardından Web'i tıklayın.
  2. Uygulama takma adı metin kutusuna My Next.js app gibi hatırlanabilir bir uygulama takma adı girin.
  3. Bu uygulama için Firebase Hosting'i de ayarlayın onay kutusunu işaretlenmemiş olarak bırakın.
  4. Uygulamayı kaydet > Konsola git'i tıklayın.

Firebase konsolunda Firebase hizmetlerini ayarlama

Kimlik doğrulama ayarlama

  1. Firebase konsolunun sol panelinde Build'i (Oluştur) genişletin ve Authentication'ı (Kimlik Doğrulama) seçin.
  2. Başlayın'ı tıklayın.
  3. Oturum açma sağlayıcıları sütununda Google > Etkinleştir'i tıklayın.
  4. Projenin herkese açık adı metin kutusuna My Next.js app gibi akılda kalıcı bir ad girin.
  5. Proje için destek e-postası açılır listesinden e-posta adresinizi seçin.
  6. Kaydet'i tıklayın.

Cloud Firestore'u ayarlama

  1. Firebase konsolunun sol panelinde Build'i (Oluştur) genişletin ve Firestore Database'i (Firestore Veritabanı) seçin.
  2. Create database'i (Veritabanı oluştur) tıklayın.
  3. Standart sürüm'ü seçip Sonraki'yi tıklayın.
  4. Veritabanı kimliğini değiştirmeyin, (default) olarak ayarlayın.
  5. Veritabanınız için bir konum seçin ve Sonraki'yi tıklayın.
    Gerçek bir uygulama için kullanıcılarınıza yakın bir konum seçmeniz gerekir.
  6. Test modunda başlat'ı tıklayın. Güvenlik kurallarıyla ilgili sorumluluk reddi beyanını okuyun.
    Bu codelab'in ilerleyen bölümlerinde, verilerinizin güvenliğini sağlamak için güvenlik kuralları ekleyeceksiniz. Veritabanınıza güvenlik kuralları eklemeden uygulamayı herkese açık şekilde dağıtmayın veya herkese açık olarak kullanıma sunmayın.
  7. Oluştur'u tıklayın.

Cloud Storage for Firebase'i ayarlama

  1. Firebase konsolunun sol panelinde Build'i (Oluştur) genişletin ve Storage'ı (Depolama) seçin.
  2. Başlayın'ı tıklayın.
  3. Varsayılan depolama paketinize bir konum seçin.
    US-WEST1, US-CENTRAL1 ve US-EAST1 bölgelerindeki paketler, Google Cloud Storage için "Daima Ücretsiz" katmanından yararlanabilir. Diğer tüm konumlardaki paketler için Google Cloud Storage fiyatlandırması ve kullanımı geçerlidir.
  4. Test modunda başlat'ı tıklayın. Güvenlik kurallarıyla ilgili sorumluluk reddi beyanını okuyun.
    Bu codelab'in ilerleyen bölümlerinde, verilerinizin güvenliğini sağlamak için güvenlik kuralları ekleyeceksiniz. Depolamapaketinize güvenlik kuralları eklemeden uygulamayı herkese açık olarak dağıtmayın veya kullanıma sunmayın.
  5. Oluştur'u tıklayın.

Güvenlik kurallarını dağıtma

Kodda, Firestore ve Firebase için Cloud Storage'e yönelik güvenlik kuralı kümeleri zaten vardır. Güvenlik Kurallarını dağıttıktan sonra, veritabanınızdaki ve paketinizeki veriler kötüye kullanıma karşı daha iyi korunur.

  1. Terminalinizde, CLI'yı daha önce oluşturduğunuz Firebase projesini kullanacak şekilde yapılandırın:
    firebase use --add
    
    Takma ad istendiğinde friendlyeats-codelab girin.
  2. Bu güvenlik kurallarını (ve daha sonra gerekli olacak dizinleri) dağıtmak için terminalinizde şu komutu çalıştırın:
    firebase deploy --only firestore,storage
    
  3. "Cloud Storage for Firebase needs an IAM Role to use cross-service rules. Grant the new role?" sorusu sorulursa Evet'i seçmek için Enter tuşuna basın.

4. Başlangıç kod tabanını inceleme

Bu bölümde, uygulamanın başlangıç kod tabanının bu codelab'de işlev ekleyeceğiniz birkaç alanını inceleyeceksiniz.

Klasör ve dosya yapısı

Aşağıdaki tabloda, uygulamanın klasör ve dosya yapısına genel bir bakış sunulmaktadır:

Klasörler ve dosyalar

Açıklama

src/components

Filtreler, başlıklar, restoran bilgileri ve yorumlar için React bileşenleri

src/lib

Mutlaka React veya Next.js'ye bağlı olmayan yardımcı işlevler

src/lib/firebase

Firebase'e özgü kod ve Firebase yapılandırması

public

Web uygulamasındaki simgeler gibi statik öğeler

src/app

Next.js uygulama yönlendiricisiyle yönlendirme

package.json ve package-lock.json

npm ile proje bağımlılıkları

next.config.js

Next.js'e özgü yapılandırma (sunucu işlemleri etkinleştirilir)

jsconfig.json

JavaScript dil hizmeti yapılandırması

Sunucu ve istemci bileşenleri

Uygulama, App Router'ı kullanan bir Next.js web uygulamasıdır. Uygulamanın her yerinde sunucu oluşturma kullanılır. Örneğin, src/app/page.js dosyası ana sayfadan sorumlu bir sunucu bileşenidir. src/components/RestaurantListings.jsx dosyası, dosyanın başında "use client" yönergesiyle belirtilen bir istemci bileşenidir.

Ekstreleri içe aktarma

Aşağıdakilere benzer içe aktarma ifadeleri görebilirsiniz:

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

Uygulama, hantal göreli içe aktarma yollarını önlemek için @ sembolünü kullanır ve bu, yol takma adları sayesinde mümkün olur.

Firebase'e özgü API'ler

Tüm Firebase API kodu src/lib/firebase dizinine yerleştirilir. Daha sonra tek tek React bileşenleri, Firebase işlevlerini doğrudan içe aktarmak yerine sarmalanmış işlevleri src/lib/firebase dizininden içe aktarır.

Sahte veriler

Sahte restoran ve yorum verileri src/lib/randomData.js dosyasında yer alır. Bu dosyadaki veriler, src/lib/fakeRestaurants.js dosyasındaki kodda bir araya getirilir.

5. App Hosting arka ucu oluşturma

Bu bölümde, Git deponuzdaki bir dalı izlemek için App Hosting arka ucu ayarlayacaksınız.

Bu bölümün sonunda, GitHub'daki deponuza bağlı bir App Hosting arka ucunuz olacak. Bu arka uç, main dalınıza yeni bir taahhüt gönderdiğinizde uygulamanızın yeni bir sürümünü otomatik olarak yeniden oluşturup kullanıma sunacak.

Arka uç oluşturma

  1. Firebase konsolunda App Hosting sayfasına gidin.
  2. Arka uç oluşturma akışını başlatmak için Başlayın'ı tıklayın.
  3. Bölge seçin. Gerçek bir uygulama için kullanıcılarınıza en yakın bölgeyi seçersiniz.
  4. GitHub kimlik doğrulamasını ayarlamak için GitHub deposunu içe aktarma adımındaki istemleri uygulayın.
  5. Repository (Depo) bölümünde Grant access to a new repository in GitHub (GitHub'da yeni bir depoya erişim izni ver) seçeneğini belirleyin ve daha önce oluşturduğunuz GitHub deposuna erişimi etkinleştirmek için istemleri uygulayın.
  6. Listeyi yenilemek için Listeyi yenile'yi tıklayın, ardından deponuzu seçip Sonraki'yi tıklayın.
  7. Dağıtım ayarlarını belirleyin:
    1. Canlı dalı main olarak ayarlayın.
    2. Kök dizini / olarak bırakın.
    3. Otomatik kullanıma sunma işlemlerini etkinleştirin.
  8. Arka uçunuza ad verin friendlyeats-codelab ve İleri'yi tıklayın.
  9. Firebase web uygulaması ilişkilendirme bölümünde Mevcut bir Firebase web uygulaması seçin'i belirleyin ve listeden eklediğiniz uygulamayı seçin.
  10. Bitir ve dağıt'ı tıklayın. Yeni uygulama barındırma arka uçunuzun durumunu görebileceğiniz yeni bir sayfaya yönlendirilirsiniz.
  11. Dağıtım durumu, günlükler ve kullanım ayrıntıları da dahil olmak üzere App Hosting dağıtımınız hakkında daha fazla bilgi görüntülemek için Görüntüle'yi tıklayın.
  12. Dağıtımınız tamamlandıktan sonra Alanlar bölümünde site URL'nizi açmak için tıklayın. DNS yayılımı nedeniyle çalışmaya başlaması birkaç dakika sürebilir.
  13. Hay aksi! Sayfayı yüklediğinizde "Uygulama hatası: Sunucu tarafında bir istisna oluştu (daha fazla bilgi için sunucu günlüklerine bakın)." hata mesajını görürsünüz.
  14. Firebase konsolunda, App Hosting arka uçunuzun Günlükler sekmesini kontrol edin. "Error: not implemented" (Hata: uygulanmadı) günlüğü gösterilir. Kimlik doğrulama eklediğimizde bu sorunu sonraki adımda düzelteceğiz.

İlk web uygulamanızı dağıttınız. GitHub deponuzun main dalına her yeni kaydetme işlemi gönderdiğinizde Firebase konsolunda yeni bir derleme ve dağıtımın başladığını görürsünüz. Dağıtım tamamlandıktan sonra siteniz otomatik olarak güncellenir.

6. Web uygulamasına kimlik doğrulama ekleme

Bu bölümde, web uygulamasına kimlik doğrulama ekleyerek uygulamaya giriş yapabilirsiniz.

Yetkilendirilen alan ekleyin

Firebase Authentication yalnızca izin verdiğiniz alanlardan gelen oturum açma isteklerini kabul eder. Burada, App Hosting arka uçunuzun alanını projenizdeki onaylı alanlar listesine ekleyeceğiz.

  1. Uygulama Barındırma sayfasını açın ve Genel Bakış sayfasına erişmek için dağıtılan sitenizin altındaki Görüntüle'yi tıklayın. Uygulama barındırma arka uçunuzun alan adını kopyalayın.
  2. Yetkilendirme Ayarları sekmesine gidin ve yetkilendirilmiş bir alan eklemek istediğiniz projeyi seçin. Ardından, Yetkili Alanlar bölümünü bulup tıklayın.
  3. Alan ekle düğmesini tıklayın.
  4. Uygulama barındırma arka uçunuzun alanını girin.
  5. Ekle'yi tıklayın.

Oturum açma ve oturum kapatma işlevlerini uygulama

src/lib/firebase/auth.js dosyasında onAuthStateChanged, onIdTokenChanged, signInWithGoogle ve signOut işlevlerini aşağıdaki kodla değiştirin:

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);
  }
}

Bu kod aşağıdaki Firebase API'lerini kullanır:

Firebase API

Açıklama

auth.onAuthStateChanged

Kullanıcının oturum açma durumundaki değişiklikler için bir gözlemci ekler.

auth.onIdTokenChanged

Kullanıcının kimlik jetonunda yapılan değişiklikler için bir gözlemci ekler.

GoogleAuthProvider

Google kimlik doğrulama sağlayıcı örneği oluşturur.

signInWithPopup

İletişime dayalı bir kimlik doğrulama akışı başlatır.

auth.signOut

Kullanıcının oturumunu kapatır.

src/components/Header.jsx dosyasındaki kod, signInWithGoogle ve signOut işlevlerini zaten çağırır.

Kimlik doğrulama durumunu sunucuya gönderme

Kimlik doğrulama durumunu sunucuya iletmek için çerezleri kullanırız. İstemcide kimlik doğrulama durumu her değiştiğinde __session çerezini güncelleriz.

src/components/Header.jsx içinde useUserSession işlevini aşağıdaki kodla değiştirin:

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;
}

Sunucudaki kimlik doğrulama durumunu okuma

İstemcinin kimlik doğrulama durumunu sunucuda yansıtmak için FirebaseServerApp'i kullanacağız.

src/lib/firebase/serverApp.js dosyasını açın ve getAuthenticatedAppForUser işlevini değiştirin:

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 };
}

Değişiklikleri doğrulama

src/app/layout.js dosyasındaki kök düzen, başlığı oluşturur ve varsa kullanıcıyı bir özellik olarak geçirir.

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

Bu, <Header> bileşeninin, varsa kullanıcı verilerini sunucu çalışma zamanında oluşturduğu anlamına gelir. Sayfa ilk yüklendikten sonra sayfa yaşam döngüsü sırasında kimlik doğrulama güncellemeleri olursa onAuthStateChanged işleyici bunları yönetir.

Şimdi yeni bir derleme yayınlamanın ve oluşturduklarınızı doğrulamanın zamanı.

  1. "Add authentication" (Kimlik doğrulama ekle) mesajını içeren bir commit oluşturun ve bunu GitHub deponuza gönderin.
    git add .
    
    git commit -m "Add authentication"
    
    git push
    
  2. Uygulama barındırma sayfasını açın ve yeni dağıtımınız tamamlandığında site URL'sini tıklayarak açın.
  3. Kimlik doğrulama testi:
    1. Google Hesabınızla oturum açın ve oturum açtıktan sonra görünen adınızın üstbilgide göründüğünü doğrulayın.
    2. Oturumu kapatıp tekrar açın. Bu adımı farklı kullanıcılarla tekrarlayabilirsiniz.
    3. İsteğe bağlı: Web uygulamasını sağ tıklayın, Sayfa kaynağını görüntüle'yi seçin ve görünen adı arayın. Sunucudan döndürülen ham HTML kaynağında görünür.

7. Restoran bilgilerini görüntüleme

Web uygulamasında restoranlar ve yorumlar için örnek veriler yer alır.

Bir veya daha fazla restoran ekleme

Yerel Cloud Firestore veritabanınıza sahte restoran verileri eklemek için aşağıdaki adımları uygulayın:

  1. Henüz yapmadıysanız web uygulamasında oturum açın. Ardından 2cf67d488d8e6332.png> Örnek restoranlar ekle'yi seçin. Henüz veri getirme kodu ayarlamadığımız için Friendly Eats web uygulamasında herhangi bir restoranın görünmediğini unutmayın. Bu sorunu bir sonraki adımda düzelteceğiz.
  2. Firebase konsolundaki Firestore Database (Firestore Veritabanı) sayfasında restaurants'ı (restoranlar) seçin. Restoran koleksiyonundaki üst düzey dokümanları görürsünüz. Bu dokümanların her biri bir restoranı temsil eder.
  3. Bir restoran dokümanının özelliklerini keşfetmek için birkaç dokümanı tıklayın.

Restoran listesini görüntüleme

Cloud Firestore veritabanınızda artık Next.js web uygulamasının gösterebileceği restoranlar var.

Veri getirme kodunu tanımlamak için aşağıdaki adımları uygulayın:

  1. src/app/page.js dosyasında <Home /> sunucu bileşenini bulun ve sunucu çalışma zamanında restoran listesini alan getRestaurants işlevine yapılan çağrıyı inceleyin. getRestaurants işlevini aşağıdaki adımlarda uygulayacaksınız.
  2. src/lib/firebase/firestore.js dosyasında, applyQueryFilters ve getRestaurants işlevlerini aşağıdaki kodla değiştirin:
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. "Read the list of restaurants from Firestore" (Firestore'dan restoran listesini oku) commit mesajıyla bir commit oluşturun ve bunu GitHub deponuza gönderin.
    git add .
    
    git commit -m "Read the list of restaurants from Firestore"
    
    git push
    
  2. Firebase konsolunda Uygulama Barındırma sayfasını açın ve yeni dağıtımınızın tamamlanmasını bekleyin.
  3. Web uygulamasında sayfayı yenileyin. Restoran resimleri sayfada bloklar halinde gösterilir.

Restoran listelemelerinin sunucu çalışma zamanında yüklendiğini doğrulayın.

Next.js çerçevesi kullanılırken verilerin sunucu çalışma zamanında mı yoksa istemci tarafı çalışma zamanında mı yüklendiği anlaşılmayabilir.

Restoran girişlerinin sunucu çalışma zamanında yüklendiğini doğrulamak için aşağıdaki adımları uygulayın:

  1. Web uygulamasında Geliştirici Araçları'nı açın ve JavaScript'i devre dışı bırakın.

Geliştirici Araçları&#39;nda JavaScript&#39;i devre dışı bırakma

  1. Web uygulamasını yenileyin. Restoran listeleri yine de yüklenir. Restoran bilgileri, sunucu yanıtında döndürülür. JavaScript etkinleştirildiğinde restoran bilgileri, istemci tarafındaki JavaScript kodu aracılığıyla doldurulur.
  2. Geliştirici Araçları'nda JavaScript'i yeniden etkinleştirin.

Cloud Firestore anlık görüntü dinleyicileriyle restoran güncellemelerini dinleme

Önceki bölümde, ilk restoran grubunun src/app/page.js dosyasından nasıl yüklendiğini görmüştünüz. src/app/page.js dosyası bir sunucu bileşenidir ve Firebase veri getirme kodu da dahil olmak üzere sunucuda oluşturulur.

src/components/RestaurantListings.jsx dosyası bir istemci bileşenidir ve sunucu tarafından oluşturulan işaretlemeyi dolduracak şekilde yapılandırılabilir.

Sunucu tarafında oluşturulan işaretlemeyi doldurmak için src/components/RestaurantListings.jsx dosyasını yapılandırmak üzere aşağıdaki adımları uygulayın:

  1. src/components/RestaurantListings.jsx dosyasında, sizin için önceden yazılmış olan aşağıdaki kodu inceleyin:
useEffect(() => {
    return getRestaurantsSnapshot((data) => {
      setRestaurants(data);
    }, filters);
  }, [filters]);

Bu kod, önceki adımda uyguladığınız getRestaurants() işlevine benzer olan getRestaurantsSnapshot() işlevini çağırır. Ancak bu anlık görüntü işlevi, geri çağırma mekanizması sağlar. Böylece, restoranın koleksiyonunda her değişiklik yapıldığında geri çağırma işlemi tetiklenir.

  1. src/lib/firebase/firestore.js dosyasında, getRestaurantsSnapshot() işlevini aşağıdaki kodla değiştirin:
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. src/lib/firebase/firestore.js dosyasında, getRestaurantSnapshotById() işlevini aşağıdaki kodla değiştirin:
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(),
    });
  });
}

Firestore Database sayfası üzerinden yapılan değişiklikler artık web uygulamasına gerçek zamanlı olarak yansıtılıyor.

  1. "Listen for realtime restaurant updates" (Anlık restoran güncellemelerini dinle) mesajıyla bir commit oluşturun ve bunu GitHub deponuza gönderin.
    git add .
    
    git commit -m "Listen for realtime restaurant updates"
    
    git push
    
  2. Firebase konsolunda Uygulama Barındırma sayfasını açın ve yeni dağıtımınızın tamamlanmasını bekleyin.
  3. Web uygulamasında 27ca5d1e8ed8adfe.png> Örnek restoranlar ekle'yi seçin. Anlık görüntü işleviniz doğru şekilde uygulanmışsa restoranlar, sayfa yenilenmeden anlık olarak görünür.

8. Web uygulamasından gönderilen kullanıcı yorumlarını kaydetme

  1. src/lib/firebase/firestore.js dosyasında, updateWithRating() işlevini aşağıdaki kodla değiştirin:
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()),
  });
};

Bu kod, yeni incelemeyi temsil eden yeni bir Firestore dokümanı ekler. Kod, restoranı temsil eden mevcut Firestore belgesini de puan sayısı ve hesaplanan ortalama puanla ilgili güncellenmiş rakamlarla günceller.

  1. addReviewToRestaurant() işlevini aşağıdaki kodla değiştirin:
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;
  }
}

Next.js sunucu işlemi uygulama

Next.js sunucu işlemi, form verilerine erişmek için kullanışlı bir API sağlar. Örneğin, form gönderimi yükünden metin değerini almak için data.get("text") kullanılır.

Yorum formu gönderimini işlemek için Next.js Server Action kullanmak istiyorsanız aşağıdaki adımları uygulayın:

  1. src/components/ReviewDialog.jsx dosyasında, <form> öğesindeki action özelliğini bulun.
<form
  action={handleReviewFormSubmission}
  onSubmit={() => {
    handleClose();
  }}
>

action özellik değeri, bir sonraki adımda uygulayacağınız bir işlevi ifade eder.

  1. src/app/actions.js dosyasında, handleReviewFormSubmission() işlevini aşağıdaki kodla değiştirin:
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"),
  });
}

Bir restoran için yorum ekleme

Yorum gönderimleriyle ilgili destek uyguladınız. Artık yorumlarınızın Cloud Firestore'a doğru şekilde eklendiğini doğrulayabilirsiniz.

Yorum eklemek ve Cloud Firestore'a eklendiğini doğrulamak için aşağıdaki adımları uygulayın:

  1. "Allow users to submit restaurant reviews" (Kullanıcıların restoran yorumu göndermesine izin ver) mesajını içeren bir commit oluşturun ve bunu GitHub deponuza gönderin.
    git add .
    
    git commit -m "Allow users to submit restaurant reviews"
    
    git push
    
  2. Firebase konsolunda Uygulama Barındırma sayfasını açın ve yeni dağıtımınızın tamamlanmasını bekleyin.
  3. Web uygulamasını yenileyin ve ana sayfadan bir restoran seçin.
  4. Restoranın sayfasında 3e19beef78bb0d0e.png simgesini tıklayın.
  5. Yıldız puanı seçin.
  6. Yorum yazın.
  7. Gönder'i tıklayın. Yorumunuz, yorum listesinin en üstünde görünür.
  8. Cloud Firestore'da, Add document (Belge ekle) panelinde incelediğiniz restoranın belgesini arayın ve seçin.
  9. Koleksiyonu başlat panelinde puanlar'ı seçin.
  10. Belge ekle panelinde, beklendiği gibi eklenip eklenmediğini doğrulamak için inceleyeceğiniz belgeyi bulun.

9. Web uygulamasından kullanıcı tarafından yüklenen dosyaları kaydetme

Bu bölümde, oturum açtığınızda bir restoranla ilişkili resmi değiştirebilmeniz için işlevsellik ekleyeceksiniz. Resmi Firebase Storage'a yüklersiniz ve restoranı temsil eden Cloud Firestore belgesindeki resim URL'sini güncellersiniz.

Web uygulamasında kullanıcı tarafından yüklenen dosyaları kaydetmek için aşağıdaki adımları uygulayın:

  1. src/components/Restaurant.jsx dosyasında, kullanıcı bir dosya yüklediğinde çalışan kodu inceleyin:
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 });
}

Bu işlevde herhangi bir değişiklik yapmanız gerekmez ancak updateRestaurantImage() işlevinin davranışını aşağıdaki adımlarda uygulayabilirsiniz.

  1. src/lib/firebase/storage.js dosyasında, updateRestaurantImage() ve uploadImage() işlevlerini aşağıdaki kodla değiştirin:
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);
}

updateRestaurantImageReference() işlevi sizin için zaten uygulanmış. Bu işlev, Cloud Firestore'da mevcut bir restoran dokümanını güncellenmiş bir resim URL'siyle günceller.

Resim yükleme işlevini doğrulama

Resmin beklendiği gibi yüklendiğini doğrulamak için aşağıdaki adımları uygulayın:

  1. "Allow users to change each restaurants' photo" (Kullanıcıların her restoranın fotoğrafını değiştirmesine izin ver) mesajını içeren bir commit oluşturun ve bunu GitHub deponuza aktarın.
    git add .
    
    git commit -m "Allow users to change each restaurants' photo"
    
    git push
    
  2. Firebase konsolunda Uygulama Barındırma sayfasını açın ve yeni dağıtımınızın tamamlanmasını bekleyin.
  3. Web uygulamasında giriş yaptığınızı doğrulayın ve bir restoran seçin.
  4. 7067eb41fea41ff0.png simgesini tıklayın ve dosya sisteminizden bir resim yükleyin. Resminiz yerel ortamınızdan ayrılır ve Cloud Storage'a yüklenir. Resim, yükledikten hemen sonra görünür.
  5. Firebase için Cloud Storage'a gidin.
  6. Restoranı temsil eden klasöre gidin. Yüklediğiniz resim klasörde bulunur.

6cf3f9e2303c931c.png

10. Üretken yapay zeka ile restoran yorumlarını özetleme

Bu bölümde, kullanıcıların her yorumu okumak zorunda kalmadan bir restoran hakkındaki genel görüşleri hızlıca anlaması için yorum özeti özelliği ekleyeceksiniz.

Cloud Secret Manager'da Gemini API anahtarı depolama

  1. Gemini API'yi kullanmak için API anahtarına ihtiyacınız vardır. Google AI Studio'yu ziyaret edin ve API anahtarı oluştur'u tıklayın.
  2. Anahtarı istediğiniz gibi adlandırın. Projeniz İçe aktarılan bir proje seçin bölümünde listelenmiyorsa Proje içe aktar'ı tıklayın, listede projenizi işaretleyin ve İçe aktar'ı tıklayın. Son olarak, İçe aktarılan bir proje seçin bölümünde projeyi seçip Anahtar oluştur'u tıklayın.
  3. Uygulama Barındırma, API anahtarları gibi hassas değerleri güvenli bir şekilde depolamanıza olanak tanımak için Cloud Secret Manager ile entegre olur:
    1. Terminalde yeni bir gizli anahtar oluşturma komutunu çalıştırın:
    firebase apphosting:secrets:set GEMINI_API_KEY
    
    1. Gizli değer istendiğinde Google AI Studio'daki Gemini API anahtarınızı kopyalayıp yapıştırın.
    2. Yeni gizli dizinin üretim veya yerel test için olup olmadığı sorulduğunda "Üretim"i seçin.
    3. Arka uçtaki hizmet hesabınızın gizli diziye erişebilmesi için erişim izni vermek isteyip istemediğiniz sorulduğunda "Evet"i seçin.
    4. Yeni gizli anahtarın apphosting.yaml'ya eklenip eklenmeyeceği sorulduğunda kabul etmek için Y yazın.

Gemini API anahtarınız artık Cloud Secret Manager'da güvenli bir şekilde saklanıyor ve App Hosting arka ucunuz tarafından erişilebiliyor.

Yorum özeti bileşenini uygulama

  1. src/components/Reviews/ReviewSummary.jsx içinde GeminiSummary işlevini aşağıdaki kodla değiştirin:
    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. "Use AI to summarize reviews" (Yorumları özetlemek için yapay zekayı kullan) yorum mesajıyla bir commit oluşturun ve bunu GitHub deponuza gönderin.
    git add .
    
    git commit -m "Use AI to summarize reviews"
    
    git push
    
  3. Firebase konsolunda Uygulama Barındırma sayfasını açın ve yeni dağıtımınızın tamamlanmasını bekleyin.
  4. Bir restoranın sayfasını açın. En üstte, sayfadaki tüm yorumların tek cümlelik bir özetini görürsünüz.
  5. Yeni bir yorum ekleyin ve sayfayı yenileyin. Özet değişikliğini görmeniz gerekir.

11. App Hosting sitenizi yayından kaldırma

Bu codelab'i tamamladıktan sonra uygulamayı kullanmaya devam etmeyecekseniz Firestore, Storage ve Gemini kaynaklarınıza kimsenin erişmemesi için uygulamayı yayından kaldırabilirsiniz. Bunu istediğiniz zaman yeniden yayınlayabilirsiniz.

App Hosting sitesini yayından kaldırmak için:

  1. Firebase konsolunda App Hosting'i açın.
  2. Uygulamanızın arka ucunu bulup Görüntüle'yi tıklayın.
  3. Backend information (Arka uç bilgileri) bölümünde, Domains'in (Alanlar) yanındaki Manage'i (Yönet) tıklayın. Bu işlem, Alanlar sayfasını yükler.
  4. Alanınızın yanındaki Diğer simgesini (üç dikey nokta) tıklayın, Alanı devre dışı bırak'ı seçin ve onaylamak için Devre dışı bırak'ı tıklayın.

12. Sonuç

Tebrikler! Firebase'i kullanarak Next.js uygulamasına nasıl özellik ve işlev ekleyeceğinizi öğrendiniz. Özellikle aşağıdaki özellikleri kullandınız:

Daha fazla bilgi