دمج Firebase مع تطبيق Next.js

1- قبل البدء

في هذا الدرس التطبيقي حول الترميز، ستتعرّف على كيفية دمج Firebase مع تطبيق ويب Next.js المسمى Friendly Eats، وهو موقع إلكتروني لمراجعات المطاعم.

تطبيق الويب Friendly Eats

يقدِّم تطبيق الويب المكتمل ميزات مفيدة توضّح كيف يمكن لمنصة Firebase مساعدتك في إنشاء تطبيقات Next.js. وتشمل هذه الميزات ما يلي:

  • الإنشاء والنشر تلقائيًا: يستخدم هذا الدرس التطبيقي حول الترميز استضافة تطبيقات Firebase لإنشاء رمز Next.js ونشره تلقائيًا في كل مرة ترسل فيها إلى فرع تم إعداده.
  • تسجيل الدخول وتسجيل الخروج:يتيح لك تطبيق الويب المكتمل تسجيل الدخول باستخدام حساب Google وتسجيل الخروج. تتم إدارة تسجيل دخول المستخدم واستمرارية تثبيت التطبيق بالكامل من خلال مصادقة Firebase.
  • الصور: يسمح تطبيق الويب المكتمل للمستخدمين الذين سجّلوا الدخول بتحميل صور المطاعم. يتم تخزين مواد عرض الصور في Cloud Storage for Firebase. توفِّر حزمة تطوير البرامج (SDK) لـ Firebase JavaScript عنوان URL علنيًا للصور التي يتم تحميلها. يتم بعد ذلك تخزين عنوان URL العلني هذا في مستند المطعم ذي الصلة في Cloud Firestore.
  • المراجعات: يتيح تطبيق الويب المكتمل للمستخدمين الذين سجّلوا الدخول نشر مراجعات للمطاعم التي تتألف من تقييم بالنجوم ورسالة نصية. يتم تخزين معلومات المراجعة في Cloud Firestore.
  • الفلاتر: يسمح تطبيق الويب المكتمل للمستخدمين الذين سجّلوا الدخول بفلترة قائمة المطاعم استنادًا إلى الفئة والموقع الجغرافي والسعر. يمكنك أيضًا تخصيص طريقة الترتيب المستخدَمة. يتم الوصول إلى البيانات من Cloud Firestore، ويتم تطبيق طلبات بحث Firestore بناءً على الفلاتر المستخدمة.

المتطلبات الأساسية

  • حساب GitHub
  • معرفة Next.js وJavaScript

المعلومات التي ستطّلع عليها

  • كيفية استخدام Firebase مع "جهاز توجيه التطبيقات" في Next.js والعرض من جهة الخادم
  • كيفية الاحتفاظ بالصور في Cloud Storage لبرنامج Firebase.
  • كيفية قراءة البيانات وكتابتها في قاعدة بيانات Cloud Firestore.
  • كيفية استخدام ميزة "تسجيل الدخول باستخدام حساب Google" باستخدام حزمة تطوير البرامج (SDK) لJavaScript لمنصة Firebase

المتطلبات

  • جيت
  • إصدار ثابت حديث من Node.js
  • متصفح من اختيارك، مثل Google Chrome
  • بيئة تطوير تتضمن أداة لتعديل الرموز والطرف الطرفي
  • حساب على Google لإنشاء مشروعك على Firebase وإدارته
  • إمكانية ترقية مشروع Firebase إلى خطة أسعار Blaze

2- إعداد بيئة التطوير ومستودع GitHub

يوفّر هذا الدرس التطبيقي حول الترميز قاعدة رموز لإجراءات التفعيل الخاصة بالتطبيق ويعتمد على واجهة سطر الأوامر في Firebase.

إنشاء مستودع GitHub

يمكن العثور على مصدر الدرس التطبيقي حول الترميز على الرابط https://github.com/firebase/friendeats-web. يحتوي المستودع على نماذج مشروعات لأنظمة أساسية متعددة. مع ذلك، يستخدم هذا الدرس التطبيقي دليل 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 commit -a -m "codelab starting point"
    
    git branch -M main
    
  4. أنشئ مستودع GitHub جديد: https://github.com/new. يمكنك تسميته أي شيء تريده.
    1. سيمنحك GitHub عنوان URL جديد للمستودع بالتنسيق https://github.com//.git أو git@github.com:/.git. انسخ عنوان URL هذا.
  5. يمكنك إرسال التغييرات المحلية إلى مستودع GitHub الجديد. شغِّل الأمر التالي، واستبدل عنوان URL للمستودع بالعنصر النائب .
    git remote add origin <your-repository-url>
    
    git push -u origin main
    
  6. من المفترض أن يظهر لك الآن رمز إجراء التفعيل في مستودع جيت هب.

تثبيت واجهة سطر الأوامر في Firebase أو تحديثه

شغِّل الأمر التالي للتحقّق من تثبيت واجهة سطر الأوامر في Firebase ومن أنّه الإصدار 13.9.0 أو إصدار أحدث:

firebase --version

في حال ظهور إصدار أقدم أو عدم تثبيت واجهة سطر الأوامر في Firebase، شغِّل أمر التثبيت:

npm install -g firebase-tools@latest

إذا لم تتمكن من تثبيت واجهة سطر الأوامر في Firebase بسبب أخطاء في الأذونات، راجِع مستندات npm أو استخدِم خيار تثبيت آخر.

تسجيل الدخول إلى Firebase

  1. شغِّل الأمر التالي لتسجيل الدخول إلى واجهة سطر الأوامر في Firebase:
    firebase login
    
  2. بناءً على ما إذا كنت تريد من Firebase جمع البيانات، أدخِل Y أو N.
  3. في المتصفّح، اختَر حسابك على Google، ثم انقر على السماح.

3- إعداد مشروع Firebase

في هذا القسم، يمكنك إعداد مشروع Firebase وربط تطبيق ويب Firebase به. سيتم أيضًا إعداد خدمات Firebase التي يستخدمها نموذج تطبيق الويب.

إنشاء مشروع على Firebase

  1. في وحدة تحكُّم Firebase، انقر على إضافة مشروع.
  2. في مربّع النص إدخال اسم مشروعك، أدخِل FriendlyEats Codelab (أو اسم مشروع من اختيارك)، ثم انقر على متابعة.
  3. في النافذة المشروطة تأكيد خطة فوترة Firebase، تأكَّد من أنّ الخطة مفعّلة، ثم انقر على تأكيد الخطة.
  4. لا تحتاج إلى "إحصاءات Google" في هذا الدرس التطبيقي حول الترميز، لذا أوقِف خيار تفعيل "إحصاءات Google" لهذا المشروع.
  5. انقر على إنشاء مشروع.
  6. انتظر حتى يتم توفير المشروع، ثم انقر على متابعة.
  7. في مشروع Firebase، انتقِل إلى إعدادات المشروع. دوِّن رقم تعريف مشروعك لأنك ستحتاج إليه لاحقًا. يمثّل هذا المعرّف الفريد طريقة تحديد مشروعك (على سبيل المثال، في واجهة سطر الأوامر في Firebase).

ترقية خطة أسعار Firebase

لاستخدام ميزة "استضافة التطبيقات"، يجب أن يكون مشروعك في Firebase ضمن خطة أسعار Blaze، ما يعني أنّه مرتبط بحساب فوترة على Cloud.

  • يتطلب حساب الفوترة في Cloud طريقة دفع، مثل بطاقة الائتمان.
  • إذا كنت مستخدمًا جديدًا لمنصة Firebase وGoogle Cloud، تحقَّق من أهليتك للحصول على رصيد بقيمة 300 دولار أمريكي (أو ما يعادله بالعملة المحلية) وحساب فوترة مجاني على Cloud.

لترقية مشروعك إلى خطة Blaze، اتّبِع الخطوات التالية:

  1. في "وحدة تحكُّم Firebase"، اختَر ترقية خطتك.
  2. في مربّع الحوار، اختَر خطة Blaze، ثم اتّبِع التعليمات الظاهرة على الشاشة لربط مشروعك بحساب فوترة Cloud.
    إذا احتجت إلى إنشاء حساب فوترة على Cloud، قد تحتاج إلى الرجوع إلى مسار الترقية في وحدة تحكُّم Firebase لإكمال عملية الترقية.

إضافة تطبيق ويب إلى مشروعك على Firebase

  1. انتقِل إلى نظرة عامة على المشروع في مشروعك على Firebase، ثم انقر على e41f2efdd9539c31.png الويب.

    إذا سبق لك تسجيل تطبيقات في مشروعك، انقر على إضافة تطبيق لعرض رمز الويب.
  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. يمكنك استخدام الموقع الجغرافي التلقائي أو اختيار موقع جغرافي من اختيارك.
    إذا كان لديك تطبيق حقيقي، عليك اختيار موقع قريب من المستخدمين. يُرجى العِلم أنّه لا يمكن تغيير هذا الموقع الجغرافي لاحقًا، وسيصبح أيضًا تلقائيًا موقع حزمتك التلقائية على Cloud Storage (الخطوة التالية).
  4. انقر على تم.

إعداد Cloud Storage لمنصّة Firebase

  1. في "وحدة تحكُّم Firebase"، انتقِل إلى مساحة التخزين.
  2. انقر على البدء > البدء في وضع الاختبار > التالي.
    في وقت لاحق من هذا الدرس التطبيقي حول الترميز، عليك إضافة "قواعد الأمان" لتأمين بياناتك. يجب عدم توزيع تطبيق أو عرضه بشكل علني بدون إضافة قواعد أمان إلى حزمة مساحة التخزين.
  3. يجب أن يكون قد تم اختيار موقع الحزمة مسبقًا (بسبب إعداد Firestore في الخطوة السابقة).
  4. انقر على تم.

4. مراجعة قاعدة الرموز الخاصة بإجراءات التفعيل

في هذا القسم، ستراجع بعض أجزاء قاعدة الرموز الخاصة بمبتدئ التطبيق والتي ستضيف إليها وظائف في هذا الدرس التطبيقي حول الترميز.

بنية المجلدات والملفات

يحتوي الجدول التالي على نظرة عامة على بنية المجلدات والملفات الخاصة بالتطبيق:

المجلدات والملفات

الوصف

src/components

تفاعل مكونات الفلاتر والعناوين وتفاصيل المطعم والمراجعات

src/lib

دوال الأداة التي لا ترتبط بالضرورة بحزمة React أو Next.js

src/lib/firebase

الرمز البرمجي الخاص بمنصة Firebase وإعدادات Firebase

public

مواد العرض الثابتة في تطبيق الويب، مثل الرموز

src/app

التوجيه باستخدام جهاز توجيه التطبيقات Next.js

src/app/restaurant

معالِج مسار واجهة برمجة التطبيقات

package.json وpackage-lock.json

تبعيات المشروع مع npm

next.config.js

ضبط خاص بـ Next.js (تم تفعيل إجراءات الخادم)

jsconfig.json

ضبط خدمة لغة JavaScript

مكونات الخادم والعميل

التطبيق هو تطبيق ويب Next.js يستخدم جهاز توجيه التطبيقات. يُستخدَم عرض الخادم في جميع أنحاء التطبيق. على سبيل المثال، الملف src/app/page.js هو عنصر في الخادم مسؤول عن الصفحة الرئيسية. الملف src/components/RestaurantListings.jsx هو مكوّن برنامج يتم الإشارة إليه من خلال التوجيه "use client" في بداية الملف.

عبارات الاستيراد

قد تلاحظ عبارات استيراد مثل ما يلي:

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

يستخدم التطبيق الرمز @ لتجنُّب مسارات الاستيراد النسبية القديمة وأصبح ممكنًا من خلال الأسماء المستعارة للمسارات.

واجهات برمجة التطبيقات المتعلّقة بمنصّة Firebase

يكون كل رموز واجهة برمجة التطبيقات Firebase مرفقة في دليل src/lib/firebase. بعد ذلك، تستورد مكوّنات React الفردية الدوال التي تم تضمينها من دليل src/lib/firebase، بدلاً من استيراد وظائف Firebase مباشرةً.

البيانات الزائفة

تم تضمين بيانات المراجعات والمطاعم الوهمية في ملف src/lib/randomData.js. ويتم تجميع البيانات من هذا الملف ضمن الرمز البرمجي في ملف src/lib/fakeRestaurants.js.

5- إنشاء واجهة خلفية لاستضافة التطبيقات

في هذا القسم، ستقوم بإعداد واجهة خلفية لاستضافة التطبيقات لمشاهدة فرع على مستودع git.

في نهاية هذا القسم، ستكون لديك خلفية "استضافة التطبيقات" مرتبطة بمستودعك في GitHub والتي ستعمل تلقائيًا على إعادة إنشاء إصدار جديد من تطبيقك وطرحه عند إرسال التزام جديد إلى فرع main التابع لك.

نشر قواعد الأمان

يتضمن الرمز مجموعات من قواعد الأمان من أجل Firestore وCloud Storage for Firebase. بعد نشر "قواعد الأمان"، تتم حماية البيانات في قاعدة البيانات وحزمتك بشكل أفضل من إساءة الاستخدام.

  1. في الوحدة الطرفية، اضبط واجهة سطر الأوامر لاستخدام مشروع Firebase الذي أنشأته سابقًا:
    firebase use --add
    
    عندما يُطلب منك إدخال اسم مستعار، أدخِل friendlyeats-codelab.
  2. لنشر قواعد الأمان هذه، شغِّل الأمر التالي في الوحدة الطرفية:
    firebase deploy --only firestore:rules,storage
    
  3. إذا تم سؤالك: "Cloud Storage for Firebase needs an IAM Role to use cross-service rules. Grant the new role?"، اضغط على Enter لاختيار نعم.

إضافة إعدادات Firebase إلى رمز تطبيق الويب

  1. في "وحدة تحكُّم Firebase"، انتقِل إلى إعدادات المشروع.
  2. في لوحة إعداد حزمة تطوير البرامج (SDK) وضبطها، انقر على "إضافة تطبيق". وانقر على رمز الأقواس لتسجيل تطبيق ويب جديد.
  3. في نهاية عملية إنشاء تطبيق الويب، انسخ المتغيّر firebaseConfig وانسخ خصائصه وقيمه.
  4. افتح ملف apphosting.yaml في أداة تعديل الرموز واملأ قيم متغيّرات البيئة بقيم الإعدادات من وحدة تحكُّم Firebase.
  5. في الملف، استبدِل المواقع الإلكترونية الحالية بتلك التي نسختها.
  6. احفظ الملف.

إنشاء واجهة خلفية

  1. انتقِل إلى صفحة استضافة التطبيق في وحدة تحكُّم Firebase:

الحالة الصفرية لوحدة تحكُّم استضافة التطبيقات، مع وجود زر &quot;البدء&quot; زر

  1. انقر على "البدء" لبدء تدفق الإنشاء في الخلفية. اضبط الخلفية كما يلي:
  2. اتبع المطالبات الواردة في الخطوة الأولى لربط مستودع GitHub الذي أنشأته سابقًا.
  3. ضبط إعدادات النشر:
    1. الاحتفاظ بالدليل الجذر باسم /
    2. ضبط الفرع المباشر على main
    3. تفعيل عمليات الطرح التلقائية
  4. أدخِل اسمًا للخلفية friendlyeats-codelab.
  5. في قسم "إنشاء تطبيق ويب على Firebase أو ربطه"، اختر تطبيق الويب الذي ضبطته سابقًا من الخيار "اختيار تطبيق ويب حالي على Firebase". المنسدلة.
  6. انقر على "إنهاء ونشر". بعد لحظات، سيتم نقلك إلى صفحة جديدة يمكنك من خلالها الاطلاع على حالة الواجهة الخلفية الجديدة لاستضافة التطبيق.
  7. بعد اكتمال عملية الطرح، انقر على النطاق المجاني ضمن "النطاقات". قد يستغرق ذلك بضع دقائق لبدء العمل بسبب نشر نظام أسماء النطاقات.

لقد نشرت تطبيق الويب الأولي! في كل مرة ترسل فيها التزامًا جديدًا إلى فرع main من مستودع GitHub، ستظهر لك نسخة جديدة وطرحها في وحدة تحكُّم Firebase، وسيتم تحديث موقعك الإلكتروني تلقائيًا فور اكتمال عملية الطرح.

6- إضافة طريقة مصادقة إلى تطبيق الويب

يمكنك في هذا القسم إضافة مصادقة إلى تطبيق الويب لتتمكن من تسجيل الدخول إليه.

تنفيذ وظيفتَي تسجيل الدخول وتسجيل الخروج

  1. في الملف src/lib/firebase/auth.js، استبدِل الدوال onAuthStateChanged وsignInWithGoogle وsignOut بالرمز التالي:
export function onAuthStateChanged(cb) {
	return _onAuthStateChanged(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 التالية:

واجهة برمجة تطبيقات Firebase

الوصف

GoogleAuthProvider

تنشئ مثيلاً لموفّر مصادقة Google.

signInWithPopup

لبدء عملية مصادقة مستندة إلى مربّع الحوار

auth.signOut

خروج المستخدم

في الملف src/components/Header.jsx، يستدعي الرمز الدالتين signInWithGoogle وsignOut من قبل.

  1. إنشاء التزام مع رسالة الإتمام "إضافة مصادقة Google" وأرسله إلى مستودع جيت هب. 1- افتح صفحة استضافة التطبيق في وحدة تحكُّم Firebase وانتظِر إلى أن تكتمل عملية الطرح الجديدة.
  2. في تطبيق الويب، أعِد تحميل الصفحة وانقر على تسجيل الدخول باستخدام حساب Google. لا يتم تحديث تطبيق الويب، لذا ليس من الواضح ما إذا تم تسجيل الدخول بنجاح أم لا.

إرسال حالة المصادقة إلى الخادم

لتمرير حالة المصادقة إلى الخادم، سنستخدم عامل خدمات. استبدل الدالتين fetchWithFirebaseHeaders وgetAuthIdToken بالرمز التالي:

async function fetchWithFirebaseHeaders(request) {
  const app = initializeApp(firebaseConfig);
  const auth = getAuth(app);
  const installations = getInstallations(app);
  const headers = new Headers(request.headers);
  const [authIdToken, installationToken] = await Promise.all([
    getAuthIdToken(auth),
    getToken(installations),
  ]);
  headers.append("Firebase-Instance-ID-Token", installationToken);
  if (authIdToken) headers.append("Authorization", `Bearer ${authIdToken}`);
  const newRequest = new Request(request, { headers });
  return await fetch(newRequest);
}

async function getAuthIdToken(auth) {
  await auth.authStateReady();
  if (!auth.currentUser) return;
  return await getIdToken(auth.currentUser);
}

قراءة حالة المصادقة على الخادم

سنستخدم FirebaseServerApp لعرض حالة مصادقة البرنامج على الخادم.

افتح src/lib/firebase/serverApp.js، واستبدِل الدالة getAuthenticatedAppForUser:

export async function getAuthenticatedAppForUser() {
  const idToken = headers().get("Authorization")?.split("Bearer ")[1];
  console.log('firebaseConfig', JSON.stringify(firebaseConfig));
  const firebaseServerApp = initializeServerApp(
    firebaseConfig,
    idToken
      ? {
          authIdToken: idToken,
        }
      : {}
  );

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

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

الاشتراك لتلقّي تغييرات المصادقة

للاشتراك في تغييرات المصادقة، اتبع الخطوات التالية:

  1. انتقِل إلى ملف src/components/Header.jsx.
  2. استبدل الدالة useUserSession بالرمز التالي:
function useUserSession(initialUser) {
	// The initialUser comes from the server via a server component
	const [user, setUser] = useState(initialUser);
	const router = useRouter();

	// Register the service worker that sends auth state back to server
	// The service worker is built with npm run build-service-worker
	useEffect(() => {
		if ("serviceWorker" in navigator) {
			const serializedFirebaseConfig = encodeURIComponent(JSON.stringify(firebaseConfig));
			const serviceWorkerUrl = `/auth-service-worker.js?firebaseConfig=${serializedFirebaseConfig}`
		
		  navigator.serviceWorker
			.register(serviceWorkerUrl)
			.then((registration) => console.log("scope is: ", registration.scope));
		}
	  }, []);

	useEffect(() => {
		const unsubscribe = onAuthStateChanged((authUser) => {
			setUser(authUser)
		})

		return () => unsubscribe()
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, []);

	useEffect(() => {
		onAuthStateChanged((authUser) => {
			if (user === undefined) return

			// refresh when user changed to ease testing
			if (user?.email !== authUser?.email) {
				router.refresh()
			}
		})
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [user])

	return user;
}

يستخدم هذا الرمز عنصر جذب حالة React لتعديل المستخدم عندما تحدد الدالة onAuthStateChanged أنّ هناك تغييرًا في حالة المصادقة.

التحقّق من التغييرات

يعرض التنسيق الجذر في ملف src/app/layout.js العنوان وتمريره إلى المستخدم، إذا كان متاحًا، كأداة مساعدة.

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

وهذا يعني أنّ المكوِّن <Header> يعرض بيانات المستخدمين، إذا كان ذلك متاحًا، خلال وقت تشغيل الخادم. إذا حدثت أي تعديلات على المصادقة خلال دورة حياة الصفحة بعد التحميل الأولي للصفحة، سيعالجها معالج onAuthStateChanged.

حان الآن وقت طرح إصدار جديد والتحقّق من العناصر التي أنشأتها.

  1. إنشاء التزام مع رسالة الإتمام "إظهار حالة تسجيل الدخول" وأرسله إلى مستودع جيت هب.
  2. افتح صفحة استضافة التطبيق في وحدة تحكُّم Firebase وانتظِر إلى أن تكتمل عملية الطرح الجديدة.
  3. تحقَّق من سلوك المصادقة الجديد:
    1. في المتصفّح، أعِد تحميل تطبيق الويب. يظهر الاسم المعروض في الرأس.
    2. سجِّل الخروج، ثم أعِد تسجيل الدخول. يتم تعديل الصفحة في الوقت الفعلي بدون إعادة تحميل الصفحة. يمكنك تكرار هذه الخطوة مع مستخدمين مختلفين.
    3. اختياري: انقر بزر الماوس الأيمن على تطبيق الويب، واختَر عرض مصدر الصفحة، وابحث عن الاسم المعروض. ويظهر في مصدر HTML الأولي الذي يعرضه الخادم.

7- عرض معلومات المطعم

يتضمّن تطبيق الويب بيانات وهمية عن المطاعم والمراجعات.

إضافة مطعم واحد أو أكثر

لإدراج بيانات مطعم وهمية في قاعدة بيانات Cloud Firestore المحلية، اتبع الخطوات التالية:

  1. في تطبيق الويب، حدد 2cf67d488d8e6332.png > أضِف نماذج المطاعم.
  2. في "وحدة تحكُّم Firebase" في صفحة قاعدة بيانات متجر مكافحة الحرائق، اختَر المطاعم. ستظهر لك مستندات المستوى الأعلى في مجموعة المطاعم، ويمثّل كل منها مطعمًا.
  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" وأرسله إلى مستودع جيت هب.
  2. افتح صفحة استضافة التطبيق في وحدة تحكُّم Firebase وانتظِر إلى أن تكتمل عملية الطرح الجديدة.
  3. في تطبيق الويب، أعِد تحميل الصفحة. تظهر صور المطاعم في شكل مربّعات على الصفحة.

التحقق من تحميل بطاقات بيانات المطعم في وقت تشغيل الخادم

باستخدام إطار عمل Next.js، قد لا يظهر بوضوح وقت تحميل البيانات في وقت تشغيل الخادم أو وقت التشغيل من جهة العميل.

للتحقّق من تحميل بيانات المطاعم في وقت تشغيل الخادم، اتبع الخطوات التالية:

  1. في تطبيق الويب، افتح "أدوات مطوري البرامج" وأوقِف JavaScript.

إيقاف JavaScipt في &quot;أدوات مطوري البرامج&quot;

  1. أعِد تحميل تطبيق الويب. لا يزال تحميل بيانات المطعم جاريًا. يتم عرض معلومات المطعم في استجابة الخادم. وعند تفعيل JavaScript، يتم ترطيب معلومات المطاعم من خلال رمز JavaScript من جهة العميل.
  2. في "أدوات مطوري البرامج"، أعِد تفعيل JavaScript.

استمِع إلى أحدث المعلومات عن المطاعم مع مستمعي اللقطات من 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(() => {
        const unsubscribe = getRestaurantsSnapshot(data => {
                setRestaurants(data);
        }, filters);

        return () => {
                unsubscribe();
        };
}, [filters]);

يستدعي هذا الرمز الدالة getRestaurantsSnapshot()، التي تشبه الدالة getRestaurants() التي نفذتها في خطوة سابقة. ومع ذلك، توفر دالة اللقطة هذه آلية استدعاء بحيث يتم استدعاء استدعاء في كل مرة يتم فيها إجراء تغيير على مجموعة المطعم.

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

	const unsubscribe = 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);
	});

	return unsubscribe;
}

تظهر التغييرات التي يتم إجراؤها من خلال صفحة قاعدة بيانات متجر Fire الآن في تطبيق الويب في الوقت الفعلي.

  1. إنشاء التزام مع رسالة التزام بعنوان "الاستماع إلى أحدث المعلومات عن المطعم في الوقت الفعلي" وأرسله إلى مستودع جيت هب.
  2. افتح صفحة استضافة التطبيق في وحدة تحكُّم 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 واجهة برمجة تطبيقات مناسبة للوصول إلى بيانات النموذج، مثل data.get("text") للحصول على القيمة النصية من حمولة إرسال النموذج.

لاستخدام إجراء خادم Next.js لمعالجة إرسال نموذج المراجعة، يمكنك اتباع الخطوات التالية:

  1. في الملف src/components/ReviewDialog.jsx، ابحث عن السمة action في العنصر <form>.
<form action={handleReviewFormSubmission}>

تشير قيمة السمة action إلى دالة يتم تنفيذها في الخطوة التالية.

  1. في الملف 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، يُرجى اتّباع الخطوات التالية:

  1. إنشاء التزام برسالة "السماح للمستخدمين بإرسال مراجعات عن المطعم" وأرسله إلى مستودع جيت هب.
  2. افتح صفحة استضافة التطبيق في وحدة تحكُّم Firebase وانتظِر إلى أن تكتمل عملية الطرح الجديدة.
  3. أعِد تحميل تطبيق الويب، واختَر مطعمًا من الصفحة الرئيسية.
  4. في صفحة المطعم، انقر على 3e19beef78bb0d0e.png.
  5. اختَر تقييمًا بالنجوم.
  6. كتابة مراجعة.
  7. انقر على إرسال. تظهر مراجعتك في أعلى قائمة المراجعات.
  8. في Cloud Firestore، ابحث في لوحة إضافة مستند عن مستند المطعم الذي راجعته واختَره.
  9. في لوحة بدء المجموعة، اختَر التقييمات.
  10. في لوحة إضافة مستند، ابحث عن المستند لمراجعته للتأكّد من إدراجه على النحو المتوقّع.

المستندات المتوفّرة في محاكي Firestore

9- حفظ الملفات التي حمّلها المستخدمون من تطبيق الويب

في هذا القسم، يمكنك إضافة وظائف حتى تتمكّن من استبدال الصورة المرتبطة بالمطعم عند تسجيل الدخول. يمكنك تحميل الصورة إلى 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);
        setRestaurant({ ...restaurant, 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. إنشاء التزام مع تضمين رسالة الالتزام: "السماح للمستخدمين بتغيير كل مطعم" صورة" وأرسله إلى مستودع جيت هب.
  2. افتح صفحة استضافة التطبيق في وحدة تحكُّم Firebase وانتظِر إلى أن تكتمل عملية الطرح الجديدة.
  3. في تطبيق الويب، تأكَّد من تسجيل الدخول واختَر مطعمًا.
  4. انقر على 7067eb41fea41ff0.png وحمِّل صورة من نظام الملفات. تغادر صورتك بيئتك المحلية ويتم تحميلها إلى Cloud Storage. تظهر الصورة فورًا بعد تحميلها.
  5. انتقِل إلى Cloud Storage لبرنامج Firebase.
  6. انتقِل إلى المجلد الذي يمثّل المطعم. تتوفّر الصورة التي حمّلتها في المجلد.

6cf3f9e2303c931c.png

10- تلخيص مراجعات المطاعم باستخدام الذكاء الاصطناعي التوليدي

في هذا القسم، ستضيف ميزة ملخص المراجعة حتى يتمكن المستخدم من فهم رأي الجميع بسرعة حول مطعم دون الحاجة إلى قراءة كل مراجعة.

تخزين مفتاح واجهة برمجة تطبيقات Gemini في "مدير Cloud Secret Manager"

  1. لاستخدام Gemini API، يجب توفُّر مفتاح واجهة برمجة تطبيقات. أنشِئ مفتاحًا في Google AI Studio.
  2. تتكامل استضافة التطبيقات مع Cloud Secret Manager للسماح لك بتخزين قيم حسّاسة، مثل مفاتيح واجهة برمجة التطبيقات بأمان:
    1. في نافذة Terminal، شغِّل الأمر لإنشاء مفتاح سرّي جديد:
    firebase apphosting:secrets:set gemini-api-key
    
    1. يجب نسخ مفتاح Gemini API ولصقه من Google AI Studio عندما يُطلب منك إدخال قيمة السر.
    2. عند سؤالك عمّا إذا كان يجب إضافة واجهة برمجة التطبيقات السرّية الجديدة إلى apphosting.yaml، أدخِل Y للموافقة.

أصبح مفتاح Gemini API مخزّنًا بأمان في Cloud Secret Manager، ويمكنك الوصول إليه من خلال الواجهة الخلفية لـ "استضافة التطبيقات".

تنفيذ مكوّن ملخّص المراجعات

  1. في src/components/Reviews/ReviewSummary.jsx، استبدِل الدالة GeminiSummary بالرمز التالي:
    export async function GeminiSummary({ restaurantId }) {
        const { firebaseServerApp } = await getAuthenticatedAppForUser();
        const reviews = await getReviewsByRestaurantId(
            getFirestore(firebaseServerApp),
            restaurantId
        );
    
        const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
        const model = genAI.getGenerativeModel({ model: "gemini-pro"});
    
        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 {
            const result = await model.generateContent(prompt);
            const response = await result.response;
            const text = response.text();
    
            return (
                <div className="restaurant__review_summary">
                    <p>{text}</p>
                    <p> Summarized with Gemini</p>
                </div>
            );
        } catch (e) {
            console.error(e);
            return <p>Error contacting Gemini</p>;
        }
    }
    
  2. إنشاء التزام مع رسالة التزام بعنوان "استخدام الذكاء الاصطناعي لتلخيص المراجعات" وأرسله إلى مستودع جيت هب.
  3. افتح صفحة استضافة التطبيق في وحدة تحكُّم Firebase وانتظِر إلى أن تكتمل عملية الطرح الجديدة.
  4. افتح صفحة خاصة بمطعم. في الجزء العلوي، من المفترض أن يظهر لك ملخص من جملة واحدة لجميع المراجعات في الصفحة.
  5. يمكنك إضافة مراجعة جديدة وإعادة تحميل الصفحة. من المفترض أن يظهر لك التغيير في الملخّص.

11- الخاتمة

تهانينا لقد تعلمت كيفية استخدام Firebase لإضافة ميزات ووظائف إلى تطبيق Next.js. على وجه التحديد، استخدمت ما يلي:

مزيد من المعلومات