Dashboard Refactor: Flow-based Metrics + Unified Data Model #4

Merged
aetos merged 11 commits from cached-reports into main 2026-05-18 05:37:52 +00:00
6 changed files with 58 additions and 39 deletions
Showing only changes of commit ccfb597342 - Show all commits

View File

@@ -100,14 +100,6 @@ export default function DashboardView({
return ( return (
<Grid key={section.id} size={section.style?.size || 12 as any}> <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 <Component
{...section.settings} {...section.settings}
header={section.title} header={section.title}

View File

@@ -8,6 +8,7 @@ export interface LatestItem {
export interface LatestItemsViewProps { export interface LatestItemsViewProps {
items: LatestItem[]; items: LatestItem[];
header: string;
accentColor: string; accentColor: string;
canExpand: boolean; canExpand: boolean;
onExpand: () => void; onExpand: () => void;

View File

@@ -6,6 +6,7 @@ import LatestItemsView from "./LatestItems.view";
type Props = { type Props = {
reportData: ReportData; reportData: ReportData;
flow: "outflows" | "inflows"; flow: "outflows" | "inflows";
header: string;
selectedPeriodId: string | null; selectedPeriodId: string | null;
selectedGroupKey?: GroupKey | null; selectedGroupKey?: GroupKey | null;
accentColor: string; accentColor: string;
@@ -15,6 +16,7 @@ type Props = {
export default function LatestItems({ export default function LatestItems({
reportData, reportData,
flow, flow,
header,
selectedPeriodId, selectedPeriodId,
selectedGroupKey = null, selectedGroupKey = null,
accentColor, accentColor,
@@ -35,6 +37,7 @@ export default function LatestItems({
return ( return (
<LatestItemsView <LatestItemsView
items={visibleItems} items={visibleItems}
header={header}
accentColor={accentColor} accentColor={accentColor}
canExpand={canExpand} canExpand={canExpand}
isFetching={isFetching} isFetching={isFetching}

View File

@@ -14,6 +14,7 @@ import { LatestItemsViewProps } from "./LatestItems.models";
export default function LatestItemsView({ export default function LatestItemsView({
items, items,
header,
accentColor, accentColor,
canExpand, canExpand,
onExpand, onExpand,
@@ -23,7 +24,7 @@ export default function LatestItemsView({
<Box sx={{ width: "100%", bgcolor: "background.paper", borderRadius: 4, p: 2, opacity: isFetching ? 0.6 : 1, transition: "opacity 0.3s ease", pointerEvents: isFetching ? "none" : "auto" }}> <Box sx={{ width: "100%", bgcolor: "background.paper", borderRadius: 4, p: 2, opacity: isFetching ? 0.6 : 1, transition: "opacity 0.3s ease", pointerEvents: isFetching ? "none" : "auto" }}>
<Box sx={{ mb: 2, px: 2 }}> <Box sx={{ mb: 2, px: 2 }}>
<Typography variant="h6" fontWeight="bold"> <Typography variant="h6" fontWeight="bold">
Recent Transactions {header}
</Typography> </Typography>
</Box> </Box>

View File

@@ -1,5 +1,5 @@
import * as React from "react"; import * as React from "react";
import { Box } from "@mui/material"; import { Box, Paper, Typography } from "@mui/material";
import { ReportData, GroupKey } from "../../features/report"; import { ReportData, GroupKey } from "../../features/report";
import ProgressCard from "./ProgressCard"; import ProgressCard from "./ProgressCard";
import { extractTopTags } from "./TopTags.adapter"; import { extractTopTags } from "./TopTags.adapter";
@@ -7,6 +7,7 @@ import { extractTopTags } from "./TopTags.adapter";
type Props = { type Props = {
reportData: ReportData; reportData: ReportData;
flow: "outflows" | "inflows"; flow: "outflows" | "inflows";
header: string;
selectedPeriodId?: string | null; selectedPeriodId?: string | null;
selectedGroupKey?: GroupKey | null; selectedGroupKey?: GroupKey | null;
setSelectedGroupKey?: (key: GroupKey | null) => void; setSelectedGroupKey?: (key: GroupKey | null) => void;
@@ -17,6 +18,7 @@ type Props = {
export default function TopTags({ export default function TopTags({
reportData, reportData,
flow, flow,
header,
selectedPeriodId, selectedPeriodId,
selectedGroupKey, selectedGroupKey,
setSelectedGroupKey, setSelectedGroupKey,
@@ -28,37 +30,56 @@ export default function TopTags({
}, [reportData, flow, selectedPeriodId]); }, [reportData, flow, selectedPeriodId]);
return ( return (
<Box <Paper
sx={{ sx={{
display: "grid", p: { xs: 2.5, sm: 4 },
gridTemplateColumns: { borderRadius: 4,
xs: "1fr", width: "100%",
sm: "repeat(2, 1fr)", boxShadow: "none",
md: "repeat(4, 1fr)", border: "1px solid",
}, borderColor: "divider",
gap: 2, bgcolor: "background.paper",
opacity: isFetching ? 0.6 : 1,
transition: "opacity 0.3s ease",
pointerEvents: isFetching ? "none" : "auto",
}} }}
> >
{items.map((item) => { <Typography variant="h6" fontWeight={700} gutterBottom>
const isSelected = selectedGroupKey?.tags?.includes(item.tag); {header}
return ( </Typography>
<ProgressCard
key={item.tag} <Box
header={item.tag} sx={{
progressAmount={item.amount} display: "grid",
totalAmount={total} gridTemplateColumns: {
compact={compact} xs: "1fr",
colorTheme={flow === "outflows" ? "error" : "success"} sm: "repeat(2, 1fr)",
selected={isSelected} md: "repeat(4, 1fr)",
isFetching={isFetching} },
onClick={() => { gap: 2,
if (setSelectedGroupKey) { }}
setSelectedGroupKey(isSelected ? null : { tags: [item.tag] }); >
} {items.map((item) => {
}} const isSelected = selectedGroupKey?.tags?.includes(item.tag);
/> return (
); <ProgressCard
})} key={item.tag}
</Box> header={item.tag}
progressAmount={item.amount}
totalAmount={total}
compact={compact}
colorTheme={flow === "outflows" ? "error" : "success"}
selected={isSelected}
isFetching={isFetching}
onClick={() => {
if (setSelectedGroupKey) {
setSelectedGroupKey(isSelected ? null : { tags: [item.tag] });
}
}}
/>
);
})}
</Box>
</Paper>
); );
} }

View File

@@ -31,6 +31,7 @@ export const configuration: DashboardConfig = {
}, },
{ {
id: "items", id: "items",
title: 'Recent Transactions',
component: LatestItems, component: LatestItems,
style: { style: {
size: 12, size: 12,