diff --git a/backend/app/db/seed.py b/backend/app/db/seed.py
index fe93f35..20729cd 100644
--- a/backend/app/db/seed.py
+++ b/backend/app/db/seed.py
@@ -31,6 +31,10 @@ DEFAULT_INCOME_CATEGORIES = [
("Freelance", "briefcase", "#1baf7a"),
("Investments", "trending-up", "#4a3aa7"),
("Gifts", "gift", "#e87ba4"),
+ ("Business Income", "building-2", "#eb6834"),
+ ("Rental Income", "key", "#eda100"),
+ ("Benefits", "hand-coins", "#008300"),
+ ("Item Sales", "tag", "#e34948"),
("Other Income", "plus-circle", "#898781"),
]
diff --git a/frontend/package.json b/frontend/package.json
index e328f11..5bac112 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,7 +1,7 @@
{
"name": "aurum-frontend",
"private": true,
- "version": "0.23.0",
+ "version": "0.23.1",
"type": "module",
"scripts": {
"dev": "vite",
diff --git a/frontend/src/components/categories/CategoryList.tsx b/frontend/src/components/categories/CategoryList.tsx
index d1a5de7..eceac5a 100644
--- a/frontend/src/components/categories/CategoryList.tsx
+++ b/frontend/src/components/categories/CategoryList.tsx
@@ -1,4 +1,5 @@
import { Pencil, Trash2 } from "lucide-react";
+import { translateCategoryName } from "@/lib/categoryLabels";
import { getCategoryIcon } from "@/lib/icons";
import { useTranslation } from "@/lib/i18n";
import type { Category } from "@/types";
@@ -30,7 +31,7 @@ export function CategoryList({ items, onEdit, onDelete }: CategoryListProps) {
- {category.name}
+ {translateCategoryName(category.name)}
{category.is_default && (
{t("category.defaultBadge")}
diff --git a/frontend/src/lib/categoryLabels.ts b/frontend/src/lib/categoryLabels.ts
index 3b1381d..828163b 100644
--- a/frontend/src/lib/categoryLabels.ts
+++ b/frontend/src/lib/categoryLabels.ts
@@ -1,10 +1,10 @@
import { t, type TranslationKey } from "@/lib/i18n";
// Maps the exact seeded English category name (backend/app/db/seed.py) to
-// its translation key. There's no category-management UI yet, so every
-// category currently in the database is one of these — anything that
-// doesn't match (a renamed default, or a future custom category) falls
-// through unchanged.
+// its translation key, so the fixed default set reads in the user's chosen
+// language regardless of what the DB literally stores. Categories created
+// through the category-management UI (CategoriesPage) aren't in this map —
+// their name is whatever the user typed and is shown as-is.
const DEFAULT_CATEGORY_KEYS: Record = {
"Housing & Utilities": "category.housingUtilities",
Groceries: "category.groceries",
@@ -18,6 +18,10 @@ const DEFAULT_CATEGORY_KEYS: Record = {
Freelance: "category.freelance",
Investments: "category.investments",
Gifts: "category.gifts",
+ "Business Income": "category.businessIncome",
+ "Rental Income": "category.rentalIncome",
+ Benefits: "category.benefits",
+ "Item Sales": "category.itemSales",
"Other Income": "category.otherIncome",
};
diff --git a/frontend/src/lib/i18n.ts b/frontend/src/lib/i18n.ts
index 5b1a926..9a5df61 100644
--- a/frontend/src/lib/i18n.ts
+++ b/frontend/src/lib/i18n.ts
@@ -324,11 +324,10 @@ const ru = {
"cashFlow.net": "Баланс",
"cashFlow.noData": "Нет данных за выбранный период.",
- // Default seeded categories (backend/app/db/seed.py) — there's no
- // category-management UI yet, so every category currently in the
- // database is one of these; translateCategoryName() matches on the exact
- // seeded English name and falls through unchanged for anything else
- // (a renamed default, or a future custom category).
+ // Default seeded categories (backend/app/db/seed.py) — translateCategoryName()
+ // matches on the exact seeded English name and falls through unchanged
+ // for anything else (a renamed default, or a custom category added via
+ // the category-management UI).
"category.housingUtilities": "Жильё и коммуналка",
"category.groceries": "Продукты",
"category.diningOut": "Кафе и рестораны",
@@ -341,6 +340,10 @@ const ru = {
"category.freelance": "Фриланс",
"category.investments": "Инвестиции",
"category.gifts": "Подарки",
+ "category.businessIncome": "Доход от бизнеса",
+ "category.rentalIncome": "Сдача недвижимости",
+ "category.benefits": "Пособия и соцвыплаты",
+ "category.itemSales": "Продажа личных вещей",
"category.otherIncome": "Прочий доход",
"months.jan": "Янв",
@@ -689,6 +692,10 @@ const en: Record = {
"category.freelance": "Freelance",
"category.investments": "Investments",
"category.gifts": "Gifts",
+ "category.businessIncome": "Business Income",
+ "category.rentalIncome": "Rental Income",
+ "category.benefits": "Benefits",
+ "category.itemSales": "Item Sales",
"category.otherIncome": "Other Income",
"months.jan": "Jan",
diff --git a/frontend/src/lib/icons.tsx b/frontend/src/lib/icons.tsx
index d2e6970..75a6942 100644
--- a/frontend/src/lib/icons.tsx
+++ b/frontend/src/lib/icons.tsx
@@ -11,8 +11,10 @@ import {
Gem,
Gift,
GraduationCap,
+ HandCoins,
HeartPulse,
Home,
+ Key,
MoreHorizontal,
Package,
Plane,
@@ -26,6 +28,7 @@ import {
Smartphone,
Sofa,
Sparkles,
+ Tag,
TrendingUp,
Truck,
Utensils,
@@ -71,6 +74,9 @@ const ICON_MAP: Record = {
smartphone: Smartphone,
sofa: Sofa,
sparkles: Sparkles,
+ tag: Tag,
+ "hand-coins": HandCoins,
+ key: Key,
truck: Truck,
// lucide-react dropped brand/trademarked glyphs (no "Youtube" icon) — a
// generic video-camera icon is the closest available stand-in.