fix(web): planner category drill-down — filter to the actual category (backend appends unrelated stragglers) + localized title/icon
This commit is contained in:
parent
2e391ce244
commit
7014ed3d2e
1 changed files with 16 additions and 6 deletions
|
|
@ -3,7 +3,8 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { TextFieldRoot, TextFieldInput } from "@seed-design/react";
|
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 { tugrik } from "@/ds/money";
|
||||||
import { useTransactions } from "@/api/hooks/reads";
|
import { useTransactions } from "@/api/hooks/reads";
|
||||||
import type { Txn } from "@/api/schemas";
|
import type { Txn } from "@/api/schemas";
|
||||||
|
|
@ -36,12 +37,20 @@ export function CategoryTransactions({ category }: CategoryTransactionsProps) {
|
||||||
});
|
});
|
||||||
const [search, setSearch] = React.useState("");
|
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 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();
|
const needle = search.trim().toLowerCase();
|
||||||
if (!needle) return all;
|
if (!needle) return inCategory;
|
||||||
return all.filter((t) => t.title.toLowerCase().includes(needle));
|
return inCategory.filter((t) => t.title.toLowerCase().includes(needle));
|
||||||
}, [data, search]);
|
}, [data, category, search]);
|
||||||
|
|
||||||
|
const cat = categoryStyle(category);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-4">
|
<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 href="/planner" aria-label={s.amountEntry.cancel} style={{ color: "var(--seed-color-fg-neutral)" }}>
|
||||||
←
|
←
|
||||||
</Link>
|
</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>
|
</div>
|
||||||
|
|
||||||
<TextFieldRoot value={search} onValueChange={setSearch}>
|
<TextFieldRoot value={search} onValueChange={setSearch}>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue