forlogic-core 1.8.13 → 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
@@ -1,12 +1,12 @@
1
1
  # 🧱 forlogic-core - Guia de Desenvolvimento
2
2
 
3
- > **IMPORTANTE**: Este README é genérico para todos os projetos. Para configurações específicas do projeto (como schema padrão), consulte o arquivo **KNOWLEDGE.md**.
3
+ > **IMPORTANTE**: Este README é genérico para todos os projetos. Para configurações específicas do projeto (como schema padrão), consulte o **Custom Knowledge** do projeto nas configurações do Lovable.
4
4
 
5
5
  ---
6
6
 
7
7
  ## 🤖 REGRAS CRÍTICAS
8
8
 
9
- > **📋 Schema Padrão**: Veja no arquivo **KNOWLEDGE.md** qual é o schema padrão deste projeto específico.
9
+ > **📋 Schema Padrão**: Veja no **Custom Knowledge** do projeto (Settings → Manage Knowledge) qual é o schema padrão deste projeto específico.
10
10
 
11
11
  ### ⚠️ TOP 4 ERROS MAIS COMUNS
12
12
 
@@ -16,7 +16,7 @@
16
16
  // ❌ ERRADO
17
17
  .from('table')
18
18
 
19
- // ✅ CORRETO (verifique o schema padrão no KNOWLEDGE.md)
19
+ // ✅ CORRETO (verifique o schema padrão no Custom Knowledge)
20
20
  .schema('SEU_SCHEMA').from('table')
21
21
  ```
22
22
 
@@ -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,6 +5478,293 @@ fetch(url, { headers: { 'un-alias': 'true' } }); // ✅
5459
5478
 
5460
5479
  ---
5461
5480
 
5481
+ ## 🔍 COMPONENTE DE SELEÇÃO: SelectSearch
5482
+
5483
+ ### **SelectSearch** - Componente Unificado de Seleção
5484
+
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.
5486
+
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
+ ```
5522
+
5523
+ ---
5524
+
5525
+ ### **Exemplo 1: Seleção Única**
5526
+
5527
+ ```typescript
5528
+ import { SelectSearch } from 'forlogic-core';
5529
+
5530
+ function MyForm() {
5531
+ const [language, setLanguage] = useState<string>();
5532
+
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
+ ```
5549
+
5550
+ ---
5551
+
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
+ }
5576
+ ```
5577
+
5578
+ ---
5579
+
5580
+ ### **Exemplo 3: Dentro de Dialog** ⚠️ **CRÍTICO**
5581
+
5582
+ Para funcionar corretamente dentro de um Dialog, você **DEVE** passar o `popoverContainer`:
5583
+
5584
+ ```typescript
5585
+ import { SelectSearch, Dialog, DialogContent } from 'forlogic-core';
5586
+
5587
+ function MyDialog() {
5588
+ const [open, setOpen] = useState(false);
5589
+ const [category, setCategory] = useState<string>();
5590
+ const dialogContentRef = useRef<HTMLDivElement>(null);
5591
+
5592
+ return (
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 */}
5600
+ <SelectSearch
5601
+ options={categories}
5602
+ value={category}
5603
+ onChange={setCategory}
5604
+ placeholder="Selecione categoria"
5605
+ popoverContainer={dialogContentRef.current}
5606
+ />
5607
+ </div>
5608
+ </DialogContent>
5609
+ </Dialog>
5610
+ );
5611
+ }
5612
+ ```
5613
+
5614
+ ---
5615
+
5616
+ ### **⚠️ IMPORTANTE: Uso em Dialog**
5617
+
5618
+ **Configuração Correta:**
5619
+ ```tsx
5620
+ // 1. Ref no DialogContent
5621
+ const dialogContentRef = useRef<HTMLDivElement>(null);
5622
+
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
+ ```
5637
+
5638
+ **❌ Configurações Incorretas Comuns:**
5639
+
5640
+ ```tsx
5641
+ // ❌ ERRADO: Sem popoverContainer
5642
+ <SelectSearch options={data} value={value} onChange={onChange} />
5643
+
5644
+ // ❌ ERRADO: overflow-hidden no DialogContent
5645
+ <DialogContent className="overflow-hidden">
5646
+
5647
+ // ❌ ERRADO: Sem div interna com scroll
5648
+ <DialogContent className="overflow-visible">
5649
+ <SelectSearch {...props} />
5650
+ </DialogContent>
5651
+ ```
5652
+
5653
+ ---
5654
+
5655
+ ### **Características Avançadas**
5656
+
5657
+ #### **Busca Inteligente**
5658
+ - **Case-insensitive**: `react` encontra `React`
5659
+ - **Accent-insensitive**: `frances` encontra `Français`
5660
+ - **Busca em qualquer parte**: `script` encontra `TypeScript`
5661
+
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
5666
+
5667
+ #### **Estados**
5668
+ ```typescript
5669
+ // Loading
5670
+ <SelectSearch isLoading options={[]} />
5671
+
5672
+ // Erro
5673
+ <SelectSearch error="Falha ao carregar opções" options={[]} />
5674
+
5675
+ // Desabilitado
5676
+ <SelectSearch disabled options={data} />
5677
+ ```
5678
+
5679
+ ---
5680
+
5681
+ ### **Uso em BaseForm**
5682
+
5683
+ ```typescript
5684
+ import { BaseForm, SelectSearch } from 'forlogic-core';
5685
+
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
+ ```
5718
+
5719
+ ---
5720
+
5721
+ ### **Migração de MultiSelect e EntitySelect (DEPRECATED)**
5722
+
5723
+ ⚠️ **Estes componentes estão obsoletos. Use `SelectSearch` para todos os casos de seleção.**
5724
+
5725
+ **Migração de MultiSelect:**
5726
+
5727
+ ```typescript
5728
+ // ❌ ANTIGO: MultiSelect
5729
+ <MultiSelect
5730
+ options={data}
5731
+ value={selected}
5732
+ onChange={setSelected}
5733
+ />
5734
+
5735
+ // ✅ NOVO: SelectSearch
5736
+ <SelectSearch
5737
+ multiple
5738
+ options={data}
5739
+ value={selected}
5740
+ onChange={setSelected}
5741
+ />
5742
+ ```
5743
+
5744
+ **Migração de EntitySelect:**
5745
+
5746
+ ```typescript
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
+ />
5755
+
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
+ />
5764
+ ```
5765
+
5766
+ ---
5767
+
5462
5768
  ## 🔍 FILTROS NO BACKEND (Backend Filtering)
5463
5769
 
5464
5770
  ### **Por que Filtros no Backend?**
@@ -6051,4 +6357,4 @@ src/
6051
6357
 
6052
6358
  ## 📝 Licença
6053
6359
 
6054
- MIT License - ForLogic © 2025
6360
+ MIT License - ForLogic © 2025