Launched best Saas Marketing template at cheap — Check out

Personal Finance

Personal Finance Dashboard with budget tracking, expense analytics, savings goals, and transaction management micro UI components.

Folder Structure

budget-progress.tsx
dashboard-layout.tsx
Header.tsx
IncomeExpenseChart.tsx
MonthlySpendingChart.tsx
RecentTransactions.tsx
SavingsGoals.tsx
Footer.tsx
StatsCards.tsx
index.tsx

Installation and Setup

To set up the Personal Finance Dashboard, follow these steps

Install the necessary components for the dashboard

Run the following command to install all finance dashboard components

npx mvpblocks add personal-finance-dashboard-1

Install required dependencies

npm install recharts lucide-react next-theme

or

yarn add recharts lucide-react next-theme

Copy the following components and paste them into your project

Add index.tsx => Copy the code from the above on clicking the "Code" tab which is present corresponding to "Preview tab" after the component title.

Add dashboard-layout.tsx

'use client';import { ReactNode, useState } from 'react';import PersonalSidebar from './personal-sidebar';import PersonalHeader from './personal-header';import PersonalFooter from './personal-footer';interface DashboardLayoutProps {  children: ReactNode;}export default function DashboardLayout({ children }: DashboardLayoutProps) {  const [collapsed, setCollapsed] = useState<boolean>(false);  return (    <div className="min-h-screen w-full overflow-hidden">      <div        className={`mt-16 grid min-h-screen grid-cols-1 transition-all duration-500 ${          collapsed ? 'ml-20 lg:grid-cols-[1fr]' : 'lg:grid-cols-[16rem_1fr]'        }`}      >        <div>          <PersonalSidebar collapsed={collapsed} setCollapsed={setCollapsed} />        </div>        <div className="flex w-full flex-col transition-all duration-500">          <PersonalHeader />          <main className="flex-1 overflow-y-auto p-3 md:p-6">{children}</main>          <PersonalFooter />        </div>      </div>    </div>  );}

Add personal-sidebar.tsx

'use client';import { Dispatch, SetStateAction, useState } from 'react';import {  LayoutDashboard,  Wallet,  Target,  BarChart3,  Settings,  PiggyBank,  ChevronRight,  Bell,  User,  Menu,  DollarSign,} from 'lucide-react';import { cn } from '@/lib/utils';import Link from 'next/link';import { Button } from '@/components/ui/button';interface SidebarProps {  collapsed: boolean;  setCollapsed: Dispatch<SetStateAction<boolean>>;}const navigation = [  { name: 'Dashboard', href: '#', icon: LayoutDashboard, current: true },  { name: 'Transactions', href: '#', icon: Wallet, current: false },  { name: 'Budget', href: '#', icon: BarChart3, current: false },  { name: 'Goals', href: '#', icon: Target, current: false },  { name: 'Investments', href: '#', icon: PiggyBank, current: false },  { name: 'Settings', href: '#', icon: Settings, current: false },];export default function Sidebar({ collapsed, setCollapsed }: SidebarProps) {  const [mobileOpen, setMobileOpen] = useState(false);  return (    <>      <div className="fixed top-[0.8rem] left-3 z-60 md:hidden">        <Button          size="icon"          onClick={() => setMobileOpen(!mobileOpen)}          className="rounded-sm !bg-primary text-white hover:!bg-primary"          aria-label="Toggle sidebar"        >          <Menu className="size-5" />        </Button>      </div>      {/* Sidebar */}      <div        className={cn(          'bg-background fixed inset-y-0 top-14 left-0 z-50 transform overflow-hidden border-r transition-all duration-500 ease-in-out',          // On mobile, slide sidebar in/out based on mobileOpen          'md:translate-x-0',          mobileOpen ? 'w-64 translate-x-0' : 'w-64 -translate-x-full',          collapsed && 'w-16 md:w-20',        )}      >        <div className="flex h-full flex-col">          {/* Header */}          <div className="hidden items-center justify-between border-b md:flex">            <button              onClick={() => setCollapsed(!collapsed)}              className="hover:bg-muted flex w-full cursor-pointer items-center justify-between p-3.5 transition-all duration-500"            >              <div                className={cn(                  'flex w-full items-center gap-3',                  collapsed ? 'm-auto justify-center' : 'justify-start',                )}              >                <DollarSign className="size-8 text-primary" />                {!collapsed && (                  <h1 className="text-2xl font-medium">FinDash Pro</h1>                )}              </div>              <ChevronRight                className={cn(                  'size-5 transition-all duration-500',                  collapsed ? 'hidden' : 'block',                )}              />            </button>          </div>          {/* Navigation */}          <nav className="flex-1 space-y-2 p-2 pt-4 md:p-4">            {navigation.map((item) => (              <Link                key={item.name}                href={item.href}                className={cn(                  'group flex items-center rounded-sm border border-transparent p-3 text-sm font-medium transition-all duration-300 hover:scale-105',                  item.current                    ? 'border-primary/30 bg-gradient-to-br from-primary/10 text-primary'                    : 'text-muted-foreground from-primary/10 hover:border-primary/30 hover:bg-gradient-to-br hover:text-primary',                )}                onClick={() => setMobileOpen(false)}              >                <item.icon                  className={cn(                    item.current                      ? 'text-primary'                      : 'text-muted-foreground group-hover:text-primary',                    collapsed ? 'mx-auto size-5' : 'mr-3 size-5',                  )}                />                {!collapsed && item.name}              </Link>            ))}          </nav>          {/* Mobile user & notification buttons */}          <nav className="flex flex-col space-y-2 p-2 md:hidden md:p-4">            <button              className={cn(                'group flex items-center rounded-sm border border-transparent px-3 py-3 text-sm font-medium transition-all duration-300 hover:scale-105',                'border-primary/30 bg-gradient-to-br from-primary/10 text-primary',              )}              aria-label="Notifications"              onClick={() => setMobileOpen(false)}            >              <Bell                className={cn(                  'text-primary',                  collapsed ? 'mx-auto size-5' : 'mr-3 size-5',                )}              />              {!collapsed && 'Notifications'}            </button>            <button              className={cn(                'group flex items-center rounded-sm border border-transparent px-3 py-3 text-sm font-medium transition-all duration-300 hover:scale-105',                'border-primary/30 bg-gradient-to-br from-primary/10 text-primary',              )}              aria-label="Profile"              onClick={() => setMobileOpen(false)}            >              <User                className={cn(                  'text-primary',                  collapsed ? 'mx-auto size-5' : 'mr-3 size-5',                )}              />              {!collapsed && 'Profile'}            </button>          </nav>          {/* Footer */}          {!collapsed && (            <div className="h-20 w-full border-t p-5">              <div className="w-full rounded-sm border border-primary/30 bg-gradient-to-b from-primary/20 p-3 text-center text-xs text-primary">                šŸ’° Save more this month !              </div>            </div>          )}        </div>      </div>    </>  );}

Add personal-header.tsx

'use client';import { useEffect, useState } from 'react';import { Bell, User, Calendar, Moon, Sun, DollarSign } from 'lucide-react';import { useTheme } from 'next-themes';import { Button } from '@/components/ui/button';import {  DropdownMenu,  DropdownMenuContent,  DropdownMenuItem,  DropdownMenuTrigger,} from '@/components/ui/dropdown-menu';import { cn } from '@/lib/utils';export default function Header() {  const [currentDate, setCurrentDate] = useState<string>('');  const { theme, setTheme } = useTheme();  const [mounted, setMounted] = useState(false);  useEffect(() => {    setMounted(true);  }, []);  useEffect(() => {    const formattedDate = new Date().toLocaleDateString('en-US', {      weekday: 'long',      year: 'numeric',      month: 'long',      day: 'numeric',    });    setCurrentDate(formattedDate);  }, []);  return (    <header className="bg-background/80 fixed top-0 left-0 z-50 w-full border-b backdrop-blur-md">      <div className="flex w-full items-center justify-between px-3 py-3 md:px-6">        {/* Desktop and tablet layout */}        <div className="m-auto flex w-full items-center justify-center text-center">          {currentDate && (            <div className="text-muted-foreground hidden w-full items-center gap-2 text-xs md:flex md:text-sm">              <Calendar className="size-4" />              <span>{currentDate}</span>            </div>          )}          <div            className={cn(              'm-auto flex w-full items-center justify-center gap-1.5 text-center md:hidden',            )}          >            <DollarSign className="text-primary" />            <h1 className="text-xl font-medium">FinDash Pro</h1>          </div>          <div className="block w-auto md:hidden">            <Button              size="icon"              className="!bg-primary rounded-sm text-white hover:!bg-rose-600"              onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}              aria-label="Toggle theme"            >              {mounted &&                (theme === 'dark' ? (                  <Sun className="size-5" />                ) : (                  <Moon className="size-5" />                ))}            </Button>          </div>        </div>        <div className="ml-auto hidden w-auto items-center justify-end gap-2 md:flex md:w-full md:max-w-xs">          <Button variant="outline" size="icon" className="relative rounded-sm">            <Bell className="size-5" />            <span className="bg-primary absolute -top-1 -right-1 size-3 rounded-full border border-white" />          </Button>          <DropdownMenu>            <DropdownMenuTrigger asChild>              <Button                variant="outline"                size="icon"                className="relative rounded-sm"              >                <User className="size-5" />              </Button>            </DropdownMenuTrigger>            <DropdownMenuContent align="end" className="rounded-sm">              <DropdownMenuItem className="hover:!bg-primary rounded hover:!text-white">                Profile              </DropdownMenuItem>              <DropdownMenuItem className="hover:!bg-primary rounded hover:!text-white">                Settings              </DropdownMenuItem>              <DropdownMenuItem className="hover:!bg-primary rounded hover:!text-white">                Logout              </DropdownMenuItem>            </DropdownMenuContent>          </DropdownMenu>          <Button            variant="outline"            size="icon"            className="rounded-sm"            onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}            aria-label="Toggle theme"          >            {mounted &&              (theme === 'dark' ? (                <Sun className="size-5" />              ) : (                <Moon className="size-5" />              ))}          </Button>        </div>      </div>    </header>  );}

Add personal-footer.tsx

import React from 'react';import Link from 'next/link';import { Button } from '@/components/ui/button';import { Twitter, Facebook, Linkedin } from 'lucide-react';export default function Footer() {  const currentYear = new Date().getFullYear();  return (    <footer className="mt-8 flex h-20 w-full flex-col items-center justify-between gap-1 border-t p-5 text-center md:flex-row">      <span className="text-muted-foreground text-xs">        Ā© {currentYear} FinDash Pro. All rights reserved.      </span>      <div className="flex justify-center gap-1">        <Button          variant="ghost"          size="icon"          asChild          className="text-muted-foreground hover:!bg-primary rounded transition-all duration-500 hover:scale-105 hover:text-white"        >          <Link            href="https://twitter.com"            target="_blank"            rel="noopener noreferrer"            aria-label="Twitter"          >            <Twitter className="size-4" />          </Link>        </Button>        <Button          variant="ghost"          size="icon"          asChild          className="text-muted-foreground hover:!bg-primary rounded transition-all duration-500 hover:scale-105 hover:text-white"        >          <Link            href="https://facebook.com"            target="_blank"            rel="noopener noreferrer"            aria-label="Facebook"          >            <Facebook className="size-4" />          </Link>        </Button>        <Button          variant="ghost"          size="icon"          asChild          className="text-muted-foreground hover:!bg-primary rounded transition-all duration-500 hover:scale-105 hover:text-white"        >          <Link            href="https://linkedin.com"            target="_blank"            rel="noopener noreferrer"            aria-label="LinkedIn"          >            <Linkedin className="size-4" />          </Link>        </Button>      </div>    </footer>  );}

Add stats-cards.tsx

'use client';import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';import {  ArrowUpIcon,  ArrowDownIcon,  Wallet,  Target,  TrendingUp,} from 'lucide-react';import { Badge } from '@/components/ui/badge';const stats = [  {    title: 'Total Balance',    value: '$12,456',    change: '+12.4%',    trend: 'up',    icon: Wallet,    description: 'From last month',    gradient: 'from-green-500 to-emerald-500',  },  {    title: 'Monthly Income',    value: '$4,200',    change: '+8.2%',    trend: 'up',    icon: ArrowUpIcon,    description: 'This month',    gradient: 'from-blue-500 to-cyan-500',  },  {    title: 'Monthly Expenses',    value: '$2,843',    change: '-3.1%',    trend: 'down',    icon: ArrowDownIcon,    description: 'This month',    gradient: 'from-orange-500 to-red-500',  },  {    title: 'Savings Rate',    value: '32.4%',    change: '+5.7%',    trend: 'up',    icon: Target,    description: 'Of total income',    gradient: 'from-purple-500 to-pink-500',  },];export default function StatsCards() {  return (    <div className="grid grid-cols-1 gap-3 sm:grid-cols-2 md:gap-6 xl:grid-cols-4">      {stats.map((stat) => (        <Card          key={stat.title}          className="bg-gradient-to-br from-secondary/30 gap-2 overflow-hidden rounded-lg shadow-none transition-all duration-500 hover:scale-105"        >          <CardHeader className="flex w-full flex-row items-center justify-between">            <CardTitle className="text-lg font-medium">{stat.title}</CardTitle>            <div              className={`rounded-sm bg-gradient-to-br p-2 ${stat.gradient}`}            >              <stat.icon className="size-5 text-white" />            </div>          </CardHeader>          <CardContent>            <div className="mb-3 text-2xl font-bold">{stat.value}</div>            <div className="flex items-center justify-between">              <Badge                variant="secondary"                className="rounded px-3 py-1.5 text-xs"              >                <TrendingUp className="mr-1 size-3" />                {stat.change}              </Badge>              <span className="text-muted-foreground text-xs">                {stat.description}              </span>            </div>          </CardContent>        </Card>      ))}    </div>  );}

Add budget-progress.tsx

"use client";import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";import { Progress } from "@/components/ui/progress";import { AlertTriangle, CheckCircle2, FileText } from "lucide-react";const categories = [  {    name: "Food & Dining",    spent: 320,    budget: 500,    color: "bg-blue-500",    icon: "šŸ”",  },  {    name: "Transportation",    spent: 180,    budget: 300,    color: "bg-green-500",    icon: "šŸš—",  },  {    name: "Entertainment",    spent: 120,    budget: 200,    color: "bg-purple-500",    icon: "šŸŽ¬",  },  {    name: "Shopping",    spent: 450,    budget: 400,    color: "bg-red-500",    icon: "šŸ›ļø",  },  {    name: "Utilities",    spent: 220,    budget: 250,    color: "bg-yellow-500",    icon: "šŸ’”",  },  {    name: "Healthcare",    spent: 150,    budget: 200,    color: "bg-pink-500",    icon: "šŸ„",  },];export default function BudgetProgress() {  const totalSpent = categories.reduce((sum, cat) => sum + cat.spent, 0);  const totalBudget = categories.reduce((sum, cat) => sum + cat.budget, 0);  return (    <Card className="bg-background rounded-lg p-0 gap-0 overflow-hidden shadow-none max-h-[30rem]">      <CardHeader className="p-3 !pb-2 flex items-center justify-center text-center m-auto bg-background border-b h-16 w-full">        <CardTitle className="flex items-center justify-between text-center m-auto w-full h-full">          <div className="flex items-center gap-2">            <FileText className="size-6 text-primary" />            <span>Budget Tracking</span>          </div>          <span className="text-base md:text-lg font-medium">            ${totalSpent} / ${totalBudget}          </span>        </CardTitle>      </CardHeader>      <CardContent className="space-y-3 p-3 overflow-auto bg-background h-full">        {categories.map((category) => {          const percentage = (category.spent / category.budget) * 100;          const isOverBudget = category.spent > category.budget;          const isCloseToBudget = percentage > 80 && !isOverBudget;          return (            <div              key={category.name}              className="space-y-3 p-5 rounded-md border bg-gradient-to-tl from-secondary/30"            >              <div className="flex items-center justify-between">                <div className="flex items-center gap-2 font-medium">                  <span>{category.icon}</span>                  <span>{category.name}</span>                </div>                <div className="flex items-center space-x-2">                  {isOverBudget && (                    <AlertTriangle className="size-5 text-red-500" />                  )}                  {!isOverBudget && percentage >= 100 && (                    <CheckCircle2 className="size-5 text-green-500" />                  )}                  <span                    className={`text-sm font-semibold ${                      isOverBudget ? "text-red-500" : ""                    }`}                  >                    ${category.spent} / ${category.budget}                  </span>                </div>              </div>              <Progress                value={percentage > 100 ? 100 : percentage}                className={`h-2 ${                  isOverBudget                    ? "bg-red-500/30 [&>div]:bg-red-500"                    : isCloseToBudget                    ? "bg-yellow-400/30 [&>div]:bg-yellow-400"                    : "bg-green-500/30 [&>div]:bg-green-500"                }`}              />              <div className="flex justify-between text-xs">                <span>{percentage.toFixed(1)}% of budget</span>                {isOverBudget && (                  <span className="text-red-500 font-semibold">                    Over by ${category.spent - category.budget}                  </span>                )}                {isCloseToBudget && !isOverBudget && (                  <span className="text-yellow-400 font-semibold">                    Close to limit                  </span>                )}              </div>            </div>          );        })}      </CardContent>    </Card>  );}

Add income-expense-chart.tsx

'use client';import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';import { BarChart, Bar, CartesianGrid, XAxis, YAxis } from 'recharts';import {  ChartContainer,  ChartTooltip,  ChartTooltipContent,} from '@/components/ui/chart';const data = [  { month: 'Jan', income: 4200, expenses: 2843, net: 1357 },  { month: 'Feb', income: 3800, expenses: 2950, net: 850 },  { month: 'Mar', income: 5200, expenses: 3100, net: 2100 },  { month: 'Apr', income: 4800, expenses: 2650, net: 2150 },  { month: 'May', income: 5100, expenses: 2900, net: 2200 },  { month: 'Jun', income: 4700, expenses: 2750, net: 1950 },  { month: 'Jul', income: 5300, expenses: 3000, net: 2300 },];export default function IncomeExpenseChart() {  return (    <Card className="bg-gradient-to-t from-secondary/30 rounded-lg shadow-none">      <CardHeader className="flex flex-col items-center justify-between gap-3 md:flex-row">        <CardTitle>Income vs Expenses</CardTitle>        <div className="flex items-center justify-center gap-2">          <div className="flex items-center gap-2">            <div className="size-3 rounded-full bg-green-500"></div>            <span>Income</span>          </div>          <div className="flex items-center gap-2">            <div className="size-3 rounded-full bg-red-500"></div>            <span>Expenses</span>          </div>          <div className="flex items-center gap-2">            <div className="size-3 rounded-full bg-blue-500"></div>            <span>Net</span>          </div>        </div>      </CardHeader>      <CardContent className="px-0">        <ChartContainer          config={{            income: { label: 'Income', color: '#10b981' },            expenses: { label: 'Expenses', color: '#ef4444' },            net: { label: 'Net', color: '#3b82f6' },          }}          className="h-[15rem] md:h-[20rem] w-full"        >          <BarChart data={data}>            <CartesianGrid vertical={true} />            <XAxis dataKey="month" />            <YAxis />            <ChartTooltip content={<ChartTooltipContent />} />            <Bar              dataKey="income"              fill="var(--color-income)"              radius={[4, 4, 0, 0]}            />            <Bar              dataKey="expenses"              fill="var(--color-expenses)"              radius={[4, 4, 0, 0]}            />            <Bar dataKey="net" fill="var(--color-net)" radius={[4, 4, 0, 0]} />          </BarChart>        </ChartContainer>      </CardContent>    </Card>  );}

Add monthly-spending-chart.tsx

"use client";import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";import {  PieChart,  Pie,  Cell,  ResponsiveContainer,  Tooltip,  Legend,} from "recharts";const data = [  { name: "Food & Dining", value: 320, color: "#3b82f6" },  { name: "Transportation", value: 180, color: "#10b981" },  { name: "Entertainment", value: 120, color: "#8b5cf6" },  { name: "Shopping", value: 450, color: "#ef4444" },  { name: "Utilities", value: 220, color: "#f59e0b" },  { name: "Healthcare", value: 150, color: "#ec4899" },];interface CustomTooltipProps {  active?: boolean;  payload?: Array<{    name: string;    value: number;    color?: string;  }>;  label?: string;}const CustomTooltip = ({ active, payload }: CustomTooltipProps) => {  if (active && payload && payload.length) {    const data = payload[0]; // directly access payload[0] instead of payload[0].payload    return (      <div className="bg-background p-3 border border-green-500/70 rounded-md shadow-xl">        <p className="font-medium">{data.name}</p>        <p className="text-sm" style={{ color: data.color }}>          Amount : <span className="font-bold">${data.value}</span>        </p>        <p className="text-sm">          Percentage : {((data.value / 1440) * 100).toFixed(1)}%        </p>      </div>    );  }  return null;};export default function MonthlySpendingChart() {  return (    <Card className="bg-gradient-to-t from-secondary/30 rounded-lg shadow-none">      <CardHeader>        <CardTitle>Monthly Spending by Category</CardTitle>      </CardHeader>      <CardContent>        <div className="h-40 md:h-60">          <ResponsiveContainer width="100%" height="100%">            <PieChart>              <Pie                data={data}                cx="50%"                cy="50%"                innerRadius="50%" // relative to chart size                outerRadius="100%"                paddingAngle={2}                dataKey="value"              >                {data.map((entry, index) => (                  <Cell key={`cell-${index}`} fill={entry.color} className="ml-10" />                ))}              </Pie>              <Tooltip content={<CustomTooltip />} />              <Legend layout="vertical" verticalAlign="middle" align="right" />            </PieChart>          </ResponsiveContainer>        </div>        <div className="grid grid-cols-2 gap-4 mt-4 pt-4 border-t">          <div className="text-center">            <p className="text-2xl font-bold">$1,440</p>            <p className="text-sm text-muted-foreground">Total Spent</p>          </div>          <div className="text-center">            <p className="text-2xl font-bold text-green-500">$760</p>            <p className="text-sm text-muted-foreground">Remaining Budget</p>          </div>        </div>      </CardContent>    </Card>  );}

Add recent-transactions.tsx

'use client';import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';import { Badge } from '@/components/ui/badge';import { Button } from '@/components/ui/button';import {  ArrowUpIcon,  ArrowDownIcon,  Plus,  MoreVertical,  History,} from 'lucide-react';const transactions = [  {    id: 1,    description: 'Grocery Store',    amount: -85.2,    category: 'Food & Dining',    date: '2024-01-15',    type: 'expense',    merchant: 'Whole Foods',  },  {    id: 2,    description: 'Salary Deposit',    amount: 3200.0,    category: 'Income',    date: '2024-01-14',    type: 'income',    merchant: 'Company Inc',  },  {    id: 3,    description: 'Netflix Subscription',    amount: -15.99,    category: 'Entertainment',    date: '2024-01-13',    type: 'expense',    merchant: 'Netflix',  },  {    id: 4,    description: 'Gas Station',    amount: -45.0,    category: 'Transportation',    date: '2024-01-12',    type: 'expense',    merchant: 'Shell',  },  {    id: 5,    description: 'Freelance Work',    amount: 850.0,    category: 'Income',    date: '2024-01-11',    type: 'income',    merchant: 'Client Co',  },  {    id: 6,    description: 'Coffee Shop',    amount: -12.5,    category: 'Food & Dining',    date: '2024-01-10',    type: 'expense',    merchant: 'Starbucks',  },  {    id: 7,    description: 'Stock Dividend',    amount: 120.0,    category: 'Income',    date: '2024-01-09',    type: 'income',    merchant: 'Investments LLC',  },  {    id: 8,    description: 'Gym Membership',    amount: -35.0,    category: 'Health & Fitness',    date: '2024-01-08',    type: 'expense',    merchant: 'Gym Co',  },  {    id: 9,    description: 'Dining Out',    amount: -60.0,    category: 'Food & Dining',    date: '2024-01-07',    type: 'expense',    merchant: 'Olive Garden',  },  {    id: 10,    description: 'Project Bonus',    amount: 500.0,    category: 'Income',    date: '2024-01-06',    type: 'income',    merchant: 'Client Inc',  },];export default function RecentTransactions() {  return (    <>      <Card className="bg-background gap-0 overflow-hidden rounded-lg p-0 shadow-none">        <CardHeader className="bg-background flex flex-col items-center justify-between gap-2 border-b !p-3 md:flex-row">          <div className="flex items-center gap-2">            <History className="size-10" />            <div className="flex flex-col items-start gap-1">              <CardTitle>                <span>Recent 10 Transactions</span>              </CardTitle>              <span className="text-muted-foreground text-xs italic">                <span className="text-green-500">Green</span> means gain,{' '}                <span className="text-red-500">Red</span> means spend - track                your flow easily              </span>            </div>          </div>          <Button className="bg-primary hover:bg-primary flex w-full items-center gap-2 rounded-sm text-white md:w-auto">            <Plus className="size-4" />            <span>Add New</span>          </Button>        </CardHeader>        <CardContent className="p-0">          <div className="max-h-[25rem] space-y-3 overflow-auto p-3">            {transactions.map((transaction) => (              <div                key={transaction.id}                className="group flex items-center justify-between rounded-md border bg-gradient-to-r from-secondary/30 hover:border-primary/50 p-2"              >                <div className="flex items-center gap-3">                  <div                    className={`rounded-sm p-3 text-white ${                      transaction.type === 'income'                        ? 'bg-green-500'                        : 'bg-red-500'                    }`}                  >                    {transaction.type === 'income' ? (                      <ArrowUpIcon className="size-5" />                    ) : (                      <ArrowDownIcon className="size-5" />                    )}                  </div>                  <div>                    <p className="text-sm font-medium md:text-base">                      {transaction.description}                    </p>                    <div className="flex flex-col gap-0.5 opacity-60 md:flex-row md:items-center md:gap-2">                      <p className="text-[0.65rem] md:text-xs">                        {transaction.merchant}                      </p>                      <span className="hidden md:block">•</span>                      <p className="text-[0.65rem] md:text-xs">                        {transaction.date}                      </p>                    </div>                  </div>                </div>                <div className="ml-auto flex items-center justify-end gap-1 text-end">                  <div className="flex flex-col items-center md:flex-row md:gap-4">                    <span                      className={`w-full text-sm font-bold md:text-lg ${                        transaction.type === 'income'                          ? 'text-green-500'                          : 'text-primary'                      }`}                    >                      {transaction.type === 'income' ? '+' : '-'}$                      {Math.abs(transaction.amount).toFixed(2)}                    </span>                    <Badge                      variant="outline"                      className="mt-1 ml-auto rounded px-1.5 py-0 text-[0.6rem] md:mt-0 md:px-3 md:py-1.5 md:text-xs"                    >                      {transaction.category}                    </Badge>                  </div>                  <button>                    <MoreVertical className="size-4" />                  </button>                </div>              </div>            ))}          </div>        </CardContent>      </Card>    </>  );}

Add savings-goals.tsx

'use client';import { useEffect, useState } from 'react';import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';import { Progress } from '@/components/ui/progress';import { Button } from '@/components/ui/button';import { Target, Calendar, Plus } from 'lucide-react';const goals = [  {    name: 'Emergency Fund',    target: 10000,    current: 7500,    deadline: '2026-10-31',    color: 'from-blue-500 to-cyan-500',    icon: 'šŸ›”ļø',  },  {    name: 'New Car',    target: 25000,    current: 12000,    deadline: '2025-01-30',    color: 'from-green-500 to-emerald-500',    icon: 'šŸš—',  },  {    name: 'Vacation',    target: 5000,    current: 3200,    deadline: '2025-12-15',    color: 'from-purple-500 to-pink-500',    icon: 'šŸļø',  },];export default function SavingsGoals() {  const [formattedDates, setFormattedDates] = useState<{    [key: string]: string;  }>({});  useEffect(() => {    const newFormattedDates: { [key: string]: string } = {};    goals.forEach((goal) => {      newFormattedDates[goal.name] = new Date(goal.deadline).toLocaleDateString(        'en-GB',        {          day: '2-digit',          month: 'short',          year: 'numeric',        },      );    });    setFormattedDates(newFormattedDates);  }, []);  return (    <Card className="bg-background max-h-[30rem] gap-0 overflow-hidden rounded-lg p-0 shadow-none">      <CardHeader className="bg-background m-auto flex h-16 w-full flex-row items-center justify-between border-b p-3 !pb-3">        <CardTitle className="m-auto flex h-full w-full items-center gap-2 text-center">          <Target className="text-primary size-6" />          <span>Savings Goals</span>        </CardTitle>        <Button className="flex items-center gap-2 rounded-sm">          <Plus className="size-4" />          <span>Add Goal</span>        </Button>      </CardHeader>      <CardContent className="bg-background h-full space-y-3 overflow-auto p-3">        {goals.map((goal) => {          const percentage = (goal.current / goal.target) * 100;          const monthsLeft = Math.ceil(            (new Date(goal.deadline).getTime() - new Date().getTime()) /              (30 * 24 * 60 * 60 * 1000),          );          return (            <div              key={goal.name}              className="space-y-3 rounded-md border bg-gradient-to-tl from-secondary/30 p-5"            >              <div className="flex items-center justify-between">                <div className="flex items-center gap-3">                  <span className="text-2xl">{goal.icon}</span>                  <div>                    <h4 className="font-semibold">{goal.name}</h4>                    <p className="text-sm">                      Target : ${goal.target.toLocaleString()}                    </p>                  </div>                </div>                <div className="text-right">                  <p className="text-lg font-bold">                    ${goal.current.toLocaleString()}                  </p>                  <p className="text-sm">{percentage.toFixed(1)}%</p>                </div>              </div>              <div className="space-y-2">                <Progress                  value={percentage}                  className="h-2 bg-green-500/20 [&>div]:bg-green-500"                />                <div className="flex justify-between text-xs">                  <span>Saved : ${goal.current.toLocaleString()}</span>                  <span>                    Left : ${(goal.target - goal.current).toLocaleString()}                  </span>                </div>              </div>              <div className="flex items-center justify-between text-xs">                <div className="flex items-center gap-1 text-sm">                  <Calendar className="size-4" />                  <span>Due : {formattedDates[goal.name] || ''}</span>                </div>                <span                  className={`rounded-full border px-3 py-1.5 text-xs font-medium ${                    monthsLeft < 3                      ? 'border-red-500/70 bg-red-500/5 text-red-500'                      : monthsLeft < 6                        ? 'border-yellow-400/70 bg-yellow-400/5 text-yellow-400'                        : 'border-green-500/70 bg-green-500/5 text-green-500'                  }`}                >                  {monthsLeft} months left                </span>              </div>            </div>          );        })}      </CardContent>    </Card>  );}

Import and use the dashboard in your application

import PersonalFinanceDashboard from '@/components/dashboards/personal-finance-dashboard-1/index';

export default function FinancePage() {
  return <PersonalFinanceDashboard />;
}

Customization

Adding New Categories

Update the categories array in BudgetProgress.tsx:

const categories = [
  {
    name: 'Food & Dining',
    spent: 320,
    budget: 500,
    color: 'bg-blue-500',
    icon: 'šŸ”',
  },
  // ...add more like this
];

Adding New Monthly Spending Data

Update the data array in MonthlySpendingChart.tsx:

const data = [
  { name: 'Food & Dining', value: 320, color: '#3b82f6' },
  { name: 'Transportation', value: 180, color: '#10b981' },
  { name: 'Entertainment', value: 120, color: '#8b5cf6' },
  // ...add more like this
];

Like this do changes in the data or add new data in particular files.