import { useEffect, useRef, useState } from 'react'; import { parseAmountInput } from '@kurus/shared'; import type { Category, Expense } from '../lib/api'; import { translations, getLang } from '../lib/i18n'; import { useMainButton, useHaptic } from '../hooks/useTelegramUI'; interface Props { categories: Category[]; initial?: Expense | null; defaultSpentAt?: string; onSave: (data: { amountMinor: number; categoryId: number | null; note: string | null; spentAt: string }) => Promise; onDelete?: (expense: Expense) => Promise; onClose: () => void; } /** * Alttan açılan harcama ekleme/düzenleme paneli. * Telegram MainButton'ı ile kaydeder; kendi butonunu çizmez. */ export function ExpenseSheet({ categories, initial, defaultSpentAt, onSave, onDelete, onClose }: Props) { const lang = getLang(); const t = translations[lang]; const haptic = useHaptic(); const { setMainButton } = useMainButton(); const [amountText, setAmountText] = useState( initial ? `${Math.floor(initial.amountMinor / 100)}${String(initial.amountMinor % 100).padStart(2, '0')}` : '' ); const [categoryId, setCategoryId] = useState(initial?.categoryId ?? categories[0]?.id ?? null); const [note, setNote] = useState(initial?.note ?? ''); const [spentAt, setSpentAt] = useState(initial?.spentAt ?? defaultSpentAt ?? todayStr()); const [saving, setSaving] = useState(false); const inputRef = useRef(null); const amountMinor = parseAmountInput(amountText); const canSave = amountMinor !== null && amountMinor > 0 && !saving; const handleSave = async () => { if (!canSave) return; setSaving(true); try { await onSave({ amountMinor: amountMinor!, categoryId, note: note.trim() || null, spentAt, }); haptic.success(); onClose(); } catch { haptic.impact(); } finally { setSaving(false); } }; // MainButton — save / cancel useEffect(() => { if (initial) { setMainButton(t.save, handleSave, { enabled: canSave, progress: saving }); } else { setMainButton(t.save, handleSave, { enabled: canSave, progress: saving }); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [canSave, saving, amountText, categoryId, note, spentAt]); useEffect(() => { inputRef.current?.focus(); }, []); // Canlı biçim: 1240 → 12,40 const display = amountMinor !== null ? `${Math.floor(amountMinor / 100).toLocaleString('tr-TR')},${String(amountMinor % 100).padStart(2, '0')}` : amountText; return (
e.stopPropagation()} >
{/* Tutar girişi */}
{ const v = e.target.value.replace(/[^\d]/g, '').slice(0, 12); setAmountText(v); }} />
{/* Kategori seçici */}
{categories.map((c) => ( ))}
{/* Not */} setNote(e.target.value)} /> {/* Tarih */} setSpentAt(e.target.value)} /> {/* Düzenleme modunda sil */} {initial && onDelete && ( )}
); } function todayStr(): string { const d = new Date(); return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`; } function minDateStr(): string { const d = new Date(); d.setFullYear(d.getFullYear() - 5); return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`; }