@pattern-stack/frontend-patterns 0.0.6 → 0.1.1

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 (86) hide show
  1. package/dist/atoms/composed/index.d.ts +0 -1
  2. package/dist/atoms/composed/index.d.ts.map +1 -1
  3. package/dist/atoms/types/index.d.ts +0 -2
  4. package/dist/atoms/types/index.d.ts.map +1 -1
  5. package/dist/atoms/ui/ErrorBoundary.d.ts +1 -1
  6. package/dist/atoms/ui/button.d.ts +1 -1
  7. package/dist/atoms/utils/utils.d.ts +0 -2
  8. package/dist/atoms/utils/utils.d.ts.map +1 -1
  9. package/dist/features/auth/components/ProtectedRoute.d.ts +1 -1
  10. package/dist/frontend-patterns.css +1 -1
  11. package/dist/index.es.js +15 -403
  12. package/dist/index.es.js.map +1 -1
  13. package/dist/index.js +14 -403
  14. package/dist/index.js.map +1 -1
  15. package/dist/molecules/layout/Sidebar.d.ts.map +1 -1
  16. package/dist/molecules/layout/SidebarButton/SidebarButton.d.ts +0 -2
  17. package/dist/molecules/layout/SidebarButton/SidebarButton.d.ts.map +1 -1
  18. package/dist/molecules/layout/index.d.ts +0 -3
  19. package/dist/molecules/layout/index.d.ts.map +1 -1
  20. package/dist/templates/factory.d.ts +1 -2
  21. package/dist/templates/factory.d.ts.map +1 -1
  22. package/dist/templates/index.d.ts.map +1 -1
  23. package/package.json +3 -7
  24. package/src/App.tsx +1 -11
  25. package/src/atoms/composed/index.ts +0 -1
  26. package/src/atoms/types/index.ts +1 -3
  27. package/src/atoms/utils/utils.ts +2 -4
  28. package/src/molecules/layout/Sidebar.tsx +23 -10
  29. package/src/molecules/layout/SidebarButton/SidebarButton.tsx +10 -32
  30. package/src/molecules/layout/index.ts +1 -4
  31. package/src/organisms/index.ts +1 -5
  32. package/src/pages/AdminShowcase/AdminDashboardShowcase.tsx +75 -77
  33. package/src/pages/AdminShowcase/index.tsx +1 -2
  34. package/src/pages/index.ts +1 -2
  35. package/src/templates/factory.tsx +7 -14
  36. package/src/templates/index.ts +0 -4
  37. package/dist/atoms/composed/SalesPanel/SalesPanel.d.ts +0 -19
  38. package/dist/atoms/composed/SalesPanel/SalesPanel.d.ts.map +0 -1
  39. package/dist/atoms/composed/SalesPanel/index.d.ts +0 -2
  40. package/dist/atoms/composed/SalesPanel/index.d.ts.map +0 -1
  41. package/dist/atoms/composed/SalesPanel/mockSalesData.d.ts +0 -63
  42. package/dist/atoms/composed/SalesPanel/mockSalesData.d.ts.map +0 -1
  43. package/dist/atoms/types/entity-config.d.ts +0 -117
  44. package/dist/atoms/types/entity-config.d.ts.map +0 -1
  45. package/dist/atoms/types/navigation.d.ts +0 -30
  46. package/dist/atoms/types/navigation.d.ts.map +0 -1
  47. package/dist/atoms/utils/icon-resolver.d.ts +0 -72
  48. package/dist/atoms/utils/icon-resolver.d.ts.map +0 -1
  49. package/dist/atoms/utils/metric-engine.d.ts +0 -30
  50. package/dist/atoms/utils/metric-engine.d.ts.map +0 -1
  51. package/dist/molecules/layout/DashboardWithSidePanel/DashboardWithSidePanel.d.ts +0 -16
  52. package/dist/molecules/layout/DashboardWithSidePanel/DashboardWithSidePanel.d.ts.map +0 -1
  53. package/dist/molecules/layout/DashboardWithSidePanel/index.d.ts +0 -2
  54. package/dist/molecules/layout/DashboardWithSidePanel/index.d.ts.map +0 -1
  55. package/dist/molecules/layout/NavigationContext.d.ts +0 -15
  56. package/dist/molecules/layout/NavigationContext.d.ts.map +0 -1
  57. package/src/__tests__/atoms/composed/databadge.test.tsx +0 -106
  58. package/src/__tests__/atoms/composed/statcard.test.tsx +0 -133
  59. package/src/__tests__/atoms/utils/icon-resolver.test.tsx +0 -140
  60. package/src/atoms/composed/SalesPanel/SalesPanel.tsx +0 -116
  61. package/src/atoms/composed/SalesPanel/index.ts +0 -1
  62. package/src/atoms/composed/SalesPanel/mockSalesData.ts +0 -151
  63. package/src/atoms/types/entity-config.ts +0 -127
  64. package/src/atoms/types/navigation.ts +0 -43
  65. package/src/atoms/utils/icon-resolver.tsx +0 -54
  66. package/src/atoms/utils/metric-engine.ts +0 -236
  67. package/src/molecules/layout/DashboardWithSidePanel/DashboardWithSidePanel.tsx +0 -42
  68. package/src/molecules/layout/DashboardWithSidePanel/index.ts +0 -1
  69. package/src/molecules/layout/NavigationContext.tsx +0 -63
  70. package/src/organisms/entity/CategoryBreakdownPanel.tsx +0 -427
  71. package/src/organisms/entity/EntityListPanel.tsx +0 -339
  72. package/src/organisms/entity/MetricsOverviewPanel.tsx +0 -236
  73. package/src/organisms/entity/TrendAnalysisPanel.tsx +0 -337
  74. package/src/organisms/entity/index.ts +0 -4
  75. package/src/pages/AdminShowcase/SalesPerformanceDashboard.tsx +0 -158
  76. package/src/pages/EntityShowcase/EntityManagementShowcase.tsx +0 -137
  77. package/src/pages/EntityShowcase/EntityPerformanceShowcase.tsx +0 -117
  78. package/src/pages/EntityShowcase/index.ts +0 -2
  79. package/src/pages/EntityTemplateExample.tsx +0 -229
  80. package/src/pages/TestEntityTemplate.tsx +0 -40
  81. package/src/templates/entity/EntityManagementTemplate.tsx +0 -430
  82. package/src/templates/entity/EntityPerformanceDashboardTemplate.tsx +0 -277
  83. package/src/templates/entity/configs/financial-config.ts +0 -141
  84. package/src/templates/entity/configs/index.ts +0 -1
  85. package/src/templates/entity/index.ts +0 -3
  86. package/src/templates/financial/FinancialDashboardTemplate.tsx +0 -326
@@ -1,133 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest'
2
- import { render, screen, userEvent } from '../../utils'
3
- import { StatCard } from '../../../atoms/composed/StatCard'
4
-
5
- describe('StatCard (Composed)', () => {
6
- it('renders basic stat card with title and value', () => {
7
- render(<StatCard title="Total Users" value="1,234" />)
8
-
9
- expect(screen.getByText('Total Users')).toBeInTheDocument()
10
- expect(screen.getByText('1,234')).toBeInTheDocument()
11
- })
12
-
13
- it('renders with subtitle', () => {
14
- render(
15
- <StatCard
16
- title="Revenue"
17
- value="$45,678"
18
- subtitle="+12% from last month"
19
- />
20
- )
21
-
22
- expect(screen.getByText('Revenue')).toBeInTheDocument()
23
- expect(screen.getByText('$45,678')).toBeInTheDocument()
24
- expect(screen.getByText('+12% from last month')).toBeInTheDocument()
25
- })
26
-
27
- it('renders with icon', () => {
28
- render(
29
- <StatCard
30
- title="Orders"
31
- value="567"
32
- icon="ShoppingCart"
33
- />
34
- )
35
-
36
- expect(screen.getByText('Orders')).toBeInTheDocument()
37
- expect(screen.getByText('567')).toBeInTheDocument()
38
- // Icon should be rendered (we can't easily test the actual icon, but we can test it doesn't crash)
39
- })
40
-
41
- it('applies category theming', () => {
42
- render(<StatCard title="Test" value="123" category={3} />)
43
-
44
- const card = screen.getByText('Test').closest('[data-component-name="StatCard"]')
45
- expect(card).toBeInTheDocument()
46
- expect(card).toHaveAttribute('data-component-name', 'StatCard')
47
- })
48
-
49
- it('handles click events', async () => {
50
- const user = userEvent.setup()
51
- const handleClick = vi.fn()
52
-
53
- render(
54
- <StatCard
55
- title="Clickable Card"
56
- value="999"
57
- onClick={handleClick}
58
- />
59
- )
60
-
61
- const card = screen.getByText('Clickable Card').closest('[role="button"]')
62
- expect(card).toBeInTheDocument()
63
-
64
- await user.click(card!)
65
- expect(handleClick).toHaveBeenCalledOnce()
66
- })
67
-
68
- it('applies hover effects when clickable', () => {
69
- render(
70
- <StatCard
71
- title="Hoverable"
72
- value="555"
73
- onClick={() => {}}
74
- />
75
- )
76
-
77
- const card = screen.getByText('Hoverable').closest('[role="button"]')
78
- expect(card).toHaveClass('cursor-pointer')
79
- expect(card).toHaveClass('hover:shadow-md')
80
- })
81
-
82
- it('does not apply click styles when not clickable', () => {
83
- render(<StatCard title="Static Card" value="111" />)
84
-
85
- const card = screen.getByText('Static Card').closest('div')
86
- expect(card).not.toHaveAttribute('role', 'button')
87
- expect(card).not.toHaveClass('cursor-pointer')
88
- })
89
-
90
- it('displays numbers as provided', () => {
91
- render(<StatCard title="Big Number" value={1234567} />)
92
-
93
- expect(screen.getByText('1234567')).toBeInTheDocument()
94
- })
95
-
96
- it('handles string and number values', () => {
97
- const { rerender } = render(<StatCard title="String" value="Custom Text" />)
98
- expect(screen.getByText('Custom Text')).toBeInTheDocument()
99
-
100
- rerender(<StatCard title="Number" value={42} />)
101
- expect(screen.getByText('42')).toBeInTheDocument()
102
- })
103
-
104
- it('applies custom className', () => {
105
- render(
106
- <StatCard
107
- title="Custom"
108
- value="123"
109
- className="custom-stat-card"
110
- />
111
- )
112
-
113
- const card = screen.getByText('Custom').closest('.custom-stat-card')
114
- expect(card).toBeInTheDocument()
115
- })
116
-
117
- it('renders loading state', () => {
118
- render(<StatCard title="Loading" value="..." isLoading={true} />)
119
-
120
- const card = screen.getByText('Loading').closest('[data-component-name="StatCard"]')
121
- expect(card).toBeInTheDocument()
122
- // Check for skeleton elements in loading state
123
- const skeletons = card?.querySelectorAll('.animate-pulse')
124
- expect(skeletons?.length).toBeGreaterThan(0)
125
- })
126
-
127
- it('renders with data component name', () => {
128
- render(<StatCard title="Test Card" value="123" />)
129
-
130
- const card = screen.getByText('Test Card').closest('[data-component-name="StatCard"]')
131
- expect(card).toHaveAttribute('data-component-name', 'StatCard')
132
- })
133
- })
@@ -1,140 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest'
2
- import { render, screen } from '../../utils'
3
- import { Icon, getIcon, iconMap } from '../../../atoms/utils/icon-resolver'
4
-
5
- // Mock console.warn to avoid noise in tests
6
- const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
7
-
8
- describe('Icon Resolver', () => {
9
- afterEach(() => {
10
- consoleSpy.mockClear()
11
- })
12
-
13
- describe('Icon component', () => {
14
- it('renders valid icon', () => {
15
- render(<Icon name="Home" data-testid="home-icon" />)
16
-
17
- const icon = screen.getByTestId('home-icon')
18
- expect(icon).toBeInTheDocument()
19
- })
20
-
21
- it('applies default className', () => {
22
- render(<Icon name="Users" data-testid="users-icon" />)
23
-
24
- const icon = screen.getByTestId('users-icon')
25
- expect(icon).toHaveClass('w-5', 'h-5')
26
- })
27
-
28
- it('applies custom className', () => {
29
- render(<Icon name="Settings" className="w-8 h-8 text-blue-500" data-testid="settings-icon" />)
30
-
31
- const icon = screen.getByTestId('settings-icon')
32
- expect(icon).toHaveClass('w-8', 'h-8', 'text-blue-500')
33
- })
34
-
35
- it('applies size prop', () => {
36
- render(<Icon name="Search" size={24} data-testid="search-icon" />)
37
-
38
- const icon = screen.getByTestId('search-icon')
39
- expect(icon).toHaveAttribute('width', '24')
40
- expect(icon).toHaveAttribute('height', '24')
41
- })
42
-
43
- it('renders fallback icon for invalid name', () => {
44
- render(<Icon name="InvalidIcon" data-testid="fallback-icon" />)
45
-
46
- const icon = screen.getByTestId('fallback-icon')
47
- expect(icon).toBeInTheDocument()
48
- expect(consoleSpy).toHaveBeenCalledWith('Icon "InvalidIcon" not found. Using default Menu icon.')
49
- })
50
-
51
- it('handles undefined icon name gracefully', () => {
52
- render(<Icon name={undefined as any} data-testid="undefined-icon" />)
53
-
54
- const icon = screen.getByTestId('undefined-icon')
55
- expect(icon).toBeInTheDocument()
56
- expect(consoleSpy).toHaveBeenCalled()
57
- })
58
- })
59
-
60
- describe('getIcon function', () => {
61
- it('returns icon component for valid name', () => {
62
- const HomeIcon = getIcon('Home')
63
- expect(HomeIcon).toBeDefined()
64
- expect(typeof HomeIcon).toBe('function')
65
- })
66
-
67
- it('returns Menu icon for invalid name', () => {
68
- const InvalidIcon = getIcon('InvalidIcon' as any)
69
- expect(InvalidIcon).toBeDefined()
70
- expect(typeof InvalidIcon).toBe('function')
71
- })
72
-
73
- it('returns Menu icon for undefined name', () => {
74
- const UndefinedIcon = getIcon(undefined as any)
75
- expect(UndefinedIcon).toBeDefined()
76
- })
77
- })
78
-
79
- describe('iconMap', () => {
80
- it('contains expected common icons', () => {
81
- const expectedIcons = [
82
- 'Home', 'Users', 'Settings', 'Search', 'Menu',
83
- 'ChevronDown', 'ChevronRight', 'X', 'Plus',
84
- 'ShoppingCart', 'Calendar', 'Mail', 'Phone'
85
- ]
86
-
87
- expectedIcons.forEach(iconName => {
88
- expect(iconMap).toHaveProperty(iconName)
89
- expect(typeof iconMap[iconName]).toBe('function')
90
- })
91
- })
92
-
93
- it('has reasonable number of icons', () => {
94
- const iconCount = Object.keys(iconMap).length
95
- expect(iconCount).toBeGreaterThan(30)
96
- expect(iconCount).toBeLessThan(100) // Keep it manageable
97
- })
98
-
99
- it('all icon map values are functions', () => {
100
- Object.values(iconMap).forEach(iconComponent => {
101
- expect(typeof iconComponent).toBe('function')
102
- })
103
- })
104
- })
105
-
106
- describe('Icon rendering variations', () => {
107
- const testIcons = ['Home', 'Users', 'Settings', 'Search', 'Bell']
108
-
109
- testIcons.forEach(iconName => {
110
- it(`renders ${iconName} icon without errors`, () => {
111
- render(<Icon name={iconName} data-testid={`${iconName.toLowerCase()}-icon`} />)
112
-
113
- const icon = screen.getByTestId(`${iconName.toLowerCase()}-icon`)
114
- expect(icon).toBeInTheDocument()
115
- })
116
- })
117
- })
118
-
119
- describe('Integration with real icon names', () => {
120
- it('renders navigation icons correctly', () => {
121
- const navIcons = ['Home', 'Users', 'Settings', 'FileText', 'BarChart']
122
-
123
- navIcons.forEach(iconName => {
124
- const { unmount } = render(<Icon name={iconName} />)
125
- // If it renders without throwing, it's valid
126
- unmount()
127
- })
128
- })
129
-
130
- it('renders action icons correctly', () => {
131
- const actionIcons = ['Plus', 'Edit', 'Trash2', 'Save', 'Download']
132
-
133
- actionIcons.forEach(iconName => {
134
- const { unmount } = render(<Icon name={iconName} />)
135
- // If it renders without throwing, it's valid
136
- unmount()
137
- })
138
- })
139
- })
140
- })
@@ -1,116 +0,0 @@
1
- import React from 'react';
2
- import { DataBadge } from '../DataBadge';
3
- import { Button } from '../../ui/button';
4
- import {
5
- Target,
6
- ExternalLink
7
- } from 'lucide-react';
8
-
9
- interface SalesPanelProps {
10
- sales: Array<{
11
- id: string;
12
- customer: string;
13
- product: string;
14
- amount: number;
15
- stage: string;
16
- salesperson: string;
17
- region: string;
18
- closeDate: string;
19
- dealSize: string;
20
- }>;
21
- onSaleClick?: (sale: any) => void;
22
- onClose?: () => void;
23
- }
24
-
25
- const getStageStatus = (stage: string) => {
26
- switch (stage) {
27
- case 'Closed Won': return 'success';
28
- case 'Negotiation': return 'warning';
29
- case 'Proposal Sent': return 'info';
30
- case 'Qualified': return 'info';
31
- case 'Discovery': return 'neutral';
32
- default: return 'neutral';
33
- }
34
- };
35
-
36
- export const SalesPanel: React.FC<SalesPanelProps> = ({
37
- sales,
38
- onSaleClick,
39
- onClose
40
- }) => {
41
- const topDeals = sales.slice(0, 5); // Show only top 5 recent deals
42
- const totalValue = sales.reduce((sum, sale) => sum + sale.amount, 0);
43
-
44
- return (
45
- <div className="fixed right-0 top-16 h-[calc(100vh-4rem)] w-72 bg-background border-l border-border shadow-lg flex flex-col z-30">
46
- {/* Header */}
47
- <div className="p-3 border-b border-border">
48
- <div className="flex items-center justify-between">
49
- <h3 className="font-medium flex items-center gap-2">
50
- <Target className="w-4 h-4" />
51
- Pipeline
52
- </h3>
53
- {onClose && (
54
- <Button variant="ghost" size="sm" onClick={onClose}>
55
- ×
56
- </Button>
57
- )}
58
- </div>
59
- </div>
60
-
61
- {/* Quick Stats */}
62
- <div className="p-3 border-b border-border">
63
- <div className="space-y-2">
64
- <div className="flex justify-between">
65
- <span className="text-sm text-muted-foreground">Total Value</span>
66
- <span className="font-semibold text-green-600">${totalValue.toLocaleString()}</span>
67
- </div>
68
- <div className="flex justify-between">
69
- <span className="text-sm text-muted-foreground">Active Deals</span>
70
- <span className="font-semibold">{sales.length}</span>
71
- </div>
72
- </div>
73
- </div>
74
-
75
- {/* Recent Deals */}
76
- <div className="flex-1 overflow-auto p-3">
77
- <h4 className="text-sm font-medium mb-3">Recent Opportunities</h4>
78
- <div className="space-y-2">
79
- {topDeals.map((sale) => (
80
- <div
81
- key={sale.id}
82
- className="p-2 border border-border rounded-md hover:bg-muted/50 cursor-pointer transition-colors"
83
- onClick={() => onSaleClick?.(sale)}
84
- >
85
- <div className="flex justify-between items-start mb-1">
86
- <div className="flex-1 min-w-0">
87
- <p className="text-sm font-medium truncate">{sale.customer}</p>
88
- <p className="text-xs text-muted-foreground truncate">{sale.product}</p>
89
- </div>
90
- <div className="text-right ml-2">
91
- <p className="text-sm font-semibold text-green-600">
92
- ${sale.amount.toLocaleString()}
93
- </p>
94
- </div>
95
- </div>
96
- <div className="flex justify-between items-center">
97
- <DataBadge variant="status" status={getStageStatus(sale.stage)}>
98
- {sale.stage}
99
- </DataBadge>
100
- <span className="text-xs text-muted-foreground">{sale.salesperson}</span>
101
- </div>
102
- </div>
103
- ))}
104
- </div>
105
- </div>
106
-
107
- {/* Footer */}
108
- <div className="p-3 border-t border-border">
109
- <Button variant="outline" size="sm" className="w-full">
110
- <ExternalLink className="w-4 h-4 mr-2" />
111
- View All Deals
112
- </Button>
113
- </div>
114
- </div>
115
- );
116
- };
@@ -1 +0,0 @@
1
- export { SalesPanel } from './SalesPanel';
@@ -1,151 +0,0 @@
1
- // Mock sales data for demonstrations
2
- export const mockSalesData = [
3
- {
4
- id: 'SALE-2024-001',
5
- customer: 'TechCorp Industries',
6
- product: 'Enterprise License',
7
- amount: 45000,
8
- stage: 'Closed Won',
9
- salesperson: 'Sarah Chen',
10
- region: 'North America',
11
- closeDate: '2024-06-08',
12
- dealSize: 'Large'
13
- },
14
- {
15
- id: 'SALE-2024-002',
16
- customer: 'StartupXYZ',
17
- product: 'Professional Plan',
18
- amount: 12000,
19
- stage: 'Proposal Sent',
20
- salesperson: 'Mike Johnson',
21
- region: 'North America',
22
- closeDate: '2024-06-15',
23
- dealSize: 'Medium'
24
- },
25
- {
26
- id: 'SALE-2024-003',
27
- customer: 'Global Enterprises Ltd',
28
- product: 'Enterprise Suite',
29
- amount: 78000,
30
- stage: 'Negotiation',
31
- salesperson: 'Lisa Wang',
32
- region: 'Europe',
33
- closeDate: '2024-06-20',
34
- dealSize: 'Large'
35
- },
36
- {
37
- id: 'SALE-2024-004',
38
- customer: 'Innovation Labs',
39
- product: 'Starter Package',
40
- amount: 5000,
41
- stage: 'Qualified',
42
- salesperson: 'David Kim',
43
- region: 'Asia Pacific',
44
- closeDate: '2024-06-25',
45
- dealSize: 'Small'
46
- },
47
- {
48
- id: 'SALE-2024-005',
49
- customer: 'FutureTech Solutions',
50
- product: 'Custom Integration',
51
- amount: 95000,
52
- stage: 'Discovery',
53
- salesperson: 'Sarah Chen',
54
- region: 'North America',
55
- closeDate: '2024-07-01',
56
- dealSize: 'Large'
57
- }
58
- ];
59
-
60
- // Sales configuration for entity template
61
- export const salesConfig = {
62
- entityType: 'performance' as const,
63
- display: {
64
- title: 'Sales Performance',
65
- subtitle: 'Monitor sales metrics, team performance, and revenue trends',
66
- category: 3 as const
67
- },
68
- metrics: [
69
- {
70
- key: 'revenue',
71
- label: 'Total Revenue',
72
- type: 'currency' as const,
73
- aggregate: 'sum',
74
- showTrend: true,
75
- category: 2
76
- },
77
- {
78
- key: 'deals',
79
- label: 'Deals Closed',
80
- type: 'number' as const,
81
- aggregate: 'count',
82
- showTrend: true,
83
- category: 3
84
- },
85
- {
86
- key: 'conversion',
87
- label: 'Conversion Rate',
88
- type: 'percentage' as const,
89
- aggregate: 'average',
90
- showTrend: true,
91
- category: 1
92
- },
93
- {
94
- key: 'pipeline',
95
- label: 'Pipeline Value',
96
- type: 'currency' as const,
97
- aggregate: 'sum',
98
- showTrend: true,
99
- category: 4
100
- }
101
- ],
102
- categories: [
103
- { key: 'region', label: 'By Region', type: 'categorical' },
104
- { key: 'product', label: 'By Product', type: 'categorical' },
105
- { key: 'stage', label: 'By Stage', type: 'categorical' }
106
- ],
107
- trends: {
108
- periods: ['7d', '30d', '90d', '1y'],
109
- defaultPeriod: '30d'
110
- }
111
- };
112
-
113
- // Sample sales performance data
114
- export const salesPerformanceData = [
115
- {
116
- id: 'sale-1',
117
- revenue: 45000,
118
- deals: 12,
119
- conversion: 0.24,
120
- pipeline: 125000,
121
- region: 'North America',
122
- product: 'Enterprise',
123
- stage: 'Closed Won',
124
- date: '2024-06-01',
125
- salesperson: 'Sarah Chen'
126
- },
127
- {
128
- id: 'sale-2',
129
- revenue: 32000,
130
- deals: 8,
131
- conversion: 0.18,
132
- pipeline: 89000,
133
- region: 'Europe',
134
- product: 'Professional',
135
- stage: 'Negotiation',
136
- date: '2024-06-02',
137
- salesperson: 'Mike Johnson'
138
- },
139
- {
140
- id: 'sale-3',
141
- revenue: 67000,
142
- deals: 15,
143
- conversion: 0.31,
144
- pipeline: 156000,
145
- region: 'Asia Pacific',
146
- product: 'Enterprise',
147
- stage: 'Closed Won',
148
- date: '2024-06-03',
149
- salesperson: 'Lisa Wang'
150
- }
151
- ];
@@ -1,127 +0,0 @@
1
- import * as React from 'react';
2
-
3
- export type EntityType = 'transactional' | 'categorical' | 'temporal';
4
-
5
- export type MetricType = 'currency' | 'percentage' | 'count' | 'duration' | 'ratio';
6
-
7
- export type AggregationType = 'sum' | 'avg' | 'count' | 'min' | 'max';
8
-
9
- export type TemporalCycle = 'daily' | 'weekly' | 'monthly' | 'quarterly' | 'yearly';
10
-
11
- export type ForecastingAlgorithm = 'linear' | 'seasonal' | 'ml';
12
-
13
- export type ActionType = 'primary' | 'secondary' | 'danger';
14
-
15
- export interface FormatConfig {
16
- decimals?: number;
17
- prefix?: string;
18
- suffix?: string;
19
- thousands?: boolean;
20
- }
21
-
22
- export interface MetricConfig {
23
- key: string;
24
- label: string;
25
- type: MetricType;
26
- format?: FormatConfig;
27
- trend?: boolean;
28
- target?: number | ((data: EntityData[]) => number);
29
- aggregation?: AggregationType;
30
- icon?: React.ComponentType;
31
- }
32
-
33
- export interface TemporalConfig {
34
- cycles: TemporalCycle[];
35
- defaultCycle: TemporalCycle;
36
- enableComparisons: boolean;
37
- forecasting?: {
38
- enabled: boolean;
39
- periods: number;
40
- algorithm: ForecastingAlgorithm;
41
- };
42
- }
43
-
44
- export interface CategoryConfig {
45
- hierarchy: string[];
46
- defaultGroupBy: string;
47
- enableDrillDown: boolean;
48
- colorCoding?: boolean;
49
- }
50
-
51
- export interface ActionConfig {
52
- label: string;
53
- type: ActionType;
54
- onClick: (context: { selectedItems?: EntityData[]; data?: EntityData[]; config?: EntityTemplateConfig }) => void | Promise<void>;
55
- icon?: React.ComponentType;
56
- permissions?: string[];
57
- validation?: (context: { selectedItems?: EntityData[]; data?: EntityData[]; config?: EntityTemplateConfig }) => boolean;
58
- }
59
-
60
- export interface BusinessRulesConfig<T> {
61
- validation?: (item: T) => string[];
62
- constraints?: {
63
- [key: string]: {
64
- min?: number;
65
- max?: number;
66
- required?: boolean;
67
- pattern?: RegExp;
68
- };
69
- };
70
- workflows?: {
71
- [status: string]: string[];
72
- };
73
- }
74
-
75
- export interface EntityDisplayConfig {
76
- title: string;
77
- description?: string;
78
- category?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
79
- }
80
-
81
- export interface EntityTemplateConfig<T = EntityData> {
82
- entityType: EntityType;
83
- display: EntityDisplayConfig;
84
- metrics: MetricConfig[];
85
- temporal?: TemporalConfig;
86
- categories?: CategoryConfig;
87
- businessRules?: BusinessRulesConfig<T>;
88
- actions?: ActionConfig[];
89
- }
90
-
91
- export interface EntityData {
92
- id: string | number;
93
- [key: string]: unknown;
94
- }
95
-
96
- export interface MetricValue {
97
- current: number;
98
- previous?: number;
99
- trend?: 'up' | 'down' | 'neutral';
100
- target?: number;
101
- formattedValue: string;
102
- }
103
-
104
- export interface CategoryBreakdown {
105
- category: string;
106
- value: number;
107
- percentage: number;
108
- color?: string;
109
- subcategories?: CategoryBreakdown[];
110
- }
111
-
112
- export interface TrendDataPoint {
113
- date: string;
114
- value: number;
115
- label?: string;
116
- }
117
-
118
- export interface EntityAnalyticsData {
119
- metrics: Record<string, MetricValue>;
120
- categories: CategoryBreakdown[];
121
- trends: Record<string, TrendDataPoint[]>;
122
- insights?: {
123
- type: 'positive' | 'negative' | 'neutral';
124
- message: string;
125
- value?: number;
126
- }[];
127
- }