forlogic-core 1.8.14 → 1.8.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/README.md CHANGED
@@ -1923,30 +1923,9 @@ KR1 50% dos indicadores de empreendimento e áreas de negócio atingindo a meta
1923
1923
 
1924
1924
  O `forlogic-core` suporta enriquecimento automático de **múltiplos campos de ID de usuário** com dados do Qualiex (nome, email, username).
1925
1925
 
1926
- #### **Configuração Global**
1926
+ #### **Como Funciona**
1927
1927
 
1928
- Configure o enrichment uma vez na inicialização do app:
1929
-
1930
- ```typescript
1931
- import { setQualiexConfig } from 'forlogic-core';
1932
-
1933
- // Configuração básica (usa localStorage como fallback)
1934
- setQualiexConfig({
1935
- enableUserEnrichment: true,
1936
- enableUsersApi: true,
1937
- });
1938
-
1939
- // Configuração avançada (recomendado)
1940
- setQualiexConfig({
1941
- enableUserEnrichment: true,
1942
- enableUsersApi: true,
1943
- getAccessToken: () => localStorage.getItem('qualiex_access_token'),
1944
- getCompanyId: () => localStorage.getItem('selectedUnitId'),
1945
- userNameFieldSuffix: '_name', // default
1946
- userEmailFieldSuffix: '_email', // default
1947
- userUsernameFieldSuffix: '_username', // default
1948
- });
1949
- ```
1928
+ O enriquecimento é **explícito e controlado por serviço**, não requer configuração global. Você decide quando enriquecer ativando `enableQualiexEnrichment` nos serviços.
1950
1929
 
1951
1930
  #### **Uso Básico: Lista de Campos de ID**
1952
1931
 
@@ -2059,21 +2038,61 @@ const { service } = createSimpleService({
2059
2038
  ✅ **Type-safe**: TypeScript valida configurações
2060
2039
  ✅ **Retrocompatível**: Projetos antigos continuam funcionando
2061
2040
 
2041
+ #### **Hook useQualiexUsers - Controle Explícito**
2042
+
2043
+ Para buscar usuários do Qualiex em componentes, use `enabled: true` explicitamente:
2044
+
2045
+ ```typescript
2046
+ import { useQualiexUsers } from 'forlogic-core';
2047
+
2048
+ // ✅ CORRETO: Busca ativa quando enabled=true
2049
+ const { data: users = [] } = useQualiexUsers({ enabled: true });
2050
+
2051
+ // ✅ CORRETO: Busca sob demanda com refetch
2052
+ const { data: users = [], refetch } = useQualiexUsers({ enabled: false });
2053
+ // Depois, quando necessário:
2054
+ await refetch();
2055
+ ```
2056
+
2057
+ **Exemplo: Importação de Qualiex**
2058
+
2059
+ ```typescript
2060
+ function ImportQualiexButton() {
2061
+ // Não busca automaticamente
2062
+ const { data: qualiexUsers = [], refetch, isLoading } = useQualiexUsers({
2063
+ enabled: false
2064
+ });
2065
+
2066
+ const handleImport = async () => {
2067
+ // Busca apenas quando usuário clica
2068
+ const { data } = await refetch();
2069
+ // Processar data...
2070
+ };
2071
+
2072
+ return <Button onClick={handleImport}>Importar do Qualiex</Button>;
2073
+ }
2074
+ ```
2075
+
2062
2076
  #### **Boas Práticas**
2063
2077
 
2064
- ✅ **BOM**: Configurar `getAccessToken` e `getCompanyId` para evitar dependência de localStorage
2078
+ ✅ **BOM**: Ativar enrichment apenas onde necessário
2065
2079
 
2066
2080
  ```typescript
2067
- setQualiexConfig({
2068
- enableUserEnrichment: true,
2069
- getAccessToken: async () => {
2070
- // Buscar token de forma segura (ex: context, Zustand, etc)
2071
- return myAuthStore.getToken();
2072
- },
2073
- getCompanyId: () => myAppStore.getSelectedCompanyId(),
2081
+ const { service } = createSimpleService({
2082
+ tableName: 'processes',
2083
+ entityName: 'Processo',
2084
+ enableQualiexEnrichment: true, // Enriquece dados de usuário
2085
+ userIdFields: ['created_by_id', 'owner_id'],
2074
2086
  });
2075
2087
  ```
2076
2088
 
2089
+ ✅ **BOM**: Usar `enabled: true` apenas quando precisar dos dados
2090
+
2091
+ ```typescript
2092
+ // Em um componente que mostra lista de usuários
2093
+ const { data: users } = useQualiexUsers({ enabled: true });
2094
+ ```
2095
+
2077
2096
  ❌ **EVITAR**: Múltiplos campos apontando para o mesmo campo de saída
2078
2097
 
2079
2098
  ```typescript
@@ -5459,78 +5478,131 @@ fetch(url, { headers: { 'un-alias': 'true' } }); // ✅
5459
5478
 
5460
5479
  ---
5461
5480
 
5462
- ## 🔍 COMPONENTES DE SELEÇÃO: SelectSearch vs MultiSelect vs EntitySelect
5481
+ ## 🔍 COMPONENTE DE SELEÇÃO: SelectSearch
5463
5482
 
5464
- ### **Quando Usar Cada Componente?**
5483
+ ### **SelectSearch** - Componente Unificado de Seleção
5465
5484
 
5466
- | Componente | Uso Recomendado | Modo | Características |
5467
- |------------|----------------|------|-----------------|
5468
- | **SelectSearch** | Seleção versátil (única OU múltipla) | Configurável | Mais flexível, ideal para formulários dinâmicos |
5469
- | **MultiSelect** | Seleção múltipla apenas | Múltiplo (default) | Otimizado para badges, limite de badges exibidos |
5470
- | **EntitySelect** | Seleção única de entidades | Único | Mais simples, ideal para foreign keys |
5485
+ Componente versátil que suporta **seleção única** ou **múltipla** com busca inteligente, normalização de acentos e funciona perfeitamente dentro de Dialogs.
5471
5486
 
5472
- ### **SelectSearch - Componente Versátil**
5487
+ ⚠️ **IMPORTANTE**: `MultiSelect` e `EntitySelect` estão obsoletos. Use `SelectSearch` para todos os casos de seleção.
5488
+
5489
+ ---
5490
+
5491
+ ### **Props Principais**
5492
+
5493
+ ```typescript
5494
+ interface SelectSearchProps<T> {
5495
+ options: T[]; // Lista de opções
5496
+ value?: string | string[]; // Valor(es) selecionado(s)
5497
+ onChange: (value: string | string[] | undefined) => void; // Callback de mudança
5498
+
5499
+ // Labels e placeholder
5500
+ placeholder?: string; // Ex: "Selecione..."
5501
+ emptyMessage?: string; // Ex: "Nenhum item encontrado"
5502
+
5503
+ // Configuração de modo
5504
+ multiple?: boolean; // false (padrão) = seleção única, true = múltipla
5505
+
5506
+ // Funções de mapeamento (default: { value: 'id', label: 'name' })
5507
+ getOptionValue?: (option: T) => string;
5508
+ getOptionLabel?: (option: T) => string;
5509
+
5510
+ // Ordenação
5511
+ sortOptions?: boolean; // true (padrão) = ordena por label
5512
+
5513
+ // Uso em Dialog (CRÍTICO!)
5514
+ popoverContainer?: HTMLElement | null; // Necessário para funcionar dentro de Dialog
5515
+
5516
+ // Estados
5517
+ isLoading?: boolean; // Mostra skeleton
5518
+ error?: string; // Mostra mensagem de erro
5519
+ disabled?: boolean; // Desabilita o componente
5520
+ }
5521
+ ```
5473
5522
 
5474
- **Quando usar:**
5475
- - ✅ Precisa alternar entre modo único e múltiplo dinamicamente
5476
- - ✅ Formulários onde o modo pode mudar com base em lógica
5477
- - ✅ Situações onde você quer um único componente para ambos os casos
5523
+ ---
5478
5524
 
5479
- **Exemplo básico:**
5525
+ ### **Exemplo 1: Seleção Única**
5480
5526
 
5481
5527
  ```typescript
5482
5528
  import { SelectSearch } from 'forlogic-core';
5483
5529
 
5484
- // Seleção única
5485
- const [selectedLanguage, setSelectedLanguage] = useState<string>('');
5530
+ function MyForm() {
5531
+ const [language, setLanguage] = useState<string>();
5486
5532
 
5487
- <SelectSearch
5488
- options={languageOptions}
5489
- value={selectedLanguage}
5490
- onChange={setSelectedLanguage}
5491
- placeholder="Selecione um idioma..."
5492
- label="Idioma"
5493
- />
5533
+ return (
5534
+ <SelectSearch
5535
+ options={[
5536
+ { id: 'pt', name: 'Português' },
5537
+ { id: 'en', name: 'English' },
5538
+ { id: 'es', name: 'Español' }
5539
+ ]}
5540
+ value={language}
5541
+ onChange={setLanguage}
5542
+ placeholder="Selecione um idioma"
5543
+ getOptionValue={(opt) => opt.id}
5544
+ getOptionLabel={(opt) => opt.name}
5545
+ />
5546
+ );
5547
+ }
5548
+ ```
5494
5549
 
5495
- // Seleção múltipla
5496
- const [selectedTags, setSelectedTags] = useState<string[]>([]);
5550
+ ---
5497
5551
 
5498
- <SelectSearch
5499
- multiple
5500
- options={tagOptions}
5501
- value={selectedTags}
5502
- onChange={setSelectedTags}
5503
- placeholder="Selecione tags..."
5504
- label="Tags"
5505
- maxDisplayedBadges={3}
5506
- />
5552
+ ### **Exemplo 2: Seleção Múltipla**
5553
+
5554
+ ```typescript
5555
+ import { SelectSearch } from 'forlogic-core';
5556
+
5557
+ function MyForm() {
5558
+ const [tags, setTags] = useState<string[]>([]);
5559
+
5560
+ return (
5561
+ <SelectSearch
5562
+ multiple
5563
+ options={[
5564
+ { id: '1', name: 'React' },
5565
+ { id: '2', name: 'TypeScript' },
5566
+ { id: '3', name: 'Tailwind' }
5567
+ ]}
5568
+ value={tags}
5569
+ onChange={(value) => setTags(value as string[])}
5570
+ placeholder="Selecione tecnologias"
5571
+ getOptionValue={(opt) => opt.id}
5572
+ getOptionLabel={(opt) => opt.name}
5573
+ />
5574
+ );
5575
+ }
5507
5576
  ```
5508
5577
 
5509
- **Uso dentro de Dialog (scroll funcionando):**
5578
+ ---
5579
+
5580
+ ### **Exemplo 3: Dentro de Dialog** ⚠️ **CRÍTICO**
5581
+
5582
+ Para funcionar corretamente dentro de um Dialog, você **DEVE** passar o `popoverContainer`:
5510
5583
 
5511
5584
  ```typescript
5512
- import { Dialog, DialogContent, SelectSearch } from 'forlogic-core';
5585
+ import { SelectSearch, Dialog, DialogContent } from 'forlogic-core';
5513
5586
 
5514
- function MyComponent() {
5515
- const [dialogContentRef, setDialogContentRef] = useState<HTMLDivElement | null>(null);
5516
- const [selected, setSelected] = useState<string>('');
5587
+ function MyDialog() {
5588
+ const [open, setOpen] = useState(false);
5589
+ const [category, setCategory] = useState<string>();
5590
+ const dialogContentRef = useRef<HTMLDivElement>(null);
5517
5591
 
5518
5592
  return (
5519
- <Dialog>
5520
- <DialogTrigger asChild>
5521
- <Button>Abrir Seleção</Button>
5522
- </DialogTrigger>
5523
- <DialogContent ref={setDialogContentRef} className="max-h-[90vh] overflow-visible">
5524
- <DialogHeader>
5525
- <DialogTitle>Selecione uma Categoria</DialogTitle>
5526
- </DialogHeader>
5527
- <div className="mt-4 max-h-[60vh] overflow-auto pr-1">
5593
+ <Dialog open={open} onOpenChange={setOpen}>
5594
+ <DialogContent
5595
+ ref={dialogContentRef}
5596
+ className="overflow-visible" // ⚠️ IMPORTANTE: overflow-visible no DialogContent
5597
+ >
5598
+ <div className="space-y-4 overflow-auto max-h-[60vh]">
5599
+ {/* ⚠️ CRÍTICO: Passar popoverContainer */}
5528
5600
  <SelectSearch
5529
- options={categoryOptions}
5530
- value={selected}
5531
- onChange={setSelected}
5532
- placeholder="Selecione..."
5533
- popoverContainer={dialogContentRef} {/* ✅ CRÍTICO para scroll funcionar */}
5601
+ options={categories}
5602
+ value={category}
5603
+ onChange={setCategory}
5604
+ placeholder="Selecione categoria"
5605
+ popoverContainer={dialogContentRef.current}
5534
5606
  />
5535
5607
  </div>
5536
5608
  </DialogContent>
@@ -5539,156 +5611,156 @@ function MyComponent() {
5539
5611
  }
5540
5612
  ```
5541
5613
 
5542
- **Props principais:**
5614
+ ---
5543
5615
 
5544
- ```typescript
5545
- interface SelectSearchProps<T> {
5546
- multiple?: boolean; // Modo: false = único, true = múltiplo
5547
- options: T[]; // Array de itens
5548
- value?: string | string[]; // Valor(es) selecionado(s)
5549
- onChange?: (value: string | string[]) => void;
5550
- getOptionValue?: (option: T) => string;
5551
- getOptionLabel?: (option: T) => string;
5552
- placeholder?: string;
5553
- label?: string;
5554
- disabled?: boolean;
5555
- required?: boolean;
5556
- isLoading?: boolean;
5557
- error?: string | boolean;
5558
- sortOptions?: boolean; // Default: true
5559
- maxDisplayedBadges?: number; // Limite de badges (modo múltiplo)
5560
- popoverContainer?: HTMLElement | null; // ✅ Essencial para Dialog
5561
- }
5562
- ```
5616
+ ### **⚠️ IMPORTANTE: Uso em Dialog**
5563
5617
 
5564
- ### **MultiSelect - Seleção Múltipla**
5618
+ **Configuração Correta:**
5619
+ ```tsx
5620
+ // 1. Ref no DialogContent
5621
+ const dialogContentRef = useRef<HTMLDivElement>(null);
5565
5622
 
5566
- **Quando usar:**
5567
- - Seleção múltipla obrigatória (não precisa alternar para único)
5568
- - ✅ Exibição de badges é importante
5569
- - Precisa de limite de badges exibidos (+N)
5623
+ // 2. overflow-visible no DialogContent
5624
+ <DialogContent ref={dialogContentRef} className="overflow-visible">
5625
+
5626
+ // 3. Div interna com overflow-auto
5627
+ <div className="overflow-auto max-h-[60vh]">
5628
+
5629
+ // 4. Passar popoverContainer
5630
+ <SelectSearch
5631
+ {...props}
5632
+ popoverContainer={dialogContentRef.current}
5633
+ />
5634
+ </div>
5635
+ </DialogContent>
5636
+ ```
5570
5637
 
5571
- **Exemplo:**
5638
+ **❌ Configurações Incorretas Comuns:**
5572
5639
 
5573
- ```typescript
5574
- import { MultiSelect } from 'forlogic-core';
5640
+ ```tsx
5641
+ // ERRADO: Sem popoverContainer
5642
+ <SelectSearch options={data} value={value} onChange={onChange} />
5575
5643
 
5576
- const [selectedFrameworks, setSelectedFrameworks] = useState<string[]>([]);
5644
+ // ERRADO: overflow-hidden no DialogContent
5645
+ <DialogContent className="overflow-hidden">
5577
5646
 
5578
- <MultiSelect
5579
- options={frameworks}
5580
- value={selectedFrameworks}
5581
- onChange={setSelectedFrameworks}
5582
- getOptionValue={(opt) => opt.id}
5583
- getOptionLabel={(opt) => opt.name}
5584
- placeholder="Selecione frameworks..."
5585
- label="Frameworks"
5586
- maxDisplayedBadges={3} // Exibe: [Badge 1] [Badge 2] [Badge 3] [+5]
5587
- />
5647
+ // ❌ ERRADO: Sem div interna com scroll
5648
+ <DialogContent className="overflow-visible">
5649
+ <SelectSearch {...props} />
5650
+ </DialogContent>
5588
5651
  ```
5589
5652
 
5590
- **Modo único (suportado mas não recomendado):**
5591
-
5592
- ```typescript
5593
- // ⚠️ Use SelectSearch ou EntitySelect para modo único
5594
- <MultiSelect
5595
- multiple={false} // Funciona, mas SelectSearch é mais apropriado
5596
- options={options}
5597
- value={selected}
5598
- onChange={setSelected}
5599
- />
5600
- ```
5653
+ ---
5601
5654
 
5602
- ### **EntitySelect - Seleção Única Simples**
5655
+ ### **Características Avançadas**
5603
5656
 
5604
- **Quando usar:**
5605
- - Seleção única de entidades (processos, usuários, categorias)
5606
- - Foreign keys em formulários
5607
- - Casos simples sem necessidade de badges ou modo múltiplo
5657
+ #### **Busca Inteligente**
5658
+ - **Case-insensitive**: `react` encontra `React`
5659
+ - **Accent-insensitive**: `frances` encontra `Français`
5660
+ - **Busca em qualquer parte**: `script` encontra `TypeScript`
5608
5661
 
5609
- **Exemplo:**
5662
+ #### **Badges Interativos (modo múltiplo)**
5663
+ - Exibe badges com `×` para remover itens
5664
+ - Limite de 3 badges exibidos, com `+N` para excedentes
5665
+ - Click em `+N` expande para mostrar todos
5610
5666
 
5667
+ #### **Estados**
5611
5668
  ```typescript
5612
- import { EntitySelect } from 'forlogic-core';
5669
+ // Loading
5670
+ <SelectSearch isLoading options={[]} />
5613
5671
 
5614
- const [selectedFramework, setSelectedFramework] = useState<string>('');
5672
+ // Erro
5673
+ <SelectSearch error="Falha ao carregar opções" options={[]} />
5615
5674
 
5616
- <EntitySelect
5617
- items={frameworks}
5618
- value={selectedFramework}
5619
- onChange={setSelectedFramework}
5620
- getItemValue={(opt) => opt.id}
5621
- getItemLabel={(opt) => opt.name}
5622
- placeholder="Selecione um framework..."
5623
- searchPlaceholder="Buscar framework..."
5624
- />
5675
+ // Desabilitado
5676
+ <SelectSearch disabled options={data} />
5625
5677
  ```
5626
5678
 
5627
- ### **Comparação de Props**
5628
-
5629
- | Prop | SelectSearch | MultiSelect | EntitySelect |
5630
- |------|--------------|-------------|--------------|
5631
- | `multiple` | ✅ Configurável | ✅ Default true | ❌ Sempre único |
5632
- | `maxDisplayedBadges` | ✅ Modo múltiplo | ✅ | ❌ |
5633
- | `popoverContainer` | ✅ | ✅ | ❌ |
5634
- | `items` vs `options` | `options` | `options` | `items` |
5635
- | Complexidade | Média | Média | Baixa |
5679
+ ---
5636
5680
 
5637
- ### **Recomendações**
5681
+ ### **Uso em BaseForm**
5638
5682
 
5639
- 1. **Use SelectSearch quando:**
5640
- - Precisar de flexibilidade para alternar entre único/múltiplo
5641
- - Estiver dentro de Dialog e precisar de scroll
5642
- - Quiser um componente versátil para diversos casos
5683
+ ```typescript
5684
+ import { BaseForm, SelectSearch } from 'forlogic-core';
5643
5685
 
5644
- 2. **Use MultiSelect quando:**
5645
- - Seleção múltipla for o único caso de uso
5646
- - Precisar de controle avançado de badges
5647
- - Precisar de modo único ocasionalmente (mas prefira SelectSearch)
5686
+ const fields = [
5687
+ {
5688
+ name: 'language',
5689
+ label: 'Idioma',
5690
+ type: 'custom' as const,
5691
+ component: ({ field }: any) => (
5692
+ <SelectSearch
5693
+ options={languages}
5694
+ value={field.value}
5695
+ onChange={field.onChange}
5696
+ placeholder="Selecione um idioma"
5697
+ />
5698
+ ),
5699
+ validation: z.string().min(1, 'Idioma obrigatório')
5700
+ },
5701
+ {
5702
+ name: 'tags',
5703
+ label: 'Tags',
5704
+ type: 'custom' as const,
5705
+ component: ({ field }: any) => (
5706
+ <SelectSearch
5707
+ multiple
5708
+ options={allTags}
5709
+ value={field.value}
5710
+ onChange={field.onChange}
5711
+ placeholder="Selecione tags"
5712
+ />
5713
+ ),
5714
+ validation: z.array(z.string()).min(1, 'Selecione ao menos uma tag')
5715
+ }
5716
+ ];
5717
+ ```
5648
5718
 
5649
- 3. **Use EntitySelect quando:**
5650
- - Seleção única simples for suficiente
5651
- - Não precisar de Dialog ou scroll especial
5652
- - Quiser o componente mais leve e focado
5719
+ ---
5653
5720
 
5654
- ### **⚠️ IMPORTANTE: Uso em Dialog**
5721
+ ### **Migração de MultiSelect e EntitySelect (DEPRECATED)**
5655
5722
 
5656
- Tanto `SelectSearch` quanto `MultiSelect` funcionam perfeitamente dentro de `Dialog`, mas requerem configuração específica:
5723
+ ⚠️ **Estes componentes estão obsoletos. Use `SelectSearch` para todos os casos de seleção.**
5657
5724
 
5658
- **✅ Configuração correta:**
5725
+ **Migração de MultiSelect:**
5659
5726
 
5660
5727
  ```typescript
5661
- // 1. State para ref do DialogContent
5662
- const [dialogContentRef, setDialogContentRef] = useState<HTMLDivElement | null>(null);
5728
+ // ANTIGO: MultiSelect
5729
+ <MultiSelect
5730
+ options={data}
5731
+ value={selected}
5732
+ onChange={setSelected}
5733
+ />
5663
5734
 
5664
- // 2. DialogContent com overflow-visible
5665
- <DialogContent ref={setDialogContentRef} className="max-h-[90vh] overflow-visible">
5666
-
5667
- {/* 3. Container interno com overflow-auto */}
5668
- <div className="mt-4 max-h-[60vh] overflow-auto pr-1">
5669
-
5670
- {/* 4. Passar ref como popoverContainer */}
5671
- <SelectSearch
5672
- options={options}
5673
- value={selected}
5674
- onChange={setSelected}
5675
- popoverContainer={dialogContentRef} {/* ✅ CRÍTICO */}
5676
- />
5677
- </div>
5678
- </DialogContent>
5735
+ // NOVO: SelectSearch
5736
+ <SelectSearch
5737
+ multiple
5738
+ options={data}
5739
+ value={selected}
5740
+ onChange={setSelected}
5741
+ />
5679
5742
  ```
5680
5743
 
5681
- **❌ Erros comuns:**
5744
+ **Migração de EntitySelect:**
5682
5745
 
5683
5746
  ```typescript
5684
- // ❌ ERRADO: Sem popoverContainer
5685
- <SelectSearch options={options} value={selected} onChange={setSelected} />
5686
-
5687
- // ❌ ERRADO: DialogContent sem overflow-visible
5688
- <DialogContent className="max-h-[90vh] overflow-auto">
5747
+ // ❌ ANTIGO: EntitySelect
5748
+ <EntitySelect
5749
+ items={data}
5750
+ value={selected}
5751
+ onChange={setSelected}
5752
+ getItemValue={(item) => item.id}
5753
+ getItemLabel={(item) => item.name}
5754
+ />
5689
5755
 
5690
- // ERRADO: Usar document.body como container (perde scroll)
5691
- <SelectSearch popoverContainer={document.body} />
5756
+ // NOVO: SelectSearch
5757
+ <SelectSearch
5758
+ options={data}
5759
+ value={selected}
5760
+ onChange={setSelected}
5761
+ getOptionValue={(item) => item.id}
5762
+ getOptionLabel={(item) => item.name}
5763
+ />
5692
5764
  ```
5693
5765
 
5694
5766
  ---