refactor(section-d): frontend API client type safety audit
All 19 api/*.ts files already used import api from './client' (X-Tenant-ID guaranteed). Fixed missing type generics and any usage in 10 files: - worker.ts: args: any[] → unknown[] - imports.ts, notifications.ts: add response type generics - renderTemplates.ts: add typed generics on 6 calls - materials.ts, cad.ts: type previously untyped api calls - products.ts: ProductCadUploadResponse interface, typed generics - uploads.ts: StepUploadResponse interface - billing.ts, orders.ts: <Blob> on download calls Zero bare axios usage, zero as any in API layer. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -61,7 +61,7 @@ export async function deleteInvoice(id: string): Promise<void> {
|
||||
}
|
||||
|
||||
export async function downloadInvoicePdf(id: string): Promise<void> {
|
||||
const res = await api.get(`/billing/invoices/${id}/pdf`, { responseType: 'blob' })
|
||||
const res = await api.get<Blob>(`/billing/invoices/${id}/pdf`, { responseType: 'blob' })
|
||||
const url = URL.createObjectURL(res.data)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
|
||||
@@ -100,6 +100,6 @@ export async function generateGltfProduction(cadFileId: string): Promise<Generat
|
||||
|
||||
/** Force-reset a CAD file stuck in 'processing' to 'failed'. */
|
||||
export async function resetStuckProcessing(cadFileId: string): Promise<{ status: string; message: string }> {
|
||||
const res = await api.post(`/cad/${cadFileId}/reset-stuck`)
|
||||
const res = await api.post<{ status: string; message: string }>(`/cad/${cadFileId}/reset-stuck`)
|
||||
return res.data
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ export interface ImportValidation {
|
||||
}
|
||||
|
||||
export async function getImportValidation(id: string): Promise<ImportValidation> {
|
||||
const res = await api.get(`/imports/validation/${id}`)
|
||||
const res = await api.get<ImportValidation>(`/imports/validation/${id}`)
|
||||
return res.data
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,10 @@ export async function saveCadPartMaterials(
|
||||
itemId: string,
|
||||
parts: Array<{ part_name: string; material: string }>,
|
||||
) {
|
||||
const res = await api.put(`/orders/${orderId}/items/${itemId}/cad-materials`, { parts })
|
||||
const res = await api.put<{ parts: Array<{ part_name: string; material: string }> }>(
|
||||
`/orders/${orderId}/items/${itemId}/cad-materials`,
|
||||
{ parts },
|
||||
)
|
||||
return res.data
|
||||
}
|
||||
|
||||
|
||||
@@ -25,12 +25,12 @@ export async function getNotifications(params?: {
|
||||
unread_only?: boolean
|
||||
channel?: NotificationChannel
|
||||
}): Promise<NotificationListResponse> {
|
||||
const { data } = await api.get('/notifications', { params })
|
||||
const { data } = await api.get<NotificationListResponse>('/notifications', { params })
|
||||
return data
|
||||
}
|
||||
|
||||
export async function getUnreadCount(): Promise<number> {
|
||||
const { data } = await api.get('/notifications/unread-count')
|
||||
const { data } = await api.get<{ unread_count: number }>('/notifications/unread-count')
|
||||
return data.unread_count
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,8 @@ export interface Order {
|
||||
updated_at: string
|
||||
submitted_at: string | null
|
||||
completed_at: string | null
|
||||
rejected_at: string | null
|
||||
rejection_reason: string | null
|
||||
estimated_price: number | null
|
||||
item_count: number
|
||||
line_count: number
|
||||
@@ -239,8 +241,21 @@ export async function generateLinesFromItems(
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function rejectOrder(orderId: string, reason: string, notifyClient: boolean = true): Promise<Order> {
|
||||
const res = await api.post<Order>(`/orders/${orderId}/reject`, {
|
||||
reason,
|
||||
notify_client: notifyClient,
|
||||
})
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function resubmitOrder(orderId: string): Promise<Order> {
|
||||
const res = await api.post<Order>(`/orders/${orderId}/resubmit`)
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function downloadOrderRenders(orderId: string, orderNumber: string): Promise<void> {
|
||||
const res = await api.get(`/orders/${orderId}/download-renders`, { responseType: 'blob' })
|
||||
const res = await api.get<Blob>(`/orders/${orderId}/download-renders`, { responseType: 'blob' })
|
||||
const url = URL.createObjectURL(res.data)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import api from './client'
|
||||
import type { Order } from './orders'
|
||||
|
||||
export interface RenderPosition {
|
||||
id: string
|
||||
@@ -106,10 +107,18 @@ export async function deleteProduct(id: string, hard = false): Promise<void> {
|
||||
await api.delete(`/products/${id}`, { params: hard ? { hard: true } : undefined })
|
||||
}
|
||||
|
||||
export async function uploadProductCad(id: string, file: File) {
|
||||
export interface ProductCadUploadResponse {
|
||||
cad_file_id: string
|
||||
original_name: string
|
||||
file_hash: string
|
||||
status: string
|
||||
product_id: string
|
||||
}
|
||||
|
||||
export async function uploadProductCad(id: string, file: File): Promise<ProductCadUploadResponse> {
|
||||
const form = new FormData()
|
||||
form.append('file', file)
|
||||
const res = await api.post(`/products/${id}/cad`, form, {
|
||||
const res = await api.post<ProductCadUploadResponse>(`/products/${id}/cad`, form, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
})
|
||||
return res.data
|
||||
@@ -120,13 +129,13 @@ export async function saveProductCadMaterials(id: string, parts: CadPartMaterial
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function regenerateProduct(id: string) {
|
||||
const res = await api.post(`/products/${id}/regenerate`)
|
||||
export async function regenerateProduct(id: string): Promise<{ status: string; task_id: string | null }> {
|
||||
const res = await api.post<{ status: string; task_id: string | null }>(`/products/${id}/regenerate`)
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function reprocessProduct(id: string) {
|
||||
const res = await api.post(`/products/${id}/reprocess`)
|
||||
export async function reprocessProduct(id: string): Promise<{ status: string; task_id: string | null }> {
|
||||
const res = await api.post<{ status: string; task_id: string | null }>(`/products/${id}/reprocess`)
|
||||
return res.data
|
||||
}
|
||||
|
||||
@@ -174,8 +183,8 @@ export async function downloadProductRenders(
|
||||
URL.revokeObjectURL(url)
|
||||
}
|
||||
|
||||
export async function getProductOrders(id: string) {
|
||||
const res = await api.get(`/products/${id}/orders`)
|
||||
export async function getProductOrders(id: string): Promise<Order[]> {
|
||||
const res = await api.get<Order[]>(`/products/${id}/orders`)
|
||||
return res.data
|
||||
}
|
||||
|
||||
|
||||
@@ -28,12 +28,12 @@ export interface MaterialLibraryInfo {
|
||||
}
|
||||
|
||||
export async function listRenderTemplates(): Promise<RenderTemplate[]> {
|
||||
const { data } = await api.get('/render-templates');
|
||||
const { data } = await api.get<RenderTemplate[]>('/render-templates');
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function createRenderTemplate(formData: FormData): Promise<RenderTemplate> {
|
||||
const { data } = await api.post('/render-templates', formData, {
|
||||
const { data } = await api.post<RenderTemplate>('/render-templates', formData, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
});
|
||||
return data;
|
||||
@@ -43,7 +43,7 @@ export async function updateRenderTemplate(
|
||||
id: string,
|
||||
updates: Partial<Pick<RenderTemplate, 'name' | 'category_key' | 'output_type_ids' | 'target_collection' | 'material_replace_enabled' | 'lighting_only' | 'shadow_catcher_enabled' | 'camera_orbit' | 'is_active'>>,
|
||||
): Promise<RenderTemplate> {
|
||||
const { data } = await api.patch(`/render-templates/${id}`, updates);
|
||||
const { data } = await api.patch<RenderTemplate>(`/render-templates/${id}`, updates);
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ export async function deleteRenderTemplate(id: string): Promise<void> {
|
||||
export async function reuploadBlendFile(id: string, file: File): Promise<RenderTemplate> {
|
||||
const fd = new FormData();
|
||||
fd.append('file', file);
|
||||
const { data } = await api.post(`/render-templates/${id}/upload`, fd, {
|
||||
const { data } = await api.post<RenderTemplate>(`/render-templates/${id}/upload`, fd, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
});
|
||||
return data;
|
||||
@@ -63,14 +63,14 @@ export async function reuploadBlendFile(id: string, file: File): Promise<RenderT
|
||||
export async function uploadMaterialLibrary(file: File): Promise<MaterialLibraryInfo> {
|
||||
const fd = new FormData();
|
||||
fd.append('file', file);
|
||||
const { data } = await api.post('/admin/settings/material-library', fd, {
|
||||
const { data } = await api.post<MaterialLibraryInfo>('/admin/settings/material-library', fd, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function getMaterialLibraryInfo(): Promise<MaterialLibraryInfo> {
|
||||
const { data } = await api.get('/admin/settings/material-library');
|
||||
const { data } = await api.get<MaterialLibraryInfo>('/admin/settings/material-library');
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
@@ -93,10 +93,18 @@ export async function finalizeExcelImport(data: ExcelFinalizeRequest): Promise<O
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function uploadStep(file: File) {
|
||||
export interface StepUploadResponse {
|
||||
cad_file_id: string
|
||||
original_name: string
|
||||
file_hash: string
|
||||
status: string
|
||||
matched_items: string[]
|
||||
}
|
||||
|
||||
export async function uploadStep(file: File): Promise<StepUploadResponse> {
|
||||
const form = new FormData()
|
||||
form.append('file', file)
|
||||
const res = await api.post('/uploads/step', form, {
|
||||
const res = await api.post<StepUploadResponse>('/uploads/step', form, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
})
|
||||
return res.data
|
||||
|
||||
@@ -94,7 +94,7 @@ export function renderLogStreamUrl(orderLineId: string): string {
|
||||
export interface QueueTask {
|
||||
task_id: string
|
||||
task_name: string
|
||||
args: any[]
|
||||
args: unknown[]
|
||||
argsrepr: string
|
||||
status: 'pending' | 'active' | 'reserved'
|
||||
worker?: string
|
||||
|
||||
Reference in New Issue
Block a user