1. Prima di iniziare
In questo codelab imparerai a integrare Firebase con un'app web Next.js chiamata Friendly Eats, un sito web per le recensioni di ristoranti.
L'app web completata offre funzionalità utili che dimostrano come Firebase può aiutarti a creare app Next.js. Queste funzionalità includono:
- Compilazione e deployment automatici:questo codelab utilizza Firebase App Hosting per compilare ed eseguire il deployment automatico del codice Next.js ogni volta che esegui il push in un ramo configurato.
- Accesso e disconnessione:l'app web completata ti consente di accedere con Google e di disconnetterti. L'accesso e la persistenza degli utenti sono gestiti interamente tramite Firebase Authentication.
- Immagini:l'app web completata consente agli utenti che hanno eseguito l'accesso di caricare immagini del ristorante. Gli asset immagine sono archiviati in Cloud Storage for Firebase. L'SDK Firebase JavaScript fornisce un URL pubblico alle immagini caricate. Questo URL pubblico viene quindi archiviato nel documento del ristorante pertinente in Cloud Firestore.
- Recensioni:l'app web completata consente agli utenti che hanno eseguito l'accesso di pubblicare recensioni di ristoranti costituite da una valutazione a stelle e un messaggio basato su testo. Le informazioni sulle recensioni vengono archiviate in Cloud Firestore.
- Filtri:l'app web completata consente agli utenti che hanno eseguito l'accesso di filtrare l'elenco dei ristoranti in base a categoria, posizione e prezzo. Puoi anche personalizzare il metodo di ordinamento utilizzato. I dati vengono accessibili da Cloud Firestore e le query Firestore vengono applicate in base ai filtri utilizzati.
Prerequisiti
- Un account GitHub
- Conoscenza di Next.js e JavaScript
Obiettivi didattici
- Come utilizzare Firebase con il router delle app Next.js e il rendering lato server.
- Come rendere persistenti le immagini in Cloud Storage for Firebase.
- Come leggere e scrivere dati in un database Cloud Firestore.
- Come utilizzare Accedi con Google con l'SDK Firebase JavaScript.
Che cosa ti serve
- Git
- Una versione stabile recente di Node.js
- Un browser a tua scelta, ad esempio Google Chrome
- Un ambiente di sviluppo con un editor di codice e un terminale
- Un Account Google per la creazione e la gestione del tuo progetto Firebase
- La possibilità di eseguire l'upgrade del progetto Firebase al piano tariffario Blaze
2. Configura l'ambiente di sviluppo e il repository GitHub
Questo codelab fornisce il codebase iniziale dell'app e si basa sulla CLI Firebase.
Creare un repository GitHub
Il codice sorgente del codelab è disponibile all'indirizzo https://github.com/firebase/friendlyeats-web. Il repository contiene progetti di esempio per più piattaforme. Tuttavia, questo codelab utilizza solo la directory nextjs-start
. Prendi nota delle seguenti directory:
* `nextjs-start`: contains the starter code upon which you build.
* `nextjs-end`: contains the solution code for the finished web app.
Copia la cartella nextjs-start
nel tuo repository:
- Utilizzando un terminale, crea una nuova cartella sul computer e passa alla nuova directory:
mkdir codelab-friendlyeats-web cd codelab-friendlyeats-web
- Utilizza il pacchetto npm giget per recuperare solo la cartella
nextjs-start
:npx giget@latest gh:firebase/friendlyeats-web/nextjs-start#master . --install
- Tieni traccia delle modifiche localmente con Git:
git init git add . git commit -m "codelab starting point" git branch -M main
- Crea un nuovo repository GitHub: https://github.com/new. Assegna il nome che preferisci.
- Copia il nuovo URL creato da GitHub. L'aspetto sarà simile a uno dei seguenti:
https://github.com/<USER_NAME>/<REPOSITORY_NAME>.git
ogit@github.com:<USER_NAME>/<REPOSITORY_NAME>.git
- Esegui il push delle modifiche locali nel nuovo repository GitHub eseguendo il comando seguente. Sostituisci l'URL effettivo del repository con il segnaposto
<REPOSITORY_URL>
.git remote add origin <REPOSITORY_URL> git push -u origin main
- Ora dovresti vedere il codice iniziale nel tuo repository GitHub.
Installare o aggiornare l'interfaccia a riga di comando di Firebase
Esegui questo comando per verificare che Firebase CLI sia installata e che la versione sia 14.1.0 o successive:
firebase --version
Se visualizzi una versione precedente o se non hai installato l'interfaccia a riga di comando di Firebase, esegui il comando di installazione:
npm install -g firebase-tools@latest
Se non riesci a installare l'interfaccia a riga di comando di Firebase a causa di errori di autorizzazione, consulta la documentazione di npm o utilizza un'altra opzione di installazione.
Accedi a Firebase
- Esegui questo comando per accedere alla CLI di Firebase:
firebase login
- A seconda che tu voglia che Firebase raccolga dati, inserisci
Y
oN
. - Nel browser, seleziona il tuo Account Google e poi fai clic su Consenti.
3. Configura il progetto Firebase
In questa sezione, configurerai un progetto Firebase e gli assocerai un'app web Firebase. Configurerai anche i servizi Firebase utilizzati dall'app web di esempio.
Crea un progetto Firebase
- Accedi alla console Firebase utilizzando lo stesso Account Google utilizzato nel passaggio precedente.
- Fai clic sul pulsante per creare un nuovo progetto, quindi inserisci un nome per il progetto (ad esempio
FriendlyEats Codelab
).
- Fai clic su Continua.
- Se richiesto, leggi e accetta i termini di Firebase, quindi fai clic su Continua.
- (Facoltativo) Attiva l'assistenza AI nella console Firebase (denominata "Gemini in Firebase").
- Per questo codelab non hai bisogno di Google Analytics, quindi disattiva l'opzione Google Analytics.
- Fai clic su Crea progetto, attendi il provisioning del progetto, poi fai clic su Continua.
Esegui l'upgrade del piano tariffario Firebase
Per utilizzare Firebase App Hosting e Cloud Storage for Firebase, il tuo progetto Firebase deve essere incluso nel piano tariffario con pagamento a consumo (Blaze), il che significa che è collegato a un account di fatturazione Cloud.
- Un account di fatturazione Cloud richiede un metodo di pagamento, ad esempio una carta di credito.
- Se non hai mai utilizzato Firebase e Google Cloud, verifica se hai diritto a un credito di 300$e a un account Cloud Billing di prova senza costi.
- Se stai svolgendo questo codelab nell'ambito di un evento, chiedi all'organizzatore se sono disponibili crediti Cloud.
Per eseguire l'upgrade del progetto al piano Blaze:
- Nella console Firebase, seleziona l'opzione per eseguire l'upgrade del piano.
- Seleziona il piano Blaze. Segui le istruzioni sullo schermo per collegare un account di fatturazione Cloud al tuo progetto.
Se hai dovuto creare un account di fatturazione Cloud nell'ambito di questo upgrade, potresti dover tornare al flusso di upgrade nella console Firebase per completarlo.
Aggiungere un'app web al tuo progetto Firebase
- Vai alla Panoramica del progetto nel tuo progetto Firebase, poi fai clic su
Web.
Se nel progetto sono già registrate delle app, fai clic su Aggiungi app per visualizzare l'icona Web. - Nella casella di testo Nickname app, inserisci un nickname memorabile per l'app, ad esempio
My Next.js app
. - Lascia deselezionata la casella di controllo Configura anche Firebase Hosting per questa app.
- Fai clic su Registra app > Continua alla console.
Configurare i servizi Firebase nella console Firebase
Configurare l'autenticazione
- Nella console Firebase, vai ad Autenticazione.
- Fai clic su Inizia.
- Nella colonna Provider aggiuntivi, fai clic su Google > Attiva.
- Nella casella di testo Nome visibile al pubblico del progetto, inserisci un nome memorabile, ad esempio
My Next.js app
. - Dal menu a discesa Email di assistenza per il progetto, seleziona il tuo indirizzo email.
- Fai clic su Salva.
Configura Cloud Firestore
- Nel riquadro a sinistra della console Firebase, espandi Build e seleziona Firestore Database.
- Fai clic su Crea database.
- Lascia l'ID database impostato su
(default)
. - Seleziona una posizione per il database, poi fai clic su Avanti.
Per un'app reale, devi scegliere una posizione vicina ai tuoi utenti. - Fai clic su Avvia in modalità di test. Leggi l'esclusione di responsabilità relativa alle regole di sicurezza.
Più avanti in questo codelab, aggiungerai regole di sicurezza per proteggere i tuoi dati. Non distribuire o esporre pubblicamente un'app senza aggiungere regole di sicurezza per il tuo database. - Fai clic su Crea.
Configura Cloud Storage for Firebase
- Nel riquadro a sinistra della console Firebase, espandi Build e seleziona Storage.
- Fai clic su Inizia.
- Seleziona una posizione per il bucket di archiviazione predefinito.
I bucket inUS-WEST1
,US-CENTRAL1
eUS-EAST1
possono usufruire del livello"Sempre senza costi" per Google Cloud Storage. I bucket in tutte le altre località seguono i prezzi e l'utilizzo di Google Cloud Storage. - Fai clic su Avvia in modalità di test. Leggi l'esclusione di responsabilità relativa alle regole di sicurezza.
Più avanti in questo codelab, aggiungerai regole di sicurezza per proteggere i tuoi dati. Nondistribuire o esporre pubblicamente un'app senza aggiungere regole di sicurezza per il bucket Storage. - Fai clic su Crea.
Esegui il deployment delle regole di sicurezza
Il codice contiene già set di regole di sicurezza per Firestore e per Cloud Storage for Firebase. Dopo aver implementato le regole di sicurezza, i dati nel database e nel bucket sono protetti meglio dall'uso improprio.
- Nel terminale, configura l'interfaccia a riga di comando in modo da utilizzare il progetto Firebase che hai creato in precedenza:
Quando ti viene chiesto un alias, inseriscifirebase use --add
friendlyeats-codelab
. - Per eseguire il deployment di queste regole di sicurezza (nonché degli indici che saranno necessari in un secondo momento), esegui questo comando nel terminale:
firebase deploy --only firestore,storage
- Se ti viene chiesto:
"Cloud Storage for Firebase needs an IAM Role to use cross-service rules. Grant the new role?"
, premiEnter
per selezionare Sì.
4. Esamina la codebase iniziale
In questa sezione esaminerai alcune aree del codebase iniziale dell'app a cui aggiungerai funzionalità in questo codelab.
Struttura di cartelle e file
La tabella seguente contiene una panoramica della struttura di cartelle e file dell'app:
Cartelle e file | Descrizione |
| Componenti React per filtri, intestazioni, dettagli del ristorante e recensioni |
| Funzioni di utilità che non sono necessariamente associate a React o Next.js |
| Codice specifico di Firebase e configurazione di Firebase |
| Asset statici nell'app web, come le icone |
| Routing con il router delle app Next.js |
| Dipendenze del progetto con npm |
| Configurazione specifica di Next.js (le azioni del server sono attive) |
| Configurazione del servizio di linguaggio JavaScript |
Componenti server e client
L'app è un'app web Next.js che utilizza App Router. Il rendering lato server viene utilizzato in tutta l'app. Ad esempio, il file src/app/page.js
è un componente server responsabile della pagina principale. Il file src/components/RestaurantListings.jsx
è un componente client indicato dalla direttiva "use client"
all'inizio del file.
Importare estratti conto
Potresti notare istruzioni di importazione come le seguenti:
import RatingPicker from "@/src/components/RatingPicker.jsx";
L'app utilizza il simbolo @
per evitare percorsi di importazione relativi macchinosi ed è resa possibile dagli alias di percorso.
API specifiche di Firebase
Tutto il codice dell'API Firebase è incluso nella directory src/lib/firebase
. I singoli componenti React importano quindi le funzioni sottoposte a wrapping dalla directory src/lib/firebase
, anziché importare direttamente le funzioni Firebase.
Dati simulati
I dati simulati di ristoranti e recensioni sono contenuti nel file src/lib/randomData.js
. I dati di questo file vengono assemblati nel codice del file src/lib/fakeRestaurants.js
.
5. Crea un backend di hosting delle app
In questa sezione configurerai un backend App Hosting per monitorare un ramo del repository Git.
Al termine di questa sezione, avrai un backend App Hosting connesso al tuo repository in GitHub che ricompilerà e implementerà automaticamente una nuova versione della tua app ogni volta che esegui il push di un nuovo commit nel ramo main
.
Crea un backend
- Vai alla pagina App Hosting nella console Firebase:
- Fai clic su "Inizia" per avviare il flusso di creazione del backend. Configura il backend nel seguente modo:
- Scegli un'area geografica. Per un'app reale, scegli la regione più vicina ai tuoi utenti.
- Segui le istruzioni del passaggio "Importa un repository GitHub" per connettere il repository GitHub che hai creato in precedenza.
- Imposta le impostazioni di deployment:
- Mantieni la directory root come
/
- Imposta il ramo live su
main
- Abilita implementazioni automatiche
- Mantieni la directory root come
- Assegna un nome al backend
friendlyeats-codelab
. - In "Associa un'app web Firebase", fai clic su "Crea una nuova app web Firebase".
- Fai clic su "Fine ed esegui il deployment". Dopo qualche istante, verrà visualizzata una nuova pagina in cui potrai vedere lo stato del nuovo backend di App Hosting.
- Una volta completato il lancio, fai clic sul tuo dominio senza costi nella sezione "Domini". L'attivazione potrebbe richiedere alcuni minuti a causa della propagazione del DNS.
- Oh oh. Quando carichi la pagina, viene visualizzato il messaggio di errore "Errore dell'applicazione: si è verificata un'eccezione lato server (per ulteriori informazioni, consulta i log del server)".
- Nella console Firebase, controlla la scheda "Log" del backend di App Hosting. Verrà visualizzato un log "Errore: non implementato". Risolviamo il problema nel passaggio successivo, quando aggiungiamo l'autenticazione.
Hai eseguito il deployment dell'app web iniziale. Ogni volta che esegui il push di un nuovo commit nel ramo main
del tuo repository GitHub, nella console Firebase viene avviata una nuova build e un nuovo rollout e il tuo sito viene aggiornato automaticamente al termine del rollout.
6. Aggiungere l'autenticazione all'app web
In questa sezione aggiungi l'autenticazione all'app web per poter accedere.
Aggiungi un dominio autorizzato
Firebase Authentication accetterà solo le richieste di accesso dai domini che consenti. Qui aggiungeremo il dominio del backend di App Hosting all'elenco dei domini approvati nel tuo progetto.
- Copia il dominio del backend App Hosting dalla pagina "Panoramica" di App Hosting.
- Vai alla scheda Impostazioni autenticazione e scegli Domini autorizzati.
- Fai clic sul pulsante Aggiungi dominio.
- Inserisci il dominio del backend App Hosting.
- Fai clic su Aggiungi.
Implementa le funzioni di accesso e disconnessione
- Nel file
src/lib/firebase/auth.js
, sostituisci le funzionionAuthStateChanged
,onIdTokenChanged
,signInWithGoogle
esignOut
con il seguente codice:
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);
}
}
Questo codice utilizza le seguenti API Firebase:
API Firebase | Descrizione |
Aggiunge un osservatore per le modifiche allo stato di accesso dell'utente. | |
Aggiunge un osservatore per le modifiche al token ID dell'utente. | |
Crea un'istanza del provider di autenticazione Google. | |
Avvia un flusso di autenticazione basato su finestre di dialogo. | |
Disconnette l'utente. |
Nel file src/components/Header.jsx
, il codice richiama già le funzioni signInWithGoogle
e signOut
.
Invia lo stato di autenticazione al server
Per trasferire lo stato di autenticazione al server, utilizzeremo i cookie. Ogni volta che lo stato di autenticazione cambia nel client, aggiorneremo il cookie __session
.
In src/components/Header.jsx
, sostituisci la funzione useUserSession
con il seguente codice:
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;
}
Leggere lo stato di autenticazione sul server
Utilizzeremo FirebaseServerApp per rispecchiare lo stato di autenticazione del client sul server.
Apri src/lib/firebase/serverApp.js
e sostituisci la funzione 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 };
}
Verificare le modifiche
Il layout principale nel file src/app/layout.js
esegue il rendering dell'intestazione e passa l'utente, se disponibile, come proprietà.
<Header initialUser={currentUser?.toJSON()} />
Ciò significa che il componente <Header>
esegue il rendering dei dati utente, se disponibili, durante il runtime del server. Se durante il ciclo di vita della pagina si verificano aggiornamenti dell'autenticazione dopo il caricamento iniziale della pagina, vengono gestiti dal gestore onAuthStateChanged
.
Ora è il momento di implementare una nuova build e verificare ciò che hai creato.
- Crea un commit con il messaggio "Add authentication" (Aggiungi autenticazione) ed eseguine il push nel repository GitHub.
- Apri la pagina App Hosting nella console Firebase e attendi il completamento del nuovo rollout.
- Verifica il nuovo comportamento di autenticazione:
- Nel browser, aggiorna l'app web. Il tuo nome visualizzato viene visualizzato nell'intestazione.
- Esci e accedi di nuovo. Puoi ripetere questo passaggio con utenti diversi.
- (Facoltativo) Fai clic con il tasto destro del mouse sull'app web, seleziona Visualizza codice sorgente pagina e cerca il nome visualizzato. Viene visualizzato nel codice sorgente HTML non elaborato restituito dal server.
7. Visualizzare le informazioni sul ristorante
L'app web include dati fittizi per ristoranti e recensioni.
Aggiungi uno o più ristoranti
Per inserire dati di ristoranti simulati nel database Cloud Firestore locale:
- Accedi all'app web, se non l'hai ancora fatto. Poi, seleziona
> Aggiungi ristoranti di esempio.
- Nella console Firebase, nella pagina Firestore Database, seleziona restaurants. Vengono visualizzati i documenti di primo livello nella raccolta di ristoranti, ognuno dei quali rappresenta un ristorante.
- Fai clic su alcuni documenti per esplorare le proprietà di un documento di un ristorante.
Visualizzare l'elenco dei ristoranti
Il tuo database Cloud Firestore ora contiene ristoranti che l'app web Next.js può visualizzare.
Per definire il codice di recupero dei dati:
- Nel file
src/app/page.js
, individua il componente server<Home />
e controlla la chiamata alla funzionegetRestaurants
, che recupera un elenco di ristoranti in fase di esecuzione del server. Implementerai la funzionegetRestaurants
nei passaggi successivi. - Nel file
src/lib/firebase/firestore.js
, sostituisci le funzioniapplyQueryFilters
egetRestaurants
con il seguente codice:
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(),
};
});
}
- Crea un commit con il messaggio "Read the list of restaurants from Firestore" (Leggi l'elenco dei ristoranti da Firestore) ed eseguine il push nel repository GitHub.
- Apri la pagina App Hosting nella console Firebase e attendi il completamento del nuovo rollout.
- Nell'app web, aggiorna la pagina. Le immagini dei ristoranti vengono visualizzate come riquadri nella pagina.
Verifica che le schede dei ristoranti vengano caricate durante l'esecuzione del server
Se utilizzi il framework Next.js, potrebbe non essere ovvio quando i dati vengono caricati in fase di runtime del server o del client.
Per verificare che le schede dei ristoranti vengano caricate in fase di esecuzione del server:
- Nell'app web, apri DevTools e disattiva JavaScript.
- Aggiorna l'app web. Gli elenchi dei ristoranti vengono comunque caricati. Le informazioni sul ristorante vengono restituite nella risposta del server. Quando JavaScript è abilitato, le informazioni sul ristorante vengono idratate tramite il codice JavaScript lato client.
- In DevTools, riattiva JavaScript.
Ascolta gli aggiornamenti del ristorante con i listener di snapshot di Cloud Firestore
Nella sezione precedente hai visto come è stato caricato il set iniziale di ristoranti dal file src/app/page.js
. Il file src/app/page.js
è un componente server e viene visualizzato sul server, incluso il codice di recupero dei dati Firebase.
Il file src/components/RestaurantListings.jsx
è un componente client e può essere configurato per l'idratazione del markup sottoposto a rendering lato server.
Per configurare il file src/components/RestaurantListings.jsx
in modo da idratare il markup sottoposto a rendering lato server:
- Nel file
src/components/RestaurantListings.jsx
, osserva il seguente codice, che è già scritto per te:
useEffect(() => {
return getRestaurantsSnapshot((data) => {
setRestaurants(data);
}, filters);
}, [filters]);
Questo codice richiama la funzione getRestaurantsSnapshot()
, simile alla funzione getRestaurants()
implementata in un passaggio precedente. Tuttavia, questa funzione di snapshot fornisce un meccanismo di callback in modo che il callback venga richiamato ogni volta che viene apportata una modifica alla raccolta del ristorante.
- Nel file
src/lib/firebase/firestore.js
, sostituisci la funzionegetRestaurantsSnapshot()
con il seguente codice:
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);
});
}
Le modifiche apportate tramite la pagina Database Firestore ora vengono visualizzate nell'app web in tempo reale.
- Crea un commit con il messaggio "Listen for realtime restaurant updates" (Ascolta gli aggiornamenti in tempo reale dei ristoranti) ed eseguine il push nel repository GitHub.
- Apri la pagina App Hosting nella console Firebase e attendi il completamento del nuovo rollout.
- Nell'app web, seleziona
> Aggiungi ristoranti di esempio. Se la funzione snapshot è implementata correttamente, i ristoranti vengono visualizzati in tempo reale senza aggiornamento della pagina.
8. Salvare le recensioni inviate dagli utenti dall'app web
- Nel file
src/lib/firebase/firestore.js
, sostituisci la funzioneupdateWithRating()
con il seguente codice:
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()),
});
};
Questo codice inserisce un nuovo documento Firestore che rappresenta la nuova recensione. Il codice aggiorna anche il documento Firestore esistente che rappresenta il ristorante con i dati aggiornati per il numero di valutazioni e la valutazione media calcolata.
- Sostituisci la funzione
addReviewToRestaurant()
con il seguente codice:
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;
}
}
Implementare un'azione server Next.js
Un'azione server Next.js fornisce un'API pratica per accedere ai dati del modulo, ad esempio data.get("text")
per ottenere il valore di testo dal payload di invio del modulo.
Per utilizzare un'azione server Next.js per elaborare l'invio del modulo di recensione:
- Nel file
src/components/ReviewDialog.jsx
, trova l'attributoaction
nell'elemento<form>
.
<form action={handleReviewFormSubmission}>
Il valore dell'attributo action
si riferisce a una funzione che implementerai nel passaggio successivo.
- Nel file
src/app/actions.js
, sostituisci la funzionehandleReviewFormSubmission()
con il seguente codice:
// 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"),
});
}
Aggiungere recensioni per un ristorante
Hai implementato il supporto per l'invio di recensioni, quindi ora puoi verificare che le recensioni vengano inserite correttamente in Cloud Firestore.
Per aggiungere una recensione e verificare che sia inserita in Cloud Firestore:
- Crea un commit con il messaggio "Allow users to submit restaurant reviews" (Consenti agli utenti di inviare recensioni di ristoranti) ed eseguine il push nel repository GitHub.
- Apri la pagina App Hosting nella console Firebase e attendi il completamento del nuovo rollout.
- Aggiorna l'app web e seleziona un ristorante dalla home page.
- Nella pagina del ristorante, fai clic su
.
- Seleziona una valutazione a stelle.
- Scrivi una recensione.
- Fai clic su Invia. La tua recensione viene visualizzata nella parte superiore dell'elenco delle recensioni.
- In Cloud Firestore, cerca il riquadro Aggiungi documento per il documento del ristorante che hai recensito e selezionalo.
- Nel riquadro Avvia raccolta, seleziona Valutazioni.
- Nel riquadro Aggiungi documento, trova il documento da rivedere per verificare che sia stato inserito come previsto.
9. Salvare i file caricati dagli utenti dall'app web
In questa sezione, aggiungi la funzionalità che ti consente di sostituire l'immagine associata a un ristorante quando hai eseguito l'accesso. Carichi l'immagine su Firebase Storage e aggiorni l'URL dell'immagine nel documento Cloud Firestore che rappresenta il ristorante.
Per salvare i file caricati dagli utenti dall'app web:
- Nel file
src/components/Restaurant.jsx
, osserva il codice eseguito quando l'utente carica un file:
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 });
}
Non sono necessarie modifiche a questa funzione, ma implementerai il comportamento della funzione updateRestaurantImage()
nei passaggi successivi.
- Nel file
src/lib/firebase/storage.js
, sostituisci le funzioniupdateRestaurantImage()
euploadImage()
con il seguente codice:
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);
}
La funzione updateRestaurantImageReference()
è già implementata per te. Questa funzione aggiorna un documento del ristorante esistente in Cloud Firestore con un URL immagine aggiornato.
Verifica la funzionalità di caricamento delle immagini
Per verificare che l'immagine venga caricata come previsto:
- Crea un commit con il messaggio "Allow users to change each restaurants' photo" (Consenti agli utenti di modificare la foto di ogni ristorante) ed eseguine il push nel repository GitHub.
- Apri la pagina App Hosting nella console Firebase e attendi il completamento del nuovo rollout.
- Nell'app web, verifica di aver eseguito l'accesso e seleziona un ristorante.
- Fai clic su
e carica un'immagine dal tuo file system. L'immagine esce dall'ambiente locale e viene caricata su Cloud Storage. L'immagine viene visualizzata immediatamente dopo il caricamento.
- Vai a Cloud Storage per Firebase.
- Vai alla cartella che rappresenta il ristorante. L'immagine che hai caricato esiste nella cartella.
10. Riepilogare le recensioni dei ristoranti con l'AI generativa
In questa sezione, aggiungerai una funzionalità di riepilogo delle recensioni in modo che un utente possa capire rapidamente cosa pensano tutti di un ristorante senza dover leggere ogni recensione.
Archivia una chiave API Gemini in Cloud Secret Manager
- Per utilizzare l'API Gemini, devi avere una chiave API. Visita Google AI Studio e fai clic su "Crea chiave API".
- Nel campo di input "Cerca progetti Google Cloud", scegli il tuo progetto Firebase. Ogni progetto Firebase è supportato da un progetto Google Cloud.
- App Hosting si integra con Cloud Secret Manager per consentirti di archiviare in modo sicuro valori sensibili come le chiavi API:
- In un terminale, esegui il comando per creare un nuovo secret:
firebase apphosting:secrets:set GEMINI_API_KEY
- Quando ti viene chiesto il valore del secret, copia e incolla la chiave API Gemini da Google AI Studio.
- Quando ti viene chiesto se il nuovo segreto è per la produzione o per i test locali, scegli "Produzione".
- Quando ti viene chiesto se vuoi concedere l'accesso in modo che l'account di servizio del backend possa accedere al secret, seleziona "Sì".
- Quando ti viene chiesto se il nuovo segreto deve essere aggiunto a
apphosting.yaml
, inserisciY
per accettare.
La chiave API Gemini ora è archiviata in modo sicuro in Cloud Secret Manager ed è accessibile al backend di App Hosting.
Implementare il componente di riepilogo delle recensioni
- In
src/components/Reviews/ReviewSummary.jsx
, sostituisci la funzioneGeminiSummary
con il seguente codice: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>; } }
- Crea un commit con il messaggio "Use AI to summarize reviews" (Utilizza l'AI per riassumere le recensioni) ed eseguine il push nel repository GitHub.
- Apri la pagina App Hosting nella console Firebase e attendi il completamento del nuovo rollout.
- Apri una pagina di un ristorante. In alto, dovresti vedere un riepilogo di una frase di tutte le recensioni sulla pagina.
- Aggiungi una nuova recensione e aggiorna la pagina. Dovresti visualizzare la modifica del riepilogo.
11. Conclusione
Complimenti! Hai imparato a utilizzare Firebase per aggiungere funzionalità a un'app Next.js. In particolare, hai utilizzato:
- Firebase App Hosting per creare ed eseguire automaticamente il deployment del codice Next.js ogni volta che esegui il push in un ramo configurato.
- Firebase Authentication per attivare la funzionalità di accesso e disconnessione.
- Cloud Firestore per i dati dei ristoranti e delle recensioni dei ristoranti.
- Cloud Storage for Firebase per le immagini del ristorante.