Kategorien dazu

This commit is contained in:
2026-03-01 11:26:44 +00:00
parent 319ac8699e
commit ed6bc21248
8 changed files with 126 additions and 14 deletions

View File

@@ -1,7 +1,8 @@
'use client';
import { useState, useEffect, useCallback } from 'react';
import { useState, useEffect, useCallback, useRef } from 'react';
import { CreateAusgabenEntry, AusgabenEntry, ZAHLUNGSARTEN_HAUSHALT, ZAHLUNGSARTEN_PRIVAT, MonthlyStats } from '@/types/ausgaben';
import { Category } from '@/app/api/categories/route';
interface AusgabenFormProps {
onSuccess: () => void;
@@ -18,6 +19,7 @@ export default function AusgabenForm({ onSuccess, selectedEntry, typ }: Ausgaben
WochTag: '',
Wo: '',
Was: '',
Kat: 'L',
Wieviel: '',
Wie: defaultZahlungsart,
TYP: typ,
@@ -35,6 +37,9 @@ export default function AusgabenForm({ onSuccess, selectedEntry, typ }: Ausgaben
// Autocomplete data
const [autoCompleteWo, setAutoCompleteWo] = useState<string[]>([]);
const [autoCompleteWas, setAutoCompleteWas] = useState<string[]>([]);
const [categories, setCategories] = useState<Category[]>([]);
const [katDropdownOpen, setKatDropdownOpen] = useState(false);
const katDropdownRef = useRef<HTMLDivElement>(null);
const fetchStats = useCallback(async (y: string, m: string) => {
if (!y || !m) return;
@@ -87,6 +92,25 @@ export default function AusgabenForm({ onSuccess, selectedEntry, typ }: Ausgaben
fetchAutoComplete();
}, [typ, fetchAutoComplete]);
// Close Kat dropdown when clicking outside
useEffect(() => {
const handleClickOutside = (e: MouseEvent) => {
if (katDropdownRef.current && !katDropdownRef.current.contains(e.target as Node)) {
setKatDropdownOpen(false);
}
};
document.addEventListener('mousedown', handleClickOutside);
return () => document.removeEventListener('mousedown', handleClickOutside);
}, []);
// Fetch categories once on mount
useEffect(() => {
fetch('/api/categories')
.then((r) => r.json())
.then((data) => { if (data.success) setCategories(data.data); })
.catch(() => {});
}, []);
const handleMonthChange = (newMonth: string) => {
setMonth(newMonth);
};
@@ -113,6 +137,7 @@ export default function AusgabenForm({ onSuccess, selectedEntry, typ }: Ausgaben
WochTag: selectedEntry.WochTag,
Wo: selectedEntry.Wo,
Was: selectedEntry.Was,
Kat: selectedEntry.Kat || 'L',
Wieviel: selectedEntry.Wieviel.toString(),
Wie: selectedEntry.Wie,
TYP: selectedEntry.TYP,
@@ -132,6 +157,7 @@ export default function AusgabenForm({ onSuccess, selectedEntry, typ }: Ausgaben
WochTag: weekday,
Wo: '',
Was: '',
Kat: 'L',
Wieviel: '',
Wie: defaultZahlungsart,
TYP: typ,
@@ -184,6 +210,7 @@ export default function AusgabenForm({ onSuccess, selectedEntry, typ }: Ausgaben
Datum: formData.Datum,
Wo: formData.Wo,
Was: formData.Was,
Kat: formData.Kat,
Wieviel: formData.Wieviel,
Wie: formData.Wie,
TYP: formData.TYP,
@@ -223,6 +250,7 @@ export default function AusgabenForm({ onSuccess, selectedEntry, typ }: Ausgaben
WochTag: weekday,
Wo: '',
Was: '',
Kat: 'L',
Wieviel: '',
Wie: defaultZahlungsart,
TYP: typ,
@@ -247,6 +275,7 @@ export default function AusgabenForm({ onSuccess, selectedEntry, typ }: Ausgaben
<th className="p-2 w-32">Datum</th>
<th className="p-2">Wo</th>
<th className="p-2">Was</th>
<th className="p-2 w-12">Kat.</th>
<th className="p-2 w-24">Wieviel</th>
<th className="p-2 w-4"></th>
<th className="p-2 w-38 text-left">Wie</th>
@@ -295,6 +324,35 @@ export default function AusgabenForm({ onSuccess, selectedEntry, typ }: Ausgaben
))}
</datalist>
</td>
<td className="p-2 w-12">
<div ref={katDropdownRef} className="relative w-full">
<button
type="button"
onClick={() => setKatDropdownOpen((o) => !o)}
className="w-full px-2 py-1 text-base text-left rounded border-2 border-gray-400 bg-white focus:border-blue-500 focus:outline-none"
>
{formData.Kat}
</button>
{katDropdownOpen && (
<ul className="absolute z-50 left-0 mt-1 w-48 bg-white border-2 border-gray-400 rounded shadow-lg max-h-60 overflow-y-auto text-left">
{categories.map((cat) => (
<li
key={cat.value}
className={`px-3 py-1 cursor-pointer hover:bg-blue-100 text-sm ${
formData.Kat === cat.value ? 'bg-blue-50 font-semibold' : ''
}`}
onMouseDown={() => {
setFormData({ ...formData, Kat: cat.value });
setKatDropdownOpen(false);
}}
>
{cat.value} - {cat.label}
</li>
))}
</ul>
)}
</div>
</td>
<td className="p-2 w-24">
<input
type="number"

View File

@@ -29,12 +29,7 @@ export default function AusgabenList({ entries, onDelete, onEdit }: AusgabenList
};
const formatDate = (dateStr: string) => {
const date = new Date(dateStr);
return date.toLocaleDateString('de-DE', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
});
return dateStr.toString().split('T')[0];
};
const formatAmount = (amount: number) => {
@@ -53,6 +48,7 @@ export default function AusgabenList({ entries, onDelete, onEdit }: AusgabenList
<th className="border-b-2 border-black p-2 w-12">Tag</th>
<th className="border-b-2 border-black p-2 w-36">Wo</th>
<th className="border-b-2 border-black p-2 w-48">Was</th>
<th className="border-b-2 border-black p-2 w-12">Kat.</th>
<th className="border-b-2 border-black p-2 w-8">Betrag</th>
<th className="border-b-2 border-black p-2 w-16">Wie</th>
<th className="border-b-2 border-black p-2 w-38">Aktion</th>
@@ -61,7 +57,7 @@ export default function AusgabenList({ entries, onDelete, onEdit }: AusgabenList
<tbody>
{entries.length === 0 ? (
<tr>
<td colSpan={7} className="text-center p-4 text-gray-500">
<td colSpan={8} className="text-center p-4 text-gray-500">
Keine Einträge vorhanden
</td>
</tr>
@@ -74,6 +70,7 @@ export default function AusgabenList({ entries, onDelete, onEdit }: AusgabenList
<td className="border-y border-black p-2 text-center">{entry.WochTag.slice(0, 2)}</td>
<td className="border-y border-black p-2">{entry.Wo}</td>
<td className="border-y border-black p-2">{entry.Was}</td>
<td className="border-y border-black p-2 text-center">{entry.Kat}</td>
<td className="border-y border-black p-2 text-right">
{formatAmount(entry.Wieviel)}
</td>