1. Antes de começar
Neste codelab, você aprenderá a integrar o Firebase a um app da Web Next.js chamado Friendly Eats, que é um site de avaliações de restaurantes.
O app da Web completo oferece recursos úteis que demonstram como o Firebase pode ajudar você a criar apps Next.js. Esses recursos incluem o seguinte:
- Build e implantação automáticos: este codelab usa o Firebase App Hosting para criar e implantar automaticamente o código do Next.js sempre que você envia para uma ramificação configurada.
- Login e logout:o app da Web concluído permite que você faça login com o Google e saia. O login e a persistência do usuário são gerenciados inteiramente pelo Firebase Authentication.
- Imagens: o app da Web concluído permite que os usuários que fizeram login façam upload de imagens de restaurantes. Os recursos de imagem são armazenados no Cloud Storage para Firebase. O SDK do Firebase para JavaScript fornece um URL público para as imagens enviadas. Esse URL público é armazenado no documento do restaurante relevante no Cloud Firestore.
- Avaliações: o app da Web concluído permite que os usuários conectados postem avaliações de restaurantes com uma nota e uma mensagem de texto. As informações das avaliações são armazenadas no Cloud Firestore.
- Filtros: o app da Web concluído permite que os usuários que fizeram login filtrem a lista de restaurantes por categoria, local e preço. Também é possível personalizar o método de classificação usado. Os dados são acessados do Cloud Firestore, e as consultas do Firestore são aplicadas com base nos filtros usados.
Pré-requisitos
- Uma conta no GitHub
- Conhecimento de Next.js e JavaScript.
Neste curso, você vai aprender a:
- Como usar o Firebase com o roteador de apps Next.js e a renderização do lado do servidor.
- Como manter imagens no Cloud Storage para Firebase.
- Como ler e gravar dados em um banco de dados do Cloud Firestore.
- Como usar o login com o Google com o SDK do Firebase para JavaScript.
Pré-requisitos
- Git
- Uma versão estável recente do Node.js
- Um navegador da sua escolha, como o Google Chrome
- Ambiente de desenvolvimento com um editor de código e um terminal
- Uma Conta do Google para a criação e o gerenciamento do seu projeto do Firebase
- A capacidade de fazer upgrade do seu projeto do Firebase para o plano de preços Blaze
2. Configurar o ambiente de desenvolvimento e o repositório do GitHub
Este codelab fornece a base de código inicial do app e depende da CLI do Firebase.
Crie um repositório do GitHub
A origem do codelab pode ser encontrada em https://github.com/firebase/friendlyeats-web. O repositório contém projetos de exemplo para várias plataformas. No entanto, este codelab usa apenas o diretório nextjs-start
. Anote os seguintes diretórios:
* `nextjs-start`: contains the starter code upon which you build.
* `nextjs-end`: contains the solution code for the finished web app.
Copie a pasta nextjs-start
para seu repositório:
- Usando um terminal, crie uma nova pasta no computador e mude para o novo diretório:
mkdir codelab-friendlyeats-web cd codelab-friendlyeats-web
- Use o pacote npm giget para buscar apenas a pasta
nextjs-start
:npx giget@latest gh:firebase/friendlyeats-web/nextjs-start#master . --install
- Acompanhe as mudanças localmente com o git:
git init git commit -a -m "codelab starting point" git branch -M main
- Crie um novo repositório do GitHub: https://github.com/new. Dê o nome que quiser a ele.
- O GitHub vai fornecer um novo URL do repositório que se parece com
https://github.com/
ou/ .git git@github.com:
. Copie esse URL./ .git
- O GitHub vai fornecer um novo URL do repositório que se parece com
- Envie as mudanças locais para o novo repositório do GitHub. Execute o comando a seguir, substituindo o URL do repositório pelo marcador de posição
.git remote add origin <your-repository-url> git push -u origin main
- O código inicial vai aparecer no seu repositório do GitHub.
Instalar ou atualizar a CLI do Firebase
Execute o seguinte comando para verificar se você tem a CLI do Firebase instalada e se ela é a v13.9.0 ou mais recente:
firebase --version
Se você encontrar uma versão anterior ou não tiver a CLI do Firebase instalada, execute o comando de instalação:
npm install -g firebase-tools@latest
Se não for possível instalar a CLI do Firebase devido a erros de permissão, consulte a documentação do npm ou use outra opção de instalação.
Fazer login no Firebase
- Execute o comando a seguir para fazer login na CLI do Firebase:
firebase login
- Para que o Firebase colete dados, insira
Y
ouN
. - No navegador, selecione sua Conta do Google e clique em Permitir.
3. Configurar seu projeto do Firebase
Nesta seção, você vai configurar um projeto do Firebase e associar um app da Web do Firebase a ele. Você também vai configurar os serviços do Firebase usados pelo app da Web de exemplo.
Criar um projeto do Firebase
- No Console do Firebase, clique em Adicionar projeto.
- Na caixa de texto Digite o nome do projeto, digite
FriendlyEats Codelab
ou o nome do projeto que você quiser e clique em Continuar. - No modal Confirmar plano de faturamento do Firebase, confirme se o plano é Blaze e clique em Confirmar plano.
- Neste codelab, você não precisa do Google Analytics. Portanto, desative a opção Ativar o Google Analytics para este projeto.
- Clique em Criar projeto.
- Aguarde o provisionamento do projeto e clique em Continuar.
- No projeto do Firebase, acesse Configurações do projeto. Anote o ID do projeto, porque você vai precisar dele mais tarde. Esse identificador exclusivo é como seu projeto é identificado (por exemplo, na CLI do Firebase).
Fazer upgrade do plano de preços do Firebase
Para usar o Firebase App Hosting e o Cloud Storage para Firebase, seu projeto do Firebase precisa estar no plano de preços de pagamento por uso (Blaze), o que significa que ele está vinculado a uma conta do Cloud Billing.
- Uma conta do Cloud Billing exige uma forma de pagamento, como cartão de crédito.
- Se você ainda não conhece o Firebase e o Google Cloud, confira se tem qualificação para receber um crédito de US$ 300 e uma conta de teste gratuito do Cloud Billing.
- Se você estiver fazendo este codelab como parte de um evento, pergunte ao organizador se há créditos do Cloud disponíveis.
Para fazer upgrade do seu projeto para o plano Blaze, siga estas etapas:
- No console do Firebase, selecione Fazer upgrade do seu plano.
- Selecione o plano Blaze. Siga as instruções na tela para vincular uma conta do Cloud Billing ao seu projeto.
Se você precisou criar uma conta do Cloud Billing como parte desse upgrade, talvez seja necessário voltar ao fluxo de upgrade no console do Firebase para concluir o upgrade.
Adicionar um app da Web ao seu projeto do Firebase
- Navegue até a Visão geral do projeto no seu projeto do Firebase e clique em Web.
Se você já tiver apps registrados no seu projeto, clique em Adicionar app para ver o ícone da Web. - Na caixa de texto Apelido do app, digite um apelido fácil de lembrar, como
My Next.js app
. - Mantenha a caixa de seleção Também configurar o Firebase Hosting para este app desmarcada.
- Clique em Registrar app > Próxima > Próxima > Continuar para o console.
Configurar serviços do Firebase no console do Firebase
Configurar o Authentication
- No console do Firebase, navegue até Autenticação.
- Clique em Começar.
- Na coluna Outros provedores, clique em Google > Ativar.
- Na caixa de texto Nome voltado ao público do projeto, digite um nome fácil de lembrar, como
My Next.js app
. - No menu suspenso E-mail de suporte do projeto, selecione seu endereço de e-mail.
- Clique em Salvar.
Configurar o Cloud Firestore
- No painel esquerdo do Console do Firebase, expanda Build e selecione Banco de dados do Firestore.
- Clique em Criar banco de dados.
- Deixe o ID do banco de dados definido como
(default)
. - Selecione um local para o banco de dados e clique em Próxima.
No caso de apps reais, escolha um local próximo aos usuários. - Clique em Iniciar no modo de teste. Leia o aviso sobre as regras de segurança.
Mais adiante neste codelab, você vai adicionar regras de segurança para proteger seus dados. Não distribua ou exponha um aplicativo publicamente sem adicionar regras de segurança ao seu banco de dados. - Clique em Criar.
Configurar o Cloud Storage para Firebase
- No painel esquerdo do Console do Firebase, abra Build e selecione Armazenamento.
- Clique em Começar.
- Selecione um local para o bucket padrão do Storage.
Buckets emUS-WEST1
,US-CENTRAL1
eUS-EAST1
podem aproveitar o nível "Sempre sem custo financeiro" do Google Cloud Storage. Os buckets em todos os outros locais seguem os preços e o uso do Google Cloud Storage. - Clique em Iniciar no modo de teste. Leia a exoneração de responsabilidade sobre as regras de segurança.
Mais adiante neste codelab, você vai adicionar regras de segurança para proteger seus dados. Não distribua ou exponha um aplicativo publicamente sem adicionar regras de segurança ao bucket do Storage. - Clique em Criar.
4. Revisar a base de código inicial
Nesta seção, você vai revisar algumas áreas da base de código inicial do app às quais vai adicionar funcionalidades neste codelab.
Estrutura de pastas e arquivos
A tabela a seguir contém uma visão geral da estrutura de pastas e arquivos do app:
Pastas e arquivos | Descrição |
| Componentes do React para filtros, cabeçalhos, detalhes de restaurantes e avaliações |
| Funções utilitárias que não estão necessariamente vinculadas ao React ou Next.js. |
| Código específico e configuração do Firebase |
| Recursos estáticos no app da Web, como ícones |
| Roteamento com o roteador de apps Next.js |
| Um gerenciador de rotas de API |
| Dependências do projeto com npm |
| Configuração específica do Next.js (as ações do servidor estão ativadas) |
| Configuração do serviço de linguagem JavaScript |
Componentes do servidor e do cliente
O app é um app da Web Next.js que usa o Roteador de apps. A renderização do servidor é usada em todo o app. Por exemplo, o arquivo src/app/page.js
é um componente do servidor responsável pela página principal. O arquivo src/components/RestaurantListings.jsx
é um componente do cliente indicado pela diretiva "use client"
no início do arquivo.
Declarações de importação
Você vai notar instruções de importação como estas:
import RatingPicker from "@/src/components/RatingPicker.jsx";
O app usa o símbolo @
para evitar caminhos de importação relativos pesados e é possível graças a aliases de caminho.
APIs específicas do Firebase
Todo o código da API do Firebase é encapsulado no diretório src/lib/firebase
. Os componentes individuais do React importam as funções encapsuladas do diretório src/lib/firebase
, em vez de importar as funções do Firebase diretamente.
Dados simulados
Os dados simulados de restaurantes e avaliações estão no arquivo src/lib/randomData.js
. Os dados desse arquivo são reunidos no código do arquivo src/lib/fakeRestaurants.js
.
5. Criar um back-end do App Hosting
Nesta seção, você vai configurar um back-end do App Hosting para monitorar uma ramificação no seu repositório git.
Ao final desta seção, você terá um back-end do App Hosting conectado ao seu repositório no GitHub, que vai criar e lançar automaticamente uma nova versão do app sempre que você enviar um novo commit para a ramificação main
.
Implantar regras de segurança
O código já tem conjuntos de regras de segurança para o Firestore e o Cloud Storage para Firebase. Após a implantação das regras de segurança, os dados no banco de dados e no bucket ficam mais bem protegidos contra uso indevido.
- No terminal, configure a CLI para usar o projeto do Firebase que você criou anteriormente:
Quando um alias for solicitado, insirafirebase use --add
friendlyeats-codelab
. - Para implantar essas regras de segurança, execute este comando no terminal:
firebase deploy --only firestore:rules,storage
- Se a mensagem
"Cloud Storage for Firebase needs an IAM Role to use cross-service rules. Grant the new role?"
aparecer, pressioneEnter
para selecionar Sim.
Adicionar a configuração do Firebase ao código do app da Web
- No console do Firebase, acesse as Configurações do projeto.
- No painel Configuração e configuração do SDK, clique em "Adicionar app" e no ícone de colchetes de código
para registrar um novo app da Web.
- No final do fluxo de criação do app da Web, copie a variável
firebaseConfig
, as propriedades e os valores dela. - Abra o arquivo
apphosting.yaml
no editor de código e preencha os valores das variáveis de ambiente com os valores de configuração do console do Firebase. - No arquivo, substitua as propriedades atuais pelas que você copiou.
- Salve o arquivo.
Criar um back-end
- Acesse a página "App Hosting" no console do Firebase:
- Clique em "Começar" para iniciar o fluxo de criação do back-end. Configure o back-end da seguinte maneira:
- Siga as instruções da primeira etapa para conectar o repositório do GitHub criado anteriormente.
- Defina as configurações de implantação:
- Mantenha o diretório raiz como
/
- Defina a ramificação ativa como
main
- Ativar os lançamentos automáticos
- Mantenha o diretório raiz como
- Nomeie o back-end como
friendlyeats-codelab
. - Em "Criar ou associar um app da Web do Firebase", escolha o app da Web que você configurou anteriormente no menu suspenso "Selecionar um app da Web atual do Firebase".
- Clique em "Concluir e implantar". Depois de um momento, você vai ser direcionado a uma nova página com o status do seu novo back-end do App Hosting.
- Quando o lançamento for concluído, clique no seu domínio sem custo financeiro em "domains". Isso pode levar alguns minutos para começar a funcionar devido à propagação do DNS.
Você implantou o app da Web inicial. Sempre que você enviar uma nova confirmação para a ramificação main
do repositório do GitHub, um novo build e lançamento serão iniciados no console do Firebase, e seu site será atualizado automaticamente após a conclusão do lançamento.
6. Adicionar autenticação ao app da Web
Nesta seção, você vai adicionar uma autenticação ao app da Web para fazer login nele.
Implementar as funções de login e logout
- No arquivo
src/lib/firebase/auth.js
, substitua as funçõesonAuthStateChanged
,signInWithGoogle
esignOut
pelo seguinte código:
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);
}
}
Esse código usa as seguintes APIs do Firebase:
API Firebase | Descrição |
Cria uma instância do provedor de autenticação do Google. | |
Inicia um fluxo de autenticação baseado em caixa de diálogo. | |
Desconecta o usuário. |
No arquivo src/components/Header.jsx
, o código já invoca as funções signInWithGoogle
e signOut
.
- Crie uma confirmação com a mensagem "Adicionar autenticação do Google" e envie para o repositório do GitHub. 1. Abra a página "App Hosting" no Console do Firebase e aguarde a conclusão do novo lançamento.
- No app da Web, atualize a página e clique em Fazer login com o Google. O app da Web não é atualizado, então não está claro se o login foi bem-sucedido.
Enviar o estado de autenticação ao servidor
Para transmitir o estado de autenticação ao servidor, vamos usar um service worker. Substitua as funções fetchWithFirebaseHeaders
e getAuthIdToken
pelo seguinte código:
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);
}
Ler o estado de autenticação no servidor
Vamos usar o FirebaseServerApp para espelhar o estado de autenticação do cliente no servidor.
Abra src/lib/firebase/serverApp.js
e substitua a função 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 };
}
Receber notificações sobre mudanças na autenticação
Para receber as mudanças na autenticação, siga estas etapas:
- Navegue até o arquivo
src/components/Header.jsx
. - Substitua a função
useUserSession
por este código:
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;
}
Esse código usa um hook de estado do React para atualizar o usuário quando a função onAuthStateChanged
especifica que há uma mudança no estado de autenticação.
Verificar mudanças
O layout raiz no arquivo src/app/layout.js
renderiza o cabeçalho e transmite o usuário, se disponível, como uma propriedade.
<Header initialUser={currentUser?.toJSON()} />
Isso significa que o componente <Header>
renderiza dados do usuário, se disponíveis, durante o ambiente de execução do servidor. Se houver alguma atualização de autenticação durante o ciclo de vida da página após o carregamento inicial da página, ela será processada pelo gerenciador onAuthStateChanged
.
Agora é hora de lançar um novo build e verificar o que você criou.
- Crie uma confirmação com a mensagem "Mostrar estado de login" e envie para seu repositório do GitHub.
- Abra a página "Hospedagem de apps" no Console do Firebase e aguarde a conclusão do novo lançamento.
- Verifique o novo comportamento de autenticação:
- No navegador, atualize o app da Web. Seu nome de exibição aparece no cabeçalho.
- Saia e faça login novamente. A página é atualizada em tempo real sem ser atualizada. Repita essa etapa com diferentes usuários.
- Opcional: clique com o botão direito do mouse no app da Web, selecione Conferir código-fonte da página e pesquise o nome de exibição. Ele aparece no código-fonte HTML bruto retornado do servidor.
7. Acessar informações do restaurante
O app da Web inclui dados simulados de restaurantes e avaliações.
Adicionar um ou mais restaurantes
Para inserir dados simulados de restaurantes no seu banco de dados local do Cloud Firestore, siga estas etapas:
- No app da Web, selecione > Adicionar restaurantes de exemplo.
- No console do Firebase, na página Banco de dados do Firestore, selecione restaurantes. Você encontrará os documentos de nível superior na coleção do restaurante. Cada um deles representa um restaurante.
- Clique em alguns documentos para explorar as propriedades de um documento de restaurante.
Mostrar a lista de restaurantes
Seu banco de dados do Cloud Firestore agora tem restaurantes que o app da Web Next.js pode exibir.
Para definir o código de busca de dados, siga estas etapas:
- No arquivo
src/app/page.js
, encontre o componente de servidor<Home />
e revise a chamada para a funçãogetRestaurants
, que recupera uma lista de restaurantes no ambiente de execução do servidor. Implemente a funçãogetRestaurants
nas etapas a seguir. - No arquivo
src/lib/firebase/firestore.js
, substitua as funçõesapplyQueryFilters
egetRestaurants
pelo seguinte código:
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(),
};
});
}
- Crie um commit com a mensagem "Ler a lista de restaurantes do Firestore" e envie por push ao repositório do GitHub.
- Abra a página "App Hosting" no Console do Firebase e aguarde a conclusão do novo lançamento.
- No app da Web, atualize a página. As imagens de restaurantes aparecem como blocos na página.
Verificar se as listas do restaurante são carregadas no ambiente de execução do servidor
Usando o framework Next.js, pode não ser óbvio quando os dados são carregados no ambiente de execução do servidor ou do lado do cliente.
Para verificar se as fichas de restaurantes são carregadas no ambiente de execução do servidor, siga estas etapas:
- No app da Web, abra o DevTools e desative o JavaScript.
- Atualize o app da Web. As listas dos restaurantes ainda são carregadas. As informações do restaurante são retornadas na resposta do servidor. Quando o JavaScript está ativado, as informações do restaurante são hidratadas com o código JavaScript do lado do cliente.
- No DevTools, reative o JavaScript.
Detectar atualizações de restaurantes com listeners de snapshots do Cloud Firestore
Na seção anterior, você soube como o conjunto inicial de restaurantes foi carregado do arquivo src/app/page.js
. O arquivo src/app/page.js
é um componente do servidor e é renderizado no servidor, incluindo o código de busca de dados do Firebase.
O arquivo src/components/RestaurantListings.jsx
é um componente do cliente e pode ser configurado para hidratar a marcação renderizada pelo servidor.
Se quiser configurar o arquivo src/components/RestaurantListings.jsx
para hidratar a marcação renderizada pelo servidor, siga estas etapas:
- No arquivo
src/components/RestaurantListings.jsx
, observe o seguinte código, que já está escrito para você:
useEffect(() => {
const unsubscribe = getRestaurantsSnapshot(data => {
setRestaurants(data);
}, filters);
return () => {
unsubscribe();
};
}, [filters]);
Esse código invoca a função getRestaurantsSnapshot()
, que é semelhante à função getRestaurants()
implementada em uma etapa anterior. No entanto, essa função de snapshot fornece um mecanismo de callback para que o callback seja invocado sempre que uma mudança for feita na coleção do restaurante.
- No arquivo
src/lib/firebase/firestore.js
, substitua a funçãogetRestaurantsSnapshot()
pelo seguinte código:
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;
}
As alterações feitas na página do banco de dados do Firestore agora são refletidas no app da Web em tempo real.
- Crie uma confirmação com a mensagem "Listen for real-time restaurant updates" e envie para o repositório do GitHub.
- Abra a página "App Hosting" no Console do Firebase e aguarde a conclusão do novo lançamento.
- No app da Web, selecione > Adicionar restaurantes de exemplo. Se a função de snapshot for implementada corretamente, os restaurantes vão aparecer em tempo real, sem precisar atualizar a página.
8. Salvar avaliações enviadas pelos usuários a partir do app da Web
- No arquivo
src/lib/firebase/firestore.js
, substitua a funçãoupdateWithRating()
pelo seguinte código:
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()),
});
};
Esse código insere um novo documento do Firestore que representa a nova avaliação. O código também atualiza o documento atual do Firestore que representa o restaurante com números atualizados para o número de avaliações e a classificação média calculada.
- Substitua a função
addReviewToRestaurant()
por este código:
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;
}
}
Implementar uma ação do servidor Next.js
Uma ação do servidor Next.js oferece uma API conveniente para acessar dados de formulário, como data.get("text")
, para acessar o valor de texto do payload de envio de formulário.
Se quiser usar uma ação do servidor do Next.js para processar o envio do formulário de avaliação, siga estas etapas:
- No arquivo
src/components/ReviewDialog.jsx
, encontre o atributoaction
no elemento<form>
.
<form action={handleReviewFormSubmission}>
O valor do atributo action
se refere a uma função que você vai implementar na próxima etapa.
- No arquivo
src/app/actions.js
, substitua a funçãohandleReviewFormSubmission()
pelo seguinte código:
// 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"),
});
}
Adicionar avaliações de um restaurante
Você implementou a compatibilidade com envios de avaliação, então agora pode verificar se as avaliações foram inseridas corretamente no Cloud Firestore.
Para adicionar uma avaliação e verificar se ela está inserida no Cloud Firestore, siga estas etapas:
- Crie uma confirmação com a mensagem "Permitir que os usuários enviem avaliações de restaurantes" e a envie ao seu repositório do GitHub.
- Abra a página "App Hosting" no Console do Firebase e aguarde a conclusão do novo lançamento.
- Atualize o app da Web e selecione um restaurante na página inicial.
- Na página do restaurante, clique em .
- Selecione uma nota.
- Escreva uma avaliação.
- Clique em Enviar. Sua avaliação vai aparecer no topo da lista.
- No Cloud Firestore, pesquise o documento do restaurante que você avaliou no painel Adicionar documento e selecione-o.
- No painel Iniciar coleção, selecione classificações.
- No painel Adicionar documento, encontre o documento da sua avaliação para verificar se ele foi inserido conforme o esperado.
9. Salvar arquivos enviados pelo usuário no app da Web
Nesta seção, você vai adicionar uma funcionalidade para substituir a imagem associada a um restaurante quando estiver conectado. Você faz upload da imagem para o Firebase Storage e atualiza o URL da imagem no documento do Cloud Firestore que representa o restaurante.
Para salvar arquivos enviados por usuários no app da Web, siga estas etapas:
- No arquivo
src/components/Restaurant.jsx
, observe o código executado quando o usuário faz upload de um arquivo:
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 });
}
Nenhuma mudança é necessária, mas você vai implementar o comportamento da função updateRestaurantImage()
nas etapas a seguir.
- No arquivo
src/lib/firebase/storage.js
, substitua as funçõesupdateRestaurantImage()
euploadImage()
pelo seguinte código:
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);
}
A função updateRestaurantImageReference()
já foi implementada para você. Essa função atualiza um documento de restaurante no Cloud Firestore com um URL de imagem atualizado.
Verificar a funcionalidade de upload de imagem
Para verificar se o upload da imagem é o esperado, siga estas etapas:
- Crie uma confirmação com a mensagem "Permitir que os usuários alterem a foto de cada restaurante" e a envie ao seu repositório do GitHub.
- Abra a página "Hospedagem de apps" no Console do Firebase e aguarde a conclusão do novo lançamento.
- No app da Web, verifique se você fez login e selecione um restaurante.
- Clique em e faça upload de uma imagem do seu sistema de arquivos. A imagem sai do ambiente local e é carregada no Cloud Storage. A imagem aparece imediatamente após o upload.
- Acesse o Cloud Storage para Firebase.
- Navegue até a pasta que representa o restaurante. A imagem que você enviou existe na pasta.
10. Resuma avaliações de restaurantes com IA generativa
Nesta seção, você vai adicionar um recurso de resumo de avaliações para que o usuário entenda rapidamente o que todos pensam sobre um restaurante sem ter que ler cada avaliação.
Armazenar uma chave de API Gemini no Cloud Secret Manager
- Para usar a API Gemini, você precisa de uma chave de API. Crie uma chave no Google AI Studio.
- O App Hosting se integra ao Cloud Secret Manager para permitir que você armazene valores sensíveis, como chaves de API, com segurança:
- Em um terminal, execute o comando para criar um novo secret:
firebase apphosting:secrets:set gemini-api-key
- Quando o valor secreto for solicitado, copie e cole sua chave da API Gemini no Google AI Studio.
- Quando for perguntado se o novo secret precisa ser adicionado a
apphosting.yaml
, digiteY
para aceitar.
Agora, sua chave de API Gemini é armazenada com segurança no Cloud Secret Manager e pode ser acessada pelo back-end do App Engine.
Implementar o componente de resumo da avaliação
- Em
src/components/Reviews/ReviewSummary.jsx
, substitua a funçãoGeminiSummary
pelo seguinte código: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>; } }
- Crie uma confirmação com a mensagem "Use AI to summarize reviews" e envie para o repositório do GitHub.
- Abra a página "Hospedagem de apps" no Console do Firebase e aguarde a conclusão do novo lançamento.
- Abra a página de um restaurante. Na parte superior, você verá um resumo de uma frase de todos os comentários da página.
- Adicione uma nova avaliação e atualize a página. Você vai notar uma mudança no resumo.
11. Conclusão
Parabéns! Você aprendeu a usar o Firebase para adicionar recursos e funcionalidades a um app Next.js. Especificamente, você usou o seguinte:
- Firebase App Hosting para criar e implantar automaticamente seu código Next.js sempre que você enviar por push para uma ramificação configurada.
- Firebase Authentication para ativar a funcionalidade de login e logout.
- Cloud Firestore para dados de restaurantes e dados de avaliações de restaurantes.
- Cloud Storage para Firebase, para imagens de restaurantes.