feat(plan): ilk dönem sihirbazı (dönem, gelir, gider, birikim, bütçe)
- /plan/donem-ac?adim=1..5: her adım hemen kaydedilir, adım adreste - Panel ve Plan'da açık dönem yoksa "Dönemi başlat" kartı - MoneyInput (sayısal klavye, Türkçe biçim), moneyText/toKurus, period-dates - lib/periods.ts: dönem, plan kalemi, özet, bütçe ve öneri kancaları - SummaryTiles, PageLoading/PageError; 13 yeni vitest Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Formlarda tutar alanı: kullanıcı metin yazar (`1.250,50`), doğrulama `parseMoney` ile yapılır.
|
||||
* Gönderirken `toKurus(metin)` ile kuruşa çevrilir.
|
||||
*/
|
||||
import { z } from 'zod'
|
||||
import { parseMoney } from './format'
|
||||
|
||||
/** Backend ile aynı üst sınır (`services/period.rs` → `MAX_AMOUNT`): 100 milyar ₺ */
|
||||
export const MAX_AMOUNT_KURUS = 10_000_000_000_000
|
||||
|
||||
export const moneyMessages = {
|
||||
required: 'Tutarı yazın',
|
||||
invalid: 'Geçerli bir tutar yazın (ör. 1.250,50)',
|
||||
positive: 'Tutar sıfırdan büyük olmalı',
|
||||
negative: 'Tutar eksi olamaz',
|
||||
tooLarge: 'Tutar çok büyük',
|
||||
}
|
||||
|
||||
/**
|
||||
* - `positive`: 0'dan büyük olmalı (gelir/gider kalemi)
|
||||
* - `optional`: boş bırakılabilir → 0 sayılır (birikim hedefi, bütçe)
|
||||
*/
|
||||
export function moneyText(mode: 'positive' | 'optional') {
|
||||
return z
|
||||
.string()
|
||||
.trim()
|
||||
.superRefine((value, ctx) => {
|
||||
if (value === '') {
|
||||
if (mode === 'positive') ctx.addIssue({ code: 'custom', message: moneyMessages.required })
|
||||
return
|
||||
}
|
||||
const k = parseMoney(value)
|
||||
if (k === null) return ctx.addIssue({ code: 'custom', message: moneyMessages.invalid })
|
||||
if (k < 0) return ctx.addIssue({ code: 'custom', message: moneyMessages.negative })
|
||||
if (mode === 'positive' && k === 0)
|
||||
return ctx.addIssue({ code: 'custom', message: moneyMessages.positive })
|
||||
if (k > MAX_AMOUNT_KURUS) ctx.addIssue({ code: 'custom', message: moneyMessages.tooLarge })
|
||||
})
|
||||
}
|
||||
|
||||
/** Doğrulanmış metin → kuruş (boş → 0) */
|
||||
export function toKurus(value: string): number {
|
||||
return parseMoney(value) ?? 0
|
||||
}
|
||||
Reference in New Issue
Block a user