'use client'; 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; selectedEntry?: AusgabenEntry | null; typ: number; // 0 = Haushalt, 1 = Privat } export default function AusgabenForm({ onSuccess, selectedEntry, typ }: AusgabenFormProps) { const zahlungsarten = typ === 0 ? ZAHLUNGSARTEN_HAUSHALT : ZAHLUNGSARTEN_PRIVAT; const defaultZahlungsart = typ === 0 ? 'ECR' : 'bar'; const [formData, setFormData] = useState({ Datum: '', WochTag: '', Wo: '', Was: '', Kat: 'L', Wieviel: '', Wie: defaultZahlungsart, TYP: typ, }); const [isSubmitting, setIsSubmitting] = useState(false); const [editId, setEditId] = useState(null); // Monthly stats const [stats, setStats] = useState(null); const [month, setMonth] = useState(''); const [year, setYear] = useState(''); const [isLoadingStats, setIsLoadingStats] = useState(false); // Autocomplete data const [autoCompleteWo, setAutoCompleteWo] = useState([]); const [autoCompleteWas, setAutoCompleteWas] = useState([]); const [categories, setCategories] = useState([]); const [katDropdownOpen, setKatDropdownOpen] = useState(false); const katDropdownRef = useRef(null); const fetchStats = useCallback(async (y: string, m: string) => { if (!y || !m) return; setIsLoadingStats(true); try { const response = await fetch(`/api/ausgaben/stats?year=${y}&month=${m}&typ=${typ}`); const data = await response.json(); if (data.success) { setStats(data.data); } } catch (error) { console.error('Error fetching stats:', error); } finally { setIsLoadingStats(false); } }, [typ]); const fetchAutoComplete = useCallback(async () => { try { const response = await fetch(`/api/ausgaben/autocomplete?typ=${typ}`); const data = await response.json(); if (data.success) { setAutoCompleteWo(data.data.wo); setAutoCompleteWas(data.data.was); } } catch (error) { console.error('Error fetching autocomplete data:', error); } }, [typ]); // Initialize month/year on first load useEffect(() => { const now = new Date(); const currentMonth = String(now.getMonth() + 1).padStart(2, '0'); const currentYear = String(now.getFullYear()); setMonth(currentMonth); setYear(currentYear); }, []); // Fetch stats when month, year, or typ changes useEffect(() => { if (month && year) { fetchStats(year, month); } }, [month, year, typ, fetchStats]); // Fetch autocomplete data when typ changes useEffect(() => { 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); }; const handleYearChange = (newYear: string) => { setYear(newYear); }; const formatAmount = (amount: number | null) => { if (amount === null || amount === undefined) return '0,00 €'; return new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR', }).format(amount); }; useEffect(() => { if (selectedEntry) { // Load selected entry for editing const dateStr = selectedEntry.Datum.toString().split('T')[0]; setFormData({ Datum: dateStr, WochTag: selectedEntry.WochTag, Wo: selectedEntry.Wo, Was: selectedEntry.Was, Kat: selectedEntry.Kat || 'L', Wieviel: selectedEntry.Wieviel.toString(), Wie: selectedEntry.Wie, TYP: selectedEntry.TYP, }); // Handle both uppercase and lowercase ID field names const entryId = (selectedEntry as any).id || selectedEntry.ID; setEditId(entryId); } else { // Reset form for new entry const now = new Date(); const dateStr = now.toISOString().split('T')[0]; const weekday = getWeekday(now); setFormData({ Datum: dateStr, WochTag: weekday, Wo: '', Was: '', Kat: 'L', Wieviel: '', Wie: defaultZahlungsart, TYP: typ, }); setEditId(null); } }, [selectedEntry]); // Update TYP when tab changes useEffect(() => { if (!selectedEntry) { setFormData(prev => ({ ...prev, TYP: typ, Wie: defaultZahlungsart, })); } }, [typ]); const getWeekday = (date: Date): string => { const weekdays = ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag']; return weekdays[date.getDay()]; }; const handleDateChange = (dateStr: string) => { const [year, month, day] = dateStr.split('-'); const date = new Date(Number(year), Number(month) - 1, Number(day)); const weekday = getWeekday(date); setFormData(prev => ({ ...prev, Datum: dateStr, WochTag: weekday })); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!formData.Wo || !formData.Was || !formData.Wieviel) { alert('Bitte alle Pflichtfelder ausfüllen!'); return; } setIsSubmitting(true); try { const url = editId ? `/api/ausgaben/${editId}` : '/api/ausgaben'; const method = editId ? 'PUT' : 'POST'; // Send only the fields we need, excluding any extra fields const dataToSend = { Datum: formData.Datum, Wo: formData.Wo, Was: formData.Was, Kat: formData.Kat, Wieviel: formData.Wieviel, Wie: formData.Wie, TYP: formData.TYP, }; const response = await fetch(url, { method: method, headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(dataToSend), }); if (response.ok) { handleReset(); onSuccess(); // Refresh stats after successful save fetchStats(year, month); } else { alert('Fehler beim Speichern!'); } } catch (error) { console.error('Error:', error); alert('Fehler beim Speichern!'); } finally { setIsSubmitting(false); } }; const handleReset = () => { const now = new Date(); const dateStr = now.toISOString().split('T')[0]; const weekday = getWeekday(now); setFormData({ Datum: dateStr, WochTag: weekday, Wo: '', Was: '', Kat: 'L', Wieviel: '', Wie: defaultZahlungsart, TYP: typ, }); setEditId(null); }; return (
{editId && (
ℹ️ Bearbeitungsmodus: Sie bearbeiten einen bestehenden Eintrag.
)}
Datum Wo Was Kat. Wieviel Wie
handleDateChange(e.target.value)} className="w-full px-2 py-1 text-base rounded border-2 border-gray-400 bg-white focus:border-blue-500 focus:outline-none" required /> setFormData({ ...formData, Wo: e.target.value })} className="w-full px-2 py-1 text-base rounded border-2 border-gray-400 bg-white focus:border-blue-500 focus:outline-none" placeholder="Geschäft/Ort" list="wo-suggestions" required /> {autoCompleteWo.map((wo, index) => ( setFormData({ ...formData, Was: e.target.value })} className="w-full px-2 py-1 text-base rounded border-2 border-gray-400 bg-white focus:border-blue-500 focus:outline-none" placeholder="Beschreibung" list="was-suggestions" required /> {autoCompleteWas.map((was, index) => (
{katDropdownOpen && (
    {categories.map((cat) => (
  • { setFormData({ ...formData, Kat: cat.value }); setKatDropdownOpen(false); }} > {cat.value} - {cat.label}
  • ))}
)}
setFormData({ ...formData, Wieviel: e.target.value })} className="w-full px-2 py-1 text-base rounded border-2 border-gray-400 bg-white focus:border-blue-500 focus:outline-none [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none" placeholder="0.00" required />
{/* Wochentag */}
{formData.WochTag}
{/* Buttons */}
{/* Monatsstatistiken */}
handleYearChange(e.target.value)} className="border border-gray-400 rounded px-3 py-1 w-24" min="2013" max="2099" />
{isLoadingStats ? ( Lade... ) : stats ? ( Summe: {formatAmount(stats.totalAusgaben)} ) : null}
); }