ผสานรวม Firebase กับแอป Next.js

1. ก่อนเริ่มต้น

ใน Codelab นี้ คุณจะได้เรียนรู้วิธีผสานรวม Firebase กับเว็บแอป Next.js ที่ชื่อ Friendly Eats ซึ่งเป็นเว็บไซต์สำหรับรีวิวร้านอาหาร

เว็บแอป Friendly Eats

เว็บแอปที่เสร็จสมบูรณ์จะมีฟีเจอร์ที่มีประโยชน์ซึ่งแสดงให้เห็นว่า Firebase ช่วยคุณสร้างแอป Next.js ได้อย่างไร ฟีเจอร์เหล่านี้รวมถึงสิ่งต่อไปนี้

  • การสร้างและติดตั้งใช้งานอัตโนมัติ: Codelab นี้ใช้ Firebase App Hosting เพื่อสร้างและติดตั้งใช้งานโค้ด Next.js โดยอัตโนมัติทุกครั้งที่คุณพุชไปยัง Branch ที่กำหนดค่าไว้
  • การลงชื่อเข้าใช้และการออกจากระบบ: เว็บแอปที่เสร็จสมบูรณ์จะช่วยให้คุณลงชื่อเข้าใช้ด้วย Google และออกจากระบบได้ การเข้าสู่ระบบของผู้ใช้และความต่อเนื่องจะได้รับการจัดการผ่านการตรวจสอบสิทธิ์ Firebase ทั้งหมด
  • รูปภาพ: เว็บแอปที่เสร็จสมบูรณ์จะช่วยให้ผู้ใช้ที่ลงชื่อเข้าใช้สามารถอัปโหลดรูปภาพร้านอาหารได้ ชิ้นงานรูปภาพจะจัดเก็บไว้ใน Cloud Storage for Firebase Firebase JavaScript SDK มี URL สาธารณะสำหรับรูปภาพที่อัปโหลด จากนั้นระบบจะจัดเก็บ URL สาธารณะนี้ไว้ในเอกสารร้านอาหารที่เกี่ยวข้องใน Cloud Firestore
  • รีวิว: เว็บแอปที่เสร็จสมบูรณ์จะช่วยให้ผู้ใช้ที่ลงชื่อเข้าใช้สามารถโพสต์รีวิวร้านอาหารซึ่งประกอบด้วยการให้ดาวและข้อความ ข้อมูลรีวิวจะจัดเก็บไว้ใน Cloud Firestore
  • ตัวกรอง: เว็บแอปที่เสร็จสมบูรณ์ช่วยให้ผู้ใช้ที่ลงชื่อเข้าใช้กรองรายชื่อร้านอาหารตามหมวดหมู่ สถานที่ตั้ง และราคาได้ นอกจากนี้ คุณยังปรับแต่งวิธีการจัดเรียงที่ใช้ได้ด้วย ระบบจะเข้าถึงข้อมูลจาก Cloud Firestore และใช้การค้นหา Firestore ตามตัวกรองที่ใช้

ข้อกำหนดเบื้องต้น

  • บัญชี GitHub
  • ความรู้เกี่ยวกับ Next.js และ JavaScript

สิ่งที่คุณจะได้เรียนรู้

สิ่งที่ต้องมี

  • Git
  • Node.js เวอร์ชันเสถียรล่าสุด
  • เบราว์เซอร์ที่คุณเลือก เช่น Google Chrome
  • สภาพแวดล้อมในการพัฒนาซอฟต์แวร์ที่มีตัวแก้ไขโค้ดและเทอร์มินัล
  • บัญชี Google สำหรับการสร้างและจัดการโปรเจ็กต์ Firebase
  • ความสามารถในการอัปเกรดโปรเจ็กต์ Firebase เป็นแพ็กเกจราคา Blaze

2. ตั้งค่าสภาพแวดล้อมในการพัฒนาซอฟต์แวร์และที่เก็บ GitHub

Codelab นี้มีฐานของโค้ดเริ่มต้นของแอปและใช้ Firebase CLI

สร้างที่เก็บ GitHub

ดูแหล่งที่มาของ Codelab ได้ที่ https://github.com/firebase/friendlyeats-web ที่เก็บมีโปรเจ็กต์ตัวอย่างสำหรับหลายแพลตฟอร์ม อย่างไรก็ตาม Codelab นี้ใช้เฉพาะไดเรกทอรี nextjs-start เท่านั้น โปรดจดบันทึกไดเรกทอรีต่อไปนี้

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

คัดลอกโฟลเดอร์ nextjs-start ไปยังที่เก็บของคุณเองโดยทำดังนี้

  1. สร้างโฟลเดอร์ใหม่ในคอมพิวเตอร์โดยใช้เทอร์มินัล แล้วเปลี่ยนเป็นไดเรกทอรีใหม่ โดยทำดังนี้
    mkdir codelab-friendlyeats-web
    
    cd codelab-friendlyeats-web
    
  2. ใช้แพ็กเกจ npm giget เพื่อดึงข้อมูลเฉพาะโฟลเดอร์ nextjs-start ดังนี้
    npx giget@latest "gh:firebase/friendlyeats-web/nextjs-start#master" . --install
    
  3. ติดตามการเปลี่ยนแปลงในเครื่องด้วย Git:
    git init
    
    git add .
    
    git commit -m "Codelab starting point"
    
    git branch -M main
    
  4. สร้างที่เก็บ GitHub ใหม่: https://github.com/new ตั้งชื่อตามที่ต้องการ
  5. คัดลอก URL ใหม่ที่ GitHub สร้างให้คุณ โดยขึ้นอยู่กับวิธีที่คุณตรวจสอบสิทธิ์กับ GitHub (HTTPS หรือ SSH)
    • https://github.com/<USER_NAME>/<REPOSITORY_NAME>.git หรือ
    • git@github.com:<USER_NAME>/<REPOSITORY_NAME>.git
  6. พุชการเปลี่ยนแปลงในเครื่องไปยังที่เก็บ GitHub ใหม่โดยเรียกใช้คำสั่งต่อไปนี้ แทนที่ตัวยึดตำแหน่ง <REPOSITORY_URL> ด้วย URL ของที่เก็บจริง
    git remote add origin <REPOSITORY_URL>
    
    git push -u origin main
    
  7. ตอนนี้คุณควรเห็นโค้ดเริ่มต้นในที่เก็บ GitHub แล้ว

ติดตั้งหรืออัปเดต Firebase CLI

เรียกใช้คำสั่งต่อไปนี้เพื่อยืนยันว่าคุณได้ติดตั้ง Firebase CLI และเป็นเวอร์ชัน 14.1.0 ขึ้นไป

firebase --version

หากเห็นเวอร์ชันที่ต่ำกว่าหรือไม่ได้ติดตั้ง Firebase CLI ให้เรียกใช้คำสั่งติดตั้งดังนี้

npm install -g firebase-tools@latest

หากติดตั้ง Firebase CLI ไม่ได้เนื่องจากข้อผิดพลาดเกี่ยวกับสิทธิ์ โปรดดูเอกสารประกอบของ npm หรือใช้ตัวเลือกการติดตั้งอื่น

เข้าสู่ระบบ Firebase

  1. เรียกใช้คำสั่งต่อไปนี้เพื่อเข้าสู่ระบบ Firebase CLI
    firebase login
    
  2. ป้อน Y หรือ N โดยขึ้นอยู่กับว่าคุณต้องการให้ Firebase รวบรวมข้อมูลหรือไม่
  3. ในเบราว์เซอร์ ให้เลือกบัญชี Google แล้วคลิกอนุญาต

3. ตั้งค่าโปรเจ็กต์ Firebase

ในส่วนนี้ คุณจะตั้งค่าโปรเจ็กต์ Firebase และเชื่อมโยงเว็บแอป Firebase กับโปรเจ็กต์ดังกล่าว นอกจากนี้ คุณยังจะได้ตั้งค่าบริการ Firebase ที่เว็บแอปตัวอย่างใช้ด้วย

สร้างโปรเจ็กต์ Firebase

  1. ลงชื่อเข้าใช้คอนโซล Firebase ด้วยบัญชี Google เดียวกับที่ใช้ในขั้นตอนก่อนหน้า
  2. คลิกปุ่มเพื่อสร้างโปรเจ็กต์ใหม่ แล้วป้อนชื่อโปรเจ็กต์ (เช่น FriendlyEats Codelab)
  3. คลิกต่อไป
  4. หากได้รับข้อความแจ้ง ให้อ่านและยอมรับข้อกำหนดของ Firebase แล้วคลิกต่อไป
  5. (ไม่บังคับ) เปิดใช้ความช่วยเหลือจาก AI ในคอนโซล Firebase (เรียกว่า "Gemini ใน Firebase")
  6. สำหรับ Codelab นี้ คุณไม่จำเป็นต้องใช้ Google Analytics ดังนั้นให้ปิดตัวเลือก Google Analytics
  7. คลิกสร้างโปรเจ็กต์ รอให้ระบบจัดสรรโปรเจ็กต์ แล้วคลิกต่อไป

อัปเกรดแพ็กเกจราคา Firebase

หากต้องการใช้ Firebase App Hosting และ Cloud Storage for Firebase โปรเจ็กต์ Firebase ต้องใช้แพ็กเกจราคาแบบจ่ายเมื่อใช้ (Blaze) ซึ่งหมายความว่าโปรเจ็กต์จะลิงก์กับบัญชีสำหรับการเรียกเก็บเงินใน Cloud

หากต้องการอัปเกรดโปรเจ็กต์เป็นแพ็กเกจ Blaze ให้ทำตามขั้นตอนต่อไปนี้

  1. ในคอนโซล Firebase ให้เลือกอัปเกรดแพ็กเกจ
  2. เลือกแพ็กเกจ Blaze ทำตามวิธีการบนหน้าจอเพื่อลิงก์บัญชีสำหรับการเรียกเก็บเงินใน Cloud กับโปรเจ็กต์
    หากคุณจำเป็นต้องสร้างบัญชีสำหรับการเรียกเก็บเงินใน Cloud เพื่ออัปเกรด คุณอาจต้องกลับไปที่ขั้นตอนการอัปเกรดในคอนโซล Firebase เพื่อทำการอัปเกรดให้เสร็จสมบูรณ์

เพิ่มเว็บแอปลงในโปรเจ็กต์ Firebase

  1. ไปที่ภาพรวมโปรเจ็กต์ในโปรเจ็กต์ Firebase คลิกเพิ่มแอป แล้วคลิกเว็บ
  2. ในกล่องข้อความชื่อเล่นของแอป ให้ป้อนชื่อเล่นของแอปที่จำง่าย เช่น My Next.js app
  3. ยกเลิกการเลือกช่องทำเครื่องหมายตั้งค่าโฮสติ้งของ Firebase สำหรับแอปนี้ด้วย
  4. คลิกลงทะเบียนแอป > ไปที่คอนโซล

ตั้งค่าบริการ Firebase ในคอนโซล Firebase

ตั้งค่าการตรวจสอบสิทธิ์

  1. ในแผงด้านซ้ายของคอนโซล Firebase ให้ขยายสร้าง แล้วเลือกการตรวจสอบสิทธิ์
  2. คลิกเริ่มต้นใช้งาน
  3. ในคอลัมน์ผู้ให้บริการลงชื่อเข้าใช้ ให้คลิก Google > เปิดใช้
  4. ในกล่องข้อความชื่อโปรเจ็กต์ที่แสดงต่อสาธารณะ ให้ป้อนชื่อที่จำง่าย เช่น My Next.js app
  5. จากเมนูแบบเลื่อนลงอีเมลสนับสนุนสำหรับโปรเจ็กต์ ให้เลือกอีเมลของคุณ
  6. คลิกบันทึก

ตั้งค่า Cloud Firestore

  1. ในแผงด้านซ้ายของคอนโซล Firebase ให้ขยายสร้าง แล้วเลือกฐานข้อมูล Firestore
  2. คลิกสร้างฐานข้อมูล
  3. เลือก Standard Edition แล้วคลิกถัดไป
  4. อย่าเปลี่ยนรหัสฐานข้อมูล โดยปล่อยให้ตั้งค่าเป็น (default)
  5. เลือกตำแหน่งสำหรับฐานข้อมูล แล้วคลิกถัดไป
    สำหรับแอปจริง คุณควรเลือกตำแหน่งที่อยู่ใกล้กับผู้ใช้
  6. คลิกเริ่มในโหมดทดสอบ อ่านข้อจำกัดความรับผิดเกี่ยวกับกฎความปลอดภัย
    ในภายหลังใน Codelab นี้ คุณจะเพิ่มกฎความปลอดภัยเพื่อรักษาความปลอดภัยให้ข้อมูลของคุณ อย่าเผยแพร่หรือเปิดเผยแอปต่อสาธารณะโดยไม่เพิ่มกฎความปลอดภัยสำหรับฐานข้อมูล
  7. คลิกสร้าง

ตั้งค่า Cloud Storage for Firebase

  1. ในแผงด้านซ้ายของคอนโซล Firebase ให้ขยายสร้าง แล้วเลือกพื้นที่เก็บข้อมูล
  2. คลิกเริ่มต้นใช้งาน
  3. เลือกตำแหน่งสำหรับที่เก็บข้อมูลเริ่มต้น
    ที่เก็บข้อมูลในUS-WEST1, US-CENTRAL1 และUS-EAST1สามารถใช้ประโยชน์จากระดับ "ฟรีตลอด" สำหรับ Google Cloud Storage ส่วนที่เก็บข้อมูลในตำแหน่งอื่นๆ ทั้งหมดจะเป็นไปตามราคาและการใช้งาน Google Cloud Storage
  4. คลิกเริ่มในโหมดทดสอบ อ่านข้อจำกัดความรับผิดเกี่ยวกับกฎความปลอดภัย
    ในภายหลังใน Codelab นี้ คุณจะเพิ่มกฎความปลอดภัยเพื่อรักษาความปลอดภัยให้ข้อมูลของคุณ อย่าเผยแพร่หรือเปิดเผยแอปต่อสาธารณะโดยไม่เพิ่มกฎความปลอดภัยสำหรับที่เก็บข้อมูล Storage
  5. คลิกสร้าง

ติดตั้งใช้งานกฎความปลอดภัย

โค้ดมีชุดกฎความปลอดภัยสำหรับ Firestore และ Cloud Storage for Firebase อยู่แล้ว หลังจากติดตั้งใช้งานกฎความปลอดภัยแล้ว ข้อมูลในฐานข้อมูลและที่เก็บข้อมูลจะได้รับการปกป้องจากการใช้ในทางที่ผิดได้ดียิ่งขึ้น

  1. ในเทอร์มินัล ให้กำหนดค่า CLI เพื่อใช้โปรเจ็กต์ Firebase ที่คุณสร้างไว้ก่อนหน้านี้ โดยทำดังนี้
    firebase use --add
    
    เมื่อระบบขอชื่อแทน ให้ป้อน friendlyeats-codelab
  2. หากต้องการติดตั้งใช้งานกฎความปลอดภัยเหล่านี้ (รวมถึงดัชนีที่จำเป็นในภายหลัง) ให้เรียกใช้คำสั่งนี้ในเทอร์มินัล
    firebase deploy --only firestore,storage
    
  3. หากระบบถามว่า "Cloud Storage for Firebase needs an IAM Role to use cross-service rules. Grant the new role?" ให้กด Enter เพื่อเลือกใช่

4. ตรวจสอบฐานของโค้ดเริ่มต้น

ในส่วนนี้ คุณจะได้ตรวจสอบบางส่วนของฐานของโค้ดเริ่มต้นของแอปซึ่งคุณจะเพิ่มฟังก์ชันการทำงานใน Codelab นี้

โครงสร้างโฟลเดอร์และไฟล์

ตารางต่อไปนี้แสดงภาพรวมของโครงสร้างโฟลเดอร์และไฟล์ของแอป

โฟลเดอร์และไฟล์

คำอธิบาย

src/components

คอมโพเนนต์ React สำหรับตัวกรอง ส่วนหัว รายละเอียดร้านอาหาร และรีวิว

src/lib

ฟังก์ชันยูทิลิตีที่ไม่จำเป็นต้องเชื่อมโยงกับ React หรือ Next.js

src/lib/firebase

โค้ดเฉพาะ Firebase และการกำหนดค่า Firebase

public

ชิ้นงานแบบคงที่ในเว็บแอป เช่น ไอคอน

src/app

การกำหนดเส้นทางด้วย Next.js App Router

package.json และ package-lock.json

ทรัพยากร Dependency ของโปรเจ็กต์ที่มี npm

next.config.js

การกำหนดค่าเฉพาะ Next.js (การดำเนินการของเซิร์ฟเวอร์เปิดอยู่)

jsconfig.json

การกำหนดค่าบริการภาษา JavaScript

คอมโพเนนต์เซิร์ฟเวอร์และไคลเอ็นต์

แอปนี้เป็นเว็บแอป Next.js ที่ใช้ App Router มีการใช้การแสดงผลฝั่งเซิร์ฟเวอร์ทั่วทั้งแอป ตัวอย่างเช่น ไฟล์ src/app/page.js เป็นคอมโพเนนต์ฝั่งเซิร์ฟเวอร์ที่รับผิดชอบหน้าหลัก ไฟล์ src/components/RestaurantListings.jsx เป็นคอมโพเนนต์ฝั่งไคลเอ็นต์ที่ระบุโดยคำสั่ง "use client" ที่จุดเริ่มต้นของไฟล์

นำเข้ารายการเคลื่อนไหวของบัญชี

คุณอาจสังเกตเห็นคำสั่งนำเข้า เช่น

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

แอปใช้สัญลักษณ์ @ เพื่อหลีกเลี่ยงเส้นทางการนำเข้าแบบสัมพัทธ์ที่ยุ่งยาก และใช้ชื่อแทนเส้นทางเพื่อให้เป็นไปได้

API เฉพาะของ Firebase

โค้ด Firebase API ทั้งหมดจะรวมอยู่ในไดเรกทอรี src/lib/firebase จากนั้นคอมโพเนนต์ React แต่ละรายการจะนำเข้าฟังก์ชันที่รวมไว้จากไดเรกทอรี src/lib/firebase แทนที่จะนำเข้าฟังก์ชันของ Firebase โดยตรง

ข้อมูลจำลอง

ข้อมูลร้านอาหารและรีวิวจำลองอยู่ในไฟล์ src/lib/randomData.js ข้อมูลจากไฟล์ดังกล่าวจะรวมอยู่ในโค้ดในไฟล์ src/lib/fakeRestaurants.js

5. สร้างแบ็กเอนด์ App Hosting

ในส่วนนี้ คุณจะตั้งค่าแบ็กเอนด์ App Hosting เพื่อดูสาขาในที่เก็บ Git

เมื่อจบส่วนนี้ คุณจะมีแบ็กเอนด์ App Hosting ที่เชื่อมต่อกับที่เก็บใน GitHub ซึ่งจะสร้างใหม่และเปิดตัวแอปเวอร์ชันใหม่โดยอัตโนมัติทุกครั้งที่คุณพุชคอมมิตใหม่ไปยังสาขา main

สร้างแบ็กเอนด์

  1. ไปที่หน้า App Hosting ในคอนโซล Firebase
  2. คลิกเริ่มต้นใช้งานเพื่อเริ่มขั้นตอนการสร้างแบ็กเอนด์
  3. เลือกภูมิภาค สำหรับแอปจริง คุณควรเลือกภูมิภาคที่ใกล้กับผู้ใช้มากที่สุด
  4. ทำตามข้อความแจ้งในขั้นตอนนำเข้าที่เก็บ GitHub เพื่อตั้งค่าการตรวจสอบสิทธิ์ GitHub
  5. จากที่เก็บ ให้เลือกให้สิทธิ์เข้าถึงที่เก็บใหม่ใน GitHub แล้วทำตามข้อความแจ้งเพื่อเปิดใช้สิทธิ์เข้าถึงที่เก็บ GitHub ที่คุณสร้างไว้ก่อนหน้านี้
  6. คลิกรีเฟรชรายการเพื่อรีเฟรชรายการ จากนั้นเลือกที่เก็บข้อมูลแล้วคลิกถัดไป
  7. ตั้งค่าการติดตั้งใช้งาน
    1. ตั้งค่าสาขาที่ใช้จริงเป็น main
    2. เก็บไดเรกทอรีรากเป็น /
    3. เปิดใช้การเปิดตัวอัตโนมัติ
  8. ตั้งชื่อแบ็กเอนด์ friendlyeats-codelab แล้วคลิกถัดไป
  9. จากเชื่อมโยงเว็บแอป Firebase ให้เลือกเลือกเว็บแอป Firebase ที่มีอยู่ แล้วเลือกแอปที่คุณเพิ่มจากรายการ
  10. คลิกเสร็จสิ้นและติดตั้งใช้งาน ระบบจะเปลี่ยนเส้นทางคุณไปยังหน้าใหม่ซึ่งคุณจะเห็นสถานะของแบ็กเอนด์ App Hosting ใหม่
  11. คลิกดูเพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับการติดตั้งใช้งาน App Hosting รวมถึงสถานะการเปิดตัว บันทึก และรายละเอียดการใช้งาน
  12. หลังจากเปิดตัวเสร็จแล้ว ให้คลิกเพื่อเปิด URL ของเว็บไซต์ในส่วนโดเมน การดำเนินการนี้อาจใช้เวลาสักครู่จึงจะเริ่มทำงานเนื่องจากการเผยแพร่ DNS
  13. อ๊ะ! เมื่อโหลดหน้าเว็บ คุณจะเห็นข้อความแสดงข้อผิดพลาดที่ระบุว่า "Application error: a server-side exception has occurred (see the server logs for more information)"
  14. ในคอนโซล Firebase ให้ตรวจสอบแท็บบันทึกของแบ็กเอนด์ App Hosting คุณจะเห็นบันทึก "ข้อผิดพลาด: ไม่ได้ติดตั้งใช้งาน" เราจะแก้ไขปัญหานี้ในขั้นตอนถัดไปเมื่อเพิ่มการตรวจสอบสิทธิ์

คุณได้ติดตั้งใช้งานเว็บแอปเริ่มต้นแล้ว ทุกครั้งที่คุณพุชคอมมิตใหม่ไปยังสาขา main ของที่เก็บ GitHub คุณจะเห็นบิลด์ใหม่และการเปิดตัวเริ่มต้นในคอนโซล Firebase และเว็บไซต์จะอัปเดตโดยอัตโนมัติหลังจากการเปิดตัวเสร็จสมบูรณ์

6. เพิ่มการตรวจสอบสิทธิ์ลงในเว็บแอป

ในส่วนนี้ คุณจะเพิ่มการตรวจสอบสิทธิ์ลงในเว็บแอปเพื่อให้เข้าสู่ระบบได้

เพิ่มโดเมนที่ได้รับอนุญาต

การตรวจสอบสิทธิ์ Firebase จะยอมรับคำขอลงชื่อเข้าใช้จากโดเมนที่คุณอนุญาตเท่านั้น ในขั้นตอนนี้ เราจะเพิ่มโดเมนแบ็กเอนด์ของ App Hosting ลงในรายการโดเมนที่ได้รับอนุมัติในโปรเจ็กต์

  1. เปิดหน้า App Hosting แล้วคลิกดูใต้เว็บไซต์ที่ทำให้ใช้งานได้เพื่อเข้าถึงหน้าภาพรวม คัดลอกชื่อโดเมนของแบ็กเอนด์ App Hosting
  2. ไปที่แท็บการตั้งค่าการตรวจสอบสิทธิ์ แล้วเลือกโปรเจ็กต์ที่ต้องการเพิ่มโดเมนที่ได้รับอนุญาต จากนั้นค้นหาส่วนโดเมนที่ได้รับอนุญาต แล้วคลิก
  3. คลิกปุ่มเพิ่มโดเมน
  4. ป้อนโดเมนของแบ็กเอนด์ App Hosting
  5. คลิกเพิ่ม

ใช้ฟังก์ชันการลงชื่อเข้าใช้และออกจากระบบ

ในไฟล์ src/lib/firebase/auth.js ให้แทนที่ฟังก์ชัน onAuthStateChanged, onIdTokenChanged, signInWithGoogle และ signOut ด้วยโค้ดต่อไปนี้

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

โค้ดนี้ใช้ Firebase API ต่อไปนี้

Firebase API

คำอธิบาย

auth.onAuthStateChanged

เพิ่มผู้สังเกตการณ์สำหรับการเปลี่ยนแปลงสถานะการลงชื่อเข้าใช้ของผู้ใช้

auth.onIdTokenChanged

เพิ่มผู้สังเกตการณ์สำหรับการเปลี่ยนแปลงโทเค็นระบุตัวตนของผู้ใช้

GoogleAuthProvider

สร้างอินสแตนซ์ผู้ให้บริการตรวจสอบสิทธิ์ของ Google

signInWithPopup

เริ่มขั้นตอนการตรวจสอบสิทธิ์ตามกล่องโต้ตอบ

auth.signOut

นำผู้ใช้ออกจากระบบ

ในไฟล์ src/components/Header.jsx โค้ดจะเรียกใช้ฟังก์ชัน signInWithGoogle และ signOut อยู่แล้ว

ส่งสถานะการตรวจสอบสิทธิ์ไปยังเซิร์ฟเวอร์

เราจะใช้คุกกี้เพื่อส่งสถานะการตรวจสอบสิทธิ์ไปยังเซิร์ฟเวอร์ เมื่อใดก็ตามที่สถานะการตรวจสอบสิทธิ์เปลี่ยนแปลงในไคลเอ็นต์ เราจะอัปเดตคุกกี้ __session

ใน src/components/Header.jsx ให้แทนที่ฟังก์ชัน useUserSession ด้วยโค้ดต่อไปนี้

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

อ่านสถานะการตรวจสอบสิทธิ์บนเซิร์ฟเวอร์

เราจะใช้ FirebaseServerApp เพื่อจำลองสถานะการตรวจสอบสิทธิ์ของไคลเอ็นต์บนเซิร์ฟเวอร์

เปิด src/lib/firebase/serverApp.js และแทนที่ฟังก์ชัน 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 };
}

ยืนยันการเปลี่ยนแปลง

เลย์เอาต์รูทในไฟล์ src/app/layout.js จะแสดงผลส่วนหัวและส่งต่อผู้ใช้ (หากมี) เป็นพร็อพ

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

ซึ่งหมายความว่าคอมโพเนนต์ <Header> จะแสดงผลข้อมูลผู้ใช้ (หากมี) ในระหว่างรันไทม์ของเซิร์ฟเวอร์ หากมีการอัปเดตการตรวจสอบสิทธิ์ระหว่างวงจรของหน้าเว็บหลังจากโหลดหน้าเว็บครั้งแรก ตัวแฮนเดิล onAuthStateChanged จะจัดการการอัปเดตเหล่านั้น

ตอนนี้ก็ได้เวลาเปิดตัวบิลด์ใหม่และยืนยันสิ่งที่คุณสร้างขึ้นแล้ว

  1. สร้างคอมมิตที่มีข้อความคอมมิตว่า "เพิ่มการตรวจสอบสิทธิ์" แล้วพุชไปยังที่เก็บ GitHub
    git add .
    
    git commit -m "Add authentication"
    
    git push
    
  2. เปิดหน้า App Hosting และเมื่อการเปิดตัวใหม่เสร็จสมบูรณ์ ให้คลิก URL ของเว็บไซต์เพื่อเปิด
  3. ทดสอบการตรวจสอบสิทธิ์:
    1. ลงชื่อเข้าใช้ด้วยบัญชี Google และยืนยันว่าชื่อที่แสดงปรากฏในส่วนหัวหลังจากลงชื่อเข้าใช้
    2. ออกจากระบบและลงชื่อเข้าใช้อีกครั้ง คุณสามารถทำขั้นตอนนี้ซ้ำกับผู้ใช้รายอื่นได้
    3. ไม่บังคับ: คลิกขวาที่เว็บแอป เลือกดูซอร์สโค้ดของหน้าเว็บ แล้วค้นหาชื่อที่แสดง โดยจะปรากฏในแหล่งที่มา HTML ดิบที่ส่งคืนจากเซิร์ฟเวอร์

7. ดูข้อมูลร้านอาหาร

เว็บแอปมีข้อมูลจำลองสำหรับร้านอาหารและรีวิว

เพิ่มร้านอาหารอย่างน้อย 1 ร้าน

หากต้องการแทรกข้อมูลร้านอาหารจำลองลงในฐานข้อมูล Cloud Firestore ในเครื่อง ให้ทำตามขั้นตอนต่อไปนี้

  1. ลงชื่อเข้าใช้เว็บแอป หากยังไม่ได้ดำเนินการ จากนั้นเลือก 2cf67d488d8e6332.png> เพิ่มร้านอาหารตัวอย่าง โปรดทราบว่าเราไม่เห็นร้านอาหารใดๆ แสดงในเว็บแอป Friendly Eats เนื่องจากเรายังไม่ได้ตั้งค่าโค้ดการดึงข้อมูล เราจะแก้ไขปัญหานี้ในขั้นตอนถัดไป
  2. ในคอนโซล Firebase บนหน้าฐานข้อมูล Firestore ให้เลือก restaurants คุณจะเห็นเอกสารระดับบนสุดในคอลเล็กชันร้านอาหาร ซึ่งแต่ละรายการแสดงถึงร้านอาหาร 1 ร้าน
  3. คลิกเอกสาร 2-3 รายการเพื่อสำรวจพร็อพเพอร์ตี้ของเอกสารร้านอาหาร

แสดงรายชื่อร้านอาหาร

ตอนนี้ฐานข้อมูล Cloud Firestore มีร้านอาหารที่เว็บแอป Next.js แสดงได้แล้ว

หากต้องการกำหนดโค้ดการดึงข้อมูล ให้ทำตามขั้นตอนต่อไปนี้

  1. ในไฟล์ src/app/page.js ให้ค้นหาคอมโพเนนต์เซิร์ฟเวอร์ <Home /> และตรวจสอบการเรียกใช้ฟังก์ชัน getRestaurants ซึ่งจะดึงข้อมูลรายชื่อร้านอาหารที่รันไทม์ของเซิร์ฟเวอร์ คุณใช้ฟังก์ชัน getRestaurants ในขั้นตอนต่อไปนี้
  2. ในไฟล์ src/lib/firebase/firestore.js ให้แทนที่ฟังก์ชัน applyQueryFilters และ getRestaurants ด้วยโค้ดต่อไปนี้
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" แล้วพุชไปยังที่เก็บ GitHub ของคุณ
    git add .
    
    git commit -m "Read the list of restaurants from Firestore"
    
    git push
    
  2. เปิดหน้า App Hosting ในคอนโซล Firebase แล้วรอให้การเปิดตัวใหม่เสร็จสมบูรณ์
  3. รีเฟรชหน้าในเว็บแอป รูปภาพร้านอาหารจะปรากฏเป็นชิ้นส่วนบนหน้าเว็บ

ตรวจสอบว่าข้อมูลร้านอาหารโหลดที่รันไทม์ของเซิร์ฟเวอร์

เมื่อใช้เฟรมเวิร์ก Next.js คุณอาจไม่ทราบว่าระบบโหลดข้อมูลเมื่อใดในรันไทม์ฝั่งเซิร์ฟเวอร์หรือรันไทม์ฝั่งไคลเอ็นต์

หากต้องการยืนยันว่าข้อมูลร้านอาหารโหลดที่รันไทม์ของเซิร์ฟเวอร์ ให้ทำตามขั้นตอนต่อไปนี้

  1. ในเว็บแอป ให้เปิดเครื่องมือสำหรับนักพัฒนาเว็บและปิดใช้ JavaScript

ปิดใช้ JavaScript ในเครื่องมือสำหรับนักพัฒนาเว็บ

  1. รีเฟรชเว็บแอป ข้อมูลร้านอาหารจะยังคงโหลดอยู่ ข้อมูลร้านอาหารจะแสดงในการตอบกลับของเซิร์ฟเวอร์ เมื่อเปิดใช้ JavaScript ข้อมูลร้านอาหารจะได้รับการเติมเต็มผ่านโค้ด JavaScript ฝั่งไคลเอ็นต์
  2. เปิดใช้ JavaScript อีกครั้งในเครื่องมือสำหรับนักพัฒนาเว็บ

คอยฟังการอัปเดตเกี่ยวกับร้านอาหารด้วย Listener สแนปชอตของ Cloud Firestore

ในส่วนก่อนหน้า คุณได้เห็นวิธีโหลดชุดร้านอาหารเริ่มต้นจากไฟล์ src/app/page.js ไฟล์ src/app/page.js เป็นคอมโพเนนต์ของเซิร์ฟเวอร์และแสดงผลบนเซิร์ฟเวอร์ รวมถึงโค้ดการดึงข้อมูล Firebase

ไฟล์ src/components/RestaurantListings.jsx เป็นคอมโพเนนต์ฝั่งไคลเอ็นต์และสามารถกำหนดค่าให้ไฮเดรตมาร์กอัปที่แสดงผลฝั่งเซิร์ฟเวอร์ได้

หากต้องการกำหนดค่าไฟล์ src/components/RestaurantListings.jsx เพื่อเติมมาร์กอัปที่แสดงผลฝั่งเซิร์ฟเวอร์ ให้ทำตามขั้นตอนต่อไปนี้

  1. ในไฟล์ src/components/RestaurantListings.jsx ให้สังเกตโค้ดต่อไปนี้ซึ่งเขียนไว้ให้คุณแล้ว
useEffect(() => {
    return getRestaurantsSnapshot((data) => {
      setRestaurants(data);
    }, filters);
  }, [filters]);

โค้ดนี้จะเรียกใช้ฟังก์ชัน getRestaurantsSnapshot() ซึ่งคล้ายกับฟังก์ชัน getRestaurants() ที่คุณใช้ในขั้นตอนก่อนหน้า อย่างไรก็ตาม ฟังก์ชันสแนปชอตนี้มีกลไก Callback เพื่อให้ระบบเรียกใช้ Callback ทุกครั้งที่มีการเปลี่ยนแปลงคอลเล็กชันของร้านอาหาร

  1. ในไฟล์ src/lib/firebase/firestore.js ให้แทนที่ฟังก์ชัน getRestaurantsSnapshot() ด้วยโค้ดต่อไปนี้
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 ให้แทนที่ฟังก์ชัน getRestaurantSnapshotById() ด้วยโค้ดต่อไปนี้
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 จะแสดงในเว็บแอปแบบเรียลไทม์แล้ว

  1. สร้างคอมมิตที่มีข้อความคอมมิตว่า "Listen for realtime restaurant updates" แล้วพุชไปยังที่เก็บ GitHub
    git add .
    
    git commit -m "Listen for realtime restaurant updates"
    
    git push
    
  2. เปิดหน้า App Hosting ในคอนโซล Firebase แล้วรอให้การเปิดตัวใหม่เสร็จสมบูรณ์
  3. ในเว็บแอป ให้เลือก 27ca5d1e8ed8adfe.png> เพิ่มร้านอาหารตัวอย่าง หากใช้ฟังก์ชันสแนปชอตอย่างถูกต้อง ร้านอาหารจะปรากฏแบบเรียลไทม์โดยไม่ต้องรีเฟรชหน้าเว็บ

8. บันทึกรีวิวที่ผู้ใช้ส่งมาจากเว็บแอป

  1. ในไฟล์ src/lib/firebase/firestore.js ให้แทนที่ฟังก์ชัน updateWithRating() ด้วยโค้ดต่อไปนี้
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()),
  });
};

โค้ดนี้จะแทรกเอกสาร Firestore ใหม่ที่แสดงถึงรีวิวใหม่ นอกจากนี้ โค้ดยังอัปเดตเอกสาร Firestore ที่มีอยู่ซึ่งแสดงถึงร้านอาหารด้วยตัวเลขที่อัปเดตสำหรับจำนวนคะแนนและคะแนนเฉลี่ยที่คำนวณได้

  1. แทนที่ฟังก์ชัน addReviewToRestaurant() ด้วยโค้ดต่อไปนี้
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

Next.js Server Action มี API ที่สะดวกในการเข้าถึงข้อมูลแบบฟอร์ม เช่น data.get("text") เพื่อรับค่าข้อความจากเพย์โหลดการส่งแบบฟอร์ม

หากต้องการใช้ Next.js Server Action เพื่อประมวลผลการส่งแบบฟอร์มรีวิว ให้ทำตามขั้นตอนต่อไปนี้

  1. ในไฟล์ src/components/ReviewDialog.jsx ให้ค้นหาแอตทริบิวต์ action ในองค์ประกอบ <form>
<form
  action={handleReviewFormSubmission}
  onSubmit={() => {
    handleClose();
  }}
>

ค่าแอตทริบิวต์ action หมายถึงฟังก์ชันที่คุณใช้ในขั้นตอนถัดไป

  1. ในไฟล์ src/app/actions.js ให้แทนที่ฟังก์ชัน handleReviewFormSubmission() ด้วยโค้ดต่อไปนี้
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"),
  });
}

เพิ่มรีวิวสำหรับร้านอาหาร

คุณได้ใช้การรองรับการส่งรีวิวแล้ว ตอนนี้คุณจึงยืนยันได้ว่าระบบแทรกรีวิวลงใน Cloud Firestore อย่างถูกต้อง

หากต้องการเพิ่มรีวิวและยืนยันว่าได้แทรกลงใน Cloud Firestore แล้ว ให้ทำตามขั้นตอนต่อไปนี้

  1. สร้างคอมมิตที่มีข้อความคอมมิตว่า "อนุญาตให้ผู้ใช้ส่งรีวิวร้านอาหาร" และพุชไปยังที่เก็บ GitHub ของคุณ
    git add .
    
    git commit -m "Allow users to submit restaurant reviews"
    
    git push
    
  2. เปิดหน้า App Hosting ในคอนโซล Firebase แล้วรอให้การเปิดตัวใหม่เสร็จสมบูรณ์
  3. รีเฟรชเว็บแอป แล้วเลือกร้านอาหารจากหน้าแรก
  4. คลิก 3e19beef78bb0d0e.png ในหน้าของร้านอาหาร
  5. เลือกการให้ดาว
  6. เขียนรีวิว
  7. คลิกส่ง รีวิวของคุณจะปรากฏที่ด้านบนของรายการรีวิว
  8. ใน Cloud Firestore ให้ค้นหาแผงเพิ่มเอกสารเพื่อหาเอกสารของร้านอาหารที่คุณรีวิว แล้วเลือกเอกสารนั้น
  9. ในแผงเริ่มการรวบรวม ให้เลือกการจัดประเภท
  10. ในแผงเพิ่มเอกสาร ให้ค้นหาเอกสารที่ต้องการตรวจสอบเพื่อยืนยันว่าได้แทรกตามที่คาดไว้

9. บันทึกไฟล์ที่ผู้ใช้อัปโหลดจากเว็บแอป

ในส่วนนี้ คุณจะเพิ่มฟังก์ชันการทำงานเพื่อให้แทนที่รูปภาพที่เชื่อมโยงกับร้านอาหารได้เมื่อเข้าสู่ระบบ คุณอัปโหลดรูปภาพไปยังพื้นที่เก็บข้อมูลของ Firebase และอัปเดต URL ของรูปภาพในเอกสาร Cloud Firestore ที่แสดงถึงร้านอาหาร

หากต้องการบันทึกไฟล์ที่ผู้ใช้อัปโหลดจากเว็บแอป ให้ทำตามขั้นตอนต่อไปนี้

  1. ในไฟล์ src/components/Restaurant.jsx ให้สังเกตโค้ดที่ทำงานเมื่อผู้ใช้อัปโหลดไฟล์ ดังนี้
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 });
}

คุณไม่จำเป็นต้องทำการเปลี่ยนแปลงใดๆ กับฟังก์ชันนี้ แต่คุณจะใช้ลักษณะการทำงานของฟังก์ชัน updateRestaurantImage() ในขั้นตอนต่อไปนี้

  1. ในไฟล์ src/lib/firebase/storage.js ให้แทนที่ฟังก์ชัน updateRestaurantImage() และ uploadImage() ด้วยโค้ดต่อไปนี้
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() ให้คุณแล้ว ฟังก์ชันนี้จะอัปเดตเอกสารร้านอาหารที่มีอยู่ใน Cloud Firestore ด้วย URL รูปภาพที่อัปเดตแล้ว

ยืนยันฟังก์ชันการอัปโหลดรูปภาพ

หากต้องการยืนยันว่ารูปภาพอัปโหลดตามที่คาดไว้ ให้ทำตามขั้นตอนต่อไปนี้

  1. สร้างคอมมิตที่มีข้อความคอมมิตว่า "Allow users to change each restaurants' photo" แล้วพุชไปยังที่เก็บ GitHub
    git add .
    
    git commit -m "Allow users to change each restaurants' photo"
    
    git push
    
  2. เปิดหน้า App Hosting ในคอนโซล Firebase แล้วรอให้การเปิดตัวใหม่เสร็จสมบูรณ์
  3. ในเว็บแอป ให้ยืนยันว่าคุณเข้าสู่ระบบแล้วและเลือกร้านอาหาร
  4. คลิก 7067eb41fea41ff0.png แล้วอัปโหลดรูปภาพจากระบบไฟล์ รูปภาพจะออกจากสภาพแวดล้อมในเครื่องและอัปโหลดไปยัง Cloud Storage รูปภาพจะปรากฏขึ้นทันทีหลังจากที่คุณอัปโหลด
  5. ไปที่ Cloud Storage for Firebase
  6. ไปที่โฟลเดอร์ที่แสดงถึงร้านอาหาร รูปภาพที่คุณอัปโหลดมีอยู่ในโฟลเดอร์แล้ว

6cf3f9e2303c931c.png

10. สรุปรีวิวร้านอาหารด้วย Generative AI

ในส่วนนี้ คุณจะเพิ่มฟีเจอร์สรุปรีวิวเพื่อให้ผู้ใช้เข้าใจสิ่งที่ทุกคนคิดเกี่ยวกับร้านอาหารได้อย่างรวดเร็วโดยไม่ต้องอ่านรีวิวทุกรายการ

จัดเก็บคีย์ Gemini API ใน Cloud Secret Manager

  1. หากต้องการใช้ Gemini API คุณจะต้องมีคีย์ API ไปที่ Google AI Studio แล้วคลิกสร้างคีย์ API
  2. ตั้งชื่อคีย์ตามต้องการ หากโปรเจ็กต์ไม่อยู่ในส่วนเลือกโปรเจ็กต์ที่นำเข้า ให้คลิกนำเข้าโปรเจ็กต์ เลือกโปรเจ็กต์ในรายการ แล้วคลิกนำเข้า สุดท้าย ให้เลือกโปรเจ็กต์ในส่วนเลือกโปรเจ็กต์ที่นำเข้า แล้วคลิกสร้างคีย์
  3. App Hosting ผสานรวมกับ Cloud Secret Manager เพื่อให้คุณจัดเก็บค่าที่ละเอียดอ่อน เช่น คีย์ API ได้อย่างปลอดภัย
    1. ในเทอร์มินัล ให้เรียกใช้คำสั่งเพื่อสร้างข้อมูลลับใหม่ ดังนี้
    firebase apphosting:secrets:set GEMINI_API_KEY
    
    1. เมื่อระบบแจ้งให้ป้อนค่าข้อมูลลับ ให้คัดลอกและวางคีย์ Gemini API จาก Google AI Studio
    2. เมื่อระบบถามว่าข้อมูลลับใหม่มีไว้สำหรับการใช้งานจริงหรือการทดสอบในเครื่อง ให้เลือก "ใช้งานจริง"
    3. เมื่อระบบถามว่าคุณต้องการให้สิทธิ์เข้าถึงเพื่อให้บัญชีบริการของแบ็กเอนด์เข้าถึงข้อมูลลับได้หรือไม่ ให้เลือก "ใช่"
    4. เมื่อระบบถามว่าควรเพิ่มข้อมูลลับใหม่ลงใน apphosting.yaml หรือไม่ ให้ป้อน Y เพื่อยอมรับ

ตอนนี้คีย์ Gemini API ของคุณจัดเก็บไว้อย่างปลอดภัยใน Cloud Secret Manager และเข้าถึงได้จากแบ็กเอนด์ของ App Hosting

ใช้คอมโพเนนต์สรุปรีวิว

  1. ใน src/components/Reviews/ReviewSummary.jsx ให้แทนที่ฟังก์ชัน GeminiSummary ด้วยโค้ดต่อไปนี้
    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://genkit.dev/docs/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. สร้างคอมมิตที่มีข้อความคอมมิตว่า "ใช้ AI เพื่อสรุปรีวิว" แล้วพุชไปยังที่เก็บ GitHub
    git add .
    
    git commit -m "Use AI to summarize reviews"
    
    git push
    
  3. เปิดหน้า App Hosting ในคอนโซล Firebase แล้วรอให้การเปิดตัวใหม่เสร็จสมบูรณ์
  4. เปิดหน้าเว็บของร้านอาหาร ที่ด้านบน คุณจะเห็นสรุปรีวิวทั้งหมดในหน้าเว็บเป็นประโยคเดียว
  5. เพิ่มรีวิวใหม่และรีเฟรชหน้าเว็บ คุณควรเห็นการเปลี่ยนแปลงในสรุป

11. ยกเลิกการเผยแพร่เว็บไซต์ App Hosting

หลังจากจบคอร์สเรียน Codelab นี้แล้ว หากคุณจะไม่ใช้แอปต่อ คุณสามารถเลิกเผยแพร่แอปเพื่อไม่ให้ผู้อื่นเข้าถึงทรัพยากร Firestore, Storage และ Gemini ของคุณได้ ทั้งนี้คุณเผยแพร่อีกครั้งได้ทุกเมื่อ

วิธียกเลิกการเผยแพร่เว็บไซต์ App Hosting

  1. เปิด App Hosting ในคอนโซล Firebase
  2. ค้นหาแบ็กเอนด์ของแอปแล้วคลิกดู
  3. ในส่วนข้อมูลแบ็กเอนด์ ให้คลิกจัดการข้างโดเมน ซึ่งจะโหลดหน้าโดเมน
  4. ข้างโดเมน ให้คลิกไอคอนเพิ่มเติม (จุดแนวตั้ง 3 จุด) เลือกปิดใช้โดเมน แล้วคลิกปิดใช้เพื่อยืนยัน

12. บทสรุป

ยินดีด้วย คุณได้เรียนรู้วิธีใช้ Firebase เพื่อเพิ่มฟีเจอร์และฟังก์ชันการทำงานลงในแอป Next.js โดยเฉพาะอย่างยิ่ง คุณได้ใช้สิ่งต่อไปนี้

  • Firebase App Hosting เพื่อสร้างและติดตั้งใช้งานโค้ด Next.js โดยอัตโนมัติทุกครั้งที่คุณพุชไปยัง Branch ที่กำหนดค่าไว้
  • การตรวจสอบสิทธิ์ Firebase เพื่อเปิดใช้ฟังก์ชันการลงชื่อเข้าใช้และออกจากระบบ
  • Cloud Firestore สำหรับข้อมูลร้านอาหารและข้อมูลรีวิวร้านอาหาร
  • Cloud Storage for Firebase สำหรับรูปภาพร้านอาหาร

ดูข้อมูลเพิ่มเติม