Dashboard Components
The Dashboard Components provide statistical displays, metric cards, and dashboard layouts for the WorkPayCore Frontend application. These components handle key performance indicators, summary statistics, and data visualization with consistent styling and interactive behaviors.
Overview
This document covers dashboard-related components that display statistics, metrics, and summary information throughout the application with WorkPay's branded styling and interaction patterns.
Components Overview
Core Dashboard Components
- TopStatCard - Primary statistics card with icons and hover effects
- StatCardBluePrint - Blueprint for custom statistics cards
- TopPortalStatCard - Portal-specific statistics card
Dashboard Layout Components
- StatCardHeader - Header section for statistics cards
- StatCardBody - Body section for statistics cards
- StatCardFooter - Footer section for statistics cards
Dashboard Patterns
- Admin Dashboard - Main administrative dashboard layout
- Portal Dashboard - Employee portal dashboard layout
- Module Dashboards - Specialized module dashboards
TopStatCard
The primary statistics card component for displaying key metrics with icons, hover effects, and navigation links.
Component Location
import TopStatCard from 'components/Dashboard/TopStatCard';
// or
import TopStatCard from 'containers/MainDashboard/TopStatCard';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| stat | object | ✓ | - | Statistics data object |
| meta | object | ✓ | - | Metadata including id and links |
| isPercentage | boolean | - | false | Whether to display percentage symbol |
TypeScript Interface
interface StatData {
total: number;
isLoading?: boolean;
}
interface MetaData {
id: string;
statFor: string;
linkTo?: string;
linkLable?: string;
isLoading?: boolean;
}
interface TopStatCardProps {
stat: StatData;
meta: MetaData;
isPercentage?: boolean;
}
Supported Stat Types
The component supports different statistics with specific icons:
- employees - User icon for employee counts
- leaves - Overtime icon for leave requests
- salary_advances - Salary advance icon for advance requests
- employee_turnover - User minus icon for turnover rates
Usage Examples
Basic Employee Stats Card
import TopStatCard from 'components/Dashboard/TopStatCard';
function EmployeeStatsCard() {
const employeeStats = {
total: 150,
};
const metaData = {
id: 'employees',
statFor: 'Total Employees',
linkTo: '/employees',
linkLable: 'View All Employees',
isLoading: false,
};
return <TopStatCard stat={employeeStats} meta={metaData} />;
}
Loading State Card
function LoadingStatsCard() {
const metaData = {
id: 'leaves',
statFor: 'Leave Requests',
isLoading: true,
};
return <TopStatCard stat={{ total: 0 }} meta={metaData} />;
}
Percentage Display Card
function TurnoverStatsCard() {
const turnoverStats = {
total: 15.5,
};
const metaData = {
id: 'employee_turnover',
statFor: 'Employee Turnover',
linkTo: '/reports/turnover',
linkLable: 'View Report',
};
return <TopStatCard stat={turnoverStats} meta={metaData} isPercentage />;
}
Card Without Link
function SimpleStatsCard() {
const simpleStats = {
total: 42,
};
const metaData = {
id: 'employees',
statFor: 'Active Projects',
// No linkTo provided
};
return <TopStatCard stat={simpleStats} meta={metaData} />;
}
Interactive Features
- Hover Effects: Background gradient and icon color changes
- Navigation: Click-through to detailed views
- Icons: Contextual icons based on stat type
- Loading States: Skeleton loading animation
StatCardBluePrint
A blueprint component for creating custom statistics cards with flexible header, body, and footer sections.
Component Location
import StatCardBluePrint, {
StatCardHeader,
StatCardBody,
StatCardFooter,
} from 'components/Dashboard/StatCardBluePrint';
// or
import StatCardBluePrint, {
StatCardHeader,
StatCardBody,
StatCardFooter,
} from 'containers/MainDashboard/StatCardBlueprints';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| header | ReactNode | - | - | Header section content |
| body | ReactNode | - | - | Body section content |
| footer | ReactNode | - | - | Footer section content |
| noFooter | boolean | - | false | Hide footer section |
| topDivider | boolean | - | false | Show divider after header |
Usage Examples
Complete Custom Card
import StatCardBluePrint, {
StatCardHeader,
StatCardBody,
StatCardFooter,
} from 'components/Dashboard/StatCardBluePrint';
import { Text, VStack, Button } from '@chakra-ui/react';
function CustomMetricsCard() {
const header = (
<StatCardHeader heading='Monthly Overview' subHeading='September 2024' />
);
const body = (
<StatCardBody px={5} py={2} w='full' justify='center'>
<VStack spacing={4} align='center'>
<Text fontSize='3xl' color='green' fontWeight='bold'>
85%
</Text>
<Text fontSize='md' textAlign='center'>
Employee Satisfaction Score
</Text>
<Text fontSize='sm' color='gray.600' textAlign='center'>
Based on latest quarterly survey
</Text>
</VStack>
</StatCardBody>
);
const footer = (
<StatCardFooter>
<Text fontSize='sm' color='green'>
+5% from last month
</Text>
</StatCardFooter>
);
return <StatCardBluePrint header={header} body={body} footer={footer} />;
}
Card Without Footer
function SimpleCard() {
const header = <StatCardHeader heading='Recent Activity' />;
const body = (
<StatCardBody p={4}>
<VStack spacing={3} align='stretch'>
<Text>New employee onboarded</Text>
<Text>Payroll processed</Text>
<Text>Leave request approved</Text>
</VStack>
</StatCardBody>
);
return <StatCardBluePrint header={header} body={body} noFooter />;
}
Chart Integration Card
import { Chart } from 'react-google-charts';
function PayrollChartCard({ payrollData }) {
const header = <StatCardHeader heading='Payroll Summary' />;
const body = (
<StatCardBody px={5} py={2} w='full' justify='flex-start'>
<VStack w='full' align='flex-start'>
<HStack w='full' justify='space-between'>
<HStack>
<Text color='onyx' fontWeight='bold' fontSize='lg'>
KES 2,500,000
</Text>
<Text color='#387E1B' bg='#e7f1e3' fontSize='sm' p={1}>
+12%
</Text>
</HStack>
</HStack>
<HStack w='full' h='full' justify='center' align='center'>
{payrollData?.length > 0 ? (
<Chart
chartType='LineChart'
width='100%'
height='300px'
data={payrollData}
options={chartOptions}
/>
) : (
<NotDataFound message='No payroll data available' />
)}
</HStack>
</VStack>
</StatCardBody>
);
return <StatCardBluePrint header={header} body={body} topDivider />;
}
TopPortalStatCard
A specialized statistics card designed for the employee portal with button-style interactions.
Component Location
import TopPortalStatCard from 'containers/MainDashboard/TopPortalStatCard';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| stat | object | ✓ | - | Statistics data |
| meta | object | ✓ | - | Metadata and styling |
Usage Examples
Portal Quick Action Card
import TopPortalStatCard from 'containers/MainDashboard/TopPortalStatCard';
function LeaveRequestCard() {
const metaData = {
statFor: 'Leave Requests',
description: 'Submit and track your leave requests',
linkTo: '/leaves/new',
linkLable: 'Request Leave',
};
return <TopPortalStatCard stat={{ isLoading: false }} meta={metaData} />;
}
StatCardHeader
Header component for statistics cards with title and subtitle support.
Component Location
import { StatCardHeader } from 'components/Dashboard/StatCardBluePrint';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| heading | string | ✓ | - | Main heading text |
| subHeading | string | - | - | Subtitle text |
| children | ReactNode | - | - | Additional content |
Usage Examples
Basic Header
<StatCardHeader heading='Employee Statistics' />
Header with Subtitle
<StatCardHeader heading='Monthly Report' subHeading='September 2024' />
Header with Actions
<StatCardHeader heading='Recent Activity'>
<Button variant='ghost' size='sm'>
View All
</Button>
</StatCardHeader>
StatCardBody
Body component for statistics cards with flexible content layout.
Component Location
import { StatCardBody } from 'components/Dashboard/StatCardBluePrint';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| children | ReactNode | ✓ | - | Body content |
Usage Examples
Standard Body
<StatCardBody p={4}>
<VStack spacing={4}>
<Text fontSize='2xl'>150</Text>
<Text>Active Employees</Text>
</VStack>
</StatCardBody>
Chart Body
<StatCardBody px={5} py={2} w='full' justify='center'>
<Chart
chartType='PieChart'
data={chartData}
options={chartOptions}
width='100%'
height='300px'
/>
</StatCardBody>
StatCardFooter
Footer component for statistics cards with centered content and styling.
Component Location
import { StatCardFooter } from 'components/Dashboard/StatCardBluePrint';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| children | ReactNode | ✓ | - | Footer content |
Usage Examples
Simple Footer
<StatCardFooter>
<Text fontSize='sm' color='green'>
+5% from last month
</Text>
</StatCardFooter>
Footer with Multiple Elements
<StatCardFooter>
<HStack spacing={4}>
<Text fontSize='sm' color='gray.600'>
Last updated: 2 hours ago
</Text>
<Button variant='link' size='sm' color='green'>
Refresh
</Button>
</HStack>
</StatCardFooter>
Dashboard Patterns
Admin Dashboard
Main administrative dashboard with comprehensive statistics and navigation.
import { Grid, GridItem, Stack } from '@chakra-ui/react';
import { WPTabbedPage } from 'components/WPagesTemplates';
import TopStatCard from 'components/Dashboard/TopStatCard';
function AdminDashboard() {
const activeEmployees = useActiveEmployeeCountRequest();
const leaveRequestCount = useLeaveRequestsCount();
const salaryAdvanceRequestsCount = useSalaryAdvanceRequestsCount();
const employeeTurnOver = useEmployeeTurnOver();
return (
<WPTabbedPage pageTitle='Dashboard' overflow='scroll'>
<Stack spacing={4}>
{/* Top Statistics Row */}
<Grid
templateColumns={{ base: 'repeat(1, 1fr)', lg: 'repeat(4, 1fr)' }}
gap={4}
>
<GridItem w='full' h='full' colSpan={1}>
<TopStatCard
stat={activeEmployees}
meta={{
id: 'employees',
statFor: 'active employees',
linkLable: 'View employees',
linkTo: '/employees',
}}
/>
</GridItem>
<GridItem w='full' h='full' colSpan={1}>
<TopStatCard
stat={leaveRequestCount}
meta={{
id: 'leaves',
statFor: 'pending leaves',
linkLable: 'View leaves',
linkTo: '/leaves',
}}
/>
</GridItem>
<GridItem w='full' h='full' colSpan={1}>
<TopStatCard
stat={salaryAdvanceRequestsCount}
meta={{
id: 'salary_advances',
statFor: 'salary advances',
linkLable: 'View advances',
linkTo: '/salary-advance',
}}
/>
</GridItem>
<GridItem w='full' h='full' colSpan={1}>
<TopStatCard
stat={employeeTurnOver}
meta={{
id: 'employee_turnover',
statFor: 'employee turnover',
linkLable: 'Go to exits',
linkTo: '/exits',
}}
isPercentage
/>
</GridItem>
</Grid>
{/* Secondary Content Row */}
<Grid
templateColumns={{ base: 'repeat(1, 1fr)', lg: 'repeat(4, 1fr)' }}
gap={4}
>
<GridItem w='full' h='full' colSpan={3}>
<RecentTransactions />
</GridItem>
<GridItem w='full' h='full' colSpan={1}>
<UpcomingEvents />
</GridItem>
</Grid>
{/* Charts and Analytics Row */}
<Stack
w='full'
spacing={4}
h='400px'
direction={{ base: 'column', lg: 'row' }}
>
<RecentLeaveRequestsStats />
<PastPayrollsStats />
</Stack>
</Stack>
</WPTabbedPage>
);
}
Portal Dashboard
Employee portal dashboard with feature-based navigation cards.
function PortalDashboard() {
const { currentUser } = useCurrentUser();
const { data: features, isLoading: isCompanyFeaturesLoading } =
useCompanyEnabledFeatures();
const carouselData = useDashboardContent(currentUser);
return (
<WPTabbedPage pageTitle='Home'>
<Stack spacing={8} direction={{ base: 'column', lg: 'row' }}>
{/* Main Content */}
<Box flex='3' width='full'>
<VStack align='stretch' width='full' spacing={0}>
{/* Hero Carousel */}
<Stack mt='8px !important'>
<HomeCarousel carouselData={carouselData} />
</Stack>
{/* Feature Cards */}
{isCompanyFeaturesLoading ? (
<SettingsSkeleton />
) : (
<>
<Text
mt='72px !important'
letterSpacing={-0.16}
fontSize='lg'
fontWeight='500'
>
For your Company
</Text>
<Grid
mt='8px !important'
templateRows='repeat(2, 1fr)'
templateColumns='repeat(2, 1fr)'
gap={6}
>
{features?.map((feature, idx) =>
idx <= 3 ? (
<GridItem
key={feature?.id}
height='214px'
rowSpan={1}
colSpan={{ base: 2, md: 1 }}
>
<HomeCard feature={feature} />
</GridItem>
) : null,
)}
</Grid>
</>
)}
</VStack>
</Box>
{/* Sidebar */}
<Stack flex='2' marginTop='80px !important' spacing={6}>
<EventsCarousel />
<ClientOnboardingProgress />
</Stack>
</Stack>
</WPTabbedPage>
);
}
Module Dashboards
Specialized dashboards for specific modules like Performance Management.
function PerformanceManagementDashboard() {
const allEmployeeKpis = useEmployeeKpiStats();
const departmentKpis = useDepartmentKpiStats();
const allAppraisals = useEmployeeAppraisalStats();
const employeesInPip = useAllPipStats();
return (
<WPTabbedPage pageTitle='Performance Management Dashboard'>
{/* KPI Statistics */}
<Grid
templateColumns={{ base: 'repeat(1, 1fr)', lg: 'repeat(8, 1fr)' }}
gap={4}
maxH={{ base: 'fit-content', lg: '470px' }}
>
<GridItem w='full' h='full' colSpan={2}>
<TopStatCard
stat={allEmployeeKpis?.data?.data?.data}
meta={{
id: 'employees',
statFor: 'total employee KPIs',
isLoading: allEmployeeKpis?.isLoading,
linkLable: 'Go-to employee KPIs',
linkTo: '/performance-management/employee-kpi',
}}
/>
</GridItem>
<GridItem w='full' h='full' colSpan={2}>
<TopStatCard
stat={departmentKpis?.data?.data?.data}
meta={{
id: 'leaves',
statFor: 'Total Department KPIs',
isLoading: departmentKpis?.isLoading,
linkLable: 'View Department KPIs',
linkTo: '/performance-management/department-kpi',
}}
/>
</GridItem>
<GridItem w='full' h='full' colSpan={2}>
<TopStatCard
stat={allAppraisals?.data?.data?.data}
meta={{
id: 'salary_advances',
statFor: 'Submitted Appraisals',
isLoading: allAppraisals?.isLoading,
linkLable: 'View Appraisals',
linkTo: '/performance-management/employee-appraisal',
}}
/>
</GridItem>
<GridItem w='full' h='full' colSpan={2}>
<TopStatCard
stat={employeesInPip?.data?.data?.data}
meta={{
id: 'leaves',
statFor: 'Employees under PIP',
linkLable: 'Go-to PIPs',
isLoading: employeesInPip?.isLoading,
linkTo: '/performance-management/pip',
}}
/>
</GridItem>
</Grid>
{/* Department KPI Stats */}
<Grid
templateColumns={{ base: 'repeat(1, 1fr)', lg: 'repeat(4, 1fr)' }}
gap={4}
>
<GridItem w='full' h='full' colSpan={4}>
<DepartmentKpiStats />
</GridItem>
</Grid>
{/* Employee KPI Stats */}
<Grid
templateColumns={{ base: 'repeat(1, 1fr)', lg: 'repeat(4, 1fr)' }}
gap={4}
>
<GridItem w='full' h='full' colSpan={4}>
<EmployeeKpiStats />
</GridItem>
</Grid>
</WPTabbedPage>
);
}
Time Attendance Dashboard
Dashboard for time attendance monitoring with specialized metrics.
function TimeAttendanceDashboard() {
const [branch, setBranch] = useState();
const [selectedIsHeadOffice, setSelectedIsHeadOffice] = useState(true);
return (
<WPTabbedPage pageTitle='Time Attendance Dashboard'>
{/* Filters */}
<HStack spacing={4} mb={6}>
<BranchFilter
value={branch}
onChange={setBranch}
selectedIsHeadOffice={selectedIsHeadOffice}
setSelectedIsHeadOffice={setSelectedIsHeadOffice}
/>
</HStack>
{/* Summary Breakdown */}
<Grid
templateColumns={{ base: 'repeat(1, 1fr)', lg: 'repeat(1, 1fr)' }}
gap={4}
mb={6}
>
<GridItem w='full' h='full' colSpan={1}>
<TotalSummaryBreakdown
branch_id={branch?.value}
selectedIsHeadOffice={selectedIsHeadOffice}
/>
</GridItem>
</Grid>
{/* Attendance and Shifts */}
<Grid
templateColumns={{ base: 'repeat(1, 1fr)', lg: 'repeat(4, 1fr)' }}
gap={4}
>
<GridItem w='full' h='full' colSpan={2}>
<AttendanceStats branch_id={branch?.value} date={currentDate} />
</GridItem>
<GridItem w='full' h='full' colSpan={2}>
<ShiftStats
branch_id={branch?.value}
records_count={20}
date={currentDate}
/>
</GridItem>
</Grid>
</WPTabbedPage>
);
}
Best Practices
Card Design
-
Consistent Sizing
- Use uniform card heights within rows
- Maintain consistent padding and spacing
- Ensure responsive behavior across devices
-
Visual Hierarchy
- Place most important metrics prominently
- Use color coding for different metric types
- Provide clear navigation paths
-
Loading States
- Implement skeleton loading for all cards
- Handle error states gracefully
- Provide retry mechanisms when appropriate
Data Display
-
Number Formatting
// Format large numbers
const formatNumber = num => {
if (num >= 1000000) return `${(num / 1000000).toFixed(1)}M`;
if (num >= 1000) return `${(num / 1000).toFixed(1)}K`;
return num.toString();
}; -
Percentage Display
// Consistent percentage formatting
const formatPercentage = (value, decimals = 1) => {
return `${value.toFixed(decimals)}%`;
}; -
Status Indicators
// Color-coded status indicators
const getStatusColor = change => {
if (change > 0) return 'green';
if (change < 0) return 'red';
return 'gray';
};
Performance
-
Data Fetching
- Use React Query for efficient data management
- Implement proper caching strategies
- Handle concurrent requests appropriately
-
Rendering Optimization
- Memoize expensive calculations
- Use React.memo for stable components
- Implement proper dependency arrays
-
Real-time Updates
// Implement real-time updates for critical metrics
const useRealTimeStats = (endpoint, interval = 30000) => {
return useQuery(['realtime-stats', endpoint], () => fetchStats(endpoint), {
refetchInterval: interval,
refetchIntervalInBackground: true,
});
};
Accessibility
-
Screen Reader Support
- Provide meaningful aria-labels
- Use semantic HTML structure
- Announce changes in dynamic content
-
Keyboard Navigation
- Ensure all interactive elements are keyboard accessible
- Implement proper focus management
- Provide keyboard shortcuts for common actions
-
Color Accessibility
- Ensure sufficient color contrast
- Don't rely solely on color for information
- Support high contrast modes
Testing
Unit Tests
import { render, screen } from '@testing-library/react';
import TopStatCard from 'components/Dashboard/TopStatCard';
describe('TopStatCard', () => {
it('renders stat data correctly', () => {
const stat = { total: 150 };
const meta = {
id: 'employees',
statFor: 'Total Employees',
};
render(<TopStatCard stat={stat} meta={meta} />);
expect(screen.getByText('150')).toBeInTheDocument();
expect(screen.getByText('Total Employees')).toBeInTheDocument();
});
it('displays percentage when specified', () => {
const stat = { total: 15.5 };
const meta = {
id: 'employee_turnover',
statFor: 'Employee Turnover',
};
render(<TopStatCard stat={stat} meta={meta} isPercentage />);
expect(screen.getByText('15.5%')).toBeInTheDocument();
});
it('shows loading state', () => {
const stat = { total: 0 };
const meta = {
id: 'employees',
statFor: 'Total Employees',
isLoading: true,
};
render(<TopStatCard stat={stat} meta={meta} />);
expect(screen.getByTestId('skeleton')).toBeInTheDocument();
});
it('renders navigation link when provided', () => {
const stat = { total: 150 };
const meta = {
id: 'employees',
statFor: 'Total Employees',
linkTo: '/employees',
linkLable: 'View All',
};
render(<TopStatCard stat={stat} meta={meta} />);
const link = screen.getByRole('link', { name: /view all/i });
expect(link).toHaveAttribute('href', '/employees');
});
});
Integration Tests
describe('AdminDashboard', () => {
it('renders all stat cards', async () => {
render(<AdminDashboard />);
await waitFor(() => {
expect(screen.getByText('active employees')).toBeInTheDocument();
expect(screen.getByText('pending leaves')).toBeInTheDocument();
expect(screen.getByText('salary advances')).toBeInTheDocument();
expect(screen.getByText('employee turnover')).toBeInTheDocument();
});
});
it('handles loading states correctly', () => {
// Mock loading state
render(<AdminDashboard />);
expect(screen.getAllByTestId('skeleton')).toHaveLength(4);
});
it('navigates to correct pages on card click', async () => {
const { user } = render(<AdminDashboard />);
await waitFor(() => {
const employeeLink = screen.getByText('View employees');
expect(employeeLink).toBeInTheDocument();
});
await user.click(screen.getByText('View employees'));
expect(mockNavigate).toHaveBeenCalledWith('/employees');
});
});
Migration Guide
From Legacy Dashboard Components
-
Update Import Paths
// Old
import StatCard from 'components/OldStatCard';
// New
import TopStatCard from 'components/Dashboard/TopStatCard'; -
Update Props Structure
// Old
<StatCard
title="Total Employees"
value={150}
link="/employees"
/>
// New
<TopStatCard
stat={{ total: 150 }}
meta={{
id: 'employees',
statFor: 'Total Employees',
linkTo: '/employees',
linkLable: 'View All',
}}
/> -
Update Loading States
// Old
<StatCard isLoading={true} />
// New
<TopStatCard
stat={{ total: 0 }}
meta={{
id: 'employees',
statFor: 'Total Employees',
isLoading: true,
}}
/>
CSS to Chakra UI Migration
// Old CSS-based styling
.stat-card {
background: white;
border-radius: 12px;
padding: 16px;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
// New Chakra UI styling
<StatCardBluePrint
bg="white"
borderRadius="2xl"
p={4}
boxShadow="lg"
>
{/* Content */}
</StatCardBluePrint>
Advanced Usage
Custom Dashboard Layout
function CustomDashboardLayout({ children, sidebar }) {
return (
<WPTabbedPage pageTitle='Custom Dashboard'>
<Grid templateColumns='1fr 300px' gap={6}>
{/* Main Content */}
<GridItem>
<Stack spacing={6}>{children}</Stack>
</GridItem>
{/* Sidebar */}
<GridItem>
<Stack spacing={4}>{sidebar}</Stack>
</GridItem>
</Grid>
</WPTabbedPage>
);
}
Dynamic Stat Card Configuration
const statCardConfigs = [
{
key: 'employees',
title: 'Active Employees',
icon: 'employees',
link: '/employees',
permission: 'view_employees',
},
{
key: 'leaves',
title: 'Pending Leaves',
icon: 'leaves',
link: '/leaves',
permission: 'view_leaves',
},
// ... more configs
];
function DynamicDashboard({ permissions }) {
const visibleCards = statCardConfigs.filter(config =>
permissions.includes(config.permission),
);
return (
<Grid templateColumns='repeat(auto-fit, minmax(300px, 1fr))' gap={4}>
{visibleCards.map(config => (
<TopStatCard
key={config.key}
stat={statsData[config.key]}
meta={{
id: config.key,
statFor: config.title,
linkTo: config.link,
linkLable: `View ${config.title}`,
}}
/>
))}
</Grid>
);
}
Real-time Dashboard Updates
function RealTimeDashboard() {
const stats = useRealTimeStats('/api/dashboard/stats');
const lastUpdate = useRef(Date.now());
useInterval(() => {
// Refetch data every 30 seconds
stats.refetch();
lastUpdate.current = Date.now();
}, 30000);
return (
<Stack spacing={6}>
<HStack justify='space-between' align='center'>
<Text fontSize='lg' fontWeight='bold'>
Dashboard
</Text>
<Text fontSize='sm' color='gray.600'>
Last updated: {format(lastUpdate.current, 'HH:mm:ss')}
</Text>
</HStack>
<Grid templateColumns='repeat(4, 1fr)' gap={4}>
{/* Real-time stat cards */}
</Grid>
</Stack>
);
}