import { useState } from 'react' import { zodResolver } from '@hookform/resolvers/zod' import { Loader2, Sparkles } from 'lucide-react' import { Controller, useForm, useWatch } from 'react-hook-form' import { FormError, FormField } from '@/components/form-field' import { MoneyInput } from '@/components/money-input' import { PageError, PageLoading } from '@/components/page' import { Button } from '@/components/ui/button' import { SummaryTiles } from '@/features/planning/summary-tiles' import { ApiError } from '@/lib/api' import { formatMoney, formatNumber, parseMoney } from '@/lib/format' import { GROUPS } from '@/lib/groups' import { toKurus } from '@/lib/money-schema' import { useBudget, useSetBudget, useSuggestion, useSummary } from '@/lib/periods' import { t } from '@/lib/strings' import { cn } from '@/lib/utils' import type { GroupAmounts } from '@/types/GroupAmounts' import type { Period } from '@/types/Period' import type { PeriodSummary } from '@/types/PeriodSummary' import type { SuggestMethod } from '@/types/SuggestMethod' import { budgetSchema, type BudgetForm } from './schemas' import { StepActions, StepIntro } from './wizard-ui' const s = t.wizard.budget const METHODS: SuggestMethod[] = ['default', 'previous', 'avg3'] function toForm(a: GroupAmounts): BudgetForm { const f = (k: number) => (k ? formatNumber(k / 100) : '') return { needs: f(a.needs), wants: f(a.wants), culture: f(a.culture), unexpected: f(a.unexpected), } } /** * 5. adım: harcanabilir tutarı 4 gruba dağıt. * Daha önce bütçe girilmişse o gösterilir; yoksa varsayılan öneriyle doldurulur. */ export function StepBudget({ period, onBack, onDone, }: { period: Period onBack: () => void onDone: () => void }) { const summary = useSummary(period.id) const budget = useBudget(period.id) const suggestion = useSuggestion(period.id, 'default') const queries = [summary, budget, suggestion] const failed = queries.find((q) => q.isError) if (failed?.error) return if (!summary.data || !budget.data || !suggestion.data) return const saved = Object.fromEntries(budget.data.map((g) => [g.group, g.monthly])) as GroupAmounts const hasSaved = budget.data.some((g) => g.monthly > 0) return ( ) } function BudgetStepForm({ period, summary, initial, onBack, onDone, }: { period: Period summary: PeriodSummary initial: BudgetForm onBack: () => void onDone: () => void }) { const setBudget = useSetBudget(period.id) const [method, setMethod] = useState('default') const suggestion = useSuggestion(period.id, method) const { control, handleSubmit, reset, setError, formState: { errors, isSubmitting }, } = useForm({ resolver: zodResolver(budgetSchema), mode: 'onTouched', defaultValues: initial, }) const values = useWatch({ control }) const distributed = GROUPS.reduce( (sum, g) => sum + Math.max(parseMoney(values[g.code] ?? '') ?? 0, 0), 0, ) const remaining = summary.spendable - distributed const onSubmit = handleSubmit(async (v) => { try { await setBudget.mutateAsync({ needs: toKurus(v.needs), wants: toKurus(v.wants), culture: toKurus(v.culture), unexpected: toKurus(v.unexpected), }) onDone() } catch (e) { setError('root', { message: e instanceof ApiError ? e.message : String(e) }) } }) return (
{/* Öneri seçimi */}
{s.method}
{METHODS.map((m) => ( ))}
{suggestion.isPending ? ( ) : suggestion.data?.available ? ( ) : (

{suggestion.data?.message ?? suggestion.error?.message}

)}
{/* 4 grup */}
{GROUPS.map((g) => ( {(f) => (
( )} />

{g.description}

)}
))}
{/* Dağıtım durumu */}
{s.distributed} {formatMoney(distributed)} / {formatMoney(summary.spendable)}
0 ? Math.min(100, (distributed / summary.spendable) * 100) : 0}%`, }} />

{remaining < 0 ? s.over(formatMoney(-remaining)) : remaining > 0 ? s.unallocated(formatMoney(remaining)) : s.balanced}

) }