Carregando usuário logado do cookie no CrazyStack Next.js
Tags: javascript, react, nextjs, braziliandevs
Published: 2023-03-10 15:15:21

Nesta aula, você aprenderá como carregar os dados de um usuário logado a partir de um cookie usando a biblioteca "nookies".

O vídeo dessa aula está publicada no bootcamp CrazyStack, se você ainda não garantiu sua vaga clique [aqui](https://www.udemy.com/course/nextjs-avancado-atomic-design/?referralCode=931E9B885B9F032D1CB1)

A ideia é salvar o estado de autenticação do usuário no cookie ao fazer o login, e carregá-lo na próxima vez que o usuário acessar o site. Isso é importante para que o usuário não precise fazer login novamente toda vez que recarregar a página.

A biblioteca "nookies" é uma solução fácil de usar para gerenciar cookies em aplicações Next.js. Ela fornece uma maneira simples de ler e escrever cookies em sua aplicação, além de permitir que você configure a validade de um cookie e outras opções importantes.

A aula começará explicando como instalar e configurar a biblioteca "nookies". Em seguida, você aprenderá como usar o hook "useCookies" para ler o cookie de autenticação do usuário e verificar se ele está logado.

Finalmente, você verá como salvar o estado de autenticação do usuário no cookie ao fazer login e como excluir o cookie ao fazer logout.

Com essa aula, você terá uma solução completa e confiável para gerenciar o estado de autenticação de um usuário em sua aplicação Next.js.
```tsx
import { createContext, useEffect, useContext, ReactNode, useState, useMemo } from "react";
import { setCookie, destroyCookie, parseCookies } from "nookies";
import Router from "next/router";
import { api } from "shared/api";
type User = {
  email: string;
  role: string;
  _id: string;
};
type AuthProviderProps = {
  children: ReactNode;
};
type LoginCredentials = {
  email: string;
  password: string;
};
type AuthContextData = {
  login(credentials: LoginCredentials): Promise<void>;
  isAuthenticated: boolean;
  user: User | null;
};
const AuthContext = createContext({} as AuthContextData);

export function AuthProvider({ children }: AuthProviderProps) {
  const [user, setUser] = useState<User | null>(null);
  const isAuthenticated = !!user;
  const parseJSON = (json: string) => {
    try {
      return JSON.parse(json);
    } catch (error) {
      return null;
    }
  };
  useEffect(() => {
    const {
      "belezixadmin.user": userComingFromCookie,
      "belezixadmin.refreshToken": refreshToken = null,
    } = parseCookies();
    const parsedUser = parseJSON(userComingFromCookie);
    if (parsedUser && refreshToken) {
      setUser(parsedUser);
    } else {
      signOut();
    }
  }, []);

  const login = async ({ email, password }: LoginCredentials) => {
    try {
      const response = await api.post("auth/login", {
        email,
        password,
        passwordConfirmation: password,
      });
      const { accessToken: token, refreshToken, user: userComing } = response?.data || {};
      setCookie(undefined, "belezixadmin.token", token, {
        maxAge: 60 * 60 * 24 * 30,
        path: "/",
      });
      setCookie(undefined, "belezixadmin.refreshToken", refreshToken, {
        maxAge: 60 * 60 * 24 * 30,
        path: "/",
      });
      setCookie(undefined, "belezixadmin.user", JSON.stringify(userComing), {
        maxAge: 60 * 60 * 24 * 30,
        path: "/",
      });
      setUser(userComing);
      api.defaults.timeout = 5000;
      api.defaults.headers["Authorization"] = `Bearer ${token}`;
      Router.push("/");
    } catch (error) {
      alert("erro no servidor");
    }
  };
  const contextValue = useMemo(
    () => ({ login, isAuthenticated, user }),
    [isAuthenticated, user]
  );
  return <AuthContext.Provider value={contextValue}>{children}</AuthContext.Provider>;
}
export const useAuth = () => useContext(AuthContext);

export function signOut() {
  destroyCookie(undefined, "belezixadmin.token");
  destroyCookie(undefined, "belezixadmin.refreshToken");
  destroyCookie(undefined, "belezixadmin.user");
  Router.push("/");
} 
``` 
Este código cria um contexto de autenticação para uma aplicação React, com as funcionalidades de login e logout, usando cookies para armazenar informações do usuário logado.

O contexto é criado usando o método `createContext` do React, que permite compartilhar informações entre componentes sem precisar passar props em cada nível da árvore de componentes. Neste caso, o contexto é inicializado com um objeto vazio `{} as AuthContextData`.

A classe `AuthProvider` é usada para fornecer o contexto em toda a aplicação, e sua propriedade `children` representa os componentes filhos. Ela contém dois estados: `user` e `isAuthenticated`. O estado `user` armazena informações do usuário logado, enquanto `isAuthenticated` é uma variável booleana que indica se há um usuário logado.

O `useEffect` é executado somente uma vez, na primeira renderização da página, e seu objetivo é verificar se há um usuário e refreshToken nos cookies. Se houver, o usuário é recuperado e o estado `user` é atualizado. Caso contrário, a função `signOut` é executada.

A função `login` é responsável por fazer a requisição à API para realizar o login, recebendo como argumento as credenciais do usuário (email e senha). Se a requisição for bem-sucedida, o token de acesso, o token de atualização e as informações do usuário são armazenados nos cookies e o estado `user` é atualizado. Além disso, o header da requisição padrão é atualizado para incluir o token de acesso. Por fim, o usuário é redirecionado para a página inicial da aplicação.

A função `signOut` é responsável por destruir todos os cookies relacionados ao usuário logado e redirecionar o usuário para a página de login.

Por fim, a função `useAuth` é usada para permitir que outros componentes possam obter acesso ao contexto de autenticação.

Em resumo, este código cria um contexto de autenticação completo, com funções de login e logout, que é fornecido em toda a aplicação e permite aos componentes obter informações sobre o usuário logado e realizar ações de autenticação.