@pattern-stack/frontend-patterns 0.0.4 → 0.0.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/dist/frontend-patterns.css +1 -1
- package/dist/index.es.js +1917 -2
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +1916 -1
- package/dist/index.js.map +1 -1
- package/package.json +6 -3
- package/src/App.tsx +11 -1
- package/src/atoms/composed/SalesPanel/SalesPanel.tsx +116 -0
- package/src/atoms/composed/SalesPanel/index.ts +1 -0
- package/src/atoms/composed/SalesPanel/mockSalesData.ts +151 -0
- package/src/atoms/composed/index.ts +1 -0
- package/src/atoms/types/entity-config.ts +127 -0
- package/src/atoms/types/index.ts +2 -1
- package/src/atoms/utils/metric-engine.ts +236 -0
- package/src/atoms/utils/utils.ts +2 -1
- package/src/molecules/layout/DashboardWithSidePanel/DashboardWithSidePanel.tsx +42 -0
- package/src/molecules/layout/DashboardWithSidePanel/index.ts +1 -0
- package/src/molecules/layout/Sidebar.tsx +10 -2
- package/src/molecules/layout/index.ts +1 -0
- package/src/organisms/entity/CategoryBreakdownPanel.tsx +427 -0
- package/src/organisms/entity/EntityListPanel.tsx +339 -0
- package/src/organisms/entity/MetricsOverviewPanel.tsx +236 -0
- package/src/organisms/entity/TrendAnalysisPanel.tsx +337 -0
- package/src/organisms/entity/index.ts +4 -0
- package/src/organisms/index.ts +4 -1
- package/src/pages/AdminShowcase/AdminDashboardShowcase.tsx +77 -75
- package/src/pages/AdminShowcase/SalesPerformanceDashboard.tsx +158 -0
- package/src/pages/AdminShowcase/index.tsx +2 -1
- package/src/pages/EntityShowcase/EntityManagementShowcase.tsx +137 -0
- package/src/pages/EntityShowcase/EntityPerformanceShowcase.tsx +117 -0
- package/src/pages/EntityShowcase/index.ts +2 -0
- package/src/pages/EntityTemplateExample.tsx +229 -0
- package/src/pages/TestEntityTemplate.tsx +40 -0
- package/src/pages/index.ts +2 -1
- package/src/templates/entity/EntityManagementTemplate.tsx +430 -0
- package/src/templates/entity/EntityPerformanceDashboardTemplate.tsx +277 -0
- package/src/templates/entity/configs/financial-config.ts +141 -0
- package/src/templates/entity/configs/index.ts +1 -0
- package/src/templates/entity/index.ts +3 -0
- package/src/templates/financial/FinancialDashboardTemplate.tsx +326 -0
- package/src/templates/index.ts +3 -0
- package/dist/atoms/composed/Accordion/Accordion.d.ts +0 -20
- package/dist/atoms/composed/Accordion/Accordion.d.ts.map +0 -1
- package/dist/atoms/composed/Accordion/index.d.ts +0 -2
- package/dist/atoms/composed/Accordion/index.d.ts.map +0 -1
- package/dist/atoms/composed/Alert/Alert.d.ts +0 -25
- package/dist/atoms/composed/Alert/Alert.d.ts.map +0 -1
- package/dist/atoms/composed/Alert/index.d.ts +0 -2
- package/dist/atoms/composed/Alert/index.d.ts.map +0 -1
- package/dist/atoms/composed/Breadcrumb/Breadcrumb.d.ts +0 -17
- package/dist/atoms/composed/Breadcrumb/Breadcrumb.d.ts.map +0 -1
- package/dist/atoms/composed/Breadcrumb/index.d.ts +0 -2
- package/dist/atoms/composed/Breadcrumb/index.d.ts.map +0 -1
- package/dist/atoms/composed/Chart/Chart.d.ts +0 -37
- package/dist/atoms/composed/Chart/Chart.d.ts.map +0 -1
- package/dist/atoms/composed/Chart/index.d.ts +0 -3
- package/dist/atoms/composed/Chart/index.d.ts.map +0 -1
- package/dist/atoms/composed/ColorSwatch/ColorSwatch.d.ts +0 -19
- package/dist/atoms/composed/ColorSwatch/ColorSwatch.d.ts.map +0 -1
- package/dist/atoms/composed/ColorSwatch/index.d.ts +0 -2
- package/dist/atoms/composed/ColorSwatch/index.d.ts.map +0 -1
- package/dist/atoms/composed/DarkModeToggle.d.ts +0 -4
- package/dist/atoms/composed/DarkModeToggle.d.ts.map +0 -1
- package/dist/atoms/composed/DataBadge/DataBadge.d.ts +0 -13
- package/dist/atoms/composed/DataBadge/DataBadge.d.ts.map +0 -1
- package/dist/atoms/composed/DataBadge/index.d.ts +0 -2
- package/dist/atoms/composed/DataBadge/index.d.ts.map +0 -1
- package/dist/atoms/composed/DataTable/DataTable.d.ts +0 -28
- package/dist/atoms/composed/DataTable/DataTable.d.ts.map +0 -1
- package/dist/atoms/composed/DataTable/TableCellWithTooltip.d.ts +0 -10
- package/dist/atoms/composed/DataTable/TableCellWithTooltip.d.ts.map +0 -1
- package/dist/atoms/composed/DataTable/index.d.ts +0 -3
- package/dist/atoms/composed/DataTable/index.d.ts.map +0 -1
- package/dist/atoms/composed/DateTimePicker/DateTimePicker.d.ts +0 -45
- package/dist/atoms/composed/DateTimePicker/DateTimePicker.d.ts.map +0 -1
- package/dist/atoms/composed/DateTimePicker/index.d.ts +0 -3
- package/dist/atoms/composed/DateTimePicker/index.d.ts.map +0 -1
- package/dist/atoms/composed/DetailedCard/DetailedCard.d.ts +0 -30
- package/dist/atoms/composed/DetailedCard/DetailedCard.d.ts.map +0 -1
- package/dist/atoms/composed/DetailedCard/index.d.ts +0 -3
- package/dist/atoms/composed/DetailedCard/index.d.ts.map +0 -1
- package/dist/atoms/composed/EmptyState/EmptyState.d.ts +0 -18
- package/dist/atoms/composed/EmptyState/EmptyState.d.ts.map +0 -1
- package/dist/atoms/composed/EmptyState/index.d.ts +0 -2
- package/dist/atoms/composed/EmptyState/index.d.ts.map +0 -1
- package/dist/atoms/composed/FileUpload/FileUpload.d.ts +0 -46
- package/dist/atoms/composed/FileUpload/FileUpload.d.ts.map +0 -1
- package/dist/atoms/composed/FileUpload/index.d.ts +0 -3
- package/dist/atoms/composed/FileUpload/index.d.ts.map +0 -1
- package/dist/atoms/composed/FormField/FormField.d.ts +0 -23
- package/dist/atoms/composed/FormField/FormField.d.ts.map +0 -1
- package/dist/atoms/composed/FormField/index.d.ts +0 -2
- package/dist/atoms/composed/FormField/index.d.ts.map +0 -1
- package/dist/atoms/composed/GlobalSearch/GlobalSearch.d.ts +0 -8
- package/dist/atoms/composed/GlobalSearch/GlobalSearch.d.ts.map +0 -1
- package/dist/atoms/composed/GlobalSearch/index.d.ts +0 -2
- package/dist/atoms/composed/GlobalSearch/index.d.ts.map +0 -1
- package/dist/atoms/composed/IconBadge/IconBadge.d.ts +0 -16
- package/dist/atoms/composed/IconBadge/IconBadge.d.ts.map +0 -1
- package/dist/atoms/composed/IconBadge/index.d.ts +0 -3
- package/dist/atoms/composed/IconBadge/index.d.ts.map +0 -1
- package/dist/atoms/composed/Modal/Modal.d.ts +0 -18
- package/dist/atoms/composed/Modal/Modal.d.ts.map +0 -1
- package/dist/atoms/composed/Modal/index.d.ts +0 -3
- package/dist/atoms/composed/Modal/index.d.ts.map +0 -1
- package/dist/atoms/composed/PaletteSwitcher.d.ts +0 -7
- package/dist/atoms/composed/PaletteSwitcher.d.ts.map +0 -1
- package/dist/atoms/composed/ProgressBar/ProgressBar.d.ts +0 -25
- package/dist/atoms/composed/ProgressBar/ProgressBar.d.ts.map +0 -1
- package/dist/atoms/composed/ProgressBar/index.d.ts +0 -2
- package/dist/atoms/composed/ProgressBar/index.d.ts.map +0 -1
- package/dist/atoms/composed/StatCard/StatCard.d.ts +0 -21
- package/dist/atoms/composed/StatCard/StatCard.d.ts.map +0 -1
- package/dist/atoms/composed/StatCard/index.d.ts +0 -2
- package/dist/atoms/composed/StatCard/index.d.ts.map +0 -1
- package/dist/atoms/composed/StyleGuide.d.ts +0 -3
- package/dist/atoms/composed/StyleGuide.d.ts.map +0 -1
- package/dist/atoms/composed/Toast/Toast.d.ts +0 -40
- package/dist/atoms/composed/Toast/Toast.d.ts.map +0 -1
- package/dist/atoms/composed/Toast/index.d.ts +0 -2
- package/dist/atoms/composed/Toast/index.d.ts.map +0 -1
- package/dist/atoms/composed/Tooltip/Tooltip.d.ts +0 -16
- package/dist/atoms/composed/Tooltip/Tooltip.d.ts.map +0 -1
- package/dist/atoms/composed/Tooltip/index.d.ts +0 -2
- package/dist/atoms/composed/Tooltip/index.d.ts.map +0 -1
- package/dist/atoms/composed/UserAvatar/UserAvatar.d.ts +0 -8
- package/dist/atoms/composed/UserAvatar/UserAvatar.d.ts.map +0 -1
- package/dist/atoms/composed/UserAvatar/index.d.ts +0 -2
- package/dist/atoms/composed/UserAvatar/index.d.ts.map +0 -1
- package/dist/atoms/composed/UserMenu/UserMenu.d.ts +0 -8
- package/dist/atoms/composed/UserMenu/UserMenu.d.ts.map +0 -1
- package/dist/atoms/composed/UserMenu/index.d.ts +0 -2
- package/dist/atoms/composed/UserMenu/index.d.ts.map +0 -1
- package/dist/atoms/composed/index.d.ts +0 -25
- package/dist/atoms/composed/index.d.ts.map +0 -1
- package/dist/atoms/hooks/useApi.d.ts +0 -25
- package/dist/atoms/hooks/useApi.d.ts.map +0 -1
- package/dist/atoms/hooks/useHealth.d.ts +0 -19
- package/dist/atoms/hooks/useHealth.d.ts.map +0 -1
- package/dist/atoms/index.d.ts +0 -9
- package/dist/atoms/index.d.ts.map +0 -1
- package/dist/atoms/services/api/client.d.ts +0 -20
- package/dist/atoms/services/api/client.d.ts.map +0 -1
- package/dist/atoms/services/auth-service.d.ts +0 -24
- package/dist/atoms/services/auth-service.d.ts.map +0 -1
- package/dist/atoms/services/health.d.ts +0 -7
- package/dist/atoms/services/health.d.ts.map +0 -1
- package/dist/atoms/services/index.d.ts +0 -4
- package/dist/atoms/services/index.d.ts.map +0 -1
- package/dist/atoms/shared/config/constants.d.ts +0 -15
- package/dist/atoms/shared/config/constants.d.ts.map +0 -1
- package/dist/atoms/shared/config/dashboard-sizes.d.ts +0 -83
- package/dist/atoms/shared/config/dashboard-sizes.d.ts.map +0 -1
- package/dist/atoms/shared/config/environment.d.ts +0 -10
- package/dist/atoms/shared/config/environment.d.ts.map +0 -1
- package/dist/atoms/shared/index.d.ts +0 -4
- package/dist/atoms/shared/index.d.ts.map +0 -1
- package/dist/atoms/types/auth.d.ts +0 -56
- package/dist/atoms/types/auth.d.ts.map +0 -1
- package/dist/atoms/types/generated.d.ts +0 -1469
- package/dist/atoms/types/generated.d.ts.map +0 -1
- package/dist/atoms/types/index.d.ts +0 -4
- package/dist/atoms/types/index.d.ts.map +0 -1
- package/dist/atoms/types/loading.d.ts +0 -26
- package/dist/atoms/types/loading.d.ts.map +0 -1
- package/dist/atoms/ui/Badge.d.ts +0 -10
- package/dist/atoms/ui/Badge.d.ts.map +0 -1
- package/dist/atoms/ui/ErrorBoundary.d.ts +0 -18
- package/dist/atoms/ui/ErrorBoundary.d.ts.map +0 -1
- package/dist/atoms/ui/Select.d.ts +0 -28
- package/dist/atoms/ui/Select.d.ts.map +0 -1
- package/dist/atoms/ui/Switch.d.ts +0 -9
- package/dist/atoms/ui/Switch.d.ts.map +0 -1
- package/dist/atoms/ui/Tabs.d.ts +0 -30
- package/dist/atoms/ui/Tabs.d.ts.map +0 -1
- package/dist/atoms/ui/avatar.d.ts +0 -7
- package/dist/atoms/ui/avatar.d.ts.map +0 -1
- package/dist/atoms/ui/button.d.ts +0 -14
- package/dist/atoms/ui/button.d.ts.map +0 -1
- package/dist/atoms/ui/card.d.ts +0 -12
- package/dist/atoms/ui/card.d.ts.map +0 -1
- package/dist/atoms/ui/dropdown-menu.d.ts +0 -28
- package/dist/atoms/ui/dropdown-menu.d.ts.map +0 -1
- package/dist/atoms/ui/index.d.ts +0 -15
- package/dist/atoms/ui/index.d.ts.map +0 -1
- package/dist/atoms/ui/input.d.ts +0 -5
- package/dist/atoms/ui/input.d.ts.map +0 -1
- package/dist/atoms/ui/label.d.ts +0 -6
- package/dist/atoms/ui/label.d.ts.map +0 -1
- package/dist/atoms/ui/skeleton.d.ts +0 -3
- package/dist/atoms/ui/skeleton.d.ts.map +0 -1
- package/dist/atoms/ui/spinner.d.ts +0 -14
- package/dist/atoms/ui/spinner.d.ts.map +0 -1
- package/dist/atoms/ui/table.d.ts +0 -11
- package/dist/atoms/ui/table.d.ts.map +0 -1
- package/dist/atoms/utils/animations.d.ts +0 -65
- package/dist/atoms/utils/animations.d.ts.map +0 -1
- package/dist/atoms/utils/tooltip-helpers.d.ts +0 -71
- package/dist/atoms/utils/tooltip-helpers.d.ts.map +0 -1
- package/dist/atoms/utils/utils.d.ts +0 -4
- package/dist/atoms/utils/utils.d.ts.map +0 -1
- package/dist/features/auth/components/LoginForm.d.ts +0 -2
- package/dist/features/auth/components/LoginForm.d.ts.map +0 -1
- package/dist/features/auth/components/LogoutButton.d.ts +0 -2
- package/dist/features/auth/components/LogoutButton.d.ts.map +0 -1
- package/dist/features/auth/components/ProtectedRoute.d.ts +0 -10
- package/dist/features/auth/components/ProtectedRoute.d.ts.map +0 -1
- package/dist/features/auth/components/index.d.ts +0 -4
- package/dist/features/auth/components/index.d.ts.map +0 -1
- package/dist/features/auth/hooks/index.d.ts +0 -3
- package/dist/features/auth/hooks/index.d.ts.map +0 -1
- package/dist/features/auth/hooks/useAuth.d.ts +0 -10
- package/dist/features/auth/hooks/useAuth.d.ts.map +0 -1
- package/dist/features/auth/hooks/usePermissions.d.ts +0 -13
- package/dist/features/auth/hooks/usePermissions.d.ts.map +0 -1
- package/dist/features/auth/index.d.ts +0 -3
- package/dist/features/auth/index.d.ts.map +0 -1
- package/dist/features/index.d.ts +0 -2
- package/dist/features/index.d.ts.map +0 -1
- package/dist/index.d.ts +0 -10
- package/dist/index.d.ts.map +0 -1
- package/dist/molecules/forms/FormGroup.d.ts +0 -17
- package/dist/molecules/forms/FormGroup.d.ts.map +0 -1
- package/dist/molecules/forms/SearchInput.d.ts +0 -36
- package/dist/molecules/forms/SearchInput.d.ts.map +0 -1
- package/dist/molecules/forms/index.d.ts +0 -3
- package/dist/molecules/forms/index.d.ts.map +0 -1
- package/dist/molecules/index.d.ts +0 -4
- package/dist/molecules/index.d.ts.map +0 -1
- package/dist/molecules/layout/AppHeader/AppHeader.d.ts +0 -7
- package/dist/molecules/layout/AppHeader/AppHeader.d.ts.map +0 -1
- package/dist/molecules/layout/AppHeader/index.d.ts +0 -2
- package/dist/molecules/layout/AppHeader/index.d.ts.map +0 -1
- package/dist/molecules/layout/AppLayout.d.ts +0 -2
- package/dist/molecules/layout/AppLayout.d.ts.map +0 -1
- package/dist/molecules/layout/PageTemplate.d.ts +0 -19
- package/dist/molecules/layout/PageTemplate.d.ts.map +0 -1
- package/dist/molecules/layout/SectionHeader/SectionHeader.d.ts +0 -24
- package/dist/molecules/layout/SectionHeader/SectionHeader.d.ts.map +0 -1
- package/dist/molecules/layout/SectionHeader/index.d.ts +0 -2
- package/dist/molecules/layout/SectionHeader/index.d.ts.map +0 -1
- package/dist/molecules/layout/ShowcaseSection.d.ts +0 -22
- package/dist/molecules/layout/ShowcaseSection.d.ts.map +0 -1
- package/dist/molecules/layout/Sidebar.d.ts +0 -6
- package/dist/molecules/layout/Sidebar.d.ts.map +0 -1
- package/dist/molecules/layout/SidebarButton/SidebarButton.d.ts +0 -13
- package/dist/molecules/layout/SidebarButton/SidebarButton.d.ts.map +0 -1
- package/dist/molecules/layout/SidebarButton/index.d.ts +0 -2
- package/dist/molecules/layout/SidebarButton/index.d.ts.map +0 -1
- package/dist/molecules/layout/SidebarContext.d.ts +0 -12
- package/dist/molecules/layout/SidebarContext.d.ts.map +0 -1
- package/dist/molecules/layout/index.d.ts +0 -8
- package/dist/molecules/layout/index.d.ts.map +0 -1
- package/dist/molecules/navigation/NavMenu.d.ts +0 -20
- package/dist/molecules/navigation/NavMenu.d.ts.map +0 -1
- package/dist/molecules/navigation/Pagination.d.ts +0 -14
- package/dist/molecules/navigation/Pagination.d.ts.map +0 -1
- package/dist/molecules/navigation/index.d.ts +0 -3
- package/dist/molecules/navigation/index.d.ts.map +0 -1
- package/dist/organisms/index.d.ts +0 -2
- package/dist/organisms/index.d.ts.map +0 -1
- package/dist/organisms/showcase/ComponentShowcasePage.d.ts +0 -3
- package/dist/organisms/showcase/ComponentShowcasePage.d.ts.map +0 -1
- package/dist/templates/AuthTemplate.d.ts +0 -68
- package/dist/templates/AuthTemplate.d.ts.map +0 -1
- package/dist/templates/ComponentShowcaseTemplate.d.ts +0 -53
- package/dist/templates/ComponentShowcaseTemplate.d.ts.map +0 -1
- package/dist/templates/DashboardTemplate.d.ts +0 -62
- package/dist/templates/DashboardTemplate.d.ts.map +0 -1
- package/dist/templates/DataTemplate.d.ts +0 -78
- package/dist/templates/DataTemplate.d.ts.map +0 -1
- package/dist/templates/admin/AdminCRUDTemplate.d.ts +0 -105
- package/dist/templates/admin/AdminCRUDTemplate.d.ts.map +0 -1
- package/dist/templates/admin/AdminDashboardTemplate.d.ts +0 -89
- package/dist/templates/admin/AdminDashboardTemplate.d.ts.map +0 -1
- package/dist/templates/admin/AdminDetailTemplate.d.ts +0 -132
- package/dist/templates/admin/AdminDetailTemplate.d.ts.map +0 -1
- package/dist/templates/admin/index.d.ts +0 -4
- package/dist/templates/admin/index.d.ts.map +0 -1
- package/dist/templates/factory.d.ts +0 -28
- package/dist/templates/factory.d.ts.map +0 -1
- package/dist/templates/index.d.ts +0 -7
- package/dist/templates/index.d.ts.map +0 -1
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import React, { useMemo, useState } from 'react';
|
|
2
|
+
import { Chart } from '../../atoms/composed/Chart';
|
|
3
|
+
import type { ChartDataPoint, ChartType } from '../../atoms/composed/Chart';
|
|
4
|
+
import { Card } from '../../atoms/ui/card';
|
|
5
|
+
import { Button } from '../../atoms/ui/button';
|
|
6
|
+
import { Select } from '../../atoms/ui/Select';
|
|
7
|
+
import { Badge } from '../../atoms/ui/Badge';
|
|
8
|
+
import { MetricCalculationEngine } from '../../atoms/utils/metric-engine';
|
|
9
|
+
import type { MetricConfig, EntityData, TemporalConfig, TemporalCycle } from '../../atoms/types';
|
|
10
|
+
import { cn } from '../../atoms/utils/utils';
|
|
11
|
+
import { TrendingUp, BarChart3, LineChart, AreaChart, Download } from 'lucide-react';
|
|
12
|
+
|
|
13
|
+
export interface TrendAnalysisPanelProps {
|
|
14
|
+
metrics: MetricConfig[];
|
|
15
|
+
data: EntityData[];
|
|
16
|
+
temporal?: TemporalConfig;
|
|
17
|
+
isLoading?: boolean;
|
|
18
|
+
className?: string;
|
|
19
|
+
category?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
|
|
20
|
+
|
|
21
|
+
// Chart configuration
|
|
22
|
+
defaultChartType?: ChartType;
|
|
23
|
+
dateField?: string;
|
|
24
|
+
enablePeriodSelection?: boolean;
|
|
25
|
+
enableChartTypeSelection?: boolean;
|
|
26
|
+
enableMetricSelection?: boolean;
|
|
27
|
+
showComparisons?: boolean;
|
|
28
|
+
|
|
29
|
+
// Extension points
|
|
30
|
+
renderHeader?: () => React.ReactNode;
|
|
31
|
+
renderFooter?: () => React.ReactNode;
|
|
32
|
+
renderCustomChart?: (metric: MetricConfig, chartData: ChartDataPoint[], chartType: ChartType) => React.ReactNode;
|
|
33
|
+
headerSlot?: React.ReactNode;
|
|
34
|
+
footerSlot?: React.ReactNode;
|
|
35
|
+
|
|
36
|
+
// Event handlers
|
|
37
|
+
onMetricChange?: (metric: MetricConfig) => void;
|
|
38
|
+
onPeriodChange?: (period: TemporalCycle) => void;
|
|
39
|
+
onChartTypeChange?: (chartType: ChartType) => void;
|
|
40
|
+
onExport?: (data: ChartDataPoint[], metric: MetricConfig) => void;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const TrendAnalysisPanel: React.FC<TrendAnalysisPanelProps> = ({
|
|
44
|
+
metrics,
|
|
45
|
+
data,
|
|
46
|
+
temporal,
|
|
47
|
+
isLoading = false,
|
|
48
|
+
className,
|
|
49
|
+
category,
|
|
50
|
+
defaultChartType = 'line',
|
|
51
|
+
dateField = 'date',
|
|
52
|
+
enablePeriodSelection = true,
|
|
53
|
+
enableChartTypeSelection = true,
|
|
54
|
+
enableMetricSelection = true,
|
|
55
|
+
showComparisons = true,
|
|
56
|
+
renderHeader,
|
|
57
|
+
renderFooter,
|
|
58
|
+
renderCustomChart,
|
|
59
|
+
headerSlot,
|
|
60
|
+
footerSlot,
|
|
61
|
+
onMetricChange,
|
|
62
|
+
onPeriodChange,
|
|
63
|
+
onChartTypeChange,
|
|
64
|
+
onExport
|
|
65
|
+
}) => {
|
|
66
|
+
const [selectedMetric, setSelectedMetric] = useState<MetricConfig>(metrics[0]);
|
|
67
|
+
const [selectedPeriod, setSelectedPeriod] = useState<TemporalCycle>(temporal?.defaultCycle || 'monthly');
|
|
68
|
+
const [selectedChartType, setSelectedChartType] = useState<ChartType>(defaultChartType);
|
|
69
|
+
const [showForecast, setShowForecast] = useState(false);
|
|
70
|
+
|
|
71
|
+
// Calculate trend data for selected metric
|
|
72
|
+
const trendData = useMemo(() => {
|
|
73
|
+
if (!selectedMetric || !data.length) return [];
|
|
74
|
+
|
|
75
|
+
// Determine periods to show based on selected cycle
|
|
76
|
+
const periods = selectedPeriod === 'yearly' ? 5 :
|
|
77
|
+
selectedPeriod === 'quarterly' ? 8 :
|
|
78
|
+
selectedPeriod === 'monthly' ? 12 :
|
|
79
|
+
selectedPeriod === 'weekly' ? 12 : 30;
|
|
80
|
+
|
|
81
|
+
return MetricCalculationEngine.calculateTrendData(
|
|
82
|
+
selectedMetric,
|
|
83
|
+
data,
|
|
84
|
+
dateField,
|
|
85
|
+
periods
|
|
86
|
+
);
|
|
87
|
+
}, [selectedMetric, data, dateField, selectedPeriod]);
|
|
88
|
+
|
|
89
|
+
// Convert trend data to chart format
|
|
90
|
+
const chartData = useMemo((): ChartDataPoint[] => {
|
|
91
|
+
return trendData.map(point => ({
|
|
92
|
+
label: point.label || point.date,
|
|
93
|
+
value: point.value,
|
|
94
|
+
category: category
|
|
95
|
+
}));
|
|
96
|
+
}, [trendData, category]);
|
|
97
|
+
|
|
98
|
+
// Calculate trend percentage
|
|
99
|
+
const trendPercentage = useMemo(() => {
|
|
100
|
+
if (chartData.length < 2) return null;
|
|
101
|
+
|
|
102
|
+
const first = chartData[0].value;
|
|
103
|
+
const last = chartData[chartData.length - 1].value;
|
|
104
|
+
|
|
105
|
+
if (first === 0) return null;
|
|
106
|
+
|
|
107
|
+
return ((last - first) / Math.abs(first)) * 100;
|
|
108
|
+
}, [chartData]);
|
|
109
|
+
|
|
110
|
+
// Generate forecast data if enabled
|
|
111
|
+
const forecastData = useMemo(() => {
|
|
112
|
+
if (!showForecast || !temporal?.forecasting?.enabled || chartData.length < 3) {
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const periods = temporal?.forecasting?.periods || 3;
|
|
117
|
+
const lastValue = chartData[chartData.length - 1].value;
|
|
118
|
+
const trend = trendPercentage ? trendPercentage / 100 : 0;
|
|
119
|
+
|
|
120
|
+
return Array.from({ length: periods }, (_, index) => ({
|
|
121
|
+
label: `Future ${index + 1}`,
|
|
122
|
+
value: lastValue * (1 + trend * (index + 1) / chartData.length),
|
|
123
|
+
category: 8 as const // Use category 8 for forecast
|
|
124
|
+
}));
|
|
125
|
+
}, [showForecast, temporal?.forecasting, chartData, trendPercentage]);
|
|
126
|
+
|
|
127
|
+
// Combined chart data with forecast
|
|
128
|
+
const combinedChartData = useMemo(() => {
|
|
129
|
+
if (forecastData.length === 0) return chartData;
|
|
130
|
+
return [...chartData, ...forecastData];
|
|
131
|
+
}, [chartData, forecastData]);
|
|
132
|
+
|
|
133
|
+
const handleMetricChange = (metricKey: string) => {
|
|
134
|
+
const metric = metrics.find(m => m.key === metricKey);
|
|
135
|
+
if (metric) {
|
|
136
|
+
setSelectedMetric(metric);
|
|
137
|
+
onMetricChange?.(metric);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const handlePeriodChange = (period: TemporalCycle) => {
|
|
142
|
+
setSelectedPeriod(period);
|
|
143
|
+
onPeriodChange?.(period);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const handleChartTypeChange = (chartType: ChartType) => {
|
|
147
|
+
setSelectedChartType(chartType);
|
|
148
|
+
onChartTypeChange?.(chartType);
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const handleExport = () => {
|
|
152
|
+
if (onExport) {
|
|
153
|
+
onExport(combinedChartData, selectedMetric);
|
|
154
|
+
} else {
|
|
155
|
+
// Default CSV export
|
|
156
|
+
const csvContent = [
|
|
157
|
+
'Date,Value',
|
|
158
|
+
...combinedChartData.map(point => `${point.label},${point.value}`)
|
|
159
|
+
].join('\n');
|
|
160
|
+
|
|
161
|
+
const blob = new Blob([csvContent], { type: 'text/csv' });
|
|
162
|
+
const url = URL.createObjectURL(blob);
|
|
163
|
+
const a = document.createElement('a');
|
|
164
|
+
a.href = url;
|
|
165
|
+
a.download = `${selectedMetric.label}-trend-data.csv`;
|
|
166
|
+
a.click();
|
|
167
|
+
URL.revokeObjectURL(url);
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const renderControls = () => {
|
|
172
|
+
return (
|
|
173
|
+
<div className="flex items-center justify-between mb-4">
|
|
174
|
+
<div className="flex items-center gap-4">
|
|
175
|
+
<div className="flex items-center gap-2">
|
|
176
|
+
<TrendingUp className="w-4 h-4 text-muted-foreground" />
|
|
177
|
+
<h3 className="text-lg font-semibold text-foreground">Trend Analysis</h3>
|
|
178
|
+
</div>
|
|
179
|
+
|
|
180
|
+
{trendPercentage !== null && (
|
|
181
|
+
<Badge variant={trendPercentage > 0 ? 'default' : 'destructive'}>
|
|
182
|
+
{trendPercentage > 0 ? '+' : ''}{trendPercentage.toFixed(1)}%
|
|
183
|
+
</Badge>
|
|
184
|
+
)}
|
|
185
|
+
</div>
|
|
186
|
+
|
|
187
|
+
<div className="flex items-center gap-2">
|
|
188
|
+
{enableMetricSelection && metrics.length > 1 && (
|
|
189
|
+
<Select
|
|
190
|
+
value={selectedMetric.key}
|
|
191
|
+
onValueChange={handleMetricChange}
|
|
192
|
+
>
|
|
193
|
+
{metrics.map(metric => (
|
|
194
|
+
<option key={metric.key} value={metric.key}>
|
|
195
|
+
{metric.label}
|
|
196
|
+
</option>
|
|
197
|
+
))}
|
|
198
|
+
</Select>
|
|
199
|
+
)}
|
|
200
|
+
|
|
201
|
+
{enablePeriodSelection && (
|
|
202
|
+
<Select
|
|
203
|
+
value={selectedPeriod}
|
|
204
|
+
onValueChange={(value) => handlePeriodChange(value as TemporalCycle)}
|
|
205
|
+
>
|
|
206
|
+
{(temporal?.cycles || ['daily', 'weekly', 'monthly', 'quarterly', 'yearly']).map(cycle => (
|
|
207
|
+
<option key={cycle} value={cycle}>
|
|
208
|
+
{cycle.charAt(0).toUpperCase() + cycle.slice(1)}
|
|
209
|
+
</option>
|
|
210
|
+
))}
|
|
211
|
+
</Select>
|
|
212
|
+
)}
|
|
213
|
+
|
|
214
|
+
{enableChartTypeSelection && (
|
|
215
|
+
<div className="flex items-center border rounded">
|
|
216
|
+
<Button
|
|
217
|
+
variant={selectedChartType === 'line' ? 'default' : 'ghost'}
|
|
218
|
+
size="sm"
|
|
219
|
+
onClick={() => handleChartTypeChange('line')}
|
|
220
|
+
>
|
|
221
|
+
<LineChart className="w-4 h-4" />
|
|
222
|
+
</Button>
|
|
223
|
+
<Button
|
|
224
|
+
variant={selectedChartType === 'bar' ? 'default' : 'ghost'}
|
|
225
|
+
size="sm"
|
|
226
|
+
onClick={() => handleChartTypeChange('bar')}
|
|
227
|
+
>
|
|
228
|
+
<BarChart3 className="w-4 h-4" />
|
|
229
|
+
</Button>
|
|
230
|
+
<Button
|
|
231
|
+
variant={selectedChartType === 'area' ? 'default' : 'ghost'}
|
|
232
|
+
size="sm"
|
|
233
|
+
onClick={() => handleChartTypeChange('area')}
|
|
234
|
+
>
|
|
235
|
+
<AreaChart className="w-4 h-4" />
|
|
236
|
+
</Button>
|
|
237
|
+
</div>
|
|
238
|
+
)}
|
|
239
|
+
|
|
240
|
+
{temporal?.forecasting?.enabled && (
|
|
241
|
+
<Button
|
|
242
|
+
variant={showForecast ? 'default' : 'outline'}
|
|
243
|
+
size="sm"
|
|
244
|
+
onClick={() => setShowForecast(!showForecast)}
|
|
245
|
+
>
|
|
246
|
+
Forecast
|
|
247
|
+
</Button>
|
|
248
|
+
)}
|
|
249
|
+
|
|
250
|
+
<Button
|
|
251
|
+
variant="outline"
|
|
252
|
+
size="sm"
|
|
253
|
+
onClick={handleExport}
|
|
254
|
+
disabled={chartData.length === 0}
|
|
255
|
+
>
|
|
256
|
+
<Download className="w-4 h-4" />
|
|
257
|
+
</Button>
|
|
258
|
+
</div>
|
|
259
|
+
</div>
|
|
260
|
+
);
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
const renderChart = () => {
|
|
264
|
+
if (renderCustomChart) {
|
|
265
|
+
const customChart = renderCustomChart(selectedMetric, combinedChartData, selectedChartType);
|
|
266
|
+
if (customChart) return customChart;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return (
|
|
270
|
+
<Chart
|
|
271
|
+
title={selectedMetric.label}
|
|
272
|
+
subtitle={`${selectedPeriod} trend analysis`}
|
|
273
|
+
data={combinedChartData}
|
|
274
|
+
type={selectedChartType}
|
|
275
|
+
category={category}
|
|
276
|
+
showTrend={true}
|
|
277
|
+
trend={trendPercentage !== null ? {
|
|
278
|
+
value: trendPercentage,
|
|
279
|
+
label: 'overall trend'
|
|
280
|
+
} : undefined}
|
|
281
|
+
height="large"
|
|
282
|
+
isLoading={isLoading}
|
|
283
|
+
noWrapper={true}
|
|
284
|
+
showLegend={forecastData.length > 0}
|
|
285
|
+
/>
|
|
286
|
+
);
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
const renderComparisons = () => {
|
|
290
|
+
if (!showComparisons || !temporal?.enableComparisons || chartData.length === 0) {
|
|
291
|
+
return null;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const currentValue = chartData[chartData.length - 1]?.value || 0;
|
|
295
|
+
const previousValue = chartData[chartData.length - 2]?.value || 0;
|
|
296
|
+
const periodChange = previousValue !== 0 ? ((currentValue - previousValue) / Math.abs(previousValue)) * 100 : 0;
|
|
297
|
+
|
|
298
|
+
return (
|
|
299
|
+
<div className="border-t pt-4 mt-4">
|
|
300
|
+
<h4 className="text-sm font-semibold text-foreground mb-3">Period Comparisons</h4>
|
|
301
|
+
<div className="grid grid-cols-3 gap-4">
|
|
302
|
+
<div className="text-center">
|
|
303
|
+
<div className="text-2xl font-bold">{currentValue.toFixed(0)}</div>
|
|
304
|
+
<div className="text-xs text-muted-foreground">Current</div>
|
|
305
|
+
</div>
|
|
306
|
+
<div className="text-center">
|
|
307
|
+
<div className="text-2xl font-bold">{previousValue.toFixed(0)}</div>
|
|
308
|
+
<div className="text-xs text-muted-foreground">Previous</div>
|
|
309
|
+
</div>
|
|
310
|
+
<div className="text-center">
|
|
311
|
+
<div className={cn(
|
|
312
|
+
"text-2xl font-bold",
|
|
313
|
+
periodChange > 0 ? 'text-status-success' : periodChange < 0 ? 'text-status-error' : 'text-muted-foreground'
|
|
314
|
+
)}>
|
|
315
|
+
{periodChange > 0 ? '+' : ''}{periodChange.toFixed(1)}%
|
|
316
|
+
</div>
|
|
317
|
+
<div className="text-xs text-muted-foreground">Change</div>
|
|
318
|
+
</div>
|
|
319
|
+
</div>
|
|
320
|
+
</div>
|
|
321
|
+
);
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
return (
|
|
325
|
+
<Card className={cn('p-6', className)} category={category} data-component-name="TrendAnalysisPanel">
|
|
326
|
+
{headerSlot}
|
|
327
|
+
{renderHeader && renderHeader()}
|
|
328
|
+
|
|
329
|
+
{renderControls()}
|
|
330
|
+
{renderChart()}
|
|
331
|
+
{renderComparisons()}
|
|
332
|
+
|
|
333
|
+
{renderFooter && renderFooter()}
|
|
334
|
+
{footerSlot}
|
|
335
|
+
</Card>
|
|
336
|
+
);
|
|
337
|
+
};
|
package/src/organisms/index.ts
CHANGED
|
@@ -2,4 +2,7 @@
|
|
|
2
2
|
// These are complete, reusable component interfaces that compose molecules and atoms
|
|
3
3
|
|
|
4
4
|
// Showcase components
|
|
5
|
-
export { ComponentShowcasePage } from './showcase/ComponentShowcasePage';
|
|
5
|
+
export { ComponentShowcasePage } from './showcase/ComponentShowcasePage';
|
|
6
|
+
|
|
7
|
+
// Entity components - Cross-domain configurable panels
|
|
8
|
+
export * from './entity';
|
|
@@ -1,71 +1,71 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { AdminDashboardTemplate } from '../../templates/admin';
|
|
3
3
|
import type { MetricCard, ChartConfig, ActivityItem, AlertItem } from '../../templates/admin';
|
|
4
|
-
import { Users, DollarSign, TrendingUp } from 'lucide-react';
|
|
4
|
+
import { Users, DollarSign, TrendingUp, ShoppingCart, Calendar, CreditCard } from 'lucide-react';
|
|
5
5
|
|
|
6
6
|
// Mock data for demonstration
|
|
7
7
|
const mockMetrics: MetricCard[] = [
|
|
8
8
|
{
|
|
9
|
-
title: 'Total
|
|
10
|
-
value: '
|
|
11
|
-
change:
|
|
12
|
-
changePeriod: 'from last month',
|
|
13
|
-
icon: <Users className="w-5 h-5" />,
|
|
14
|
-
category: 1,
|
|
15
|
-
onClick: () => console.log('Navigate to users')
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
title: 'Revenue',
|
|
19
|
-
value: '$89,432',
|
|
20
|
-
change: 8.2,
|
|
9
|
+
title: 'Total Revenue',
|
|
10
|
+
value: '$124,832',
|
|
11
|
+
change: 15.3,
|
|
21
12
|
changePeriod: 'from last month',
|
|
22
13
|
icon: <DollarSign className="w-5 h-5" />,
|
|
23
14
|
category: 2,
|
|
24
15
|
onClick: () => console.log('Navigate to revenue')
|
|
25
16
|
},
|
|
26
17
|
{
|
|
27
|
-
title: '
|
|
28
|
-
value: '
|
|
29
|
-
change:
|
|
30
|
-
changePeriod: 'from last
|
|
31
|
-
icon: <
|
|
32
|
-
category:
|
|
33
|
-
onClick: () => console.log('Navigate to
|
|
18
|
+
title: 'Active Users',
|
|
19
|
+
value: '8,429',
|
|
20
|
+
change: 12.5,
|
|
21
|
+
changePeriod: 'from last week',
|
|
22
|
+
icon: <Users className="w-5 h-5" />,
|
|
23
|
+
category: 1,
|
|
24
|
+
onClick: () => console.log('Navigate to users')
|
|
34
25
|
},
|
|
35
26
|
{
|
|
36
|
-
title: '
|
|
37
|
-
value: '
|
|
38
|
-
change:
|
|
27
|
+
title: 'Daily Orders',
|
|
28
|
+
value: '342',
|
|
29
|
+
change: 8.7,
|
|
39
30
|
changePeriod: 'from yesterday',
|
|
40
|
-
icon: <
|
|
31
|
+
icon: <ShoppingCart className="w-5 h-5" />,
|
|
32
|
+
category: 3,
|
|
33
|
+
onClick: () => console.log('Navigate to orders')
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
title: 'Conversion Rate',
|
|
37
|
+
value: '4.2%',
|
|
38
|
+
change: -1.8,
|
|
39
|
+
changePeriod: 'from last month',
|
|
40
|
+
icon: <TrendingUp className="w-5 h-5" />,
|
|
41
41
|
category: 4,
|
|
42
|
-
onClick: () => console.log('Navigate to
|
|
42
|
+
onClick: () => console.log('Navigate to analytics')
|
|
43
43
|
}
|
|
44
44
|
];
|
|
45
45
|
|
|
46
46
|
const mockCharts: ChartConfig[] = [
|
|
47
47
|
{
|
|
48
|
-
title: '
|
|
48
|
+
title: 'Revenue Trends',
|
|
49
49
|
type: 'line',
|
|
50
50
|
data: [
|
|
51
|
-
{ label: 'Jan', value:
|
|
52
|
-
{ label: 'Feb', value:
|
|
53
|
-
{ label: 'Mar', value:
|
|
54
|
-
{ label: 'Apr', value:
|
|
55
|
-
{ label: 'May', value:
|
|
56
|
-
{ label: 'Jun', value:
|
|
51
|
+
{ label: 'Jan', value: 89000 },
|
|
52
|
+
{ label: 'Feb', value: 96000 },
|
|
53
|
+
{ label: 'Mar', value: 108000 },
|
|
54
|
+
{ label: 'Apr', value: 115000 },
|
|
55
|
+
{ label: 'May', value: 118000 },
|
|
56
|
+
{ label: 'Jun', value: 125000 }
|
|
57
57
|
],
|
|
58
|
-
category:
|
|
58
|
+
category: 2
|
|
59
59
|
},
|
|
60
60
|
{
|
|
61
|
-
title: '
|
|
61
|
+
title: 'Order Distribution',
|
|
62
62
|
type: 'pie',
|
|
63
63
|
data: [
|
|
64
|
-
{ label: '
|
|
65
|
-
{ label: '
|
|
66
|
-
{ label: '
|
|
64
|
+
{ label: 'Online', value: 65, category: 1 },
|
|
65
|
+
{ label: 'Mobile App', value: 25, category: 3 },
|
|
66
|
+
{ label: 'In-Store', value: 10, category: 4 }
|
|
67
67
|
],
|
|
68
|
-
category:
|
|
68
|
+
category: 3
|
|
69
69
|
}
|
|
70
70
|
];
|
|
71
71
|
|
|
@@ -73,44 +73,44 @@ const mockActivities: ActivityItem[] = [
|
|
|
73
73
|
{
|
|
74
74
|
id: '1',
|
|
75
75
|
type: 'user',
|
|
76
|
-
message: 'New
|
|
77
|
-
timestamp: new Date(Date.now() -
|
|
78
|
-
user: 'System'
|
|
76
|
+
message: 'New customer order placed: $342.50',
|
|
77
|
+
timestamp: new Date(Date.now() - 2 * 60 * 1000),
|
|
78
|
+
user: 'Order System'
|
|
79
79
|
},
|
|
80
80
|
{
|
|
81
81
|
id: '2',
|
|
82
|
-
type: '
|
|
83
|
-
message: '
|
|
84
|
-
timestamp: new Date(Date.now() -
|
|
85
|
-
user: '
|
|
82
|
+
type: 'content',
|
|
83
|
+
message: 'Product "Summer Collection 2024" launched',
|
|
84
|
+
timestamp: new Date(Date.now() - 8 * 60 * 1000),
|
|
85
|
+
user: 'Product Team'
|
|
86
86
|
},
|
|
87
87
|
{
|
|
88
88
|
id: '3',
|
|
89
|
-
type: '
|
|
90
|
-
message: '
|
|
91
|
-
timestamp: new Date(Date.now() -
|
|
92
|
-
user: '
|
|
89
|
+
type: 'user',
|
|
90
|
+
message: 'Premium subscription activated: emma.clark@example.com',
|
|
91
|
+
timestamp: new Date(Date.now() - 15 * 60 * 1000),
|
|
92
|
+
user: 'Billing System'
|
|
93
93
|
},
|
|
94
94
|
{
|
|
95
95
|
id: '4',
|
|
96
96
|
type: 'system',
|
|
97
|
-
message: '
|
|
98
|
-
timestamp: new Date(Date.now() -
|
|
99
|
-
user: '
|
|
97
|
+
message: 'Daily revenue report generated: $24,892',
|
|
98
|
+
timestamp: new Date(Date.now() - 25 * 60 * 1000),
|
|
99
|
+
user: 'Analytics Engine'
|
|
100
100
|
},
|
|
101
101
|
{
|
|
102
102
|
id: '5',
|
|
103
103
|
type: 'user',
|
|
104
|
-
message: '
|
|
105
|
-
timestamp: new Date(Date.now() -
|
|
106
|
-
user: '
|
|
104
|
+
message: 'Customer support ticket resolved #8429',
|
|
105
|
+
timestamp: new Date(Date.now() - 35 * 60 * 1000),
|
|
106
|
+
user: 'Support Team'
|
|
107
107
|
},
|
|
108
108
|
{
|
|
109
109
|
id: '6',
|
|
110
|
-
type: '
|
|
111
|
-
message: '
|
|
112
|
-
timestamp: new Date(Date.now() -
|
|
113
|
-
user: '
|
|
110
|
+
type: 'security',
|
|
111
|
+
message: 'Weekly security scan completed - no issues found',
|
|
112
|
+
timestamp: new Date(Date.now() - 45 * 60 * 1000),
|
|
113
|
+
user: 'Security Monitor'
|
|
114
114
|
}
|
|
115
115
|
];
|
|
116
116
|
|
|
@@ -118,26 +118,26 @@ const mockAlerts: AlertItem[] = [
|
|
|
118
118
|
{
|
|
119
119
|
id: '1',
|
|
120
120
|
severity: 'critical',
|
|
121
|
-
title: '
|
|
122
|
-
description: '
|
|
123
|
-
timestamp: new Date(Date.now() -
|
|
124
|
-
onResolve: () => console.log('Resolving
|
|
121
|
+
title: 'Payment Gateway Error',
|
|
122
|
+
description: 'Multiple payment failures detected in the last hour',
|
|
123
|
+
timestamp: new Date(Date.now() - 8 * 60 * 1000),
|
|
124
|
+
onResolve: () => console.log('Resolving payment gateway alert')
|
|
125
125
|
},
|
|
126
126
|
{
|
|
127
127
|
id: '2',
|
|
128
128
|
severity: 'medium',
|
|
129
|
-
title: 'Low
|
|
130
|
-
description: '
|
|
131
|
-
timestamp: new Date(Date.now() -
|
|
132
|
-
onResolve: () => console.log('Resolving
|
|
129
|
+
title: 'Inventory Low',
|
|
130
|
+
description: '5 products are running low on stock',
|
|
131
|
+
timestamp: new Date(Date.now() - 20 * 60 * 1000),
|
|
132
|
+
onResolve: () => console.log('Resolving inventory alert')
|
|
133
133
|
},
|
|
134
134
|
{
|
|
135
135
|
id: '3',
|
|
136
136
|
severity: 'low',
|
|
137
|
-
title: '
|
|
138
|
-
description: '
|
|
139
|
-
timestamp: new Date(Date.now() -
|
|
140
|
-
onResolve: () => console.log('Resolving
|
|
137
|
+
title: 'API Rate Limit Warning',
|
|
138
|
+
description: 'Third-party API usage at 75% of daily limit',
|
|
139
|
+
timestamp: new Date(Date.now() - 40 * 60 * 1000),
|
|
140
|
+
onResolve: () => console.log('Resolving API rate limit alert')
|
|
141
141
|
}
|
|
142
142
|
];
|
|
143
143
|
|
|
@@ -148,8 +148,8 @@ export const AdminDashboardShowcase: React.FC = () => {
|
|
|
148
148
|
|
|
149
149
|
return (
|
|
150
150
|
<AdminDashboardTemplate
|
|
151
|
-
title="
|
|
152
|
-
description="Monitor
|
|
151
|
+
title="Business Dashboard"
|
|
152
|
+
description="Monitor revenue, orders, customers, and operational health"
|
|
153
153
|
metrics={mockMetrics}
|
|
154
154
|
charts={mockCharts}
|
|
155
155
|
activities={mockActivities}
|
|
@@ -159,10 +159,12 @@ export const AdminDashboardShowcase: React.FC = () => {
|
|
|
159
159
|
actions={
|
|
160
160
|
<div className="flex gap-2">
|
|
161
161
|
<button className="px-3 py-2 text-sm border border-input rounded-md hover:bg-muted">
|
|
162
|
+
<Calendar className="w-4 h-4 mr-2 inline" />
|
|
162
163
|
Export Report
|
|
163
164
|
</button>
|
|
164
|
-
<button className="px-3 py-2 text-sm bg-category-
|
|
165
|
-
|
|
165
|
+
<button className="px-3 py-2 text-sm bg-category-2 text-white rounded-md hover:bg-category-2/90">
|
|
166
|
+
<CreditCard className="w-4 h-4 mr-2 inline" />
|
|
167
|
+
View Transactions
|
|
166
168
|
</button>
|
|
167
169
|
</div>
|
|
168
170
|
}
|