import { useState } from 'react' import { CircleCheck, Landmark, Loader2, Pencil, Plus } from 'lucide-react' import { Link } from 'react-router' import { toast } from 'sonner' import { FormError } from '@/components/form-field' import { paths } from '@/components/layout/nav-items' import { MoneyInput } from '@/components/money-input' import { Button } from '@/components/ui/button' import { findInstallmentItem, usePeriodDebt, useSetOpeningDebt } from '@/lib/debt' import { formatDate, formatMoney, formatNumber, parseMoney } from '@/lib/format' import { useCreatePlanItem } from '@/lib/periods' import { t } from '@/lib/strings' import { cn } from '@/lib/utils' import type { Period } from '@/types/Period' import type { PeriodDebt } from '@/types/PeriodDebt' import type { PlanItem } from '@/types/PlanItem' const s = t.debt.period /** * Aylık plan: bu ayın banka borcu (docs/BORC_TAKIBI.md §3). Ay başı borç son ölçümden * (elle düzeltilebilir), devreden, borç ödemesi (= birikim hedefi), taksit yükü, hedef ay sonu. * Borç takibinde hiç veri yoksa görünmez. */ export function PeriodDebtSection({ period, items, writable, }: { period: Period items: PlanItem[] writable: boolean }) { const q = usePeriodDebt(period.id) const d = q.data if (!d || (d.opening_total === null && d.installment_load === 0)) return null return (

{s.title}

{s.toDebt}

{s.hint}

{writable && ( )}
) } function Tile({ label, amount, sign, hint, }: { label: string amount: number | null sign?: string hint?: string }) { return (
{sign && {sign} } {label}
{amount === null ? '—' : formatMoney(amount)}
{hint &&

{hint}

}
) } /** Ay başı borç: kaynağı yazılı; düzeltilebilir (dönem açıkken) */ function Opening({ period, d, writable }: { period: Period; d: PeriodDebt; writable: boolean }) { const set = useSetOpeningDebt(period.id) const [editing, setEditing] = useState(false) const [value, setValue] = useState('') const [error, setError] = useState() const source = d.opening_source === 'manual' ? s.manual : d.opening_date ? s.fromSnapshot(formatDate(d.opening_date)) : s.noOpening async function save(amount: number | null) { setError(undefined) try { await set.mutateAsync(amount) setEditing(false) toast.success(s.openingSaved) } catch (e) { setError(e instanceof Error ? e.message : String(e)) } } return (
{s.opening} {writable && !editing && ( )}
{editing ? (
{d.opening_source === 'manual' && ( )}
) : ( <>
{d.opening_total === null ? '—' : formatMoney(d.opening_total)}

{source}

)}
) } /** Hedef ay sonu borç (+ yol haritasıyla karşılaştırma) */ function Target({ d }: { d: PeriodDebt }) { const diff = d.closing_target !== null && d.roadmap_target !== null ? d.closing_target - d.roadmap_target : null return (
= {s.target}
{d.closing_target === null ? '—' : formatMoney(d.closing_target)}
{d.roadmap_target !== null && (

{s.roadmap(formatMoney(d.roadmap_target))} {diff !== null && diff !== 0 && ( 0 ? 'text-expense' : 'text-income'}> {' · '} {diff > 0 ? s.vsRoadmapAbove(formatMoney(diff)) : s.vsRoadmapBelow(formatMoney(-diff))} )}

)}
) } /** Aylık başarı: ay başı − son ölçüm ≥ borç ödemesi + taksit */ function Progress({ d }: { d: PeriodDebt }) { if (d.opening_total === null || d.latest_total === null || !d.latest_date) return null const down = d.opening_total - d.latest_total const needed = d.payment + d.installment_load const ok = down >= needed && needed > 0 const ratio = needed > 0 ? Math.min(Math.max(down / needed, 0), 1) : 0 return (

{s.progressTitle(formatDate(d.latest_date))}

{ok && } {down >= 0 ? s.paidDown(formatMoney(down)) : s.grew(formatMoney(-down))} {' '} · {s.needed(formatMoney(needed))}

) } /** Taksit yükü planda "Taksitler" sabit gideri olarak yoksa: tek tıkla ekle */ function InstallmentsSuggestion({ period, items, load, }: { period: Period items: PlanItem[] load: number }) { const create = useCreatePlanItem(period.id) if (load <= 0) return null const existing = findInstallmentItem(items) if (existing) { if (existing.amount === load) return null return (

{s.installmentsMismatch(formatMoney(existing.amount), formatMoney(load))}

) } return ( ) }