- Rewrite BudgetSetup to use month picker + currency + Generate button - Remove manual form fields (name, dates, carryover, copy-from select) - Handle 409 conflict gracefully by calling onCreated() to refresh list - Remove copyFrom method from budgets API (TMPL-06) - Update BudgetSetup test to reflect new month-picker UI - Remove copyFrom from DashboardPage test mock - Add budget.generate, budget.month, budget.generating i18n keys (EN/DE) - Remove budget.copyFrom and budget.setup i18n keys
62 lines
2.2 KiB
TypeScript
62 lines
2.2 KiB
TypeScript
import { useState } from 'react'
|
|
import { useTranslation } from 'react-i18next'
|
|
import { Card, CardContent, CardHeader, CardTitle, CardFooter } from '@/components/ui/card'
|
|
import { Button } from '@/components/ui/button'
|
|
import { Input } from '@/components/ui/input'
|
|
import { Spinner } from '@/components/ui/spinner'
|
|
import { budgets as budgetsApi, type Budget, ApiError } from '@/lib/api'
|
|
|
|
interface Props {
|
|
existingBudgets: Budget[]
|
|
onCreated: () => void
|
|
onCancel: () => void
|
|
}
|
|
|
|
export function BudgetSetup({ existingBudgets: _existingBudgets, onCreated, onCancel }: Props) {
|
|
const { t } = useTranslation()
|
|
const [month, setMonth] = useState('')
|
|
const [currency, setCurrency] = useState('EUR')
|
|
const [saving, setSaving] = useState(false)
|
|
|
|
const handleGenerate = async () => {
|
|
setSaving(true)
|
|
try {
|
|
await budgetsApi.generate({ month, currency })
|
|
onCreated()
|
|
} catch (err) {
|
|
if (err instanceof ApiError && err.status === 409) {
|
|
// Budget already exists for this month — navigate to it by refreshing the list
|
|
onCreated()
|
|
} else {
|
|
throw err
|
|
}
|
|
} finally {
|
|
setSaving(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<Card>
|
|
<CardHeader className="bg-gradient-to-r from-violet-50 to-purple-50">
|
|
<CardTitle>{t('budget.generate')}</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="flex flex-col gap-4 pt-4">
|
|
<div className="flex flex-col gap-2">
|
|
<label className="text-sm font-medium">{t('budget.month')}</label>
|
|
<Input type="month" value={month} onChange={(e) => setMonth(e.target.value)} />
|
|
</div>
|
|
<div className="flex flex-col gap-2">
|
|
<label className="text-sm font-medium">{t('budget.currency')}</label>
|
|
<Input value={currency} onChange={(e) => setCurrency(e.target.value)} />
|
|
</div>
|
|
</CardContent>
|
|
<CardFooter className="flex gap-2 justify-end">
|
|
<Button variant="outline" onClick={onCancel}>{t('common.cancel')}</Button>
|
|
<Button onClick={handleGenerate} disabled={saving || !month} className="min-w-[160px]">
|
|
{saving ? <Spinner /> : t('budget.generate')}
|
|
</Button>
|
|
</CardFooter>
|
|
</Card>
|
|
)
|
|
}
|