Some checks failed
Build & Release / build (push) Failing after 33s
Each destination route's search must match its validateSearch shape exactly:
- Detail pages (tab-based): { tab: '...' }
- List pages with extra filters: include status, instructorId, view, categoryId etc.
- Form pages (enrollments/new, repairs/new): include only their specific fields
- use-pagination.ts: fix search reducer to use (prev: any) instead of invalid cast
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
63 lines
2.7 KiB
TypeScript
63 lines
2.7 KiB
TypeScript
import { createFileRoute, useNavigate } from '@tanstack/react-router'
|
|
import { useQuery } from '@tanstack/react-query'
|
|
import { enrollmentListOptions } from '@/api/lessons'
|
|
import { DataTable, type Column } from '@/components/shared/data-table'
|
|
import { Button } from '@/components/ui/button'
|
|
import { Badge } from '@/components/ui/badge'
|
|
import { Plus } from 'lucide-react'
|
|
import { useAuthStore } from '@/stores/auth.store'
|
|
import type { Enrollment } from '@/types/lesson'
|
|
|
|
export const Route = createFileRoute('/_authenticated/accounts/$accountId/enrollments')({
|
|
component: AccountEnrollmentsTab,
|
|
})
|
|
|
|
function statusBadge(status: string) {
|
|
const variants: Record<string, 'default' | 'secondary' | 'destructive' | 'outline'> = {
|
|
active: 'default', paused: 'secondary', cancelled: 'destructive', completed: 'outline',
|
|
}
|
|
return <Badge variant={variants[status] ?? 'outline'}>{status}</Badge>
|
|
}
|
|
|
|
const columns: Column<Enrollment & { memberName?: string }>[] = [
|
|
{ key: 'member_name', header: 'Member', sortable: true, render: (e) => <span className="font-medium">{e.memberName ?? e.memberId}</span> },
|
|
{ key: 'status', header: 'Status', sortable: true, render: (e) => statusBadge(e.status) },
|
|
{ key: 'start_date', header: 'Start', sortable: true, render: (e) => <>{new Date(e.startDate + 'T00:00:00').toLocaleDateString()}</> },
|
|
{ key: 'rate', header: 'Rate', render: (e) => <>{e.rate ? `$${e.rate}${e.billingInterval ? ` / ${e.billingInterval} ${e.billingUnit}` : ''}` : <span className="text-muted-foreground">—</span>}</> },
|
|
]
|
|
|
|
function AccountEnrollmentsTab() {
|
|
const { accountId } = Route.useParams()
|
|
const navigate = useNavigate()
|
|
const hasPermission = useAuthStore((s) => s.hasPermission)
|
|
|
|
const { data, isLoading } = useQuery({
|
|
...enrollmentListOptions({ accountId, page: 1, limit: 100 }),
|
|
enabled: !!accountId,
|
|
})
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
<div className="flex items-center justify-between">
|
|
<p className="text-sm text-muted-foreground">{data?.pagination.total ?? 0} enrollment(s)</p>
|
|
{hasPermission('lessons.edit') && (
|
|
<Button size="sm" onClick={() => navigate({ to: '/lessons/enrollments/new', search: { memberId: undefined, accountId: undefined } })}>
|
|
<Plus className="h-4 w-4 mr-1" />Enroll a Member
|
|
</Button>
|
|
)}
|
|
</div>
|
|
<DataTable
|
|
columns={columns}
|
|
data={data?.data ?? []}
|
|
loading={isLoading}
|
|
page={1}
|
|
totalPages={1}
|
|
total={data?.data?.length ?? 0}
|
|
onPageChange={() => {}}
|
|
onSort={() => {}}
|
|
onRowClick={(e) => navigate({ to: '/lessons/enrollments/$enrollmentId', params: { enrollmentId: e.id }, search: { tab: 'details' } })}
|
|
/>
|
|
</div>
|
|
)
|
|
}
|