Add repair list filters, template management page, and backend filter support

Repairs list now has a filter panel with status (defaults to active only),
condition, batch/individual toggle, and date range filters for intake and
promised dates. Added Batch column to the repairs table. Backend list
endpoint accepts filter query params for status, condition, dates, and
batch membership. Template management page (admin only) with CRUD for
common repair services (rehair, string change, etc.) with instrument
type, size, and default pricing. Sidebar updated with Repair Templates
link gated on repairs.admin permission.
This commit is contained in:
Ryan Moon
2026-03-29 10:13:38 -05:00
parent 7d55fbe7ef
commit 01cff80f2b
7 changed files with 527 additions and 17 deletions

View File

@@ -4,12 +4,14 @@ import { useState } from 'react'
import { repairTicketListOptions } from '@/api/repairs'
import { usePagination } from '@/hooks/use-pagination'
import { DataTable, type Column } from '@/components/shared/data-table'
import { RepairFilterPanel, DEFAULT_FILTERS, type RepairFilters } from '@/components/repairs/repair-filters'
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 { RepairTicket } from '@/types/repair'
import type { PaginationInput } from '@forte/shared/schemas'
export const Route = createFileRoute('/_authenticated/repairs/')({
validateSearch: (search: Record<string, unknown>) => ({
@@ -24,6 +26,7 @@ export const Route = createFileRoute('/_authenticated/repairs/')({
function statusBadge(status: string) {
const variants: Record<string, 'default' | 'secondary' | 'destructive' | 'outline'> = {
in_transit: 'secondary',
intake: 'outline',
diagnosing: 'secondary',
pending_approval: 'secondary',
@@ -36,6 +39,7 @@ function statusBadge(status: string) {
cancelled: 'destructive',
}
const labels: Record<string, string> = {
in_transit: 'In Transit',
intake: 'Intake',
diagnosing: 'Diagnosing',
pending_approval: 'Pending Approval',
@@ -74,6 +78,11 @@ const columns: Column<RepairTicket>[] = [
sortable: true,
render: (t) => statusBadge(t.status),
},
{
key: 'batch',
header: 'Batch',
render: (t) => t.repairBatchId ? <Badge variant="outline">Batch</Badge> : <span className="text-muted-foreground">-</span>,
},
{
key: 'intake_date',
header: 'Intake',
@@ -98,8 +107,19 @@ function RepairsListPage() {
const hasPermission = useAuthStore((s) => s.hasPermission)
const { params, setPage, setSearch, setSort } = usePagination()
const [searchInput, setSearchInput] = useState(params.q ?? '')
const [filters, setFilters] = useState<RepairFilters>(DEFAULT_FILTERS)
const { data, isLoading } = useQuery(repairTicketListOptions(params))
// Build query params with filters
const queryParams: Record<string, unknown> = { ...params }
if (filters.status?.length) queryParams.status = filters.status.join(',')
if (filters.conditionIn?.length) queryParams.conditionIn = filters.conditionIn.join(',')
if (filters.isBatch !== undefined) queryParams.isBatch = String(filters.isBatch)
if (filters.intakeDateFrom) queryParams.intakeDateFrom = filters.intakeDateFrom
if (filters.intakeDateTo) queryParams.intakeDateTo = filters.intakeDateTo
if (filters.promisedDateFrom) queryParams.promisedDateFrom = filters.promisedDateFrom
if (filters.promisedDateTo) queryParams.promisedDateTo = filters.promisedDateTo
const { data, isLoading } = useQuery(repairTicketListOptions(queryParams as PaginationInput))
function handleSearchSubmit(e: React.FormEvent) {
e.preventDefault()
@@ -135,6 +155,8 @@ function RepairsListPage() {
<Button type="submit" variant="secondary">Search</Button>
</form>
<RepairFilterPanel filters={filters} onChange={setFilters} />
<DataTable
columns={columns}
data={data?.data ?? []}