forlogic-core 2.1.3 → 2.1.5
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/features/import/attachment-idempotency-registry.md +8 -8
- package/.note/memory/features/import/attachment-strategy.md +30 -30
- package/.note/memory/patterns/admin-i18n-policy.md +20 -20
- package/.note/memory/patterns/alias-url-resolution.md +69 -69
- package/.note/memory/patterns/doc-sync-rule.md +35 -35
- package/.note/memory/patterns/documentation-standard.md +17 -17
- package/.note/memory/patterns/dynamic-supabase-config.md +4 -4
- package/.note/memory/patterns/environment-detection-logic.md +35 -35
- package/.note/memory/patterns/i18n-architecture.md +3 -3
- package/README.md +68 -68
- package/dist/action-plans/components/ActionPlanStatusBadge.d.ts +6 -2
- package/dist/components/ui/__tests__/status-badge.test.d.ts +1 -0
- package/dist/components/ui/status-badge.d.ts +49 -0
- package/dist/crud/primitives/Table.d.ts +1 -1
- package/dist/crud/primitives/types.d.ts +6 -0
- package/dist/exports/crud.d.ts +5 -0
- package/dist/exports/ui.d.ts +1 -0
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.js +1 -1
- package/dist/utils/color.d.ts +26 -0
- package/dist/utils/index.d.ts +1 -0
- package/docs/PUBLISH.md +168 -0
- package/docs/WORKSPACE_KNOWLEDGE.md +119 -119
- package/docs/design-system/README.md +1 -1
- package/docs/design-system/buttons-actions.md +130 -130
- package/docs/design-system/charts-dashboards.md +340 -301
- package/docs/design-system/crud.md +174 -114
- package/docs/design-system/data-display.md +108 -103
- package/docs/design-system/dialogs.md +212 -212
- package/docs/design-system/domain.md +317 -317
- package/docs/design-system/examples.md +275 -275
- package/docs/design-system/foundation.md +1 -1
- package/docs/design-system/inputs.md +131 -131
- package/docs/design-system/layout.md +202 -154
- package/docs/design-system/navigation.md +271 -325
- package/docs/design-system/notifications-feedback.md +34 -34
- package/docs/design-system/patterns/README.md +53 -53
- package/docs/design-system/patterns/action-button.md +22 -22
- package/docs/design-system/patterns/alertdialog-deletion.md +46 -46
- package/docs/design-system/patterns/baseform-custom-fields.md +59 -59
- package/docs/design-system/patterns/baseform-usage.md +42 -42
- package/docs/design-system/patterns/body-content-scroll.md +56 -56
- package/docs/design-system/patterns/combo-tree.md +23 -23
- package/docs/design-system/patterns/components-registry.md +17 -17
- package/docs/design-system/patterns/core-providers.md +39 -39
- package/docs/design-system/patterns/crud-bulk-actions.md +12 -12
- package/docs/design-system/patterns/crud-config-props.md +16 -16
- package/docs/design-system/patterns/crud-defaults.md +17 -17
- package/docs/design-system/patterns/crud-toolbar.md +28 -28
- package/docs/design-system/patterns/delete-confirmation.md +40 -40
- package/docs/design-system/patterns/dialog-body-scroll.md +26 -26
- package/docs/design-system/patterns/dialog-structure.md +32 -32
- package/docs/design-system/patterns/dialog-variants.md +41 -41
- package/docs/design-system/patterns/feature-flags.md +24 -20
- package/docs/design-system/patterns/header-metadata.md +57 -57
- package/docs/design-system/patterns/i18n-setup.md +117 -117
- package/docs/design-system/patterns/pagination.md +27 -27
- package/docs/design-system/patterns/single-scroll.md +39 -39
- package/docs/design-system/patterns/vite-tailwind-setup.md +48 -48
- package/docs/design-system/platform.md +18 -18
- package/docs/design-system/selectors.md +236 -236
- package/docs/design-system/tables-grids.md +95 -38
- package/package.json +144 -144
- package/dist/README.md +0 -1079
- package/dist/bin/bootstrap.js +0 -40
- package/dist/bin/pull-docs.js +0 -186
- package/dist/docs/KNOWLEDGE.md +0 -109
|
@@ -1,275 +1,275 @@
|
|
|
1
|
-
# Golden Snippets — Exemplos Completos do Design System
|
|
2
|
-
|
|
3
|
-
> Implementações de referência para a IA copiar e adaptar.
|
|
4
|
-
> Cada snippet é funcional e segue 100% dos padrões do DS.
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## 1. CRUD Completo com createCrudPage
|
|
9
|
-
|
|
10
|
-
```tsx
|
|
11
|
-
// src/pages/ProcessesPage.tsx
|
|
12
|
-
import { createSimpleService, createCrudPage, usePageMetadata } from 'forlogic-core';
|
|
13
|
-
|
|
14
|
-
const processService = createSimpleService({
|
|
15
|
-
tableName: 'processes',
|
|
16
|
-
schema: 'quality',
|
|
17
|
-
entityName: 'processo',
|
|
18
|
-
searchFields: ['title', 'description'],
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
const ProcessesPage = createCrudPage({
|
|
22
|
-
title: 'Processos',
|
|
23
|
-
service: processService,
|
|
24
|
-
columns: [
|
|
25
|
-
{ key: 'title', header: 'Título' },
|
|
26
|
-
{ key: 'status', header: 'Status' },
|
|
27
|
-
{ key: 'responsible', header: 'Responsável' },
|
|
28
|
-
{ key: 'updated_at', header: 'Atualizado em', format: 'datetime' },
|
|
29
|
-
],
|
|
30
|
-
formSections: [{
|
|
31
|
-
id: 'main',
|
|
32
|
-
fields: [
|
|
33
|
-
{ name: 'title', label: 'Título', type: 'text', required: true },
|
|
34
|
-
{ name: 'description', label: 'Descrição', type: 'textarea' },
|
|
35
|
-
{ name: 'status', label: 'Status', type: 'combobox', options: [
|
|
36
|
-
{ value: 'active', label: 'Ativo' },
|
|
37
|
-
{ value: 'inactive', label: 'Inativo' },
|
|
38
|
-
]},
|
|
39
|
-
{ name: 'id_responsible', label: 'Responsável', type: 'combobox', entity: 'users' },
|
|
40
|
-
],
|
|
41
|
-
}],
|
|
42
|
-
actions: [
|
|
43
|
-
{ label: 'Editar', action: 'edit' },
|
|
44
|
-
{ label: 'Inativar', action: 'toggle-status', confirm: true },
|
|
45
|
-
],
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
export default ProcessesPage;
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
---
|
|
52
|
-
|
|
53
|
-
## 2. CrudTable Customizado com ActionButton
|
|
54
|
-
|
|
55
|
-
```tsx
|
|
56
|
-
// src/pages/DocumentsPage.tsx
|
|
57
|
-
import {
|
|
58
|
-
CrudTable, CrudActionBar, ActionButton, Badge,
|
|
59
|
-
usePageMetadata, useTranslation, getSupabaseClient,
|
|
60
|
-
} from 'forlogic-core';
|
|
61
|
-
|
|
62
|
-
export function DocumentsPage() {
|
|
63
|
-
const { t } = useTranslation();
|
|
64
|
-
usePageMetadata({ title: t('documents'), subtitle: t('documents_subtitle') });
|
|
65
|
-
|
|
66
|
-
const columns = [
|
|
67
|
-
{ key: 'name', header: 'Nome' },
|
|
68
|
-
{
|
|
69
|
-
key: 'status',
|
|
70
|
-
header: 'Status',
|
|
71
|
-
cell: (row) => (
|
|
72
|
-
<Badge variant={row.status === 'approved' ? 'default' : 'secondary'}>
|
|
73
|
-
{row.status}
|
|
74
|
-
</Badge>
|
|
75
|
-
),
|
|
76
|
-
},
|
|
77
|
-
{ key: 'version', header: 'Versão' },
|
|
78
|
-
{
|
|
79
|
-
key: 'actions',
|
|
80
|
-
header: '',
|
|
81
|
-
cell: (row) => (
|
|
82
|
-
<ActionButton
|
|
83
|
-
actions={[
|
|
84
|
-
{ label: 'Editar', onClick: () => handleEdit(row) },
|
|
85
|
-
{ label: 'Duplicar', onClick: () => handleDuplicate(row) },
|
|
86
|
-
{ label: 'Inativar', onClick: () => handleDeactivate(row), variant: 'destructive' },
|
|
87
|
-
]}
|
|
88
|
-
/>
|
|
89
|
-
),
|
|
90
|
-
},
|
|
91
|
-
];
|
|
92
|
-
|
|
93
|
-
return (
|
|
94
|
-
<div className="p-6 space-y-4">
|
|
95
|
-
<CrudActionBar
|
|
96
|
-
onAdd={() => setDialogOpen(true)}
|
|
97
|
-
addLabel="Novo Documento"
|
|
98
|
-
showSearch
|
|
99
|
-
/>
|
|
100
|
-
<CrudTable columns={columns} data={documents} />
|
|
101
|
-
</div>
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
---
|
|
107
|
-
|
|
108
|
-
## 3. Layout com AppLayout + Sidebar + Separador
|
|
109
|
-
|
|
110
|
-
```tsx
|
|
111
|
-
// src/App.tsx
|
|
112
|
-
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
|
113
|
-
import { CoreProviders, AppLayout } from 'forlogic-core';
|
|
114
|
-
import { Home, FileText, Settings, BarChart3 } from 'lucide-react';
|
|
115
|
-
import ptBR from './i18n/pt-BR.json';
|
|
116
|
-
|
|
117
|
-
const sidebarConfig = {
|
|
118
|
-
navigation: [
|
|
119
|
-
{ label: 'Início', path: '/', icon: Home },
|
|
120
|
-
{ label: 'Documentos', path: '/documents', icon: FileText },
|
|
121
|
-
{ label: 'Relatórios', path: '/reports', icon: BarChart3 },
|
|
122
|
-
{ type: 'separator' as const, label: '', path: '' },
|
|
123
|
-
{ label: 'Configurações', path: '/settings', icon: Settings },
|
|
124
|
-
],
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
export default function App() {
|
|
128
|
-
return (
|
|
129
|
-
<CoreProviders moduleAlias="quality" appTranslations={{ 'pt-BR': ptBR }}>
|
|
130
|
-
<BrowserRouter>
|
|
131
|
-
<AppLayout sidebarConfig={sidebarConfig}>
|
|
132
|
-
<Routes>
|
|
133
|
-
<Route path="/" element={<HomePage />} />
|
|
134
|
-
<Route path="/documents" element={<DocumentsPage />} />
|
|
135
|
-
</Routes>
|
|
136
|
-
</AppLayout>
|
|
137
|
-
</BrowserRouter>
|
|
138
|
-
</CoreProviders>
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
---
|
|
144
|
-
|
|
145
|
-
## 4. Formulário com Dialog + BaseForm + Combobox
|
|
146
|
-
|
|
147
|
-
```tsx
|
|
148
|
-
// src/components/ProcessForm.tsx
|
|
149
|
-
import {
|
|
150
|
-
Dialog, DialogContent, DialogHeader, DialogTitle,
|
|
151
|
-
Input, Label, Combobox, Button,
|
|
152
|
-
useTranslation,
|
|
153
|
-
} from 'forlogic-core';
|
|
154
|
-
import { useForm } from 'react-hook-form';
|
|
155
|
-
import { zodResolver } from '@hookform/resolvers/zod';
|
|
156
|
-
import { z } from 'zod';
|
|
157
|
-
|
|
158
|
-
const schema = z.object({
|
|
159
|
-
title: z.string().min(3, 'Mínimo 3 caracteres'),
|
|
160
|
-
status: z.string(),
|
|
161
|
-
id_responsible: z.string().uuid(),
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
type FormData = z.infer<typeof schema>;
|
|
165
|
-
|
|
166
|
-
interface ProcessFormProps {
|
|
167
|
-
open: boolean;
|
|
168
|
-
onOpenChange: (open: boolean) => void;
|
|
169
|
-
onSubmit: (data: FormData) => void;
|
|
170
|
-
defaultValues?: Partial<FormData>;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
export function ProcessForm({ open, onOpenChange, onSubmit, defaultValues }: ProcessFormProps) {
|
|
174
|
-
const { t } = useTranslation();
|
|
175
|
-
const form = useForm<FormData>({
|
|
176
|
-
resolver: zodResolver(schema),
|
|
177
|
-
defaultValues,
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
return (
|
|
181
|
-
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
182
|
-
<DialogContent>
|
|
183
|
-
<DialogHeader>
|
|
184
|
-
<DialogTitle>{defaultValues ? t('edit') : t('create')}</DialogTitle>
|
|
185
|
-
</DialogHeader>
|
|
186
|
-
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
|
187
|
-
<div className="space-y-2">
|
|
188
|
-
<Label htmlFor="title">{t('title')}</Label>
|
|
189
|
-
<Input id="title" {...form.register('title')} />
|
|
190
|
-
</div>
|
|
191
|
-
<div className="space-y-2">
|
|
192
|
-
<Label>{t('status')}</Label>
|
|
193
|
-
<Combobox
|
|
194
|
-
options={[
|
|
195
|
-
{ value: 'active', label: 'Ativo' },
|
|
196
|
-
{ value: 'inactive', label: 'Inativo' },
|
|
197
|
-
]}
|
|
198
|
-
value={form.watch('status')}
|
|
199
|
-
onValueChange={(v) => form.setValue('status', v)}
|
|
200
|
-
/>
|
|
201
|
-
</div>
|
|
202
|
-
<div className="flex justify-end gap-2">
|
|
203
|
-
<Button variant="outline" onClick={() => onOpenChange(false)}>{t('cancel')}</Button>
|
|
204
|
-
<Button type="submit">{t('save')}</Button>
|
|
205
|
-
</div>
|
|
206
|
-
</form>
|
|
207
|
-
</DialogContent>
|
|
208
|
-
</Dialog>
|
|
209
|
-
);
|
|
210
|
-
}
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
---
|
|
214
|
-
|
|
215
|
-
## 5. Supabase com Schema Correto
|
|
216
|
-
|
|
217
|
-
```tsx
|
|
218
|
-
// src/services/processService.ts
|
|
219
|
-
import { getSupabaseClient } from 'forlogic-core';
|
|
220
|
-
|
|
221
|
-
const SCHEMA = 'quality';
|
|
222
|
-
|
|
223
|
-
export async function fetchProcesses() {
|
|
224
|
-
const supabase = getSupabaseClient();
|
|
225
|
-
const { data, error } = await supabase
|
|
226
|
-
.schema(SCHEMA)
|
|
227
|
-
.from('processes')
|
|
228
|
-
.select('*')
|
|
229
|
-
.is('deleted_at', null)
|
|
230
|
-
.order('created_at', { ascending: false });
|
|
231
|
-
|
|
232
|
-
if (error) throw error;
|
|
233
|
-
return data;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
export async function softDeleteProcess(id: string) {
|
|
237
|
-
const supabase = getSupabaseClient();
|
|
238
|
-
const { error } = await supabase
|
|
239
|
-
.schema(SCHEMA)
|
|
240
|
-
.from('processes')
|
|
241
|
-
.update({ deleted_at: new Date().toISOString() })
|
|
242
|
-
.eq('id', id);
|
|
243
|
-
|
|
244
|
-
if (error) throw error;
|
|
245
|
-
}
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
---
|
|
249
|
-
|
|
250
|
-
## 6. Página com usePageMetadata + Breadcrumbs
|
|
251
|
-
|
|
252
|
-
```tsx
|
|
253
|
-
// src/pages/ProcessDetailPage.tsx
|
|
254
|
-
import { usePageMetadata } from 'forlogic-core';
|
|
255
|
-
import { useParams } from 'react-router-dom';
|
|
256
|
-
|
|
257
|
-
export function ProcessDetailPage() {
|
|
258
|
-
const { id } = useParams();
|
|
259
|
-
|
|
260
|
-
usePageMetadata({
|
|
261
|
-
title: 'Detalhes do Processo',
|
|
262
|
-
subtitle: 'Visualize e edite os dados do processo',
|
|
263
|
-
breadcrumbs: [
|
|
264
|
-
{ label: 'Processos', href: '/processes' },
|
|
265
|
-
{ label: 'Detalhes' },
|
|
266
|
-
],
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
return (
|
|
270
|
-
<div className="p-6">
|
|
271
|
-
{/* conteúdo da página */}
|
|
272
|
-
</div>
|
|
273
|
-
);
|
|
274
|
-
}
|
|
275
|
-
```
|
|
1
|
+
# Golden Snippets — Exemplos Completos do Design System
|
|
2
|
+
|
|
3
|
+
> Implementações de referência para a IA copiar e adaptar.
|
|
4
|
+
> Cada snippet é funcional e segue 100% dos padrões do DS.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 1. CRUD Completo com createCrudPage
|
|
9
|
+
|
|
10
|
+
```tsx
|
|
11
|
+
// src/pages/ProcessesPage.tsx
|
|
12
|
+
import { createSimpleService, createCrudPage, usePageMetadata } from 'forlogic-core';
|
|
13
|
+
|
|
14
|
+
const processService = createSimpleService({
|
|
15
|
+
tableName: 'processes',
|
|
16
|
+
schema: 'quality',
|
|
17
|
+
entityName: 'processo',
|
|
18
|
+
searchFields: ['title', 'description'],
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const ProcessesPage = createCrudPage({
|
|
22
|
+
title: 'Processos',
|
|
23
|
+
service: processService,
|
|
24
|
+
columns: [
|
|
25
|
+
{ key: 'title', header: 'Título' },
|
|
26
|
+
{ key: 'status', header: 'Status' },
|
|
27
|
+
{ key: 'responsible', header: 'Responsável' },
|
|
28
|
+
{ key: 'updated_at', header: 'Atualizado em', format: 'datetime' },
|
|
29
|
+
],
|
|
30
|
+
formSections: [{
|
|
31
|
+
id: 'main',
|
|
32
|
+
fields: [
|
|
33
|
+
{ name: 'title', label: 'Título', type: 'text', required: true },
|
|
34
|
+
{ name: 'description', label: 'Descrição', type: 'textarea' },
|
|
35
|
+
{ name: 'status', label: 'Status', type: 'combobox', options: [
|
|
36
|
+
{ value: 'active', label: 'Ativo' },
|
|
37
|
+
{ value: 'inactive', label: 'Inativo' },
|
|
38
|
+
]},
|
|
39
|
+
{ name: 'id_responsible', label: 'Responsável', type: 'combobox', entity: 'users' },
|
|
40
|
+
],
|
|
41
|
+
}],
|
|
42
|
+
actions: [
|
|
43
|
+
{ label: 'Editar', action: 'edit' },
|
|
44
|
+
{ label: 'Inativar', action: 'toggle-status', confirm: true },
|
|
45
|
+
],
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
export default ProcessesPage;
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## 2. CrudTable Customizado com ActionButton
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
// src/pages/DocumentsPage.tsx
|
|
57
|
+
import {
|
|
58
|
+
CrudTable, CrudActionBar, ActionButton, Badge,
|
|
59
|
+
usePageMetadata, useTranslation, getSupabaseClient,
|
|
60
|
+
} from 'forlogic-core';
|
|
61
|
+
|
|
62
|
+
export function DocumentsPage() {
|
|
63
|
+
const { t } = useTranslation();
|
|
64
|
+
usePageMetadata({ title: t('documents'), subtitle: t('documents_subtitle') });
|
|
65
|
+
|
|
66
|
+
const columns = [
|
|
67
|
+
{ key: 'name', header: 'Nome' },
|
|
68
|
+
{
|
|
69
|
+
key: 'status',
|
|
70
|
+
header: 'Status',
|
|
71
|
+
cell: (row) => (
|
|
72
|
+
<Badge variant={row.status === 'approved' ? 'default' : 'secondary'}>
|
|
73
|
+
{row.status}
|
|
74
|
+
</Badge>
|
|
75
|
+
),
|
|
76
|
+
},
|
|
77
|
+
{ key: 'version', header: 'Versão' },
|
|
78
|
+
{
|
|
79
|
+
key: 'actions',
|
|
80
|
+
header: '',
|
|
81
|
+
cell: (row) => (
|
|
82
|
+
<ActionButton
|
|
83
|
+
actions={[
|
|
84
|
+
{ label: 'Editar', onClick: () => handleEdit(row) },
|
|
85
|
+
{ label: 'Duplicar', onClick: () => handleDuplicate(row) },
|
|
86
|
+
{ label: 'Inativar', onClick: () => handleDeactivate(row), variant: 'destructive' },
|
|
87
|
+
]}
|
|
88
|
+
/>
|
|
89
|
+
),
|
|
90
|
+
},
|
|
91
|
+
];
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<div className="p-6 space-y-4">
|
|
95
|
+
<CrudActionBar
|
|
96
|
+
onAdd={() => setDialogOpen(true)}
|
|
97
|
+
addLabel="Novo Documento"
|
|
98
|
+
showSearch
|
|
99
|
+
/>
|
|
100
|
+
<CrudTable columns={columns} data={documents} />
|
|
101
|
+
</div>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## 3. Layout com AppLayout + Sidebar + Separador
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
// src/App.tsx
|
|
112
|
+
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
|
113
|
+
import { CoreProviders, AppLayout } from 'forlogic-core';
|
|
114
|
+
import { Home, FileText, Settings, BarChart3 } from 'lucide-react';
|
|
115
|
+
import ptBR from './i18n/pt-BR.json';
|
|
116
|
+
|
|
117
|
+
const sidebarConfig = {
|
|
118
|
+
navigation: [
|
|
119
|
+
{ label: 'Início', path: '/', icon: Home },
|
|
120
|
+
{ label: 'Documentos', path: '/documents', icon: FileText },
|
|
121
|
+
{ label: 'Relatórios', path: '/reports', icon: BarChart3 },
|
|
122
|
+
{ type: 'separator' as const, label: '', path: '' },
|
|
123
|
+
{ label: 'Configurações', path: '/settings', icon: Settings },
|
|
124
|
+
],
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export default function App() {
|
|
128
|
+
return (
|
|
129
|
+
<CoreProviders moduleAlias="quality" appTranslations={{ 'pt-BR': ptBR }}>
|
|
130
|
+
<BrowserRouter>
|
|
131
|
+
<AppLayout sidebarConfig={sidebarConfig}>
|
|
132
|
+
<Routes>
|
|
133
|
+
<Route path="/" element={<HomePage />} />
|
|
134
|
+
<Route path="/documents" element={<DocumentsPage />} />
|
|
135
|
+
</Routes>
|
|
136
|
+
</AppLayout>
|
|
137
|
+
</BrowserRouter>
|
|
138
|
+
</CoreProviders>
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## 4. Formulário com Dialog + BaseForm + Combobox
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
// src/components/ProcessForm.tsx
|
|
149
|
+
import {
|
|
150
|
+
Dialog, DialogContent, DialogHeader, DialogTitle,
|
|
151
|
+
Input, Label, Combobox, Button,
|
|
152
|
+
useTranslation,
|
|
153
|
+
} from 'forlogic-core';
|
|
154
|
+
import { useForm } from 'react-hook-form';
|
|
155
|
+
import { zodResolver } from '@hookform/resolvers/zod';
|
|
156
|
+
import { z } from 'zod';
|
|
157
|
+
|
|
158
|
+
const schema = z.object({
|
|
159
|
+
title: z.string().min(3, 'Mínimo 3 caracteres'),
|
|
160
|
+
status: z.string(),
|
|
161
|
+
id_responsible: z.string().uuid(),
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
type FormData = z.infer<typeof schema>;
|
|
165
|
+
|
|
166
|
+
interface ProcessFormProps {
|
|
167
|
+
open: boolean;
|
|
168
|
+
onOpenChange: (open: boolean) => void;
|
|
169
|
+
onSubmit: (data: FormData) => void;
|
|
170
|
+
defaultValues?: Partial<FormData>;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function ProcessForm({ open, onOpenChange, onSubmit, defaultValues }: ProcessFormProps) {
|
|
174
|
+
const { t } = useTranslation();
|
|
175
|
+
const form = useForm<FormData>({
|
|
176
|
+
resolver: zodResolver(schema),
|
|
177
|
+
defaultValues,
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
return (
|
|
181
|
+
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
182
|
+
<DialogContent>
|
|
183
|
+
<DialogHeader>
|
|
184
|
+
<DialogTitle>{defaultValues ? t('edit') : t('create')}</DialogTitle>
|
|
185
|
+
</DialogHeader>
|
|
186
|
+
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
|
187
|
+
<div className="space-y-2">
|
|
188
|
+
<Label htmlFor="title">{t('title')}</Label>
|
|
189
|
+
<Input id="title" {...form.register('title')} />
|
|
190
|
+
</div>
|
|
191
|
+
<div className="space-y-2">
|
|
192
|
+
<Label>{t('status')}</Label>
|
|
193
|
+
<Combobox
|
|
194
|
+
options={[
|
|
195
|
+
{ value: 'active', label: 'Ativo' },
|
|
196
|
+
{ value: 'inactive', label: 'Inativo' },
|
|
197
|
+
]}
|
|
198
|
+
value={form.watch('status')}
|
|
199
|
+
onValueChange={(v) => form.setValue('status', v)}
|
|
200
|
+
/>
|
|
201
|
+
</div>
|
|
202
|
+
<div className="flex justify-end gap-2">
|
|
203
|
+
<Button variant="outline" onClick={() => onOpenChange(false)}>{t('cancel')}</Button>
|
|
204
|
+
<Button type="submit">{t('save')}</Button>
|
|
205
|
+
</div>
|
|
206
|
+
</form>
|
|
207
|
+
</DialogContent>
|
|
208
|
+
</Dialog>
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## 5. Supabase com Schema Correto
|
|
216
|
+
|
|
217
|
+
```tsx
|
|
218
|
+
// src/services/processService.ts
|
|
219
|
+
import { getSupabaseClient } from 'forlogic-core';
|
|
220
|
+
|
|
221
|
+
const SCHEMA = 'quality';
|
|
222
|
+
|
|
223
|
+
export async function fetchProcesses() {
|
|
224
|
+
const supabase = getSupabaseClient();
|
|
225
|
+
const { data, error } = await supabase
|
|
226
|
+
.schema(SCHEMA)
|
|
227
|
+
.from('processes')
|
|
228
|
+
.select('*')
|
|
229
|
+
.is('deleted_at', null)
|
|
230
|
+
.order('created_at', { ascending: false });
|
|
231
|
+
|
|
232
|
+
if (error) throw error;
|
|
233
|
+
return data;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export async function softDeleteProcess(id: string) {
|
|
237
|
+
const supabase = getSupabaseClient();
|
|
238
|
+
const { error } = await supabase
|
|
239
|
+
.schema(SCHEMA)
|
|
240
|
+
.from('processes')
|
|
241
|
+
.update({ deleted_at: new Date().toISOString() })
|
|
242
|
+
.eq('id', id);
|
|
243
|
+
|
|
244
|
+
if (error) throw error;
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## 6. Página com usePageMetadata + Breadcrumbs
|
|
251
|
+
|
|
252
|
+
```tsx
|
|
253
|
+
// src/pages/ProcessDetailPage.tsx
|
|
254
|
+
import { usePageMetadata } from 'forlogic-core';
|
|
255
|
+
import { useParams } from 'react-router-dom';
|
|
256
|
+
|
|
257
|
+
export function ProcessDetailPage() {
|
|
258
|
+
const { id } = useParams();
|
|
259
|
+
|
|
260
|
+
usePageMetadata({
|
|
261
|
+
title: 'Detalhes do Processo',
|
|
262
|
+
subtitle: 'Visualize e edite os dados do processo',
|
|
263
|
+
breadcrumbs: [
|
|
264
|
+
{ label: 'Processos', href: '/processes' },
|
|
265
|
+
{ label: 'Detalhes' },
|
|
266
|
+
],
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
return (
|
|
270
|
+
<div className="p-6">
|
|
271
|
+
{/* conteúdo da página */}
|
|
272
|
+
</div>
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
```
|
|
@@ -41,7 +41,7 @@ const NotesPage = createCrudPage({
|
|
|
41
41
|
- Nível Médio: CrudTable/CrudGrid — componentes compostos para layouts customizados
|
|
42
42
|
- Nível Baixo: Primitives (DataTable, DataPagination, DataFilterBar) — controle total
|
|
43
43
|
|
|
44
|
-
> Fonte: `src
|
|
44
|
+
> Fonte: `src/design-system/docs/components/crud/CrudOverviewDoc.tsx`
|
|
45
45
|
|
|
46
46
|
---
|
|
47
47
|
|