feat: add template checkpoint edit dialog and vendor management components

- Implemented TemplateCheckpointEditDialog for creating and editing inspection checkpoints.
- Added VendorActions component for managing vendor actions including edit, activate/deactivate, and delete.
- Created VendorContext for managing vendor state across components.
- Developed VendorGeneralInfo component to display detailed vendor information.
- Introduced AedSymbol and Money components for consistent currency representation.
- Added PromptDialog for user input prompts throughout the application.
- Implemented RelationLink component for unified related-data display in CRUD tables.
- Created InspectionTemplatesClient for API interactions related to inspection templates.
This commit is contained in:
2026-05-18 12:08:42 +04:00
parent 54d11f01b4
commit 4bfd8c84a9
111 changed files with 5002 additions and 1047 deletions
+58
View File
@@ -8,6 +8,7 @@ export const INSPECTION_ROUTES = {
CATEGORY_BY_ID: "/api/inspection-categories/{id}",
INDEX: "/api/inspections",
BY_ID: "/api/inspections/{id}",
FROM_TEMPLATE: "/api/inspections/from-template",
CHANGE_STATUS: "/api/change-inspection-status",
CHECKPOINT_LABELS: "/api/check-point-label",
CHECKPOINT_LABEL_BY_ID: "/api/check-point-label/{id}",
@@ -54,6 +55,63 @@ export class InspectionsClient extends CrudClient<
return this.post(INSPECTION_ROUTES.CHANGE_STATUS, payload)
}
async showOne(id: number | string): Promise<{ data: any }> {
return this.get(`/api/inspections/{id}` as never, { params: { id: String(id) } } as never) as never
}
async sign(id: number | string, who: "technician" | "customer", dataUrl: string) {
return this.post(`/api/inspections/{id}/sign` as never, { who, signature: dataUrl } as never, { params: { id: String(id) } } as never) as never
}
/**
* Upload one or many photos/videos/audio files to a checkpoint via the
* unified attachments endpoint. The single-file `addCheckpointAttachment`
* (body-based) above stays available for legacy callers.
*/
async uploadCheckpointAttachments(
checkpointId: number | string,
files: File[],
caption?: string,
): Promise<{ data: Array<{ id: number; url: string; media_type: string; sort_order: number; caption?: string | null }> }> {
const fd = new FormData()
files.forEach((f) => fd.append("attachments[]", f))
if (caption) fd.append("caption", caption)
const url = `/api/inspection-check-points/${encodeURIComponent(String(checkpointId))}/attachments`
return (this as any).postFormData(url, fd)
}
async destroyCheckpointAttachment(checkpointId: number | string, attachmentId: number | string) {
return this.delete(
`/api/inspection-check-points/{id}/attachments/{attachmentId}` as never,
{ params: { id: String(checkpointId), attachmentId: String(attachmentId) } } as never,
) as never
}
async share(id: number | string): Promise<{ data: { share_token: string; share_url: string; share_enabled_at: string; share_expires_at: string } }> {
return this.post(`/api/inspections/{id}/share` as never, undefined as never, { params: { id: String(id) } } as never) as never
}
async revokeShare(id: number | string): Promise<{ message: string }> {
return this.post(`/api/inspections/{id}/revoke-share` as never, undefined as never, { params: { id: String(id) } } as never) as never
}
async createFromTemplate(payload: {
template_id: number
title: string
customer_id: number | string
vehicle_id: number | string
department_id: number | string
employee_id: number | string
order_number: string
date: string
time: string
odometer?: number
note?: string
inspection_category_id?: number | string
}) {
return this.post(INSPECTION_ROUTES.FROM_TEMPLATE as never, payload as never) as never
}
// ── Checkpoint Labels ──
async listCheckpointLabels(query?: ApiListQueryParams) {
return this.get(INSPECTION_ROUTES.CHECKPOINT_LABELS, query ? { query } as never : undefined)