dashboard loader

This commit is contained in:
2026-04-04 20:14:39 +05:30
parent 84059a84b5
commit 68337ba312
2 changed files with 243 additions and 121 deletions

View File

@@ -1,138 +1,106 @@
import * as React from "react";
import { Box, Container, Grid, Typography, Avatar } from "@mui/material";
import { Box, Container, Grid, Typography, Avatar, CircularProgress, Alert } from "@mui/material";
import LatestItemsList, { LatestItem } from "./components/LatestItemsList";
import ProgressCard from "./components/ProgressCard";
import HistoryChart from "./components/HistoryChart";
import ShoppingBagIcon from "@mui/icons-material/ShoppingBag";
import SubscriptionsIcon from "@mui/icons-material/Subscriptions";
import RestaurantIcon from "@mui/icons-material/Restaurant";
import FoodBankIcon from "@mui/icons-material/FoodBank";
const mockLatestItems: LatestItem[] = [
{
id: 1,
icon: <ShoppingBagIcon sx={{ color: "#388e3c" }} />,
iconBgColor: "#e8f5e9",
title: "Grocery Shopping",
subtitle: "Buy some grocery",
amount: "Rs 3000",
timeAgo: "3 days ago",
},
{
id: 2,
icon: <SubscriptionsIcon sx={{ color: "#7b1fa2" }} />,
iconBgColor: "#f3e5f5",
title: "Subscription",
subtitle: "Netflix monthly",
amount: "Rs 800",
timeAgo: "5 days ago",
},
{
id: 3,
icon: <RestaurantIcon sx={{ color: "#d32f2f" }} />,
iconBgColor: "#ffebee",
title: "Food",
subtitle: "Buy a chinese noodles",
amount: "Rs 1000",
timeAgo: "6 days ago",
},
{
id: 4,
icon: <FoodBankIcon sx={{ color: "#fbc02d" }} />,
iconBgColor: "#fff8e1",
title: "Food Club",
subtitle: "Buy a chinese noodles",
amount: "Rs 1000",
timeAgo: "6 days ago",
},
];
const mockChartData = {
today: [
{ id: "6am", amount: 100 },
{ id: "9am", amount: 500 },
{ id: "12pm", amount: 200 },
{ id: "3pm", amount: 1000, highlighted: true },
{ id: "6pm", amount: 600 },
{ id: "9pm", amount: 300 },
],
week: [
{ id: "Mon", amount: 1500 },
{ id: "Tue", amount: 1000 },
{ id: "Wed", amount: 2000 },
{ id: "Thu", amount: 500, highlighted: true },
{ id: "Fri", amount: 3000 },
{ id: "Sat", amount: 4500 },
{ id: "Sun", amount: 2000 },
],
month: [
{ id: "Week 1", amount: 10000 },
{ id: "Week 2", amount: 5000 },
{ id: "Week 3", amount: 12000, highlighted: true },
{ id: "Week 4", amount: 8000 },
],
year: [
{ id: "Q1", amount: 50000 },
{ id: "Q2", amount: 45000 },
{ id: "Q3", amount: 60000, highlighted: true },
{ id: "Q4", amount: 48000 },
],
};
import { fetchLatestExpenses, fetchAggregatedExpenses, AggregatedDashboardData } from "./utils/dashboardLoader";
export default function Dashboard() {
return (
<Container maxWidth="lg" sx={{ mt: 4, mb: 4 }}>
<Grid container spacing={4}>
{/* Left Column */}
<Grid item xs={12} md={6}>
{/* User Greeting */}
<Box sx={{ display: 'flex', alignItems: 'center', mb: 4, px: 2 }}>
<Avatar sx={{ width: 56, height: 56, mr: 2 }} src="https://i.pravatar.cc/150?img=5" />
<Box>
<Typography variant="h5" fontWeight={700}>Hello Ananya</Typography>
<Typography variant="subtitle1" color="text.secondary">Good Morning</Typography>
</Box>
</Box>
const [latest, setLatest] = React.useState<LatestItem[]>([]);
const [aggregated, setAggregated] = React.useState<AggregatedDashboardData | null>(null);
const [loading, setLoading] = React.useState(true);
const [error, setError] = React.useState<string | null>(null);
<ProgressCard
header="Account Balance"
summary="Rs 2,700,00"
progressAmount={270000}
totalAmount={270000}
colorTheme="info"
React.useEffect(() => {
async function loadData() {
try {
setLoading(true);
const [latestData, aggData] = await Promise.all([
fetchLatestExpenses(),
fetchAggregatedExpenses()
]);
setLatest(latestData);
setAggregated(aggData);
} catch (err: any) {
console.error(err);
setError(err.message || "Failed to load dashboard data");
} finally {
setLoading(false);
}
}
loadData();
}, []);
if (loading) {
return (
<Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '60vh' }}>
<CircularProgress />
</Box>
);
}
if (error) {
return (
<Container sx={{ mt: 4 }}>
<Alert severity="error">{error}</Alert>
</Container>
);
}
const themes = ["primary", "secondary", "info", "success", "warning"] as const;
return (
<Container maxWidth="xl" sx={{ mt: 4, mb: 4 }}>
<Grid container spacing={4}>
{/* Column 1: Latest Transactions */}
<Grid item xs={12} md={4}>
<LatestItemsList
title="Recent Transactions"
items={latest}
onViewAll={() => {}}
/>
<Box mt={4}>
<LatestItemsList
title="Recent Transactions"
items={mockLatestItems}
onViewAll={() => {}}
/>
</Box>
</Grid>
{/* Right Column */}
<Grid item xs={12} md={6}>
<Box sx={{ mb: 4, display: 'flex', justifyContent: 'center' }}>
<Typography variant="h6" fontWeight={700}>Statistics</Typography>
</Box>
<ProgressCard
header="Total Expense"
progressAmount={27000}
totalAmount={30000}
summary="Rs 27000 / Rs 30000 per month"
colorTheme="info"
{/* Column 2: Breakdown Graph */}
<Grid item xs={12} md={4}>
<Box sx={{ mb: 4, display: 'flex', justifyContent: 'center', visibility: 'hidden' }}>
<Typography variant="h6">Spacer</Typography>
</Box>
<HistoryChart
header="Expense Breakdown"
summary="Interactive chronological tracking"
tabs={["Today", "Week", "Month", "Year"]}
data={aggregated?.chartData || {}}
/>
</Grid>
{/* Column 3: Top Payees Progress */}
<Grid item xs={12} md={4}>
<Box sx={{ mb: 4, display: 'flex', justifyContent: 'center' }}>
<Typography variant="h6" fontWeight={700}>Top Analytics</Typography>
</Box>
<Box mt={4}>
<HistoryChart
header="Expense Breakdown"
summary="Limit each day Rs 5000/-"
tabs={["Today", "Week", "Month", "Year"]}
data={mockChartData}
<Box sx={{ mb: 4 }}>
<ProgressCard
header="Total Expenses"
progressAmount={aggregated?.totalAmount || 0}
totalAmount={aggregated?.totalAmount || 0}
summary={`Rs ${aggregated?.totalAmount || 0}`}
colorTheme="error" // Highlight total in red/error or use info
/>
</Box>
<Typography variant="h6" fontWeight={600} mb={2} px={1}>Top 5 Payees</Typography>
{aggregated?.topPayees.map((payee, idx) => (
<Box sx={{ mb: 2 }} key={payee.payeeName}>
<ProgressCard
header={payee.payeeName}
progressAmount={payee.amount}
totalAmount={aggregated?.totalAmount || 1}
colorTheme={themes[idx % themes.length]}
/>
</Box>
))}
</Grid>
</Grid>
</Container>