Componente genérico de Detalhes de Categoria usando Chakra UI no CrazyStack Next.js
Tags: javascript, braziliandevs, reactnative, react
Published: 2023-06-26 14:27:50

Bem-vindo à aula "Componente Genérico de Detalhes de Categoria usando Chakra UI e Atomic Design". Nesta aula, exploraremos como criar um componente genérico de detalhes de categoria, que pode ser facilmente reutilizado em diferentes projetos de interface do usuário. Usando o poder do Chakra UI, um conjunto de ferramentas de design de interface do usuário, e o Atomic Design, um método para criar hierarquias de componentes de interface do usuário, criaremos um componente versátil e flexível.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y3ex37tagrz5niffljhz.png)
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)

O Atomic Design permite que criemos componentes mais complexos a partir de componentes menores e mais simples, como átomos, moléculas e organismos. Ao utilizar essa abordagem, podemos criar componentes reutilizáveis e escaláveis ​​que podem ser facilmente modificados e adaptados a diferentes necessidades de design. Combinado com o Chakra UI, que fornece uma ampla variedade de componentes pré-projetados e personalizáveis, podemos criar rapidamente interfaces de usuário atraentes e funcionais.

Ao final desta aula, você terá uma compreensão clara de como criar um componente genérico de detalhes de categoria usando o Chakra UI e o Atomic Design. Você também poderá aplicar esse conhecimento para criar outros componentes reutilizáveis, escaláveis e personalizáveis para suas próprias interfaces de usuário. Vamos começar!
 
## GenericDetailsItem (Molécula)
Este arquivo implementa uma molécula que pode ser usada em diferentes partes do projeto para exibir detalhes genéricos de um item. Ele usa o sistema de grid do Chakra UI para exibir cada detalhe do item. Os detalhes que são exibidos são determinados por meio de uma lista de campos que são passados como props para a molécula. A molécula é altamente reutilizável, uma vez que não é específica para nenhum item em particular, tornando-se uma boa implementação do conceito de Atomic Design.
```tsx
import { Grid, GridItem, Text } from "@chakra-ui/react";
import React from "react";
interface GenericDetailsItemProps {
  item: any;
  fields: any[];
}

export const GenericDetailsItem: React.FC<GenericDetailsItemProps> = ({
  item,
  fields,
}) => {
  return (
    <Grid
      templateRows="repeat(2, 1fr)"
      templateColumns={["repeat(1,1fr)", "repeat(2,1f)", "repeat(3,1fr)"]}
      gap={2}
    >
      {!!item &&
        fields?.map?.((field, index) => (
          <React.Fragment key={`${Math.random() * 10}-${index}`}>
            {!!item?.[field?.id] && (
              <GridItem w="100%" p={["0", "0", "0", "4"]}>
                <Text>{field?.label}:&nbsp;</Text>
                <Text>{item?.[field?.id]}</Text>
              </GridItem>
            )}
          </React.Fragment>
        ))}
    </Grid>
  );
};
```
O código acima é um componente React chamado `GenericDetailsItem`, que é uma molécula que pode ser reutilizada em diferentes partes de um projeto para exibir informações de um item em um formato de tabela. O componente usa o pacote `@chakra-ui/react` para estilização.

O componente recebe duas propriedades:

* `item`: um objeto contendo as informações do item a ser exibido.
* `fields`: uma matriz de objetos que descreve os campos do item que devem ser exibidos. Cada objeto contém uma propriedade `id`, que é a chave do campo no objeto `item`, e uma propriedade `label`, que é a etiqueta que deve ser exibida para o campo.

O componente é composto por um `Grid`, que é uma grade flexível usada para exibir as informações do item em colunas. O `Grid` tem três propriedades:

* `templateRows`: define o número de linhas e sua altura na grade.
* `templateColumns`: define o número de colunas e sua largura na grade. Para diferentes tamanhos de tela, o número de colunas é ajustado automaticamente usando a sintaxe de matriz responsiva do Chakra UI. Por exemplo, para telas pequenas, o `templateColumns` tem uma única coluna (`repeat(1, 1fr)`), enquanto para telas maiores, ele tem três colunas (`repeat(3, 1fr)`).
* `gap`: define o espaçamento entre as células da grade.

O componente também usa a função `.map` para percorrer a matriz `fields` e gerar um conjunto de `GridItem` para cada campo. Cada `GridItem` contém um rótulo `Text` e o valor correspondente do item, que são exibidos em colunas adjacentes. O `GridItem` tem uma propriedade `w` que define a largura da célula. Para diferentes tamanhos de tela, essa largura é ajustada automaticamente usando a sintaxe responsiva do Chakra UI.

Por fim, o componente usa a sintaxe condicional `!!` para garantir que o campo seja exibido apenas se o item tiver um valor para esse campo. Se o item não tiver um valor para o campo, o campo não será exibido.
## CategoryDetails
Este arquivo implementa um organismo que exibe os detalhes de uma categoria específica. Ele usa a molécula GenericDetailsItem para exibir os detalhes da categoria e também tem um botão de edição que leva o usuário para a página de edição da categoria. O organismo é específico para a exibição de detalhes de uma categoria e usa a molécula como seu componente genérico de detalhes.
```tsx
import { Flex, GenericDetailsItem, Text, Button } from "shared/ui";
import { Heading, Icon } from "@chakra-ui/react";
import NextLink from "next/link";
import { RiAddLine } from "react-icons/ri";
import { CategoryProps } from "../category.model";
type CategoryDetailsProps = {
  category: CategoryProps;
};

export const CategoryDetails = ({ category }: CategoryDetailsProps) => {
  return (
    <>
      <Flex mb="8" justify="space-between" align="center">
        <Heading size="lg" fontWeight={"normal"}>
          Categoria {category?.name}
        </Heading>
        <NextLink passHref href={`/categorys/edit/${category?._id}`}>
          <Button
            size="sm"
            fontSize={"sm"}
            colorScheme="green"
            leftIcon={<Icon fontSize="20" as={RiAddLine} />}
          >
            Editar
          </Button>
        </NextLink>
      </Flex>
      <GenericDetailsItem
        item={category}
        fields={[
          { id: "name", label: "Nome" },
          { id: "createdById", label: "Id do criador" },
          { id: "createdAt", label: "Data de criação" },
        ]}
      />
    </>
  );
};
```
O código acima define um componente React chamado CategoryDetails, que é responsável por exibir os detalhes de uma categoria específica. Ele recebe uma propriedade chamada "category", que é um objeto que contém informações sobre a categoria a ser exibida. O componente é composto por dois elementos principais, um componente Flex e um componente GenericDetailsItem.

O componente Flex é responsável por exibir o título da página e um botão de edição. O título é definido como "Categoria" seguido pelo nome da categoria, que é extraído da propriedade "category" usando a notação de ponto. O botão de edição é um componente NextLink que leva o usuário para a página de edição da categoria.

O componente GenericDetailsItem é responsável por exibir os detalhes da categoria, como o nome, o ID do criador e a data de criação. Ele recebe duas propriedades, "item" e "fields". A propriedade "item" é definida como a propriedade "category" que foi passada para o componente CategoryDetails. A propriedade "fields" é um array de objetos que descreve os campos que devem ser exibidos na lista de detalhes da categoria.

O componente GenericDetailsItem usa o componente Grid do Chakra UI para exibir os campos de detalhes da categoria em uma grade. Ele mapeia os campos definidos na propriedade "fields" e usa a notação de ponto para obter os valores correspondentes do objeto "category". Se o valor do campo não for nulo, ele é exibido usando o componente GridItem, que contém um componente Text para o rótulo do campo e outro componente Text para o valor do campo. Se houver mais de um campo, eles serão exibidos em colunas adicionais na grade.

Em resumo, o componente CategoryDetails é responsável por exibir os detalhes de uma categoria, incluindo o título da página e um botão de edição, juntamente com os detalhes da categoria em si. O componente GenericDetailsItem é usado para exibir os campos de detalhes da categoria em uma grade. Juntos, esses componentes fornecem uma visualização clara e organizada dos detalhes da categoria.
## CategoryDetailsPage
Este arquivo implementa uma página que exibe os detalhes de uma categoria. Ele usa o organismo CategoryDetails e envolve-o em um componente de caixa que fornece estilos e espaçamento para a página. A página também usa o componente Head para definir o título e a descrição da página. A página é um exemplo de como os componentes do Atomic Design podem ser usados para criar páginas completas.
```tsx
import { Box, Head } from "shared/ui";
import { CategoryDetails } from "entidades/category/details";
import { CategoryProps } from "entidades/category";
type CategoryDetailsProps = {
  data: CategoryProps;
  id: string;
};
export const CategoryDetailsPage = ({ data, id }: CategoryDetailsProps) => {
  const props = { category: data };
  return (
    <>
      <Head
        title={"Belezix Admin | Categorias"}
        description="Página de detalhes de categorias do painel de Admin Belezix"
      />
      <Box flex="1" borderRadius={8} bg="purple.800" p="8">
        <CategoryDetails {...props} />
      </Box>
    </>
  );
};
```
Esse é um código para a página de detalhes de uma categoria. A página recebe duas propriedades: `data` e `id`. A propriedade `data` contém todas as informações da categoria, enquanto a propriedade `id` é apenas o identificador da categoria.

Dentro da função `CategoryDetailsPage`, é definido um objeto `props` que contém a propriedade `category`, que é igual a `data`. Em seguida, é renderizada uma caixa (`Box`) que contém o componente `CategoryDetails` passando as propriedades `category` e `props`. O componente `Head` é usado para definir informações de SEO da página, como o título e a descrição.

Basicamente, a página de detalhes de categoria é exibida com a categoria passada como propriedade para o componente `CategoryDetails`, que, por sua vez, usa o componente `GenericDetailsItem` para exibir os detalhes da categoria de forma organizada em uma tabela.
## Category API
Este arquivo contém um serviço que faz uma chamada à API para obter os detalhes de uma categoria específica. Ele usa o cliente HTTP setupAPIClient para fazer a chamada e retorna os detalhes da categoria como um objeto CategoryProps. Se houver um erro ao fazer a chamada à API, ele retorna null. O serviço é responsável por buscar os dados da API para fornecer aos componentes da interface do usuário.
```tsx
export const getCategoryById = async (
  id: string,
  ctx: any
): Promise<CategoryProps | null> => {
  try {
    const { data } = await setupAPIClient(ctx).get("/category/load", {
      params: { _id: id },
    });
    if (!data) {
      return null;
    }
    return categoryModel(data).format();
  } catch (error) {
    return null;
  }
};
```
Esse é um código que exporta uma função chamada `getCategoryById`. Essa função recebe dois argumentos: `id` e `ctx`. O primeiro é uma string que representa o id da categoria que se deseja buscar. O segundo é um objeto de contexto que é utilizado para realizar a requisição à API.

Dentro da função, há uma chamada à função `setupAPIClient`, que é responsável por configurar o cliente HTTP utilizado para realizar a requisição. Essa função utiliza o objeto de contexto para adicionar o token de autenticação à requisição.

Em seguida, é realizada uma requisição GET para o endpoint "/category/load", passando o id da categoria como parâmetro na URL. Caso a requisição seja bem sucedida, o objeto `data` retornado é utilizado para criar uma instância de `categoryModel`, que é responsável por formatar os dados recebidos para um formato mais adequado.

Se a requisição falhar ou não retornar nenhum dado, a função retorna `null`.

Em resumo, esse código é responsável por buscar uma categoria específica na API a partir do seu id, formatar os dados recebidos e retornar um objeto que representa a categoria buscada.
## details/[id]
Este arquivo é uma página do Next.js que usa a função getServerSideProps para obter os detalhes de uma categoria a partir da API e passá-los para o componente CategoryDetailsPage. A função withSSRAuth é usada para garantir que o usuário esteja autenticado antes de acessar a página. Se o ID fornecido na URL não for uma string válida, a página retornará um erro 404. A página é um exemplo de como os componentes do Atomic Design podem ser usados em conjunto com o Next.js para criar páginas dinâmicas e autenticadas.
```tsx
import { CategoryDetailsPage } from "screens/category/details/CategoryDetailsPage";
import { getCategoryById } from "entidades/category/category.api";
import { GetServerSideProps } from "next";
import { withSSRAuth } from "shared/libs/utils";
export const getServerSideProps: GetServerSideProps = withSSRAuth(async (context) => {
  const id = context?.query?.id;
  if (!id || typeof id !== "string") {
    return {
      notFound: true,
    };
  }
  const data = await getCategoryById(id, context);
  return {
    props: {
      data,
      id,
    },
  };
});
export default CategoryDetailsPage;
```
Esse código faz parte da página de detalhes de categoria da aplicação. Quando o usuário acessa a página `/details/[id]`, o servidor executa a função `getServerSideProps`, que busca os dados da categoria correspondente ao `id` passado na URL.

A função `getServerSideProps` usa o utilitário `withSSRAuth` para garantir que o usuário esteja autenticado antes de carregar a página. Caso contrário, ele é redirecionado para a página de login.

Se o `id` não for uma string ou não existir, a página retorna o status 404 (não encontrado).

Se tudo estiver correto, a função `getCategoryById` é chamada para buscar os dados da categoria correspondente ao `id` passado. Se a busca for bem-sucedida, os dados são retornados como propriedades da página `CategoryDetailsPage`. Caso contrário, a propriedade `data` é nula e a página é carregada sem as informações da categoria.

## Conclusão
Nesta aula, aprendemos sobre a criação de componentes genéricos de detalhes de categoria usando Chakra UI e Atomic Design. Vimos como criar moléculas, que são componentes compostos de átomos, e como usar essas moléculas para construir componentes maiores, como a página de detalhes de categoria.

Além disso, aprendemos sobre a organização do código em módulos e como o Atomic Design pode ajudar a criar componentes mais reutilizáveis e escaláveis. Também vimos exemplos de como essa organização pode ser aplicada em um projeto real.

Por fim, vimos como usar a API do Next.js para buscar dados do servidor e como usar a autenticação de rota para controlar o acesso a esses dados. Esperamos que esses conceitos tenham sido úteis e ajudado a entender como criar componentes reutilizáveis, escaláveis e bem organizados em seus projetos.