Theme System Refactor #6
@@ -10,8 +10,14 @@ import {
|
|||||||
Button
|
Button
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
|
|
||||||
import ConfigurableDashboard from "./components/Dashboard";
|
import DashboardView from "./components/Dashboard";
|
||||||
import { DashboardState } from "./components/Dashboard";
|
|
||||||
|
import {
|
||||||
|
DashboardState,
|
||||||
|
DashboardStateSetters,
|
||||||
|
DashboardFlow,
|
||||||
|
} from "./components/Dashboard";
|
||||||
|
|
||||||
import { configuration } from "./dashboard-config";
|
import { configuration } from "./dashboard-config";
|
||||||
import {
|
import {
|
||||||
useReport,
|
useReport,
|
||||||
@@ -19,7 +25,13 @@ import {
|
|||||||
} from "./features/report";
|
} from "./features/report";
|
||||||
|
|
||||||
export default function Dashboard() {
|
export default function Dashboard() {
|
||||||
const [flow, setFlow] = React.useState<"outflows" | "inflows">("outflows");
|
const [state, setState] = React.useState<DashboardState>({
|
||||||
|
flow: "outflows",
|
||||||
|
periodType: "rolling",
|
||||||
|
selectedPeriodId: null,
|
||||||
|
selectedGroupKey: null,
|
||||||
|
comparison: false,
|
||||||
|
});
|
||||||
|
|
||||||
const [appliedPayees, setAppliedPayees] = React.useState<string[]>([]);
|
const [appliedPayees, setAppliedPayees] = React.useState<string[]>([]);
|
||||||
const [appliedTags, setAppliedTags] = React.useState<string[]>([]);
|
const [appliedTags, setAppliedTags] = React.useState<string[]>([]);
|
||||||
@@ -32,7 +44,7 @@ export default function Dashboard() {
|
|||||||
|
|
||||||
const report = useReport({
|
const report = useReport({
|
||||||
periods: ["daily", "weekly", "monthly", "all"],
|
periods: ["daily", "weekly", "monthly", "all"],
|
||||||
flow: flow,
|
flow: state.flow,
|
||||||
payee: appliedPayees.length > 0 ? appliedPayees : undefined,
|
payee: appliedPayees.length > 0 ? appliedPayees : undefined,
|
||||||
tags: appliedTags.length > 0 ? appliedTags : undefined,
|
tags: appliedTags.length > 0 ? appliedTags : undefined,
|
||||||
});
|
});
|
||||||
@@ -69,14 +81,124 @@ export default function Dashboard() {
|
|||||||
}
|
}
|
||||||
}, [report.data?.data]);
|
}, [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 isLoading = report.isLoading;
|
||||||
const error = report.error;
|
const error = report.error;
|
||||||
|
|
||||||
/** Callback for the ConfigurableDashboard's flow toggle */
|
|
||||||
const handleFlowChange = React.useCallback((newState: DashboardState) => {
|
|
||||||
setFlow(newState.flow);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
if (isLoading && !report.data) {
|
if (isLoading && !report.data) {
|
||||||
return (
|
return (
|
||||||
<Box sx={{ display: "flex", justifyContent: "center", alignItems: "center", height: "60vh" }}>
|
<Box sx={{ display: "flex", justifyContent: "center", alignItems: "center", height: "60vh" }}>
|
||||||
@@ -157,11 +279,12 @@ export default function Dashboard() {
|
|||||||
</Button>
|
</Button>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Container>
|
</Container>
|
||||||
<ConfigurableDashboard
|
<DashboardView
|
||||||
config={configuration}
|
config={configuration}
|
||||||
data={data}
|
data={data}
|
||||||
|
state={state}
|
||||||
|
stateSetters={stateSetters}
|
||||||
isFetching={report.isFetching}
|
isFetching={report.isFetching}
|
||||||
onFlowChange={handleFlowChange}
|
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -50,11 +50,12 @@ export interface DashboardConfig {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DashboardProps {
|
export interface DashboardViewProps {
|
||||||
config: DashboardConfig;
|
config: DashboardConfig;
|
||||||
data: ReportData;
|
data: ReportData;
|
||||||
|
state: DashboardState;
|
||||||
|
stateSetters: DashboardStateSetters;
|
||||||
isFetching: boolean;
|
isFetching: boolean;
|
||||||
onFlowChange?: (state: DashboardState) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,88 +8,22 @@ import {
|
|||||||
Button
|
Button
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { useTheme, alpha } from "@mui/material/styles";
|
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,
|
config,
|
||||||
data,
|
data,
|
||||||
|
state,
|
||||||
|
stateSetters,
|
||||||
isFetching,
|
isFetching,
|
||||||
onFlowChange,
|
}: DashboardViewProps) {
|
||||||
}: DashboardProps) {
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const themeMode = theme.palette.mode;
|
const themeMode = theme.palette.mode;
|
||||||
|
|
||||||
const [state, setState] = React.useState<DashboardState>({
|
const {
|
||||||
flow: "outflows",
|
flow,
|
||||||
periodType: "rolling",
|
selectedGroupKey,
|
||||||
selectedPeriodId: null,
|
} = state;
|
||||||
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<HTMLElement>,
|
|
||||||
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 colors = React.useMemo(() => {
|
const colors = React.useMemo(() => {
|
||||||
const palette = config.style.palette[flow];
|
const palette = config.style.palette[flow];
|
||||||
@@ -145,7 +79,7 @@ export default function Dashboard({
|
|||||||
<ToggleButtonGroup
|
<ToggleButtonGroup
|
||||||
value={flow}
|
value={flow}
|
||||||
exclusive
|
exclusive
|
||||||
onChange={handleFlowChange}
|
onChange={stateSetters.toggleFlow}
|
||||||
sx={{
|
sx={{
|
||||||
borderRadius: 3,
|
borderRadius: 3,
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
@@ -169,7 +103,7 @@ export default function Dashboard({
|
|||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
sx={{ mt: 1, textTransform: "none" }}
|
sx={{ mt: 1, textTransform: "none" }}
|
||||||
onClick={() => setSelectedGroupKey(null)}
|
onClick={() => stateSetters.setSelectedGroupKey(null)}
|
||||||
>
|
>
|
||||||
Clear Drill-down
|
Clear Drill-down
|
||||||
</Button>
|
</Button>
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
export { default } from "./Dashboard";
|
export { default } from "./Dashboard.view";
|
||||||
export * from "./Dashboard.models";
|
export * from "./Dashboard.models";
|
||||||
|
|||||||
Reference in New Issue
Block a user