From a36d9119bb7f853a5e583b070a5d9703a443a405 Mon Sep 17 00:00:00 2001 From: Vishesh 'ironeagle' Bangotra Date: Sat, 25 Apr 2026 13:21:34 +0530 Subject: [PATCH] configurable Dashboard.tsx --- src/Dashboard.tsx | 120 ++--------------- src/components/Dashboard/Dashboard.models.ts | 43 +++++++ src/components/Dashboard/Dashboard.tsx | 19 +++ src/components/Dashboard/Dashboard.view.tsx | 129 +++++++++++++++++++ src/components/Dashboard/index.ts | 2 + src/dashboard-config.ts | 60 +++++++++ 6 files changed, 262 insertions(+), 111 deletions(-) create mode 100644 src/components/Dashboard/Dashboard.models.ts create mode 100644 src/components/Dashboard/Dashboard.tsx create mode 100644 src/components/Dashboard/Dashboard.view.tsx create mode 100644 src/components/Dashboard/index.ts create mode 100644 src/dashboard-config.ts diff --git a/src/Dashboard.tsx b/src/Dashboard.tsx index 0397633..44e8a87 100644 --- a/src/Dashboard.tsx +++ b/src/Dashboard.tsx @@ -2,44 +2,18 @@ import * as React from "react"; import { Box, Container, - Grid, CircularProgress, - Alert, - ToggleButton, - ToggleButtonGroup, - Typography + Alert } from "@mui/material"; -import LatestItems from "./components/LatestItems"; -import HistoryChart from "./components/HistoryChart"; -import ProgressCard from "./components/ProgressCard"; - +import DashboardComponent from "./components/Dashboard"; +import { configuration } from "./dashboard-config"; import { useDashboardData } from "./features/dashboard"; export default function Dashboard() { const [mode, setMode] = React.useState<"expense" | "income">("expense"); - const [period, setPeriod] = React.useState<"rolling" | "calendar">("rolling"); - const [comparison, setComparison] = React.useState(false); - - const palette = { - expense: { - primary: "#d32f2f", - light: "#fdecea", - dark: "#9a0007", - text: "#b71c1c" - }, - income: { - primary: "#2e7d32", - light: "#e8f5e9", - dark: "#1b5e20", - text: "#1b5e20" - } - }; - const { data, latest, isLoading, error } = useDashboardData(mode); - const colors = palette[mode]; - if (isLoading) { return ( @@ -61,87 +35,11 @@ export default function Dashboard() { } return ( - - - val && setMode(val)} - sx={{ - borderRadius: 3, - overflow: "hidden", - "& .MuiToggleButton-root": { - px: 3, - textTransform: "none", - color: "text.secondary" - }, - "&.Mui-selected": { - bgcolor: colors.primary, - color: "white", - borderColor: colors.primary - }, - }} - > - Expenses - Income - - - - - - - - - {data.topPayees && data.topPayees.length > 0 && ( - - - - Top {mode === "expense" ? "Payees" : "Payors"} - - - - {data.topPayees.map((payee: any) => ( - - - - ))} - - - )} - - - {}} - accentColor={colors.primary} - /> - - - + setMode(newMode)} + /> ); } diff --git a/src/components/Dashboard/Dashboard.models.ts b/src/components/Dashboard/Dashboard.models.ts new file mode 100644 index 0000000..6cbaa6c --- /dev/null +++ b/src/components/Dashboard/Dashboard.models.ts @@ -0,0 +1,43 @@ +import * as React from "react"; + +export type DashboardMode = "expense" | "income"; +export type DashboardPeriod = "rolling" | "calendar"; + +export interface DashboardState { + mode: DashboardMode; + period: DashboardPeriod; + comparison: boolean; +} + +export interface DashboardSection { + id: string; + title?: string; + summary?: string; + component: React.ComponentType; + dataKey?: string; + settings?: Record; + isList?: boolean; + style?: { + size?: number; + [key: string]: any; + }; +} + +export interface DashboardConfig { + sections: DashboardSection[]; + style?: { + palette: Record; + }; +} + +export interface DashboardProps { + config: DashboardConfig; + data: any; // Aggregated data from features + latest: any[]; // Latest items from features + onModeChange?: (mode: DashboardMode) => void; +} diff --git a/src/components/Dashboard/Dashboard.tsx b/src/components/Dashboard/Dashboard.tsx new file mode 100644 index 0000000..e68ba4b --- /dev/null +++ b/src/components/Dashboard/Dashboard.tsx @@ -0,0 +1,19 @@ +import * as React from "react"; +import DashboardView from "./Dashboard.view"; +import { DashboardProps, DashboardState } from "./Dashboard.models"; + +export default function Dashboard(props: DashboardProps) { + const [state, setState] = React.useState({ + mode: "expense", + period: "rolling", + comparison: false, + }); + + return ( + + ); +} diff --git a/src/components/Dashboard/Dashboard.view.tsx b/src/components/Dashboard/Dashboard.view.tsx new file mode 100644 index 0000000..ca95e08 --- /dev/null +++ b/src/components/Dashboard/Dashboard.view.tsx @@ -0,0 +1,129 @@ +import * as React from "react"; +import { + Box, + Container, + Grid, + Typography, + ToggleButton, + ToggleButtonGroup +} from "@mui/material"; +import { DashboardProps, DashboardState } from "./Dashboard.models"; + +interface ViewProps extends DashboardProps { + state: DashboardState; + setState: React.Dispatch>; +} + +export default function DashboardView({ + config, + data, + latest, + state, + setState, + onModeChange +}: ViewProps) { + const { mode, period, comparison } = state; + const colors = config.style?.palette[mode] || { primary: '#000', light: '#fff' }; + + const handleModeChange = (_: any, newMode: any) => { + if (newMode && onModeChange) { + onModeChange(newMode); + setState(prev => ({ ...prev, mode: newMode })); + } + }; + + return ( + + + + Expenses + Income + + + + + {config.sections.map((section) => { + const Component = section.component; + + return ( + + {section.title && !section.isList && ( + + + {section.title} + + + )} + + {section.isList ? ( + + {section.title && ( + + + {section.title} + + + )} + + {(data[section.dataKey || ""] || []).map((item: any, idx: number) => ( + + + + ))} + + + ) : ( + setState(prev => ({ ...prev, period: p }))} + comparison={comparison} + setComparison={(c: any) => setState(prev => ({ ...prev, comparison: c }))} + /> + )} + + ); + })} + + + ); +} diff --git a/src/components/Dashboard/index.ts b/src/components/Dashboard/index.ts new file mode 100644 index 0000000..2f01984 --- /dev/null +++ b/src/components/Dashboard/index.ts @@ -0,0 +1,2 @@ +export { default } from "./Dashboard"; +export * from "./Dashboard.models"; diff --git a/src/dashboard-config.ts b/src/dashboard-config.ts new file mode 100644 index 0000000..2799ee4 --- /dev/null +++ b/src/dashboard-config.ts @@ -0,0 +1,60 @@ +import HistoryChart from "./components/HistoryChart"; +import ProgressCard from "./components/ProgressCard"; +import LatestItems from "./components/LatestItems"; +import { DashboardConfig } from "./components/Dashboard"; + +export const configuration: DashboardConfig = { + sections: [ + { + id: "breakdown", + title: "Breakdown", + summary: "Interactive chronological tracking", + component: HistoryChart, + dataKey: "chartData", + settings: { + tabs: ["Daily", "Weekly", "Monthly"], + }, + style: { + size: 12, + }, + }, + { + id: "top-payees", + title: 'Top Payees', + component: ProgressCard, + dataKey: "topPayees", + isList: true, + settings: { + compact: true, + }, + style: { + size: 12, + }, + }, + { + id: "latest", + title: 'Recent Transactions', + component: LatestItems, + dataKey: "latest", + style: { + size: 12, + }, + }, + ], + style: { + palette: { + expense: { + primary: "#d32f2f", + light: "#fdecea", + dark: "#9a0007", + text: "#b71c1c" + }, + income: { + primary: "#2e7d32", + light: "#e8f5e9", + dark: "#1b5e20", + text: "#1b5e20" + } + } + } +};