Pular para o conteúdo principal

Layout Service

Gerencia operações relacionadas aos layouts de formulários, permitindo buscar configurações de layout por entidade.

Visão Geral

O LayoutService é responsável por:

  • Buscar layouts de formulários da API remota
  • Filtrar layouts por entidade (Cliente, Produto, Cabeçalho, Contato)
  • Fornecer estruturas de layout para renderização dinâmica de formulários

Os layouts definem quais campos devem ser exibidos em formulários para diferentes entidades do sistema, permitindo customização por organização.

Localização: services/layout/layout.service.ts

Endpoints Utilizados

Base URL

Todos os endpoints são relativos à base URL configurada em services/api.service.ts

Métodos

fetchRemote(params)

Busca layouts remotamente com opções de filtro e paginação.

Endpoint: GET /layout

Parâmetros:

type FetchLayoutParams = {
page?: number; // Número da página (padrão: 0)
size?: number; // Quantidade de itens por página (padrão: 999)
dataHora?: string;
entity?: LayoutEntity; // Filtro por entidade
};

type LayoutEntity = "Cliente" | "Produto" | "Cabeçalho" | "Contato";

Query Params enviados:

  • page: número da página
  • size: tamanho da página
  • dataHora: timestamp (opcional)
  • entity: entidade para filtrar (opcional)

Retorno:

Promise<Layout[]>;

Exemplo de uso:

import { layoutService } from "@/services/layout/layout.instance";

// Buscar todos os layouts
const allLayouts = await layoutService.fetchRemote();

// Buscar layouts apenas para Cliente
const clientLayouts = await layoutService.fetchRemote({
entity: "Cliente",
});

// Buscar layouts com paginação
const layoutsPage = await layoutService.fetchRemote({
page: 0,
size: 50,
entity: "Produto",
});

Tratamento de erros:

  • Lança Error se o status da resposta não for 2xx
  • Mensagem: LayoutService.fetchRemote failed: {status}

Estruturas de Dados

Interface Layout

type Layout = {
id: string;
idOrganization: string;
nome: string;
entidade: LayoutEntity;
organization: string;
layout: FieldLayout[];
};

Type LayoutEntity

type LayoutEntity = "Cliente" | "Produto" | "Cabeçalho" | "Contato";

Define as entidades suportadas pelo sistema de layouts.

Interface FieldLayout

Os layouts contêm um array de FieldLayout que define cada campo:

type FieldLayout = {
fieldLayoutId: string;
requerido: "S" | "N";
editavel: "S" | "N";
visivel: "S" | "N";
valorPadrao: string;
aba: string;
field: FieldBasic;
layout: LayoutBasic;
Opcoes: Option[];
};

Ver Field Layout Service para detalhes completos.


Componentes Relacionados

filterLayoutByEntity Helper

Função utilitária que filtra layouts por entidade.

Localização: helpers/fiterLayoutByEntity.ts

function filterLayoutByEntity(layout: Layout[], entity: string): Layout[];

Nota: Essa função é usada internamente porque a API atualmente não filtra corretamente por entidade. Quando o backend for corrigido, essa filtragem pode ser removida.

buildQueryParams Helper

Função utilitária que converte objeto de parâmetros em URLSearchParams.

Localização: helpers/buildQueryParams.ts

PageResponse Interface

Interface compartilhada para respostas paginadas.

Localização: services/client/client.service.ts

interface PageResponse<T> {
content: T[]; // Array de itens da página
page?: number; // Número da página atual
size?: number; // Tamanho da página
totalPages?: number; // Total de páginas
totalElements?: number; // Total de elementos
}

Fluxo de Integração

Fluxo de Busca de Layouts

1. App precisa renderizar formulário de Cliente
2. App chama layoutService.fetchRemote({ entity: 'Cliente' })
3. GET /layout é enviado com query params
4. API retorna layouts disponíveis
5. Filtro por entidade é aplicado (workaround temporário)
6. Layouts filtrados são retornados
7. App usa layout.layout (array de FieldLayout) para renderizar formulário

Fluxo de Renderização Dinâmica

1. Obter layout para entidade específica
2. Para cada FieldLayout no array layout.layout:
a. Verificar se visivel === "S"
b. Renderizar campo com base em field.tipo
c. Aplicar validação se requerido === "S"
d. Desabilitar campo se editavel === "N"
e. Aplicar valorPadrao se definido
f. Renderizar options se disponíveis
3. Agrupar campos por aba

Casos de Uso

Buscar Layout de Cliente

// Buscar layouts para formulário de cadastro de cliente
const clientLayouts = await layoutService.fetchRemote({
entity: "Cliente",
});

if (clientLayouts.length > 0) {
const mainLayout = clientLayouts[0];
console.log("Layout name:", mainLayout.nome);
console.log("Total fields:", mainLayout.layout.length);

// Agrupar campos por aba
const fieldsByTab = mainLayout.layout.reduce(
(acc, field) => {
if (!acc[field.aba]) acc[field.aba] = [];
acc[field.aba].push(field);
return acc;
},
{} as Record<string, FieldLayout[]>,
);

console.log("Tabs:", Object.keys(fieldsByTab));
}

Testes

Localização

services/layout/layout.service.test.ts

Executar Testes

# Teste específico do serviço
npx jest services/layout/layout.service.test.ts

# Modo watch
npx jest services/layout/layout.service.test.ts --watch

# Com coverage
npx jest services/layout/layout.service.test.ts --coverage

Casos de Teste

  • fetchRemote: busca de layouts sem filtros
  • fetchRemote: busca de layouts filtrados por entidade
  • fetchRemote: busca com paginação
  • ✅ Tratamento de erros para status não-2xx
  • ✅ Filtro por entidade aplicado corretamente

Mocks

Localização

__mocks__/layout.mock.ts

Dados Disponíveis

Array de layouts de exemplo para diferentes entidades:

  • Layout de Cliente (L-001): Layout simples com campos básicos
  • Layout de Produto (L-002): Layout com campos de produto
  • Layout de Cabeçalho (L-003): Layout para documentos
  • Layout de Contato (L-004): Layout para contatos

Exemplo de uso em testes:

import { layouts } from "@/__mocks__/layout.mock";

// Mock da API
const apiMock = {
get: jest.fn(async () => ({
status: 200,
data: { content: layouts },
})),
};

const service = new LayoutService({ apiWithoutAccessToken: apiMock });
const result = await service.fetchRemote({ entity: "Cliente" });

expect(result).toHaveLength(1);
expect(result[0].entidade).toBe("Cliente");