@horizon-apps/domain-schema-core
Version:
Core domain schema utilities for Horizon Platform - Schema generators, data enrichers, converters and specifications
674 lines (550 loc) • 15.3 kB
Markdown
# 🎨 Horizon Domain Data Display Enricher
> Enriquecedor genérico de dados de domínios para display - Transforma dados brutos de entidades em objetos enriquecidos para UI
## 📋 Índice
1. [Visão Geral](#visão-geral)
2. [Instalação](#instalação)
3. [Uso Básico](#uso-básico)
4. [API Completa](#api-completa)
5. [Formatadores](#formatadores)
6. [Templates](#templates)
7. [Exemplos Práticos](#exemplos-práticos)
8. [Migração](#migração)
9. [Estrutura do Pacote](#estrutura-do-pacote)
## 🎯 Visão Geral
O **Horizon Domain Data Display Enricher** é uma biblioteca genérica para transformar dados brutos de qualquer domínio (Property, Broker, User, etc.) em objetos enriquecidos com metadados, formatação e informações adicionais para facilitar a exibição no frontend.
### Principais Características
- ✅ **Genérico**: Funciona com qualquer tipo de domínio
- ✅ **Formatação Automática**: Suporta currency, date, area, distance, percent, count
- ✅ **Templates Inteligentes**: Processamento de pluralização e substituições
- ✅ **Type-Safe**: Escrito em TypeScript com tipos completos
- ✅ **Extensível**: Permite customização via opções
- ✅ **Retrocompatível**: Mantém compatibilidade com API antiga
### Transformação Exemplo
```typescript
// ENTRADA (dados brutos)
{
valor: 1500000,
dormitorios: 3
}
// SAÍDA (dados enriquecidos)
{
valor: {
value: 1500000,
label: "Valor",
type: "Number",
format: "currency",
valueLabel: "R$ 1.500.000,00",
composedLabel: "R$ 1.500.000,00"
},
dormitorios: {
value: 3,
label: "Dormitórios",
type: "Number",
format: "count",
valueLabel: "3",
composedLabel: "3 dormitórios"
}
}
```
## 📦 Instalação
### Como Pacote NPM (Futuro)
```bash
npm install @horizon/domain-data-display-enricher
# ou
yarn add @horizon/domain-data-display-enricher
# ou
pnpm add @horizon/domain-data-display-enricher
```
### Uso Local (Atual)
```typescript
import { enrichDomainDataForDisplay } from '@/modules/horizon-platform-toolkit';
```
## 🚀 Uso Básico
### 1. Exemplo Simples
```typescript
import { enrichDomainDataForDisplay } from '@horizon/domain-data-display-enricher';
// Dados brutos do domínio
const propertyData = {
title: "Apartamento 3 quartos",
price: 750000,
area: 120,
rooms: 3
};
// Metadados do schema
const metadata = [
{
key: "title",
label: "Título",
type: "String"
},
{
key: "price",
label: "Preço",
type: "Number",
format: "currency",
unit: "BRL"
},
{
key: "area",
label: "Área",
type: "Number",
format: "area",
unit: "m2"
},
{
key: "rooms",
label: "Quartos",
type: "Number",
format: "count",
composedLabel: "{{value}} quarto{{p:s}}"
}
];
// Enriquecer dados
const enrichedData = enrichDomainDataForDisplay({
data: propertyData,
metadata: metadata
});
console.log(enrichedData.price.valueLabel); // "R$ 750.000,00"
console.log(enrichedData.area.valueLabel); // "120 m²"
console.log(enrichedData.rooms.composedLabel); // "3 quartos"
```
### 2. Com Opções Avançadas
```typescript
const enrichedData = enrichDomainDataForDisplay({
data: myData,
metadata: myMetadata,
locale: 'en-US',
currency: 'USD',
getIcon: (iconName) => IconLibrary.get(iconName)
});
```
## 📚 API Completa
### Função Principal
#### `enrichDomainDataForDisplay(options: EnrichmentOptions)`
Enriquece dados de domínio com metadados para display.
**Parâmetros:**
```typescript
interface EnrichmentOptions {
data: Record<string, any>; // Dados brutos
metadata: FieldMetadata[]; // Metadados dos campos
locale?: string; // Locale (default: 'pt-BR')
currency?: string; // Moeda padrão (default: 'BRL')
getIcon?: (name: string) => any; // Função para obter ícones
}
```
**Retorno:**
```typescript
Record<string, EnrichedField | any>
```
### Tipos
#### `FieldMetadata`
```typescript
interface FieldMetadata {
key: string; // Chave do campo
label?: string; // Label para UI
type?: string; // Tipo do dado
format?: string; // Formato de exibição
unit?: string; // Unidade de medida
categories?: string[]; // Categorias
composedLabel?: string; // Template de composição
icon?: string; // Ícone direto
iconName?: string; // Nome do ícone
validation?: any; // Regras de validação
[key: string]: any; // Campos adicionais
}
```
#### `EnrichedField`
```typescript
interface EnrichedField extends FieldMetadata {
value: any; // Valor original
valueLabel?: string; // Valor formatado
composedLabel?: string; // Label composto processado
icon?: any; // Ícone resolvido
}
```
## 🎨 Formatadores
### Formatadores Disponíveis
| Format | Descrição | Exemplo |
|--------|-----------|---------|
| `currency` | Valores monetários | 1500 → "R$ 1.500,00" |
| `date` | Datas | "2025-08-07" → "7 de agosto de 2025" |
| `area` | Áreas | 100 → "100 m²" |
| `distance` | Distâncias | 150 → "150m" |
| `percent` | Porcentagens | 15 → "15%" |
| `count` | Contagem | 3 → "3" |
| `year` | Anos | 2025 → "2025" |
### Uso Direto dos Formatadores
```typescript
import { formatters } from '@horizon/domain-data-display-enricher';
// Moeda
formatters.currency(1500.50, 'BRL', 'pt-BR'); // "R$ 1.500,50"
formatters.currency(1500.50, 'USD', 'en-US'); // "$1,500.50"
// Data
formatters.date(new Date('2025-08-07'), 'pt-BR'); // "7 de agosto de 2025"
// Área
formatters.area(120, 'm2'); // "120 m²"
formatters.area(50, 'hectares'); // "50 hectares"
// Distância
formatters.distance(150, 'm'); // "150m"
formatters.distance(5, 'km'); // "5km"
// Porcentagem
formatters.percent(15); // "15%"
formatters.percent(0.15); // "15.00%"
```
## 📝 Templates
### Sistema de Templates
O sistema suporta templates com substituições dinâmicas:
| Placeholder | Descrição | Exemplo |
|-------------|-----------|---------|
| `{{value}}` | Valor bruto | 3 → "3" |
| `{{valueLabel}}` | Valor formatado | 3 → "3" |
| `{{p:texto}}` | Texto no plural | 1 → "", 2 → "texto" |
| `{{s:texto}}` | Texto no singular | 1 → "texto", 2 → "" |
### Exemplos de Templates
```typescript
// Pluralização
"{{value}} quarto{{p:s}}"
// 1 → "1 quarto"
// 3 → "3 quartos"
// Singular condicional
"{{s:Apenas }}{{value}} vaga{{p:s}}"
// 1 → "Apenas 1 vaga"
// 2 → "2 vagas"
// Com valor formatado
"Total: {{valueLabel}}"
// 1500 com format: currency → "Total: R$ 1.500,00"
```
### Uso do Processador de Templates
```typescript
import { templateProcessor } from '@horizon/domain-data-display-enricher';
const result = templateProcessor(
"{{value}} item{{p:s}} - {{valueLabel}}",
3,
"R$ 30,00"
);
// "3 items - R$ 30,00"
```
## 💡 Exemplos Práticos
### Exemplo 1: Sistema de Imóveis
```typescript
const propertyData = {
reference: "APT-001",
type: "Apartamento",
price: 850000,
rent: 3500,
area: 150,
rooms: 3,
bathrooms: 2,
garage: 2,
condo_fee: 800,
distance_beach: 200,
furnished: true,
features: ["Piscina", "Academia", "Playground"]
};
const propertyMetadata = [
{ key: "reference", label: "Referência", type: "String" },
{ key: "type", label: "Tipo", type: "String" },
{
key: "price",
label: "Valor de Venda",
type: "Number",
format: "currency",
unit: "BRL",
categories: ["valores", "principais"]
},
{
key: "rent",
label: "Valor de Aluguel",
type: "Number",
format: "currency",
unit: "BRL",
composedLabel: "{{valueLabel}}/mês"
},
{
key: "area",
label: "Área",
type: "Number",
format: "area",
unit: "m2",
iconName: "area"
},
{
key: "rooms",
label: "Dormitórios",
type: "Number",
format: "count",
composedLabel: "{{value}} dormitório{{p:s}}",
iconName: "bedroom"
},
{
key: "bathrooms",
label: "Banheiros",
type: "Number",
format: "count",
composedLabel: "{{value}} banheiro{{p:s}}",
iconName: "bathroom"
},
{
key: "garage",
label: "Vagas",
type: "Number",
format: "count",
composedLabel: "{{value}} vaga{{p:s}}",
iconName: "garage"
},
{
key: "distance_beach",
label: "Distância da Praia",
type: "Number",
format: "distance",
unit: "m",
composedLabel: "{{valueLabel}} da praia"
},
{
key: "furnished",
label: "Mobiliado",
type: "Boolean"
},
{
key: "features",
label: "Características",
type: "Array"
}
];
const enriched = enrichDomainDataForDisplay({
data: propertyData,
metadata: propertyMetadata,
getIcon: (name) => `icon-${name}` // Mock icon function
});
// Resultados
console.log(enriched.price.valueLabel); // "R$ 850.000,00"
console.log(enriched.rent.composedLabel); // "R$ 3.500,00/mês"
console.log(enriched.area.valueLabel); // "150 m²"
console.log(enriched.rooms.composedLabel); // "3 dormitórios"
console.log(enriched.bathrooms.composedLabel); // "2 banheiros"
console.log(enriched.garage.composedLabel); // "2 vagas"
console.log(enriched.distance_beach.composedLabel); // "200m da praia"
console.log(enriched.furnished.valueLabel); // "Sim"
```
### Exemplo 2: Sistema de Usuários
```typescript
const userData = {
name: "João Silva",
age: 28,
salary: 5500,
hire_date: "2023-03-15",
performance: 0.92,
active: true,
skills: ["JavaScript", "TypeScript", "React"]
};
const userMetadata = [
{ key: "name", label: "Nome", type: "String" },
{ key: "age", label: "Idade", type: "Number", format: "count" },
{
key: "salary",
label: "Salário",
type: "Number",
format: "currency",
unit: "BRL"
},
{
key: "hire_date",
label: "Data de Contratação",
type: "String",
format: "date"
},
{
key: "performance",
label: "Performance",
type: "Number",
format: "percent"
},
{ key: "active", label: "Ativo", type: "Boolean" },
{ key: "skills", label: "Habilidades", type: "Array" }
];
const enrichedUser = enrichDomainDataForDisplay({
data: userData,
metadata: userMetadata
});
console.log(enrichedUser.salary.valueLabel); // "R$ 5.500,00"
console.log(enrichedUser.hire_date.valueLabel); // "15 de março de 2023"
console.log(enrichedUser.performance.valueLabel); // "92.00%"
console.log(enrichedUser.active.valueLabel); // "Sim"
```
## 🔄 Migração
### Da API Antiga para a Nova
```typescript
// ANTES (API antiga)
import { EnrichFieldsWithMetadata } from 'caminho/antigo';
const result = EnrichFieldsWithMetadata({
data: myData,
metadata: myMetadata
});
// DEPOIS (API nova)
import { enrichDomainDataForDisplay } from '@horizon/domain-data-display-enricher';
const result = enrichDomainDataForDisplay({
data: myData,
metadata: myMetadata
});
```
### Compatibilidade
A função `EnrichFieldsWithMetadata` ainda está disponível para retrocompatibilidade:
```typescript
import { EnrichFieldsWithMetadata } from '@horizon/domain-data-display-enricher';
// Funciona como antes (mas está deprecated)
const result = EnrichFieldsWithMetadata({ data, metadata });
```
## 📂 Estrutura do Pacote
```
horizon-domain-data-display-enricher/
├── src/
│ ├── index.ts # Arquivo principal
│ ├── types.ts # Definições de tipos
│ ├── formatters.ts # Funções de formatação
│ ├── templates.ts # Processador de templates
│ └── enricher.ts # Lógica de enriquecimento
├── tests/
│ ├── index.test.ts # Testes principais
│ ├── formatters.test.ts # Testes dos formatadores
│ └── templates.test.ts # Testes de templates
├── docs/
│ └── README.md # Esta documentação
├── package.json
├── tsconfig.json
└── README.md
```
## 🔧 Configuração para NPM
### package.json Sugerido
```json
{
"name": "@horizon/domain-data-display-enricher",
"version": "1.0.0",
"description": "Generic domain data enricher for display - Transform raw entity data into enriched UI objects",
"main": "dist/index.js",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
"files": [
"dist",
"README.md"
],
"scripts": {
"build": "tsup src/index.ts --format cjs,esm --dts",
"test": "vitest",
"test:coverage": "vitest run --coverage"
},
"keywords": [
"horizon",
"enricher",
"formatter",
"display",
"ui",
"metadata",
"transform"
],
"author": "Horizon Platform",
"license": "MIT",
"dependencies": {
"date-fns": "^2.30.0"
},
"devDependencies": {
"@types/node": "^20.0.0",
"tsup": "^8.0.0",
"typescript": "^5.0.0",
"vitest": "^1.0.0"
},
"peerDependencies": {
"date-fns": ">=2.0.0"
},
"repository": {
"type": "git",
"url": "https://github.com/horizon-platform/domain-data-display-enricher"
}
}
```
### tsconfig.json Sugerido
```json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020"],
"declaration": true,
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"moduleResolution": "node"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "tests"]
}
```
## 🚀 Publicação no NPM
### Passos para Publicar
1. **Criar repositório separado**
```bash
git init horizon-domain-data-display-enricher
cd horizon-domain-data-display-enricher
```
2. **Copiar arquivos necessários**
- Copiar o código de `/src/_modules/horizon-platform-toolkit/packages/horizon-domain-data-display-enricher/`
- Adaptar imports (remover dependências locais)
- Adicionar package.json e tsconfig.json
3. **Instalar dependências**
```bash
pnpm install
```
4. **Rodar testes**
```bash
pnpm test
```
5. **Build**
```bash
pnpm build
```
6. **Publicar**
```bash
npm login
npm publish --access public
```
## 📝 Notas de Implementação
### Dependências Externas
Atualmente o código tem algumas dependências que precisam ser resolvidas:
1. **getIcon**: Função para obter ícones
- Solução: Tornar opcional via options
2. **date-fns**: Formatação de datas
- Solução: Já está como dependência
3. **horizon-fields-metadata.json**: Metadados centralizados
- Solução: Remover dependência, tornar configurável
### Ajustes Necessários
Para tornar o pacote totalmente independente:
1. Remover import de `src/core/ui/icons`
2. Remover import de `horizon-fields-metadata.json`
3. Tornar unitListModel configurável
4. Adicionar mais opções de configuração
## 📄 Licença
MIT
## 🤝 Contribuindo
Contribuições são bem-vindas! Por favor, abra uma issue ou pull request.
## 📧 Suporte
Para suporte, abra uma issue no GitHub ou entre em contato com a equipe Horizon.
*Desenvolvido com ❤️ pela equipe Horizon Platform*