'use client' import { useCallback, useEffect, useState } from 'react' import { useRouter } from 'next/navigation' import { useTranslations } from 'next-intl' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { EmptyState } from '@/components/ui/empty-state' import { Skeleton } from '@/components/ui/skeleton' import { TH_CLASS, TD_CLASS, QUIET_LINK_CLASS } from '@/components/ui/dry-table' import { Package, Plus } from 'lucide-react' import { cn, formatCurrency, formatDate } from '@/lib/utils' import type { Asset, AssetCategory } from '@/types' import { CreateAssetDialog } from '@/components/bookkeeping/assets/CreateAssetDialog' import { EditAssetDialog } from '@/components/bookkeeping/assets/EditAssetDialog' /** GET /api/assets annotates each row with whether depreciation has posted. */ type AssetRow = Asset & { has_posted_depreciation?: boolean } const CATEGORY_LABEL_KEYS: Record = { immaterial: 'category_immaterial', building: 'category_building', land_improvement: 'category_land_improvement', machinery: 'category_machinery', equipment: 'category_equipment', vehicle: 'category_vehicle', computer: 'category_computer', other_tangible: 'category_other_tangible', } export default function AssetsPage() { const t = useTranslations('assets') const router = useRouter() const [assets, setAssets] = useState(null) const [error, setError] = useState(null) const [dialogOpen, setDialogOpen] = useState(false) const [editing, setEditing] = useState(null) const [reloadKey, setReloadKey] = useState(0) useEffect(() => { let cancelled = false fetch('/api/assets') .then(async (res) => { if (cancelled) return if (!res.ok) { setError(t('load_failed')) return } const { data } = (await res.json()) as { data: AssetRow[] } if (cancelled) return setError(null) setAssets(data) }) .catch(() => { if (!cancelled) setError(t('load_failed')) }) return () => { cancelled = true } }, [reloadKey, t]) const handleCreated = useCallback(() => { setDialogOpen(false) setReloadKey((k) => k + 1) }, []) const handleSaved = useCallback(() => { setEditing(null) setReloadKey((k) => k + 1) }, []) return (
{/* Page header (concept scene 29): title + Ny tillgÄng */}

{t('title')}

{assets === null && !error && (
{[1, 2, 3].map((i) => ( ))}
)} {error &&

{error}

} {assets !== null && assets.length === 0 && ( setDialogOpen(true)} /> )} {assets !== null && assets.length > 0 && ( <>
{assets.map((asset) => { const years = Math.round(asset.useful_life_months / 12) const disposed = !!asset.disposed_at return ( setEditing(asset) : undefined} > {/* Row actions as hover-revealed quiet links (concept) */} ) })}
{t('th_name')} {t('th_category')} {t('th_acquired')} {t('th_acquisition_cost')} {t('th_useful_life')} {t('th_status')}
{asset.name} {t(CATEGORY_LABEL_KEYS[asset.category])} {formatDate(asset.acquisition_date)} {formatCurrency(Number(asset.acquisition_cost))} {t('useful_life_format', { years, months: asset.useful_life_months })} {disposed ? ( {t('status_disposed')} {formatDate(asset.disposed_at!)} ) : ( {t('status_active')} )} e.stopPropagation()} > {!disposed && ( )}
{/* Footer count (concept pgnote) */}

{t('count_footer', { count: assets.length })}

)} {editing && ( { if (!open) setEditing(null) }} onSaved={handleSaved} /> )}
) }