Reuse CategoryPicker in transactions page

This commit is contained in:
Matthias
2026-06-23 11:42:33 +02:00
parent fba74ec217
commit c072ab4593
5 changed files with 337 additions and 60 deletions

View File

@@ -28,6 +28,7 @@ import { Badge } from "@/components/ui/badge";
import { amountClass, formatAmount, formatDate, formatMonth } from "@/lib/format";
import { TransactionFormDialog } from "@/components/transactions/TransactionFormDialog";
import { AssignMonthDialog } from "@/components/transactions/AssignMonthDialog";
import { CategoryPicker } from "@/components/transactions/CategoryPicker";
import { toast } from "sonner";
import {
getVisibleSelectionState,
@@ -82,64 +83,18 @@ const AccountCell = memo(function AccountCell({ name }: { name: string | undefin
const CategoryCell = memo(function CategoryCell({
tx,
categories,
categoryMap,
onUpdate,
}: {
tx: Tx;
categories: Category[] | undefined;
categoryMap: Map<Id<"categories">, Category>;
onUpdate: (id: Id<"transactions">, categoryId: Id<"categories">) => void;
onUpdate: (id: Id<"transactions">, categoryId: Id<"categories">) => Promise<void>;
}) {
const [open, setOpen] = useState(false);
const cat = tx.categoryId ? categoryMap.get(tx.categoryId) : null;
if (!open) {
return (
<button
type="button"
onClick={() => setOpen(true)}
className="inline-flex h-6 items-center rounded px-1.5 text-xs hover:bg-accent"
>
{cat ? (
<Badge style={{ backgroundColor: cat.color, color: "#fff", border: "none" }}>
{cat.name}
</Badge>
) : (
<span className="text-muted-foreground">Kategorie</span>
)}
</button>
);
}
return (
<Select
defaultOpen
value={tx.categoryId ?? "none"}
onValueChange={(v) => {
if (v !== "none") onUpdate(tx._id, v as Id<"categories">);
setOpen(false);
}}
onOpenChange={(o) => {
if (!o) setOpen(false);
}}
>
<SelectTrigger className="h-7 w-[130px]">
<SelectValue placeholder="Kategorie" />
</SelectTrigger>
<SelectContent>
{categories?.map((c) => (
<SelectItem key={c._id} value={c._id}>
<span className="inline-flex items-center gap-1.5">
<span
className="inline-block h-2.5 w-2.5 rounded-full"
style={{ backgroundColor: c.color }}
/>
{c.name}
</span>
</SelectItem>
))}
</SelectContent>
</Select>
<CategoryPicker
categories={categories}
value={tx.categoryId}
onSelect={(categoryId) => onUpdate(tx._id, categoryId)}
/>
);
});
@@ -228,10 +183,6 @@ export function TransactionsPage() {
{ initialNumItems: 50 },
);
const categoryMap = useMemo(
() => new Map(categories?.map((c) => [c._id, c])),
[categories],
);
const accountMap = useMemo(
() => new Map(accounts?.map((a) => [a._id, a.name])),
[accounts],
@@ -247,8 +198,8 @@ export function TransactionsPage() {
);
const handleUpdateCategory = useCallback(
(id: Id<"transactions">, categoryId: Id<"categories">) => {
void updateTx({ id, categoryId });
async (id: Id<"transactions">, categoryId: Id<"categories">) => {
await updateTx({ id, categoryId });
},
[updateTx],
);
@@ -343,7 +294,6 @@ export function TransactionsPage() {
<CategoryCell
tx={row.original}
categories={categories}
categoryMap={categoryMap}
onUpdate={handleUpdateCategory}
/>
),
@@ -382,7 +332,6 @@ export function TransactionsPage() {
],
[
categories,
categoryMap,
accountMap,
handleUpdateCategory,
handleEdit,