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

เว็บแอปที่สร้างเสร็จแล้วมีฟีเจอร์ที่มีประโยชน์ซึ่งแสดงให้เห็นว่า Firebase ช่วยคุณสร้างแอป Next.js ได้อย่างไร ฟีเจอร์เหล่านี้ ได้แก่
- สร้างและติดตั้งใช้งานโดยอัตโนมัติ: Codelab นี้ใช้ Firebase App Hosting เพื่อสร้างและติดตั้งใช้งานโค้ด Next.js โดยอัตโนมัติทุกครั้งที่คุณพุชไปยังกิ่งที่กำหนดค่าไว้
 - การลงชื่อเข้าใช้และออกจากระบบ: เว็บแอปที่เสร็จสมบูรณ์แล้วจะช่วยให้คุณลงชื่อเข้าใช้ด้วย Google และออกจากระบบได้ ระบบจะจัดการการเข้าสู่ระบบและการคงอยู่ของผู้ใช้ผ่าน Firebase Authentication ทั้งหมด
 - รูปภาพ: เว็บแอปที่เสร็จสมบูรณ์แล้วจะช่วยให้ผู้ใช้ที่ลงชื่อเข้าใช้สามารถอัปโหลดรูปภาพร้านอาหารได้ ระบบจะจัดเก็บชิ้นงานรูปภาพไว้ใน Cloud Storage for Firebase Firebase JavaScript SDK มี URL สาธารณะสำหรับรูปภาพที่อัปโหลด จากนั้นระบบจะจัดเก็บ URL สาธารณะนี้ไว้ในเอกสารร้านอาหารที่เกี่ยวข้องใน Cloud Firestore
 - รีวิว: เว็บแอปที่เสร็จสมบูรณ์แล้วจะช่วยให้ผู้ใช้ที่ลงชื่อเข้าใช้โพสต์รีวิวร้านอาหารซึ่งประกอบด้วยการให้คะแนนเป็นดาวและข้อความที่เป็นข้อความได้ ระบบจะจัดเก็บข้อมูลรีวิวไว้ใน Cloud Firestore
 - ตัวกรอง: เว็บแอปที่เสร็จสมบูรณ์แล้วจะช่วยให้ผู้ใช้ที่ลงชื่อเข้าใช้กรองรายชื่อร้านอาหารตามหมวดหมู่ สถานที่ตั้ง และราคาได้ นอกจากนี้ คุณยังปรับแต่งวิธีการจัดเรียงที่ใช้ได้ด้วย ระบบจะเข้าถึงข้อมูลจาก Cloud Firestore และใช้การค้นหา Firestore ตามตัวกรองที่ใช้
 
ข้อกำหนดเบื้องต้น
- บัญชี GitHub
 - มีความรู้เกี่ยวกับ Next.js และ JavaScript
 
สิ่งที่คุณจะได้เรียนรู้
- วิธีใช้ Firebase กับ App Router และการแสดงผลฝั่งเซิร์ฟเวอร์ของ Next.js
 - วิธีจัดเก็บรูปภาพอย่างถาวรใน Cloud Storage for Firebase
 - วิธีอ่านและเขียนข้อมูลในฐานข้อมูล Cloud Firestore
 - วิธีใช้การลงชื่อเข้าใช้ด้วย Google กับ Firebase JavaScript SDK
 
สิ่งที่ต้องมี
- 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 ไปยังที่เก็บของคุณเอง
- ใช้เทอร์มินัลเพื่อสร้างโฟลเดอร์ใหม่ในคอมพิวเตอร์และเปลี่ยนเป็นไดเรกทอรีใหม่โดยทำดังนี้
mkdir codelab-friendlyeats-web cd codelab-friendlyeats-web - ใช้แพ็กเกจ npm giget เพื่อดึงเฉพาะโฟลเดอร์ 
nextjs-startnpx giget@latest gh:firebase/friendlyeats-web/nextjs-start#master . --install - ติดตามการเปลี่ยนแปลงในเครื่องด้วย Git โดยทำดังนี้
git init git add . git commit -m "codelab starting point" git branch -M main - สร้างที่เก็บ GitHub ใหม่: https://github.com/new ตั้งชื่อได้ตามต้องการ
 - คัดลอก URL ใหม่ที่ GitHub สร้างให้คุณ  โดยจะมีลักษณะดังต่อไปนี้
https://github.com/<USER_NAME>/<REPOSITORY_NAME>.gitหรือgit@github.com:<USER_NAME>/<REPOSITORY_NAME>.git
 - พุชการเปลี่ยนแปลงในเครื่องไปยังที่เก็บ GitHub ใหม่โดยเรียกใช้คำสั่งต่อไปนี้ แทนที่ตัวยึดตำแหน่ง 
<REPOSITORY_URL>ด้วย URL ของที่เก็บจริงgit remote add origin <REPOSITORY_URL> git push -u origin main - ตอนนี้คุณควรเห็นโค้ดเริ่มต้นในที่เก็บ GitHub แล้ว
 
ติดตั้งหรืออัปเดต Firebase CLI
เรียกใช้คำสั่งต่อไปนี้เพื่อยืนยันว่าคุณได้ติดตั้ง Firebase CLI และเป็นเวอร์ชัน 14.1.0 ขึ้นไป
firebase --version
หากเห็นเวอร์ชันที่ต่ำกว่าหรือไม่ได้ติดตั้ง Firebase CLI ให้เรียกใช้คำสั่งติดตั้ง
npm install -g firebase-tools@latest
หากติดตั้ง Firebase CLI ไม่ได้เนื่องจากข้อผิดพลาดเกี่ยวกับสิทธิ์ โปรดดูเอกสารประกอบของ npm หรือใช้ตัวเลือกการติดตั้งอื่น
เข้าสู่ระบบ Firebase
- เรียกใช้คำสั่งต่อไปนี้เพื่อเข้าสู่ระบบ Firebase CLI
firebase login
 - ป้อน 
YหรือNขึ้นอยู่กับว่าคุณต้องการให้ Firebase รวบรวมข้อมูลหรือไม่ - ในเบราว์เซอร์ ให้เลือกบัญชี Google แล้วคลิกอนุญาต
 
3. ตั้งค่าโปรเจ็กต์ Firebase
ในส่วนนี้ คุณจะตั้งค่าโปรเจ็กต์ Firebase และเชื่อมโยงเว็บแอป Firebase กับโปรเจ็กต์ นอกจากนี้ คุณยังต้องตั้งค่าบริการ Firebase ที่เว็บแอปตัวอย่างใช้ด้วย
สร้างโปรเจ็กต์ Firebase
- ลงชื่อเข้าใช้คอนโซล Firebase โดยใช้บัญชี Google เดียวกับที่คุณใช้ในขั้นตอนก่อนหน้า
 - คลิกปุ่มเพื่อสร้างโปรเจ็กต์ใหม่ แล้วป้อนชื่อโปรเจ็กต์ (เช่น 
FriendlyEats Codelab)
 - คลิกต่อไป
 - หากได้รับแจ้ง ให้อ่านและยอมรับข้อกำหนดของ Firebase แล้วคลิกต่อไป
 - (ไม่บังคับ) เปิดใช้ความช่วยเหลือจาก AI ในคอนโซล Firebase (เรียกว่า "Gemini ใน Firebase")
 - สำหรับ Codelab นี้ คุณไม่จำเป็นต้องใช้ Google Analytics ดังนั้นให้ปิดตัวเลือก Google Analytics
 - คลิกสร้างโปรเจ็กต์ รอให้ระบบจัดสรรโปรเจ็กต์ แล้วคลิกดำเนินการต่อ
 
อัปเกรดแพ็กเกจราคาของ Firebase
หากต้องการใช้ Firebase App Hosting และ Cloud Storage สำหรับ Firebase โปรเจ็กต์ Firebase ของคุณต้องอยู่ในแพ็กเกจราคาแบบจ่ายเมื่อใช้ (Blaze) ซึ่งหมายความว่าต้องลิงก์กับบัญชีการเรียกเก็บเงินในระบบคลาวด์
- บัญชีสำหรับการเรียกเก็บเงินของ Cloud ต้องมีวิธีการชำระเงิน เช่น บัตรเครดิต
 - หากเพิ่งเริ่มใช้ Firebase และ Google Cloud โปรดตรวจสอบว่าคุณมีสิทธิ์รับเครดิต$300 และบัญชีสำหรับการเรียกเก็บเงินในระบบคลาวด์แบบทดลองใช้ฟรีหรือไม่
 - หากคุณกำลังทำ Codelab นี้เป็นส่วนหนึ่งของกิจกรรม โปรดสอบถามผู้จัดว่ามีเครดิต Cloud ให้หรือไม่
 
หากต้องการอัปเกรดโปรเจ็กต์เป็นแพ็กเกจ Blaze ให้ทำตามขั้นตอนต่อไปนี้
- ในคอนโซล Firebase ให้เลือกอัปเกรดแพ็กเกจ
 - เลือกแพ็กเกจ Blaze ทำตามวิธีการบนหน้าจอเพื่อลิงก์บัญชีสำหรับการเรียกเก็บเงินใน Cloud กับโปรเจ็กต์
หากคุณต้องสร้างบัญชีสำหรับการเรียกเก็บเงินใน Cloud เป็นส่วนหนึ่งของการอัปเกรดนี้ คุณอาจต้องกลับไปที่ขั้นตอนการอัปเกรดใน Firebase Console เพื่อทำการอัปเกรดให้เสร็จสมบูรณ์ 
เพิ่มเว็บแอปไปยังโปรเจ็กต์ Firebase
- ไปที่ภาพรวมโปรเจ็กต์ในโปรเจ็กต์ Firebase แล้วคลิก 
 Web
หากลงทะเบียนแอปในโปรเจ็กต์แล้ว ให้คลิกเพิ่มแอปเพื่อดูไอคอนเว็บ - ในกล่องข้อความชื่อเล่นของแอป ให้ป้อนชื่อเล่นของแอปที่จำง่าย เช่น 
My Next.js app - ไม่ต้องเลือกช่องทำเครื่องหมายตั้งค่าโฮสติ้งของ Firebase สำหรับแอปนี้ด้วย
 - คลิกลงทะเบียนแอป > ไปที่คอนโซล
 
ตั้งค่าบริการ Firebase ในคอนโซล Firebase
ตั้งค่าการตรวจสอบสิทธิ์
- ในคอนโซล Firebase ให้ไปที่การตรวจสอบสิทธิ์
 - คลิกเริ่มต้นใช้งาน
 - ในคอลัมน์ผู้ให้บริการเพิ่มเติม ให้คลิก Google > เปิดใช้
 - ในกล่องข้อความชื่อที่เปิดเผยต่อสาธารณะของโปรเจ็กต์ ให้ป้อนชื่อที่จดจำง่าย เช่น 
My Next.js app - เลือกอีเมลของคุณจากเมนูแบบเลื่อนลงอีเมลสนับสนุนสำหรับโปรเจ็กต์
 - คลิกบันทึก
 
ตั้งค่า Cloud Firestore
- ในแผงด้านซ้ายของคอนโซล Firebase ให้ขยายสร้าง แล้วเลือกฐานข้อมูล Firestore
 - คลิกสร้างฐานข้อมูล
 - ตั้งค่ารหัสฐานข้อมูลเป็น 
(default)ไว้ดังเดิม - เลือกตำแหน่งสำหรับฐานข้อมูล แล้วคลิกถัดไป
สำหรับแอปจริง คุณควรเลือกตำแหน่งที่อยู่ใกล้กับผู้ใช้ - คลิกเริ่มในโหมดทดสอบ อ่านข้อจำกัดความรับผิดเกี่ยวกับกฎความปลอดภัย
ในภายหลังใน Codelab นี้ คุณจะเพิ่มกฎความปลอดภัยเพื่อรักษาความปลอดภัยของข้อมูล อย่าเผยแพร่หรือเปิดเผยแอปต่อสาธารณะโดยไม่ได้เพิ่มกฎความปลอดภัยสำหรับฐานข้อมูล - คลิกสร้าง
 
ตั้งค่า Cloud Storage for Firebase
- ในแผงด้านซ้ายของคอนโซล Firebase ให้ขยายสร้าง แล้วเลือก Storage
 - คลิกเริ่มต้นใช้งาน
 - เลือกตำแหน่งสำหรับที่เก็บข้อมูลเริ่มต้น
ที่เก็บข้อมูลในUS-WEST1,US-CENTRAL1และUS-EAST1จะใช้ประโยชน์จากระดับ"ใช้งานฟรีเสมอ" สำหรับ Google Cloud Storage ได้ ที่เก็บข้อมูลในตำแหน่งอื่นๆ ทั้งหมดจะเป็นไปตามราคาและการใช้งาน Google Cloud Storage - คลิกเริ่มในโหมดทดสอบ อ่านข้อจำกัดความรับผิดเกี่ยวกับกฎความปลอดภัย
ในภายหลังใน Codelab นี้ คุณจะเพิ่มกฎความปลอดภัยเพื่อรักษาความปลอดภัยของข้อมูล อย่าเผยแพร่หรือแสดงแอปต่อสาธารณะโดยไม่ได้เพิ่มกฎความปลอดภัยสำหรับที่เก็บข้อมูล - คลิกสร้าง
 
ติดตั้งใช้งานกฎความปลอดภัย
โค้ดมีชุดกฎการรักษาความปลอดภัยสำหรับ Firestore และสำหรับ Cloud Storage สำหรับ Firebase อยู่แล้ว หลังจากที่คุณติดตั้งใช้งานกฎความปลอดภัยแล้ว ข้อมูลในฐานข้อมูลและที่เก็บข้อมูลจะได้รับการปกป้องจากการละเมิดได้ดียิ่งขึ้น
- ในเทอร์มินัล ให้กำหนดค่า CLI เพื่อใช้โปรเจ็กต์ Firebase ที่คุณสร้างไว้ก่อนหน้านี้โดยทำดังนี้
 เมื่อได้รับข้อความแจ้งให้ระบุชื่อแทน ให้ป้อนfirebase use --add
friendlyeats-codelab - หากต้องการติดตั้งใช้งานกฎความปลอดภัยเหล่านี้ (รวมถึงดัชนีที่จะต้องใช้ในภายหลัง) ให้เรียกใช้คำสั่งนี้ในเทอร์มินัล
firebase deploy --only firestore,storage
 - หากระบบถามว่า 
"Cloud Storage for Firebase needs an IAM Role to use cross-service rules. Grant the new role?"ให้กดEnterเพื่อเลือกใช่ 
4. ตรวจสอบโค้ดเบสเริ่มต้น
ในส่วนนี้ คุณจะได้ตรวจสอบโค้ดเบสเริ่มต้นของแอปบางส่วน ซึ่งคุณจะเพิ่มฟังก์ชันการทำงานในโค้ดแล็บนี้
โครงสร้างโฟลเดอร์และไฟล์
ตารางต่อไปนี้แสดงภาพรวมของโครงสร้างโฟลเดอร์และไฟล์ของแอป
โฟลเดอร์และไฟล์  | คำอธิบาย  | 
  | คอมโพเนนต์ React สำหรับตัวกรอง ส่วนหัว รายละเอียดร้านอาหาร และรีวิว  | 
  | ฟังก์ชันยูทิลิตีที่ไม่จำเป็นต้องเชื่อมโยงกับ React หรือ Next.js  | 
  | โค้ดและการกำหนดค่า Firebase โดยเฉพาะ  | 
  | ชิ้นงานแบบคงที่ในเว็บแอป เช่น ไอคอน  | 
  | การกำหนดเส้นทางด้วย App Router ของ Next.js  | 
  | ทรัพยากร Dependency ของโปรเจ็กต์ด้วย npm  | 
  | การกำหนดค่าเฉพาะ Next.js (เปิดใช้การดำเนินการของเซิร์ฟเวอร์)  | 
  | การกำหนดค่าบริการภาษา 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
สร้างแบ็กเอนด์
- ไปที่หน้า App Hosting ในคอนโซล Firebase โดยทำดังนี้
 

- คลิก "เริ่มต้นใช้งาน" เพื่อเริ่มขั้นตอนการสร้างแบ็กเอนด์ กำหนดค่าแบ็กเอนด์ดังนี้
 - เลือกภูมิภาค สำหรับแอปจริง คุณควรเลือกภูมิภาคที่ใกล้กับผู้ใช้มากที่สุด
 - ทำตามข้อความแจ้งในขั้นตอน "นำเข้าที่เก็บ GitHub" เพื่อเชื่อมต่อที่เก็บ GitHub ที่คุณสร้างไว้ก่อนหน้านี้
 - ตั้งค่าการทำให้ใช้งานได้
- เก็บไดเรกทอรีรากไว้เป็น 
/ - ตั้งค่าสาขาที่ใช้งานจริงเป็น 
main - เปิดใช้การเปิดตัวอัตโนมัติ
 
 - เก็บไดเรกทอรีรากไว้เป็น 
 - ตั้งชื่อแบ็กเอนด์ 
friendlyeats-codelab - ใน "เชื่อมโยงเว็บแอป Firebase" ให้คลิก "สร้างเว็บแอป Firebase ใหม่"
 - คลิก "เสร็จสิ้นและทำให้ใช้งานได้" หลังจากนั้น ระบบจะนำคุณไปยังหน้าใหม่ซึ่งคุณจะเห็นสถานะของแบ็กเอนด์การโฮสต์แอปใหม่
 - เมื่อการเปิดตัวเสร็จสมบูรณ์แล้ว ให้คลิกโดเมนฟรีในส่วน "โดเมน" การดำเนินการนี้อาจใช้เวลาสักครู่จึงจะเริ่มทำงานเนื่องจากการเผยแพร่ DNS
 - อ๊ะ! เมื่อโหลดหน้าเว็บ คุณจะเห็นข้อความแสดงข้อผิดพลาดที่ระบุว่า "ข้อผิดพลาดของแอปพลิเคชัน: เกิดข้อยกเว้นฝั่งเซิร์ฟเวอร์ (ดูข้อมูลเพิ่มเติมได้ในบันทึกของเซิร์ฟเวอร์)"
 - ในคอนโซล Firebase ให้ตรวจสอบแท็บ "บันทึก" ของแบ็กเอนด์ App Hosting คุณจะเห็นบันทึก "ข้อผิดพลาด: ไม่ได้ติดตั้งใช้งาน" เราจะแก้ไขปัญหานี้ในขั้นตอนถัดไปเมื่อเพิ่มการตรวจสอบสิทธิ์
 
คุณได้ติดตั้งใช้งานเว็บแอปเริ่มต้นแล้ว ทุกครั้งที่คุณพุชคอมมิตใหม่ไปยังกิ่ง main ของที่เก็บ GitHub คุณจะเห็นว่ามีการเริ่มบิลด์และการเปิดตัวใหม่ในคอนโซล Firebase และเว็บไซต์จะอัปเดตโดยอัตโนมัติเมื่อการเปิดตัวเสร็จสมบูรณ์
6. เพิ่มการตรวจสอบสิทธิ์ลงในเว็บแอป
ในส่วนนี้ คุณจะเพิ่มการตรวจสอบสิทธิ์ลงในเว็บแอปเพื่อให้เข้าสู่ระบบได้
เพิ่มโดเมนที่ได้รับอนุญาต
การตรวจสอบสิทธิ์ Firebase จะยอมรับเฉพาะคำขอลงชื่อเข้าใช้จากโดเมนที่คุณอนุญาตเท่านั้น ในส่วนนี้ เราจะเพิ่มโดเมนของแบ็กเอนด์การโฮสต์แอปไปยังรายการโดเมนที่ได้รับอนุมัติในโปรเจ็กต์
- คัดลอกโดเมนของแบ็กเอนด์ App Hosting จากหน้า "ภาพรวม" ของ App Hosting
 - ไปที่แท็บการตั้งค่าการตรวจสอบสิทธิ์ แล้วเลือกโดเมนที่ได้รับอนุญาต
 - คลิกปุ่มเพิ่มโดเมน
 - ป้อนโดเมนของแบ็กเอนด์ App Hosting
 - คลิกเพิ่ม
 
ใช้ฟังก์ชันการลงชื่อเข้าใช้และออกจากระบบ
- ในไฟล์ 
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  | คำอธิบาย  | 
เพิ่ม Observer สำหรับการเปลี่ยนแปลงสถานะการลงชื่อเข้าใช้ของผู้ใช้  | |
เพิ่ม Observer สำหรับการเปลี่ยนแปลงโทเค็นรหัสของผู้ใช้  | |
สร้างอินสแตนซ์ของผู้ให้บริการการตรวจสอบสิทธิ์ของ Google  | |
เริ่มขั้นตอนการตรวจสอบสิทธิ์ที่อิงตามกล่องโต้ตอบ  | |
นำผู้ใช้ออกจากระบบ  | 
ในไฟล์ 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 จะจัดการการอัปเดตเหล่านั้น
ตอนนี้ได้เวลาเปิดตัวบิลด์ใหม่และยืนยันสิ่งที่คุณสร้างแล้ว
- สร้างคอมมิตที่มีข้อความคอมมิตว่า "เพิ่มการตรวจสอบสิทธิ์" แล้วพุชไปยังที่เก็บ GitHub
 - เปิดหน้า App Hosting ในคอนโซล Firebase แล้วรอให้การเปิดตัวใหม่เสร็จสมบูรณ์
 - ยืนยันลักษณะการทำงานของการตรวจสอบสิทธิ์แบบใหม่
- รีเฟรชเว็บแอปในเบราว์เซอร์ ชื่อที่แสดงจะปรากฏในส่วนหัว
 - ออกจากระบบแล้วลงชื่อเข้าใช้อีกครั้ง คุณทำขั้นตอนนี้ซ้ำกับผู้ใช้รายอื่นได้
 - ไม่บังคับ: คลิกขวาที่เว็บแอป เลือกดูซอร์สโค้ดของหน้าเว็บ แล้วค้นหาชื่อที่แสดง โดยจะปรากฏในแหล่งที่มาของ HTML ดิบที่ส่งคืนจากเซิร์ฟเวอร์
 
 
7. ดูข้อมูลร้านอาหาร
เว็บแอปมีข้อมูลจำลองสำหรับร้านอาหารและรีวิว
เพิ่มร้านอาหารอย่างน้อย 1 ร้าน
หากต้องการแทรกข้อมูลร้านอาหารจำลองลงในฐานข้อมูล Cloud Firestore ในเครื่อง ให้ทำตามขั้นตอนต่อไปนี้
- ลงชื่อเข้าใช้เว็บแอป หากยังไม่ได้ทำ จากนั้นเลือก 
 > เพิ่มร้านอาหารตัวอย่าง - ในคอนโซล Firebase ในหน้าฐานข้อมูล Firestore ให้เลือก restaurants คุณจะเห็นเอกสารระดับบนสุดในคอลเล็กชันร้านอาหาร ซึ่งแต่ละเอกสารแสดงถึงร้านอาหาร
 - คลิกเอกสาร 2-3 รายการเพื่อสำรวจพร็อพเพอร์ตี้ของเอกสารร้านอาหาร
 
แสดงรายชื่อร้านอาหาร
ตอนนี้ฐานข้อมูล Cloud Firestore มีร้านอาหารที่เว็บแอป Next.js แสดงได้แล้ว
หากต้องการกำหนดโค้ดการดึงข้อมูล ให้ทำตามขั้นตอนต่อไปนี้
- ในไฟล์ 
src/app/page.jsให้ค้นหาคอมโพเนนต์เซิร์ฟเวอร์<Home />และตรวจสอบการเรียกใช้ฟังก์ชันgetRestaurantsซึ่งจะดึงรายการร้านอาหารในเวลาที่เซิร์ฟเวอร์ทำงาน คุณใช้ฟังก์ชันgetRestaurantsได้โดยทำตามขั้นตอนต่อไปนี้ - ในไฟล์ 
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(),
    };
  });
}
- สร้างคอมมิตที่มีข้อความคอมมิตว่า "อ่านรายชื่อร้านอาหารจาก Firestore" แล้วพุชไปยังที่เก็บ GitHub
 - เปิดหน้า App Hosting ในคอนโซล Firebase แล้วรอให้การเปิดตัวใหม่เสร็จสมบูรณ์
 - ในเว็บแอป ให้รีเฟรชหน้าเว็บ รูปภาพร้านอาหารจะปรากฏเป็นไทล์ในหน้า
 
ตรวจสอบว่าข้อมูลร้านอาหารโหลดที่รันไทม์ของเซิร์ฟเวอร์
การใช้เฟรมเวิร์ก Next.js อาจไม่ชัดเจนเมื่อมีการโหลดข้อมูลในเวลาเรียกใช้เซิร์ฟเวอร์หรือเวลาเรียกใช้ฝั่งไคลเอ็นต์
หากต้องการยืนยันว่าข้อมูลร้านอาหารโหลดที่รันไทม์ของเซิร์ฟเวอร์ ให้ทำตามขั้นตอนต่อไปนี้
- ในเว็บแอป ให้เปิด DevTools แล้วปิดใช้ JavaScript
 

- รีเฟรชเว็บแอป ข้อมูลร้านอาหารจะยังคงโหลดอยู่ ข้อมูลร้านอาหารจะแสดงในการตอบกลับของเซิร์ฟเวอร์ เมื่อเปิดใช้ JavaScript ระบบจะ ไฮเดรตข้อมูลร้านอาหารผ่านโค้ด JavaScript ฝั่งไคลเอ็นต์
 - เปิดใช้ JavaScript อีกครั้งในเครื่องมือสำหรับนักพัฒนาเว็บ
 
ฟังการอัปเดตร้านอาหารด้วยเครื่องมือฟังสแนปชอตของ Cloud Firestore
ในส่วนก่อนหน้า คุณได้เห็นวิธีโหลดชุดร้านอาหารเริ่มต้นจากไฟล์ src/app/page.js ไฟล์ src/app/page.js เป็นคอมโพเนนต์ฝั่งเซิร์ฟเวอร์และแสดงผลบนเซิร์ฟเวอร์ ซึ่งรวมถึงโค้ดการดึงข้อมูล Firebase
ไฟล์ src/components/RestaurantListings.jsx เป็นคอมโพเนนต์ฝั่งไคลเอ็นต์และกำหนดค่าให้ไฮเดรตมาร์กอัปที่ฝั่งเซิร์ฟเวอร์ได้
หากต้องการกำหนดค่าไฟล์ src/components/RestaurantListings.jsx เพื่อไฮเดรตมาร์กอัปที่ฝั่งเซิร์ฟเวอร์ ให้ทำตามขั้นตอนต่อไปนี้
- ในไฟล์ 
src/components/RestaurantListings.jsxให้สังเกตโค้ดต่อไปนี้ ซึ่งเขียนไว้ให้คุณแล้ว 
useEffect(() => {
    return getRestaurantsSnapshot((data) => {
      setRestaurants(data);
    }, filters);
  }, [filters]);
โค้ดนี้จะเรียกใช้ฟังก์ชัน getRestaurantsSnapshot() ซึ่งคล้ายกับฟังก์ชัน getRestaurants() ที่คุณใช้ในขั้นตอนก่อนหน้า อย่างไรก็ตาม ฟังก์ชันสแนปชอตนี้มีกลไกการเรียกกลับเพื่อให้ระบบเรียกใช้การเรียกกลับทุกครั้งที่มีการเปลี่ยนแปลงคอลเล็กชันของร้านอาหาร
- ในไฟล์ 
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);
  });
}
การเปลี่ยนแปลงที่ทำผ่านหน้าฐานข้อมูล Firestore จะแสดงในเว็บแอปแบบเรียลไทม์แล้ว
- สร้างคอมมิตด้วยข้อความคอมมิต "Listen for realtime restaurant updates" แล้วพุชไปยังที่เก็บ GitHub
 - เปิดหน้า App Hosting ในคอนโซล Firebase แล้วรอให้การเปิดตัวใหม่เสร็จสมบูรณ์
 - ในเว็บแอป ให้เลือก 
 > เพิ่มร้านอาหารตัวอย่าง หากใช้ฟังก์ชันสแนปชอตอย่างถูกต้อง ร้านอาหารจะปรากฏแบบเรียลไทม์โดยไม่ต้องรีเฟรชหน้าเว็บ 
8. บันทึกรีวิวที่ผู้ใช้ส่งจากเว็บแอป
- ในไฟล์ 
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 ที่มีอยู่ซึ่งแสดงถึงร้านอาหารด้วยตัวเลขที่อัปเดตสำหรับจำนวนการให้คะแนนและคะแนนเฉลี่ยที่คำนวณแล้ว
- แทนที่ฟังก์ชัน 
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
Server Action ของ Next.js มี API ที่สะดวกในการเข้าถึงข้อมูลแบบฟอร์ม เช่น data.get("text") เพื่อรับค่าข้อความจากเพย์โหลดการส่งแบบฟอร์ม
หากต้องการใช้ Next.js Server Action เพื่อประมวลผลการส่งแบบฟอร์มรีวิว ให้ทำตามขั้นตอนต่อไปนี้
- ในไฟล์ 
src/components/ReviewDialog.jsxให้ค้นหาแอตทริบิวต์actionในองค์ประกอบ<form> 
<form action={handleReviewFormSubmission}>
ค่าแอตทริบิวต์ action หมายถึงฟังก์ชันที่คุณจะใช้ในขั้นตอนถัดไป
- ในไฟล์ 
src/app/actions.jsให้แทนที่ฟังก์ชันhandleReviewFormSubmission()ด้วยโค้ดต่อไปนี้ 
// This is a next.js server action, which is an alpha feature, so
// use with caution.
// https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions
export async function handleReviewFormSubmission(data) {
        const { app } = await getAuthenticatedAppForUser();
        const db = getFirestore(app);
        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 แล้ว ให้ทำตามขั้นตอนต่อไปนี้
- สร้างคอมมิตพร้อมข้อความคอมมิต "อนุญาตให้ผู้ใช้ส่งรีวิวร้านอาหาร" แล้วพุชไปยังที่เก็บ GitHub
 - เปิดหน้า App Hosting ในคอนโซล Firebase แล้วรอให้การเปิดตัวใหม่เสร็จสมบูรณ์
 - รีเฟรชเว็บแอป แล้วเลือกร้านอาหารจากหน้าแรก
 - คลิก 
 ในหน้าของร้านอาหาร - เลือกการให้ดาว
 - เขียนรีวิว
 - คลิกส่ง รีวิวของคุณจะปรากฏที่ด้านบนของรายการรีวิว
 - ใน Cloud Firestore ให้ค้นหาบานหน้าต่างเพิ่มเอกสารสำหรับเอกสารของร้านอาหารที่คุณรีวิว แล้วเลือกเอกสารนั้น
 - ในแผงเริ่มรวบรวม ให้เลือกการให้คะแนน
 - ในแผงเพิ่มเอกสาร ให้ค้นหาเอกสารที่จะตรวจสอบเพื่อยืนยันว่ามีการแทรกเอกสารตามที่คาดไว้
 

9. บันทึกไฟล์ที่ผู้ใช้อัปโหลดจากเว็บแอป
ในส่วนนี้ คุณจะเพิ่มฟังก์ชันเพื่อให้แทนที่รูปภาพที่เชื่อมโยงกับร้านอาหารได้เมื่อเข้าสู่ระบบ คุณอัปโหลดรูปภาพไปยัง Firebase Storage และอัปเดต URL ของรูปภาพในเอกสาร Cloud Firestore ที่แสดงถึงร้านอาหาร
หากต้องการบันทึกไฟล์ที่ผู้ใช้อัปโหลดจากเว็บแอป ให้ทำตามขั้นตอนต่อไปนี้
- ในไฟล์ 
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() ได้ในขั้นตอนต่อไปนี้
- ในไฟล์ 
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 รูปภาพที่อัปเดตแล้ว
ยืนยันฟังก์ชันการอัปโหลดรูปภาพ
หากต้องการยืนยันว่ารูปภาพอัปโหลดตามที่คาดไว้ ให้ทำตามขั้นตอนต่อไปนี้
- สร้างคอมมิตพร้อมข้อความคอมมิตว่า "อนุญาตให้ผู้ใช้เปลี่ยนรูปภาพของร้านอาหารแต่ละร้าน" แล้วพุชไปยังที่เก็บ GitHub
 - เปิดหน้า App Hosting ในคอนโซล Firebase แล้วรอให้การเปิดตัวใหม่เสร็จสมบูรณ์
 - ในเว็บแอป ให้ตรวจสอบว่าคุณเข้าสู่ระบบแล้วและเลือกร้านอาหาร
 - คลิก 
 แล้วอัปโหลดรูปภาพจากระบบไฟล์ รูปภาพจะออกจากสภาพแวดล้อมในเครื่องและอัปโหลดไปยัง Cloud Storage รูปภาพจะปรากฏขึ้นทันทีหลังจากที่คุณอัปโหลด - ไปที่ Cloud Storage สำหรับ Firebase
 - ไปยังโฟลเดอร์ที่แสดงถึงร้านอาหาร รูปภาพที่คุณอัปโหลดจะอยู่ในโฟลเดอร์
 

10. สรุปรีวิวร้านอาหารด้วย Generative AI
ในส่วนนี้ คุณจะเพิ่มฟีเจอร์สรุปรีวิวเพื่อให้ผู้ใช้ทราบได้อย่างรวดเร็วว่าทุกคนคิดอย่างไรกับร้านอาหารโดยไม่ต้องอ่านรีวิวทั้งหมด
จัดเก็บคีย์ Gemini API ใน Cloud Secret Manager
- หากต้องการใช้ Gemini API คุณจะต้องมีคีย์ API ไปที่ Google AI Studio แล้วคลิก "สร้างคีย์ API"
 - ในช่องป้อนข้อมูล "ค้นหาโปรเจ็กต์ Google Cloud" ให้เลือกโปรเจ็กต์ Firebase โปรเจ็กต์ Firebase ทุกโปรเจ็กต์ได้รับการสนับสนุนโดยโปรเจ็กต์ Google Cloud
 - App Hosting ผสานรวมกับ Cloud Secret Manager เพื่อให้คุณจัดเก็บค่าที่มีความละเอียดอ่อน เช่น คีย์ API ได้อย่างปลอดภัย
- ในเทอร์มินัล ให้เรียกใช้คำสั่งเพื่อสร้างข้อมูลลับใหม่
 
firebase apphosting:secrets:set GEMINI_API_KEY- เมื่อระบบแจ้งให้ระบุค่าลับ ให้คัดลอกและวางคีย์ Gemini API จาก Google AI Studio
 - เมื่อระบบถามว่ารหัสลับใหม่นี้ใช้สำหรับการทดสอบในเวอร์ชันที่ใช้งานจริงหรือการทดสอบในเครื่อง ให้เลือก "เวอร์ชันที่ใช้งานจริง"
 - เมื่อระบบถามว่าต้องการให้สิทธิ์เข้าถึงเพื่อให้บัญชีบริการของแบ็กเอนด์เข้าถึงข้อมูลลับได้หรือไม่ ให้เลือก "ใช่"
 - เมื่อระบบถามว่าควรเพิ่มข้อมูลลับใหม่ลงใน 
apphosting.yamlไหม ให้ป้อนYเพื่อยอมรับ 
 
ตอนนี้ระบบได้จัดเก็บคีย์ Gemini API ของคุณไว้อย่างปลอดภัยใน Cloud Secret Manager และแบ็กเอนด์ App Hosting ของคุณสามารถเข้าถึงได้
ติดตั้งใช้งานคอมโพเนนต์สรุปรีวิว
- ใน 
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://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>; } } - สร้างการคอมมิตพร้อมข้อความคอมมิต "ใช้ AI เพื่อสรุปรีวิว" แล้วพุชไปยังที่เก็บ GitHub
 - เปิดหน้า App Hosting ในคอนโซล Firebase แล้วรอให้การเปิดตัวใหม่เสร็จสมบูรณ์
 - เปิดหน้าเว็บของร้านอาหาร ที่ด้านบน คุณจะเห็นสรุปรีวิวทั้งหมดในหน้าเป็นประโยคเดียว
 - เพิ่มรีวิวใหม่และรีเฟรชหน้าเว็บ คุณควรเห็นการเปลี่ยนแปลงสรุป
 
11. บทสรุป
ยินดีด้วย คุณได้เรียนรู้วิธีใช้ Firebase เพื่อเพิ่มฟีเจอร์และฟังก์ชันการทํางานลงในแอป Next.js โดยเฉพาะอย่างยิ่ง คุณได้ใช้สิ่งต่อไปนี้
- Firebase App Hosting เพื่อสร้างและติดตั้งใช้งานโค้ด Next.js โดยอัตโนมัติทุกครั้งที่คุณพุชไปยังกิ่งที่กำหนดค่าไว้
 - การตรวจสอบสิทธิ์ Firebase เพื่อเปิดใช้ฟังก์ชันการลงชื่อเข้าใช้และลงชื่อออก
 - Cloud Firestore สำหรับข้อมูลร้านอาหารและข้อมูลรีวิวร้านอาหาร
 - Cloud Storage for Firebase สำหรับรูปภาพร้านอาหาร