Reviewed-on: #2 Co-authored-by: Vishesh 'ironeagle' Bangotra <aetoskia@gmail.com> Co-committed-by: Vishesh 'ironeagle' Bangotra <aetoskia@gmail.com>
140 lines
4.1 KiB
TypeScript
140 lines
4.1 KiB
TypeScript
import * as React from "react";
|
|
import {
|
|
Box,
|
|
Container,
|
|
Grid,
|
|
Typography,
|
|
ToggleButton,
|
|
ToggleButtonGroup
|
|
} from "@mui/material";
|
|
import { useTheme, alpha } from "@mui/material/styles";
|
|
import { GroupKey } from "../../features/report";
|
|
import { DashboardProps, DashboardState } from "./Dashboard.models";
|
|
|
|
interface ViewProps extends DashboardProps {
|
|
state: DashboardState;
|
|
setState: React.Dispatch<React.SetStateAction<DashboardState>>;
|
|
toggleMode: () => void;
|
|
togglePeriodType: () => void;
|
|
setSelectedPeriodId: (id: string | null) => void;
|
|
setSelectedGroupKey: (groupKey: GroupKey | null) => void;
|
|
toggleComparison: () => void;
|
|
}
|
|
|
|
export default function DashboardView({
|
|
config,
|
|
data,
|
|
state,
|
|
setState,
|
|
toggleMode,
|
|
togglePeriodType,
|
|
toggleComparison,
|
|
setSelectedPeriodId,
|
|
setSelectedGroupKey,
|
|
}: ViewProps) {
|
|
const theme = useTheme();
|
|
const themeMode = theme.palette.mode;
|
|
const { mode, periodType, comparison, selectedPeriodId, selectedGroupKey } = state;
|
|
|
|
// Resolve colors with fallbacks
|
|
const colors = React.useMemo(() => {
|
|
const palette = config.style?.palette?.[mode];
|
|
const modeColors = palette ? palette[themeMode] : null;
|
|
|
|
if (modeColors) {
|
|
return {
|
|
primary: modeColors.primary,
|
|
light: modeColors.background || alpha(modeColors.primary, 0.1),
|
|
text: modeColors.text || (themeMode === 'light' ? theme.palette.text.primary : '#fff')
|
|
};
|
|
}
|
|
|
|
// Fallback to standard theme colors
|
|
const themeColor = mode === 'expense' ? theme.palette.error : theme.palette.success;
|
|
return {
|
|
primary: themeColor.main,
|
|
light: alpha(themeColor.main, themeMode === 'light' ? 0.08 : 0.15),
|
|
text: themeColor.main
|
|
};
|
|
}, [config.style?.palette, mode, themeMode, theme.palette]);
|
|
|
|
return (
|
|
<Container
|
|
sx={{
|
|
mt: 4,
|
|
mb: 4,
|
|
background: `linear-gradient(180deg, ${colors.light} 0%, transparent 100%)`,
|
|
borderRadius: 4,
|
|
p: 2,
|
|
transition: 'background 0.3s ease'
|
|
}}
|
|
>
|
|
<Box sx={{ display: "flex", justifyContent: "center", mb: 3 }}>
|
|
<ToggleButtonGroup
|
|
value={mode}
|
|
exclusive
|
|
onChange={toggleMode}
|
|
sx={{
|
|
borderRadius: 3,
|
|
overflow: "hidden",
|
|
"& .MuiToggleButton-root": {
|
|
px: 3,
|
|
textTransform: "none",
|
|
color: "text.secondary"
|
|
},
|
|
"&.Mui-selected": {
|
|
bgcolor: colors.primary,
|
|
color: "white",
|
|
borderColor: colors.primary
|
|
},
|
|
}}
|
|
>
|
|
<ToggleButton value="expense">Expenses</ToggleButton>
|
|
<ToggleButton value="income">Income</ToggleButton>
|
|
</ToggleButtonGroup>
|
|
</Box>
|
|
|
|
<Grid container spacing={4}>
|
|
{config.sections.map((section) => {
|
|
const Component = section.component;
|
|
|
|
return (
|
|
<Grid key={section.id} size={section.style?.size || 12 as any}>
|
|
{section.title && !section.isList && (
|
|
<Box sx={{ mb: 2 }}>
|
|
<Typography variant="h6" fontWeight={700}>
|
|
{section.title}
|
|
</Typography>
|
|
</Box>
|
|
)}
|
|
|
|
<Component
|
|
{...section.settings}
|
|
header={section.title}
|
|
summary={section.summary}
|
|
reportData={data}
|
|
title={section.title}
|
|
accentColor={colors.primary}
|
|
colorScheme={colors}
|
|
|
|
// State management
|
|
mode={mode}
|
|
|
|
periodType={periodType}
|
|
comparison={comparison}
|
|
selectedPeriodId={selectedPeriodId}
|
|
selectedGroupKey={selectedGroupKey}
|
|
|
|
togglePeriodType={togglePeriodType}
|
|
toggleComparison={toggleComparison}
|
|
setSelectedPeriodId={setSelectedPeriodId}
|
|
setSelectedGroupKey={setSelectedGroupKey}
|
|
/>
|
|
</Grid>
|
|
);
|
|
})}
|
|
</Grid>
|
|
</Container>
|
|
);
|
|
}
|