forlogic-core 1.17.4 → 1.20.0
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/.note/memory/patterns/alias-url-resolution.md +28 -12
- package/dist/auth/components/AliasRouteGuard.d.ts +8 -13
- package/dist/components/layout/AppHeader.d.ts +0 -57
- package/dist/components/layout/SidebarLogo.d.ts +5 -0
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.esm.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -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/...`).
|
|
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,31 @@ 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
|
|
25
|
+
Wrapper de rota com **1 effect de decisão** (sem heurísticas de origem):
|
|
16
26
|
|
|
17
27
|
| Cenário | Ação |
|
|
18
28
|
|---------|------|
|
|
19
29
|
| Alias ausente na URL | Redireciona para `/{aliasAtivo}/{path}` |
|
|
20
|
-
| Alias
|
|
21
|
-
| Alias diferente do ativo
|
|
30
|
+
| Alias inválido | Redireciona para `/{aliasAtivo}/{path}` |
|
|
31
|
+
| Alias válido e diferente do ativo | Chama `switchUnit()` |
|
|
22
32
|
| Alias correto | Renderiza children |
|
|
23
|
-
| Alias inválido | Redireciona para `/{aliasDefault}/{path}` |
|
|
24
|
-
| Troca via seletor de unidades | Atualiza URL automaticamente |
|
|
25
33
|
|
|
26
|
-
|
|
34
|
+
Proteção de concorrência: `switchingRef` evita chamadas duplicadas no mesmo ciclo.
|
|
35
|
+
|
|
36
|
+
### `AppHeader` (mudança de unidade)
|
|
27
37
|
|
|
28
|
-
O
|
|
38
|
+
O header usa `navigate()` para trocar o segmento de alias na URL:
|
|
29
39
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
40
|
+
```tsx
|
|
41
|
+
const handleUnitChangeNavigate = (company) => {
|
|
42
|
+
const segments = pathname.split('/');
|
|
43
|
+
const aliasIndex = segments.indexOf(alias);
|
|
44
|
+
segments[aliasIndex] = company.alias;
|
|
45
|
+
navigate(segments.join('/') + search + hash);
|
|
46
|
+
};
|
|
33
47
|
|
|
34
|
-
|
|
48
|
+
<UserInfo onUnitChange={handleUnitChangeNavigate} />
|
|
49
|
+
```
|
|
35
50
|
|
|
36
51
|
## Uso nos Consumidores
|
|
37
52
|
|
|
@@ -48,3 +63,4 @@ O ref é atualizado **sempre** no Effect 3 (fora do condicional de navegação),
|
|
|
48
63
|
- Se `switchUnit` falha, mantém alias atual (sem loop)
|
|
49
64
|
- `switchUnit` já faz `queryClient.clear()` — cache é limpo automaticamente
|
|
50
65
|
- Navegação inter-módulos já usa `{alias}` nas URLs (`modulesData.ts`)
|
|
66
|
+
- **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
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
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
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
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
|
}
|