fix(web): planner category drill-down — filter to the actual category (backend appends unrelated stragglers) + localized title/icon

This commit is contained in:
Munkherdene 2026-08-22 23:33:25 +08:00
parent 2e391ce244
commit 7014ed3d2e

View file

@ -3,7 +3,8 @@
import * as React from "react";
import Link from "next/link";
import { TextFieldRoot, TextFieldInput } from "@seed-design/react";
import { Card } from "@/ds";
import { Card, IconChip } from "@/ds";
import { categoryStyle } from "@/ds/categoryStyle";
import { tugrik } from "@/ds/money";
import { useTransactions } from "@/api/hooks/reads";
import type { Txn } from "@/api/schemas";
@ -36,12 +37,20 @@ export function CategoryTransactions({ category }: CategoryTransactionsProps) {
});
const [search, setSearch] = React.useState("");
// The backend's ?category= filter always appends a handful of unrelated
// "straggler" rows (recent uncategorized/other-category txns) to every
// result, which makes a low-activity category look like it shows the wrong
// transactions. Filter to the exact category client-side so the drill-down
// is trustworthy (empty categories correctly show empty). Case-insensitive.
const rows: Txn[] = React.useMemo(() => {
const all = data ?? [];
const key = category.trim().toLowerCase();
const inCategory = (data ?? []).filter((t) => (t.category ?? "").trim().toLowerCase() === key);
const needle = search.trim().toLowerCase();
if (!needle) return all;
return all.filter((t) => t.title.toLowerCase().includes(needle));
}, [data, search]);
if (!needle) return inCategory;
return inCategory.filter((t) => t.title.toLowerCase().includes(needle));
}, [data, category, search]);
const cat = categoryStyle(category);
return (
<div className="flex flex-col gap-4">
@ -49,7 +58,8 @@ export function CategoryTransactions({ category }: CategoryTransactionsProps) {
<Link href="/planner" aria-label={s.amountEntry.cancel} style={{ color: "var(--seed-color-fg-neutral)" }}>
</Link>
<h1 style={{ fontWeight: 700, fontSize: 16 }}>{category}</h1>
<IconChip icon={cat.icon} tint={cat.tint} fg={cat.fg} size={34} />
<h1 style={{ fontWeight: 700, fontSize: 18 }}>{cat.name}</h1>
</div>
<TextFieldRoot value={search} onValueChange={setSearch}>