|
|
|
import { useMemo } from "react";
|
|
import AppLayout from "@/components/layout/AppLayout";
|
|
import Header from "@/components/shared/Header";
|
|
import BalanceCard from "@/components/dashboard/BalanceCard";
|
|
import RecentTransactions from "@/components/dashboard/RecentTransactions";
|
|
import SpendingAnalytics from "@/components/dashboard/SpendingAnalytics";
|
|
import { Transaction } from "@/components/dashboard/RecentTransactions";
|
|
import { Card, CardContent } from "@/components/ui/card";
|
|
import {
|
|
Carousel,
|
|
CarouselContent,
|
|
CarouselItem,
|
|
CarouselNext,
|
|
CarouselPrevious,
|
|
} from "@/components/ui/carousel";
|
|
import {
|
|
Coffee,
|
|
Utensils,
|
|
Briefcase,
|
|
Zap
|
|
} from "lucide-react";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
|
|
const mockTransactions: Transaction[] = [
|
|
{
|
|
id: "1",
|
|
title: "Grocery Shopping",
|
|
amount: 56.78,
|
|
type: "expense",
|
|
category: "food",
|
|
date: new Date(2023, 9, 15)
|
|
},
|
|
{
|
|
id: "2",
|
|
title: "Monthly Salary",
|
|
amount: 3200,
|
|
type: "income",
|
|
category: "salary",
|
|
date: new Date(2023, 9, 1)
|
|
},
|
|
{
|
|
id: "3",
|
|
title: "Coffee Shop",
|
|
amount: 4.50,
|
|
type: "expense",
|
|
category: "coffee",
|
|
date: new Date(2023, 9, 14)
|
|
},
|
|
{
|
|
id: "4",
|
|
title: "Gas Bill",
|
|
amount: 45.20,
|
|
type: "expense",
|
|
category: "utilities",
|
|
date: new Date(2023, 9, 10)
|
|
}
|
|
];
|
|
|
|
const spendingCategories = [
|
|
{ name: "Food", value: 450, color: "#FF6384" },
|
|
{ name: "Transport", value: 300, color: "#36A2EB" },
|
|
{ name: "Shopping", value: 200, color: "#FFCE56" },
|
|
{ name: "Utilities", value: 150, color: "#4BC0C0" },
|
|
{ name: "Entertainment", value: 100, color: "#9966FF" }
|
|
];
|
|
|
|
const Index = () => {
|
|
|
|
const { balance, income, expenses } = useMemo(() => {
|
|
let totalIncome = 0;
|
|
let totalExpenses = 0;
|
|
|
|
mockTransactions.forEach(transaction => {
|
|
if (transaction.type === "income") {
|
|
totalIncome += transaction.amount;
|
|
} else {
|
|
totalExpenses += transaction.amount;
|
|
}
|
|
});
|
|
|
|
return {
|
|
balance: totalIncome - totalExpenses,
|
|
income: totalIncome,
|
|
expenses: totalExpenses
|
|
};
|
|
}, []);
|
|
|
|
return (
|
|
<AppLayout>
|
|
<div className="max-w-md mx-auto">
|
|
<Header
|
|
title="Flutter"
|
|
subtitle="Your finances at a glance"
|
|
/>
|
|
|
|
<div className="px-4 space-y-6 pb-6">
|
|
<BalanceCard
|
|
balance={balance}
|
|
income={income}
|
|
expenses={expenses}
|
|
/>
|
|
|
|
<Card className="p-5 bg-white/80 backdrop-blur-lg border border-slate-200 shadow-lg rounded-2xl relative overflow-hidden">
|
|
<div className="absolute inset-0 z-0 opacity-10">
|
|
<img
|
|
src="/lovable-uploads/efa85ef3-0e1e-44d2-bbd4-34fe8f8946e4.png"
|
|
alt="Financial illustrations"
|
|
className="w-full h-full object-cover"
|
|
/>
|
|
</div>
|
|
<div className="relative z-10">
|
|
<h2 className="text-lg md:text-xl font-medium text-slate-800 mb-4">Recent Transactions</h2>
|
|
|
|
<Carousel
|
|
opts={{
|
|
align: "start",
|
|
loop: true,
|
|
slidesToScroll: 1,
|
|
}}
|
|
className="w-full"
|
|
>
|
|
<CarouselContent className="-ml-2 md:-ml-4">
|
|
{mockTransactions.map((transaction) => (
|
|
<CarouselItem key={transaction.id} className="pl-2 md:pl-4 basis-full md:basis-1/2">
|
|
<div className="p-1">
|
|
<Card className="bg-white rounded-xl shadow-sm border-0">
|
|
<div className="p-3 flex flex-col h-full">
|
|
<div className="flex items-center">
|
|
<div className={cn(
|
|
"w-10 h-10 rounded-full flex items-center justify-center mr-3",
|
|
transaction.type === "expense" ? "bg-red-100 text-red-600" : "bg-green-100 text-green-600"
|
|
)}>
|
|
{transaction.category === "food" && <Utensils size={18} />}
|
|
{transaction.category === "coffee" && <Coffee size={18} />}
|
|
{transaction.category === "salary" && <Briefcase size={18} />}
|
|
{transaction.category === "utilities" && <Zap size={18} />}
|
|
</div>
|
|
|
|
<div className="flex-1">
|
|
<h3 className="font-medium text-slate-800">{transaction.title}</h3>
|
|
<p className="text-sm text-slate-500">
|
|
{new Intl.DateTimeFormat('en-US', {
|
|
month: 'short',
|
|
day: 'numeric'
|
|
}).format(transaction.date)}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className={cn(
|
|
"font-medium text-right mt-3 pt-2 border-t border-slate-100",
|
|
transaction.type === "expense" ? "text-red-600" : "text-green-600"
|
|
)}>
|
|
{transaction.type === "expense" ? "- " : "+ "}
|
|
${new Intl.NumberFormat('en-US').format(Math.abs(transaction.amount))}
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
</div>
|
|
</CarouselItem>
|
|
))}
|
|
</CarouselContent>
|
|
<div className="flex justify-end mt-2">
|
|
<CarouselPrevious className="relative static mr-2 h-8 w-8" />
|
|
<CarouselNext className="relative static h-8 w-8" />
|
|
</div>
|
|
</Carousel>
|
|
</div>
|
|
</Card>
|
|
|
|
<Card className="p-5 bg-white/80 backdrop-blur-lg border border-slate-200 shadow-lg rounded-2xl relative overflow-hidden">
|
|
<div className="absolute inset-0 z-0 opacity-10">
|
|
<img
|
|
src="/lovable-uploads/efa85ef3-0e1e-44d2-bbd4-34fe8f8946e4.png"
|
|
alt="Financial illustrations"
|
|
className="w-full h-full object-cover"
|
|
/>
|
|
</div>
|
|
<div className="relative z-10">
|
|
<SpendingAnalytics data={spendingCategories} />
|
|
</div>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
</AppLayout>
|
|
);
|
|
};
|
|
|
|
export default Index;
|
|
|