feat(overview): add file statistics fetching and display in analytics view
This commit is contained in:
@@ -22,6 +22,8 @@ type Props = CardProps & {
|
||||
percent: number;
|
||||
color?: PaletteColorKey;
|
||||
icon: React.ReactNode;
|
||||
details?: { label: string; value: number }[];
|
||||
loading?: boolean;
|
||||
chart: {
|
||||
series: number[];
|
||||
categories: string[];
|
||||
@@ -37,6 +39,8 @@ export function AnalyticsWidgetSummary({
|
||||
chart,
|
||||
percent,
|
||||
color = 'primary',
|
||||
details,
|
||||
loading = false,
|
||||
...other
|
||||
}: Props) {
|
||||
const theme = useTheme();
|
||||
@@ -114,6 +118,23 @@ export function AnalyticsWidgetSummary({
|
||||
<Box sx={{ mb: 1, typography: 'subtitle2' }}>{title}</Box>
|
||||
|
||||
<Box sx={{ typography: 'h4' }}>{fShortenNumber(total)}</Box>
|
||||
|
||||
{details?.length ? (
|
||||
<Box component="ul" sx={{ mt: 1.5, mb: 0, pl: 0, listStyle: 'none', gap: 0.5, display: 'grid' }}>
|
||||
{details.map((item) => (
|
||||
<Box
|
||||
component="li"
|
||||
key={item.label}
|
||||
sx={{ display: 'flex', justifyContent: 'space-between', typography: 'caption', color: 'text.secondary' }}
|
||||
>
|
||||
<Box component="span">{item.label}</Box>
|
||||
<Box component="span" sx={{ color: 'text.primary', fontWeight: 'fontWeightSemiBold' }}>
|
||||
{loading ? '…' : fShortenNumber(item.value)}
|
||||
</Box>
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
) : null}
|
||||
</Box>
|
||||
|
||||
<Chart
|
||||
|
||||
@@ -22,6 +22,8 @@ type Props = CardProps & {
|
||||
percent: number;
|
||||
color?: PaletteColorKey;
|
||||
icon: React.ReactNode;
|
||||
details?: { label: string; value: number }[];
|
||||
loading?: boolean;
|
||||
chart: {
|
||||
series: number[];
|
||||
categories: string[];
|
||||
@@ -37,6 +39,8 @@ export function AnalyticsWidgetSummary({
|
||||
chart,
|
||||
percent,
|
||||
color = 'primary',
|
||||
details,
|
||||
loading = false,
|
||||
...other
|
||||
}: Props) {
|
||||
const theme = useTheme();
|
||||
@@ -114,6 +118,23 @@ export function AnalyticsWidgetSummary({
|
||||
<Box sx={{ mb: 1, typography: 'subtitle2' }}>{title}</Box>
|
||||
|
||||
<Box sx={{ typography: 'h4' }}>{fShortenNumber(total)}</Box>
|
||||
|
||||
{details?.length ? (
|
||||
<Box component="ul" sx={{ mt: 1.5, mb: 0, pl: 0, listStyle: 'none', gap: 0.5, display: 'grid' }}>
|
||||
{details.map((item) => (
|
||||
<Box
|
||||
component="li"
|
||||
key={item.label}
|
||||
sx={{ display: 'flex', justifyContent: 'space-between', typography: 'caption', color: 'text.secondary' }}
|
||||
>
|
||||
<Box component="span">{item.label}</Box>
|
||||
<Box component="span" sx={{ color: 'text.primary', fontWeight: 'fontWeightSemiBold' }}>
|
||||
{loading ? '…' : fShortenNumber(item.value)}
|
||||
</Box>
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
) : null}
|
||||
</Box>
|
||||
|
||||
<Chart
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { useMemo, useState, useEffect } from 'react';
|
||||
|
||||
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 { fetchFileStatsToday } from 'src/services/file-stats-service';
|
||||
|
||||
import { AnalyticsNews } from '../analytics-news';
|
||||
import { AnalyticsTasks } from '../analytics-tasks';
|
||||
@@ -17,6 +20,53 @@ import { AnalyticsConversionRates } from '../analytics-conversion-rates';
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export function OverviewAnalyticsView() {
|
||||
const [fileStats, setFileStats] = useState({ filed: 0, edited: 0 });
|
||||
const [loadingFiles, setLoadingFiles] = useState(true);
|
||||
const visitCategories = useMemo(() => {
|
||||
const days = ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'];
|
||||
const today = new Date();
|
||||
|
||||
const labels = Array.from({ length: 7 }, (_, idx) => {
|
||||
const d = new Date(today);
|
||||
d.setDate(today.getDate() - (6 - idx));
|
||||
const dayIdx = d.getDay();
|
||||
return days[dayIdx];
|
||||
});
|
||||
|
||||
labels[labels.length - 1] = 'Heute';
|
||||
return labels;
|
||||
}, []);
|
||||
|
||||
const baselineFiled = [43, 33, 22, 37, 67, 68];
|
||||
const baselineEdited = [51, 70, 47, 67, 40, 37];
|
||||
|
||||
const visitSeries = [
|
||||
{
|
||||
name: 'Dateien abgelegt',
|
||||
data: [...baselineFiled, fileStats.filed],
|
||||
},
|
||||
{
|
||||
name: 'Dateien bearbeitet',
|
||||
data: [...baselineEdited, fileStats.edited],
|
||||
},
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
let active = true;
|
||||
|
||||
fetchFileStatsToday()
|
||||
.then((data) => {
|
||||
if (active) setFileStats(data);
|
||||
})
|
||||
.finally(() => {
|
||||
if (active) setLoadingFiles(false);
|
||||
});
|
||||
|
||||
return () => {
|
||||
active = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<DashboardContent maxWidth="xl">
|
||||
<Typography variant="h4" sx={{ mb: { xs: 3, md: 5 } }}>
|
||||
@@ -26,13 +76,19 @@ export function OverviewAnalyticsView() {
|
||||
<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" />}
|
||||
title="Dateien - Heute"
|
||||
percent={0}
|
||||
total={fileStats.filed + fileStats.edited}
|
||||
icon={<img alt="Dateien" src="/assets/icons/glass/ic-glass-bag.svg" />}
|
||||
details={[
|
||||
{ label: 'Dateien abgelegt', value: fileStats.filed },
|
||||
{ label: 'Dateien bearbeitet', value: fileStats.edited },
|
||||
]}
|
||||
loading={loadingFiles}
|
||||
chart={{
|
||||
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug'],
|
||||
series: [22, 8, 35, 50, 82, 84, 77, 12],
|
||||
categories: ['Heute'],
|
||||
series: [fileStats.filed, fileStats.edited],
|
||||
options: { stroke: { width: 2 } },
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
@@ -95,14 +151,14 @@ export function OverviewAnalyticsView() {
|
||||
|
||||
<Grid size={{ xs: 12, md: 6, lg: 8 }}>
|
||||
<AnalyticsWebsiteVisits
|
||||
title="Website visits"
|
||||
subheader="(+43%) than last year"
|
||||
title="Dateien verarbeitet"
|
||||
subheader="(+43%) als letzte Woche"
|
||||
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] },
|
||||
],
|
||||
categories: visitCategories,
|
||||
series: visitSeries,
|
||||
options: {
|
||||
tooltip: { y: { formatter: (value: number) => `${value} Dateien` } },
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
19
src/client/dd-hub-react/src/services/file-stats-service.ts
Normal file
19
src/client/dd-hub-react/src/services/file-stats-service.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
export type FileStatsToday = {
|
||||
filed: number;
|
||||
edited: number;
|
||||
};
|
||||
|
||||
export async function fetchFilesAbgelegtToday(): Promise<number> {
|
||||
// Mock placeholder: returns number of files placed today
|
||||
return Promise.resolve(5);
|
||||
}
|
||||
|
||||
export async function fetchFilesBearbeitetToday(): Promise<number> {
|
||||
// Mock placeholder: returns number of files edited today
|
||||
return Promise.resolve(20);
|
||||
}
|
||||
|
||||
export async function fetchFileStatsToday(): Promise<FileStatsToday> {
|
||||
const [filed, edited] = await Promise.all([fetchFilesAbgelegtToday(), fetchFilesBearbeitetToday()]);
|
||||
return { filed, edited };
|
||||
}
|
||||
Reference in New Issue
Block a user