نسخ من RaghadAlkhous/RestaurantDash
Initial commit - restaurant dashboard
هذا الالتزام موجود في:
244
src/components/Home/Dashboard/AnalyticsPage.js
Normal file
244
src/components/Home/Dashboard/AnalyticsPage.js
Normal file
@@ -0,0 +1,244 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useRestaurant } from '../../../contexts/RestaurantContext';
|
||||
import StatisticsCard from './StatisticsCard';
|
||||
// import TablesManager from './TablesManager';
|
||||
import {
|
||||
Box,
|
||||
useTheme,
|
||||
useMediaQuery,
|
||||
Button,
|
||||
ButtonGroup,
|
||||
TextField
|
||||
} from '@mui/material';
|
||||
import authService from '../../../services/authService';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
const AnalyticsPage = () => {
|
||||
const { restaurantId } = useRestaurant();
|
||||
const [timeFrame, setTimeFrame] = useState('12m'); // '12m', '30d', '24h'
|
||||
const [customDate, setCustomDate] = useState(dayjs().format('YYYY-MM-DD'));
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
|
||||
const [chartData, setChartData] = useState([]);
|
||||
|
||||
const handleTimeFrameChange = (newTimeFrame) => {
|
||||
setTimeFrame(newTimeFrame);
|
||||
};
|
||||
|
||||
const handleCustomDateChange = (event) => {
|
||||
setCustomDate(event.target.value);
|
||||
};
|
||||
|
||||
const fetchStatistics = async () => {
|
||||
if (!restaurantId) return;
|
||||
|
||||
let period = 'yearly';
|
||||
let labels = [];
|
||||
let mappedData = [];
|
||||
|
||||
switch (timeFrame) {
|
||||
case '24h': // يومي
|
||||
period = 'daily';
|
||||
labels = Array.from({ length: 24 }, (_, i) => `${i.toString().padStart(2, '0')}:00`);
|
||||
try {
|
||||
const response = await authService.getOrderStatistics(restaurantId, period, customDate);
|
||||
if (response.success && response.data.length > 0) {
|
||||
mappedData = response.data.map(item => ({
|
||||
label: item.label || item.date || '',
|
||||
orders_total: item.orders_total || 0,
|
||||
items_total: item.items_total || 0
|
||||
}));
|
||||
} else {
|
||||
mappedData = labels.map(label => ({
|
||||
label,
|
||||
orders_total: 0,
|
||||
items_total: 0
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
mappedData = labels.map(label => ({
|
||||
label,
|
||||
orders_total: 0,
|
||||
items_total: 0
|
||||
}));
|
||||
}
|
||||
break;
|
||||
|
||||
case '30d': // شهري
|
||||
period = 'monthly';
|
||||
labels = Array.from({ length: 30 }, (_, i) => dayjs().startOf('month').add(i, 'day').format('DD'));
|
||||
try {
|
||||
const response = await authService.getOrderStatistics(restaurantId, period, customDate);
|
||||
if (response.success && response.data.length > 0) {
|
||||
mappedData = response.data.map(item => ({
|
||||
label: item.label ? dayjs(item.label).format('DD') : item.date ? dayjs(item.date).format('DD') : '',
|
||||
orders_total: item.orders_total || 0,
|
||||
items_total: item.items_total || 0
|
||||
}));
|
||||
} else {
|
||||
mappedData = labels.map(label => ({
|
||||
label,
|
||||
orders_total: 0,
|
||||
items_total: 0
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
mappedData = labels.map(label => ({
|
||||
label,
|
||||
orders_total: 0,
|
||||
items_total: 0
|
||||
}));
|
||||
}
|
||||
break;
|
||||
|
||||
case '12m': // سنوي
|
||||
default:
|
||||
period = 'yearly';
|
||||
labels = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
|
||||
try {
|
||||
const response = await authService.getOrderStatistics(restaurantId, period, customDate);
|
||||
if (response.success && response.data.length > 0) {
|
||||
mappedData = response.data.map(item => ({
|
||||
label: item.label || item.date || '',
|
||||
orders_total: item.orders_total || 0,
|
||||
items_total: item.items_total || 0
|
||||
}));
|
||||
} else {
|
||||
mappedData = labels.map(label => ({
|
||||
label,
|
||||
orders_total: 0,
|
||||
items_total: 0
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
mappedData = labels.map(label => ({
|
||||
label,
|
||||
orders_total: 0,
|
||||
items_total: 0
|
||||
}));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
setChartData(mappedData);
|
||||
};
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
fetchStatistics();
|
||||
}, [timeFrame, restaurantId, customDate]);
|
||||
|
||||
return (
|
||||
<Box
|
||||
pr={{ xs: 1, sm: 2 }}
|
||||
maxWidth="100%"
|
||||
overflowX="hidden">
|
||||
{/* Header Buttons */}
|
||||
<Box
|
||||
display="flex"
|
||||
flexDirection={{ xs: 'column', sm: 'row' }}
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
gap={2}
|
||||
mb={1.5}
|
||||
>
|
||||
<ButtonGroup
|
||||
size="small"
|
||||
variant="outlined"
|
||||
sx={{
|
||||
backgroundColor: '#ffffff',
|
||||
borderRadius: '8px',
|
||||
boxShadow: 'inset 0 0 0 1px #e0e0e0',
|
||||
'& .MuiButton-root': {
|
||||
textTransform: 'none',
|
||||
fontSize: '13px',
|
||||
padding: '6px 12px',
|
||||
border: 'none',
|
||||
borderRadius: '8px',
|
||||
color: '#555',
|
||||
'&:hover': { backgroundColor: '#f5f5f5' }
|
||||
},
|
||||
'& .MuiButton-contained': {
|
||||
backgroundColor: 'rgba(255, 117, 34, 0.08)',
|
||||
color: '#ff5722',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
}}
|
||||
>
|
||||
{[{ label: '12 Months', value: '12m' }, { label: '30 Days', value: '30d' }, { label: '24 Hours', value: '24h' }].map(({ label, value }) => (
|
||||
<Button
|
||||
key={value}
|
||||
variant={timeFrame === value ? 'contained' : 'text'}
|
||||
onClick={() => handleTimeFrameChange(value)}
|
||||
>
|
||||
{label}
|
||||
</Button>
|
||||
))}
|
||||
</ButtonGroup>
|
||||
|
||||
{/* Date Picker + Today Button */}
|
||||
<Box
|
||||
display="flex"
|
||||
gap={1}
|
||||
alignItems="center"
|
||||
sx={{
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
borderRadius: 2,
|
||||
p: '4px 8px',
|
||||
boxShadow: 'inset 0 0 0 1px #e0e0e0'
|
||||
}}
|
||||
>
|
||||
<TextField
|
||||
type="date"
|
||||
value={customDate}
|
||||
onChange={handleCustomDateChange}
|
||||
size="small"
|
||||
sx={{
|
||||
width: isMobile ? '100%' : 150,
|
||||
'& .MuiInputBase-input': { fontSize: isMobile ? 12 : 13, padding: '6px 8px' },
|
||||
'& .MuiOutlinedInput-notchedOutline': { border: 'none' }
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
variant="contained"
|
||||
size="small"
|
||||
onClick={() => setCustomDate(dayjs().format('YYYY-MM-DD'))}
|
||||
sx={{
|
||||
backgroundColor: 'rgba(255, 117, 34, 0.08)',
|
||||
color: '#ff5722',
|
||||
textTransform: 'none',
|
||||
boxShadow: 'none',
|
||||
fontSize: isMobile ? 12 : 13,
|
||||
'&:hover': { backgroundColor: 'rgba(255, 117, 34, 0.15)' }
|
||||
}}
|
||||
>
|
||||
Today
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* StatisticsCard */}
|
||||
<Box>
|
||||
<StatisticsCard
|
||||
title="Analytics Overview"
|
||||
subtitle="Orders Statistics"
|
||||
data={chartData}
|
||||
dataKeys={[
|
||||
{ key: 'orders_total', name: 'Orders', color: '#E46A11' },
|
||||
{ key: 'items_total', name: 'Items', color: '#0182FC' },
|
||||
]}
|
||||
xDataKey="label"
|
||||
valueFormatter={(value) => value}
|
||||
timeFrame={timeFrame}
|
||||
onTimeFrameChange={handleTimeFrameChange}
|
||||
height={320}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default AnalyticsPage;
|
||||
المرجع في مشكلة جديدة
حظر مستخدم