diff --git a/resources/js/components/accounts/account-list-card.tsx b/resources/js/components/accounts/account-list-card.tsx index 3dc35ec9..3ba44e37 100644 --- a/resources/js/components/accounts/account-list-card.tsx +++ b/resources/js/components/accounts/account-list-card.tsx @@ -9,7 +9,7 @@ import { AccountWithMetrics } from '@/hooks/use-dashboard-data'; import { formatAccountType, supportsInvestedAmount } from '@/types/account'; import { __ } from '@/utils/i18n'; import { Link } from '@inertiajs/react'; -import { useMemo, useState } from 'react'; +import { type ReactNode, useMemo, useState } from 'react'; import { Line, LineChart, ResponsiveContainer, Tooltip } from 'recharts'; import { Button } from '../ui/button'; import { UpdateBalanceDialog } from './update-balance-dialog'; @@ -34,6 +34,7 @@ interface AccountListCardProps { onBalanceUpdated?: () => void; linkedLoanMetrics?: LinkedLoanMetrics; displayCurrencyCode?: string; + dragHandle?: ReactNode; } export function AccountListCard({ @@ -42,6 +43,7 @@ export function AccountListCard({ onBalanceUpdated, linkedLoanMetrics, displayCurrencyCode, + dragHandle, }: AccountListCardProps) { const currencyCode = displayCurrencyCode ?? account.currency_code; const { accountMainLineColor, accountGainLineColor, mortgageLineColor } = @@ -134,6 +136,11 @@ export function AccountListCard({ return ( + {dragHandle && ( + + {dragHandle} + + )}
diff --git a/resources/js/components/dashboard/account-balance-card.tsx b/resources/js/components/dashboard/account-balance-card.tsx index 6b00780d..8d169829 100644 --- a/resources/js/components/dashboard/account-balance-card.tsx +++ b/resources/js/components/dashboard/account-balance-card.tsx @@ -6,10 +6,11 @@ import { AmountDisplay } from '@/components/ui/amount-display'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { useChartColors } from '@/hooks/use-chart-color-scheme'; import { AccountWithMetrics } from '@/hooks/use-dashboard-data'; +import { cn } from '@/lib/utils'; import { supportsInvestedAmount } from '@/types/account'; import { __ } from '@/utils/i18n'; import { Link } from '@inertiajs/react'; -import { useEffect, useMemo, useRef, useState } from 'react'; +import { type ReactNode, useEffect, useMemo, useRef, useState } from 'react'; import { Line, LineChart, ResponsiveContainer, Tooltip } from 'recharts'; import { AccountTypeIcon } from './account-type-icon'; import { AmountTrendIndicator } from './amount-trend-indicator'; @@ -34,6 +35,7 @@ interface AccountBalanceCardProps { onBalanceUpdated?: () => void; linkedLoanMetrics?: LinkedLoanMetrics; displayCurrencyCode?: string; + dragHandle?: ReactNode; } export function AccountBalanceCard({ @@ -42,6 +44,7 @@ export function AccountBalanceCard({ onBalanceUpdated, linkedLoanMetrics, displayCurrencyCode, + dragHandle, }: AccountBalanceCardProps) { const currencyCode = displayCurrencyCode ?? account.currency_code; const { accountMainLineColor, accountGainLineColor, mortgageLineColor } = @@ -193,11 +196,19 @@ export function AccountBalanceCard({ )}
-
+
+ {dragHandle && ( + + {dragHandle} + + )}
diff --git a/resources/js/components/sortable-grid.tsx b/resources/js/components/sortable-grid.tsx index c67fbb4e..0ea26701 100644 --- a/resources/js/components/sortable-grid.tsx +++ b/resources/js/components/sortable-grid.tsx @@ -24,7 +24,12 @@ import type { ReactNode } from 'react'; interface SortableGridProps { items: T[]; getId: (item: T) => string; - renderItem: (item: T) => ReactNode; + /** + * Renders one item. The provided drag handle must be placed inside the + * card so it sits exactly where the card wants it (e.g. over the account + * icon); it only becomes visible on hover via the wrapper's `group`. + */ + renderItem: (item: T, dragHandle: ReactNode) => ReactNode; onReorder: (orderedIds: string[]) => void; className?: string; /** Non-sortable content rendered inside the grid after the items. */ @@ -78,7 +83,7 @@ export function SortableGrid({
{items.map((item) => ( - {renderItem(item)} + {(dragHandle) => renderItem(item, dragHandle)} ))} {footer} @@ -88,7 +93,13 @@ export function SortableGrid({ ); } -function SortableItem({ id, children }: { id: string; children: ReactNode }) { +function SortableItem({ + id, + children, +}: { + id: string; + children: (dragHandle: ReactNode) => ReactNode; +}) { const { attributes, listeners, @@ -99,6 +110,19 @@ function SortableItem({ id, children }: { id: string; children: ReactNode }) { isDragging, } = useSortable({ id }); + const dragHandle = ( + + ); + return (
- {children} - + {children(dragHandle)}
); } diff --git a/resources/js/pages/Accounts/Index.tsx b/resources/js/pages/Accounts/Index.tsx index c3683f1c..5c6eb49b 100644 --- a/resources/js/pages/Accounts/Index.tsx +++ b/resources/js/pages/Accounts/Index.tsx @@ -174,9 +174,10 @@ export default function AccountsIndex({ accounts, accountMetrics }: Props) { items={orderedAccounts} getId={(account) => account.id} onReorder={handleReorder} - renderItem={(account) => ( + renderItem={(account, dragHandle) => ( account.id} onReorder={handleReorder} - renderItem={(account) => ( + renderItem={(account, dragHandle) => (