@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.
- package/dist/atoms/composed/index.d.ts +0 -1
- package/dist/atoms/composed/index.d.ts.map +1 -1
- package/dist/atoms/types/index.d.ts +0 -2
- package/dist/atoms/types/index.d.ts.map +1 -1
- package/dist/atoms/ui/ErrorBoundary.d.ts +1 -1
- package/dist/atoms/ui/button.d.ts +1 -1
- package/dist/atoms/utils/utils.d.ts +0 -2
- package/dist/atoms/utils/utils.d.ts.map +1 -1
- package/dist/features/auth/components/ProtectedRoute.d.ts +1 -1
- package/dist/frontend-patterns.css +1 -1
- package/dist/index.es.js +15 -403
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +14 -403
- package/dist/index.js.map +1 -1
- package/dist/molecules/layout/Sidebar.d.ts.map +1 -1
- package/dist/molecules/layout/SidebarButton/SidebarButton.d.ts +0 -2
- package/dist/molecules/layout/SidebarButton/SidebarButton.d.ts.map +1 -1
- package/dist/molecules/layout/index.d.ts +0 -3
- package/dist/molecules/layout/index.d.ts.map +1 -1
- package/dist/templates/factory.d.ts +1 -2
- package/dist/templates/factory.d.ts.map +1 -1
- package/dist/templates/index.d.ts.map +1 -1
- package/package.json +3 -7
- package/src/App.tsx +1 -11
- package/src/atoms/composed/index.ts +0 -1
- package/src/atoms/types/index.ts +1 -3
- package/src/atoms/utils/utils.ts +2 -4
- package/src/molecules/layout/Sidebar.tsx +23 -10
- package/src/molecules/layout/SidebarButton/SidebarButton.tsx +10 -32
- package/src/molecules/layout/index.ts +1 -4
- package/src/organisms/index.ts +1 -5
- package/src/pages/AdminShowcase/AdminDashboardShowcase.tsx +75 -77
- package/src/pages/AdminShowcase/index.tsx +1 -2
- package/src/pages/index.ts +1 -2
- package/src/templates/factory.tsx +7 -14
- package/src/templates/index.ts +0 -4
- package/dist/atoms/composed/SalesPanel/SalesPanel.d.ts +0 -19
- package/dist/atoms/composed/SalesPanel/SalesPanel.d.ts.map +0 -1
- package/dist/atoms/composed/SalesPanel/index.d.ts +0 -2
- package/dist/atoms/composed/SalesPanel/index.d.ts.map +0 -1
- package/dist/atoms/composed/SalesPanel/mockSalesData.d.ts +0 -63
- package/dist/atoms/composed/SalesPanel/mockSalesData.d.ts.map +0 -1
- package/dist/atoms/types/entity-config.d.ts +0 -117
- package/dist/atoms/types/entity-config.d.ts.map +0 -1
- package/dist/atoms/types/navigation.d.ts +0 -30
- package/dist/atoms/types/navigation.d.ts.map +0 -1
- package/dist/atoms/utils/icon-resolver.d.ts +0 -72
- package/dist/atoms/utils/icon-resolver.d.ts.map +0 -1
- package/dist/atoms/utils/metric-engine.d.ts +0 -30
- package/dist/atoms/utils/metric-engine.d.ts.map +0 -1
- package/dist/molecules/layout/DashboardWithSidePanel/DashboardWithSidePanel.d.ts +0 -16
- package/dist/molecules/layout/DashboardWithSidePanel/DashboardWithSidePanel.d.ts.map +0 -1
- package/dist/molecules/layout/DashboardWithSidePanel/index.d.ts +0 -2
- package/dist/molecules/layout/DashboardWithSidePanel/index.d.ts.map +0 -1
- package/dist/molecules/layout/NavigationContext.d.ts +0 -15
- package/dist/molecules/layout/NavigationContext.d.ts.map +0 -1
- package/src/__tests__/atoms/composed/databadge.test.tsx +0 -106
- package/src/__tests__/atoms/composed/statcard.test.tsx +0 -133
- package/src/__tests__/atoms/utils/icon-resolver.test.tsx +0 -140
- package/src/atoms/composed/SalesPanel/SalesPanel.tsx +0 -116
- package/src/atoms/composed/SalesPanel/index.ts +0 -1
- package/src/atoms/composed/SalesPanel/mockSalesData.ts +0 -151
- package/src/atoms/types/entity-config.ts +0 -127
- package/src/atoms/types/navigation.ts +0 -43
- package/src/atoms/utils/icon-resolver.tsx +0 -54
- package/src/atoms/utils/metric-engine.ts +0 -236
- package/src/molecules/layout/DashboardWithSidePanel/DashboardWithSidePanel.tsx +0 -42
- package/src/molecules/layout/DashboardWithSidePanel/index.ts +0 -1
- package/src/molecules/layout/NavigationContext.tsx +0 -63
- package/src/organisms/entity/CategoryBreakdownPanel.tsx +0 -427
- package/src/organisms/entity/EntityListPanel.tsx +0 -339
- package/src/organisms/entity/MetricsOverviewPanel.tsx +0 -236
- package/src/organisms/entity/TrendAnalysisPanel.tsx +0 -337
- package/src/organisms/entity/index.ts +0 -4
- package/src/pages/AdminShowcase/SalesPerformanceDashboard.tsx +0 -158
- package/src/pages/EntityShowcase/EntityManagementShowcase.tsx +0 -137
- package/src/pages/EntityShowcase/EntityPerformanceShowcase.tsx +0 -117
- package/src/pages/EntityShowcase/index.ts +0 -2
- package/src/pages/EntityTemplateExample.tsx +0 -229
- package/src/pages/TestEntityTemplate.tsx +0 -40
- package/src/templates/entity/EntityManagementTemplate.tsx +0 -430
- package/src/templates/entity/EntityPerformanceDashboardTemplate.tsx +0 -277
- package/src/templates/entity/configs/financial-config.ts +0 -141
- package/src/templates/entity/configs/index.ts +0 -1
- package/src/templates/entity/index.ts +0 -3
- package/src/templates/financial/FinancialDashboardTemplate.tsx +0 -326
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import type { EntityTemplateConfig, EntityData } from '../../../atoms/types';
|
|
2
|
-
import { DollarSign, Target, TrendingUp, Wallet } from 'lucide-react';
|
|
3
|
-
|
|
4
|
-
export interface FinancialTransaction extends EntityData {
|
|
5
|
-
id: string;
|
|
6
|
-
amount: number;
|
|
7
|
-
category: string;
|
|
8
|
-
account: string;
|
|
9
|
-
date: string;
|
|
10
|
-
description: string;
|
|
11
|
-
type: 'income' | 'expense' | 'transfer';
|
|
12
|
-
status: 'completed' | 'pending' | 'failed';
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export const financialConfig: EntityTemplateConfig<FinancialTransaction> = {
|
|
16
|
-
entityType: 'transactional',
|
|
17
|
-
display: {
|
|
18
|
-
title: 'Financial Dashboard',
|
|
19
|
-
description: 'Personal finance overview and transaction management',
|
|
20
|
-
category: 2 // Green theme for financial success
|
|
21
|
-
},
|
|
22
|
-
metrics: [
|
|
23
|
-
{
|
|
24
|
-
key: 'totalBalance',
|
|
25
|
-
label: 'Total Balance',
|
|
26
|
-
type: 'currency',
|
|
27
|
-
trend: true,
|
|
28
|
-
icon: DollarSign,
|
|
29
|
-
aggregation: 'sum'
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
key: 'monthlyIncome',
|
|
33
|
-
label: 'Monthly Income',
|
|
34
|
-
type: 'currency',
|
|
35
|
-
trend: true,
|
|
36
|
-
icon: TrendingUp,
|
|
37
|
-
aggregation: 'sum'
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
key: 'monthlyExpenses',
|
|
41
|
-
label: 'Monthly Expenses',
|
|
42
|
-
type: 'currency',
|
|
43
|
-
trend: true,
|
|
44
|
-
icon: Wallet,
|
|
45
|
-
aggregation: 'sum'
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
key: 'savingsRate',
|
|
49
|
-
label: 'Savings Rate',
|
|
50
|
-
type: 'percentage',
|
|
51
|
-
target: 20,
|
|
52
|
-
icon: Target
|
|
53
|
-
}
|
|
54
|
-
],
|
|
55
|
-
temporal: {
|
|
56
|
-
cycles: ['monthly', 'quarterly', 'yearly'],
|
|
57
|
-
defaultCycle: 'monthly',
|
|
58
|
-
enableComparisons: true,
|
|
59
|
-
forecasting: {
|
|
60
|
-
enabled: true,
|
|
61
|
-
periods: 3,
|
|
62
|
-
algorithm: 'seasonal'
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
categories: {
|
|
66
|
-
hierarchy: ['account', 'category', 'type'],
|
|
67
|
-
defaultGroupBy: 'category',
|
|
68
|
-
enableDrillDown: true,
|
|
69
|
-
colorCoding: true
|
|
70
|
-
},
|
|
71
|
-
actions: [
|
|
72
|
-
{
|
|
73
|
-
label: 'Add Transaction',
|
|
74
|
-
type: 'primary',
|
|
75
|
-
onClick: ({ data, config }) => {
|
|
76
|
-
console.log('Adding new transaction', { data, config });
|
|
77
|
-
}
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
label: 'Generate Report',
|
|
81
|
-
type: 'secondary',
|
|
82
|
-
onClick: ({ selectedItems, data, config }) => {
|
|
83
|
-
console.log('Generating report', { selectedItems, data, config });
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
]
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
// Sample financial data for testing
|
|
90
|
-
export const sampleFinancialData: FinancialTransaction[] = [
|
|
91
|
-
{
|
|
92
|
-
id: '1',
|
|
93
|
-
amount: 5000,
|
|
94
|
-
category: 'Salary',
|
|
95
|
-
account: 'Checking',
|
|
96
|
-
date: '2024-01-15',
|
|
97
|
-
description: 'Monthly salary',
|
|
98
|
-
type: 'income',
|
|
99
|
-
status: 'completed'
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
id: '2',
|
|
103
|
-
amount: -1200,
|
|
104
|
-
category: 'Rent',
|
|
105
|
-
account: 'Checking',
|
|
106
|
-
date: '2024-01-01',
|
|
107
|
-
description: 'Monthly rent payment',
|
|
108
|
-
type: 'expense',
|
|
109
|
-
status: 'completed'
|
|
110
|
-
},
|
|
111
|
-
{
|
|
112
|
-
id: '3',
|
|
113
|
-
amount: -300,
|
|
114
|
-
category: 'Groceries',
|
|
115
|
-
account: 'Checking',
|
|
116
|
-
date: '2024-01-10',
|
|
117
|
-
description: 'Weekly groceries',
|
|
118
|
-
type: 'expense',
|
|
119
|
-
status: 'completed'
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
id: '4',
|
|
123
|
-
amount: -80,
|
|
124
|
-
category: 'Utilities',
|
|
125
|
-
account: 'Checking',
|
|
126
|
-
date: '2024-01-05',
|
|
127
|
-
description: 'Electric bill',
|
|
128
|
-
type: 'expense',
|
|
129
|
-
status: 'completed'
|
|
130
|
-
},
|
|
131
|
-
{
|
|
132
|
-
id: '5',
|
|
133
|
-
amount: -45,
|
|
134
|
-
category: 'Entertainment',
|
|
135
|
-
account: 'Checking',
|
|
136
|
-
date: '2024-01-12',
|
|
137
|
-
description: 'Movie tickets',
|
|
138
|
-
type: 'expense',
|
|
139
|
-
status: 'completed'
|
|
140
|
-
}
|
|
141
|
-
];
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './financial-config';
|
|
@@ -1,326 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { cn } from '../../atoms/utils/utils';
|
|
3
|
-
import { SectionHeader } from '../../molecules/layout/SectionHeader';
|
|
4
|
-
import { Card } from '../../atoms/ui/card';
|
|
5
|
-
import { StatCard } from '../../atoms/composed/StatCard';
|
|
6
|
-
import { DashboardGrid } from '../DashboardTemplate';
|
|
7
|
-
import { DataBadge } from '../../atoms/composed/DataBadge';
|
|
8
|
-
import { TrendingUp, TrendingDown, DollarSign, PiggyBank, Target, AlertTriangle } from 'lucide-react';
|
|
9
|
-
|
|
10
|
-
export interface FinancialOverviewProps {
|
|
11
|
-
/** Total account balance */
|
|
12
|
-
totalBalance: number;
|
|
13
|
-
/** Monthly income */
|
|
14
|
-
monthlyIncome?: number;
|
|
15
|
-
/** Monthly expenses */
|
|
16
|
-
monthlyExpenses?: number;
|
|
17
|
-
/** Net worth change */
|
|
18
|
-
netWorthChange?: {
|
|
19
|
-
amount: number;
|
|
20
|
-
percentage: number;
|
|
21
|
-
period: string;
|
|
22
|
-
};
|
|
23
|
-
/** Savings rate */
|
|
24
|
-
savingsRate?: number;
|
|
25
|
-
/** Budget utilization */
|
|
26
|
-
budgetUtilization?: number;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface AccountSummary {
|
|
30
|
-
id: string;
|
|
31
|
-
name: string;
|
|
32
|
-
type: 'checking' | 'savings' | 'credit' | 'investment' | 'loan';
|
|
33
|
-
balance: number;
|
|
34
|
-
change?: {
|
|
35
|
-
amount: number;
|
|
36
|
-
percentage: number;
|
|
37
|
-
};
|
|
38
|
-
status?: 'healthy' | 'warning' | 'critical';
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface BudgetAlert {
|
|
42
|
-
id: string;
|
|
43
|
-
category: string;
|
|
44
|
-
spent: number;
|
|
45
|
-
budget: number;
|
|
46
|
-
severity: 'warning' | 'critical';
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export interface FinancialGoal {
|
|
50
|
-
id: string;
|
|
51
|
-
name: string;
|
|
52
|
-
target: number;
|
|
53
|
-
current: number;
|
|
54
|
-
deadline?: string;
|
|
55
|
-
status: 'on-track' | 'behind' | 'achieved';
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export interface FinancialDashboardTemplateProps {
|
|
59
|
-
/** Page title */
|
|
60
|
-
title?: string;
|
|
61
|
-
/** Page description */
|
|
62
|
-
description?: string;
|
|
63
|
-
/** Financial overview metrics */
|
|
64
|
-
overview: FinancialOverviewProps;
|
|
65
|
-
/** Account summaries */
|
|
66
|
-
accounts?: AccountSummary[];
|
|
67
|
-
/** Budget alerts */
|
|
68
|
-
budgetAlerts?: BudgetAlert[];
|
|
69
|
-
/** Financial goals */
|
|
70
|
-
goals?: FinancialGoal[];
|
|
71
|
-
/** Recent transactions preview */
|
|
72
|
-
recentTransactions?: Array<{
|
|
73
|
-
id: string;
|
|
74
|
-
description: string;
|
|
75
|
-
amount: number;
|
|
76
|
-
category: string;
|
|
77
|
-
date: string;
|
|
78
|
-
}>;
|
|
79
|
-
/** Header actions */
|
|
80
|
-
actions?: React.ReactNode;
|
|
81
|
-
/** Additional content */
|
|
82
|
-
children?: React.ReactNode;
|
|
83
|
-
/** Additional CSS classes */
|
|
84
|
-
className?: string;
|
|
85
|
-
/** Category-based styling */
|
|
86
|
-
category?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
|
|
87
|
-
/** Loading state */
|
|
88
|
-
isLoading?: boolean;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export const FinancialDashboardTemplate: React.FC<FinancialDashboardTemplateProps> = ({
|
|
92
|
-
title = "Financial Dashboard",
|
|
93
|
-
description = "Your complete financial overview",
|
|
94
|
-
overview,
|
|
95
|
-
accounts = [],
|
|
96
|
-
budgetAlerts = [],
|
|
97
|
-
goals = [],
|
|
98
|
-
recentTransactions = [],
|
|
99
|
-
actions,
|
|
100
|
-
children,
|
|
101
|
-
className,
|
|
102
|
-
category = 2, // Green theme for financial
|
|
103
|
-
isLoading = false
|
|
104
|
-
}) => {
|
|
105
|
-
const formatCurrency = (amount: number) => {
|
|
106
|
-
return new Intl.NumberFormat('en-US', {
|
|
107
|
-
style: 'currency',
|
|
108
|
-
currency: 'USD'
|
|
109
|
-
}).format(amount);
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
const getAccountIcon = (type: AccountSummary['type']) => {
|
|
113
|
-
switch (type) {
|
|
114
|
-
case 'savings': return <PiggyBank className="w-4 h-4" />;
|
|
115
|
-
case 'investment': return <TrendingUp className="w-4 h-4" />;
|
|
116
|
-
case 'credit': return <AlertTriangle className="w-4 h-4" />;
|
|
117
|
-
default: return <DollarSign className="w-4 h-4" />;
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
const getAccountStatus = (account: AccountSummary) => {
|
|
122
|
-
if (account.type === 'credit' && account.balance > 0) return 'warning';
|
|
123
|
-
if (account.type === 'loan' && account.balance > 0) return 'error';
|
|
124
|
-
return account.status || 'success';
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
return (
|
|
128
|
-
<div className={cn('flex flex-col min-h-0 flex-1', className)}>
|
|
129
|
-
{/* Header Section */}
|
|
130
|
-
<div className="flex-shrink-0 border-b border-border bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
|
|
131
|
-
<div className="container mx-auto px-6 py-6">
|
|
132
|
-
<div className="flex items-start justify-between">
|
|
133
|
-
<div className="flex-1 min-w-0">
|
|
134
|
-
<SectionHeader
|
|
135
|
-
title={title}
|
|
136
|
-
description={description}
|
|
137
|
-
size="lg"
|
|
138
|
-
className="text-left"
|
|
139
|
-
/>
|
|
140
|
-
</div>
|
|
141
|
-
|
|
142
|
-
{actions && (
|
|
143
|
-
<div className="ml-6 flex-shrink-0">
|
|
144
|
-
{actions}
|
|
145
|
-
</div>
|
|
146
|
-
)}
|
|
147
|
-
</div>
|
|
148
|
-
</div>
|
|
149
|
-
</div>
|
|
150
|
-
|
|
151
|
-
{/* Main Content */}
|
|
152
|
-
<div className="flex-1 min-h-0 overflow-auto">
|
|
153
|
-
<div className="container mx-auto px-6 py-6 space-y-6">
|
|
154
|
-
{/* Financial Overview */}
|
|
155
|
-
<div>
|
|
156
|
-
<h2 className="text-lg font-semibold mb-4">Financial Overview</h2>
|
|
157
|
-
<DashboardGrid columns={4} gap="md">
|
|
158
|
-
<StatCard
|
|
159
|
-
title="Total Balance"
|
|
160
|
-
value={formatCurrency(overview.totalBalance)}
|
|
161
|
-
icon={<DollarSign className="w-5 h-5" />}
|
|
162
|
-
category={category}
|
|
163
|
-
isLoading={isLoading}
|
|
164
|
-
/>
|
|
165
|
-
|
|
166
|
-
{overview.monthlyIncome && (
|
|
167
|
-
<StatCard
|
|
168
|
-
title="Monthly Income"
|
|
169
|
-
value={formatCurrency(overview.monthlyIncome)}
|
|
170
|
-
icon={<TrendingUp className="w-5 h-5" />}
|
|
171
|
-
category={category}
|
|
172
|
-
isLoading={isLoading}
|
|
173
|
-
/>
|
|
174
|
-
)}
|
|
175
|
-
|
|
176
|
-
{overview.monthlyExpenses && (
|
|
177
|
-
<StatCard
|
|
178
|
-
title="Monthly Expenses"
|
|
179
|
-
value={formatCurrency(overview.monthlyExpenses)}
|
|
180
|
-
icon={<TrendingDown className="w-5 h-5" />}
|
|
181
|
-
category={category}
|
|
182
|
-
isLoading={isLoading}
|
|
183
|
-
/>
|
|
184
|
-
)}
|
|
185
|
-
|
|
186
|
-
{overview.savingsRate && (
|
|
187
|
-
<StatCard
|
|
188
|
-
title="Savings Rate"
|
|
189
|
-
value={`${overview.savingsRate}%`}
|
|
190
|
-
icon={<Target className="w-5 h-5" />}
|
|
191
|
-
category={category}
|
|
192
|
-
isLoading={isLoading}
|
|
193
|
-
/>
|
|
194
|
-
)}
|
|
195
|
-
</DashboardGrid>
|
|
196
|
-
</div>
|
|
197
|
-
|
|
198
|
-
{/* Accounts Overview */}
|
|
199
|
-
{accounts.length > 0 && (
|
|
200
|
-
<div>
|
|
201
|
-
<h2 className="text-lg font-semibold mb-4">Accounts</h2>
|
|
202
|
-
<DashboardGrid columns={2} gap="md">
|
|
203
|
-
{accounts.map((account) => (
|
|
204
|
-
<Card key={account.id} category={category} className="p-4">
|
|
205
|
-
<div className="flex items-start justify-between">
|
|
206
|
-
<div className="flex items-center gap-3">
|
|
207
|
-
{getAccountIcon(account.type)}
|
|
208
|
-
<div>
|
|
209
|
-
<h3 className="font-medium">{account.name}</h3>
|
|
210
|
-
<p className="text-sm text-muted-foreground capitalize">{account.type}</p>
|
|
211
|
-
</div>
|
|
212
|
-
</div>
|
|
213
|
-
<div className="text-right">
|
|
214
|
-
<p className="font-semibold">{formatCurrency(account.balance)}</p>
|
|
215
|
-
{account.change && (
|
|
216
|
-
<div className="flex items-center gap-1 text-sm">
|
|
217
|
-
{account.change.amount > 0 ? (
|
|
218
|
-
<TrendingUp className="w-3 h-3 text-green-500" />
|
|
219
|
-
) : (
|
|
220
|
-
<TrendingDown className="w-3 h-3 text-red-500" />
|
|
221
|
-
)}
|
|
222
|
-
<span className={account.change.amount > 0 ? 'text-green-500' : 'text-red-500'}>
|
|
223
|
-
{Math.abs(account.change.percentage)}%
|
|
224
|
-
</span>
|
|
225
|
-
</div>
|
|
226
|
-
)}
|
|
227
|
-
</div>
|
|
228
|
-
</div>
|
|
229
|
-
<div className="mt-3">
|
|
230
|
-
<DataBadge
|
|
231
|
-
variant="status"
|
|
232
|
-
status={getAccountStatus(account)}
|
|
233
|
-
>
|
|
234
|
-
{account.status || 'healthy'}
|
|
235
|
-
</DataBadge>
|
|
236
|
-
</div>
|
|
237
|
-
</Card>
|
|
238
|
-
))}
|
|
239
|
-
</DashboardGrid>
|
|
240
|
-
</div>
|
|
241
|
-
)}
|
|
242
|
-
|
|
243
|
-
{/* Budget Alerts */}
|
|
244
|
-
{budgetAlerts.length > 0 && (
|
|
245
|
-
<div>
|
|
246
|
-
<h2 className="text-lg font-semibold mb-4">Budget Alerts</h2>
|
|
247
|
-
<div className="space-y-3">
|
|
248
|
-
{budgetAlerts.map((alert) => (
|
|
249
|
-
<Card key={alert.id} className="p-4">
|
|
250
|
-
<div className="flex items-center justify-between">
|
|
251
|
-
<div className="flex items-center gap-3">
|
|
252
|
-
<AlertTriangle className={cn(
|
|
253
|
-
"w-5 h-5",
|
|
254
|
-
alert.severity === 'critical' ? 'text-red-500' : 'text-yellow-500'
|
|
255
|
-
)} />
|
|
256
|
-
<div>
|
|
257
|
-
<h3 className="font-medium">{alert.category}</h3>
|
|
258
|
-
<p className="text-sm text-muted-foreground">
|
|
259
|
-
{formatCurrency(alert.spent)} of {formatCurrency(alert.budget)} spent
|
|
260
|
-
</p>
|
|
261
|
-
</div>
|
|
262
|
-
</div>
|
|
263
|
-
<div className="text-right">
|
|
264
|
-
<DataBadge
|
|
265
|
-
variant="status"
|
|
266
|
-
status={alert.severity === 'critical' ? 'error' : 'warning'}
|
|
267
|
-
>
|
|
268
|
-
{Math.round((alert.spent / alert.budget) * 100)}% used
|
|
269
|
-
</DataBadge>
|
|
270
|
-
</div>
|
|
271
|
-
</div>
|
|
272
|
-
</Card>
|
|
273
|
-
))}
|
|
274
|
-
</div>
|
|
275
|
-
</div>
|
|
276
|
-
)}
|
|
277
|
-
|
|
278
|
-
{/* Financial Goals */}
|
|
279
|
-
{goals.length > 0 && (
|
|
280
|
-
<div>
|
|
281
|
-
<h2 className="text-lg font-semibold mb-4">Financial Goals</h2>
|
|
282
|
-
<DashboardGrid columns={1} gap="md">
|
|
283
|
-
{goals.map((goal) => {
|
|
284
|
-
const progress = (goal.current / goal.target) * 100;
|
|
285
|
-
return (
|
|
286
|
-
<Card key={goal.id} category={category} className="p-4">
|
|
287
|
-
<div className="flex items-start justify-between mb-3">
|
|
288
|
-
<div>
|
|
289
|
-
<h3 className="font-medium">{goal.name}</h3>
|
|
290
|
-
<p className="text-sm text-muted-foreground">
|
|
291
|
-
{formatCurrency(goal.current)} of {formatCurrency(goal.target)}
|
|
292
|
-
</p>
|
|
293
|
-
</div>
|
|
294
|
-
<DataBadge
|
|
295
|
-
variant="status"
|
|
296
|
-
status={goal.status === 'achieved' ? 'success' : goal.status === 'behind' ? 'warning' : 'info'}
|
|
297
|
-
>
|
|
298
|
-
{goal.status}
|
|
299
|
-
</DataBadge>
|
|
300
|
-
</div>
|
|
301
|
-
<div className="w-full bg-muted rounded-full h-2">
|
|
302
|
-
<div
|
|
303
|
-
className={cn(
|
|
304
|
-
'h-2 rounded-full transition-all',
|
|
305
|
-
`bg-category-${category}`
|
|
306
|
-
)}
|
|
307
|
-
style={{ width: `${Math.min(progress, 100)}%` }}
|
|
308
|
-
/>
|
|
309
|
-
</div>
|
|
310
|
-
<p className="text-sm text-muted-foreground mt-2">
|
|
311
|
-
{Math.round(progress)}% complete
|
|
312
|
-
</p>
|
|
313
|
-
</Card>
|
|
314
|
-
);
|
|
315
|
-
})}
|
|
316
|
-
</DashboardGrid>
|
|
317
|
-
</div>
|
|
318
|
-
)}
|
|
319
|
-
|
|
320
|
-
{/* Additional Content */}
|
|
321
|
-
{children}
|
|
322
|
-
</div>
|
|
323
|
-
</div>
|
|
324
|
-
</div>
|
|
325
|
-
);
|
|
326
|
-
};
|