@fayz-ai/plugin-reports 0.9.0 → 0.10.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/README.md +4 -4
- package/dist/{chunk-LODXZ2SC.js → chunk-2ZFN6ECM.js} +3 -3
- package/dist/chunk-2ZFN6ECM.js.map +1 -0
- package/dist/data/aggregate.d.ts +14 -0
- package/dist/data/aggregate.d.ts.map +1 -0
- package/dist/data/analytics-mock.d.ts +3 -0
- package/dist/data/analytics-mock.d.ts.map +1 -0
- package/dist/data/analytics-supabase.d.ts +7 -0
- package/dist/data/analytics-supabase.d.ts.map +1 -0
- package/dist/{excel-QHUSM6IH.js → excel-WE73YE2V.js} +3 -3
- package/dist/{excel-QHUSM6IH.js.map → excel-WE73YE2V.js.map} +1 -1
- package/dist/index.d.ts +73 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1207 -654
- package/dist/index.js.map +1 -1
- package/dist/lib/lastViewed.d.ts +5 -0
- package/dist/lib/lastViewed.d.ts.map +1 -0
- package/dist/lib/legacy.d.ts +5 -0
- package/dist/lib/legacy.d.ts.map +1 -0
- package/dist/lib/tenant.d.ts +1 -0
- package/dist/lib/tenant.d.ts.map +1 -1
- package/dist/locales/en.d.ts.map +1 -1
- package/dist/locales/pt-BR.d.ts.map +1 -1
- package/dist/{pdf-HETKN26Y.js → pdf-E6DXHFXU.js} +3 -3
- package/dist/{pdf-HETKN26Y.js.map → pdf-E6DXHFXU.js.map} +1 -1
- package/dist/views/AnalyticsModule.d.ts +10 -0
- package/dist/views/AnalyticsModule.d.ts.map +1 -0
- package/dist/views/AnalyticsOverview.d.ts +3 -0
- package/dist/views/AnalyticsOverview.d.ts.map +1 -0
- package/dist/views/AnalyticsReportViewer.d.ts +5 -0
- package/dist/views/AnalyticsReportViewer.d.ts.map +1 -0
- package/dist/views/AnalyticsSurface.d.ts +97 -0
- package/dist/views/AnalyticsSurface.d.ts.map +1 -0
- package/dist/views/LiveViewPage.d.ts +3 -0
- package/dist/views/LiveViewPage.d.ts.map +1 -0
- package/dist/views/ReportsListPage.d.ts +3 -0
- package/dist/views/ReportsListPage.d.ts.map +1 -0
- package/package.json +5 -7
- package/dist/ReportsContext.d.ts +0 -16
- package/dist/ReportsContext.d.ts.map +0 -1
- package/dist/ReportsPage.d.ts +0 -8
- package/dist/ReportsPage.d.ts.map +0 -1
- package/dist/chunk-LODXZ2SC.js.map +0 -1
- package/dist/components/ReportCard.d.ts +0 -9
- package/dist/components/ReportCard.d.ts.map +0 -1
- package/dist/components/ReportFilterBar.d.ts +0 -12
- package/dist/components/ReportFilterBar.d.ts.map +0 -1
- package/dist/components/ReportSummaryRow.d.ts +0 -10
- package/dist/components/ReportSummaryRow.d.ts.map +0 -1
- package/dist/hooks/useReportData.d.ts +0 -19
- package/dist/hooks/useReportData.d.ts.map +0 -1
- package/dist/views/ReportHub.d.ts +0 -8
- package/dist/views/ReportHub.d.ts.map +0 -1
- package/dist/views/ReportViewer.d.ts +0 -9
- package/dist/views/ReportViewer.d.ts.map +0 -1
- package/src/ReportsContext.tsx +0 -33
- package/src/ReportsPage.tsx +0 -62
- package/src/components/ExportDropdown.tsx +0 -63
- package/src/components/ReportCard.tsx +0 -38
- package/src/components/ReportFilterBar.tsx +0 -132
- package/src/components/ReportPagination.tsx +0 -59
- package/src/components/ReportSummaryRow.tsx +0 -68
- package/src/data/index.ts +0 -4
- package/src/data/mock.ts +0 -9
- package/src/data/supabase.ts +0 -200
- package/src/data/types.ts +0 -10
- package/src/export/csv.ts +0 -21
- package/src/export/excel.ts +0 -42
- package/src/export/pdf.ts +0 -47
- package/src/hooks/useReportData.ts +0 -123
- package/src/index.ts +0 -142
- package/src/lib/columns.ts +0 -130
- package/src/lib/tenant.ts +0 -3
- package/src/locales/en.ts +0 -28
- package/src/locales/index.ts +0 -7
- package/src/locales/pt-BR.ts +0 -28
- package/src/types.ts +0 -171
- package/src/views/ReportHub.tsx +0 -97
- package/src/views/ReportViewer.tsx +0 -182
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { useState, useCallback, useRef } from 'react'
|
|
2
|
-
import type { ReportDef, ReportQueryState, ReportDateRange } from '../types'
|
|
3
|
-
import type { ReportDataProvider, ReportResult } from '../data/types'
|
|
4
|
-
import { dedup } from '@fayz-ai/saas'
|
|
5
|
-
|
|
6
|
-
function defaultDateRange(): ReportDateRange {
|
|
7
|
-
const now = new Date()
|
|
8
|
-
const from = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-01`
|
|
9
|
-
const to = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`
|
|
10
|
-
return { from, to }
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function buildDefaultFilters(report: ReportDef): Record<string, any> {
|
|
14
|
-
const filters: Record<string, any> = {}
|
|
15
|
-
for (const f of report.filters ?? []) {
|
|
16
|
-
if (f.defaultValue !== undefined) filters[f.key] = f.defaultValue
|
|
17
|
-
}
|
|
18
|
-
return filters
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface UseReportDataReturn {
|
|
22
|
-
data: Record<string, any>[]
|
|
23
|
-
total: number
|
|
24
|
-
loading: boolean
|
|
25
|
-
generated: boolean
|
|
26
|
-
error: string | null
|
|
27
|
-
query: ReportQueryState
|
|
28
|
-
generate: () => void
|
|
29
|
-
setDateRange: (range: ReportDateRange) => void
|
|
30
|
-
setFilter: (key: string, value: any) => void
|
|
31
|
-
setSort: (sortBy: string) => void
|
|
32
|
-
setPage: (page: number) => void
|
|
33
|
-
setPageSize: (size: number) => void
|
|
34
|
-
setSearch: (search: string) => void
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function useReportData(
|
|
38
|
-
report: ReportDef,
|
|
39
|
-
provider: ReportDataProvider,
|
|
40
|
-
defaultPageSize: number = 50,
|
|
41
|
-
): UseReportDataReturn {
|
|
42
|
-
const [query, setQuery] = useState<ReportQueryState>({
|
|
43
|
-
dateRange: defaultDateRange(),
|
|
44
|
-
filters: buildDefaultFilters(report),
|
|
45
|
-
sortBy: report.dataSource.defaultSort,
|
|
46
|
-
sortDir: report.dataSource.defaultSortDir ?? 'desc',
|
|
47
|
-
page: 1,
|
|
48
|
-
pageSize: defaultPageSize,
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
const [result, setResult] = useState<ReportResult>({ data: [], total: 0 })
|
|
52
|
-
const [loading, setLoading] = useState(false)
|
|
53
|
-
const [generated, setGenerated] = useState(false)
|
|
54
|
-
const [error, setError] = useState<string | null>(null)
|
|
55
|
-
const queryRef = useRef(query)
|
|
56
|
-
queryRef.current = query
|
|
57
|
-
|
|
58
|
-
const fetchData = useCallback(async (q: ReportQueryState) => {
|
|
59
|
-
setLoading(true)
|
|
60
|
-
setError(null)
|
|
61
|
-
try {
|
|
62
|
-
const res = await dedup(`report:${report.id}:${JSON.stringify(q)}`, () =>
|
|
63
|
-
provider.fetch(report, q),
|
|
64
|
-
)
|
|
65
|
-
setResult(res)
|
|
66
|
-
setGenerated(true)
|
|
67
|
-
} catch (err: any) {
|
|
68
|
-
setError(err?.message ?? 'Failed to load report')
|
|
69
|
-
setResult({ data: [], total: 0 })
|
|
70
|
-
} finally {
|
|
71
|
-
setLoading(false)
|
|
72
|
-
}
|
|
73
|
-
}, [report, provider])
|
|
74
|
-
|
|
75
|
-
const generate = useCallback(() => {
|
|
76
|
-
fetchData(queryRef.current)
|
|
77
|
-
}, [fetchData])
|
|
78
|
-
|
|
79
|
-
const setDateRange = useCallback((dateRange: ReportDateRange) => {
|
|
80
|
-
setQuery((q) => ({ ...q, dateRange, page: 1 }))
|
|
81
|
-
}, [])
|
|
82
|
-
|
|
83
|
-
const setFilter = useCallback((key: string, value: any) => {
|
|
84
|
-
setQuery((q) => ({ ...q, filters: { ...q.filters, [key]: value }, page: 1 }))
|
|
85
|
-
}, [])
|
|
86
|
-
|
|
87
|
-
const setSort = useCallback((sortBy: string) => {
|
|
88
|
-
setQuery((q) => ({
|
|
89
|
-
...q,
|
|
90
|
-
sortBy,
|
|
91
|
-
sortDir: q.sortBy === sortBy && q.sortDir === 'asc' ? 'desc' : 'asc',
|
|
92
|
-
page: 1,
|
|
93
|
-
}))
|
|
94
|
-
}, [])
|
|
95
|
-
|
|
96
|
-
const setPage = useCallback((page: number) => {
|
|
97
|
-
setQuery((q) => ({ ...q, page }))
|
|
98
|
-
}, [])
|
|
99
|
-
|
|
100
|
-
const setPageSize = useCallback((pageSize: number) => {
|
|
101
|
-
setQuery((q) => ({ ...q, pageSize, page: 1 }))
|
|
102
|
-
}, [])
|
|
103
|
-
|
|
104
|
-
const setSearch = useCallback((search: string) => {
|
|
105
|
-
setQuery((q) => ({ ...q, search, page: 1 }))
|
|
106
|
-
}, [])
|
|
107
|
-
|
|
108
|
-
return {
|
|
109
|
-
data: result.data,
|
|
110
|
-
total: result.total,
|
|
111
|
-
loading,
|
|
112
|
-
generated,
|
|
113
|
-
error,
|
|
114
|
-
query,
|
|
115
|
-
generate,
|
|
116
|
-
setDateRange,
|
|
117
|
-
setFilter,
|
|
118
|
-
setSort,
|
|
119
|
-
setPage,
|
|
120
|
-
setPageSize,
|
|
121
|
-
setSearch,
|
|
122
|
-
}
|
|
123
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import type { PluginManifest, PluginScope, VerticalId } from '@fayz-ai/core'
|
|
3
|
-
import { createSafeDataProvider, registerTranslations } from '@fayz-ai/core'
|
|
4
|
-
import { ReportsPage } from './ReportsPage'
|
|
5
|
-
import type { ReportDataProvider } from './data/types'
|
|
6
|
-
import { createSupabaseReportProvider } from './data/supabase'
|
|
7
|
-
import { createMockReportProvider } from './data/mock'
|
|
8
|
-
import { getReportsTenantId } from './lib/tenant'
|
|
9
|
-
import { reportsLocales } from './locales'
|
|
10
|
-
import type {
|
|
11
|
-
ReportsPluginOptions,
|
|
12
|
-
ReportsPluginLabels,
|
|
13
|
-
ResolvedReportsConfig,
|
|
14
|
-
} from './types'
|
|
15
|
-
|
|
16
|
-
// ---------------------------------------------------------------------------
|
|
17
|
-
// Defaults
|
|
18
|
-
// ---------------------------------------------------------------------------
|
|
19
|
-
|
|
20
|
-
const DEFAULT_LABELS: ReportsPluginLabels = {
|
|
21
|
-
pageTitle: 'Reports',
|
|
22
|
-
pageSubtitle: 'Access complete reports for analysis and decision making',
|
|
23
|
-
allReports: 'All Reports',
|
|
24
|
-
dateRange: 'Date Range',
|
|
25
|
-
from: 'From',
|
|
26
|
-
to: 'To',
|
|
27
|
-
export: 'Export',
|
|
28
|
-
exportCsv: 'Export CSV',
|
|
29
|
-
exportExcel: 'Export Excel',
|
|
30
|
-
exportPdf: 'Export PDF',
|
|
31
|
-
noResults: 'No results found.',
|
|
32
|
-
backToReports: 'Back',
|
|
33
|
-
reports: 'reports',
|
|
34
|
-
search: 'Search reports...',
|
|
35
|
-
today: 'Today',
|
|
36
|
-
yesterday: 'Yesterday',
|
|
37
|
-
last7Days: 'Last 7 days',
|
|
38
|
-
thisMonth: 'This month',
|
|
39
|
-
lastMonth: 'Last month',
|
|
40
|
-
thisQuarter: 'This quarter',
|
|
41
|
-
custom: 'Custom',
|
|
42
|
-
generate: 'Generate',
|
|
43
|
-
print: 'Print',
|
|
44
|
-
filterFrom: 'From',
|
|
45
|
-
filterTo: 'To',
|
|
46
|
-
filterResults: 'Results',
|
|
47
|
-
emptyStateTitle: 'Ready to generate',
|
|
48
|
-
emptyStateDescription: 'Select a date range and filters, then click Generate to view the report.',
|
|
49
|
-
unavailableTitle: 'Coming soon',
|
|
50
|
-
unavailableDescription: 'This report is not available yet. It will be enabled in a future update.',
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const DEFAULT_CURRENCY = { code: 'BRL', locale: 'pt-BR', symbol: 'R$' }
|
|
54
|
-
|
|
55
|
-
// ---------------------------------------------------------------------------
|
|
56
|
-
// Config resolver
|
|
57
|
-
// ---------------------------------------------------------------------------
|
|
58
|
-
|
|
59
|
-
function resolveConfig(options: ReportsPluginOptions): ResolvedReportsConfig {
|
|
60
|
-
return {
|
|
61
|
-
labels: { ...DEFAULT_LABELS, ...options.labels },
|
|
62
|
-
currency: { ...DEFAULT_CURRENCY, ...options.currency },
|
|
63
|
-
reports: options.reports,
|
|
64
|
-
defaultPageSize: options.defaultPageSize ?? 50,
|
|
65
|
-
showHeader: options.showHeader !== false,
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// ---------------------------------------------------------------------------
|
|
70
|
-
// Factory
|
|
71
|
-
// ---------------------------------------------------------------------------
|
|
72
|
-
|
|
73
|
-
export function createReportsPlugin(options: ReportsPluginOptions): PluginManifest {
|
|
74
|
-
const config = resolveConfig(options)
|
|
75
|
-
registerTranslations(reportsLocales)
|
|
76
|
-
const provider: ReportDataProvider = options.dataProvider ?? createSafeDataProvider(
|
|
77
|
-
() => createSupabaseReportProvider({ tenantId: () => getReportsTenantId() }),
|
|
78
|
-
() => createMockReportProvider(),
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
const PageComponent: React.FC<any> = () =>
|
|
82
|
-
React.createElement(ReportsPage, { config, provider })
|
|
83
|
-
|
|
84
|
-
return {
|
|
85
|
-
id: 'reports',
|
|
86
|
-
name: config.labels.pageTitle,
|
|
87
|
-
icon: 'BarChart3',
|
|
88
|
-
version: '1.0.0',
|
|
89
|
-
scope: options.scope ?? 'universal',
|
|
90
|
-
verticalId: options.verticalId,
|
|
91
|
-
defaultEnabled: true,
|
|
92
|
-
dependencies: [],
|
|
93
|
-
declaredFeatures: [
|
|
94
|
-
{ id: 'reports', label: config.labels.pageTitle, group: config.labels.pageTitle },
|
|
95
|
-
],
|
|
96
|
-
navigation: [
|
|
97
|
-
{
|
|
98
|
-
section: options.navSection ?? 'main',
|
|
99
|
-
position: options.navPosition ?? 9,
|
|
100
|
-
label: config.labels.pageTitle,
|
|
101
|
-
route: '/reports',
|
|
102
|
-
icon: 'BarChart3',
|
|
103
|
-
permission: { feature: 'reports', action: 'read' as const },
|
|
104
|
-
},
|
|
105
|
-
],
|
|
106
|
-
routes: [
|
|
107
|
-
{
|
|
108
|
-
path: '/reports',
|
|
109
|
-
component: PageComponent,
|
|
110
|
-
permission: { feature: 'reports', action: 'read' as const },
|
|
111
|
-
},
|
|
112
|
-
],
|
|
113
|
-
widgets: [],
|
|
114
|
-
registries: [],
|
|
115
|
-
locales: reportsLocales,
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// ---------------------------------------------------------------------------
|
|
120
|
-
// Re-exports
|
|
121
|
-
// ---------------------------------------------------------------------------
|
|
122
|
-
|
|
123
|
-
export type {
|
|
124
|
-
ReportDef,
|
|
125
|
-
ReportColumnDef,
|
|
126
|
-
ReportFilterDef,
|
|
127
|
-
ReportDateRange,
|
|
128
|
-
ReportQueryState,
|
|
129
|
-
ReportBadge,
|
|
130
|
-
ReportDataSource,
|
|
131
|
-
ReportGrain,
|
|
132
|
-
ReportAllowedAction,
|
|
133
|
-
ReportFilterOption,
|
|
134
|
-
ReportsPluginOptions,
|
|
135
|
-
ReportsPluginLabels,
|
|
136
|
-
ResolvedReportsConfig,
|
|
137
|
-
} from './types'
|
|
138
|
-
|
|
139
|
-
export type { ReportDataProvider, ReportResult } from './data/types'
|
|
140
|
-
export { createSupabaseReportProvider } from './data/supabase'
|
|
141
|
-
export type { SupabaseReportProviderConfig } from './data/supabase'
|
|
142
|
-
export { createMockReportProvider } from './data/mock'
|
package/src/lib/columns.ts
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import type { ColumnDef } from '@tanstack/react-table'
|
|
3
|
-
import type { ReportColumnDef } from '../types'
|
|
4
|
-
import { PersonLink } from '@fayz-ai/saas'
|
|
5
|
-
import {
|
|
6
|
-
formatCurrency as formatCurrencyLocale,
|
|
7
|
-
formatDate as formatDateLocale,
|
|
8
|
-
formatDateTime as formatDateTimeLocale,
|
|
9
|
-
} from '@fayz-ai/core'
|
|
10
|
-
|
|
11
|
-
// ---------------------------------------------------------------------------
|
|
12
|
-
// Formatters (mirrors fieldToColumn.tsx logic)
|
|
13
|
-
// ---------------------------------------------------------------------------
|
|
14
|
-
|
|
15
|
-
function formatCurrency(value: any, currency?: string): string {
|
|
16
|
-
const num = typeof value === 'number' ? value : parseFloat(value)
|
|
17
|
-
if (isNaN(num)) return '—'
|
|
18
|
-
return formatCurrencyLocale(num, currency)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function formatDate(value: any): string {
|
|
22
|
-
if (!value) return '—'
|
|
23
|
-
return formatDateLocale(value)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function formatDateTime(value: any): string {
|
|
27
|
-
if (!value) return '—'
|
|
28
|
-
return formatDateTimeLocale(value)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function formatNumber(value: any): string {
|
|
32
|
-
if (value == null) return '—'
|
|
33
|
-
return typeof value === 'number' ? value.toLocaleString() : String(value)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// ---------------------------------------------------------------------------
|
|
37
|
-
// Plain-text formatter for exports
|
|
38
|
-
// ---------------------------------------------------------------------------
|
|
39
|
-
|
|
40
|
-
export function formatValuePlain(value: any, col: ReportColumnDef, currency?: string): string {
|
|
41
|
-
if (value == null || value === '') return ''
|
|
42
|
-
switch (col.type) {
|
|
43
|
-
case 'currency':
|
|
44
|
-
return formatCurrency(value, col.currency ?? currency)
|
|
45
|
-
case 'date':
|
|
46
|
-
return formatDate(value)
|
|
47
|
-
case 'datetime':
|
|
48
|
-
return formatDateTime(value)
|
|
49
|
-
case 'number':
|
|
50
|
-
return formatNumber(value)
|
|
51
|
-
case 'boolean':
|
|
52
|
-
return value ? 'Yes' : 'No'
|
|
53
|
-
default:
|
|
54
|
-
return String(value)
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// ---------------------------------------------------------------------------
|
|
59
|
-
// ReportColumnDef[] → TanStack ColumnDef[]
|
|
60
|
-
// ---------------------------------------------------------------------------
|
|
61
|
-
|
|
62
|
-
export function reportColumnsToTanstack(
|
|
63
|
-
columns: ReportColumnDef[],
|
|
64
|
-
currency?: string,
|
|
65
|
-
): ColumnDef<Record<string, any>>[] {
|
|
66
|
-
return columns
|
|
67
|
-
.filter((c) => c.visible !== false)
|
|
68
|
-
.map((col): ColumnDef<Record<string, any>> => {
|
|
69
|
-
const sortable = col.sortable ?? ['text', 'number', 'currency', 'date', 'datetime', 'email'].includes(col.type)
|
|
70
|
-
const alignRight = col.align === 'right' || (!col.align && (col.type === 'currency' || col.type === 'number'))
|
|
71
|
-
const alignCenter = col.align === 'center'
|
|
72
|
-
|
|
73
|
-
return {
|
|
74
|
-
accessorKey: col.key,
|
|
75
|
-
header: col.label,
|
|
76
|
-
enableSorting: sortable,
|
|
77
|
-
cell: (ctx) => {
|
|
78
|
-
const value = ctx.getValue()
|
|
79
|
-
const row = ctx.row.original
|
|
80
|
-
|
|
81
|
-
if (col.renderCell) {
|
|
82
|
-
return col.renderCell(value, row)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (value == null || value === '') {
|
|
86
|
-
return React.createElement('span', { className: 'text-muted-foreground' }, '—')
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
let content: React.ReactNode
|
|
90
|
-
switch (col.type) {
|
|
91
|
-
case 'person':
|
|
92
|
-
content = React.createElement(PersonLink, {
|
|
93
|
-
personId: col.idKey ? row[col.idKey] : null,
|
|
94
|
-
name: String(value),
|
|
95
|
-
size: 'sm',
|
|
96
|
-
className: 'text-xs',
|
|
97
|
-
})
|
|
98
|
-
break
|
|
99
|
-
case 'currency':
|
|
100
|
-
content = formatCurrency(value, col.currency ?? currency)
|
|
101
|
-
break
|
|
102
|
-
case 'date':
|
|
103
|
-
content = formatDate(value)
|
|
104
|
-
break
|
|
105
|
-
case 'datetime':
|
|
106
|
-
content = formatDateTime(value)
|
|
107
|
-
break
|
|
108
|
-
case 'boolean':
|
|
109
|
-
content = value
|
|
110
|
-
? React.createElement('svg', { className: 'h-4 w-4 text-success', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: '2' },
|
|
111
|
-
React.createElement('polyline', { points: '20 6 9 17 4 12' }),
|
|
112
|
-
)
|
|
113
|
-
: React.createElement('span', { className: 'text-muted-foreground' }, '—')
|
|
114
|
-
break
|
|
115
|
-
case 'number':
|
|
116
|
-
content = formatNumber(value)
|
|
117
|
-
break
|
|
118
|
-
default:
|
|
119
|
-
content = String(value)
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const cls = alignRight ? 'text-right' : alignCenter ? 'text-center' : undefined
|
|
123
|
-
return cls
|
|
124
|
-
? React.createElement('div', { className: cls }, content)
|
|
125
|
-
: React.createElement(React.Fragment, null, content)
|
|
126
|
-
},
|
|
127
|
-
meta: { align: alignRight ? 'right' : alignCenter ? 'center' : 'left' },
|
|
128
|
-
}
|
|
129
|
-
})
|
|
130
|
-
}
|
package/src/lib/tenant.ts
DELETED
package/src/locales/en.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
export const en: Record<string, string> = {
|
|
2
|
-
'reports.pageTitle': 'Reports',
|
|
3
|
-
'reports.pageSubtitle': 'Access complete reports for analysis and decision making',
|
|
4
|
-
'reports.allReports': 'All Reports',
|
|
5
|
-
'reports.dateRange': 'Date Range',
|
|
6
|
-
'reports.from': 'From',
|
|
7
|
-
'reports.to': 'To',
|
|
8
|
-
'reports.export': 'Export',
|
|
9
|
-
'reports.exportCsv': 'Export CSV',
|
|
10
|
-
'reports.exportExcel': 'Export Excel',
|
|
11
|
-
'reports.exportPdf': 'Export PDF',
|
|
12
|
-
'reports.noResults': 'No results found.',
|
|
13
|
-
'reports.backToReports': 'Back',
|
|
14
|
-
'reports.reports': 'reports',
|
|
15
|
-
'reports.search': 'Search reports...',
|
|
16
|
-
'reports.today': 'Today',
|
|
17
|
-
'reports.yesterday': 'Yesterday',
|
|
18
|
-
'reports.last7Days': 'Last 7 days',
|
|
19
|
-
'reports.thisMonth': 'This month',
|
|
20
|
-
'reports.lastMonth': 'Last month',
|
|
21
|
-
'reports.thisQuarter': 'This quarter',
|
|
22
|
-
'reports.custom': 'Custom',
|
|
23
|
-
'reports.generate': 'Generate',
|
|
24
|
-
'reports.emptyStateTitle': 'Ready to generate',
|
|
25
|
-
'reports.emptyStateDescription': 'Select a date range and filters, then click Generate to view the report.',
|
|
26
|
-
'reports.unavailableTitle': 'Coming soon',
|
|
27
|
-
'reports.unavailableDescription': 'This report is not available yet. It will be enabled in a future update.',
|
|
28
|
-
}
|
package/src/locales/index.ts
DELETED
package/src/locales/pt-BR.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
export const ptBR: Record<string, string> = {
|
|
2
|
-
'reports.pageTitle': 'Relatórios',
|
|
3
|
-
'reports.pageSubtitle': 'Acesse relatórios completos para análise e tomada de decisão',
|
|
4
|
-
'reports.allReports': 'Todos os Relatórios',
|
|
5
|
-
'reports.dateRange': 'Período',
|
|
6
|
-
'reports.from': 'De',
|
|
7
|
-
'reports.to': 'Até',
|
|
8
|
-
'reports.export': 'Exportar',
|
|
9
|
-
'reports.exportCsv': 'Exportar CSV',
|
|
10
|
-
'reports.exportExcel': 'Exportar Excel',
|
|
11
|
-
'reports.exportPdf': 'Exportar PDF',
|
|
12
|
-
'reports.noResults': 'Nenhum resultado encontrado.',
|
|
13
|
-
'reports.backToReports': 'Voltar',
|
|
14
|
-
'reports.reports': 'relatórios',
|
|
15
|
-
'reports.search': 'Buscar relatórios...',
|
|
16
|
-
'reports.today': 'Hoje',
|
|
17
|
-
'reports.yesterday': 'Ontem',
|
|
18
|
-
'reports.last7Days': 'Últimos 7 dias',
|
|
19
|
-
'reports.thisMonth': 'Este mês',
|
|
20
|
-
'reports.lastMonth': 'Mês passado',
|
|
21
|
-
'reports.thisQuarter': 'Este trimestre',
|
|
22
|
-
'reports.custom': 'Personalizado',
|
|
23
|
-
'reports.generate': 'Gerar',
|
|
24
|
-
'reports.emptyStateTitle': 'Pronto para gerar',
|
|
25
|
-
'reports.emptyStateDescription': 'Selecione o período e os filtros desejados, depois clique em Gerar para visualizar o relatório.',
|
|
26
|
-
'reports.unavailableTitle': 'Em breve',
|
|
27
|
-
'reports.unavailableDescription': 'Este relatório ainda não está disponível. Será habilitado em uma atualização futura.',
|
|
28
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
import type React from 'react'
|
|
2
|
-
import type { FieldType } from '@fayz-ai/core'
|
|
3
|
-
|
|
4
|
-
// ---------------------------------------------------------------------------
|
|
5
|
-
// Report column
|
|
6
|
-
// ---------------------------------------------------------------------------
|
|
7
|
-
|
|
8
|
-
export type ReportFieldType = FieldType | 'person'
|
|
9
|
-
|
|
10
|
-
export interface ReportColumnDef {
|
|
11
|
-
key: string
|
|
12
|
-
label: string
|
|
13
|
-
type: ReportFieldType
|
|
14
|
-
sortable?: boolean
|
|
15
|
-
currency?: string
|
|
16
|
-
/** For type 'person': the row key containing the person UUID */
|
|
17
|
-
idKey?: string
|
|
18
|
-
renderCell?: (value: any, row: any) => React.ReactNode
|
|
19
|
-
/** Include in export but hide in table. Default: true */
|
|
20
|
-
visible?: boolean
|
|
21
|
-
/** Text alignment. Currency/number default to 'right' */
|
|
22
|
-
align?: 'left' | 'center' | 'right'
|
|
23
|
-
/** Aggregate for optional summary row */
|
|
24
|
-
aggregate?: 'sum' | 'avg' | 'count' | 'min' | 'max'
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// ---------------------------------------------------------------------------
|
|
28
|
-
// Report filter
|
|
29
|
-
// ---------------------------------------------------------------------------
|
|
30
|
-
|
|
31
|
-
export type ReportFilterOption = { label: string; value: string }
|
|
32
|
-
|
|
33
|
-
export interface ReportFilterDef {
|
|
34
|
-
key: string
|
|
35
|
-
label: string
|
|
36
|
-
type: 'select' | 'multiselect' | 'text' | 'boolean' | 'number'
|
|
37
|
-
options?: ReportFilterOption[] | (() => Promise<ReportFilterOption[]>)
|
|
38
|
-
defaultValue?: any
|
|
39
|
-
placeholder?: string
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// ---------------------------------------------------------------------------
|
|
43
|
-
// Report definition
|
|
44
|
-
// ---------------------------------------------------------------------------
|
|
45
|
-
|
|
46
|
-
export type ReportBadge = 'popular' | 'essential' | 'new' | (string & {})
|
|
47
|
-
|
|
48
|
-
export type ReportDataSourceKind = 'view' | 'rpc'
|
|
49
|
-
|
|
50
|
-
export interface ReportDataSource {
|
|
51
|
-
kind: ReportDataSourceKind
|
|
52
|
-
/** View name (e.g. 'rep_appointments_by_period') or RPC function name */
|
|
53
|
-
name: string
|
|
54
|
-
/** Column for date range filtering. Default: 'created_at' */
|
|
55
|
-
dateColumn?: string
|
|
56
|
-
defaultSort?: string
|
|
57
|
-
defaultSortDir?: 'asc' | 'desc'
|
|
58
|
-
/** snake_case DB → camelCase JS column mapping */
|
|
59
|
-
columnMap?: Record<string, string>
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export type ReportGrain = 'order' | 'order_item' | 'booking' | 'ledger_movement' | 'event'
|
|
63
|
-
|
|
64
|
-
export type ReportAllowedAction = 'read'
|
|
65
|
-
|
|
66
|
-
export interface ReportDef {
|
|
67
|
-
id: string
|
|
68
|
-
name: string
|
|
69
|
-
description?: string
|
|
70
|
-
icon: string
|
|
71
|
-
category: string
|
|
72
|
-
badge?: ReportBadge
|
|
73
|
-
columns: ReportColumnDef[]
|
|
74
|
-
filters?: ReportFilterDef[]
|
|
75
|
-
dataSource: ReportDataSource
|
|
76
|
-
/** Canonical read model/view used by the report. Defaults to dataSource.name. */
|
|
77
|
-
sourceView?: string
|
|
78
|
-
/** Business grain of each report row, used to prevent double counting. */
|
|
79
|
-
grain?: ReportGrain
|
|
80
|
-
/** Plugin that owns the report UI/definition. */
|
|
81
|
-
ownerPlugin?: string
|
|
82
|
-
/** Canonical data owner/spine for this report's facts. */
|
|
83
|
-
canonicalOwner?: string
|
|
84
|
-
/** Reports are normally read-only; explicit actions make that contract visible. */
|
|
85
|
-
allowedActions?: ReportAllowedAction[]
|
|
86
|
-
permission?: { feature: string; action: 'read' }
|
|
87
|
-
/** Show aggregate summary row */
|
|
88
|
-
showSummary?: boolean
|
|
89
|
-
/** Whether the backing view/RPC exists. Default: true */
|
|
90
|
-
available?: boolean
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// ---------------------------------------------------------------------------
|
|
94
|
-
// Query state
|
|
95
|
-
// ---------------------------------------------------------------------------
|
|
96
|
-
|
|
97
|
-
export interface ReportDateRange {
|
|
98
|
-
from: string // YYYY-MM-DD
|
|
99
|
-
to: string // YYYY-MM-DD
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export interface ReportQueryState {
|
|
103
|
-
dateRange: ReportDateRange
|
|
104
|
-
filters: Record<string, any>
|
|
105
|
-
sortBy?: string
|
|
106
|
-
sortDir?: 'asc' | 'desc'
|
|
107
|
-
page: number
|
|
108
|
-
pageSize: number
|
|
109
|
-
search?: string
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// ---------------------------------------------------------------------------
|
|
113
|
-
// Plugin options
|
|
114
|
-
// ---------------------------------------------------------------------------
|
|
115
|
-
|
|
116
|
-
export interface ReportsPluginLabels {
|
|
117
|
-
pageTitle: string
|
|
118
|
-
pageSubtitle: string
|
|
119
|
-
allReports: string
|
|
120
|
-
dateRange: string
|
|
121
|
-
from: string
|
|
122
|
-
to: string
|
|
123
|
-
export: string
|
|
124
|
-
exportCsv: string
|
|
125
|
-
exportExcel: string
|
|
126
|
-
exportPdf: string
|
|
127
|
-
noResults: string
|
|
128
|
-
backToReports: string
|
|
129
|
-
reports: string
|
|
130
|
-
search: string
|
|
131
|
-
today: string
|
|
132
|
-
yesterday: string
|
|
133
|
-
last7Days: string
|
|
134
|
-
thisMonth: string
|
|
135
|
-
lastMonth: string
|
|
136
|
-
thisQuarter: string
|
|
137
|
-
custom: string
|
|
138
|
-
generate: string
|
|
139
|
-
print: string
|
|
140
|
-
filterFrom: string
|
|
141
|
-
filterTo: string
|
|
142
|
-
filterResults: string
|
|
143
|
-
emptyStateTitle: string
|
|
144
|
-
emptyStateDescription: string
|
|
145
|
-
unavailableTitle: string
|
|
146
|
-
unavailableDescription: string
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
export interface ReportsPluginOptions {
|
|
150
|
-
reports: ReportDef[]
|
|
151
|
-
labels?: Partial<ReportsPluginLabels>
|
|
152
|
-
currency?: { code?: string; locale?: string; symbol?: string }
|
|
153
|
-
dataProvider?: import('./data/types').ReportDataProvider
|
|
154
|
-
navPosition?: number
|
|
155
|
-
navSection?: 'main' | 'secondary'
|
|
156
|
-
scope?: import('@fayz-ai/core').PluginScope
|
|
157
|
-
verticalId?: import('@fayz-ai/core').VerticalId
|
|
158
|
-
/** Default page size. Default: 50 */
|
|
159
|
-
defaultPageSize?: number
|
|
160
|
-
/** Render the in-content title/subtitle. Set false when the app shell owns the
|
|
161
|
-
* page title (sidebar/GHL-style layouts). Default: true. */
|
|
162
|
-
showHeader?: boolean
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
export interface ResolvedReportsConfig {
|
|
166
|
-
labels: ReportsPluginLabels
|
|
167
|
-
currency: { code: string; locale: string; symbol: string }
|
|
168
|
-
reports: ReportDef[]
|
|
169
|
-
defaultPageSize: number
|
|
170
|
-
showHeader: boolean
|
|
171
|
-
}
|