Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
"use client";

import {
ChartContainer,
ChartTooltip,
ChartTooltipContent,
type ChartConfig,
} from "@/components/ui/chart";
import { Pie, PieChart, Cell } from "recharts";
import { useLanguage } from "@/i18n/LanguageContext";

export type MandalPieItem = {
mandalId: string;
mandalName: string;
mandalNameTelugu: string;
value: number;
};

interface MandalPieChartProps {
title: string;
data: MandalPieItem[];
labelPrefix: string;
}

const PIE_COLORS = [
"#22d3ee", // cyan
"#3b82f6", // blue
"#f59e0b", // amber
"#ef4444", // red
"#a855f7", // purple
"#ec4899", // pink
"#10b981", // emerald
"#f97316", // orange
"#6366f1", // indigo
"#14b8a6", // teal
];

export function MandalPieChart({ title, data, labelPrefix }: MandalPieChartProps) {
const { lang } = useLanguage();

// Build config for ChartContainer
const config: ChartConfig = {};
data.forEach((item, idx) => {
config[item.mandalName] = {
label: lang === "te" ? item.mandalNameTelugu : item.mandalName,
color: PIE_COLORS[idx % PIE_COLORS.length],
};
});

// Build pie data
const pieData = data.map((item, idx) => ({
name: lang === "te" ? item.mandalNameTelugu : item.mandalName,
value: item.value,
fill: PIE_COLORS[idx % PIE_COLORS.length],
}));

const hasData = pieData.some((d) => d.value > 0);

return (
<div className="rounded-lg border bg-card p-4 shadow-sm flex flex-col" style={{ background: "hsl(var(--card))" }}>
<h3 className="text-base font-semibold mb-4 text-card-foreground">
{title}
</h3>

{hasData ? (
<ChartContainer config={config} className="mx-auto aspect-square w-full max-w-[280px]">
<PieChart>
<ChartTooltip
content={
<ChartTooltipContent
formatter={(value) => (
<span className="font-medium">₹{Number(value).toLocaleString("en-IN")}</span>
)}
/>
}
/>
<Pie
data={pieData}
dataKey="value"
nameKey="name"
cx="50%"
cy="50%"
innerRadius="30%"
outerRadius="80%"
paddingAngle={2}
strokeWidth={2}
stroke="hsl(var(--card))"
>
{pieData.map((entry, index) => (
<Cell key={`cell-${index}`} fill={entry.fill} />
))}
</Pie>
</PieChart>
</ChartContainer>
) : (
<div className="flex items-center justify-center h-[200px] text-muted-foreground text-sm">
</div>
)}

{/* Custom Legend */}
<div className="mt-4 space-y-2">
{data.map((item, idx) => (
<div key={item.mandalId} className="flex items-center gap-2 text-sm">
<span
className="inline-block h-3 w-3 rounded-sm shrink-0"
style={{ backgroundColor: PIE_COLORS[idx % PIE_COLORS.length] }}
/>
<span className="text-muted-foreground truncate flex-1">
{lang === "te" ? item.mandalNameTelugu : item.mandalName}
</span>
<span className="text-card-foreground font-medium whitespace-nowrap">
{labelPrefix} ₹{item.value.toLocaleString("en-IN")}
</span>
</div>
))}
</div>
</div>
);
}
73 changes: 51 additions & 22 deletions frontend/src/app/(authenticated)/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { useState, useEffect } from "react";
import { ContentLayout } from "../../../components/admin-panel/content-layout";
import { VillageTransactionsChart } from "./components/village-transactions-chart";
import { MandalPieChart, MandalPieItem } from "./components/mandal-pie-chart";
import { Loader2 } from "lucide-react";
import { useLanguage } from "@/i18n/LanguageContext";

Expand All @@ -14,8 +14,18 @@ type VillageSummary = {
totalLoans: number;
};

type MandalSummary = {
mandalId: string;
mandalName: string;
mandalNameTelugu: string;
totalDeposits: number;
totalLoans: number;
totalLaagodi: number;
};

type DashboardSummaryResponse = {
villages: VillageSummary[];
mandals: MandalSummary[];
totals: {
villageCount: number;
memberCount: number;
Expand All @@ -26,7 +36,7 @@ type DashboardSummaryResponse = {

export default function DashboardPage() {
const { t } = useLanguage();
const [data, setData] = useState<VillageSummary[]>([]);
const [mandals, setMandals] = useState<MandalSummary[]>([]);
const [totals, setTotals] = useState<DashboardSummaryResponse["totals"] | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
Expand All @@ -49,7 +59,7 @@ export default function DashboardPage() {
throw new Error(json.error?.message || "Failed to load dashboard summary");
}

setData(json.data.villages);
setMandals(json.data.mandals);
setTotals(json.data.totals);
} catch (err) {
setError(err instanceof Error ? err.message : "Unknown error");
Expand All @@ -61,10 +71,26 @@ export default function DashboardPage() {
fetchSummary();
}, []);

const chartData = data.map((village) => ({
village: village.villageName,
deposits: village.totalDeposits,
loans: village.totalLoans,
// Prepare pie chart data per category
const depositsData: MandalPieItem[] = mandals.map((m) => ({
mandalId: m.mandalId,
mandalName: m.mandalName,
mandalNameTelugu: m.mandalNameTelugu,
value: m.totalDeposits,
}));

const loansData: MandalPieItem[] = mandals.map((m) => ({
mandalId: m.mandalId,
mandalName: m.mandalName,
mandalNameTelugu: m.mandalNameTelugu,
value: m.totalLoans,
}));

const laagodiData: MandalPieItem[] = mandals.map((m) => ({
mandalId: m.mandalId,
mandalName: m.mandalName,
mandalNameTelugu: m.mandalNameTelugu,
value: m.totalLaagodi,
}));

return (
Expand Down Expand Up @@ -108,21 +134,24 @@ export default function DashboardPage() {
</div>
)}

<div className="flex-1 space-y-8 p-8 pt-4">
<div className="rounded-lg border bg-card p-4 shadow-sm">
<div className="mb-4 flex items-center justify-between">
<div>
<h2 className="text-lg font-semibold">
{t.dashboard.chartTitle}
</h2>
<p className="text-sm text-muted-foreground">
{t.dashboard.chartSubtitle}
</p>
</div>
</div>
<VillageTransactionsChart data={chartData} />
</div>
</div>
{/* Pie Charts Grid */}
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3 p-8 pt-4">
<MandalPieChart
title={t.dashboard.pieDeposits}
data={depositsData}
labelPrefix={t.dashboard.totalDepositsLabel}
/>
<MandalPieChart
title={t.dashboard.pieLoans}
data={loansData}
labelPrefix={t.dashboard.totalLoansLabel}
/>
<MandalPieChart
title={t.dashboard.pieLaagodi}
data={laagodiData}
labelPrefix={t.dashboard.totalLaagodiLabel}
/>
</div>
</div>
)}
</ContentLayout>
Expand Down
Loading