Skip to content

Commit 0b16814

Browse files
committed
Add drag-and-drop reordering to investment accounts list
1 parent 488e9e6 commit 0b16814

2 files changed

Lines changed: 37 additions & 2 deletions

File tree

src/app/(app)/investments/page.tsx

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
Loader2,
1414
Save,
1515
Check,
16+
GripVertical,
1617
} from "lucide-react";
1718
import {
1819
AreaChart,
@@ -142,6 +143,7 @@ export default function InvestmentsPage() {
142143
const [projectionYears, setProjectionYears] = useState(20);
143144
const [tickerData, setTickerData] = useState<Record<string, TickerData>>({});
144145
const [chartRange, setChartRange] = useState<"1W" | "6M" | "MAX">("6M");
146+
const [dragIdx, setDragIdx] = useState<number | null>(null);
145147

146148
useEffect(() => {
147149
console.debug("[investments] Loading investment accounts");
@@ -195,6 +197,23 @@ export default function InvestmentsPage() {
195197
}
196198
};
197199

200+
const handleDragStart = (idx: number) => { setDragIdx(idx); };
201+
const handleDragOver = (e: React.DragEvent, idx: number) => {
202+
e.preventDefault();
203+
if (dragIdx === null || dragIdx === idx) return;
204+
const reordered = [...investments];
205+
const [moved] = reordered.splice(dragIdx, 1);
206+
reordered.splice(idx, 0, moved);
207+
setInvestments(reordered);
208+
setDragIdx(idx);
209+
};
210+
const handleDragEnd = () => {
211+
setDragIdx(null);
212+
const order = investments.map((i) => i.id);
213+
fetch("/api/investments", { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ order }) }).catch(() => {});
214+
console.info("[investments] Saved new order");
215+
};
216+
198217
const updateInvestment = (id: string, field: keyof InvestmentData, value: number) => {
199218
setInvestments((prev) => prev.map((i) => i.id === id ? { ...i, [field]: value } : i));
200219
};
@@ -341,9 +360,10 @@ export default function InvestmentsPage() {
341360
))}
342361
</div>
343362
<Card className="list-card">
344-
{investments.map((inv) => (
345-
<div key={inv.id} className="debt-item">
363+
{investments.map((inv, idx) => (
364+
<div key={inv.id} className="debt-item" draggable onDragStart={() => handleDragStart(idx)} onDragOver={(e) => handleDragOver(e, idx)} onDragEnd={handleDragEnd}>
346365
<div className="debt-item-header">
366+
<GripVertical className="drag-handle" />
347367
<div>
348368
<p className="debt-item-name">{inv.name}</p>
349369
{inv.monthlyTransferred > 0 && (

src/styles/modules/pages.css

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,21 @@
437437
color: var(--muted-foreground);
438438
}
439439

440+
.drag-handle {
441+
width: 1rem;
442+
height: 1rem;
443+
flex-shrink: 0;
444+
color: var(--muted-foreground);
445+
opacity: 0.3;
446+
cursor: grab;
447+
touch-action: none;
448+
}
449+
450+
.drag-handle:active {
451+
cursor: grabbing;
452+
opacity: 0.6;
453+
}
454+
440455
.investment-ticker-info {
441456
display: flex;
442457
flex-direction: column;

0 commit comments

Comments
 (0)