diff --git a/src/components/dashboard/charts/IncomeBarChart.tsx b/src/components/dashboard/charts/IncomeBarChart.tsx
new file mode 100644
index 0000000..20caba0
--- /dev/null
+++ b/src/components/dashboard/charts/IncomeBarChart.tsx
@@ -0,0 +1,74 @@
+import {
+ BarChart,
+ Bar,
+ XAxis,
+ YAxis,
+ CartesianGrid,
+ Cell,
+} from "recharts"
+import {
+ ChartContainer,
+ ChartTooltip,
+ ChartTooltipContent,
+ ChartLegend,
+ ChartLegendContent,
+} from "@/components/ui/chart"
+import type { ChartConfig } from "@/components/ui/chart"
+import { ChartEmptyState } from "./ChartEmptyState"
+import { formatCurrency } from "@/lib/format"
+
+interface IncomeBarChartProps {
+ data: Array<{ label: string; budgeted: number; actual: number }>
+ currency: string
+ emptyMessage: string
+}
+
+const chartConfig = {
+ budgeted: { label: "Budgeted", color: "var(--color-budget-bar-bg)" },
+ actual: { label: "Actual", color: "var(--color-income-fill)" },
+} satisfies ChartConfig
+
+export function IncomeBarChart({
+ data,
+ currency,
+ emptyMessage,
+}: IncomeBarChartProps) {
+ if (data.length === 0) {
+ return
+ }
+
+ return (
+
+
+
+
+
+ formatCurrency(Number(value), currency)}
+ />
+ }
+ />
+ } />
+
+
+ {data.map((entry, index) => (
+ | entry.budgeted
+ ? "var(--color-over-budget)"
+ : "var(--color-income-fill)"
+ }
+ />
+ ))}
+ |
+
+
+ )
+}
diff --git a/src/components/dashboard/charts/SpendBarChart.tsx b/src/components/dashboard/charts/SpendBarChart.tsx
new file mode 100644
index 0000000..f60d397
--- /dev/null
+++ b/src/components/dashboard/charts/SpendBarChart.tsx
@@ -0,0 +1,84 @@
+import {
+ BarChart,
+ Bar,
+ XAxis,
+ YAxis,
+ CartesianGrid,
+ Cell,
+} from "recharts"
+import {
+ ChartContainer,
+ ChartTooltip,
+ ChartTooltipContent,
+ ChartLegend,
+ ChartLegendContent,
+} from "@/components/ui/chart"
+import type { ChartConfig } from "@/components/ui/chart"
+import { ChartEmptyState } from "./ChartEmptyState"
+import { formatCurrency } from "@/lib/format"
+
+interface SpendBarChartProps {
+ data: Array<{
+ type: string
+ label: string
+ budgeted: number
+ actual: number
+ }>
+ currency: string
+ emptyMessage: string
+}
+
+const chartConfig = {
+ budgeted: { label: "Budgeted", color: "var(--color-budget-bar-bg)" },
+ actual: { label: "Actual", color: "var(--color-muted-foreground)" },
+} satisfies ChartConfig
+
+export function SpendBarChart({
+ data,
+ currency,
+ emptyMessage,
+}: SpendBarChartProps) {
+ if (data.length === 0) {
+ return
+ }
+
+ return (
+
+
+
+
+
+ formatCurrency(Number(value), currency)}
+ />
+ }
+ />
+ } />
+
+
+ {data.map((entry, index) => (
+ entry.budgeted
+ ? "var(--color-over-budget)"
+ : `var(--color-${entry.type}-fill)`
+ }
+ />
+ ))}
+ |
+
+
+ )
+}