|
|
| 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";
|
|
|
|
|
| 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;
|
|
|