major refactor of the dashboard and react-openapi integration #1
@@ -12,6 +12,7 @@ import { useDashboardData } from "./features/dashboard";
|
|||||||
|
|
||||||
export default function Dashboard() {
|
export default function Dashboard() {
|
||||||
const [mode, setMode] = React.useState<"expense" | "income">("expense");
|
const [mode, setMode] = React.useState<"expense" | "income">("expense");
|
||||||
|
const [selectedPeriodId, setSelectedPeriodId] = React.useState<string | null>(null);
|
||||||
const { data, latest, isLoading, error } = useDashboardData(mode);
|
const { data, latest, isLoading, error } = useDashboardData(mode);
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
@@ -40,6 +41,8 @@ export default function Dashboard() {
|
|||||||
data={data}
|
data={data}
|
||||||
latest={latest}
|
latest={latest}
|
||||||
onModeChange={(newMode) => setMode(newMode)}
|
onModeChange={(newMode) => setMode(newMode)}
|
||||||
|
selectedPeriodId={selectedPeriodId}
|
||||||
|
onSelectPeriodId={(newPeriodId) => setSelectedPeriodId(newPeriodId)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,4 +46,6 @@ export interface DashboardProps {
|
|||||||
data: any; // Aggregated data from features
|
data: any; // Aggregated data from features
|
||||||
latest: any[]; // Latest items from features
|
latest: any[]; // Latest items from features
|
||||||
onModeChange?: (mode: DashboardMode) => void;
|
onModeChange?: (mode: DashboardMode) => void;
|
||||||
|
selectedPeriodId: string | null;
|
||||||
|
onSelectPeriodId: (id: string | null) => void;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,9 @@ export default function DashboardView({
|
|||||||
latest,
|
latest,
|
||||||
state,
|
state,
|
||||||
setState,
|
setState,
|
||||||
onModeChange
|
onModeChange,
|
||||||
|
selectedPeriodId,
|
||||||
|
onSelectPeriodId,
|
||||||
}: ViewProps) {
|
}: ViewProps) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const themeMode = theme.palette.mode;
|
const themeMode = theme.palette.mode;
|
||||||
@@ -143,6 +145,8 @@ export default function DashboardView({
|
|||||||
onPeriodTypeChange={(p: any) => setState(prev => ({ ...prev, periodType: p }))}
|
onPeriodTypeChange={(p: any) => setState(prev => ({ ...prev, periodType: p }))}
|
||||||
comparison={comparison}
|
comparison={comparison}
|
||||||
setComparison={(c: any) => setState(prev => ({ ...prev, comparison: c }))}
|
setComparison={(c: any) => setState(prev => ({ ...prev, comparison: c }))}
|
||||||
|
selectedPeriodId={selectedPeriodId}
|
||||||
|
onSelectPeriodId={onSelectPeriodId}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ interface ViewProps extends HistoryChartProps {
|
|||||||
startIndex: number;
|
startIndex: number;
|
||||||
setStartIndex: React.Dispatch<React.SetStateAction<number>>;
|
setStartIndex: React.Dispatch<React.SetStateAction<number>>;
|
||||||
activeDataKey: string;
|
activeDataKey: string;
|
||||||
|
selectedPeriodId: string | null;
|
||||||
|
onSelectPeriodId: (id: string | null) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function HistoryChartView(props: ViewProps) {
|
export default function HistoryChartView(props: ViewProps) {
|
||||||
@@ -47,6 +49,8 @@ export default function HistoryChartView(props: ViewProps) {
|
|||||||
startIndex,
|
startIndex,
|
||||||
setStartIndex,
|
setStartIndex,
|
||||||
activeDataKey,
|
activeDataKey,
|
||||||
|
selectedPeriodId,
|
||||||
|
onSelectPeriodId,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
@@ -159,9 +163,23 @@ export default function HistoryChartView(props: ViewProps) {
|
|||||||
? ((point.compare?.amount ?? 0) / maxAmount) * 100
|
? ((point.compare?.amount ?? 0) / maxAmount) * 100
|
||||||
: 0;
|
: 0;
|
||||||
const labelHeight = Math.max(currentHeight, compareHeight);
|
const labelHeight = Math.max(currentHeight, compareHeight);
|
||||||
|
const isSelected = selectedPeriodId === point.id;
|
||||||
|
const display = formatDisplay(point, activeTab.toLowerCase(), comparison);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box key={point.id} sx={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "flex-end", height: "100%" }}>
|
<Box
|
||||||
|
key={point.id}
|
||||||
|
onClick={() => onSelectPeriodId(isSelected ? null : point.id)}
|
||||||
|
sx={{
|
||||||
|
flex: 1,
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "flex-end",
|
||||||
|
height: "100%",
|
||||||
|
cursor: "pointer"
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Box sx={{ display: "flex", alignItems: "flex-end", gap: comparison ? 1 : 0.5, height: "100%", position: "relative" }}>
|
<Box sx={{ display: "flex", alignItems: "flex-end", gap: comparison ? 1 : 0.5, height: "100%", position: "relative" }}>
|
||||||
<Typography
|
<Typography
|
||||||
variant="caption"
|
variant="caption"
|
||||||
@@ -177,7 +195,7 @@ export default function HistoryChartView(props: ViewProps) {
|
|||||||
fontWeight: 600
|
fontWeight: 600
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{formatDisplay(point, activeTab.toLowerCase(), comparison)}
|
{isSelected ? `SELECTED: ${display}` : display}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
{comparison && (
|
{comparison && (
|
||||||
|
|||||||
Reference in New Issue
Block a user