mirror of
https://github.com/Zproger/Aurum.git
synced 2026-10-13 02:56:39 +07:00
fix: show full category path (parent · subcategory) everywhere, group filters by hierarchy
Транзакция на подкатегории показывала только её имя — непонятно было, что это подкатегория и к какой родительской категории она относится. Фильтры по категории в Транзакциях и Отчётах тоже перечисляли подкатегории наравне с родительскими, без иерархии. - categoryLabels.ts: categoryPath() и buildHierarchicalCategories() — общая логика, вынесенная из TransactionFormModal. - Список транзакций и «Последние транзакции» на Dashboard показывают счёт, затем родителя, затем подкатегорию. - Фильтр категорий в Транзакциях сгруппирован по типу (как в Отчётах); оба списка показывают подкатегорию с отступом под родителем.
This commit is contained in:
@@ -13,7 +13,7 @@ import { useCategories } from "@/hooks/useCategories";
|
||||
import { useTags } from "@/hooks/useTags";
|
||||
import type { TransactionSort } from "@/api/transactions";
|
||||
import { useTranslation } from "@/lib/i18n";
|
||||
import { translateCategoryName } from "@/lib/categoryLabels";
|
||||
import { buildHierarchicalCategories, translateCategoryName } from "@/lib/categoryLabels";
|
||||
import type { Transaction, TransactionType } from "@/types";
|
||||
|
||||
const PAGE_SIZE = 20;
|
||||
@@ -35,7 +35,7 @@ function parseYearParam(value: string | null, fallback: number): number {
|
||||
}
|
||||
|
||||
export function TransactionsPage() {
|
||||
const { t } = useTranslation();
|
||||
const { t, language } = useTranslation();
|
||||
const now = new Date();
|
||||
// Deep-linked from the Dashboard's "All transactions" link, which carries
|
||||
// the month/year the user was already looking at (?year=&month=) so this
|
||||
@@ -84,6 +84,17 @@ export function TransactionsPage() {
|
||||
const deleteTransaction = useDeleteTransaction();
|
||||
|
||||
const totalPages = data ? Math.max(1, Math.ceil(data.total / PAGE_SIZE)) : 1;
|
||||
// Grouped by kind and hierarchical within each group (a subcategory right
|
||||
// under its own parent, indented) — a bare "Sweets" option next to
|
||||
// top-level categories reads as if it were one itself.
|
||||
const expenseCategoryOptions = buildHierarchicalCategories(
|
||||
(categories ?? []).filter((category) => category.kind === "expense"),
|
||||
language
|
||||
);
|
||||
const incomeCategoryOptions = buildHierarchicalCategories(
|
||||
(categories ?? []).filter((category) => category.kind === "income"),
|
||||
language
|
||||
);
|
||||
|
||||
function openCreateModal() {
|
||||
setEditingTransaction(null);
|
||||
@@ -199,11 +210,26 @@ export function TransactionsPage() {
|
||||
className="sm:w-56"
|
||||
>
|
||||
<option value="">{t("transactions.allCategories")}</option>
|
||||
{categories?.map((category) => (
|
||||
<option key={category.id} value={category.id}>
|
||||
{translateCategoryName(category.name)}
|
||||
</option>
|
||||
))}
|
||||
{expenseCategoryOptions.length > 0 && (
|
||||
<optgroup label={t("reports.expenseGroup")}>
|
||||
{expenseCategoryOptions.map((category) => (
|
||||
<option key={category.id} value={category.id}>
|
||||
{category.indented ? ` ↳ ` : ""}
|
||||
{translateCategoryName(category.name)}
|
||||
</option>
|
||||
))}
|
||||
</optgroup>
|
||||
)}
|
||||
{incomeCategoryOptions.length > 0 && (
|
||||
<optgroup label={t("reports.incomeGroup")}>
|
||||
{incomeCategoryOptions.map((category) => (
|
||||
<option key={category.id} value={category.id}>
|
||||
{category.indented ? ` ↳ ` : ""}
|
||||
{translateCategoryName(category.name)}
|
||||
</option>
|
||||
))}
|
||||
</optgroup>
|
||||
)}
|
||||
</Select>
|
||||
{tags && tags.length > 0 && (
|
||||
<Select
|
||||
|
||||
Reference in New Issue
Block a user