feat: add expense date and CSV export to budget

- New expense_date column on budget items (DB migration #42)
- Date column in budget table with custom date picker
- CSV export button with BOM, semicolon separator, localized dates,
  currency in header, per-person/day calculations
- CustomDatePicker compact/borderless modes for inline table use
- i18n keys for all 12 languages
This commit is contained in:
Maurice
2026-04-01 12:16:11 +02:00
parent 60906cf1d1
commit 4ebf9c5f11
17 changed files with 117 additions and 28 deletions
+2
View File
@@ -931,6 +931,7 @@ const ar: Record<string, string | { name: string; category: string }[]> = {
// Budget
'budget.title': 'الميزانية',
'budget.exportCsv': 'تصدير CSV',
'budget.emptyTitle': 'لم يتم إنشاء ميزانية بعد',
'budget.emptyText': 'أنشئ فئات وإدخالات لتخطيط ميزانية سفرك',
'budget.emptyPlaceholder': 'أدخل اسم الفئة...',
@@ -945,6 +946,7 @@ const ar: Record<string, string | { name: string; category: string }[]> = {
'budget.table.perDay': 'لكل يوم',
'budget.table.perPersonDay': 'لكل شخص / يوم',
'budget.table.note': 'ملاحظة',
'budget.table.date': 'التاريخ',
'budget.newEntry': 'إدخال جديد',
'budget.defaultEntry': 'إدخال جديد',
'budget.defaultCategory': 'فئة جديدة',
+2
View File
@@ -910,6 +910,7 @@ const br: Record<string, string | { name: string; category: string }[]> = {
// Budget
'budget.title': 'Orçamento',
'budget.exportCsv': 'Exportar CSV',
'budget.emptyTitle': 'Nenhum orçamento criado ainda',
'budget.emptyText': 'Crie categorias e lançamentos para planejar o orçamento da viagem',
'budget.emptyPlaceholder': 'Nome da categoria...',
@@ -924,6 +925,7 @@ const br: Record<string, string | { name: string; category: string }[]> = {
'budget.table.perDay': 'Por dia',
'budget.table.perPersonDay': 'P. p. / dia',
'budget.table.note': 'Obs.',
'budget.table.date': 'Data',
'budget.newEntry': 'Novo lançamento',
'budget.defaultEntry': 'Novo lançamento',
'budget.defaultCategory': 'Nova categoria',
+2
View File
@@ -931,6 +931,7 @@ const cs: Record<string, string | { name: string; category: string }[]> = {
// Rozpočet (Budget)
'budget.title': 'Rozpočet',
'budget.exportCsv': 'Exportovat CSV',
'budget.emptyTitle': 'Zatím nebyl vytvořen žádný rozpočet',
'budget.emptyText': 'Vytvořte kategorie a položky pro plánování cestovního rozpočtu',
'budget.emptyPlaceholder': 'Zadejte název kategorie...',
@@ -945,6 +946,7 @@ const cs: Record<string, string | { name: string; category: string }[]> = {
'budget.table.perDay': 'Za den',
'budget.table.perPersonDay': 'Os. / den',
'budget.table.note': 'Poznámka',
'budget.table.date': 'Datum',
'budget.newEntry': 'Nová položka',
'budget.defaultEntry': 'Nová položka',
'budget.defaultCategory': 'Nová kategorie',
+2
View File
@@ -928,6 +928,7 @@ const de: Record<string, string | { name: string; category: string }[]> = {
// Budget
'budget.title': 'Budget',
'budget.exportCsv': 'CSV exportieren',
'budget.emptyTitle': 'Noch kein Budget erstellt',
'budget.emptyText': 'Erstelle Kategorien und Einträge, um dein Reisebudget zu planen',
'budget.emptyPlaceholder': 'Kategoriename eingeben...',
@@ -942,6 +943,7 @@ const de: Record<string, string | { name: string; category: string }[]> = {
'budget.table.perDay': 'Pro Tag',
'budget.table.perPersonDay': 'P. p / Tag',
'budget.table.note': 'Notiz',
'budget.table.date': 'Datum',
'budget.newEntry': 'Neuer Eintrag',
'budget.defaultEntry': 'Neuer Eintrag',
'budget.defaultCategory': 'Neue Kategorie',
+2
View File
@@ -924,6 +924,7 @@ const en: Record<string, string | { name: string; category: string }[]> = {
// Budget
'budget.title': 'Budget',
'budget.exportCsv': 'Export CSV',
'budget.emptyTitle': 'No budget created yet',
'budget.emptyText': 'Create categories and entries to plan your travel budget',
'budget.emptyPlaceholder': 'Enter category name...',
@@ -938,6 +939,7 @@ const en: Record<string, string | { name: string; category: string }[]> = {
'budget.table.perDay': 'Per Day',
'budget.table.perPersonDay': 'P. p / Day',
'budget.table.note': 'Note',
'budget.table.date': 'Date',
'budget.newEntry': 'New Entry',
'budget.defaultEntry': 'New Entry',
'budget.defaultCategory': 'New Category',
+2
View File
@@ -888,6 +888,7 @@ const es: Record<string, string> = {
// Budget
'budget.title': 'Presupuesto',
'budget.exportCsv': 'Exportar CSV',
'budget.emptyTitle': 'Aún no se ha creado ningún presupuesto',
'budget.emptyText': 'Crea categorías y entradas para planificar el presupuesto de tu viaje',
'budget.emptyPlaceholder': 'Introduce el nombre de la categoría...',
@@ -902,6 +903,7 @@ const es: Record<string, string> = {
'budget.table.perDay': 'Por día',
'budget.table.perPersonDay': 'Por pers. / día',
'budget.table.note': 'Nota',
'budget.table.date': 'Fecha',
'budget.newEntry': 'Nueva entrada',
'budget.defaultEntry': 'Nueva entrada',
'budget.defaultCategory': 'Nueva categoría',
+2
View File
@@ -927,6 +927,7 @@ const fr: Record<string, string> = {
// Budget
'budget.title': 'Budget',
'budget.exportCsv': 'Exporter CSV',
'budget.emptyTitle': 'Aucun budget créé',
'budget.emptyText': 'Créez des catégories et des entrées pour planifier votre budget de voyage',
'budget.emptyPlaceholder': 'Nom de la catégorie…',
@@ -941,6 +942,7 @@ const fr: Record<string, string> = {
'budget.table.perDay': 'Par jour',
'budget.table.perPersonDay': 'P. p / Jour',
'budget.table.note': 'Note',
'budget.table.date': 'Date',
'budget.newEntry': 'Nouvelle entrée',
'budget.defaultEntry': 'Nouvelle entrée',
'budget.defaultCategory': 'Nouvelle catégorie',
+2
View File
@@ -926,6 +926,7 @@ const hu: Record<string, string | { name: string; category: string }[]> = {
// Költségvetés
'budget.title': 'Költségvetés',
'budget.exportCsv': 'CSV exportálás',
'budget.emptyTitle': 'Még nincs költségvetés létrehozva',
'budget.emptyText': 'Hozz létre kategóriákat és bejegyzéseket az utazási költségvetés tervezéséhez',
'budget.emptyPlaceholder': 'Kategória neve...',
@@ -940,6 +941,7 @@ const hu: Record<string, string | { name: string; category: string }[]> = {
'budget.table.perDay': 'Naponta',
'budget.table.perPersonDay': 'Fő / Nap',
'budget.table.note': 'Megjegyzés',
'budget.table.date': 'Dátum',
'budget.newEntry': 'Új bejegyzés',
'budget.defaultEntry': 'Új bejegyzés',
'budget.defaultCategory': 'Új kategória',
+2
View File
@@ -926,6 +926,7 @@ const it: Record<string, string | { name: string; category: string }[]> = {
// Budget
'budget.title': 'Budget',
'budget.exportCsv': 'Esporta CSV',
'budget.emptyTitle': 'Ancora nessun budget creato',
'budget.emptyText': 'Crea categorie e voci per pianificare il budget del tuo viaggio',
'budget.emptyPlaceholder': 'Inserisci nome categoria...',
@@ -940,6 +941,7 @@ const it: Record<string, string | { name: string; category: string }[]> = {
'budget.table.perDay': 'Per giorno',
'budget.table.perPersonDay': 'P. p / gio.',
'budget.table.note': 'Nota',
'budget.table.date': 'Data',
'budget.newEntry': 'Nuova voce',
'budget.defaultEntry': 'Nuova voce',
'budget.defaultCategory': 'Nuova categoria',
+2
View File
@@ -927,6 +927,7 @@ const nl: Record<string, string> = {
// Budget
'budget.title': 'Budget',
'budget.exportCsv': 'CSV exporteren',
'budget.emptyTitle': 'Nog geen budget aangemaakt',
'budget.emptyText': 'Maak categorieën en invoeren aan om je reisbudget te plannen',
'budget.emptyPlaceholder': 'Categorienaam invoeren...',
@@ -941,6 +942,7 @@ const nl: Record<string, string> = {
'budget.table.perDay': 'Per dag',
'budget.table.perPersonDay': 'P. p. / dag',
'budget.table.note': 'Notitie',
'budget.table.date': 'Datum',
'budget.newEntry': 'Nieuwe invoer',
'budget.defaultEntry': 'Nieuwe invoer',
'budget.defaultCategory': 'Nieuwe categorie',
+2
View File
@@ -927,6 +927,7 @@ const ru: Record<string, string> = {
// Budget
'budget.title': 'Бюджет',
'budget.exportCsv': 'Экспорт CSV',
'budget.emptyTitle': 'Бюджет ещё не создан',
'budget.emptyText': 'Создайте категории и записи для планирования бюджета поездки',
'budget.emptyPlaceholder': 'Введите название категории...',
@@ -941,6 +942,7 @@ const ru: Record<string, string> = {
'budget.table.perDay': 'В день',
'budget.table.perPersonDay': 'Чел. / день',
'budget.table.note': 'Заметка',
'budget.table.date': 'Дата',
'budget.newEntry': 'Новая запись',
'budget.defaultEntry': 'Новая запись',
'budget.defaultCategory': 'Новая категория',
+2
View File
@@ -927,6 +927,7 @@ const zh: Record<string, string> = {
// Budget
'budget.title': '预算',
'budget.exportCsv': '导出 CSV',
'budget.emptyTitle': '尚未创建预算',
'budget.emptyText': '创建分类和条目来规划旅行预算',
'budget.emptyPlaceholder': '输入分类名称...',
@@ -941,6 +942,7 @@ const zh: Record<string, string> = {
'budget.table.perDay': '日均',
'budget.table.perPersonDay': '人日均',
'budget.table.note': '备注',
'budget.table.date': '日期',
'budget.newEntry': '新建条目',
'budget.defaultEntry': '新建条目',
'budget.defaultCategory': '新分类',