'use client' import { useState, useMemo } from 'react' import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, } from '@/components/ui/dialog' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { useToast } from '@/components/ui/use-toast' import { Loader2 } from 'lucide-react' import type { FiscalPeriod } from '@/types' interface Props { open: boolean onOpenChange: (open: boolean) => void entryDate: string periods: FiscalPeriod[] onCreated: () => void } function computeSuggestedPeriod(entryDate: string, periods: FiscalPeriod[]) { if (periods.length === 0) { // No periods at all — suggest a calendar year period around the entry date const year = entryDate.split('-')[0] return { name: `FY ${year}`, period_start: `${year}-01-01`, period_end: `${year}-12-31`, } } const sorted = [...periods].sort((a, b) => a.period_start.localeCompare(b.period_start)) const earliest = sorted[0] const latest = sorted[sorted.length - 1] if (entryDate < earliest.period_start) { // Backward: end = day before earliest start, start = 12 months back, 1st of month const end = new Date(earliest.period_start + 'T00:00:00') end.setDate(end.getDate() - 1) const start = new Date(end) start.setMonth(start.getMonth() - 11) start.setDate(1) const startStr = start.toISOString().split('T')[0] const endStr = end.toISOString().split('T')[0] const startYear = start.getFullYear() const endYear = end.getFullYear() const name = startYear === endYear ? `FY ${startYear}` : `FY ${startYear}/${endYear}` return { name, period_start: startStr, period_end: endStr } } // Forward: start = day after latest end, end = 12 months later (last day of month) const start = new Date(latest.period_end + 'T00:00:00') start.setDate(start.getDate() + 1) const end = new Date(start) end.setMonth(end.getMonth() + 12) end.setDate(0) // Last day of previous month const startStr = start.toISOString().split('T')[0] const endStr = end.toISOString().split('T')[0] const startYear = start.getFullYear() const endYear = end.getFullYear() const name = startYear === endYear ? `FY ${startYear}` : `FY ${startYear}/${endYear}` return { name, period_start: startStr, period_end: endStr } } export default function CreatePeriodDialog({ open, onOpenChange, entryDate, periods, onCreated }: Props) { const { toast } = useToast() const suggested = useMemo(() => computeSuggestedPeriod(entryDate, periods), [entryDate, periods]) const [name, setName] = useState(suggested.name) const [periodStart, setPeriodStart] = useState(suggested.period_start) const [periodEnd, setPeriodEnd] = useState(suggested.period_end) const [isSubmitting, setIsSubmitting] = useState(false) // Reset form when suggested values change (dialog reopened with new date) const [lastSuggested, setLastSuggested] = useState(suggested) if (suggested.name !== lastSuggested.name || suggested.period_start !== lastSuggested.period_start) { setName(suggested.name) setPeriodStart(suggested.period_start) setPeriodEnd(suggested.period_end) setLastSuggested(suggested) } const handleCreate = async () => { setIsSubmitting(true) try { const res = await fetch('/api/bookkeeping/fiscal-periods', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name, period_start: periodStart, period_end: periodEnd }), }) const result = await res.json() if (!res.ok) { toast({ title: 'Kunde inte skapa räkenskapsår', description: result.error || 'Ett oväntat fel uppstod.', variant: 'destructive', }) return } toast({ title: 'Räkenskapsår skapat', description: `${name} har skapats.` }) onOpenChange(false) onCreated() } catch { toast({ title: 'Kunde inte skapa räkenskapsår', description: 'Ett nätverksfel uppstod. Försök igen.', variant: 'destructive', }) } finally { setIsSubmitting(false) } } return ( Skapa räkenskapsår Det finns inget räkenskapsår som täcker datumet {entryDate}. Skapa ett nytt nedan.
setName(e.target.value)} className="mt-1" />
setPeriodStart(e.target.value)} className="mt-1" />
setPeriodEnd(e.target.value)} className="mt-1" />
) }