Files
RestaurantDash/src/components/Home/Analytics&Reporting/StatisticsCard.js
T

226 lines
8.1 KiB
JavaScript

import React, { useState } from 'react';
import PropTypes from 'prop-types';
import {
Box,
IconButton,
Paper,
Typography,
useTheme,
useMediaQuery,
Menu,
MenuItem,
TextField,
Button
} from '@mui/material';
import {
AreaChart,
Area,
XAxis,
YAxis,
Tooltip,
Legend,
ResponsiveContainer,
CartesianGrid
} from 'recharts';
// import MoreVertIcon from '@mui/icons-material/MoreVert';
const StatisticsCard = ({
title = "Statistics",
subtitle = "Delivery Times",
data = [],
dataKeys = [
{ key: 'revenue', name: 'Revenue', color: '#E46A11' },
{ key: 'sales', name: 'Sales', color: '#0182FC' }
],
xDataKey = 'month',
valueFormatter = (value) => value,
timeFrame = 'month',
onTimeFrameChange
}) => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
const isTablet = useMediaQuery(theme.breakpoints.between('sm', 'md'));
const [selectedDate, setSelectedDate] = useState('');
const [anchorEl, setAnchorEl] = useState(null);
const handleMenuOpen = (event) => {
setAnchorEl(event.currentTarget);
};
const handleMenuClose = () => {
setAnchorEl(null);
};
const handleDateChange = (event) => {
setSelectedDate(event.target.value);
if (onTimeFrameChange) onTimeFrameChange(timeFrame, event.target.value);
handleMenuClose();
};
const handleTodayClick = () => {
const today = new Date().toISOString().split('T')[0];
setSelectedDate(today);
if (onTimeFrameChange) onTimeFrameChange(timeFrame, today);
handleMenuClose();
};
// حساب العلامات الديناميكية للمحور الشاقولي
const ticksArray = (() => {
if (!data || data.length === 0) return [];
const maxValue = Math.max(
...data.flatMap(d => dataKeys.map(k => d[k.key] || 0))
);
const desiredTicks = 8; // عدد العلامات المطلوب
const step = Math.ceil(maxValue / desiredTicks) || 1;
const arr = [];
for (let i = 0; i <= maxValue; i += step) {
arr.push(i);
}
return arr;
})();
return (
<Box sx={{ borderRadius: 2, width: { sm: '100%', md: '167vh' } }}>
<Paper sx={{
p: { xs: 1.5, sm: 2 },
mb: { xs: 2, sm: 2 },
boxShadow: '0px 4px 5px rgba(0, 0, 0, 0.1)',
borderRadius: 2,
position: 'relative'
}}>
<IconButton
aria-label="more-actions"
sx={{
position: 'absolute',
top: { xs: 4, sm: 8 },
right: { xs: 4, sm: 8 },
color: '#667085'
}}
onClick={handleMenuOpen}
>
{/* <MoreVertIcon fontSize={isMobile ? 'small' : 'medium'} /> */}
</IconButton>
<Menu
anchorEl={anchorEl}
open={Boolean(anchorEl)}
onClose={handleMenuClose}
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
transformOrigin={{ vertical: 'top', horizontal: 'right' }}
>
<MenuItem>
<TextField
type="date"
value={selectedDate}
onChange={handleDateChange}
size="small"
sx={{ width: 150 }}
/>
</MenuItem>
<MenuItem>
<Button variant="outlined" size="small" onClick={handleTodayClick}>
Today
</Button>
</MenuItem>
</Menu>
{/* Header */}
<Box sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
mb: 2,
flexWrap: 'wrap',
gap: 1
}}>
<Box>
<Typography variant="h6" sx={{ fontSize: { xs: '15px', sm: '18px' }, fontWeight: 500 }}>
{title}
</Typography>
<Typography sx={{ fontSize: { xs: '11px', sm: '14px' }, fontWeight: 500, color: '#667085' }}>
{subtitle}
</Typography>
</Box>
</Box>
{/* Chart */}
<ResponsiveContainer width="100%" height={isMobile ? 350 : isTablet ? 390 : 395}>
<AreaChart data={data} margin={{
top: isMobile ? -30 : -45,
right: isMobile ? 15 : 30,
left: isMobile ? 10 : 20,
bottom: isMobile ? 10 : 20
}}>
<defs>
{dataKeys.map(({ key, color }) => (
<linearGradient key={key} id={`color-${key}`} x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor={color} stopOpacity={0.8} />
<stop offset="100%" stopColor={color} stopOpacity={0} />
</linearGradient>
))}
</defs>
<CartesianGrid stroke="#eee" strokeDasharray="0 0" vertical={false} />
<XAxis
dataKey={xDataKey}
axisLine={false}
tickLine={false}
tickMargin={isMobile ? 8 : 15}
tick={{
fontSize: isMobile ? 11 : 12,
angle: -25,
textAnchor: 'end'
}}
interval={0}
/>
<YAxis
ticks={ticksArray}
tickFormatter={valueFormatter}
axisLine={false}
tickLine={false}
tickMargin={isMobile ? 8 : 15}
tick={{ fontSize: isMobile ? 11 : 12 }}
/>
<Tooltip formatter={valueFormatter} />
<Legend
verticalAlign="top"
height={isMobile ? 30 : 36}
iconType="circle"
iconSize={isMobile ? 8 : 10}
wrapperStyle={{ paddingBottom: isMobile ? '15px' : '20px' }}
/>
{dataKeys.map(({ key, name, color }) => (
<Area
key={key}
name={name}
type="monotone"
dataKey={key}
stroke={color}
strokeWidth={isMobile ? 2 : 3}
fill={`url(#color-${key})`}
/>
))}
</AreaChart>
</ResponsiveContainer>
</Paper>
</Box>
);
};
StatisticsCard.propTypes = {
title: PropTypes.string,
subtitle: PropTypes.string,
data: PropTypes.arrayOf(PropTypes.object),
dataKeys: PropTypes.arrayOf(PropTypes.shape({
key: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
color: PropTypes.string.isRequired
})),
xDataKey: PropTypes.string,
valueFormatter: PropTypes.func,
timeFrame: PropTypes.oneOf(['day', 'week', 'month', 'year']),
onTimeFrameChange: PropTypes.func
};
export default StatisticsCard;