'use client'; import { useState, useEffect, useCallback } from 'react'; import { api } from '@/lib/api'; import { PageHeader } from '@/components/ui/page-header'; import { DataTable } from '@/components/ui/data-table'; import { Badge, statusBadgeVariant } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { ActionIcon } from '@/components/ui/action-icon'; import { Modal } from '@/components/ui/modal'; import { FormModal } from '@/components/ui/form-modal'; import { useToast } from '@/components/ui/toast'; const CATEGORIES = ['router', 'olt', 'cable', 'tool', 'vehicle', 'computer', 'other']; export default function AssetsPage() { const { toast } = useToast(); const [assets, setAssets] = useState([]); const [loading, setLoading] = useState(true); const [search, setSearch] = useState(''); const [showCreate, setShowCreate] = useState(false); const [detailTarget, setDetailTarget] = useState(null); const [catFilter, setCatFilter] = useState(''); const load = useCallback(async () => { try { const params = new URLSearchParams(); if (catFilter) params.set('category', catFilter); const r = await api.get(`/assets?${params}`); setAssets(r.data.data); } catch { toast('Failed to load assets', 'error'); } finally { setLoading(false); } }, [catFilter, toast]); useEffect(() => { load(); }, [load]); const filtered = search ? assets.filter((a: any) => a.name.toLowerCase().includes(search.toLowerCase()) || a.serialNumber?.toLowerCase().includes(search.toLowerCase())) : assets; return (
} />
a.id} emptyTitle="No assets" emptyDescription="Add your first equipment or tool." searchPlaceholder="Search by name or serial number..." searchValue={search} onSearchChange={setSearch} onRowClick={(a: any) => setDetailTarget(a)} columns={[ { key: 'name', label: 'Name', sortable: true, render: (a: any) => {a.name} }, { key: 'category', label: 'Category', sortable: true, render: (a: any) => }, { key: 'serialNumber', label: 'Serial #', render: (a: any) => {a.serialNumber || '—'} }, { key: 'status', label: 'Status', sortable: true, render: (a: any) => }, { key: 'assignedTo', label: 'Assigned To', render: (a: any) => a.assignedTo ? {a.assignedTo.firstName} {a.assignedTo.lastName} : Unassigned }, { key: 'purchasePrice', label: 'Value', align: 'right' as const, render: (a: any) => a.purchasePrice ? PHP {Number(a.purchasePrice).toLocaleString()} : }, ]} />
setShowCreate(false)} onSuccess={load} /> {/* Asset Detail Modal */} setDetailTarget(null)} title={detailTarget?.name || 'Asset Details'} description={detailTarget?.serialNumber ? `S/N: ${detailTarget.serialNumber}` : ''}> {detailTarget && (
Category:
Status:
Serial #: {detailTarget.serialNumber || '—'}
Value: {detailTarget.purchasePrice ? `PHP ${Number(detailTarget.purchasePrice).toLocaleString()}` : '—'}
Assigned To: {detailTarget.assignedTo ? `${detailTarget.assignedTo.firstName} ${detailTarget.assignedTo.lastName}` : 'Unassigned'}
{detailTarget.location &&
Location: {detailTarget.location}
} {detailTarget.notes &&
Notes: {detailTarget.notes}
}
)}
); } function CreateAssetModal({ open, onClose, onSuccess }: { open: boolean; onClose: () => void; onSuccess: () => void }) { const { toast } = useToast(); const [form, setForm] = useState({ name: '', category: 'router', serialNumber: '', purchasePrice: 0, location: '', notes: '' }); const [submitting, setSubmitting] = useState(false); const ic = 'mt-1 block w-full rounded-lg border border-surface-200 dark:border-surface-700 px-3.5 py-2.5 text-sm bg-white dark:bg-surface-800 text-surface-900 dark:text-surface-200 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20 transition-all duration-200'; useEffect(() => { if (open) setForm({ name: '', category: 'router', serialNumber: '', purchasePrice: 0, location: '', notes: '' }); }, [open]); async function handleSubmit(e: React.FormEvent) { e.preventDefault(); setSubmitting(true); try { await api.post('/assets', { ...form, serialNumber: form.serialNumber || undefined, purchasePrice: form.purchasePrice || undefined, location: form.location || undefined, notes: form.notes || undefined }); toast('Asset added', 'success'); onSuccess(); onClose(); } catch (err: any) { toast(err.response?.data?.error || 'Failed', 'error'); } finally { setSubmitting(false); } } return (
setForm({ ...form, name: e.target.value })} className={ic} placeholder="e.g. Mikrotik hEX S" />
setForm({ ...form, serialNumber: e.target.value })} className={ic} />
setForm({ ...form, purchasePrice: parseFloat(e.target.value) || 0 })} className={ic} />
setForm({ ...form, location: e.target.value })} className={ic} placeholder="e.g. Warehouse, Field" />
); }