feat(değerlendirme): ay sonu değerlendirmesi sayfası

- Kakeibo'nun 4 sorusu, nasıl hesaplandığıyla birlikte
- Grup bazında planlanan/gerçekleşen, en çok harcanan kategoriler, haftalık dağılım
- "Nasıl daha iyi yapabilirim?" (Markdown) ve yalnızca başlıkları listelenen notlar

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-12 12:31:35 +03:00
parent 62e92f552a
commit 311cfc8c60
16 changed files with 627 additions and 56 deletions
+26
View File
@@ -0,0 +1,26 @@
/**
* Değerlendirme sayfasının saf hesapları. Tutarlar backend'den gelir (`PeriodReview`);
* burada yalnızca yorum (durum, oran) yapılır.
*/
import type { PeriodReview } from '@/types/PeriodReview'
/** 4. soru: birikim hedefe göre nerede? */
export type SavingsStatus =
| { kind: 'above'; amount: number } // hedefe ulaşıldı/aşıldı (amount ≥ 0)
| { kind: 'below'; amount: number } // birikim var ama hedefin altında
| { kind: 'deficit'; amount: number } // açık var → borç olarak devreder
export function savingsStatus(
r: Pick<PeriodReview, 'realized_savings' | 'savings_gap'>,
): SavingsStatus {
if (r.realized_savings < 0) return { kind: 'deficit', amount: -r.realized_savings }
if (r.savings_gap < 0) return { kind: 'below', amount: -r.savings_gap }
return { kind: 'above', amount: r.savings_gap }
}
/** Oran (0–1); payda 0 ise pay varsa 1, yoksa 0. Çubuk genişliği için 1'de kesilir. */
export function ratio(part: number, total: number, cap = true): number {
if (total <= 0) return part > 0 ? 1 : 0
const r = part / total
return cap ? Math.min(r, 1) : r
}