Compare commits

..

4 Commits

7 changed files with 58 additions and 15 deletions

View File

@@ -1,11 +1,11 @@
import * as React from "react"; import * as React from "react";
export type DashboardMode = "expense" | "income"; export type DashboardMode = "expense" | "income";
export type DashboardPeriod = "rolling" | "calendar"; export type DashboardPeriodType = "rolling" | "calendar";
export interface DashboardState { export interface DashboardState {
mode: DashboardMode; mode: DashboardMode;
period: DashboardPeriod; periodType: DashboardPeriodType;
comparison: boolean; comparison: boolean;
} }

View File

@@ -5,7 +5,7 @@ import { DashboardProps, DashboardState } from "./Dashboard.models";
export default function Dashboard(props: DashboardProps) { export default function Dashboard(props: DashboardProps) {
const [state, setState] = React.useState<DashboardState>({ const [state, setState] = React.useState<DashboardState>({
mode: "expense", mode: "expense",
period: "rolling", periodType: "rolling",
comparison: false, comparison: false,
}); });

View File

@@ -25,7 +25,7 @@ export default function DashboardView({
}: ViewProps) { }: ViewProps) {
const theme = useTheme(); const theme = useTheme();
const themeMode = theme.palette.mode; const themeMode = theme.palette.mode;
const { mode, period, comparison } = state; const { mode, periodType, comparison } = state;
// Resolve colors with fallbacks // Resolve colors with fallbacks
const colors = React.useMemo(() => { const colors = React.useMemo(() => {
@@ -139,8 +139,8 @@ export default function DashboardView({
title={section.title} title={section.title}
accentColor={colors.primary} accentColor={colors.primary}
colorScheme={colors} colorScheme={colors}
period={period} periodType={periodType}
onPeriodChange={(p: any) => setState(prev => ({ ...prev, period: 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 }))}
/> />

View File

@@ -25,8 +25,8 @@ export interface HistoryChartProps {
summary?: string; summary?: string;
tabs: string[]; tabs: string[];
data: ChartData; data: ChartData;
period: "rolling" | "calendar"; periodType: "rolling" | "calendar";
onPeriodChange: (p: "rolling" | "calendar") => void; onPeriodTypeChange: (p: "rolling" | "calendar") => void;
comparison: boolean; comparison: boolean;
setComparison: (v: boolean) => void; setComparison: (v: boolean) => void;
colorScheme: { colorScheme: {

View File

@@ -3,7 +3,7 @@ import { ChartDataPoint, HistoryChartProps, ChartData } from "./HistoryChart.mod
import HistoryChartView from "./HistoryChart.view"; import HistoryChartView from "./HistoryChart.view";
export default function HistoryChart(props: HistoryChartProps) { export default function HistoryChart(props: HistoryChartProps) {
const { tabs, data, period, comparison } = props; const { tabs, data, periodType, comparison } = props;
const [activeTab, setActiveTab] = React.useState<string>(tabs[0] || ""); const [activeTab, setActiveTab] = React.useState<string>(tabs[0] || "");
const [startIndex, setStartIndex] = React.useState(0); const [startIndex, setStartIndex] = React.useState(0);
@@ -16,7 +16,7 @@ export default function HistoryChart(props: HistoryChartProps) {
rawData = data.daily || []; rawData = data.daily || [];
} else { } else {
const section = data[activeDataKey]; const section = data[activeDataKey];
rawData = section?.[period] || []; rawData = section?.[periodType] || [];
} }
const currentData = rawData; const currentData = rawData;

View File

@@ -33,8 +33,8 @@ export default function HistoryChartView(props: ViewProps) {
header, header,
summary, summary,
tabs, tabs,
period, periodType,
onPeriodChange, onPeriodTypeChange,
comparison, comparison,
setComparison, setComparison,
colorScheme, colorScheme,
@@ -99,7 +99,7 @@ export default function HistoryChartView(props: ViewProps) {
</ToggleButtonGroup> </ToggleButtonGroup>
<Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between", mb: 3 }}> <Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between", mb: 3 }}>
<ToggleButtonGroup value={period} exclusive onChange={(_, v) => v && onPeriodChange(v)} size="small"> <ToggleButtonGroup value={periodType} exclusive onChange={(_, v) => v && onPeriodTypeChange(v)} size="small">
<ToggleButton value="rolling">Rolling</ToggleButton> <ToggleButton value="rolling">Rolling</ToggleButton>
<ToggleButton value="calendar" disabled={activeDataKey === "daily"}> <ToggleButton value="calendar" disabled={activeDataKey === "daily"}>
Calendar Calendar

View File

@@ -25,14 +25,57 @@ const toLabel = (start: string, end: string, type: "weekly" | "monthly") => {
})}`; })}`;
}; };
const getWeekOfMonth = (date: Date) => {
const firstDay = new Date(date.getFullYear(), date.getMonth(), 1);
return Math.ceil((date.getDate() + firstDay.getDay()) / 7);
};
const findCompareBucket = (
current: ReportBucket,
buckets: ReportBucket[],
type: "weekly" | "monthly"
): ReportBucket | undefined => {
const start = new Date(current.start);
if (type === "monthly") {
const targetYear = start.getFullYear() - 1;
const targetMonth = start.getMonth();
return buckets.find(b => {
const d = new Date(b.start);
return (
d.getFullYear() === targetYear &&
d.getMonth() === targetMonth
);
});
}
if (type === "weekly") {
const weekIndex = getWeekOfMonth(start); // you must define this
const target = new Date(start);
target.setMonth(target.getMonth() - 1);
return buckets.find(b => {
const d = new Date(b.start);
return (
d.getFullYear() === target.getFullYear() &&
d.getMonth() === target.getMonth() &&
getWeekOfMonth(d) === weekIndex
);
});
}
return undefined;
};
const toPoints = ( const toPoints = (
buckets: ReportBucket[], buckets: ReportBucket[],
type: "weekly" | "monthly", type: "weekly" | "monthly",
flow: "expenses" | "incomes" flow: "expenses" | "incomes"
): ChartDataPoint[] => { ): ChartDataPoint[] => {
return buckets.map((b, i) => { return buckets.map((b) => {
const amount = sumBucket(b, flow); const amount = sumBucket(b, flow);
const prev = buckets[i - 1]; const prev = findCompareBucket(b, buckets, type);
return { return {
id: toLabel(b.start, b.end, type), id: toLabel(b.start, b.end, type),