BalancesPage.tsx 2 KB
import { useEffect, useState } from 'react'
import { inventory } from '@/api/client'
import type { Location, StockBalance } from '@/types/api'
import { PageHeader } from '@/components/PageHeader'
import { Loading } from '@/components/Loading'
import { ErrorBox } from '@/components/ErrorBox'
import { DataTable, type Column } from '@/components/DataTable'

interface Row extends Record<string, unknown> {
  id: string
  itemCode: string
  locationCode: string
  quantity: string | number
}

export function BalancesPage() {
  const [rows, setRows] = useState<Row[]>([])
  const [error, setError] = useState<Error | null>(null)
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    Promise.all([inventory.listBalances(), inventory.listLocations()])
      .then(([balances, locs]: [StockBalance[], Location[]]) => {
        const byId = new Map(locs.map((l) => [l.id, l.code]))
        setRows(
          balances.map((b) => ({
            id: b.id,
            itemCode: b.itemCode,
            locationCode: byId.get(b.locationId) ?? b.locationId,
            quantity: b.quantity,
          })),
        )
      })
      .catch((e: unknown) => setError(e instanceof Error ? e : new Error(String(e))))
      .finally(() => setLoading(false))
  }, [])

  const columns: Column<Row>[] = [
    { header: 'Item', key: 'itemCode', render: (r) => <span className="font-mono">{r.itemCode}</span> },
    {
      header: 'Location',
      key: 'locationCode',
      render: (r) => <span className="font-mono">{r.locationCode}</span>,
    },
    {
      header: 'Quantity',
      key: 'quantity',
      render: (r) => <span className="font-mono tabular-nums">{String(r.quantity)}</span>,
    },
  ]

  return (
    <div>
      <PageHeader
        title="Stock Balances"
        subtitle="On-hand quantities per (item, location). Updates atomically with every movement."
      />
      {loading && <Loading />}
      {error && <ErrorBox error={error} />}
      {!loading && !error && <DataTable rows={rows} columns={columns} />}
    </div>
  )
}