diff --git a/frontend/src/component/insights/GraphCover.tsx b/frontend/src/component/insights/GraphCover.tsx new file mode 100644 index 0000000000..915acb7ac9 --- /dev/null +++ b/frontend/src/component/insights/GraphCover.tsx @@ -0,0 +1,32 @@ +import { styled } from '@mui/material'; +import type { FC, PropsWithChildren } from 'react'; + +const StyledCover = styled('div')(({ theme }) => ({ + position: 'absolute', + inset: 0, + display: 'flex', + zIndex: theme.zIndex.appBar, + '&::before': { + zIndex: theme.zIndex.fab, + content: '""', + position: 'absolute', + inset: 0, + backgroundColor: theme.palette.background.paper, + opacity: 0.8, + }, +})); + +const StyledCoverContent = styled('div')(({ theme }) => ({ + zIndex: theme.zIndex.modal, + margin: 'auto', + color: theme.palette.text.secondary, + textAlign: 'center', +})); + +export const GraphCover: FC = ({ children }) => { + return ( + + {children} + + ); +}; diff --git a/frontend/src/component/insights/components/LineChart/LineChartComponent.tsx b/frontend/src/component/insights/components/LineChart/LineChartComponent.tsx index 5c684742bc..f9f71688bc 100644 --- a/frontend/src/component/insights/components/LineChart/LineChartComponent.tsx +++ b/frontend/src/component/insights/components/LineChart/LineChartComponent.tsx @@ -26,33 +26,12 @@ import { styled } from '@mui/material'; import { createOptions } from './createChartOptions.ts'; import merge from 'deepmerge'; import { customHighlightPlugin } from 'component/common/Chart/customHighlightPlugin.ts'; +import { GraphCover } from 'component/insights/GraphCover.tsx'; const StyledContainer = styled('div')(({ theme }) => ({ position: 'relative', })); -const StyledCover = styled('div')(({ theme }) => ({ - position: 'absolute', - inset: 0, - display: 'flex', - zIndex: theme.zIndex.appBar, - '&::before': { - zIndex: theme.zIndex.fab, - content: '""', - position: 'absolute', - inset: 0, - backgroundColor: theme.palette.background.paper, - opacity: 0.8, - }, -})); - -const StyledCoverContent = styled('div')(({ theme }) => ({ - zIndex: theme.zIndex.modal, - margin: 'auto', - color: theme.palette.text.secondary, - textAlign: 'center', -})); - function mergeAll(objects: Partial[]): T { return merge.all(objects.filter((i) => i)); } @@ -113,11 +92,7 @@ const LineChartComponent: FC<{ ) } elseShow={ - - - {cover !== true ? cover : ' '} - - + {cover !== true ? cover : ' '} } /> diff --git a/frontend/src/component/insights/componentsChart/CreationArchiveChart/CreationArchiveChart.tsx b/frontend/src/component/insights/componentsChart/CreationArchiveChart/CreationArchiveChart.tsx index 87652e1433..413e6738b8 100644 --- a/frontend/src/component/insights/componentsChart/CreationArchiveChart/CreationArchiveChart.tsx +++ b/frontend/src/component/insights/componentsChart/CreationArchiveChart/CreationArchiveChart.tsx @@ -4,7 +4,6 @@ import type { InstanceInsightsSchema } from 'openapi'; import { useProjectChartData } from 'component/insights/hooks/useProjectChartData'; import { useTheme } from '@mui/material'; import type { GroupedDataByProject } from 'component/insights/hooks/useGroupedProjectTrends'; -import { usePlaceholderData } from 'component/insights/hooks/usePlaceholderData'; import { CategoryScale, LinearScale, @@ -22,9 +21,12 @@ import type { TooltipState } from 'component/insights/components/LineChart/Chart import type { WeekData, RawWeekData } from './types.ts'; import { createTooltip } from 'component/insights/components/LineChart/createTooltip.ts'; import { CreationArchiveRatioTooltip } from './CreationArchiveRatioTooltip.tsx'; -import { Chart } from 'react-chartjs-2'; import { getDateFnsLocale } from '../../getDateFnsLocale.ts'; import { customHighlightPlugin } from 'component/common/Chart/customHighlightPlugin.ts'; +import { NotEnoughData } from 'component/insights/components/LineChart/LineChart.tsx'; +import { placeholderData } from './placeholderData.ts'; +import { Bar } from 'react-chartjs-2'; +import { GraphCover } from 'component/insights/GraphCover.tsx'; ChartJS.register( CategoryScale, @@ -51,11 +53,10 @@ export const CreationArchiveChart: FC = ({ }) => { const creationVsArchivedChart = useProjectChartData(creationArchiveTrends); const theme = useTheme(); - const placeholderData = usePlaceholderData(); const { locationSettings } = useLocationSettings(); const [tooltip, setTooltip] = useState(null); - const aggregateOrProjectData = useMemo(() => { + const { notEnoughData, aggregateOrProjectData } = useMemo(() => { const labels: string[] = Array.from( new Set( creationVsArchivedChart.datasets.flatMap((d) => @@ -103,46 +104,53 @@ export const CreationArchiveChart: FC = ({ .sort((a, b) => (a.week > b.week ? 1 : -1)); return { - datasets: [ - { - label: 'Flags archived', - data: weeks, - backgroundColor: theme.palette.charts.A2, - borderColor: theme.palette.charts.A2, - hoverBackgroundColor: theme.palette.charts.A2, - hoverBorderColor: theme.palette.charts.A2, - parsing: { yAxisKey: 'archivedFlags', xAxisKey: 'date' }, - order: 1, - }, - { - label: 'Flags created', - data: weeks, - backgroundColor: theme.palette.charts.A1, - borderColor: theme.palette.charts.A1, - hoverBackgroundColor: theme.palette.charts.A1, - hoverBorderColor: theme.palette.charts.A1, - parsing: { - yAxisKey: 'totalCreatedFlags', - xAxisKey: 'date', + notEnoughData: weeks.length < 2, + aggregateOrProjectData: { + datasets: [ + { + label: 'Flags archived', + data: weeks, + backgroundColor: theme.palette.charts.A2, + borderColor: theme.palette.charts.A2, + hoverBackgroundColor: theme.palette.charts.A2, + hoverBorderColor: theme.palette.charts.A2, + parsing: { + yAxisKey: 'archivedFlags', + xAxisKey: 'date', + }, + order: 1, }, - order: 2, - }, - ], + { + label: 'Flags created', + data: weeks, + backgroundColor: theme.palette.charts.A1, + borderColor: theme.palette.charts.A1, + hoverBackgroundColor: theme.palette.charts.A1, + hoverBorderColor: theme.palette.charts.A1, + parsing: { + yAxisKey: 'totalCreatedFlags', + xAxisKey: 'date', + }, + order: 2, + }, + ], + }, }; }, [creationVsArchivedChart, theme]); - const notEnoughData = useMemo( - () => - !isLoading && - !creationVsArchivedChart.datasets.some((d) => d.data.length > 1), - [creationVsArchivedChart, isLoading], - ); - const data = - notEnoughData || isLoading ? placeholderData : aggregateOrProjectData; + const useGraphCover = notEnoughData || isLoading; + const data = useGraphCover ? placeholderData : aggregateOrProjectData; const options = useMemo( () => ({ responsive: true, + ...(useGraphCover + ? { + animation: { + duration: 0, + }, + } + : {}), interaction: { mode: 'index' as const, intersect: false, @@ -157,6 +165,7 @@ export const CreationArchiveChart: FC = ({ padding: 21, boxHeight: 8, }, + display: !useGraphCover, }, tooltip: { enabled: false, @@ -181,7 +190,10 @@ export const CreationArchiveChart: FC = ({ grid: { display: false, }, - ticks: { source: 'data' }, + ticks: { + source: 'data' as const, + display: !useGraphCover, + }, }, y: { type: 'linear' as const, @@ -193,17 +205,17 @@ export const CreationArchiveChart: FC = ({ }, ticks: { stepSize: 1, + display: !useGraphCover, }, }, }, }), - [theme, locationSettings, setTooltip], + [theme, locationSettings, setTooltip, useGraphCover], ); return ( <> - = ({ ]} /> + {useGraphCover ? ( + + {notEnoughData ? : isLoading} + + ) : null} ); }; diff --git a/frontend/src/component/insights/componentsChart/CreationArchiveChart/placeholderData.ts b/frontend/src/component/insights/componentsChart/CreationArchiveChart/placeholderData.ts new file mode 100644 index 0000000000..171f7ce2fe --- /dev/null +++ b/frontend/src/component/insights/componentsChart/CreationArchiveChart/placeholderData.ts @@ -0,0 +1,63 @@ +import type { ChartData } from 'chart.js'; +import type { WeekData } from './types.ts'; + +const data = [ + { + archivedFlags: 3, + totalCreatedFlags: 4, + archivePercentage: 75, + week: '2025-30', + date: '2025-07-27T01:00:00.000Z', + }, + { + archivedFlags: 7, + totalCreatedFlags: 3, + archivePercentage: 140, + week: '2025-31', + date: '2025-08-03T01:00:00.000Z', + }, + { + archivedFlags: 2, + totalCreatedFlags: 3, + archivePercentage: 50, + week: '2025-32', + date: '2025-08-10T01:00:00.000Z', + }, + { + archivedFlags: 2, + totalCreatedFlags: 6, + archivePercentage: 25, + week: '2025-33', + date: '2025-08-17T00:40:40.606Z', + }, + { + archivedFlags: 4, + totalCreatedFlags: 9, + archivePercentage: 66.66666666666666, + week: '2025-34', + date: '2025-08-24T00:29:19.583Z', + }, +]; + +export const placeholderData: ChartData = { + datasets: [ + { + label: 'Flags archived', + data, + parsing: { + yAxisKey: 'archivedFlags', + xAxisKey: 'date', + }, + order: 1, + }, + { + label: 'Flags created', + data, + parsing: { + yAxisKey: 'totalCreatedFlags', + xAxisKey: 'date', + }, + order: 2, + }, + ], +};