|
|
|
import { useState, useEffect } from "react";
|
|
import { useParams, useNavigate } from "react-router-dom";
|
|
import { Trash, Edit, ArrowDownRight, ArrowUpRight } from "lucide-react";
|
|
import AppLayout from "@/components/layout/AppLayout";
|
|
import Header from "@/components/shared/Header";
|
|
import { Button } from "@/components/ui/button";
|
|
import { cn } from "@/lib/utils";
|
|
import { Transaction } from "@/components/dashboard/RecentTransactions";
|
|
import { toast } from "sonner";
|
|
import database from "@/services/database";
|
|
|
|
const TransactionDetail = () => {
|
|
const { id } = useParams<{ id: string }>();
|
|
const navigate = useNavigate();
|
|
const [transaction, setTransaction] = useState<Transaction | null>(null);
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
const loadTransaction = async () => {
|
|
if (!id) return;
|
|
|
|
try {
|
|
await database.initialize();
|
|
|
|
|
|
const results = database.exec('SELECT * FROM transactions WHERE id = ?', [id]);
|
|
|
|
if (results.length === 0) {
|
|
setTransaction(null);
|
|
} else {
|
|
const row = results[0];
|
|
|
|
setTransaction({
|
|
id: row.id,
|
|
title: row.title,
|
|
amount: parseFloat(row.amount),
|
|
type: row.type as 'income' | 'expense',
|
|
category: row.category,
|
|
date: new Date(row.date),
|
|
note: row.note || undefined
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading transaction:', error);
|
|
toast.error('Failed to load transaction');
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
loadTransaction();
|
|
}, [id]);
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<AppLayout>
|
|
<div className="max-w-md mx-auto p-4 flex justify-center">
|
|
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div>
|
|
</div>
|
|
</AppLayout>
|
|
);
|
|
}
|
|
|
|
if (!transaction) {
|
|
return (
|
|
<AppLayout>
|
|
<div className="max-w-md mx-auto p-4 text-center">
|
|
<h2 className="text-xl font-semibold">Transaction not found</h2>
|
|
<Button
|
|
onClick={() => navigate('/transactions')}
|
|
className="mt-4"
|
|
>
|
|
Go Back
|
|
</Button>
|
|
</div>
|
|
</AppLayout>
|
|
);
|
|
}
|
|
|
|
const formatDate = (date: Date) => {
|
|
return new Intl.DateTimeFormat('en-US', {
|
|
weekday: 'long',
|
|
year: 'numeric',
|
|
month: 'long',
|
|
day: 'numeric'
|
|
}).format(date);
|
|
};
|
|
|
|
const formatCurrency = (amount: number) => {
|
|
return new Intl.NumberFormat('en-US', {
|
|
style: 'currency',
|
|
currency: 'USD',
|
|
currencyDisplay: 'symbol',
|
|
}).format(Math.abs(amount));
|
|
};
|
|
|
|
const handleDelete = async () => {
|
|
if (!id) return;
|
|
|
|
try {
|
|
await database.initialize();
|
|
|
|
|
|
database.exec('DELETE FROM transactions WHERE id = ?', [id]);
|
|
|
|
toast.success('Transaction deleted successfully');
|
|
navigate('/transactions');
|
|
} catch (error) {
|
|
console.error('Error deleting transaction:', error);
|
|
toast.error('Failed to delete transaction');
|
|
}
|
|
};
|
|
|
|
return (
|
|
<AppLayout>
|
|
<div className="max-w-md mx-auto">
|
|
<Header
|
|
title="Transaction Details"
|
|
showBackButton
|
|
rightElement={
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
onClick={handleDelete}
|
|
className="text-red-500 hover:text-red-600 hover:bg-red-50"
|
|
>
|
|
<Trash size={18} />
|
|
</Button>
|
|
}
|
|
/>
|
|
|
|
<div className="p-4 space-y-6 animate-fade-in">
|
|
<div className="flex justify-center py-6">
|
|
<div
|
|
className={cn(
|
|
"w-16 h-16 rounded-full flex items-center justify-center",
|
|
transaction.type === "expense"
|
|
? "bg-red-100 text-red-600"
|
|
: "bg-green-100 text-green-600"
|
|
)}
|
|
>
|
|
{transaction.type === "expense"
|
|
? <ArrowUpRight size={28} />
|
|
: <ArrowDownRight size={28} />
|
|
}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="text-center">
|
|
<h2 className="text-2xl font-semibold">{transaction.title}</h2>
|
|
<p className={cn(
|
|
"text-3xl font-bold mt-2",
|
|
transaction.type === "expense" ? "text-red-600" : "text-green-600"
|
|
)}>
|
|
{transaction.type === "expense" ? "- " : "+ "}
|
|
{formatCurrency(transaction.amount)}
|
|
</p>
|
|
<p className="text-muted-foreground mt-1">{formatDate(transaction.date)}</p>
|
|
</div>
|
|
|
|
<div className="bg-card border border-border rounded-xl p-4 space-y-4">
|
|
<div>
|
|
<p className="text-sm text-muted-foreground">Type</p>
|
|
<p className="font-medium capitalize">{transaction.type}</p>
|
|
</div>
|
|
|
|
<div>
|
|
<p className="text-sm text-muted-foreground">Category</p>
|
|
<p className="font-medium capitalize">{transaction.category}</p>
|
|
</div>
|
|
|
|
<div>
|
|
<p className="text-sm text-muted-foreground">Note</p>
|
|
<p className="font-medium">{transaction.note || "No notes"}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<Button
|
|
onClick={() => navigate(`/edit-transaction/${transaction.id}`)}
|
|
className="w-full flex items-center justify-center py-6"
|
|
>
|
|
<Edit size={18} className="mr-2" />
|
|
Edit Transaction
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</AppLayout>
|
|
);
|
|
};
|
|
|
|
export default TransactionDetail;
|
|
|