forlogic-core 1.17.4 → 1.20.1

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.
@@ -2,7 +2,17 @@
2
2
 
3
3
  ## Padrão
4
4
 
5
- O alias da unidade ativa deve **sempre** estar presente na URL como primeiro segmento de rota (`/:alias/...`). O `AliasRouteGuard` garante sincronização bidirecional entre URL e sessão.
5
+ O alias da unidade ativa deve **sempre** estar presente na URL como primeiro segmento de rota (`/:alias/...`). A **URL é a fonte única de verdade** para o alias ativo.
6
+
7
+ ## Arquitetura (URL como Source of Truth)
8
+
9
+ ```
10
+ Header/Seletor → navigate(/{novoAlias}/...) → URL muda → AliasRouteGuard → switchUnit()
11
+ ```
12
+
13
+ - **Header/UI**: Apenas navega (muda a URL). Nunca chama `switchUnit` diretamente.
14
+ - **AliasRouteGuard**: Detecta que `urlAlias !== activeAlias` e chama `switchUnit()` para sincronizar a sessão.
15
+ - **Resultado**: Um único writer (guard) controla a sessão, eliminando race conditions.
6
16
 
7
17
  ## Componentes
8
18
 
@@ -12,26 +22,34 @@ Hook que extrai o alias do param de rota e valida contra `companies` do `useAuth
12
22
  Retorna: `{ urlAlias, isAliasMismatch, isValidAlias, isMissing, matchedCompany }`
13
23
 
14
24
  ### `AliasRouteGuard`
15
- Wrapper de rota que sincroniza alias da URL com a sessão. Comportamento:
25
+ Wrapper de rota com **auto-detect de modo**:
16
26
 
17
- | Cenário | Ação |
27
+ - **Modo URL** (`:alias` presente na rota): comportamento padrão com 1 effect de decisão
28
+ - **Modo Legado** (sem `:alias` na rota): passthrough transparente, sem redirects
29
+
30
+ | Cenário (Modo URL) | Ação |
18
31
  |---------|------|
19
32
  | Alias ausente na URL | Redireciona para `/{aliasAtivo}/{path}` |
20
- | Alias diferente do ativo (navegação URL) | Chama `switchUnit()` + loading |
21
- | Alias diferente do ativo (troca via seletor) | Atualiza URL (Effect 3), **não** chama `switchUnit()` |
33
+ | Alias inválido | Redireciona para `/{aliasAtivo}/{path}` |
34
+ | Alias válido e diferente do ativo | Chama `switchUnit()` |
22
35
  | Alias correto | Renderiza children |
23
- | Alias inválido | Redireciona para `/{aliasDefault}/{path}` |
24
- | Troca via seletor de unidades | Atualiza URL automaticamente |
25
36
 
26
- #### Distinção seletor vs. navegação via URL
37
+ Proteção de concorrência: `switchingRef` evita chamadas duplicadas no mesmo ciclo.
38
+
39
+ ### `AppHeader` (mudança de unidade)
27
40
 
28
- O guard usa `prevActiveAliasRef` para distinguir a origem do mismatch:
41
+ O header usa `navigate()` para trocar o segmento de alias na URL:
29
42
 
30
- - **`prevActiveAliasRef.current === null`** → primeiro carregamento (auth ainda inicializando). Effect 2 prossegue normalmente.
31
- - **`prevActiveAliasRef.current !== null` e `activeAlias !== prevRef`** → `activeAlias` acabou de mudar (troca via seletor). Effect 2 é **pulado** (Effect 3 sincroniza a URL).
32
- - **`prevActiveAliasRef.current !== null` e `activeAlias === prevRef`** → `activeAlias` não mudou, mismatch veio da URL. Effect 2 chama `switchUnit()`.
43
+ ```tsx
44
+ const handleUnitChangeNavigate = (company) => {
45
+ const segments = pathname.split('/');
46
+ const aliasIndex = segments.indexOf(alias);
47
+ segments[aliasIndex] = company.alias;
48
+ navigate(segments.join('/') + search + hash);
49
+ };
33
50
 
34
- O ref é atualizado **sempre** no Effect 3 (fora do condicional de navegação), garantindo que está sincronizado após qualquer mudança de `activeAlias`.
51
+ <UserInfo onUnitChange={handleUnitChangeNavigate} />
52
+ ```
35
53
 
36
54
  ## Uso nos Consumidores
37
55
 
@@ -48,3 +66,4 @@ O ref é atualizado **sempre** no Effect 3 (fora do condicional de navegação),
48
66
  - Se `switchUnit` falha, mantém alias atual (sem loop)
49
67
  - `switchUnit` já faz `queryClient.clear()` — cache é limpo automaticamente
50
68
  - Navegação inter-módulos já usa `{alias}` nas URLs (`modulesData.ts`)
69
+ - **Header/seletor NUNCA chama switchUnit diretamente** — apenas navega
@@ -7,19 +7,14 @@ export interface AliasRouteGuardProps {
7
7
  /**
8
8
  * Guard de rota que sincroniza o alias da URL com a sessão de autenticação.
9
9
  *
10
- * Comportamento:
11
- * - **Alias ausente na URL** Redireciona para `/{aliasAtivo}/{restoDoPath}` (replace)
12
- * - **Alias presente mas diferente do ativo** → Chama `switchUnit()` + loading
13
- * - **Alias presente e correto** → Renderiza children
14
- * - **Alias inválido (não existe em companies)** → Redireciona para `/{aliasDefault}/{restoDoPath}`
15
- * - **Troca via seletor de unidades** → Atualiza URL automaticamente
10
+ * A URL é a fonte única de verdade para o alias ativo.
11
+ * O header/seletor de unidade apenas navega para a nova URL;
12
+ * este guard detecta a mudança e chama switchUnit() para sincronizar a sessão.
16
13
  *
17
- * @example
18
- * ```tsx
19
- * <Route element={<AliasRouteGuard><Outlet /></AliasRouteGuard>}>
20
- * <Route path="/:alias/documents" element={<DocumentsPage />} />
21
- * <Route path="/:alias/documents/:id" element={<DocumentDetailPage />} />
22
- * </Route>
23
- * ```
14
+ * Fluxo determinístico (1 effect):
15
+ * - Alias ausente na URL → redirect para /{aliasAtivo}/...
16
+ * - Alias inválido → redirect para /{aliasAtivo}/...
17
+ * - Alias válido e diferente do ativo → switchUnit(matchedCompany)
18
+ * - Alias correto → renderiza children
24
19
  */
25
20
  export declare function AliasRouteGuard({ children, paramName }: AliasRouteGuardProps): import("react/jsx-runtime").JSX.Element;
@@ -1,61 +1,4 @@
1
1
  import React from 'react';
2
- /**
3
- * AppHeader Component
4
- *
5
- * Header principal da aplicação com:
6
- * - Título e subtítulo da página
7
- * - Busca global integrada ao CRUD
8
- * - Botão de refresh
9
- * - Informações do usuário e seleção de unidade
10
- *
11
- * @example
12
- * ```tsx
13
- * <AppHeader actions={<Button>Nova Ação</Button>} />
14
- * ```
15
- *
16
- * ## 🔍 Busca Global
17
- *
18
- * A busca é exibida automaticamente quando `isSearchVisible = true` no AuthContext.
19
- *
20
- * **Características:**
21
- * - ⏱️ Debounce de 500ms (configurável via SEARCH_CONFIG.debounceDelay)
22
- * - 🔗 Sincroniza com URL (?search=termo)
23
- * - ♻️ Reset automático para página 1 ao buscar
24
- * - 🎯 Integração automática com useCrud
25
- *
26
- * **Configurar campos pesquisáveis:**
27
- * ```typescript
28
- * // No service
29
- * createSimpleService({
30
- * tableName: 'items',
31
- * searchFields: ['name', 'description', 'code'], // 🔍 Campos de busca
32
- * });
33
- * ```
34
- *
35
- * **Customizar placeholder:**
36
- * ```tsx
37
- * // Opção 1: Modificar diretamente no AppHeader (linha ~102)
38
- * <Input placeholder="Buscar artigos..." />
39
- *
40
- * // Opção 2: Por rota (já implementado)
41
- * location.pathname === '/wiki' ? "Buscar artigos..." : "Buscar..."
42
- * ```
43
- *
44
- * **Controle programático:**
45
- * ```typescript
46
- * const [searchParams, setSearchParams] = useSearchParams();
47
- *
48
- * // Definir busca
49
- * const newParams = new URLSearchParams(searchParams);
50
- * newParams.set('search', 'termo');
51
- * newParams.set('page', '1');
52
- * setSearchParams(newParams);
53
- *
54
- * // Limpar busca
55
- * newParams.delete('search');
56
- * setSearchParams(newParams);
57
- * ```
58
- */
59
2
  interface AppHeaderProps {
60
3
  actions?: React.ReactNode;
61
4
  }
@@ -0,0 +1,5 @@
1
+ interface SidebarLogoProps {
2
+ appName?: string;
3
+ }
4
+ export declare function SidebarLogo({ appName }: SidebarLogoProps): import("react/jsx-runtime").JSX.Element;
5
+ export {};