228 lines
7.5 KiB
TypeScript
228 lines
7.5 KiB
TypeScript
import { api } from '@/lib/api'
|
|
import type {
|
|
PaginatedResponse,
|
|
RegionResponse,
|
|
ManageRegionResponse,
|
|
RegionHierarchyResponse,
|
|
RegionDashboardResponse,
|
|
RegionManageEntryResponse,
|
|
RegionManageEntryType,
|
|
RouteResponse,
|
|
RouteVisitResponse,
|
|
VehicleResponse,
|
|
WarehouseResponse,
|
|
VehicleType,
|
|
WarehouseType,
|
|
} from '@/types/api'
|
|
|
|
const VEHICLE_TYPE_CODES: Record<VehicleType, number> = {
|
|
Car: 0,
|
|
Truck: 1,
|
|
Van: 2,
|
|
Motorcycle: 3,
|
|
Bicycle: 4,
|
|
}
|
|
|
|
const VEHICLE_TYPE_VALUES = ['Car', 'Truck', 'Van', 'Motorcycle', 'Bicycle'] as const
|
|
|
|
function normalizeVehicleType(type: VehicleType | number): VehicleType {
|
|
if (typeof type === 'number') {
|
|
return VEHICLE_TYPE_VALUES[type] ?? 'Car'
|
|
}
|
|
|
|
return type
|
|
}
|
|
|
|
function normalizeVehicle(
|
|
vehicle: VehicleResponse | (Omit<VehicleResponse, 'type'> & { type: VehicleType | number })
|
|
): VehicleResponse {
|
|
return {
|
|
...vehicle,
|
|
type: normalizeVehicleType(vehicle.type),
|
|
}
|
|
}
|
|
|
|
function normalizeVehicleListResponse(
|
|
response: PaginatedResponse<VehicleResponse> | (Omit<VehicleResponse, 'type'> & { type: VehicleType | number })[],
|
|
params?: VehicleListParams
|
|
): PaginatedResponse<VehicleResponse> {
|
|
if (Array.isArray(response)) {
|
|
const page = params?.page ?? 1
|
|
const pageSize = params?.pageSize ?? (response.length || 1)
|
|
const start = (page - 1) * pageSize
|
|
const items = response.slice(start, start + pageSize).map(normalizeVehicle)
|
|
|
|
return {
|
|
page,
|
|
pageSize,
|
|
total: response.length,
|
|
items,
|
|
}
|
|
}
|
|
|
|
return {
|
|
...response,
|
|
items: response.items.map(normalizeVehicle),
|
|
}
|
|
}
|
|
|
|
function serializeVehicleBody(body: VehicleBody | Partial<VehicleBody>) {
|
|
return {
|
|
...body,
|
|
...(body.type ? { type: VEHICLE_TYPE_CODES[body.type] } : {}),
|
|
}
|
|
}
|
|
|
|
// ─── Pagination ───────────────────────────────────────────────────────────────
|
|
|
|
export interface PageParams {
|
|
page?: number
|
|
pageSize?: number
|
|
}
|
|
|
|
// ─── Regions ──────────────────────────────────────────────────────────────────
|
|
|
|
export interface RegionBody {
|
|
name: string
|
|
code?: string
|
|
isActive?: boolean
|
|
}
|
|
|
|
export const regions = {
|
|
list: (params?: PageParams) =>
|
|
api.get<PaginatedResponse<RegionResponse>>('/regions', { params }).then(r => r.data),
|
|
|
|
nextCode: () =>
|
|
api.get<{ code: string }>('/regions/next-code').then(r => r.data),
|
|
|
|
get: (id: string) =>
|
|
api.get<RegionResponse>(`/regions/${id}`).then(r => r.data),
|
|
|
|
create: (body: RegionBody) =>
|
|
api.post<RegionResponse>('/regions', body).then(r => r.data),
|
|
|
|
update: (id: string, body: Partial<RegionBody>) =>
|
|
api.put<RegionResponse>(`/regions/${id}`, body).then(r => r.data),
|
|
|
|
remove: (id: string) =>
|
|
api.delete(`/regions/${id}`),
|
|
|
|
// Consolidated replacement for the old separate setTarget/setBudget/mapAgency/setTaxRule
|
|
// calls — pass only the fields you want to change (Period is required alongside targetValue
|
|
// and/or budgetAmount).
|
|
manage: (id: string, body: { period?: string; targetValue?: number; budgetAmount?: number; agencyUserId?: string; ruleConfig?: string }) =>
|
|
api.put<ManageRegionResponse>(`/regions/${id}/manage`, body).then(r => r.data),
|
|
|
|
// Flat CRUD-list view over targets/budgets/tax-rules/agency-maps across all regions.
|
|
manageEntries: () =>
|
|
api.get<RegionManageEntryResponse[]>('/regions/manage-entries').then(r => r.data),
|
|
|
|
removeManageEntry: (entryType: RegionManageEntryType, id: string) =>
|
|
api.delete(`/regions/manage-entries/${entryType}/${id}`),
|
|
|
|
hierarchy: (id: string) =>
|
|
api.get<RegionHierarchyResponse>(`/regions/${id}/hierarchy`).then(r => r.data),
|
|
|
|
dashboard: (id: string, period?: string) =>
|
|
api.get<RegionDashboardResponse>(`/regions/${id}/dashboard`, { params: { period } }).then(r => r.data),
|
|
}
|
|
|
|
// ─── Routes ───────────────────────────────────────────────────────────────────
|
|
|
|
export interface RouteBody {
|
|
regionId: string
|
|
routeName: string
|
|
startPoint?: string | null
|
|
endPoint?: string | null
|
|
length?: number | null
|
|
isActive?: boolean
|
|
}
|
|
|
|
export const routes = {
|
|
list: (params?: PageParams & { regionId?: string }) =>
|
|
api.get<PaginatedResponse<RouteResponse>>('/routes', { params }).then(r => r.data),
|
|
|
|
get: (id: string) =>
|
|
api.get<RouteResponse>(`/routes/${id}`).then(r => r.data),
|
|
|
|
create: (body: RouteBody) =>
|
|
api.post<RouteResponse>('/routes', body).then(r => r.data),
|
|
|
|
update: (id: string, body: Partial<RouteBody>) =>
|
|
api.put<RouteResponse>(`/routes/${id}`, body).then(r => r.data),
|
|
|
|
remove: (id: string) =>
|
|
api.delete(`/routes/${id}`),
|
|
|
|
assignStores: (id: string, storeIds: string[]) =>
|
|
api.post<RouteResponse>(`/routes/${id}/stores`, { storeIds }).then(r => r.data),
|
|
|
|
assignOwner: (id: string, salesRepId: string) =>
|
|
api.put<RouteResponse>(`/routes/${id}/owner`, { salesRepId }).then(r => r.data),
|
|
|
|
checkIn: (id: string, body: { storeId: string; latitude: number; longitude: number; checkedInByUserId: string }) =>
|
|
api.post<RouteVisitResponse>(`/routes/${id}/visits/check-in`, body).then(r => r.data),
|
|
|
|
checkOut: (id: string, body: { storeId: string }) =>
|
|
api.post<RouteVisitResponse>(`/routes/${id}/visits/check-out`, body).then(r => r.data),
|
|
}
|
|
|
|
// ─── Vehicles ─────────────────────────────────────────────────────────────────
|
|
|
|
export interface VehicleBody {
|
|
regNumber: string
|
|
numberPlate: string
|
|
type: VehicleType
|
|
}
|
|
|
|
export interface VehicleListParams extends PageParams {
|
|
available?: boolean
|
|
isActive?: boolean
|
|
}
|
|
|
|
export const vehicles = {
|
|
list: (params?: VehicleListParams) =>
|
|
api.get<PaginatedResponse<VehicleResponse> | VehicleResponse[]>('/vehicles', { params }).then(r =>
|
|
normalizeVehicleListResponse(r.data, params)
|
|
),
|
|
|
|
get: (id: string) =>
|
|
api.get<VehicleResponse>(`/vehicles/${id}`).then(r => normalizeVehicle(r.data)),
|
|
|
|
create: (body: VehicleBody) =>
|
|
api.post<VehicleResponse>('/vehicles', serializeVehicleBody(body)).then(r => normalizeVehicle(r.data)),
|
|
|
|
update: (id: string, body: Partial<VehicleBody>) =>
|
|
api.put<VehicleResponse>(`/vehicles/${id}`, serializeVehicleBody(body)).then(r => normalizeVehicle(r.data)),
|
|
|
|
remove: (id: string) =>
|
|
api.delete(`/vehicles/${id}`),
|
|
}
|
|
|
|
// ─── Warehouses ───────────────────────────────────────────────────────────────
|
|
|
|
export interface WarehouseBody {
|
|
name: string
|
|
location: string
|
|
type: WarehouseType
|
|
vehicleId?: string | null
|
|
isActive?: boolean
|
|
}
|
|
|
|
export const warehouses = {
|
|
list: (params?: PageParams) =>
|
|
api.get<PaginatedResponse<WarehouseResponse>>('/warehouses', { params }).then(r => r.data),
|
|
|
|
get: (id: string) =>
|
|
api.get<WarehouseResponse>(`/warehouses/${id}`).then(r => r.data),
|
|
|
|
create: (body: WarehouseBody) =>
|
|
api.post<WarehouseResponse>('/warehouses', body).then(r => r.data),
|
|
|
|
update: (id: string, body: Partial<WarehouseBody>) =>
|
|
api.put<WarehouseResponse>(`/warehouses/${id}`, body).then(r => r.data),
|
|
|
|
remove: (id: string) =>
|
|
api.delete(`/warehouses/${id}`),
|
|
}
|