Skip to content

Commit edf3438

Browse files
Add debt import templates and portfolio delete functionality
- Add CSV/XLSX template download buttons to debt import page - Install xlsx and papaparse dependencies for file generation - Add delete button to portfolio cards (shows on hover) - Implement portfolio deletion with confirmation dialog - Add test CSV file with sample debt data - Update UI to refresh after portfolio deletion
1 parent ca44e89 commit edf3438

File tree

6 files changed

+256
-19
lines changed

6 files changed

+256
-19
lines changed

package-lock.json

Lines changed: 111 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
"input-otp": "^1.4.2",
4848
"lucide-react": "^0.475.0",
4949
"next-themes": "^0.4.4",
50+
"papaparse": "^5.5.3",
5051
"react": "^18.2.0",
5152
"react-day-picker": "^8.10.1",
5253
"react-dom": "^18.2.0",
@@ -58,6 +59,7 @@
5859
"tailwind-merge": "^3.0.2",
5960
"tailwindcss-animate": "^1.0.7",
6061
"vaul": "^1.1.2",
62+
"xlsx": "^0.18.5",
6163
"zod": "^3.24.2"
6264
},
6365
"devDependencies": {

src/components/portfolios/PortfolioCard.jsx

Lines changed: 60 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
1-
import React from 'react';
1+
import React, { useState } from 'react';
22
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
33
import { Badge } from "@/components/ui/badge";
4+
import { Button } from "@/components/ui/button";
45
import { Link } from "react-router-dom";
56
import { createPageUrl } from "@/utils";
7+
import { Portfolio } from "@/api/entities";
8+
import { toast } from "sonner";
69
import {
710
Percent,
811
CheckCircle,
912
Scale,
1013
UserX,
1114
AlertTriangle,
12-
DollarSign
15+
DollarSign,
16+
Trash2
1317
} from "lucide-react";
1418

1519
const KpiItem = ({ icon: Icon, value, label, colorClass }) => (
@@ -20,24 +24,53 @@ const KpiItem = ({ icon: Icon, value, label, colorClass }) => (
2024
</div>
2125
);
2226

23-
export default function PortfolioCard({ portfolio, stats }) {
27+
export default function PortfolioCard({ portfolio, stats, onDelete }) {
28+
const [showDelete, setShowDelete] = useState(false);
29+
const [isDeleting, setIsDeleting] = useState(false);
30+
2431
const typeColors = {
2532
spec: "bg-green-100 text-green-800",
2633
committed: "bg-yellow-100 text-yellow-800"
2734
};
2835

36+
const handleDelete = async (e) => {
37+
e.preventDefault();
38+
e.stopPropagation();
39+
40+
if (!confirm(`Are you sure you want to delete "${portfolio.name}"? This action cannot be undone.`)) {
41+
return;
42+
}
43+
44+
setIsDeleting(true);
45+
try {
46+
await Portfolio.delete(portfolio.id);
47+
toast.success('Portfolio deleted successfully');
48+
onDelete?.(portfolio.id);
49+
} catch (error) {
50+
console.error('Error deleting portfolio:', error);
51+
toast.error('Failed to delete portfolio');
52+
} finally {
53+
setIsDeleting(false);
54+
}
55+
};
56+
2957
return (
30-
<Link to={createPageUrl(`PortfolioDetails?id=${portfolio.id}`)}>
31-
<Card className="border-0 shadow-sm hover:shadow-lg transition-all duration-300 cursor-pointer h-full flex flex-col">
32-
<CardHeader>
33-
<div className="flex justify-between items-start">
34-
<CardTitle className="text-lg font-bold text-gray-900 leading-tight">
35-
{portfolio.name}
36-
</CardTitle>
37-
<Badge className={typeColors[portfolio.portfolio_type]}>
38-
{portfolio.portfolio_type}
39-
</Badge>
40-
</div>
58+
<div
59+
className="relative"
60+
onMouseEnter={() => setShowDelete(true)}
61+
onMouseLeave={() => setShowDelete(false)}
62+
>
63+
<Link to={createPageUrl(`PortfolioDetails?id=${portfolio.id}`)}>
64+
<Card className="border-0 shadow-sm hover:shadow-lg transition-all duration-300 cursor-pointer h-full flex flex-col">
65+
<CardHeader>
66+
<div className="flex justify-between items-start">
67+
<CardTitle className="text-lg font-bold text-gray-900 leading-tight">
68+
{portfolio.name}
69+
</CardTitle>
70+
<Badge className={typeColors[portfolio.portfolio_type]}>
71+
{portfolio.portfolio_type}
72+
</Badge>
73+
</div>
4174
<p className="text-sm text-gray-500 pt-1">{portfolio.original_creditor}</p>
4275
</CardHeader>
4376
<CardContent className="flex-grow flex flex-col justify-end">
@@ -72,6 +105,18 @@ export default function PortfolioCard({ portfolio, stats }) {
72105
</div>
73106
</CardContent>
74107
</Card>
75-
</Link>
108+
</Link>
109+
{showDelete && (
110+
<Button
111+
variant="destructive"
112+
size="sm"
113+
className="absolute top-2 right-2 z-10 opacity-90 hover:opacity-100"
114+
onClick={handleDelete}
115+
disabled={isDeleting}
116+
>
117+
<Trash2 className="w-4 h-4" />
118+
</Button>
119+
)}
120+
</div>
76121
);
77122
}

0 commit comments

Comments
 (0)