'use client' import { useCallback, useEffect, useState } from 'react' import Link from 'next/link' import { useTranslations } from 'next-intl' import { Card, CardContent } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { PageHeader } from '@/components/ui/page-header' import { EmptyState } from '@/components/ui/empty-state' import { Skeleton } from '@/components/ui/skeleton' import { Package, Pencil, Plus } from 'lucide-react' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table' import { 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 [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 (
setDialogOpen(true)}> {t('new_asset')} } /> {assets === null && !error && ( )} {error && ( {error} )} {assets !== null && assets.length === 0 && ( setDialogOpen(true)} /> )} {assets !== null && assets.length > 0 && ( {t('th_name')} {t('th_category')} {t('th_acquired')} {t('th_acquisition_cost')} {t('th_useful_life')} {t('th_status')} {t('th_actions')} {assets.map((asset) => { const years = Math.round(asset.useful_life_months / 12) return ( {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 })} {asset.disposed_at ? (
{t('status_disposed')} {formatDate(asset.disposed_at)}
) : ( {t('status_active')} )}
{!asset.disposed_at && (
)}
) })}
)} {editing && ( { if (!open) setEditing(null) }} onSaved={handleSaved} /> )}
) }