Firebase را با برنامه Next.js ادغام کنید

۱. قبل از شروع

در این آزمایشگاه کد، یاد خواهید گرفت که چگونه Firebase را با یک برنامه وب Next.js به نام Friendly Eats، که یک وب‌سایت برای بررسی رستوران‌ها است، ادغام کنید.

اپلیکیشن وب Friendly Eats

برنامه وب تکمیل‌شده ویژگی‌های مفیدی را ارائه می‌دهد که نشان می‌دهد چگونه Firebase می‌تواند به شما در ساخت برنامه‌های Next.js کمک کند. این ویژگی‌ها شامل موارد زیر است:

  • ساخت و استقرار خودکار: این codelab از Firebase App Hosting برای ساخت و استقرار خودکار کد Next.js شما هر بار که به یک شاخه پیکربندی شده ارسال می‌کنید، استفاده می‌کند.
  • ورود و خروج: برنامه وب تکمیل‌شده به شما امکان ورود و خروج با گوگل را می‌دهد. ورود و ماندگاری کاربر کاملاً از طریق احراز هویت Firebase مدیریت می‌شود.
  • تصاویر: برنامه وب تکمیل‌شده به کاربرانی که وارد سیستم شده‌اند اجازه می‌دهد تصاویر رستوران را آپلود کنند. تصاویر در فضای ذخیره‌سازی ابری برای Firebase ذخیره می‌شوند. کیت توسعه نرم‌افزاری جاوا اسکریپت Firebase یک URL عمومی برای تصاویر آپلود شده ارائه می‌دهد. این URL عمومی سپس در سند رستوران مربوطه در Cloud Firestore ذخیره می‌شود.
  • نظرات: برنامه وب تکمیل‌شده به کاربرانی که وارد سیستم شده‌اند اجازه می‌دهد نظرات خود را در مورد رستوران‌ها ارسال کنند که شامل امتیاز ستاره‌ای و پیام متنی است. اطلاعات نظرات در Cloud Firestore ذخیره می‌شود.
  • فیلترها: برنامه وب تکمیل‌شده به کاربرانی که وارد سیستم شده‌اند اجازه می‌دهد فهرست رستوران‌ها را بر اساس دسته‌بندی، موقعیت مکانی و قیمت فیلتر کنند. همچنین می‌توانید روش مرتب‌سازی مورد استفاده را سفارشی کنید. داده‌ها از Cloud Firestore قابل دسترسی هستند و جستجوهای Firestore بر اساس فیلترهای استفاده شده اعمال می‌شوند.

پیش‌نیازها

  • یک حساب کاربری گیت‌هاب
  • آشنایی با Next.js و جاوا اسکریپت

آنچه یاد خواهید گرفت

آنچه نیاز دارید

  • گیت
  • یک نسخه پایدار جدید از Node.js
  • یک مرورگر دلخواه مانند گوگل کروم
  • یک محیط توسعه با ویرایشگر کد و ترمینال
  • یک حساب گوگل برای ایجاد و مدیریت پروژه Firebase شما
  • امکان ارتقاء پروژه Firebase شما به طرح قیمت‌گذاری Blaze

۲. محیط توسعه و مخزن گیت‌هاب خود را تنظیم کنید

این codelab کدبیس اولیه برنامه را ارائه می‌دهد و به Firebase CLI متکی است.

ایجاد یک مخزن گیت‌هاب

منبع 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. از پکیج giget npm برای دریافت فقط پوشه 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. یک مخزن گیت‌هاب جدید به آدرس https://github.com/new ایجاد کنید. نام آن را هر چیزی که دوست دارید بگذارید.
  5. بسته به نحوه‌ی احراز هویت شما در گیت‌هاب (HTTPS یا SSH)، آدرس اینترنتی جدیدی که گیت‌هاب برای شما ایجاد می‌کند را کپی کنید:
    • https://github.com/<USER_NAME>/<REPOSITORY_NAME>.git یا
    • git@github.com:<USER_NAME>/<REPOSITORY_NAME>.git
  6. با اجرای دستور زیر، تغییرات محلی را به مخزن جدید GitHub خود اعمال کنید. آدرس واقعی مخزن خود را به جای <REPOSITORY_URL> قرار دهید.
    git remote add origin <REPOSITORY_URL>
    
    git push -u origin main
    
  7. اکنون باید کد آغازین را در مخزن گیت‌هاب خود مشاهده کنید.

نصب یا به‌روزرسانی رابط خط فرمان فایربیس

دستور زیر را اجرا کنید تا مطمئن شوید که Firebase CLI نصب شده است و نسخه آن ۱۴.۱.۰ یا بالاتر است:

firebase --version

اگر نسخه پایین‌تری را مشاهده می‌کنید یا Firebase CLI را نصب ندارید، دستور نصب را اجرا کنید:

npm install -g firebase-tools@latest

اگر به دلیل خطاهای مجوز نمی‌توانید Firebase CLI را نصب کنید، به مستندات npm مراجعه کنید یا از گزینه نصب دیگری استفاده کنید.

وارد فایربیس شوید

  1. برای ورود به Firebase CLI دستور زیر را اجرا کنید:
    firebase login
    
  2. بسته به اینکه می‌خواهید Firebase داده‌ها را جمع‌آوری کند یا خیر، Y یا N را وارد کنید.
  3. در مرورگر خود، حساب گوگل خود را انتخاب کنید و سپس روی «مجاز» کلیک کنید.

۳. پروژه فایربیس خود را راه‌اندازی کنید

در این بخش، یک پروژه Firebase راه‌اندازی کرده و یک برنامه وب Firebase را به آن مرتبط خواهید کرد. همچنین سرویس‌های Firebase مورد استفاده توسط برنامه وب نمونه را راه‌اندازی خواهید کرد.

ایجاد یک پروژه فایربیس

  1. با استفاده از همان حساب گوگلی که در مرحله قبل استفاده کردید، وارد کنسول Firebase شوید.
  2. برای ایجاد یک پروژه جدید، روی دکمه کلیک کنید و سپس نام پروژه را وارد کنید (برای مثال، FriendlyEats Codelab ).
  3. روی ادامه کلیک کنید.
  4. در صورت درخواست، شرایط Firebase را مرور و قبول کنید و سپس روی ادامه کلیک کنید.
  5. (اختیاری) دستیار هوش مصنوعی را در کنسول Firebase (با نام "Gemini در Firebase") فعال کنید.
  6. برای این codelab، به گوگل آنالیتیکس نیاز ندارید ، بنابراین گزینه گوگل آنالیتیکس را غیرفعال کنید .
  7. روی ایجاد پروژه کلیک کنید، منتظر بمانید تا پروژه شما آماده شود و سپس روی ادامه کلیک کنید.

طرح قیمت‌گذاری فایربیس خود را ارتقا دهید

برای استفاده از میزبانی برنامه Firebase و فضای ذخیره‌سازی ابری برای Firebase، پروژه Firebase شما باید در طرح قیمت‌گذاری pay-as-you-go (Blaze) باشد، به این معنی که به یک حساب Cloud Billing متصل باشد.

  • یک حساب Cloud Billing به یک روش پرداخت، مانند کارت اعتباری، نیاز دارد.
  • اگر در استفاده از فایربیس و گوگل کلود تازه‌کار هستید، بررسی کنید که آیا واجد شرایط دریافت اعتبار ۳۰۰ دلاری و یک حساب کاربری رایگان ابری هستید یا خیر.
  • اگر این codelab را به عنوان بخشی از یک رویداد انجام می‌دهید، از برگزارکننده خود بپرسید که آیا امکان استفاده از فضای ابری (Cloud credits) وجود دارد یا خیر.

برای ارتقاء پروژه خود به طرح Blaze، مراحل زیر را دنبال کنید:

  1. در کنسول Firebase، گزینه ارتقاء پلن خود را انتخاب کنید.
  2. طرح Blaze را انتخاب کنید. دستورالعمل‌های روی صفحه را دنبال کنید تا یک حساب Cloud Billing به پروژه شما متصل شود.
    اگر به عنوان بخشی از این ارتقا نیاز به ایجاد یک حساب Cloud Billing داشتید، ممکن است لازم باشد برای تکمیل ارتقا، به روند ارتقا در کنسول Firebase برگردید.

یک برنامه وب به پروژه Firebase خود اضافه کنید

  1. به نمای کلی پروژه خود در پروژه Firebase بروید، روی Add app و سپس روی Web کلیک کنید.
  2. در کادر متنی «نام مستعار برنامه» ، یک نام مستعار به یاد ماندنی برای برنامه، مانند My Next.js app وارد کنید.
  3. تیک گزینه‌ی «همچنین Firebase Hosting را برای این برنامه تنظیم کنید» را بردارید.
  4. روی ثبت برنامه > ادامه برای کنسول کلیک کنید.

سرویس‌های فایربیس را در کنسول فایربیس راه‌اندازی کنید

تنظیم احراز هویت

  1. در پنل سمت چپ کنسول Firebase، گزینه Build را باز کرده و سپس Authentication را انتخاب کنید.
  2. روی شروع به کار کلیک کنید.
  3. در ستون ارائه دهندگان ورود ، روی Google > Enable کلیک کنید.
  4. در کادر متن Public-facing name for project ، یک نام به یاد ماندنی مانند My Next.js app وارد کنید.
  5. از منوی کشویی ایمیل پشتیبانی برای پروژه ، آدرس ایمیل خود را انتخاب کنید.
  6. روی ذخیره کلیک کنید.

راه اندازی کلود فایر استور

  1. در پنل سمت چپ کنسول Firebase، گزینه Build را باز کرده و سپس Firestore Database را انتخاب کنید.
  2. روی ایجاد پایگاه داده کلیک کنید.
  3. نسخه استاندارد را انتخاب کنید و روی بعدی کلیک کنید.
  4. شناسه پایگاه داده را تغییر ندهید، آن را روی (default) بگذارید.
  5. مکانی را برای پایگاه داده خود انتخاب کنید، سپس روی Next کلیک کنید.
    برای یک اپلیکیشن واقعی، شما می‌خواهید مکانی را انتخاب کنید که به کاربرانتان نزدیک باشد.
  6. روی شروع در حالت آزمایشی کلیک کنید. سلب مسئولیت مربوط به قوانین امنیتی را مطالعه کنید.
    بعداً در این آزمایشگاه کد، قوانین امنیتی را برای ایمن‌سازی داده‌های خود اضافه خواهید کرد. بدون اضافه کردن قوانین امنیتی برای پایگاه داده خود ، برنامه را به صورت عمومی توزیع یا افشا نکنید .
  7. روی ایجاد کلیک کنید.

راه‌اندازی فضای ذخیره‌سازی ابری برای فایربیس

  1. در پنل سمت چپ کنسول Firebase، گزینه Build را باز کرده و سپس Storage را انتخاب کنید.
  2. روی شروع به کار کلیک کنید.
  3. مکانی را برای سطل ذخیره‌سازی پیش‌فرض خود انتخاب کنید.
    کاربران در US-WEST1 ، US-CENTRAL1 و US-EAST1 می‌توانند از ردیف «همیشه رایگان» برای Google Cloud Storage بهره‌مند شوند. کاربران در سایر مناطق، از قیمت‌ها و میزان استفاده از Google Cloud Storage پیروی می‌کنند.
  4. روی شروع در حالت آزمایشی کلیک کنید. سلب مسئولیت مربوط به قوانین امنیتی را مطالعه کنید.
    بعداً در این آزمایشگاه کد، قوانین امنیتی را برای ایمن‌سازی داده‌های خود اضافه خواهید کرد. بدون اضافه کردن قوانین امنیتی برای مخزن ذخیره‌سازی خود ، برنامه را به صورت عمومی توزیع یا در معرض نمایش قرار ندهید .
  5. روی ایجاد کلیک کنید.

استقرار قوانین امنیتی

این کد از قبل مجموعه‌ای از قوانین امنیتی برای Firestore و Cloud Storage برای 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 فشار دهید.

۴. کدبیس اولیه را بررسی کنید

در این بخش، چند بخش از کدبیس اولیه برنامه را که قرار است در این آزمایشگاه کد به آنها قابلیت اضافه کنید، مرور خواهید کرد.

ساختار پوشه و فایل

جدول زیر شامل نمای کلی از ساختار پوشه‌ها و فایل‌های برنامه است:

پوشه‌ها و فایل‌ها

توضیحات

src/components

کامپوننت‌های React برای فیلترها، هدرها، جزئیات رستوران‌ها و نقد و بررسی‌ها

src/lib

توابع کاربردی که لزوماً به React یا Next.js محدود نیستند

src/lib/firebase

کد مخصوص فایربیس و پیکربندی فایربیس

public

دارایی‌های ثابت در برنامه وب، مانند آیکون‌ها

src/app

مسیریابی با Next.js App Router

package.json و package-lock.json

وابستگی‌های پروژه با npm

next.config.js

پیکربندی مخصوص Next.js (اعمال سرور فعال هستند)

jsconfig.json

پیکربندی سرویس زبان جاوا اسکریپت

اجزای سرور و کلاینت

این برنامه یک برنامه وب Next.js است که از App Router استفاده می‌کند. رندرینگ سرور در سراسر برنامه استفاده می‌شود. برای مثال، فایل src/app/page.js یک کامپوننت سرور است که مسئول صفحه اصلی است. فایل src/components/RestaurantListings.jsx یک کامپوننت کلاینت است که با عبارت "use client" در ابتدای فایل مشخص شده است.

وارد کردن اظهارات

ممکن است متوجه عبارات import مانند موارد زیر شوید:

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

این برنامه از نماد @ برای جلوگیری از مسیرهای واردات نسبی دست و پا گیر استفاده می‌کند و این امر با نام‌های مستعار مسیر امکان‌پذیر است.

API های مخصوص فایربیس

تمام کدهای API فایربیس در دایرکتوری src/lib/firebase قرار دارند. سپس کامپوننت‌های React به صورت جداگانه توابع قرار داده شده در دایرکتوری src/lib/firebase را وارد می‌کنند، به جای اینکه مستقیماً توابع فایربیس را وارد کنند.

داده‌های ساختگی

داده‌های رستوران‌های آزمایشی و نظرات مشتریان در فایل src/lib/randomData.js قرار دارند. داده‌های این فایل در کد موجود در فایل src/lib/fakeRestaurants.js گردآوری شده‌اند.

۵. یک بک‌اند میزبانی اپلیکیشن ایجاد کنید

در این بخش، یک بک‌اند میزبانی برنامه (App Hosting backend) راه‌اندازی خواهید کرد تا بتوانید یک شاخه (branch) را در مخزن گیت خود زیر نظر داشته باشید.

در پایان این بخش، شما یک بک‌اند میزبانی برنامه (App Hosting backend) متصل به مخزن خود در گیت‌هاب خواهید داشت که هر زمان که یک کامیت جدید به شاخه main خود ارسال کنید، به‌طور خودکار نسخه جدیدی از برنامه شما را بازسازی و منتشر می‌کند.

ایجاد یک بک‌اند

  1. به صفحه App Hosting در کنسول Firebase بروید.
  2. برای شروع فرآیند ایجاد backend، روی Get started کلیک کنید.
  3. یک منطقه را انتخاب کنید. برای یک برنامه واقعی، منطقه‌ای را انتخاب می‌کنید که به کاربرانتان نزدیک‌تر باشد.
  4. برای تنظیم احراز هویت گیت‌هاب، دستورالعمل‌های موجود در مرحله‌ی «وارد کردن مخزن گیت‌هاب» را دنبال کنید.
  5. از مخزن (Repository) ، گزینه اعطای دسترسی به یک مخزن جدید در گیت‌هاب (GitHub) را انتخاب کنید و دستورالعمل‌ها را دنبال کنید تا دسترسی به مخزن گیت‌هاب که قبلاً ایجاد کرده‌اید، فعال شود.
  6. برای به‌روزرسانی لیست، روی «به‌روزرسانی لیست» کلیک کنید، سپس مخزن خود را انتخاب کرده و روی «بعدی» کلیک کنید.
  7. تنظیمات استقرار را تنظیم کنید:
    1. شاخه زنده را روی main تنظیم کنید.
    2. دایرکتوری ریشه را به صورت / نگه دارید.
    3. فعال کردن انتشار خودکار
  8. نام backend خود را friendlyeats-codelab قرار دهید و روی Next کلیک کنید.
  9. از بخش Associate a Firebase web app ، گزینه Select an existing Firebase web app را انتخاب کنید و برنامه‌ای که اضافه کرده‌اید را از لیست انتخاب کنید.
  10. روی «پایان و استقرار» کلیک کنید. شما به صفحه جدیدی هدایت می‌شوید که در آن می‌توانید وضعیت بک‌اند جدید App Hosting خود را مشاهده کنید!
  11. برای مشاهده اطلاعات بیشتر در مورد استقرار App Hosting خود، از جمله وضعیت راه‌اندازی، گزارش‌ها و جزئیات استفاده، روی «مشاهده» کلیک کنید.
  12. پس از اتمام مراحل نصب، روی باز کردن آدرس اینترنتی سایت خود در زیر دامنه‌ها کلیک کنید. به دلیل انتشار DNS، ممکن است شروع به کار این بخش چند دقیقه طول بکشد.
  13. اوه اوه! وقتی صفحه را بارگذاری می‌کنید، یک پیام خطا با این مضمون خواهید دید: «خطای برنامه: یک استثنای سمت سرور رخ داده است (برای اطلاعات بیشتر به گزارش‌های سرور مراجعه کنید)».
  14. در کنسول فایربیس، تب لاگ‌های (Logs) بک‌اند اپ هاستینگ (App Hosting) خود را بررسی کنید. لاگی با عنوان "خطا: پیاده‌سازی نشده" (Error: not implement) خواهید دید. این مشکل را در مرحله بعدی، هنگام اضافه کردن احراز هویت، برطرف خواهیم کرد.

شما برنامه وب اولیه را مستقر کرده‌اید! هر بار که یک commit جدید را به شاخه main مخزن GitHub خود ارسال می‌کنید، خواهید دید که یک build و rollout جدید در کنسول Firebase آغاز می‌شود و سایت شما پس از اتمام rollout به طور خودکار به‌روزرسانی می‌شود.

۶. احراز هویت را به برنامه وب اضافه کنید

در این بخش، احراز هویت را به برنامه وب اضافه می‌کنید تا بتوانید به آن وارد شوید.

افزودن دامنه مجاز

احراز هویت فایربیس فقط درخواست‌های ورود به سیستم را از دامنه‌هایی که شما اجازه می‌دهید می‌پذیرد. در اینجا، دامنه‌ی بک‌اند میزبانی برنامه‌ی شما را به لیست دامنه‌های تأیید شده در پروژه‌تان اضافه خواهیم کرد.

  1. صفحه App Hosting را باز کنید و برای دسترسی به صفحه Overview ، روی View در زیر سایت پیاده‌سازی شده خود کلیک کنید. نام دامنه مربوط به App Hosting backend خود را کپی کنید.
  2. به برگه تنظیمات احراز هویت (Auth Settings) بروید و پروژه‌ای را که می‌خواهید دامنه مجاز به آن اضافه کنید، انتخاب کنید. سپس، بخش دامنه‌های مجاز (Authorized Domains) را پیدا کرده و روی آن کلیک کنید.
  3. روی دکمه افزودن دامنه کلیک کنید.
  4. دامنه‌ی بک‌اند میزبانی برنامه‌ی خود را وارد کنید.
  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);
  }
}

این کد از API های Firebase زیر استفاده می‌کند:

رابط برنامه‌نویسی کاربردی فایربیس

توضیحات

auth.onAuthStateChanged

یک ناظر برای تغییرات در وضعیت ورود کاربر اضافه می‌کند.

auth.onIdTokenChanged

یک ناظر برای تغییرات در توکن شناسه کاربر اضافه می‌کند.

GoogleAuthProvider

یک نمونه از ارائه‌دهنده احراز هویت گوگل ایجاد می‌کند.

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 ، هدر را رندر می‌کند و در صورت وجود، کاربر را به عنوان یک prop به آن ارسال می‌کند.

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

این بدان معناست که کامپوننت <Header> در صورت وجود، داده‌های کاربر را در زمان اجرای سرور رندر می‌کند. اگر در طول چرخه حیات صفحه پس از بارگذاری اولیه صفحه، به‌روزرسانی‌های احراز هویت وجود داشته باشد، هندلر onAuthStateChanged آنها را مدیریت می‌کند.

اکنون زمان آن رسیده است که یک نسخه جدید را منتشر کنید و آنچه را که ساخته‌اید، تأیید کنید.

  1. یک کامیت با پیام «افزودن احراز هویت» ایجاد کنید و آن را به مخزن گیت‌هاب خود ارسال کنید.
    git add .
    
    git commit -m "Add authentication"
    
    git push
    
  2. صفحه میزبانی برنامه را باز کنید و وقتی راه‌اندازی جدید شما کامل شد، روی URL سایت کلیک کنید تا باز شود.
  3. تست احراز هویت:
    1. با حساب گوگل خود وارد شوید و تأیید کنید که نام نمایشی شما پس از ورود در سربرگ نمایش داده می‌شود.
    2. از سیستم خارج شوید و دوباره وارد شوید. می‌توانید این مرحله را با کاربران مختلف تکرار کنید.
    3. اختیاری: روی برنامه وب کلیک راست کنید، گزینه View page source را انتخاب کنید و نام نمایشی را جستجو کنید. این نام در منبع HTML خام برگردانده شده از سرور نمایش داده می‌شود.

۷. مشاهده اطلاعات رستوران

این برنامه وب شامل داده‌های آزمایشی برای رستوران‌ها و نظرات کاربران است.

اضافه کردن یک یا چند رستوران

برای وارد کردن داده‌های رستوران‌های ساختگی در پایگاه داده محلی Cloud Firestore خود، این مراحل را دنبال کنید:

  1. اگر قبلاً وارد برنامه وب نشده‌اید، وارد آن شوید. سپس، را انتخاب کنید 2cf67d488d8e6332.png > رستوران‌های نمونه را اضافه کنید . توجه داشته باشید که هیچ رستورانی در برنامه وب Friendly Eats نمایش داده نمی‌شود زیرا هنوز کد واکشی داده‌ها را تنظیم نکرده‌ایم. این مشکل را در مرحله بعدی برطرف خواهیم کرد.
  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. یک کامیت با پیام «لیست رستوران‌ها را از Firestore بخوانید» ایجاد کنید و آن را به مخزن گیت‌هاب خود ارسال کنید.
    git add .
    
    git commit -m "Read the list of restaurants from Firestore"
    
    git push
    
  2. صفحه App Hosting را در کنسول Firebase باز کنید و منتظر بمانید تا نصب جدید شما تکمیل شود.
  3. در برنامه وب، صفحه را رفرش کنید. تصاویر رستوران به صورت کاشی در صفحه ظاهر می‌شوند.

تأیید کنید که لیست رستوران‌ها در زمان اجرای سرور بارگذاری می‌شود

با استفاده از فریم‌ورک Next.js، ممکن است مشخص نباشد که داده‌ها چه زمانی در زمان اجرای سرور یا زمان اجرای سمت کلاینت بارگذاری می‌شوند.

برای تأیید اینکه لیست رستوران‌ها در زمان اجرای سرور بارگذاری می‌شود، این مراحل را دنبال کنید:

  1. در برنامه وب، DevTools را باز کنید و جاوا اسکریپت را غیرفعال کنید .

غیرفعال کردن جاوا اسکریپت در DevTools

  1. برنامه وب را رفرش کنید. فهرست رستوران‌ها هنوز بارگذاری می‌شود. اطلاعات رستوران در پاسخ سرور بازگردانده می‌شود. وقتی جاوا اسکریپت فعال باشد، اطلاعات رستوران از طریق کد جاوا اسکریپت سمت کلاینت نمایش داده می‌شود.
  2. در DevTools، جاوا اسکریپت را دوباره فعال کنید .

با استفاده از شنودگرهای اسنپ‌شات Cloud Firestore، به به‌روزرسانی‌های رستوران‌ها گوش دهید

در بخش قبلی، دیدید که چگونه مجموعه اولیه رستوران‌ها از فایل src/app/page.js بارگذاری شد. فایل src/app/page.js یک کامپوننت سرور است و روی سرور رندر می‌شود، از جمله کد واکشی داده‌های Firebase.

فایل src/components/RestaurantListings.jsx یک کامپوننت کلاینت است و می‌تواند طوری پیکربندی شود که markup رندر شده توسط سرور را هیدراته کند.

برای پیکربندی فایل src/components/RestaurantListings.jsx برای هیدراته کردن نشانه‌گذاری رندر شده توسط سرور، این مراحل را دنبال کنید:

  1. در فایل src/components/RestaurantListings.jsx ، کد زیر را که از قبل برای شما نوشته شده است، مشاهده کنید:
useEffect(() => {
    return getRestaurantsSnapshot((data) => {
      setRestaurants(data);
    }, filters);
  }, [filters]);

این کد تابع getRestaurantsSnapshot() را فراخوانی می‌کند، که مشابه تابع getRestaurants() است که در مرحله قبل پیاده‌سازی کردید. با این حال، این تابع snapshot یک مکانیزم فراخوانی مجدد (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. یک کامیت با پیام کامیت «به‌روزرسانی‌های رستوران در لحظه گوش دهید» ایجاد کنید و آن را به مخزن گیت‌هاب خود ارسال کنید.
    git add .
    
    git commit -m "Listen for realtime restaurant updates"
    
    git push
    
  2. صفحه App Hosting را در کنسول Firebase باز کنید و منتظر بمانید تا نصب جدید شما تکمیل شود.
  3. در برنامه وب، انتخاب کنید 27ca5d1e8ed8adfe.png > رستوران‌های نمونه را اضافه کنید . اگر تابع snapshot شما به درستی پیاده‌سازی شده باشد، رستوران‌ها بدون نیاز به رفرش صفحه و به صورت بلادرنگ نمایش داده می‌شوند.

۸. نظرات ارسالی کاربران را از برنامه وب ذخیره کنید

  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 یک API مناسب برای دسترسی به داده‌های فرم، مانند data.get("text") برای دریافت مقدار متن از payload ارسال فرم، ارائه می‌دهد.

برای استفاده از 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. یک کامیت با پیام «به کاربران اجازه دهید نظرات رستوران‌ها را ارسال کنند» ایجاد کنید و آن را به مخزن گیت‌هاب خود ارسال کنید.
    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. در پنل افزودن سند ، سند مورد نظر را برای بررسی پیدا کنید تا تأیید کنید که مطابق انتظار درج شده است.

۹. فایل‌های آپلود شده توسط کاربر را از برنامه وب ذخیره کنید

در این بخش، قابلیتی را اضافه می‌کنید که بتوانید هنگام ورود به سیستم، تصویر مرتبط با یک رستوران را جایگزین کنید. تصویر را در Firebase Storage آپلود می‌کنید و 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. یک کامیت با پیام «به کاربران اجازه دهید عکس هر رستوران را تغییر دهند» ایجاد کنید و آن را به مخزن گیت‌هاب خود اضافه کنید.
    git add .
    
    git commit -m "Allow users to change each restaurants' photo"
    
    git push
    
  2. صفحه App Hosting را در کنسول Firebase باز کنید و منتظر بمانید تا نصب جدید شما تکمیل شود.
  3. در برنامه وب، تأیید کنید که وارد سیستم شده‌اید و یک رستوران را انتخاب کنید.
  4. کلیک 7067eb41fea41ff0.png و یک تصویر را از سیستم فایل خود آپلود کنید. تصویر شما از محیط محلی شما خارج شده و در فضای ابری آپلود می‌شود. تصویر بلافاصله پس از آپلود شما ظاهر می‌شود.
  5. به فضای ذخیره‌سازی ابری برای فایربیس بروید.
  6. به پوشه‌ای که رستوران را نشان می‌دهد بروید. تصویری که آپلود کرده‌اید در این پوشه وجود دارد.

6cf3f9e2303c931c.png

۱۰. خلاصه نظرات رستوران‌ها را با هوش مصنوعی مولد بنویسید

در این بخش، شما یک ویژگی خلاصه نظرات اضافه خواهید کرد تا کاربر بتواند بدون نیاز به خواندن تک تک نظرات، به سرعت متوجه شود که همه در مورد یک رستوران چه فکری می‌کنند.

یک کلید API Gemini را در Cloud Secret Manager ذخیره کنید

  1. برای استفاده از API جمینی، به یک کلید API نیاز دارید. به Google AI Studio مراجعه کنید و روی Create API Key کلیک کنید.
  2. نام کلید را هر چه دوست دارید بگذارید. اگر پروژه شما در زیر «انتخاب یک پروژه وارد شده» فهرست نشده است، روی «وارد کردن پروژه» کلیک کنید، پروژه خود را در لیست بررسی کنید و سپس روی «وارد کردن» کلیک کنید. در نهایت، آن را در زیر «انتخاب یک پروژه وارد شده» انتخاب کنید و روی «ایجاد یک کلید» کلیک کنید.
  3. میزبانی برنامه با Cloud Secret Manager ادغام می‌شود تا به شما امکان دهد مقادیر حساس مانند کلیدهای API را به صورت ایمن ذخیره کنید:
    1. در ترمینال، دستور زیر را برای ایجاد یک رمز جدید اجرا کنید:
    firebase apphosting:secrets:set GEMINI_API_KEY
    
    1. وقتی از شما مقدار مخفی خواسته شد، کلید API Gemini خود را از Google AI Studio کپی و جایگذاری کنید.
    2. وقتی از شما پرسیده شد که آیا راز جدید برای تولید است یا آزمایش محلی، «تولید» را انتخاب کنید.
    3. وقتی از شما پرسیده شد که آیا می‌خواهید دسترسی بدهید تا حساب سرویس backend شما بتواند به رمز دسترسی داشته باشد، «بله» را انتخاب کنید.
    4. وقتی از شما پرسیده شد که آیا رمز جدید باید به apphosting.yaml اضافه شود، برای پذیرش، Y وارد کنید.

کلید API Gemini شما اکنون به طور ایمن در Cloud Secret manager ذخیره شده است و از طریق App Hosting backend شما قابل دسترسی است.

پیاده‌سازی مؤلفه خلاصه بررسی

  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://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. یک کامیت با پیام «استفاده از هوش مصنوعی برای خلاصه کردن نظرات» ایجاد کنید و آن را به مخزن گیت‌هاب خود ارسال کنید.
    git add .
    
    git commit -m "Use AI to summarize reviews"
    
    git push
    
  3. صفحه App Hosting را در کنسول Firebase باز کنید و منتظر بمانید تا نصب جدید شما تکمیل شود.
  4. صفحه‌ای برای یک رستوران باز کنید. در بالای صفحه، باید خلاصه‌ای یک جمله‌ای از تمام نظرات موجود در صفحه را ببینید.
  5. یک نقد جدید اضافه کنید و صفحه را رفرش کنید. باید تغییر خلاصه را ببینید.

۱۱. سایت میزبانی برنامه خود را از حالت انتشار خارج کنید

پس از تکمیل این کدلاگ، اگر قصد ادامه استفاده از برنامه را ندارید، می‌توانید آن را از حالت انتشار خارج کنید تا مطمئن شوید که هیچ‌کس به منابع Firestore، Storage و Gemini شما دسترسی ندارد. می‌توانید در هر زمانی دوباره آن را منتشر کنید.

برای لغو انتشار یک سایت میزبانی برنامه:

  1. App Hosting را در کنسول Firebase باز کنید.
  2. بخش مدیریت برنامه خود را پیدا کنید و روی «مشاهده» کلیک کنید.
  3. در بخش اطلاعات Backend ، کنار Domains ، روی Manage کلیک کنید. با این کار صفحه Domains بارگذاری می‌شود.
  4. در کنار دامنه خود، روی نماد «بیشتر » (سه نقطه عمودی) کلیک کنید، غیرفعال کردن دامنه را انتخاب کنید، سپس برای تأیید، روی غیرفعال کردن کلیک کنید.

۱۲. نتیجه‌گیری

تبریک! شما یاد گرفتید که چگونه از Firebase برای افزودن ویژگی‌ها و قابلیت‌ها به یک برنامه Next.js استفاده کنید. به طور خاص، از موارد زیر استفاده کردید:

بیشتر بدانید