Add repairs domain with tickets, line items, batches, and service templates
Full-stack implementation of instrument repair tracking: DB schema with repair_ticket, repair_line_item, repair_batch, and repair_service_template tables. Backend services and routes with pagination/search/sort. 20 API tests covering CRUD, status workflow, line items, and batch operations. Admin frontend with ticket list, detail with status progression, line item management, batch list/detail with approval workflow, and new ticket form with searchable account picker and intake photo uploads.
This commit is contained in:
103
packages/admin/src/api/repairs.ts
Normal file
103
packages/admin/src/api/repairs.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { queryOptions } from '@tanstack/react-query'
|
||||
import { api } from '@/lib/api-client'
|
||||
import type { RepairTicket, RepairLineItem, RepairBatch } from '@/types/repair'
|
||||
import type { PaginatedResponse, PaginationInput } from '@forte/shared/schemas'
|
||||
|
||||
// --- Repair Tickets ---
|
||||
|
||||
export const repairTicketKeys = {
|
||||
all: ['repair-tickets'] as const,
|
||||
list: (params: PaginationInput) => [...repairTicketKeys.all, 'list', params] as const,
|
||||
detail: (id: string) => [...repairTicketKeys.all, 'detail', id] as const,
|
||||
}
|
||||
|
||||
export function repairTicketListOptions(params: PaginationInput) {
|
||||
return queryOptions({
|
||||
queryKey: repairTicketKeys.list(params),
|
||||
queryFn: () => api.get<PaginatedResponse<RepairTicket>>('/v1/repair-tickets', params),
|
||||
})
|
||||
}
|
||||
|
||||
export function repairTicketDetailOptions(id: string) {
|
||||
return queryOptions({
|
||||
queryKey: repairTicketKeys.detail(id),
|
||||
queryFn: () => api.get<RepairTicket>(`/v1/repair-tickets/${id}`),
|
||||
})
|
||||
}
|
||||
|
||||
export const repairTicketMutations = {
|
||||
create: (data: Record<string, unknown>) =>
|
||||
api.post<RepairTicket>('/v1/repair-tickets', data),
|
||||
update: (id: string, data: Record<string, unknown>) =>
|
||||
api.patch<RepairTicket>(`/v1/repair-tickets/${id}`, data),
|
||||
updateStatus: (id: string, status: string) =>
|
||||
api.post<RepairTicket>(`/v1/repair-tickets/${id}/status`, { status }),
|
||||
delete: (id: string) =>
|
||||
api.del<RepairTicket>(`/v1/repair-tickets/${id}`),
|
||||
}
|
||||
|
||||
// --- Repair Line Items ---
|
||||
|
||||
export const repairLineItemKeys = {
|
||||
all: (ticketId: string) => ['repair-tickets', ticketId, 'line-items'] as const,
|
||||
list: (ticketId: string, params: PaginationInput) => [...repairLineItemKeys.all(ticketId), params] as const,
|
||||
}
|
||||
|
||||
export function repairLineItemListOptions(ticketId: string, params: PaginationInput) {
|
||||
return queryOptions({
|
||||
queryKey: repairLineItemKeys.list(ticketId, params),
|
||||
queryFn: () => api.get<PaginatedResponse<RepairLineItem>>(`/v1/repair-tickets/${ticketId}/line-items`, params),
|
||||
})
|
||||
}
|
||||
|
||||
export const repairLineItemMutations = {
|
||||
create: (ticketId: string, data: Record<string, unknown>) =>
|
||||
api.post<RepairLineItem>(`/v1/repair-tickets/${ticketId}/line-items`, data),
|
||||
update: (id: string, data: Record<string, unknown>) =>
|
||||
api.patch<RepairLineItem>(`/v1/repair-line-items/${id}`, data),
|
||||
delete: (id: string) =>
|
||||
api.del<RepairLineItem>(`/v1/repair-line-items/${id}`),
|
||||
}
|
||||
|
||||
// --- Repair Batches ---
|
||||
|
||||
export const repairBatchKeys = {
|
||||
all: ['repair-batches'] as const,
|
||||
list: (params: PaginationInput) => [...repairBatchKeys.all, 'list', params] as const,
|
||||
detail: (id: string) => [...repairBatchKeys.all, 'detail', id] as const,
|
||||
tickets: (batchId: string, params: PaginationInput) => [...repairBatchKeys.all, batchId, 'tickets', params] as const,
|
||||
}
|
||||
|
||||
export function repairBatchListOptions(params: PaginationInput) {
|
||||
return queryOptions({
|
||||
queryKey: repairBatchKeys.list(params),
|
||||
queryFn: () => api.get<PaginatedResponse<RepairBatch>>('/v1/repair-batches', params),
|
||||
})
|
||||
}
|
||||
|
||||
export function repairBatchDetailOptions(id: string) {
|
||||
return queryOptions({
|
||||
queryKey: repairBatchKeys.detail(id),
|
||||
queryFn: () => api.get<RepairBatch>(`/v1/repair-batches/${id}`),
|
||||
})
|
||||
}
|
||||
|
||||
export function repairBatchTicketsOptions(batchId: string, params: PaginationInput) {
|
||||
return queryOptions({
|
||||
queryKey: repairBatchKeys.tickets(batchId, params),
|
||||
queryFn: () => api.get<PaginatedResponse<RepairTicket>>(`/v1/repair-batches/${batchId}/tickets`, params),
|
||||
})
|
||||
}
|
||||
|
||||
export const repairBatchMutations = {
|
||||
create: (data: Record<string, unknown>) =>
|
||||
api.post<RepairBatch>('/v1/repair-batches', data),
|
||||
update: (id: string, data: Record<string, unknown>) =>
|
||||
api.patch<RepairBatch>(`/v1/repair-batches/${id}`, data),
|
||||
updateStatus: (id: string, status: string) =>
|
||||
api.post<RepairBatch>(`/v1/repair-batches/${id}/status`, { status }),
|
||||
approve: (id: string) =>
|
||||
api.post<RepairBatch>(`/v1/repair-batches/${id}/approve`, {}),
|
||||
reject: (id: string) =>
|
||||
api.post<RepairBatch>(`/v1/repair-batches/${id}/reject`, {}),
|
||||
}
|
||||
Reference in New Issue
Block a user