forlogic-core 1.5.2 → 1.5.4

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.
@@ -1,275 +0,0 @@
1
- /**
2
- * TEMPLATE: Hook de Verificação de Permissão
3
- * 📚 Detalhes: Consulte docs/FOR_AI.md
4
- */
5
-
6
- import { usePermissionQuery } from 'forlogic-core';
7
- import { useAuth } from 'forlogic-core';
8
- import { supabase } from '@/integrations/supabase/client';
9
-
10
- // ============= EXEMPLO 1: Verificação Simples =============
11
-
12
- /**
13
- * Hook para verificar se o usuário tem acesso a uma funcionalidade específica
14
- */
15
- export const useFeatureAccess = () => {
16
- const { user, selectedUnit } = useAuth();
17
-
18
- return usePermissionQuery({
19
- key: 'feature-access',
20
- enabled: !!user && !!selectedUnit,
21
- checkFn: async () => {
22
- const { data } = await supabase
23
- .from('feature_permissions')
24
- .select('has_access')
25
- .eq('unit_alias', selectedUnit!.alias)
26
- .eq('feature_name', 'my-feature')
27
- .single();
28
-
29
- return data?.has_access || false;
30
- },
31
- staleTime: 30 * 60 * 1000, // 30 minutos
32
- gcTime: 35 * 60 * 1000
33
- });
34
- };
35
-
36
- // ============= EXEMPLO 2: Verificação com Service =============
37
-
38
- /**
39
- * Service para centralizar lógica de permissões
40
- */
41
- class PermissionService {
42
- async checkFeatureAccess(alias: string, feature: string): Promise<boolean> {
43
- const { data, error } = await supabase
44
- .rpc('check_feature_permission', {
45
- p_alias: alias,
46
- p_feature: feature
47
- });
48
-
49
- if (error) {
50
- console.error('Permission check error:', error);
51
- return false;
52
- }
53
-
54
- return data || false;
55
- }
56
- }
57
-
58
- const permissionService = new PermissionService();
59
-
60
- /**
61
- * Hook usando service
62
- */
63
- export const useAdvancedFeatureAccess = (featureName: string) => {
64
- const { user, selectedUnit } = useAuth();
65
-
66
- return usePermissionQuery({
67
- key: `feature-access-${featureName}`,
68
- enabled: !!user && !!selectedUnit,
69
- checkFn: () => permissionService.checkFeatureAccess(
70
- selectedUnit!.alias,
71
- featureName
72
- ),
73
- staleTime: 30 * 60 * 1000,
74
- gcTime: 35 * 60 * 1000
75
- });
76
- };
77
-
78
- // ============= EXEMPLO 3: Múltiplas Permissões =============
79
-
80
- /**
81
- * Hook para verificar múltiplas permissões de uma vez
82
- */
83
- export const useMultiplePermissions = (features: string[]) => {
84
- const { user, selectedUnit } = useAuth();
85
-
86
- return usePermissionQuery({
87
- key: `multi-permissions-${features.join('-')}`,
88
- enabled: !!user && !!selectedUnit && features.length > 0,
89
- checkFn: async () => {
90
- const { data } = await supabase
91
- .from('feature_permissions')
92
- .select('feature_name, has_access')
93
- .eq('unit_alias', selectedUnit!.alias)
94
- .in('feature_name', features);
95
-
96
- // Retorna true se todas as features têm acesso
97
- return data?.every(item => item.has_access) || false;
98
- },
99
- staleTime: 30 * 60 * 1000,
100
- gcTime: 35 * 60 * 1000
101
- });
102
- };
103
-
104
- // ============= USO NOS COMPONENTES =============
105
-
106
- /**
107
- * Exemplo 1: Proteger componente inteiro
108
- */
109
- function ProtectedComponent() {
110
- const { data: hasAccess, isLoading } = useFeatureAccess();
111
-
112
- if (isLoading) {
113
- return <div>Verificando permissões...</div>;
114
- }
115
-
116
- if (!hasAccess) {
117
- return <div>Acesso negado</div>;
118
- }
119
-
120
- return <div>Conteúdo protegido</div>;
121
- }
122
-
123
- /**
124
- * Exemplo 2: Proteger ação específica
125
- */
126
- function ComponentWithProtectedAction() {
127
- const { data: hasAccess } = useFeatureAccess();
128
-
129
- const handleSensitiveAction = () => {
130
- if (!hasAccess) {
131
- toast.error('Você não tem permissão para esta ação');
132
- return;
133
- }
134
-
135
- // Executar ação
136
- };
137
-
138
- return (
139
- <button
140
- onClick={handleSensitiveAction}
141
- disabled={!hasAccess}
142
- >
143
- Ação Sensível
144
- </button>
145
- );
146
- }
147
-
148
- /**
149
- * Exemplo 3: Condicional na UI
150
- */
151
- function ConditionalUI() {
152
- const { data: hasAccess } = useFeatureAccess();
153
-
154
- return (
155
- <div>
156
- <h1>Dashboard</h1>
157
-
158
- {/* Sempre visível */}
159
- <div>Conteúdo público</div>
160
-
161
- {/* Condicional */}
162
- {hasAccess && (
163
- <div>Conteúdo exclusivo</div>
164
- )}
165
- </div>
166
- );
167
- }
168
-
169
- // ============= INTEGRAÇÃO COM SIDEBAR =============
170
-
171
- import type { SidebarConfig } from 'forlogic-core';
172
- import { Settings, Package, Users } from 'lucide-react';
173
-
174
- /**
175
- * Configuração da sidebar com itens condicionais
176
- */
177
- export const sidebarConfig: SidebarConfig = {
178
- appName: 'Minha Aplicação',
179
- navigation: [
180
- // Item sempre visível
181
- {
182
- label: 'Dashboard',
183
- path: '/dashboard',
184
- icon: Settings,
185
- },
186
- // Item condicional com hook
187
- {
188
- label: 'Gestão',
189
- path: '/management',
190
- icon: Package,
191
- useAccessHook: useFeatureAccess // Hook de verificação
192
- },
193
- // Outro item condicional
194
- {
195
- label: 'Usuários',
196
- path: '/users',
197
- icon: Users,
198
- useAccessHook: () => useAdvancedFeatureAccess('users-management')
199
- }
200
- ]
201
- };
202
-
203
- // ============= CONFIGURAÇÃO DE CACHE =============
204
-
205
- /**
206
- * Recomendações de tempo de cache por tipo de permissão
207
- */
208
-
209
- // Permissões raramente alteradas (ex: roles, perfis)
210
- export const useRoleCheck = () => {
211
- return usePermissionQuery({
212
- // ...
213
- staleTime: 30 * 60 * 1000, // 30 minutos
214
- gcTime: 60 * 60 * 1000 // 1 hora
215
- });
216
- };
217
-
218
- // Permissões dinâmicas (ex: acesso temporário)
219
- export const useDynamicPermission = () => {
220
- return usePermissionQuery({
221
- // ...
222
- staleTime: 5 * 60 * 1000, // 5 minutos
223
- gcTime: 10 * 60 * 1000 // 10 minutos
224
- });
225
- };
226
-
227
- // Verificações críticas (ex: transações financeiras)
228
- export const useCriticalPermission = () => {
229
- return usePermissionQuery({
230
- // ...
231
- staleTime: 0, // Sem cache
232
- gcTime: 0 // Sem garbage collection
233
- });
234
- };
235
-
236
- // ============= INVALIDAÇÃO MANUAL (RARAMENTE NECESSÁRIA) =============
237
-
238
- import { useQueryClient } from '@tanstack/react-query';
239
-
240
- /**
241
- * Exemplo de invalidação manual (use apenas quando necessário)
242
- */
243
- function AdminPanel() {
244
- const queryClient = useQueryClient();
245
-
246
- const handlePermissionUpdate = async () => {
247
- // Atualizar permissão no backend
248
- await updatePermission();
249
-
250
- // Invalidar cache específico
251
- queryClient.invalidateQueries({
252
- queryKey: ['permission', 'feature-access']
253
- });
254
- };
255
-
256
- return <button onClick={handlePermissionUpdate}>Atualizar Permissão</button>;
257
- }
258
-
259
- // ============= BOAS PRÁTICAS =============
260
-
261
- /**
262
- * ✅ FAÇA:
263
- * - Use staleTime apropriado para cada tipo de permissão
264
- * - Sempre habilite apenas quando user e selectedUnit existirem
265
- * - Trate loading states nos componentes
266
- * - Use keys descritivas e únicas
267
- * - Centralize lógica em services quando complexa
268
- *
269
- * ❌ NÃO FAÇA:
270
- * - Não use staleTime muito longo para permissões críticas
271
- * - Não esqueça de desabilitar quando dependências faltam
272
- * - Não ignore estados de loading
273
- * - Não invalidate manualmente sem necessidade (AuthContext já faz)
274
- * - Não faça verificações síncronas de permissão
275
- */
@@ -1,137 +0,0 @@
1
- // ============= CONFIGURAÇÃO INICIAL QUALIEX =============
2
- // Copie este código para o arquivo principal da aplicação (main.tsx ou App.tsx)
3
-
4
- import { setQualiexConfig } from 'forlogic-core';
5
-
6
- // ============= 1. VARIÁVEIS DE AMBIENTE =============
7
- // Adicione no arquivo .env do projeto:
8
- /*
9
- VITE_QUALIEX_API_URL=https://common-v4-api.qualiex.com
10
- */
11
-
12
- // Configuração da integração
13
- // Execute no início da aplicação (antes de renderizar componentes)
14
-
15
- export function setupQualiexIntegration() {
16
- setQualiexConfig({
17
- // Enriquecimento automático de entidades com responsible_name
18
- enableUserEnrichment: true,
19
-
20
- // Habilitar API de usuários Qualiex
21
- enableUsersApi: true,
22
- });
23
- }
24
-
25
- // ============= 3. USO NO MAIN.TSX =============
26
- /*
27
- import { StrictMode } from 'react';
28
- import { createRoot } from 'react-dom/client';
29
- import { setupQualiexIntegration } from './config/qualiexConfig';
30
- import App from './App';
31
-
32
- // Configurar Qualiex ANTES de renderizar
33
- setupQualiexIntegration();
34
-
35
- createRoot(document.getElementById('root')!).render(
36
- <StrictMode>
37
- <App />
38
- </StrictMode>
39
- );
40
- */
41
-
42
- // ============= 4. EXPLICAÇÃO DAS OPÇÕES =============
43
-
44
- /**
45
- * enableUserEnrichment: boolean
46
- *
47
- * Quando true, o QualiexEnrichmentService adiciona automaticamente
48
- * o campo `responsible_name` às entidades que possuem `id_user`.
49
- *
50
- * Exemplo:
51
- * const tasks = await taskService.getAll();
52
- * // Se enableUserEnrichment: true
53
- * // tasks[0] = { id: '1', title: 'Tarefa', id_user: 'user-123', responsible_name: 'João Silva' }
54
- */
55
-
56
- /**
57
- * enableUsersApi: boolean
58
- *
59
- * Quando true, habilita chamadas à API de usuários Qualiex.
60
- * Necessário para usar useQualiexUsers e QualiexUserField.
61
- *
62
- * Se false, useQualiexUsers não fará requisições.
63
- */
64
-
65
- // ============= 5. EXEMPLO DE CONFIGURAÇÃO CONDICIONAL =============
66
- // Configure baseado no ambiente ou feature flags
67
-
68
- export function setupQualiexIntegrationConditional() {
69
- const isProduction = import.meta.env.PROD;
70
- const hasQualiexUrl = !!import.meta.env.VITE_QUALIEX_API_URL;
71
-
72
- setQualiexConfig({
73
- // Habilitar enriquecimento apenas em produção
74
- enableUserEnrichment: isProduction && hasQualiexUrl,
75
-
76
- // Habilitar API sempre que URL estiver configurada
77
- enableUsersApi: hasQualiexUrl,
78
- });
79
- }
80
-
81
- // ============= 6. VALIDAÇÃO DA CONFIGURAÇÃO =============
82
- // Helper para validar se Qualiex está configurado corretamente
83
-
84
- export function validateQualiexSetup() {
85
- const qualiexUrl = import.meta.env.VITE_QUALIEX_API_URL;
86
-
87
- if (!qualiexUrl) {
88
- console.warn(
89
- '⚠️ VITE_QUALIEX_API_URL não configurado. ' +
90
- 'Integração Qualiex não funcionará.'
91
- );
92
- return false;
93
- }
94
-
95
- console.log('✅ Integração Qualiex configurada:', qualiexUrl);
96
- return true;
97
- }
98
-
99
- // ============= 7. DESABILITAR INTEGRAÇÃO =============
100
- // Para desabilitar completamente a integração Qualiex
101
-
102
- export function disableQualiexIntegration() {
103
- setQualiexConfig({
104
- enableUserEnrichment: false,
105
- enableUsersApi: false,
106
- });
107
- }
108
-
109
- // ============= RESUMO =============
110
- /*
111
- PASSOS PARA CONFIGURAR:
112
-
113
- 1. Adicionar no .env:
114
- VITE_QUALIEX_API_URL=https://common-v4-api.qualiex.com
115
-
116
- 2. No main.tsx, antes de renderizar:
117
- import { setQualiexConfig } from 'forlogic-core';
118
-
119
- setQualiexConfig({
120
- enableUserEnrichment: true,
121
- enableUsersApi: true,
122
- });
123
-
124
- 3. Usar nos componentes:
125
- import { QualiexUserField, useQualiexUsers } from 'forlogic-core';
126
-
127
- ⚠️ IMPORTANTE:
128
- - setQualiexConfig deve ser chamado ANTES de usar componentes Qualiex
129
- - VITE_QUALIEX_API_URL deve existir no .env
130
- - A autenticação é feita automaticamente via TokenManager
131
- - O header un-alias é adicionado automaticamente
132
-
133
- ✅ VERIFICAR SE ESTÁ FUNCIONANDO:
134
- - useQualiexUsers deve retornar lista de usuários
135
- - QualiexUserField deve mostrar loading e depois lista
136
- - Console não deve mostrar erros 401/403
137
- */