@pagamio/frontend-commons-lib 0.8.213 → 0.8.214

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.
Files changed (105) hide show
  1. package/lib/api/TanstackQueryProvider.d.ts +146 -0
  2. package/lib/api/TanstackQueryProvider.js +140 -0
  3. package/lib/api/index.d.ts +2 -0
  4. package/lib/api/index.js +2 -0
  5. package/lib/api/tanstackQuery.d.ts +249 -0
  6. package/lib/api/tanstackQuery.js +299 -0
  7. package/lib/components/layout/Sidebar.js +47 -24
  8. package/lib/components/ui/Sheet.d.ts +1 -1
  9. package/lib/context/SidebarContext.d.ts +10 -0
  10. package/lib/dashboard-visuals-v2/DashboardWrapperV2.d.ts +81 -0
  11. package/lib/dashboard-visuals-v2/DashboardWrapperV2.js +217 -0
  12. package/lib/dashboard-visuals-v2/cards/CardGrid.d.ts +22 -0
  13. package/lib/dashboard-visuals-v2/cards/CardGrid.js +27 -0
  14. package/lib/dashboard-visuals-v2/cards/InfoCard.d.ts +7 -0
  15. package/lib/dashboard-visuals-v2/cards/InfoCard.js +26 -0
  16. package/lib/dashboard-visuals-v2/cards/MetricCard.d.ts +7 -0
  17. package/lib/dashboard-visuals-v2/cards/MetricCard.js +37 -0
  18. package/lib/dashboard-visuals-v2/cards/StatCard.d.ts +7 -0
  19. package/lib/dashboard-visuals-v2/cards/StatCard.js +92 -0
  20. package/lib/dashboard-visuals-v2/cards/TopItemsCard.d.ts +7 -0
  21. package/lib/dashboard-visuals-v2/cards/TopItemsCard.js +34 -0
  22. package/lib/dashboard-visuals-v2/cards/TransactionListCard.d.ts +7 -0
  23. package/lib/dashboard-visuals-v2/cards/TransactionListCard.js +24 -0
  24. package/lib/dashboard-visuals-v2/cards/index.d.ts +9 -0
  25. package/lib/dashboard-visuals-v2/cards/index.js +9 -0
  26. package/lib/dashboard-visuals-v2/charts/AreaChart.d.ts +7 -0
  27. package/lib/dashboard-visuals-v2/charts/AreaChart.js +124 -0
  28. package/lib/dashboard-visuals-v2/charts/BarChart.d.ts +7 -0
  29. package/lib/dashboard-visuals-v2/charts/BarChart.js +106 -0
  30. package/lib/dashboard-visuals-v2/charts/BaseChart.d.ts +61 -0
  31. package/lib/dashboard-visuals-v2/charts/BaseChart.js +173 -0
  32. package/lib/dashboard-visuals-v2/charts/DonutChart.d.ts +7 -0
  33. package/lib/dashboard-visuals-v2/charts/DonutChart.js +108 -0
  34. package/lib/dashboard-visuals-v2/charts/HeatmapChart.d.ts +7 -0
  35. package/lib/dashboard-visuals-v2/charts/HeatmapChart.js +101 -0
  36. package/lib/dashboard-visuals-v2/charts/LineChart.d.ts +7 -0
  37. package/lib/dashboard-visuals-v2/charts/LineChart.js +109 -0
  38. package/lib/dashboard-visuals-v2/charts/MixedChart.d.ts +7 -0
  39. package/lib/dashboard-visuals-v2/charts/MixedChart.js +106 -0
  40. package/lib/dashboard-visuals-v2/charts/PieChart.d.ts +7 -0
  41. package/lib/dashboard-visuals-v2/charts/PieChart.js +10 -0
  42. package/lib/dashboard-visuals-v2/charts/RadialChart.d.ts +7 -0
  43. package/lib/dashboard-visuals-v2/charts/RadialChart.js +72 -0
  44. package/lib/dashboard-visuals-v2/charts/index.d.ts +12 -0
  45. package/lib/dashboard-visuals-v2/charts/index.js +12 -0
  46. package/lib/dashboard-visuals-v2/components/DataFetchingVisual.d.ts +0 -0
  47. package/lib/dashboard-visuals-v2/components/DataFetchingVisual.js +1 -0
  48. package/lib/dashboard-visuals-v2/components/index.d.ts +0 -0
  49. package/lib/dashboard-visuals-v2/components/index.js +1 -0
  50. package/lib/dashboard-visuals-v2/hooks/index.d.ts +4 -0
  51. package/lib/dashboard-visuals-v2/hooks/index.js +4 -0
  52. package/lib/dashboard-visuals-v2/hooks/useChartData.d.ts +72 -0
  53. package/lib/dashboard-visuals-v2/hooks/useChartData.js +122 -0
  54. package/lib/dashboard-visuals-v2/index.d.ts +10 -0
  55. package/lib/dashboard-visuals-v2/index.js +16 -0
  56. package/lib/dashboard-visuals-v2/types/card.types.d.ts +237 -0
  57. package/lib/dashboard-visuals-v2/types/card.types.js +30 -0
  58. package/lib/dashboard-visuals-v2/types/chart.types.d.ts +308 -0
  59. package/lib/dashboard-visuals-v2/types/chart.types.js +25 -0
  60. package/lib/dashboard-visuals-v2/types/index.d.ts +6 -0
  61. package/lib/dashboard-visuals-v2/types/index.js +6 -0
  62. package/lib/dashboard-visuals-v2/utils/index.d.ts +0 -0
  63. package/lib/dashboard-visuals-v2/utils/index.js +1 -0
  64. package/lib/dashboard-visuals-v2/utils/propsTransformer.d.ts +0 -0
  65. package/lib/dashboard-visuals-v2/utils/propsTransformer.js +1 -0
  66. package/lib/dashboard-visuals-v2/visualRegistry.d.ts +59 -0
  67. package/lib/dashboard-visuals-v2/visualRegistry.js +110 -0
  68. package/lib/data-table-v2/DataTable.d.ts +7 -0
  69. package/lib/data-table-v2/DataTable.js +206 -0
  70. package/lib/data-table-v2/components/DataTableBody.d.ts +19 -0
  71. package/lib/data-table-v2/components/DataTableBody.js +20 -0
  72. package/lib/data-table-v2/components/DataTableEmpty.d.ts +17 -0
  73. package/lib/data-table-v2/components/DataTableEmpty.js +13 -0
  74. package/lib/data-table-v2/components/DataTableError.d.ts +16 -0
  75. package/lib/data-table-v2/components/DataTableError.js +14 -0
  76. package/lib/data-table-v2/components/DataTableHeader.d.ts +15 -0
  77. package/lib/data-table-v2/components/DataTableHeader.js +31 -0
  78. package/lib/data-table-v2/components/DataTableLoading.d.ts +14 -0
  79. package/lib/data-table-v2/components/DataTableLoading.js +19 -0
  80. package/lib/data-table-v2/components/DataTablePagination.d.ts +36 -0
  81. package/lib/data-table-v2/components/DataTablePagination.js +20 -0
  82. package/lib/data-table-v2/components/DataTableRowActions.d.ts +13 -0
  83. package/lib/data-table-v2/components/DataTableRowActions.js +57 -0
  84. package/lib/data-table-v2/components/DataTableSearch.d.ts +19 -0
  85. package/lib/data-table-v2/components/DataTableSearch.js +33 -0
  86. package/lib/data-table-v2/components/DataTableToolbar.d.ts +54 -0
  87. package/lib/data-table-v2/components/DataTableToolbar.js +28 -0
  88. package/lib/data-table-v2/components/index.d.ts +12 -0
  89. package/lib/data-table-v2/components/index.js +12 -0
  90. package/lib/data-table-v2/hooks/index.d.ts +4 -0
  91. package/lib/data-table-v2/hooks/index.js +4 -0
  92. package/lib/data-table-v2/hooks/useTableData.d.ts +118 -0
  93. package/lib/data-table-v2/hooks/useTableData.js +210 -0
  94. package/lib/data-table-v2/index.d.ts +9 -0
  95. package/lib/data-table-v2/index.js +12 -0
  96. package/lib/data-table-v2/types/index.d.ts +296 -0
  97. package/lib/data-table-v2/types/index.js +1 -0
  98. package/lib/data-table-v2/utils/export.d.ts +26 -0
  99. package/lib/data-table-v2/utils/export.js +92 -0
  100. package/lib/data-table-v2/utils/index.d.ts +4 -0
  101. package/lib/data-table-v2/utils/index.js +4 -0
  102. package/lib/index.d.ts +4 -0
  103. package/lib/index.js +23 -0
  104. package/lib/styles.css +212 -0
  105. package/package.json +7 -1
@@ -0,0 +1,217 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ /**
3
+ * @fileoverview DashboardWrapperV2 - Main dashboard component using ApexCharts
4
+ * Drop-in replacement for V1 DashboardWrapper with improved performance
5
+ */
6
+ import { useCallback, useEffect, useMemo, useState } from 'react';
7
+ import { useApi } from '../api';
8
+ import { FilterComponent, Tab } from '../components';
9
+ import { cn } from '../helpers';
10
+ import { useMediaQueries } from '../shared';
11
+ import visualRegistryV2, { isRegisteredVisual } from './visualRegistry';
12
+ const defaultDashboardApiPaths = {
13
+ query: '/analytics/query',
14
+ metrics: '/analytics/metrics',
15
+ };
16
+ // Helper to get grid span from column count
17
+ const getGridColSpan = (numVisuals, visualId) => {
18
+ if (numVisuals === 1)
19
+ return 12;
20
+ if (numVisuals === 2)
21
+ return 6;
22
+ if (numVisuals === 3)
23
+ return 4;
24
+ if (numVisuals === 4)
25
+ return 3;
26
+ // For > 4 visuals, use 4 columns layout
27
+ return 3;
28
+ };
29
+ // Helper to extract filter options from response
30
+ const getFilterOptionsData = (response, key, valueKey) => {
31
+ const optionsData = response.map((item) => {
32
+ const record = item;
33
+ const value = valueKey ? record[valueKey] : record[key];
34
+ const label = record.label || record.name || value;
35
+ return {
36
+ value: String(value ?? ''),
37
+ label: String(label ?? ''),
38
+ };
39
+ });
40
+ return { optionsData };
41
+ };
42
+ /**
43
+ * DashboardWrapperV2 Component
44
+ * Drop-in replacement for DashboardWrapper using ApexCharts
45
+ */
46
+ export function DashboardWrapperV2({ data, showVisualHeader = true, showEventsTabbedLayout = false, handleFilterChange: externalHandleFilterChange, selectedFilters = {}, tourSelectedFilters = {}, resetFilters = () => { }, handleApplyFilters = () => { }, handleApplyTourFilters = () => { }, handleTourFilterChange = () => { }, apiPaths = defaultDashboardApiPaths, className, classNames, gridGap = 4, fullWidth = false, }) {
47
+ const [loading, setLoading] = useState(true);
48
+ const [error, setError] = useState(null);
49
+ const [tourError, setTourError] = useState(null);
50
+ const [refreshCount, setRefreshCount] = useState(0);
51
+ const [filterOptions, setFilterOptions] = useState({});
52
+ const [tourFilterOptions, setTourFilterOptions] = useState({});
53
+ const { isSm, isXs } = useMediaQueries();
54
+ const apiClient = useApi();
55
+ const { config, visualData, eventsVisualData } = data;
56
+ // Handle filter change with default fallback
57
+ const handleFilterChange = externalHandleFilterChange ?? (() => { });
58
+ // Fetch filter options
59
+ const fetchFilterData = async (key, valueKey, url, query, isTourFilter = false) => {
60
+ try {
61
+ setLoading(true);
62
+ if (isTourFilter) {
63
+ setTourError(null);
64
+ }
65
+ else {
66
+ setError(null);
67
+ }
68
+ const response = await apiClient.post(url, query);
69
+ if (response) {
70
+ const { optionsData } = getFilterOptionsData(response, key, valueKey);
71
+ if (isTourFilter) {
72
+ setTourFilterOptions((prev) => ({ ...prev, [key]: optionsData }));
73
+ }
74
+ else {
75
+ setFilterOptions((prev) => ({ ...prev, [key]: optionsData }));
76
+ }
77
+ }
78
+ }
79
+ catch (err) {
80
+ const errorMessage = 'Failed to fetch filter data';
81
+ if (isTourFilter) {
82
+ setTourError(err instanceof Error ? err : new Error(errorMessage));
83
+ }
84
+ else {
85
+ setError(err instanceof Error ? err : new Error(errorMessage));
86
+ }
87
+ }
88
+ finally {
89
+ setLoading(false);
90
+ }
91
+ };
92
+ useEffect(() => {
93
+ const fetchFilters = (filters, isTour = false) => {
94
+ filters.forEach((filter) => {
95
+ if (filter.query) {
96
+ const defaultQueryUrl = apiPaths.query;
97
+ const queryUrl = isTour ? (filter.tourUrl ?? defaultQueryUrl) : (filter.url ?? defaultQueryUrl);
98
+ fetchFilterData(filter.name, filter.valueKey, queryUrl, filter.query, isTour);
99
+ }
100
+ });
101
+ };
102
+ fetchFilters(config.filters);
103
+ if (config.tourFilters) {
104
+ fetchFilters(config.tourFilters, true);
105
+ }
106
+ }, [config.filters, refreshCount, apiPaths]);
107
+ const handleRetry = () => setRefreshCount((prev) => prev + 1);
108
+ // Build dashboard filters with custom date range support
109
+ const dashboardFilters = useMemo(() => {
110
+ const baseFilters = [...config.filters];
111
+ const dateRangeValue = typeof selectedFilters?.dateRange === 'string' ? selectedFilters.dateRange.toUpperCase() : '';
112
+ if (dateRangeValue === 'CUSTOM_RANGE') {
113
+ baseFilters.push({
114
+ name: 'customDateRange',
115
+ label: 'Custom Date Range',
116
+ placeholder: 'Select date range',
117
+ type: 'date-range',
118
+ options: [],
119
+ multi: false,
120
+ rangeKeys: { start: 'startDate', end: 'endDate' },
121
+ });
122
+ }
123
+ return baseFilters;
124
+ }, [config.filters, selectedFilters?.dateRange]);
125
+ // Resolve filter type
126
+ const resolveFilterType = (filter) => {
127
+ if (filter.type === 'date-range')
128
+ return 'date-range';
129
+ if (filter.type === 'date')
130
+ return 'date';
131
+ if (filter.type === 'multi-select')
132
+ return 'multi-select';
133
+ if (filter.type === 'select')
134
+ return 'select';
135
+ return filter.multi ? 'multi-select' : 'select';
136
+ };
137
+ // Render filter component
138
+ const renderFilters = (filters, options, selected, onChange, onApply, filterError) => {
139
+ if (loading) {
140
+ return (_jsx("div", { className: "mb-5 p-4 bg-white rounded-lg border border-gray-200 animate-pulse", children: _jsx("div", { className: "flex gap-4", children: Array.from({ length: 3 })
141
+ .map((value, index) => {
142
+ void value;
143
+ return index;
144
+ })
145
+ .map((skeletonIndex) => (_jsx("div", { className: "h-10 bg-gray-200 rounded w-40" }, skeletonIndex))) }) }));
146
+ }
147
+ if (filterError) {
148
+ return (_jsxs("div", { className: "mb-5 p-4 bg-red-50 rounded-lg border border-red-200", children: [_jsx("p", { className: "text-red-600", children: filterError.message }), _jsx("button", { onClick: handleRetry, className: "mt-2 px-4 py-2 bg-red-100 text-red-700 rounded hover:bg-red-200", children: "Retry" })] }));
149
+ }
150
+ return (_jsx(FilterComponent, { filters: filters.map((filter) => ({
151
+ name: filter.name,
152
+ placeholder: filter.placeholder ?? `Select ${filter.name}`,
153
+ type: resolveFilterType(filter),
154
+ options: options[filter.name] || filter.options || [],
155
+ rangeKeys: filter.rangeKeys,
156
+ })), showClearFilters: true, selectedFilters: selected, handleFilterChange: onChange, handleApplyFilters: onApply, resetFilters: resetFilters, isNarrow: isSm }));
157
+ };
158
+ // Render a single visual
159
+ const renderVisual = useCallback((visual, sectionTitle, span) => {
160
+ const { metricData } = visual;
161
+ const matchesSmall = isXs || isSm;
162
+ const VisualComponent = visualRegistryV2[metricData.type];
163
+ if (!VisualComponent) {
164
+ if (!isRegisteredVisual(metricData.type)) {
165
+ console.warn(`[DashboardWrapperV2] Visual type "${metricData.type}" not found in V2 registry. ` +
166
+ `Available types: ${Object.keys(visualRegistryV2).join(', ')}`);
167
+ }
168
+ return null;
169
+ }
170
+ // Determine API URL based on component type
171
+ const isTileType = metricData.type === 'Tile' || metricData.type === 'StatCard' || metricData.type === 'MetricCard';
172
+ const defaultUrl = isTileType ? apiPaths.metrics : apiPaths.query;
173
+ const url = metricData.url || defaultUrl;
174
+ // Build props compatible with V2 components
175
+ const props = {
176
+ // Common props
177
+ data: metricData.data,
178
+ title: metricData.title,
179
+ colors: metricData.colors,
180
+ // Chart-specific props
181
+ series: metricData.series,
182
+ categories: metricData.categories,
183
+ stacked: metricData.stacked,
184
+ // Card-specific props
185
+ value: metricData.value,
186
+ icon: metricData.icon,
187
+ trend: metricData.trend,
188
+ trendValue: metricData.trendValue,
189
+ // Additional props from metricData
190
+ ...metricData,
191
+ // Override with computed values
192
+ url,
193
+ themeColor: config.themeColor,
194
+ };
195
+ // Calculate grid span class
196
+ const colSpan = matchesSmall ? 12 : (visual.gridColSpan ?? span);
197
+ const colSpanClass = `col-span-${colSpan}`;
198
+ return (_jsx("div", { className: cn(colSpanClass, classNames?.visual), children: _jsx(VisualComponent, { ...props }) }, `visual-${sectionTitle}-${visual.id}`));
199
+ }, [config.themeColor, isXs, isSm, apiPaths, classNames?.visual]);
200
+ // Render visual sections
201
+ const renderSections = (sections) => (_jsx("main", { children: sections.map((section) => (_jsxs("div", { className: cn('mb-4', classNames?.section), children: [section.sectionTitle && (_jsx("h2", { className: cn('mb-3 text-lg font-semibold text-gray-900', classNames?.sectionTitle), children: section.sectionTitle })), _jsx("div", { className: cn('grid grid-cols-12', `gap-${gridGap}`, classNames?.grid), children: section.data.map((visual) => {
202
+ const numVisuals = section.data.length;
203
+ const span = getGridColSpan(numVisuals, visual.id);
204
+ return renderVisual(visual, section.sectionTitle, span);
205
+ }) })] }, section.id))) }));
206
+ // Overview tab content
207
+ const overviewContent = (_jsxs(_Fragment, { children: [renderFilters(dashboardFilters, filterOptions, selectedFilters, handleFilterChange, handleApplyFilters, error), renderSections(visualData)] }));
208
+ // Events/Tour tab content
209
+ const eventsContent = eventsVisualData ? (_jsxs(_Fragment, { children: [renderFilters(config.tourFilters || [], tourFilterOptions, tourSelectedFilters, handleTourFilterChange, handleApplyTourFilters, tourError), renderSections(eventsVisualData)] })) : null;
210
+ // Tab configuration
211
+ const tabs = [
212
+ { id: 1, title: 'Overview', content: overviewContent },
213
+ { id: 2, title: 'Tour', content: eventsContent },
214
+ ];
215
+ return (_jsxs("div", { className: cn(fullWidth ? 'w-full' : 'max-w-7xl mx-auto', className), children: [showVisualHeader && (_jsxs("div", { className: cn('mb-6', classNames?.header), children: [_jsx("h1", { className: cn('text-2xl font-bold text-gray-900', classNames?.title), children: config.title }), _jsx("p", { className: cn('text-gray-600 mt-1', classNames?.summary), children: config.summary })] })), showEventsTabbedLayout ? _jsx(Tab, { tabs: tabs, defaultTab: 0, className: "justify-end" }) : overviewContent] }));
216
+ }
217
+ export default DashboardWrapperV2;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @fileoverview Card Grid component - Responsive card layout
3
+ */
4
+ import React from 'react';
5
+ import type { CardGridProps } from '../types';
6
+ /**
7
+ * Card Grid component
8
+ * Responsive grid layout for stat/metric cards
9
+ */
10
+ export declare function CardGrid({ children, columns, gap, className, }: CardGridProps): import("react/jsx-runtime").JSX.Element;
11
+ /**
12
+ * Pre-configured grid layouts
13
+ */
14
+ export declare const StatCardGrid: ({ children, className }: {
15
+ children: React.ReactNode;
16
+ className?: string;
17
+ }) => import("react/jsx-runtime").JSX.Element;
18
+ export declare const MetricCardGrid: ({ children, className }: {
19
+ children: React.ReactNode;
20
+ className?: string;
21
+ }) => import("react/jsx-runtime").JSX.Element;
22
+ export default CardGrid;
@@ -0,0 +1,27 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn } from '../../helpers';
3
+ /**
4
+ * Card Grid component
5
+ * Responsive grid layout for stat/metric cards
6
+ */
7
+ export function CardGrid({ children, columns = { default: 1, sm: 2, md: 3, lg: 4 }, gap = 4, className, }) {
8
+ // Build column classes
9
+ const columnClasses = [
10
+ columns.default && `grid-cols-${columns.default}`,
11
+ columns.sm && `sm:grid-cols-${columns.sm}`,
12
+ columns.md && `md:grid-cols-${columns.md}`,
13
+ columns.lg && `lg:grid-cols-${columns.lg}`,
14
+ columns.xl && `xl:grid-cols-${columns.xl}`,
15
+ ]
16
+ .filter(Boolean)
17
+ .join(' ');
18
+ // Gap class
19
+ const gapClass = `gap-${gap}`;
20
+ return _jsx("div", { className: cn('grid', columnClasses, gapClass, className), children: children });
21
+ }
22
+ /**
23
+ * Pre-configured grid layouts
24
+ */
25
+ export const StatCardGrid = ({ children, className }) => (_jsx(CardGrid, { columns: { default: 1, sm: 2, lg: 4 }, gap: 4, className: className, children: children }));
26
+ export const MetricCardGrid = ({ children, className }) => (_jsx(CardGrid, { columns: { default: 1, md: 2, lg: 3 }, gap: 6, className: className, children: children }));
27
+ export default CardGrid;
@@ -0,0 +1,7 @@
1
+ import type { InfoCardProps } from '../types';
2
+ /**
3
+ * Info Card component
4
+ * Flexible card for displaying various content types
5
+ */
6
+ export declare function InfoCard({ title, value, description, icon, badge, badgeVariant, footer, children, loading, error, onClick, className, classNames, }: InfoCardProps): import("react/jsx-runtime").JSX.Element;
7
+ export default InfoCard;
@@ -0,0 +1,26 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from '../../helpers';
3
+ /**
4
+ * Info Card component
5
+ * Flexible card for displaying various content types
6
+ */
7
+ export function InfoCard({ title, value, description, icon, badge, badgeVariant = 'default', footer, children, loading = false, error, onClick, className, classNames, }) {
8
+ // Badge variant classes
9
+ const badgeClasses = {
10
+ default: 'bg-gray-100 text-gray-700',
11
+ primary: 'bg-blue-100 text-blue-700',
12
+ success: 'bg-green-100 text-green-700',
13
+ warning: 'bg-amber-100 text-amber-700',
14
+ danger: 'bg-red-100 text-red-700',
15
+ };
16
+ // Loading state
17
+ if (loading) {
18
+ return (_jsx("div", { className: cn('rounded-xl bg-white border border-gray-200 p-4 shadow-sm animate-pulse', className, classNames?.container), children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("div", { className: "w-10 h-10 rounded-lg bg-gray-200" }), _jsxs("div", { className: "flex-1 space-y-2", children: [_jsx("div", { className: "h-4 bg-gray-200 rounded w-1/3" }), _jsx("div", { className: "h-6 bg-gray-200 rounded w-1/2" }), _jsx("div", { className: "h-3 bg-gray-200 rounded w-2/3" })] })] }) }));
19
+ }
20
+ // Error state
21
+ if (error) {
22
+ return (_jsx("div", { className: cn('rounded-xl border border-red-200 bg-red-50 p-4 shadow-sm', className, classNames?.container), children: _jsx("p", { className: "text-red-600 text-sm", children: "Error loading data" }) }));
23
+ }
24
+ return (_jsxs("div", { className: cn('rounded-xl bg-white border border-gray-200 p-4 shadow-sm transition-all duration-200', onClick && 'cursor-pointer hover:shadow-md hover:border-gray-300', className, classNames?.container), onClick: onClick, children: [_jsxs("div", { className: "flex items-start gap-3", children: [icon && (_jsx("div", { className: cn('w-10 h-10 rounded-lg bg-blue-100 text-blue-600 flex items-center justify-center flex-shrink-0', classNames?.icon), children: icon })), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsxs("div", { className: "flex items-start justify-between gap-2", children: [_jsxs("div", { children: [title && _jsx("p", { className: cn('text-sm font-medium text-gray-500', classNames?.title), children: title }), value && _jsx("p", { className: cn('text-xl font-bold text-gray-900 mt-0.5', classNames?.value), children: value })] }), badge && (_jsx("span", { className: cn('px-2 py-1 rounded-full text-xs font-medium', badgeClasses[badgeVariant]), children: badge }))] }), description && _jsx("p", { className: "text-sm text-gray-600 mt-2", children: description })] })] }), children && _jsx("div", { className: "mt-4", children: children }), footer && _jsx("div", { className: "mt-4 pt-3 border-t border-gray-100", children: footer })] }));
25
+ }
26
+ export default InfoCard;
@@ -0,0 +1,7 @@
1
+ import type { MetricCardProps } from '../types';
2
+ /**
3
+ * Metric Card component
4
+ * Displays metric with optional sparkline chart
5
+ */
6
+ export declare function MetricCard({ title, value, icon, trend, trendValue, trendLabel, sparklineData, sparklineColor, subtitle, action, loading, error, className, classNames, }: MetricCardProps): import("react/jsx-runtime").JSX.Element;
7
+ export default MetricCard;
@@ -0,0 +1,37 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from '../../helpers';
3
+ import { AreaChart } from '../charts/AreaChart';
4
+ /**
5
+ * Metric Card component
6
+ * Displays metric with optional sparkline chart
7
+ */
8
+ export function MetricCard({ title, value, icon, trend, trendValue, trendLabel, sparklineData, sparklineColor = '#3B82F6', subtitle, action, loading = false, error, className, classNames, }) {
9
+ // Loading state
10
+ if (loading) {
11
+ return (_jsxs("div", { className: cn('rounded-xl bg-white border border-gray-200 p-4 shadow-sm animate-pulse', className, classNames?.container), children: [_jsxs("div", { className: "flex items-start justify-between mb-4", children: [_jsxs("div", { className: "space-y-2 flex-1", children: [_jsx("div", { className: "h-4 bg-gray-200 rounded w-1/3" }), _jsx("div", { className: "h-8 bg-gray-200 rounded w-1/2" })] }), _jsx("div", { className: "w-10 h-10 rounded-lg bg-gray-200" })] }), _jsx("div", { className: "h-16 bg-gray-200 rounded" })] }));
12
+ }
13
+ // Error state
14
+ if (error) {
15
+ return (_jsx("div", { className: cn('rounded-xl border border-red-200 bg-red-50 p-4 shadow-sm', className, classNames?.container), children: _jsx("p", { className: "text-red-600 text-sm", children: "Error loading metric" }) }));
16
+ }
17
+ // Trend classes
18
+ const trendClasses = {
19
+ up: 'text-green-600 bg-green-50',
20
+ down: 'text-red-600 bg-red-50',
21
+ neutral: 'text-gray-600 bg-gray-50',
22
+ };
23
+ return (_jsxs("div", { className: cn('rounded-xl bg-white border border-gray-200 p-4 shadow-sm', className, classNames?.container), children: [_jsxs("div", { className: "flex items-start justify-between mb-3", children: [_jsxs("div", { children: [_jsx("p", { className: cn('text-sm font-medium text-gray-500', classNames?.title), children: title }), _jsxs("div", { className: "flex items-baseline gap-2 mt-1", children: [_jsx("p", { className: cn('text-2xl font-bold text-gray-900', classNames?.value), children: value }), trend && trendValue && (_jsxs("span", { className: cn('px-2 py-0.5 rounded-full text-xs font-medium', trendClasses[trend]), children: [trend === 'up' ? '↑' : trend === 'down' ? '↓' : '', trendValue] }))] }), (trendLabel || subtitle) && _jsx("p", { className: "text-xs text-gray-500 mt-1", children: trendLabel || subtitle })] }), icon && (_jsx("div", { className: cn('w-10 h-10 rounded-lg bg-blue-100 text-blue-600 flex items-center justify-center', classNames?.icon), children: icon }))] }), sparklineData && sparklineData.length > 0 && (_jsx("div", { className: "h-16 -mx-2 -mb-2", children: _jsx(AreaChart, { data: sparklineData.map((v, i) => ({ label: i.toString(), value: v })), style: { height: 64 }, apexOptions: {
24
+ chart: {
25
+ sparkline: { enabled: true },
26
+ toolbar: { show: false },
27
+ },
28
+ colors: [sparklineColor],
29
+ xaxis: { labels: { show: false } },
30
+ yaxis: { labels: { show: false } },
31
+ tooltip: { enabled: false },
32
+ stroke: { width: 2 },
33
+ legend: { show: false },
34
+ grid: { show: false },
35
+ } }) })), action && _jsx("div", { className: "mt-3 pt-3 border-t border-gray-100", children: action })] }));
36
+ }
37
+ export default MetricCard;
@@ -0,0 +1,7 @@
1
+ import type { StatCardProps } from '../types';
2
+ /**
3
+ * Stat Card component
4
+ * Displays a single metric with optional trend indicator
5
+ */
6
+ export declare function StatCard({ title, value, icon, trend, trendValue, trendLabel, description, variant, size, loading, error, onClick, className, classNames, }: StatCardProps): import("react/jsx-runtime").JSX.Element;
7
+ export default StatCard;
@@ -0,0 +1,92 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * @fileoverview Stat Card component - Single metric display
4
+ */
5
+ import { TrendingDown, TrendingUp } from 'lucide-react';
6
+ import React from 'react';
7
+ import { cn } from '../../helpers';
8
+ /**
9
+ * Stat Card component
10
+ * Displays a single metric with optional trend indicator
11
+ */
12
+ export function StatCard({ title, value, icon, trend, trendValue, trendLabel, description, variant = 'default', size = 'md', loading = false, error, onClick, className, classNames, }) {
13
+ // Size classes
14
+ const sizeClasses = {
15
+ sm: {
16
+ container: 'p-3',
17
+ title: 'text-xs',
18
+ value: 'text-xl',
19
+ icon: 'w-8 h-8',
20
+ iconInner: 'w-4 h-4',
21
+ },
22
+ md: {
23
+ container: 'p-4',
24
+ title: 'text-sm',
25
+ value: 'text-2xl',
26
+ icon: 'w-10 h-10',
27
+ iconInner: 'w-5 h-5',
28
+ },
29
+ lg: {
30
+ container: 'p-6',
31
+ title: 'text-base',
32
+ value: 'text-3xl',
33
+ icon: 'w-12 h-12',
34
+ iconInner: 'w-6 h-6',
35
+ },
36
+ };
37
+ // Variant classes
38
+ const variantClasses = {
39
+ default: 'bg-white border border-gray-200',
40
+ primary: 'bg-blue-50 border border-blue-200',
41
+ success: 'bg-green-50 border border-green-200',
42
+ warning: 'bg-amber-50 border border-amber-200',
43
+ danger: 'bg-red-50 border border-red-200',
44
+ gradient: 'bg-gradient-to-br from-blue-500 to-purple-600 text-white',
45
+ // Solid colored variants for dashboard cards
46
+ 'primary-solid': 'bg-blue-500 text-white border-0',
47
+ 'success-solid': 'bg-emerald-500 text-white border-0',
48
+ 'warning-solid': 'bg-amber-500 text-white border-0',
49
+ 'danger-solid': 'bg-red-500 text-white border-0',
50
+ 'purple-solid': 'bg-indigo-500 text-white border-0',
51
+ 'orange-solid': 'bg-orange-500 text-white border-0',
52
+ };
53
+ // Icon background classes
54
+ const iconBgClasses = {
55
+ default: 'bg-gray-100 text-gray-600',
56
+ primary: 'bg-blue-100 text-blue-600',
57
+ success: 'bg-green-100 text-green-600',
58
+ warning: 'bg-amber-100 text-amber-600',
59
+ danger: 'bg-red-100 text-red-600',
60
+ gradient: 'bg-white/20 text-white',
61
+ // Solid variant icon backgrounds
62
+ 'primary-solid': 'bg-white/20 text-white',
63
+ 'success-solid': 'bg-white/20 text-white',
64
+ 'warning-solid': 'bg-white/20 text-white',
65
+ 'danger-solid': 'bg-white/20 text-white',
66
+ 'purple-solid': 'bg-white/20 text-white',
67
+ 'orange-solid': 'bg-white/20 text-white',
68
+ };
69
+ // Trend classes
70
+ const trendClasses = {
71
+ up: 'text-green-600',
72
+ down: 'text-red-600',
73
+ neutral: 'text-gray-500',
74
+ };
75
+ const sizes = sizeClasses[size];
76
+ // Loading state
77
+ if (loading) {
78
+ return (_jsx("div", { className: cn('rounded-xl shadow-sm animate-pulse', sizes.container, variantClasses[variant], className, classNames?.container), children: _jsxs("div", { className: "flex items-start justify-between", children: [_jsxs("div", { className: "space-y-3 flex-1", children: [_jsx("div", { className: "h-4 bg-gray-200 rounded w-1/3" }), _jsx("div", { className: "h-8 bg-gray-200 rounded w-1/2" }), _jsx("div", { className: "h-3 bg-gray-200 rounded w-2/3" })] }), _jsx("div", { className: cn('rounded-lg bg-gray-200', sizes.icon) })] }) }));
79
+ }
80
+ // Error state
81
+ if (error) {
82
+ return (_jsx("div", { className: cn('rounded-xl shadow-sm border border-red-200 bg-red-50', sizes.container, className, classNames?.container), children: _jsx("div", { className: "flex items-center gap-2 text-red-600", children: _jsx("span", { className: "text-sm", children: "Error loading data" }) }) }));
83
+ }
84
+ // Helper to check if variant is a solid color
85
+ const isSolidVariant = variant.endsWith('-solid') || variant === 'gradient';
86
+ return (_jsx("div", { className: cn('rounded-xl shadow-sm transition-all duration-200', onClick && 'cursor-pointer hover:shadow-md', sizes.container, variantClasses[variant] || variantClasses.default, className, classNames?.container), onClick: onClick, children: _jsxs("div", { className: "flex items-start justify-between", children: [_jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: cn('font-medium', sizes.title, isSolidVariant ? 'text-white/80' : 'text-gray-500', classNames?.title), children: title }), _jsx("p", { className: cn('font-bold tracking-tight', sizes.value, isSolidVariant ? 'text-white' : 'text-gray-900', classNames?.value), children: value }), _jsxs("div", { className: "flex items-center gap-2 mt-2", children: [trend && trendValue && (_jsxs("span", { className: cn('inline-flex items-center gap-1 text-xs font-medium', isSolidVariant ? (trend === 'up' ? 'text-white' : 'text-white/90') : trendClasses[trend], classNames?.trend), children: [trend === 'up' && _jsx(TrendingUp, { className: "w-3 h-3" }), trend === 'down' && _jsx(TrendingDown, { className: "w-3 h-3" }), trendValue] })), (trendLabel || description) && (_jsx("span", { className: cn('text-xs', isSolidVariant ? 'text-white/60' : 'text-gray-500'), children: trendLabel || description }))] })] }), icon && (_jsx("div", { className: cn('rounded-lg flex items-center justify-center flex-shrink-0', sizes.icon, iconBgClasses[variant] || iconBgClasses.default, classNames?.icon), children: React.isValidElement(icon)
87
+ ? React.cloneElement(icon, {
88
+ className: cn(sizes.iconInner, icon.props?.className),
89
+ })
90
+ : icon }))] }) }));
91
+ }
92
+ export default StatCard;
@@ -0,0 +1,7 @@
1
+ import type { TopItemsCardProps } from '../types';
2
+ /**
3
+ * Top Items Card component
4
+ * Displays a ranked list with progress bars
5
+ */
6
+ export declare function TopItemsCard<TItem extends Record<string, unknown>>({ title, items, labelKey, valueKey, renderLabel, renderValue, showRank, showProgress, progressColor, maxItems, loading, error, className, classNames, }: TopItemsCardProps<TItem>): import("react/jsx-runtime").JSX.Element;
7
+ export default TopItemsCard;
@@ -0,0 +1,34 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from '../../helpers';
3
+ /**
4
+ * Top Items Card component
5
+ * Displays a ranked list with progress bars
6
+ */
7
+ export function TopItemsCard({ title, items, labelKey, valueKey, renderLabel, renderValue, showRank = true, showProgress = true, progressColor = '#3B82F6', maxItems = 5, loading = false, error, className, classNames, }) {
8
+ // Loading state
9
+ if (loading) {
10
+ return (_jsxs("div", { className: cn('rounded-xl bg-white border border-gray-200 p-4 shadow-sm', className, classNames?.container), children: [_jsx("div", { className: "h-5 bg-gray-200 rounded w-1/3 mb-4 animate-pulse" }), _jsx("div", { className: "space-y-4", children: Array.from({ length: 3 })
11
+ .map((value, index) => {
12
+ void value;
13
+ return index;
14
+ })
15
+ .map((skeletonIndex) => (_jsxs("div", { className: "animate-pulse", children: [_jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx("div", { className: "h-4 bg-gray-200 rounded w-1/3" }), _jsx("div", { className: "h-4 bg-gray-200 rounded w-16" })] }), _jsx("div", { className: "h-2 bg-gray-200 rounded-full" })] }, skeletonIndex))) })] }));
16
+ }
17
+ // Error state
18
+ if (error) {
19
+ return (_jsx("div", { className: cn('rounded-xl border border-red-200 bg-red-50 p-4 shadow-sm', className, classNames?.container), children: _jsx("p", { className: "text-red-600 text-sm", children: "Error loading data" }) }));
20
+ }
21
+ const displayItems = items.slice(0, maxItems);
22
+ const maxValue = Math.max(...displayItems.map((item) => Number(item[valueKey]) || 0));
23
+ return (_jsxs("div", { className: cn('rounded-xl bg-white border border-gray-200 p-4 shadow-sm', className, classNames?.container), children: [_jsx("h3", { className: cn('font-semibold text-gray-900 mb-4', classNames?.title), children: title }), _jsx("div", { className: "space-y-4", children: displayItems.length === 0 ? (_jsx("div", { className: "text-center text-gray-500 py-4", children: "No data available" })) : (displayItems.map((item, index) => {
24
+ const value = Number(item[valueKey]) || 0;
25
+ const progress = maxValue > 0 ? (value / maxValue) * 100 : 0;
26
+ const label = renderLabel ? renderLabel(item, index) : String(item[labelKey] ?? '');
27
+ const displayValue = renderValue ? renderValue(item, index) : value.toLocaleString();
28
+ return (_jsxs("div", { className: classNames?.item, children: [_jsxs("div", { className: "flex items-center justify-between mb-1.5", children: [_jsxs("div", { className: "flex items-center gap-2", children: [showRank && _jsxs("span", { className: "text-xs font-medium text-gray-400 w-5", children: ["#", index + 1] }), _jsx("span", { className: "text-sm font-medium text-gray-700 truncate", children: label })] }), _jsx("span", { className: "text-sm font-semibold text-gray-900", children: displayValue })] }), showProgress && (_jsx("div", { className: "h-2 bg-gray-100 rounded-full overflow-hidden", children: _jsx("div", { className: "h-full rounded-full transition-all duration-500", style: {
29
+ width: `${progress}%`,
30
+ backgroundColor: progressColor,
31
+ } }) }))] }, index));
32
+ })) })] }));
33
+ }
34
+ export default TopItemsCard;
@@ -0,0 +1,7 @@
1
+ import type { TransactionListCardProps } from '../types';
2
+ /**
3
+ * Transaction List Card component
4
+ * Displays a list of transactions or activity items
5
+ */
6
+ export declare function TransactionListCard<TItem extends Record<string, unknown>>({ title, items, renderItem, keyExtractor, maxItems, emptyMessage, viewAllLabel, onViewAll, loading, error, className, classNames, }: TransactionListCardProps<TItem>): import("react/jsx-runtime").JSX.Element;
7
+ export default TransactionListCard;
@@ -0,0 +1,24 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from '../../helpers';
3
+ /**
4
+ * Transaction List Card component
5
+ * Displays a list of transactions or activity items
6
+ */
7
+ export function TransactionListCard({ title, items, renderItem, keyExtractor, maxItems = 5, emptyMessage = 'No items to display', viewAllLabel = 'View All', onViewAll, loading = false, error, className, classNames, }) {
8
+ // Loading state
9
+ if (loading) {
10
+ return (_jsxs("div", { className: cn('rounded-xl bg-white border border-gray-200 p-4 shadow-sm', className, classNames?.container), children: [_jsx("div", { className: "h-5 bg-gray-200 rounded w-1/3 mb-4 animate-pulse" }), _jsx("div", { className: "space-y-3", children: Array.from({ length: 3 })
11
+ .map((value, index) => {
12
+ void value;
13
+ return index;
14
+ })
15
+ .map((skeletonIndex) => (_jsxs("div", { className: "flex items-center gap-3 animate-pulse", children: [_jsx("div", { className: "w-10 h-10 rounded-full bg-gray-200" }), _jsxs("div", { className: "flex-1 space-y-2", children: [_jsx("div", { className: "h-4 bg-gray-200 rounded w-1/2" }), _jsx("div", { className: "h-3 bg-gray-200 rounded w-1/3" })] }), _jsx("div", { className: "h-4 bg-gray-200 rounded w-16" })] }, skeletonIndex))) })] }));
16
+ }
17
+ // Error state
18
+ if (error) {
19
+ return (_jsx("div", { className: cn('rounded-xl border border-red-200 bg-red-50 p-4 shadow-sm', className, classNames?.container), children: _jsx("p", { className: "text-red-600 text-sm", children: "Error loading transactions" }) }));
20
+ }
21
+ const displayItems = items.slice(0, maxItems);
22
+ return (_jsxs("div", { className: cn('rounded-xl bg-white border border-gray-200 shadow-sm', className, classNames?.container), children: [_jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-gray-100", children: [_jsx("h3", { className: cn('font-semibold text-gray-900', classNames?.title), children: title }), onViewAll && items.length > maxItems && (_jsx("button", { onClick: onViewAll, className: "text-sm text-blue-600 hover:text-blue-700 font-medium", children: viewAllLabel }))] }), _jsx("div", { className: cn('divide-y divide-gray-100', classNames?.list), children: displayItems.length === 0 ? (_jsx("div", { className: "px-4 py-8 text-center text-gray-500", children: emptyMessage })) : (displayItems.map((item, index) => (_jsx("div", { className: cn('px-4 py-3', classNames?.item), children: renderItem(item, index) }, keyExtractor ? keyExtractor(item, index) : index)))) })] }));
23
+ }
24
+ export default TransactionListCard;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @fileoverview Cards index - Export all card components
3
+ */
4
+ export { StatCard } from './StatCard';
5
+ export { MetricCard } from './MetricCard';
6
+ export { InfoCard } from './InfoCard';
7
+ export { CardGrid, StatCardGrid, MetricCardGrid } from './CardGrid';
8
+ export { TransactionListCard } from './TransactionListCard';
9
+ export { TopItemsCard } from './TopItemsCard';
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @fileoverview Cards index - Export all card components
3
+ */
4
+ export { StatCard } from './StatCard';
5
+ export { MetricCard } from './MetricCard';
6
+ export { InfoCard } from './InfoCard';
7
+ export { CardGrid, StatCardGrid, MetricCardGrid } from './CardGrid';
8
+ export { TransactionListCard } from './TransactionListCard';
9
+ export { TopItemsCard } from './TopItemsCard';
@@ -0,0 +1,7 @@
1
+ import type { AreaChartProps, ChartDataPoint } from '../types';
2
+ /**
3
+ * Area Chart component
4
+ * Line chart with filled area underneath
5
+ */
6
+ export declare function AreaChart<TData extends ChartDataPoint = ChartDataPoint>({ data, series: providedSeries, categories: providedCategories, xKey, yKey, yKeys, seriesNames, curve, strokeWidth, showMarkers, markerSize, fillOpacity, gradient, style, tooltip, xAxis, yAxis, apexOptions, onDataPointClick, ...baseProps }: AreaChartProps<TData>): import("react/jsx-runtime").JSX.Element;
7
+ export default AreaChart;