diff --git a/src/Dashboard.tsx b/src/Dashboard.tsx index ffcf1e9..04a5795 100644 --- a/src/Dashboard.tsx +++ b/src/Dashboard.tsx @@ -10,8 +10,14 @@ import { Button } from "@mui/material"; -import ConfigurableDashboard from "./components/Dashboard"; -import { DashboardState } from "./components/Dashboard"; +import DashboardView from "./components/Dashboard"; + +import { + DashboardState, + DashboardStateSetters, + DashboardFlow, +} from "./components/Dashboard"; + import { configuration } from "./dashboard-config"; import { useReport, @@ -19,7 +25,13 @@ import { } from "./features/report"; export default function Dashboard() { - const [flow, setFlow] = React.useState<"outflows" | "inflows">("outflows"); + const [state, setState] = React.useState({ + flow: "outflows", + periodType: "rolling", + selectedPeriodId: null, + selectedGroupKey: null, + comparison: false, + }); const [appliedPayees, setAppliedPayees] = React.useState([]); const [appliedTags, setAppliedTags] = React.useState([]); @@ -32,7 +44,7 @@ export default function Dashboard() { const report = useReport({ periods: ["daily", "weekly", "monthly", "all"], - flow: flow, + flow: state.flow, payee: appliedPayees.length > 0 ? appliedPayees : undefined, tags: appliedTags.length > 0 ? appliedTags : undefined, }); @@ -69,14 +81,124 @@ export default function Dashboard() { } }, [report.data?.data]); + const toggleFlow = + React.useCallback(() => { + setState((prev) => ({ + ...prev, + + flow: + prev.flow === + "outflows" + ? "inflows" + : "outflows", + + selectedGroupKey: + null, + + selectedPeriodId: + null, + })); + }, []); + + const setFlow = + React.useCallback( + ( + flow: DashboardFlow + ) => { + setState((prev) => ({ + ...prev, + + flow, + + selectedGroupKey: + null, + + selectedPeriodId: + null, + })); + }, + [] + ); + + const togglePeriodType = + React.useCallback(() => { + setState((prev) => ({ + ...prev, + + periodType: + prev.periodType === + "rolling" + ? "calendar" + : "rolling", + })); + }, []); + + const toggleComparison = + React.useCallback(() => { + setState((prev) => ({ + ...prev, + + comparison: + !prev.comparison, + })); + }, []); + + const setSelectedPeriodId = + React.useCallback( + ( + selectedPeriodId: DashboardState["selectedPeriodId"] + ) => { + setState((prev) => ({ + ...prev, + + selectedPeriodId, + })); + }, + [] + ); + + const setSelectedGroupKey = + React.useCallback( + ( + selectedGroupKey: DashboardState["selectedGroupKey"] + ) => { + setState((prev) => ({ + ...prev, + + selectedGroupKey, + })); + }, + [] + ); + + const stateSetters: DashboardStateSetters = + React.useMemo( + () => ({ + toggleFlow, + + setFlow, + + togglePeriodType, + + toggleComparison, + + setSelectedPeriodId, + + setSelectedGroupKey, + }), + [ + toggleFlow, + setFlow, + togglePeriodType, + toggleComparison, + setSelectedPeriodId, + setSelectedGroupKey, + ] + ); + const isLoading = report.isLoading; const error = report.error; - /** Callback for the ConfigurableDashboard's flow toggle */ - const handleFlowChange = React.useCallback((newState: DashboardState) => { - setFlow(newState.flow); - }, []); - if (isLoading && !report.data) { return ( @@ -143,8 +265,8 @@ export default function Dashboard() { sx={{ '& .MuiOutlinedInput-root': { height: 'auto', minHeight: '2.5rem', py: 0.5 } }} /> - - ); diff --git a/src/components/Dashboard/Dashboard.models.ts b/src/components/Dashboard/Dashboard.models.ts index 5ec4cf3..9af36fd 100644 --- a/src/components/Dashboard/Dashboard.models.ts +++ b/src/components/Dashboard/Dashboard.models.ts @@ -50,11 +50,12 @@ export interface DashboardConfig { }; } -export interface DashboardProps { +export interface DashboardViewProps { config: DashboardConfig; data: ReportData; + state: DashboardState; + stateSetters: DashboardStateSetters; isFetching: boolean; - onFlowChange?: (state: DashboardState) => void; } diff --git a/src/components/Dashboard/Dashboard.tsx b/src/components/Dashboard/Dashboard.view.tsx similarity index 60% rename from src/components/Dashboard/Dashboard.tsx rename to src/components/Dashboard/Dashboard.view.tsx index 8ca2035..bcc37cb 100644 --- a/src/components/Dashboard/Dashboard.tsx +++ b/src/components/Dashboard/Dashboard.view.tsx @@ -8,88 +8,22 @@ import { Button } from "@mui/material"; import { useTheme, alpha } from "@mui/material/styles"; -import { DashboardProps, DashboardState, DashboardStateSetters, DashboardFlow } from "./Dashboard.models"; +import { DashboardViewProps } from "./Dashboard.models"; -export default function Dashboard({ +export default function DashboardView({ config, data, + state, + stateSetters, isFetching, - onFlowChange, -}: DashboardProps) { +}: DashboardViewProps) { const theme = useTheme(); const themeMode = theme.palette.mode; - const [state, setState] = React.useState({ - flow: "outflows", - periodType: "rolling", - selectedPeriodId: null, - selectedGroupKey: null, - comparison: false, - }); - - const toggleFlow = () => { - setState(prev => { - const nextFlow: DashboardFlow = prev.flow === "outflows" ? "inflows" : "outflows"; - const nextState: DashboardState = { - ...prev, - flow: nextFlow, - selectedGroupKey: null, - selectedPeriodId: null, - }; - onFlowChange?.(nextState); - return nextState; - }); - }; - - const handleFlowChange = ( - _event: React.MouseEvent, - newFlow: DashboardFlow | null - ) => { - if (newFlow !== null && newFlow !== state.flow) { - setState(prev => { - const nextState: DashboardState = { - ...prev, - flow: newFlow, - selectedGroupKey: null, - selectedPeriodId: null, - }; - onFlowChange?.(nextState); - return nextState; - }); - } - }; - - const togglePeriodType = () => { - setState(prev => ({ - ...prev, - periodType: prev.periodType === "rolling" ? "calendar" : "rolling", - })); - }; - - const toggleComparison = () => { - setState(prev => ({ - ...prev, - comparison: !prev.comparison, - })); - }; - - const setSelectedPeriodId = (selectedPeriodId: typeof state.selectedPeriodId) => { - setState(prev => ({ ...prev, selectedPeriodId })); - }; - - const setSelectedGroupKey = (groupKey: typeof state.selectedGroupKey) => { - setState(prev => ({ ...prev, selectedGroupKey: groupKey })); - }; - - const stateSetters: DashboardStateSetters = { - togglePeriodType, - toggleComparison, - toggleFlow, - setSelectedPeriodId, - setSelectedGroupKey, - }; - - const { flow, selectedGroupKey } = state; + const { + flow, + selectedGroupKey, + } = state; const colors = React.useMemo(() => { const palette = config.style.palette[flow]; @@ -145,7 +79,7 @@ export default function Dashboard({ setSelectedGroupKey(null)} + onClick={() => stateSetters.setSelectedGroupKey(null)} > Clear Drill-down diff --git a/src/components/Dashboard/index.ts b/src/components/Dashboard/index.ts index 2f01984..892b9c4 100644 --- a/src/components/Dashboard/index.ts +++ b/src/components/Dashboard/index.ts @@ -1,2 +1,2 @@ -export { default } from "./Dashboard"; +export { default } from "./Dashboard.view"; export * from "./Dashboard.models";