updates
This commit is contained in:
@@ -30221,7 +30221,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/import-parts": {
|
||||
"/api/parts/import": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Import Parts"
|
||||
@@ -30264,7 +30264,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/export-parts": {
|
||||
"/api/parts/export": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Export Parts"
|
||||
@@ -30343,12 +30343,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/toggle-part-status": {
|
||||
"/api/parts/toggle-status": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Toggle Part Status"
|
||||
],
|
||||
"summary": "POST /api/toggle-part-status",
|
||||
"summary": "POST /api/parts/toggle-status",
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"info": {
|
||||
"_postman_id": "bf46649e-48e0-49d5-aa87-1790dcbc3c24",
|
||||
"_postman_id": "a879ecf0-769b-47c2-86ec-dcc11bf1973d",
|
||||
"name": "Reparee Collection",
|
||||
"description": "Auto-generated from OpenAPI spec. Import storage/app/openapi-default.json for the full schema.",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
|
||||
@@ -16122,7 +16122,7 @@
|
||||
"job-cards"
|
||||
]
|
||||
},
|
||||
"description": "Paginated list. Eager loads: labels, customer, vehicle, department, documents, attachmentFiles, serviceWriter, salesPerson, primaryTechnician. withCount: purchase_orders_count, bills_count, expenses_count, tasks_count, appointments_count, inspections_count, services_count, parts_count, expense_items_count (line-level rows on the job card). Response: `data` and `meta` only. Nested employees may include full columns in production; example uses a shortened shape. Query: status, customer_id, vehicle_id, per_page, sort_by, sort_order, start_date, end_date, service_writer_id, department_id, has_start_or_delivery_date, has_start_date, has_delivery_date, has_both_dates."
|
||||
"description": "Paginated list. Eager loads: labels, customer, vehicle, department, documents, attachmentFiles, serviceWriter, salesPerson, primaryTechnician. withCount: purchase_orders_count, bills_count, expenses_count, tasks_count, appointments_count, inspections_count, services_count, parts_count, expense_items_count (line-level rows on the job card). Response: `data` and `meta` only. Nested employees may include full columns in production; example uses a shortened shape. Query: sort_by, sort_order, status, customer_id, insurer_id, sales_person_id, primary_technician_id, service_writer_id, label_ids, delivery_date, convert_invoice, check_in_date, check_out_date, vehicle_id, start_date, end_date, department_id, search, has_start_or_delivery_date, has_start_date, has_delivery_date, has_both_dates, per_page."
|
||||
},
|
||||
"response": [
|
||||
{
|
||||
@@ -22023,13 +22023,14 @@
|
||||
]
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{base_url}}/api/import-parts",
|
||||
"raw": "{{base_url}}/api/parts/import",
|
||||
"host": [
|
||||
"{{base_url}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"import-parts"
|
||||
"parts",
|
||||
"import"
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -22071,13 +22072,14 @@
|
||||
]
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{base_url}}/api/import-parts",
|
||||
"raw": "{{base_url}}/api/parts/import",
|
||||
"host": [
|
||||
"{{base_url}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"import-parts"
|
||||
"parts",
|
||||
"import"
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -22134,13 +22136,14 @@
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{base_url}}/api/export-parts",
|
||||
"raw": "{{base_url}}/api/parts/export",
|
||||
"host": [
|
||||
"{{base_url}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"export-parts"
|
||||
"parts",
|
||||
"export"
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -22179,13 +22182,14 @@
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{base_url}}/api/export-parts",
|
||||
"raw": "{{base_url}}/api/parts/export",
|
||||
"host": [
|
||||
"{{base_url}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"export-parts"
|
||||
"parts",
|
||||
"export"
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -22209,7 +22213,7 @@
|
||||
"name": "Toggle Part Status",
|
||||
"item": [
|
||||
{
|
||||
"name": "POST /api/toggle-part-status",
|
||||
"name": "POST /api/parts/toggle-status",
|
||||
"request": {
|
||||
"auth": {
|
||||
"type": "bearer",
|
||||
@@ -22242,13 +22246,14 @@
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{base_url}}/api/toggle-part-status",
|
||||
"raw": "{{base_url}}/api/parts/toggle-status",
|
||||
"host": [
|
||||
"{{base_url}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"toggle-part-status"
|
||||
"parts",
|
||||
"toggle-status"
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -22287,13 +22292,14 @@
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{base_url}}/api/toggle-part-status",
|
||||
"raw": "{{base_url}}/api/parts/toggle-status",
|
||||
"host": [
|
||||
"{{base_url}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"toggle-part-status"
|
||||
"parts",
|
||||
"toggle-status"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -5,8 +5,8 @@ import type { ApiPath, ApiRequestBody } from "../infra/types"
|
||||
export const PARTS_ROUTES = {
|
||||
INDEX: "/api/parts",
|
||||
BY_ID: "/api/parts/{id}",
|
||||
IMPORT: "/api/import-parts",
|
||||
EXPORT: "/api/export-parts",
|
||||
IMPORT: "/api/parts/import",
|
||||
EXPORT: "/api/parts/export",
|
||||
TOGGLE_STATUS: "/api/toggle-part-status",
|
||||
} as const satisfies Record<string, ApiPath>
|
||||
|
||||
@@ -15,15 +15,15 @@ export class PartsClient extends CrudClient<
|
||||
typeof PARTS_ROUTES.BY_ID
|
||||
> {
|
||||
constructor(baseUrl?: string, defaultOptions?: ApiClientOptions) {
|
||||
super(baseUrl, defaultOptions, PARTS_ROUTES.INDEX, PARTS_ROUTES.BY_ID)
|
||||
}
|
||||
|
||||
async import(payload: ApiRequestBody<typeof PARTS_ROUTES.IMPORT, "post">) {
|
||||
return this.post(PARTS_ROUTES.IMPORT, payload)
|
||||
}
|
||||
|
||||
async export(payload: ApiRequestBody<typeof PARTS_ROUTES.EXPORT, "post">) {
|
||||
return this.post(PARTS_ROUTES.EXPORT, payload)
|
||||
super(
|
||||
baseUrl,
|
||||
defaultOptions,
|
||||
PARTS_ROUTES.INDEX,
|
||||
PARTS_ROUTES.BY_ID,
|
||||
PARTS_ROUTES.IMPORT,
|
||||
PARTS_ROUTES.EXPORT,
|
||||
"POST",
|
||||
)
|
||||
}
|
||||
|
||||
async toggleStatus(payload: ApiRequestBody<typeof PARTS_ROUTES.TOGGLE_STATUS, "post">) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { CrudClient } from "../infra/crud-client"
|
||||
import type { ApiClientOptions } from "../infra/client"
|
||||
import type { ApiPath, ApiRequestBody } from "../infra/types"
|
||||
import type { ApiPath } from "../infra/types"
|
||||
|
||||
export const SERVICE_ROUTES = {
|
||||
INDEX: "/api/services",
|
||||
@@ -14,14 +14,14 @@ export class ServicesClient extends CrudClient<
|
||||
typeof SERVICE_ROUTES.BY_ID
|
||||
> {
|
||||
constructor(baseUrl?: string, defaultOptions?: ApiClientOptions) {
|
||||
super(baseUrl, defaultOptions, SERVICE_ROUTES.INDEX, SERVICE_ROUTES.BY_ID)
|
||||
}
|
||||
|
||||
async import(payload: ApiRequestBody<typeof SERVICE_ROUTES.IMPORT, "post">) {
|
||||
return this.post(SERVICE_ROUTES.IMPORT, payload)
|
||||
}
|
||||
|
||||
async export(payload: ApiRequestBody<typeof SERVICE_ROUTES.EXPORT, "post">) {
|
||||
return this.post(SERVICE_ROUTES.EXPORT, payload)
|
||||
super(
|
||||
baseUrl,
|
||||
defaultOptions,
|
||||
SERVICE_ROUTES.INDEX,
|
||||
SERVICE_ROUTES.BY_ID,
|
||||
SERVICE_ROUTES.IMPORT,
|
||||
SERVICE_ROUTES.EXPORT,
|
||||
"POST",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,6 +190,28 @@ export class ApiClient {
|
||||
return data
|
||||
}
|
||||
|
||||
protected async fetchBlob(endpoint: string, options?: { method?: "GET" | "POST"; body?: unknown }): Promise<Blob> {
|
||||
const url = `${this.normalizeBaseUrl(this.baseUrl)}${endpoint}`
|
||||
const headers = new Headers(this.defaultOptions.headers as Record<string, string>)
|
||||
const method = options?.method ?? "POST"
|
||||
|
||||
const init: RequestInit = { method, headers }
|
||||
if (options?.body) {
|
||||
headers.set("Content-Type", "application/json")
|
||||
init.body = JSON.stringify(options.body)
|
||||
}
|
||||
|
||||
const response = await fetch(url, init)
|
||||
|
||||
if (!response.ok) {
|
||||
const text = await response.text()
|
||||
const data = text ? JSON.parse(text) : null
|
||||
throw new ApiError(response.status, response.statusText, endpoint, method.toLowerCase(), data)
|
||||
}
|
||||
|
||||
return response.blob()
|
||||
}
|
||||
|
||||
private toFetchOptions<Path extends ApiPath, Method extends HttpMethod>(
|
||||
options: ApiRequestOptions<Path, Method>,
|
||||
): Record<string, unknown> {
|
||||
|
||||
@@ -6,6 +6,8 @@ export const DEFAULT_PER_PAGE = 10
|
||||
|
||||
type CrudIndexRoute = ApiPathByMethod<"get"> & ApiPathByMethod<"post">
|
||||
type CrudByIdRoute = ApiPathByMethod<"put"> & ApiPathByMethod<"delete">
|
||||
type CrudImportRoute = ApiPathByMethod<"post">
|
||||
type CrudExportRoute = ApiPathByMethod<"get"> | ApiPathByMethod<"post">
|
||||
|
||||
export type CrudTypeOverrides = {
|
||||
listResponse?: unknown
|
||||
@@ -29,7 +31,10 @@ export abstract class CrudClient<
|
||||
constructor(baseUrl?: string, defaultOptions?: ApiClientOptions,
|
||||
|
||||
public indexRoute?: IndexRoute,
|
||||
public byIdRoute?: ByIdRoute) {
|
||||
public byIdRoute?: ByIdRoute,
|
||||
public importRoute?: CrudImportRoute,
|
||||
public exportRoute?: CrudExportRoute,
|
||||
public exportMethod: "GET" | "POST" = "GET") {
|
||||
|
||||
super(baseUrl, defaultOptions)
|
||||
|
||||
@@ -54,6 +59,21 @@ export abstract class CrudClient<
|
||||
async destroy(id: string): Promise<Resolve<Overrides, 'destroyResponse', ApiResponse<ByIdRoute, "delete">>> {
|
||||
return this.delete<ByIdRoute>(this.byIdRoute as ByIdRoute, { params: { id } } as never) as never
|
||||
}
|
||||
|
||||
async importData(file: File): Promise<{ message?: string }> {
|
||||
const formData = new FormData()
|
||||
formData.append("file", file)
|
||||
const route = (this.importRoute ?? `${this.indexRoute}/import`) as string
|
||||
return this.postFormData(route, formData)
|
||||
}
|
||||
|
||||
async exportData(filters?: Record<string, unknown>): Promise<Blob> {
|
||||
const route = (this.exportRoute ?? `${this.indexRoute}/export`) as string
|
||||
if (this.exportMethod === "POST") {
|
||||
return this.fetchBlob(route, { method: "POST", body: filters ?? {} })
|
||||
}
|
||||
return this.fetchBlob(route)
|
||||
}
|
||||
}
|
||||
|
||||
export type BaseCrudItem = { id: number }
|
||||
|
||||
@@ -20275,7 +20275,7 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/import-parts": {
|
||||
"/api/parts/import": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
@@ -20325,7 +20325,7 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/export-parts": {
|
||||
"/api/parts/export": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
@@ -20393,7 +20393,7 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/toggle-part-status": {
|
||||
"/api/parts/toggle-status": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
@@ -20402,7 +20402,7 @@ export interface paths {
|
||||
};
|
||||
get?: never;
|
||||
put?: never;
|
||||
/** POST /api/toggle-part-status */
|
||||
/** POST /api/parts/toggle-status */
|
||||
post: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
||||
Reference in New Issue
Block a user