feat(defter): haftanın girişleri, düzenle/sil + geri al, haftalık özet

- Girişler gün gün, gün toplamıyla; satırda kategori, grup, ödeme türü, açıklama
- Düzenleme aynı formda (sürüm kontrolü, pasif kategori korunur)
- Silmede "Geri al" bildirimi; grup bazlı bütçe / harcanan / kalan özeti

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-12 11:29:33 +03:00
parent f930f2fbcc
commit 16535ad7f3
13 changed files with 472 additions and 62 deletions
@@ -0,0 +1,55 @@
import { formatMoney } from '@/lib/format'
import { group } from '@/lib/groups'
import { t } from '@/lib/strings'
import { cn } from '@/lib/utils'
import type { GroupBudget } from '@/types/GroupBudget'
const s = t.ledger
/** Seçili haftada grup bazlı bütçe / harcanan / kalan (+ ilerleme çubuğu) */
export function WeekSummary({ budget, index }: { budget: GroupBudget[]; index: number }) {
return (
<div className="@container">
<ul className="grid gap-3 @lg:grid-cols-2">
{budget.map((b) => {
const g = group(b.group)
const w = b.weeks[index - 1]
const planned = w?.amount ?? 0
const spent = w?.spent ?? 0
const left = planned - spent
const over = left < 0
const ratio = planned > 0 ? Math.min(spent / planned, 1) : spent > 0 ? 1 : 0
return (
<li key={b.group} className="rounded-xl border p-3">
<div className="flex flex-wrap items-center justify-between gap-x-2">
<span className={cn('font-medium whitespace-nowrap', g.className.text)}>
<span aria-hidden>{g.emoji}</span> {g.label}
</span>
<span className={cn('money text-sm font-semibold', over && 'text-expense')}>
{over ? `${s.over} ${formatMoney(-left)}` : `${s.left} ${formatMoney(left)}`}
</span>
</div>
<div
className="my-2 h-2 overflow-hidden rounded-full bg-muted"
role="progressbar"
aria-label={`${g.label}: ${s.spent}`}
aria-valuemin={0}
aria-valuemax={100}
aria-valuenow={Math.round(ratio * 100)}
>
<div
className={cn('h-full rounded-full', over ? 'bg-expense' : g.className.fill)}
style={{ width: `${ratio * 100}%` }}
/>
</div>
<p className="text-xs text-muted-foreground">
{s.spent} <span className="money">{formatMoney(spent)}</span> / {s.budget}{' '}
<span className="money">{formatMoney(planned)}</span>
</p>
</li>
)
})}
</ul>
</div>
)
}