'use client' import { useCallback, useEffect, useState } from 'react' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Skeleton } from '@/components/ui/skeleton' import { Loader2 } from 'lucide-react' import Link from 'next/link' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table' import { formatCurrency } from '@/lib/utils' import { useToast } from '@/components/ui/use-toast' import type { Asset } from '@/types' interface ProposalItem { asset: Asset amount: number netBookValueAfter: number proRated: boolean existingScheduleId?: string existingJournalEntryId?: string | null } interface Proposal { fiscalPeriod: { id: string; name: string; period_start: string; period_end: string } items: ProposalItem[] totalAmount: number } interface DepreciationPanelProps { periodId: string /** Called after a successful post — parent refetches dispositions because * posted avskrivningar change the result which affects bolagsskatt etc. */ onPosted: () => void } export function DepreciationPanel({ periodId, onPosted }: DepreciationPanelProps) { const { toast } = useToast() const [proposal, setProposal] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [posting, setPosting] = useState(false) const load = useCallback(async () => { setLoading(true) setError(null) try { const res = await fetch(`/api/bookkeeping/fiscal-periods/${periodId}/depreciation`) const body = await res.json() if (!res.ok) { setError(body?.error?.message ?? 'Kunde inte ladda avskrivningar') return } setProposal(body.data as Proposal) } catch (err) { setError(err instanceof Error ? err.message : 'Okänt fel') } finally { setLoading(false) } }, [periodId]) useEffect(() => { void load() }, [load]) const handlePost = useCallback(async () => { setPosting(true) try { const res = await fetch(`/api/bookkeeping/fiscal-periods/${periodId}/depreciation`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}), }) const body = await res.json() if (!res.ok) { setError(body?.error?.message ?? 'Kunde inte bokföra avskrivningar') return } const posted = body.data?.posted?.length ?? 0 toast({ title: `${posted} avskrivning${posted === 1 ? '' : 'ar'} bokförd${ posted === 1 ? '' : 'a' }`, }) onPosted() await load() } catch (err) { setError(err instanceof Error ? err.message : 'Okänt fel') } finally { setPosting(false) } }, [periodId, onPosted, load, toast]) if (loading) { return ( ) } if (error) { return ( {error} ) } if (!proposal) return null const allPosted = proposal.items.length > 0 && proposal.items.every((i) => Boolean(i.existingJournalEntryId)) const anyPending = proposal.items.length > 0 && proposal.items.some((i) => !i.existingJournalEntryId) if (proposal.items.length === 0) { return ( Planenliga avskrivningar Inga aktiva anläggningstillgångar att skriva av.{' '} Lägg till tillgångar {' '} så räknar bokslutet ut avskrivningarna automatiskt. ) } return (
Planenliga avskrivningar

{proposal.items.length} tillgång{proposal.items.length === 1 ? '' : 'ar'}. {allPosted ? ' Allt redan bokfört.' : ' Bokförs som separata verifikationer.'}

{formatCurrency(proposal.totalAmount)}

Tillgång Avskrivning Restvärde Status {proposal.items.map((item) => ( {item.asset.name} {formatCurrency(item.amount)} {item.proRated && ( pro-rata )} {formatCurrency(item.netBookValueAfter)} {item.existingJournalEntryId ? ( Bokförd ) : ( Föreslagen )} ))}
{anyPending && (
)}
) }