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áginasize: tamanho da páginadataHora: 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
Errorse 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");