نسخ من RaghadAlkhous/RestaurantDash
update the dashbord and router
هذا الالتزام موجود في:
227
src/components/Home/Analytics&Reporting/AnalyticsContect.js
Normal file
227
src/components/Home/Analytics&Reporting/AnalyticsContect.js
Normal file
@@ -0,0 +1,227 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import StatisticsCard from './StatisticsCard';
|
||||
import TopSellingProduct from './TopSellingProduct';
|
||||
import SalesByLocation from './SalesByLocation';
|
||||
import {
|
||||
Box,
|
||||
useTheme,
|
||||
useMediaQuery,
|
||||
Skeleton,
|
||||
Button,
|
||||
Typography,
|
||||
ButtonGroup
|
||||
} from '@mui/material';
|
||||
import CalendarTodayOutlinedIcon from '@mui/icons-material/CalendarTodayOutlined';
|
||||
|
||||
const AnalyticsPage = () => {
|
||||
const [timeFrame, setTimeFrame] = useState('month');
|
||||
const theme = useTheme();
|
||||
const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm'));
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
|
||||
const [hasProducts, setHasProducts] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [sidebarOpen, setSidebarOpen] = useState(!isMobile);
|
||||
|
||||
const dailyData = [
|
||||
{ date: '10:00', visitors: 1500, conversions: 300 },
|
||||
{ date: '11:00', visitors: 1800, conversions: 320 },
|
||||
];
|
||||
|
||||
const weeklyData = [
|
||||
{ label: 'Week 1', visitors: 1500, conversions: 200 },
|
||||
{ label: 'Week 2', visitors: 2300, conversions: 400 },
|
||||
];
|
||||
|
||||
const monthlyData = [
|
||||
{ label: 'Jan', visitors: 15000, conversions: 3000 },
|
||||
{ label: 'Feb', visitors: 18000, conversions: 4000 },
|
||||
];
|
||||
|
||||
const yearlyData = [
|
||||
{ label: '2024', visitors: 25000, conversions: 7000 },
|
||||
{ label: '2025', visitors: 38000, conversions: 12000 },
|
||||
];
|
||||
|
||||
|
||||
const getData = () => {
|
||||
switch (timeFrame) {
|
||||
case '24h':
|
||||
return dailyData;
|
||||
case '7d':
|
||||
return weeklyData;
|
||||
case '30d':
|
||||
return monthlyData;
|
||||
case '12m':
|
||||
return yearlyData;
|
||||
case 'all':
|
||||
return [...yearlyData, ...monthlyData, ...weeklyData, ...dailyData];
|
||||
default:
|
||||
return dailyData;
|
||||
}
|
||||
};
|
||||
|
||||
const topSellingProducts = [
|
||||
{ product: 'Apple Watch', sales: 150, amount: 45000, price: 299, status: 'Published' },
|
||||
{ product: 'Samsung Galaxy', sales: 90, amount: 36000, price: 400, status: 'Low Stock' },
|
||||
{ product: 'Sony Headphones', sales: 60, amount: 18000, price: 299, status: 'Draft' },
|
||||
];
|
||||
|
||||
const salesData = [
|
||||
{ country: 'United Kingdom', amount: 17678, change: 12, sales: 340 },
|
||||
{ country: 'Spain', amount: 5500, change: -5, sales: 100 },
|
||||
{ country: 'Germany', amount: 24189, change: -25, sales: 540 },
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
const checkProducts = async () => {
|
||||
setIsLoading(true);
|
||||
const productsExist = await new Promise((resolve) =>
|
||||
setTimeout(() => resolve(true), 1500)
|
||||
);
|
||||
setHasProducts(productsExist);
|
||||
setIsLoading(false);
|
||||
};
|
||||
checkProducts();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const handleResize = () => {
|
||||
setSidebarOpen(window.innerWidth >= theme.breakpoints.values.md);
|
||||
};
|
||||
handleResize();
|
||||
window.addEventListener('resize', handleResize);
|
||||
return () => window.removeEventListener('resize', handleResize);
|
||||
}, [theme.breakpoints.values.md]);
|
||||
|
||||
return (
|
||||
<Box
|
||||
p={{ 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={3}
|
||||
>
|
||||
<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: 'All Time', value: 'all' },
|
||||
{ label: '12 Months', value: '12m' },
|
||||
{ label: '30 Days', value: '30d' },
|
||||
{ label: '7 Days', value: '7d' },
|
||||
{ label: '24 Hour', value: '24h' },
|
||||
].map(({ label, value }) => (
|
||||
<Button
|
||||
key={value}
|
||||
variant={timeFrame === value ? 'contained' : 'text'}
|
||||
onClick={() => setTimeFrame(value)}
|
||||
>
|
||||
{label}
|
||||
</Button>
|
||||
))}
|
||||
</ButtonGroup>
|
||||
|
||||
<Box display="flex" gap={2} flexWrap="wrap" justifyContent={{ xs: 'space-between', sm: 'flex-end' }} width={{ xs: '100%', sm: 'auto' }}>
|
||||
<Button
|
||||
variant="contained"
|
||||
sx={{
|
||||
textTransform: 'none',
|
||||
color: '#667085',
|
||||
backgroundColor: 'white',
|
||||
boxShadow: 'none',
|
||||
borderRadius: '8px',
|
||||
height: '40px',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
border: '1px solid #e0e0e0',
|
||||
gap: 1,
|
||||
minWidth: '120px'
|
||||
}}
|
||||
>
|
||||
<CalendarTodayOutlinedIcon sx={{ fontSize: 16 }} />
|
||||
{!isSmallScreen && 'Select Dates'}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
sx={{
|
||||
textTransform: 'none',
|
||||
color: 'white',
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
borderRadius: '8px',
|
||||
height: '40px',
|
||||
fontWeight: 600,
|
||||
fontSize: '14px',
|
||||
minWidth: '100px'
|
||||
}}
|
||||
>
|
||||
KPIs Filter
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Data Sections */}
|
||||
<Box display="flex" flexDirection={{ xs: 'column', md: 'row' }} gap={2} mb={3}>
|
||||
<Box flex={2}>
|
||||
<TopSellingProduct data={topSellingProducts} />
|
||||
</Box>
|
||||
<Box flex={1}>
|
||||
<SalesByLocation data={salesData} />
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Chart Section */}
|
||||
<Box>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<Skeleton variant="rectangular" height={50} sx={{ mb: 2 }} />
|
||||
<Skeleton variant="rectangular" height={200} sx={{ mb: 2 }} />
|
||||
<Skeleton variant="rectangular" height={300} sx={{ mb: 2 }} />
|
||||
</>
|
||||
) : (
|
||||
<StatisticsCard
|
||||
title="Analytics Overview"
|
||||
subtitle="Performance Metrics"
|
||||
data={getData()}
|
||||
dataKeys={[
|
||||
{ key: 'visitors', name: 'Visitors', color: '#4CAF50' },
|
||||
{ key: 'conversions', name: 'Conversions', color: '#9C27B0' },
|
||||
]}
|
||||
xDataKey={timeFrame === '24h' ? 'date' : 'label'}
|
||||
timeFrame={timeFrame}
|
||||
onTimeFrameChange={setTimeFrame}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default AnalyticsPage;
|
||||
المرجع في مشكلة جديدة
حظر مستخدم