155 lines
4.9 KiB
TypeScript
155 lines
4.9 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 { DashboardProps, DashboardState } from "./Dashboard.models";
|
|
|
|
interface ViewProps extends DashboardProps {
|
|
state: DashboardState;
|
|
setState: React.Dispatch<React.SetStateAction<DashboardState>>;
|
|
}
|
|
|
|
export default function DashboardView({
|
|
config,
|
|
data,
|
|
latest,
|
|
state,
|
|
setState,
|
|
onModeChange
|
|
}: ViewProps) {
|
|
const theme = useTheme();
|
|
const themeMode = theme.palette.mode;
|
|
const { mode, periodType, comparison } = 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]);
|
|
|
|
const handleModeChange = (_: any, newMode: any) => {
|
|
if (newMode && onModeChange) {
|
|
onModeChange(newMode);
|
|
setState(prev => ({ ...prev, mode: newMode }));
|
|
}
|
|
};
|
|
|
|
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={handleModeChange}
|
|
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>
|
|
)}
|
|
|
|
{section.isList ? (
|
|
<Box>
|
|
{section.title && (
|
|
<Box sx={{ mb: 2 }}>
|
|
<Typography variant="h6" fontWeight={700}>
|
|
{section.title}
|
|
</Typography>
|
|
</Box>
|
|
)}
|
|
<Grid container spacing={2}>
|
|
{(data[section.dataKey || ""] || []).map((item: any, idx: number) => (
|
|
<Grid key={idx} size={{ xs: 12, sm: 6, md: 2.4 }}>
|
|
<Component
|
|
{...section.settings}
|
|
header={item.payeeName || item.name}
|
|
progressAmount={item.amount}
|
|
totalAmount={data.totalAmount}
|
|
colorTheme={mode === "expense" ? "error" : "success"}
|
|
/>
|
|
</Grid>
|
|
))}
|
|
</Grid>
|
|
</Box>
|
|
) : (
|
|
<Component
|
|
{...section.settings}
|
|
header={section.title}
|
|
summary={section.summary}
|
|
data={section.dataKey ? data[section.dataKey] : data.chartData}
|
|
items={section.dataKey === 'latest' ? latest : (data[section.dataKey || ''] || [])}
|
|
title={section.title}
|
|
accentColor={colors.primary}
|
|
colorScheme={colors}
|
|
periodType={periodType}
|
|
onPeriodTypeChange={(p: any) => setState(prev => ({ ...prev, periodType: p }))}
|
|
comparison={comparison}
|
|
setComparison={(c: any) => setState(prev => ({ ...prev, comparison: c }))}
|
|
/>
|
|
)}
|
|
</Grid>
|
|
);
|
|
})}
|
|
</Grid>
|
|
</Container>
|
|
);
|
|
}
|