Files
kakeibo/frontend/src/features/period-wizard/schemas.ts
T
suphicakir ca0d3a505c 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>
2026-11-12 08:16:32 +03:00

56 lines
2.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { z } from 'zod'
import { moneyText } from '@/lib/money-schema'
import { daysInclusive, isIsoDate, MAX_PERIOD_DAYS } from '@/lib/period-dates'
import { t } from '@/lib/strings'
const s = t.wizard
/** 1. adım: dönem tarihleri. `last` = son gün (dahil). */
export const datesSchema = z
.object({
start: z.string(),
last: z.string(),
name: z.string().trim().max(60, s.dates.nameTooLong),
})
.superRefine((v, ctx) => {
if (!isIsoDate(v.start)) {
ctx.addIssue({ code: 'custom', path: ['start'], message: s.dates.startRequired })
}
if (!isIsoDate(v.last)) {
ctx.addIssue({ code: 'custom', path: ['last'], message: s.dates.lastRequired })
return
}
if (!isIsoDate(v.start)) return
if (v.last < v.start) {
ctx.addIssue({ code: 'custom', path: ['last'], message: s.dates.lastBeforeStart })
} else if (daysInclusive(v.start, v.last) > MAX_PERIOD_DAYS) {
ctx.addIssue({ code: 'custom', path: ['last'], message: s.dates.tooLong(MAX_PERIOD_DAYS) })
}
})
export type DatesForm = z.infer<typeof datesSchema>
/** 2–3. adım: gelir / gider kalemi. Tarih boş olabilir; doluysa dönem içinde olmalı. */
export function itemSchema(start: string, last: string) {
return z.object({
name: z.string().trim().min(1, s.items.nameRequired).max(60, s.items.nameTooLong),
amount: moneyText('positive'),
date: z
.string()
.refine((d) => d === '' || (isIsoDate(d) && d >= start && d <= last), s.items.dateOutside),
})
}
export type ItemForm = z.infer<ReturnType<typeof itemSchema>>
/** 4. adım */
export const savingsSchema = z.object({ goal: moneyText('optional') })
export type SavingsForm = z.infer<typeof savingsSchema>
/** 5. adım: 4 grubun aylık bütçesi */
export const budgetSchema = z.object({
needs: moneyText('optional'),
wants: moneyText('optional'),
culture: moneyText('optional'),
unexpected: moneyText('optional'),
})
export type BudgetForm = z.infer<typeof budgetSchema>