Files
lunarfront-app/packages/admin/src/routes/_authenticated/repair-batches/index.tsx
Ryan Moon 9400828f62 Rename Forte to LunarFront, generalize for any small business
Rebrand from Forte (music-store-specific) to LunarFront (any small business):
- Package namespace @forte/* → @lunarfront/*
- Database forte/forte_test → lunarfront/lunarfront_test
- Docker containers, volumes, connection strings
- UI branding, localStorage keys, test emails
- All documentation and planning docs

Generalize music-specific terminology:
- instrumentDescription → itemDescription
- instrumentCount → itemCount
- instrumentType → itemCategory (on service templates)
- New migration 0027_generalize_terminology for column renames
- Seed data updated with generic examples
- RBAC descriptions updated
2026-03-30 08:51:54 -05:00

122 lines
3.8 KiB
TypeScript

import { createFileRoute, useNavigate } from '@tanstack/react-router'
import { useQuery } from '@tanstack/react-query'
import { useState } from 'react'
import { repairBatchListOptions } from '@/api/repairs'
import { usePagination } from '@/hooks/use-pagination'
import { DataTable, type Column } from '@/components/shared/data-table'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Badge } from '@/components/ui/badge'
import { Plus, Search } from 'lucide-react'
import { useAuthStore } from '@/stores/auth.store'
import type { RepairBatch } from '@/types/repair'
export const Route = createFileRoute('/_authenticated/repair-batches/')({
validateSearch: (search: Record<string, unknown>) => ({
page: Number(search.page) || 1,
limit: Number(search.limit) || 25,
q: (search.q as string) || undefined,
sort: (search.sort as string) || undefined,
order: (search.order as 'asc' | 'desc') || 'desc',
}),
component: RepairBatchesListPage,
})
const columns: Column<RepairBatch>[] = [
{
key: 'batch_number',
header: 'Batch #',
sortable: true,
render: (b) => <span className="font-mono text-sm">{b.batchNumber ?? '-'}</span>,
},
{
key: 'contact',
header: 'Contact',
render: (b) => <span className="font-medium">{b.contactName ?? '-'}</span>,
},
{
key: 'status',
header: 'Status',
sortable: true,
render: (b) => <Badge variant="outline">{b.status.replace('_', ' ')}</Badge>,
},
{
key: 'approval',
header: 'Approval',
render: (b) => {
const v = b.approvalStatus === 'approved' ? 'default' : b.approvalStatus === 'rejected' ? 'destructive' : 'secondary'
return <Badge variant={v}>{b.approvalStatus}</Badge>
},
},
{
key: 'items',
header: 'Items',
render: (b) => <>{b.receivedCount}/{b.itemCount}</>,
},
{
key: 'due_date',
header: 'Due',
sortable: true,
render: (b) => <>{b.dueDate ? new Date(b.dueDate).toLocaleDateString() : '-'}</>,
},
]
function RepairBatchesListPage() {
const navigate = useNavigate()
const hasPermission = useAuthStore((s) => s.hasPermission)
const { params, setPage, setSearch, setSort } = usePagination()
const [searchInput, setSearchInput] = useState(params.q ?? '')
const { data, isLoading } = useQuery(repairBatchListOptions(params))
function handleSearchSubmit(e: React.FormEvent) {
e.preventDefault()
setSearch(searchInput)
}
function handleRowClick(batch: RepairBatch) {
navigate({ to: '/repair-batches/$batchId', params: { batchId: batch.id }, search: {} as any })
}
return (
<div className="space-y-6">
<div className="flex items-center justify-between">
<h1 className="text-2xl font-bold">Repair Batches</h1>
{hasPermission('repairs.edit') && (
<Button onClick={() => navigate({ to: '/repair-batches/new' })}>
<Plus className="mr-2 h-4 w-4" />
New Batch
</Button>
)}
</div>
<form onSubmit={handleSearchSubmit} className="flex gap-2 max-w-sm">
<div className="relative flex-1">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
<Input
placeholder="Search batches..."
value={searchInput}
onChange={(e) => setSearchInput(e.target.value)}
className="pl-9"
/>
</div>
<Button type="submit" variant="secondary">Search</Button>
</form>
<DataTable
columns={columns}
data={data?.data ?? []}
loading={isLoading}
page={params.page}
totalPages={data?.pagination.totalPages ?? 1}
total={data?.pagination.total ?? 0}
sort={params.sort}
order={params.order}
onPageChange={setPage}
onSort={setSort}
onRowClick={handleRowClick}
/>
</div>
)
}