stock / src /components /dashboard /RecentTransactions.tsx
Zelyanoth's picture
Upload 101 files
24d40b9 verified
import { useState } from "react";
import {
ChevronRight,
Coffee,
ShoppingCart,
Zap,
Home as HomeIcon,
Car,
Utensils,
Briefcase,
CreditCard
} from "lucide-react";
import { useNavigate } from "react-router-dom";
import { cn } from "@/lib/utils";
import { motion } from "framer-motion";
// Mocked transaction data
export interface Transaction {
id: string;
title: string;
amount: number;
type: "expense" | "income";
category: string;
date: Date;
note?: string;
message?: string;
}
const CATEGORY_ICONS: Record<string, any> = {
food: Utensils,
coffee: Coffee,
shopping: ShoppingCart,
utilities: Zap,
housing: HomeIcon,
transport: Car,
salary: Briefcase,
other: CreditCard
};
interface RecentTransactionsProps {
transactions: Transaction[];
currency?: string;
showViewAll?: boolean;
}
const RecentTransactions = ({
transactions,
currency = "$",
showViewAll = true
}: RecentTransactionsProps) => {
const navigate = useNavigate();
const formatDate = (date: Date) => {
return new Intl.DateTimeFormat('en-US', {
month: 'short',
day: 'numeric'
}).format(date);
};
const formatCurrency = (amount: number) => {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
currencyDisplay: 'symbol',
}).format(Math.abs(amount)).replace('$', '');
};
const getCategoryIcon = (category: string) => {
const IconComponent = CATEGORY_ICONS[category.toLowerCase()] || CreditCard;
return <IconComponent size={18} />;
};
return (
<div>
{showViewAll && (
<div className="flex items-center justify-between mb-4">
<h2 className="text-lg md:text-xl font-medium text-slate-800">Recent Transactions</h2>
<button
onClick={() => navigate('/transactions')}
className="text-sm md:text-base font-medium text-[#00a651] flex items-center"
>
View All
<ChevronRight size={16} className="md:size-18" />
</button>
</div>
)}
<div className="space-y-3 md:space-y-4">
{transactions.map((transaction, index) => (
<motion.div
key={transaction.id}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3, delay: index * 0.1 }}
onClick={() => navigate(`/transactions/${transaction.id}`)}
className="cursor-pointer"
>
<div className="bg-white rounded-xl shadow-sm p-4">
<div className="flex flex-col h-full">
<div className="flex items-center">
<div className={cn(
"flex-shrink-0 w-10 h-10 rounded-full flex items-center justify-center",
transaction.type === "expense" ? "bg-red-100 text-red-600" : "bg-green-100 text-green-600"
)}>
{getCategoryIcon(transaction.category)}
</div>
<div className="ml-3 flex-1">
<p className="font-medium text-base text-slate-800">{transaction.title}</p>
<p className="text-sm text-slate-500">{formatDate(transaction.date)}</p>
</div>
</div>
<div className={cn(
"flex-shrink-0 font-medium mt-3 pt-2 border-t border-slate-100 text-right",
transaction.type === "expense" ? "text-red-600" : "text-green-600"
)}>
{transaction.type === "expense" ? "- " : "+ "}
{currency}{formatCurrency(transaction.amount)}
</div>
</div>
</div>
</motion.div>
))}
{transactions.length === 0 && (
<div className="p-6 md:p-8 text-center bg-white/60 rounded-xl border border-slate-200 shadow">
<p className="text-slate-500 md:text-lg">No recent transactions</p>
</div>
)}
</div>
</div>
);
};
export default RecentTransactions;