feat(charts): add new ChartFlow page and analytics components for enhanced dashboard insights
This commit is contained in:
parent
df144ae357
commit
cfbdda6e02
@ -39,10 +39,15 @@ export const navData = [
|
|||||||
icon: icon('ic-cart'),
|
icon: icon('ic-cart'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'User Manager',
|
title: 'SignFlow',
|
||||||
path: '/user',
|
path: '/user',
|
||||||
icon: icon('ic-user'),
|
icon: icon('ic-user'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'ChartFlow',
|
||||||
|
path: '/chart-flow',
|
||||||
|
icon: icon('ic-user'),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'Sign in',
|
title: 'Sign in',
|
||||||
path: '/sign-in',
|
path: '/sign-in',
|
||||||
|
|||||||
20
src/client/dd-hub-react/src/pages/charts.tsx
Normal file
20
src/client/dd-hub-react/src/pages/charts.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { CONFIG } from 'src/config-global';
|
||||||
|
|
||||||
|
import { ChartsView } from 'src/sections/charts/view';
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<title>{`Dashboard - ${CONFIG.appName}`}</title>
|
||||||
|
<meta
|
||||||
|
name="description"
|
||||||
|
content="The starting point for your next project with Minimal UI Kit, built on the newest version of Material-UI ©, ready to be customized to your style"
|
||||||
|
/>
|
||||||
|
<meta name="keywords" content="react,material,kit,application,dashboard,admin,template" />
|
||||||
|
|
||||||
|
< ChartsView/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import { CONFIG } from 'src/config-global';
|
import { CONFIG } from 'src/config-global';
|
||||||
|
|
||||||
import { OverviewAnalyticsView as DashboardView, OverviewAnalyticsView } from 'src/sections/overview/view';
|
import { OverviewAnalyticsView } from 'src/sections/overview/view';
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@ -19,6 +19,7 @@ export const SignInPage = lazy(() => import('src/pages/sign-in'));
|
|||||||
export const ProductsPage = lazy(() => import('src/pages/products'));
|
export const ProductsPage = lazy(() => import('src/pages/products'));
|
||||||
export const Page404 = lazy(() => import('src/pages/page-not-found'));
|
export const Page404 = lazy(() => import('src/pages/page-not-found'));
|
||||||
export const DocumentSearch = lazy(() => import('src/pages/doc-search'));
|
export const DocumentSearch = lazy(() => import('src/pages/doc-search'));
|
||||||
|
export const ChartFlowPage = lazy(() => import('src/pages/charts'));
|
||||||
|
|
||||||
const renderFallback = () => (
|
const renderFallback = () => (
|
||||||
<Box
|
<Box
|
||||||
@ -55,6 +56,7 @@ export const routesSection: RouteObject[] = [
|
|||||||
{ path: 'products', element: <ProductsPage /> },
|
{ path: 'products', element: <ProductsPage /> },
|
||||||
{ path: 'user', element: <UserPage /> },
|
{ path: 'user', element: <UserPage /> },
|
||||||
{ path: 'blog', element: <BlogPage /> },
|
{ path: 'blog', element: <BlogPage /> },
|
||||||
|
{ path: 'chart-flow', element: <ChartFlowPage /> },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -0,0 +1,82 @@
|
|||||||
|
import type { CardProps } from '@mui/material/Card';
|
||||||
|
import type { ChartOptions } from 'src/components/chart';
|
||||||
|
|
||||||
|
import Card from '@mui/material/Card';
|
||||||
|
import CardHeader from '@mui/material/CardHeader';
|
||||||
|
import { useTheme, alpha as hexAlpha } from '@mui/material/styles';
|
||||||
|
|
||||||
|
import { fNumber } from 'src/utils/format-number';
|
||||||
|
|
||||||
|
import { Chart, useChart } from 'src/components/chart';
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
type Props = CardProps & {
|
||||||
|
title?: string;
|
||||||
|
subheader?: string;
|
||||||
|
chart: {
|
||||||
|
colors?: string[];
|
||||||
|
categories?: string[];
|
||||||
|
series: {
|
||||||
|
name: string;
|
||||||
|
data: number[];
|
||||||
|
}[];
|
||||||
|
options?: ChartOptions;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export function AnalyticsConversionRates({ title, subheader, chart, sx, ...other }: Props) {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const chartColors = chart.colors ?? [
|
||||||
|
theme.palette.primary.dark,
|
||||||
|
hexAlpha(theme.palette.primary.dark, 0.24),
|
||||||
|
];
|
||||||
|
|
||||||
|
const chartOptions = useChart({
|
||||||
|
colors: chartColors,
|
||||||
|
stroke: { width: 2, colors: ['transparent'] },
|
||||||
|
tooltip: {
|
||||||
|
shared: true,
|
||||||
|
intersect: false,
|
||||||
|
y: {
|
||||||
|
formatter: (value: number) => fNumber(value),
|
||||||
|
title: { formatter: (seriesName: string) => `${seriesName}: ` },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
xaxis: { categories: chart.categories },
|
||||||
|
dataLabels: {
|
||||||
|
enabled: true,
|
||||||
|
offsetX: -6,
|
||||||
|
style: { fontSize: '10px', colors: ['#FFFFFF', theme.palette.text.primary] },
|
||||||
|
},
|
||||||
|
plotOptions: {
|
||||||
|
bar: {
|
||||||
|
horizontal: true,
|
||||||
|
borderRadius: 2,
|
||||||
|
barHeight: '48%',
|
||||||
|
dataLabels: { position: 'top' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
...chart.options,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card sx={sx} {...other}>
|
||||||
|
<CardHeader title={title} subheader={subheader} />
|
||||||
|
|
||||||
|
<Chart
|
||||||
|
type="bar"
|
||||||
|
series={chart.series}
|
||||||
|
options={chartOptions}
|
||||||
|
slotProps={{ loading: { p: 2.5 } }}
|
||||||
|
sx={{
|
||||||
|
pl: 1,
|
||||||
|
py: 2.5,
|
||||||
|
pr: 2.5,
|
||||||
|
height: 360,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,73 @@
|
|||||||
|
import type { CardProps } from '@mui/material/Card';
|
||||||
|
import type { ChartOptions } from 'src/components/chart';
|
||||||
|
|
||||||
|
import Card from '@mui/material/Card';
|
||||||
|
import Divider from '@mui/material/Divider';
|
||||||
|
import { useTheme } from '@mui/material/styles';
|
||||||
|
import CardHeader from '@mui/material/CardHeader';
|
||||||
|
|
||||||
|
import { Chart, useChart, ChartLegends } from 'src/components/chart';
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
type Props = CardProps & {
|
||||||
|
title?: string;
|
||||||
|
subheader?: string;
|
||||||
|
chart: {
|
||||||
|
colors?: string[];
|
||||||
|
categories: string[];
|
||||||
|
series: {
|
||||||
|
name: string;
|
||||||
|
data: number[];
|
||||||
|
}[];
|
||||||
|
options?: ChartOptions;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export function AnalyticsCurrentSubject({ title, subheader, chart, sx, ...other }: Props) {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const chartColors = chart.colors ?? [
|
||||||
|
theme.palette.primary.main,
|
||||||
|
theme.palette.warning.main,
|
||||||
|
theme.palette.info.main,
|
||||||
|
];
|
||||||
|
|
||||||
|
const chartOptions = useChart({
|
||||||
|
colors: chartColors,
|
||||||
|
stroke: { width: 2 },
|
||||||
|
fill: { opacity: 0.48 },
|
||||||
|
xaxis: {
|
||||||
|
categories: chart.categories,
|
||||||
|
labels: { style: { colors: Array.from({ length: 6 }, () => theme.palette.text.secondary) } },
|
||||||
|
},
|
||||||
|
...chart.options,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card sx={sx} {...other}>
|
||||||
|
<CardHeader title={title} subheader={subheader} />
|
||||||
|
|
||||||
|
<Chart
|
||||||
|
type="radar"
|
||||||
|
series={chart.series}
|
||||||
|
options={chartOptions}
|
||||||
|
slotProps={{ loading: { py: 2.5 } }}
|
||||||
|
sx={{
|
||||||
|
my: 1,
|
||||||
|
mx: 'auto',
|
||||||
|
width: 300,
|
||||||
|
height: 300,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Divider sx={{ borderStyle: 'dashed' }} />
|
||||||
|
|
||||||
|
<ChartLegends
|
||||||
|
labels={chart.series.map((item) => item.name)}
|
||||||
|
colors={chartOptions?.colors}
|
||||||
|
sx={{ p: 3, justifyContent: 'center' }}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,81 @@
|
|||||||
|
import type { CardProps } from '@mui/material/Card';
|
||||||
|
import type { ChartOptions } from 'src/components/chart';
|
||||||
|
|
||||||
|
import Card from '@mui/material/Card';
|
||||||
|
import Divider from '@mui/material/Divider';
|
||||||
|
import { useTheme } from '@mui/material/styles';
|
||||||
|
import CardHeader from '@mui/material/CardHeader';
|
||||||
|
|
||||||
|
import { fNumber } from 'src/utils/format-number';
|
||||||
|
|
||||||
|
import { Chart, useChart, ChartLegends } from 'src/components/chart';
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
type Props = CardProps & {
|
||||||
|
title?: string;
|
||||||
|
subheader?: string;
|
||||||
|
chart: {
|
||||||
|
colors?: string[];
|
||||||
|
series: {
|
||||||
|
label: string;
|
||||||
|
value: number;
|
||||||
|
}[];
|
||||||
|
options?: ChartOptions;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export function AnalyticsCurrentVisits({ title, subheader, chart, sx, ...other }: Props) {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const chartSeries = chart.series.map((item) => item.value);
|
||||||
|
|
||||||
|
const chartColors = chart.colors ?? [
|
||||||
|
theme.palette.primary.main,
|
||||||
|
theme.palette.warning.light,
|
||||||
|
theme.palette.info.dark,
|
||||||
|
theme.palette.error.main,
|
||||||
|
];
|
||||||
|
|
||||||
|
const chartOptions = useChart({
|
||||||
|
chart: { sparkline: { enabled: true } },
|
||||||
|
colors: chartColors,
|
||||||
|
labels: chart.series.map((item) => item.label),
|
||||||
|
stroke: { width: 0 },
|
||||||
|
dataLabels: { enabled: true, dropShadow: { enabled: false } },
|
||||||
|
tooltip: {
|
||||||
|
y: {
|
||||||
|
formatter: (value: number) => fNumber(value),
|
||||||
|
title: { formatter: (seriesName: string) => `${seriesName}` },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plotOptions: { pie: { donut: { labels: { show: false } } } },
|
||||||
|
...chart.options,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card sx={sx} {...other}>
|
||||||
|
<CardHeader title={title} subheader={subheader} />
|
||||||
|
|
||||||
|
<Chart
|
||||||
|
type="pie"
|
||||||
|
series={chartSeries}
|
||||||
|
options={chartOptions}
|
||||||
|
sx={{
|
||||||
|
my: 6,
|
||||||
|
mx: 'auto',
|
||||||
|
width: { xs: 240, xl: 260 },
|
||||||
|
height: { xs: 240, xl: 260 },
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Divider sx={{ borderStyle: 'dashed' }} />
|
||||||
|
|
||||||
|
<ChartLegends
|
||||||
|
labels={chartOptions?.labels}
|
||||||
|
colors={chartOptions?.colors}
|
||||||
|
sx={{ p: 3, justifyContent: 'center' }}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
103
src/client/dd-hub-react/src/sections/charts/analytics-news.tsx
Normal file
103
src/client/dd-hub-react/src/sections/charts/analytics-news.tsx
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import type { BoxProps } from '@mui/material/Box';
|
||||||
|
import type { CardProps } from '@mui/material/Card';
|
||||||
|
|
||||||
|
import Box from '@mui/material/Box';
|
||||||
|
import Link from '@mui/material/Link';
|
||||||
|
import Card from '@mui/material/Card';
|
||||||
|
import Button from '@mui/material/Button';
|
||||||
|
import Avatar from '@mui/material/Avatar';
|
||||||
|
import CardHeader from '@mui/material/CardHeader';
|
||||||
|
import ListItemText from '@mui/material/ListItemText';
|
||||||
|
|
||||||
|
import { fToNow } from 'src/utils/format-time';
|
||||||
|
|
||||||
|
import { Iconify } from 'src/components/iconify';
|
||||||
|
import { Scrollbar } from 'src/components/scrollbar';
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
type Props = CardProps & {
|
||||||
|
title?: string;
|
||||||
|
subheader?: string;
|
||||||
|
list: {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
coverUrl: string;
|
||||||
|
description: string;
|
||||||
|
postedAt: string | number | null;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export function AnalyticsNews({ title, subheader, list, sx, ...other }: Props) {
|
||||||
|
return (
|
||||||
|
<Card sx={sx} {...other}>
|
||||||
|
<CardHeader title={title} subheader={subheader} sx={{ mb: 1 }} />
|
||||||
|
|
||||||
|
<Scrollbar sx={{ minHeight: 405 }}>
|
||||||
|
<Box sx={{ minWidth: 640 }}>
|
||||||
|
{list.map((item) => (
|
||||||
|
<Item key={item.id} item={item} />
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
</Scrollbar>
|
||||||
|
|
||||||
|
<Box sx={{ p: 2, textAlign: 'right' }}>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
color="inherit"
|
||||||
|
endIcon={<Iconify icon="eva:arrow-ios-forward-fill" width={18} sx={{ ml: -0.5 }} />}
|
||||||
|
>
|
||||||
|
View all
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
type ItemProps = BoxProps & {
|
||||||
|
item: Props['list'][number];
|
||||||
|
};
|
||||||
|
|
||||||
|
function Item({ item, sx, ...other }: ItemProps) {
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={[
|
||||||
|
(theme) => ({
|
||||||
|
py: 2,
|
||||||
|
px: 3,
|
||||||
|
gap: 2,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
borderBottom: `dashed 1px ${theme.vars.palette.divider}`,
|
||||||
|
}),
|
||||||
|
...(Array.isArray(sx) ? sx : [sx]),
|
||||||
|
]}
|
||||||
|
{...other}
|
||||||
|
>
|
||||||
|
<Avatar
|
||||||
|
variant="rounded"
|
||||||
|
alt={item.title}
|
||||||
|
src={item.coverUrl}
|
||||||
|
sx={{ width: 48, height: 48, flexShrink: 0 }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ListItemText
|
||||||
|
primary={<Link color="inherit">{item.title}</Link>}
|
||||||
|
secondary={item.description}
|
||||||
|
slotProps={{
|
||||||
|
primary: { noWrap: true },
|
||||||
|
secondary: {
|
||||||
|
noWrap: true,
|
||||||
|
sx: { mt: 0.5 },
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Box sx={{ flexShrink: 0, typography: 'caption', color: 'text.disabled' }}>
|
||||||
|
{fToNow(item.postedAt)}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,77 @@
|
|||||||
|
import type { CardProps } from '@mui/material/Card';
|
||||||
|
import type { TimelineItemProps } from '@mui/lab/TimelineItem';
|
||||||
|
|
||||||
|
import Card from '@mui/material/Card';
|
||||||
|
import Timeline from '@mui/lab/Timeline';
|
||||||
|
import TimelineDot from '@mui/lab/TimelineDot';
|
||||||
|
import Typography from '@mui/material/Typography';
|
||||||
|
import CardHeader from '@mui/material/CardHeader';
|
||||||
|
import TimelineContent from '@mui/lab/TimelineContent';
|
||||||
|
import TimelineSeparator from '@mui/lab/TimelineSeparator';
|
||||||
|
import TimelineConnector from '@mui/lab/TimelineConnector';
|
||||||
|
import TimelineItem, { timelineItemClasses } from '@mui/lab/TimelineItem';
|
||||||
|
|
||||||
|
import { fDateTime } from 'src/utils/format-time';
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
type Props = CardProps & {
|
||||||
|
title?: string;
|
||||||
|
subheader?: string;
|
||||||
|
list: {
|
||||||
|
id: string;
|
||||||
|
type: string;
|
||||||
|
title: string;
|
||||||
|
time: string | number | null;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export function AnalyticsOrderTimeline({ title, subheader, list, sx, ...other }: Props) {
|
||||||
|
return (
|
||||||
|
<Card sx={sx} {...other}>
|
||||||
|
<CardHeader title={title} subheader={subheader} />
|
||||||
|
|
||||||
|
<Timeline
|
||||||
|
sx={{ m: 0, p: 3, [`& .${timelineItemClasses.root}:before`]: { flex: 0, padding: 0 } }}
|
||||||
|
>
|
||||||
|
{list.map((item, index) => (
|
||||||
|
<Item key={item.id} item={item} lastItem={index === list.length - 1} />
|
||||||
|
))}
|
||||||
|
</Timeline>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
type ItemProps = TimelineItemProps & {
|
||||||
|
lastItem: boolean;
|
||||||
|
item: Props['list'][number];
|
||||||
|
};
|
||||||
|
|
||||||
|
function Item({ item, lastItem, ...other }: ItemProps) {
|
||||||
|
return (
|
||||||
|
<TimelineItem {...other}>
|
||||||
|
<TimelineSeparator>
|
||||||
|
<TimelineDot
|
||||||
|
color={
|
||||||
|
(item.type === 'order1' && 'primary') ||
|
||||||
|
(item.type === 'order2' && 'success') ||
|
||||||
|
(item.type === 'order3' && 'info') ||
|
||||||
|
(item.type === 'order4' && 'warning') ||
|
||||||
|
'error'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{lastItem ? null : <TimelineConnector />}
|
||||||
|
</TimelineSeparator>
|
||||||
|
|
||||||
|
<TimelineContent>
|
||||||
|
<Typography variant="subtitle2">{item.title}</Typography>
|
||||||
|
|
||||||
|
<Typography variant="caption" sx={{ color: 'text.disabled' }}>
|
||||||
|
{fDateTime(item.time)}
|
||||||
|
</Typography>
|
||||||
|
</TimelineContent>
|
||||||
|
</TimelineItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
179
src/client/dd-hub-react/src/sections/charts/analytics-tasks.tsx
Normal file
179
src/client/dd-hub-react/src/sections/charts/analytics-tasks.tsx
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
import type { BoxProps } from '@mui/material/Box';
|
||||||
|
import type { CardProps } from '@mui/material/Card';
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { usePopover } from 'minimal-shared/hooks';
|
||||||
|
|
||||||
|
import Box from '@mui/material/Box';
|
||||||
|
import Card from '@mui/material/Card';
|
||||||
|
import Stack from '@mui/material/Stack';
|
||||||
|
import Popover from '@mui/material/Popover';
|
||||||
|
import Divider from '@mui/material/Divider';
|
||||||
|
import MenuList from '@mui/material/MenuList';
|
||||||
|
import Checkbox from '@mui/material/Checkbox';
|
||||||
|
import IconButton from '@mui/material/IconButton';
|
||||||
|
import CardHeader from '@mui/material/CardHeader';
|
||||||
|
import FormControlLabel from '@mui/material/FormControlLabel';
|
||||||
|
import MenuItem, { menuItemClasses } from '@mui/material/MenuItem';
|
||||||
|
|
||||||
|
import { Iconify } from 'src/components/iconify';
|
||||||
|
import { Scrollbar } from 'src/components/scrollbar';
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
type Props = CardProps & {
|
||||||
|
title?: string;
|
||||||
|
subheader?: string;
|
||||||
|
list: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export function AnalyticsTasks({ title, subheader, list, sx, ...other }: Props) {
|
||||||
|
const [selected, setSelected] = useState(['2']);
|
||||||
|
|
||||||
|
const handleClickComplete = (taskId: string) => {
|
||||||
|
const tasksCompleted = selected.includes(taskId)
|
||||||
|
? selected.filter((value) => value !== taskId)
|
||||||
|
: [...selected, taskId];
|
||||||
|
|
||||||
|
setSelected(tasksCompleted);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card sx={sx} {...other}>
|
||||||
|
<CardHeader title={title} subheader={subheader} sx={{ mb: 1 }} />
|
||||||
|
|
||||||
|
<Scrollbar sx={{ minHeight: 304 }}>
|
||||||
|
<Stack divider={<Divider sx={{ borderStyle: 'dashed' }} />} sx={{ minWidth: 560 }}>
|
||||||
|
{list.map((item) => (
|
||||||
|
<TaskItem
|
||||||
|
key={item.id}
|
||||||
|
item={item}
|
||||||
|
selected={selected.includes(item.id)}
|
||||||
|
onChange={() => handleClickComplete(item.id)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
</Scrollbar>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
type TaskItemProps = BoxProps & {
|
||||||
|
selected: boolean;
|
||||||
|
item: Props['list'][number];
|
||||||
|
onChange: (id: string) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
function TaskItem({ item, selected, onChange, sx, ...other }: TaskItemProps) {
|
||||||
|
const menuActions = usePopover();
|
||||||
|
|
||||||
|
const handleMarkComplete = () => {
|
||||||
|
menuActions.onClose();
|
||||||
|
console.info('MARK COMPLETE', item.id);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleShare = () => {
|
||||||
|
menuActions.onClose();
|
||||||
|
console.info('SHARE', item.id);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEdit = () => {
|
||||||
|
menuActions.onClose();
|
||||||
|
console.info('EDIT', item.id);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = () => {
|
||||||
|
menuActions.onClose();
|
||||||
|
console.info('DELETE', item.id);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Box
|
||||||
|
sx={[
|
||||||
|
() => ({
|
||||||
|
pl: 2,
|
||||||
|
pr: 1,
|
||||||
|
py: 1.5,
|
||||||
|
display: 'flex',
|
||||||
|
...(selected && {
|
||||||
|
color: 'text.disabled',
|
||||||
|
textDecoration: 'line-through',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
...(Array.isArray(sx) ? sx : [sx]),
|
||||||
|
]}
|
||||||
|
{...other}
|
||||||
|
>
|
||||||
|
<FormControlLabel
|
||||||
|
label={item.name}
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
disableRipple
|
||||||
|
checked={selected}
|
||||||
|
onChange={onChange}
|
||||||
|
slotProps={{ input: { id: `${item.name}-checkbox` } }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
sx={{ flexGrow: 1, m: 0 }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<IconButton color={menuActions.open ? 'inherit' : 'default'} onClick={menuActions.onOpen}>
|
||||||
|
<Iconify icon="eva:more-vertical-fill" />
|
||||||
|
</IconButton>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Popover
|
||||||
|
open={menuActions.open}
|
||||||
|
anchorEl={menuActions.anchorEl}
|
||||||
|
onClose={menuActions.onClose}
|
||||||
|
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
|
||||||
|
transformOrigin={{ vertical: 'top', horizontal: 'right' }}
|
||||||
|
>
|
||||||
|
<MenuList
|
||||||
|
disablePadding
|
||||||
|
sx={{
|
||||||
|
p: 0.5,
|
||||||
|
gap: 0.5,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
[`& .${menuItemClasses.root}`]: {
|
||||||
|
pl: 1,
|
||||||
|
pr: 2,
|
||||||
|
gap: 2,
|
||||||
|
borderRadius: 0.75,
|
||||||
|
[`&.${menuItemClasses.selected}`]: { bgcolor: 'action.selected' },
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MenuItem onClick={handleMarkComplete}>
|
||||||
|
<Iconify icon="solar:check-circle-bold" />
|
||||||
|
Mark complete
|
||||||
|
</MenuItem>
|
||||||
|
|
||||||
|
<MenuItem onClick={handleEdit}>
|
||||||
|
<Iconify icon="solar:pen-bold" />
|
||||||
|
Edit
|
||||||
|
</MenuItem>
|
||||||
|
|
||||||
|
<MenuItem onClick={handleShare}>
|
||||||
|
<Iconify icon="solar:share-bold" />
|
||||||
|
Share
|
||||||
|
</MenuItem>
|
||||||
|
|
||||||
|
<Divider sx={{ borderStyle: 'dashed' }} />
|
||||||
|
|
||||||
|
<MenuItem onClick={handleDelete} sx={{ color: 'error.main' }}>
|
||||||
|
<Iconify icon="solar:trash-bin-trash-bold" />
|
||||||
|
Delete
|
||||||
|
</MenuItem>
|
||||||
|
</MenuList>
|
||||||
|
</Popover>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
import type { CardProps } from '@mui/material/Card';
|
||||||
|
|
||||||
|
import { varAlpha } from 'minimal-shared/utils';
|
||||||
|
|
||||||
|
import Box from '@mui/material/Box';
|
||||||
|
import Card from '@mui/material/Card';
|
||||||
|
import CardHeader from '@mui/material/CardHeader';
|
||||||
|
import Typography from '@mui/material/Typography';
|
||||||
|
|
||||||
|
import { fShortenNumber } from 'src/utils/format-number';
|
||||||
|
|
||||||
|
import { Iconify } from 'src/components/iconify';
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
type Props = CardProps & {
|
||||||
|
title?: string;
|
||||||
|
subheader?: string;
|
||||||
|
list: { value: string; label: string; total: number }[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export function AnalyticsTrafficBySite({ title, subheader, list, sx, ...other }: Props) {
|
||||||
|
return (
|
||||||
|
<Card sx={sx} {...other}>
|
||||||
|
<CardHeader title={title} subheader={subheader} />
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
p: 3,
|
||||||
|
gap: 2,
|
||||||
|
display: 'grid',
|
||||||
|
gridTemplateColumns: 'repeat(2, 1fr)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{list.map((site) => (
|
||||||
|
<Box
|
||||||
|
key={site.label}
|
||||||
|
sx={(theme) => ({
|
||||||
|
py: 2.5,
|
||||||
|
display: 'flex',
|
||||||
|
borderRadius: 1.5,
|
||||||
|
textAlign: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
flexDirection: 'column',
|
||||||
|
border: `solid 1px ${varAlpha(theme.vars.palette.grey['500Channel'], 0.12)}`,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{site.value === 'twitter' && <Iconify width={32} icon="socials:twitter" />}
|
||||||
|
{site.value === 'facebook' && <Iconify width={32} icon="socials:facebook" />}
|
||||||
|
{site.value === 'google' && <Iconify width={32} icon="socials:google" />}
|
||||||
|
{site.value === 'linkedin' && <Iconify width={32} icon="socials:linkedin" />}
|
||||||
|
|
||||||
|
<Typography variant="h6" sx={{ mt: 1 }}>
|
||||||
|
{fShortenNumber(site.total)}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography variant="body2" sx={{ color: 'text.secondary' }}>
|
||||||
|
{site.label}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
import type { CardProps } from '@mui/material/Card';
|
||||||
|
import type { ChartOptions } from 'src/components/chart';
|
||||||
|
|
||||||
|
import Card from '@mui/material/Card';
|
||||||
|
import CardHeader from '@mui/material/CardHeader';
|
||||||
|
import { useTheme, alpha as hexAlpha } from '@mui/material/styles';
|
||||||
|
|
||||||
|
import { Chart, useChart } from 'src/components/chart';
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
type Props = CardProps & {
|
||||||
|
title?: string;
|
||||||
|
subheader?: string;
|
||||||
|
chart: {
|
||||||
|
colors?: string[];
|
||||||
|
categories?: string[];
|
||||||
|
series: {
|
||||||
|
name: string;
|
||||||
|
data: number[];
|
||||||
|
}[];
|
||||||
|
options?: ChartOptions;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export function AnalyticsWebsiteVisits({ title, subheader, chart, sx, ...other }: Props) {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const chartColors = chart.colors ?? [
|
||||||
|
hexAlpha(theme.palette.primary.dark, 0.8),
|
||||||
|
hexAlpha(theme.palette.warning.main, 0.8),
|
||||||
|
];
|
||||||
|
|
||||||
|
const chartOptions = useChart({
|
||||||
|
colors: chartColors,
|
||||||
|
stroke: { width: 2, colors: ['transparent'] },
|
||||||
|
xaxis: { categories: chart.categories },
|
||||||
|
legend: { show: true },
|
||||||
|
tooltip: { y: { formatter: (value: number) => `${value} visits` } },
|
||||||
|
...chart.options,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card sx={sx} {...other}>
|
||||||
|
<CardHeader title={title} subheader={subheader} />
|
||||||
|
|
||||||
|
<Chart
|
||||||
|
type="bar"
|
||||||
|
series={chart.series}
|
||||||
|
options={chartOptions}
|
||||||
|
slotProps={{ loading: { p: 2.5 } }}
|
||||||
|
sx={{
|
||||||
|
pl: 1,
|
||||||
|
py: 2.5,
|
||||||
|
pr: 2.5,
|
||||||
|
height: 364,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,142 @@
|
|||||||
|
import type { CardProps } from '@mui/material/Card';
|
||||||
|
import type { PaletteColorKey } from 'src/theme/core';
|
||||||
|
import type { ChartOptions } from 'src/components/chart';
|
||||||
|
|
||||||
|
import { varAlpha } from 'minimal-shared/utils';
|
||||||
|
|
||||||
|
import Box from '@mui/material/Box';
|
||||||
|
import Card from '@mui/material/Card';
|
||||||
|
import { useTheme } from '@mui/material/styles';
|
||||||
|
|
||||||
|
import { fNumber, fPercent, fShortenNumber } from 'src/utils/format-number';
|
||||||
|
|
||||||
|
import { Iconify } from 'src/components/iconify';
|
||||||
|
import { SvgColor } from 'src/components/svg-color';
|
||||||
|
import { Chart, useChart } from 'src/components/chart';
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
type Props = CardProps & {
|
||||||
|
title: string;
|
||||||
|
total: number;
|
||||||
|
percent: number;
|
||||||
|
color?: PaletteColorKey;
|
||||||
|
icon: React.ReactNode;
|
||||||
|
chart: {
|
||||||
|
series: number[];
|
||||||
|
categories: string[];
|
||||||
|
options?: ChartOptions;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export function AnalyticsWidgetSummary({
|
||||||
|
sx,
|
||||||
|
icon,
|
||||||
|
title,
|
||||||
|
total,
|
||||||
|
chart,
|
||||||
|
percent,
|
||||||
|
color = 'primary',
|
||||||
|
...other
|
||||||
|
}: Props) {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const chartColors = [theme.palette[color].dark];
|
||||||
|
|
||||||
|
const chartOptions = useChart({
|
||||||
|
chart: { sparkline: { enabled: true } },
|
||||||
|
colors: chartColors,
|
||||||
|
xaxis: { categories: chart.categories },
|
||||||
|
grid: {
|
||||||
|
padding: {
|
||||||
|
top: 6,
|
||||||
|
left: 6,
|
||||||
|
right: 6,
|
||||||
|
bottom: 6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
y: { formatter: (value: number) => fNumber(value), title: { formatter: () => '' } },
|
||||||
|
},
|
||||||
|
markers: {
|
||||||
|
strokeWidth: 0,
|
||||||
|
},
|
||||||
|
...chart.options,
|
||||||
|
});
|
||||||
|
|
||||||
|
const renderTrending = () => (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
top: 16,
|
||||||
|
gap: 0.5,
|
||||||
|
right: 16,
|
||||||
|
display: 'flex',
|
||||||
|
position: 'absolute',
|
||||||
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Iconify width={20} icon={percent < 0 ? 'eva:trending-down-fill' : 'eva:trending-up-fill'} />
|
||||||
|
<Box component="span" sx={{ typography: 'subtitle2' }}>
|
||||||
|
{percent > 0 && '+'}
|
||||||
|
{fPercent(percent)}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
sx={[
|
||||||
|
() => ({
|
||||||
|
p: 3,
|
||||||
|
boxShadow: 'none',
|
||||||
|
position: 'relative',
|
||||||
|
color: `${color}.darker`,
|
||||||
|
backgroundColor: 'common.white',
|
||||||
|
backgroundImage: `linear-gradient(135deg, ${varAlpha(theme.vars.palette[color].lighterChannel, 0.48)}, ${varAlpha(theme.vars.palette[color].lightChannel, 0.48)})`,
|
||||||
|
}),
|
||||||
|
...(Array.isArray(sx) ? sx : [sx]),
|
||||||
|
]}
|
||||||
|
{...other}
|
||||||
|
>
|
||||||
|
<Box sx={{ width: 48, height: 48, mb: 3 }}>{icon}</Box>
|
||||||
|
|
||||||
|
{renderTrending()}
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
alignItems: 'flex-end',
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{ flexGrow: 1, minWidth: 112 }}>
|
||||||
|
<Box sx={{ mb: 1, typography: 'subtitle2' }}>{title}</Box>
|
||||||
|
|
||||||
|
<Box sx={{ typography: 'h4' }}>{fShortenNumber(total)}</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Chart
|
||||||
|
type="line"
|
||||||
|
series={[{ data: chart.series }]}
|
||||||
|
options={chartOptions}
|
||||||
|
sx={{ width: 84, height: 56 }}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<SvgColor
|
||||||
|
src="/assets/background/shape-square.svg"
|
||||||
|
sx={{
|
||||||
|
top: 0,
|
||||||
|
left: -20,
|
||||||
|
width: 240,
|
||||||
|
zIndex: -1,
|
||||||
|
height: 240,
|
||||||
|
opacity: 0.24,
|
||||||
|
position: 'absolute',
|
||||||
|
color: `${color}.main`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
156
src/client/dd-hub-react/src/sections/charts/view/charts-view.tsx
Normal file
156
src/client/dd-hub-react/src/sections/charts/view/charts-view.tsx
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
import Grid from '@mui/material/Grid';
|
||||||
|
import Typography from '@mui/material/Typography';
|
||||||
|
|
||||||
|
import { DashboardContent } from 'src/layouts/dashboard';
|
||||||
|
import { _posts, _tasks, _traffic, _timeline } from 'src/_mock';
|
||||||
|
|
||||||
|
import { AnalyticsNews } from '../analytics-news';
|
||||||
|
import { AnalyticsTasks } from '../analytics-tasks';
|
||||||
|
import { AnalyticsCurrentVisits } from '../analytics-current-visits';
|
||||||
|
import { AnalyticsOrderTimeline } from '../analytics-order-timeline';
|
||||||
|
import { AnalyticsWebsiteVisits } from '../analytics-website-visits';
|
||||||
|
import { AnalyticsWidgetSummary } from '../analytics-widget-summary';
|
||||||
|
import { AnalyticsTrafficBySite } from '../analytics-traffic-by-site';
|
||||||
|
import { AnalyticsCurrentSubject } from '../analytics-current-subject';
|
||||||
|
import { AnalyticsConversionRates } from '../analytics-conversion-rates';
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
export function ChartsView() {
|
||||||
|
return (
|
||||||
|
<DashboardContent maxWidth="xl">
|
||||||
|
<Typography variant="h4" sx={{ mb: { xs: 3, md: 5 } }}>
|
||||||
|
Hi, Welcome back 👋
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Grid container spacing={3}>
|
||||||
|
<Grid size={{ xs: 12, sm: 6, md: 3 }}>
|
||||||
|
<AnalyticsWidgetSummary
|
||||||
|
title="Weekly sales"
|
||||||
|
percent={2.6}
|
||||||
|
total={714000}
|
||||||
|
icon={<img alt="Weekly sales" src="/assets/icons/glass/ic-glass-bag.svg" />}
|
||||||
|
chart={{
|
||||||
|
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug'],
|
||||||
|
series: [22, 8, 35, 50, 82, 84, 77, 12],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid size={{ xs: 12, sm: 6, md: 3 }}>
|
||||||
|
<AnalyticsWidgetSummary
|
||||||
|
title="New users"
|
||||||
|
percent={-0.1}
|
||||||
|
total={1352831}
|
||||||
|
color="secondary"
|
||||||
|
icon={<img alt="New users" src="/assets/icons/glass/ic-glass-users.svg" />}
|
||||||
|
chart={{
|
||||||
|
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug'],
|
||||||
|
series: [56, 47, 40, 62, 73, 30, 23, 54],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid size={{ xs: 12, sm: 6, md: 3 }}>
|
||||||
|
<AnalyticsWidgetSummary
|
||||||
|
title="Purchase orders"
|
||||||
|
percent={2.8}
|
||||||
|
total={1723315}
|
||||||
|
color="warning"
|
||||||
|
icon={<img alt="Purchase orders" src="/assets/icons/glass/ic-glass-buy.svg" />}
|
||||||
|
chart={{
|
||||||
|
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug'],
|
||||||
|
series: [40, 70, 50, 28, 70, 75, 7, 64],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid size={{ xs: 12, sm: 6, md: 3 }}>
|
||||||
|
<AnalyticsWidgetSummary
|
||||||
|
title="Messages"
|
||||||
|
percent={3.6}
|
||||||
|
total={234}
|
||||||
|
color="error"
|
||||||
|
icon={<img alt="Messages" src="/assets/icons/glass/ic-glass-message.svg" />}
|
||||||
|
chart={{
|
||||||
|
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug'],
|
||||||
|
series: [56, 30, 23, 54, 47, 40, 62, 73],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid size={{ xs: 12, md: 6, lg: 4 }}>
|
||||||
|
<AnalyticsCurrentVisits
|
||||||
|
title="Current visits"
|
||||||
|
chart={{
|
||||||
|
series: [
|
||||||
|
{ label: 'America', value: 3500 },
|
||||||
|
{ label: 'Asia', value: 2500 },
|
||||||
|
{ label: 'Europe', value: 1500 },
|
||||||
|
{ label: 'Africa', value: 500 },
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid size={{ xs: 12, md: 6, lg: 8 }}>
|
||||||
|
<AnalyticsWebsiteVisits
|
||||||
|
title="Website visits"
|
||||||
|
subheader="(+43%) than last year"
|
||||||
|
chart={{
|
||||||
|
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep'],
|
||||||
|
series: [
|
||||||
|
{ name: 'Team A', data: [43, 33, 22, 37, 67, 68, 37, 24, 55] },
|
||||||
|
{ name: 'Team B', data: [51, 70, 47, 67, 40, 37, 24, 70, 24] },
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid size={{ xs: 12, md: 6, lg: 8 }}>
|
||||||
|
<AnalyticsConversionRates
|
||||||
|
title="Conversion rates"
|
||||||
|
subheader="(+43%) than last year"
|
||||||
|
chart={{
|
||||||
|
categories: ['Italy', 'Japan', 'China', 'Canada', 'France'],
|
||||||
|
series: [
|
||||||
|
{ name: '2022', data: [44, 55, 41, 64, 22] },
|
||||||
|
{ name: '2023', data: [53, 32, 33, 52, 13] },
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid size={{ xs: 12, md: 6, lg: 4 }}>
|
||||||
|
<AnalyticsCurrentSubject
|
||||||
|
title="Current subject"
|
||||||
|
chart={{
|
||||||
|
categories: ['English', 'History', 'Physics', 'Geography', 'Chinese', 'Math'],
|
||||||
|
series: [
|
||||||
|
{ name: 'Series 1', data: [80, 50, 30, 40, 100, 20] },
|
||||||
|
{ name: 'Series 2', data: [20, 30, 40, 80, 20, 80] },
|
||||||
|
{ name: 'Series 3', data: [44, 76, 78, 13, 43, 10] },
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid size={{ xs: 12, md: 6, lg: 8 }}>
|
||||||
|
<AnalyticsNews title="News" list={_posts.slice(0, 5)} />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid size={{ xs: 12, md: 6, lg: 4 }}>
|
||||||
|
<AnalyticsOrderTimeline title="Order timeline" list={_timeline} />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid size={{ xs: 12, md: 6, lg: 4 }}>
|
||||||
|
<AnalyticsTrafficBySite title="Traffic by site" list={_traffic} />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid size={{ xs: 12, md: 6, lg: 8 }}>
|
||||||
|
<AnalyticsTasks title="Tasks" list={_tasks} />
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</DashboardContent>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export * from './charts-view';
|
||||||
Loading…
x
Reference in New Issue
Block a user