feat(T02): vehicle management + mobile.de push + vehicle UI
- Vehicle model: 25+ fields, 5 vehicle types, soft-delete - Vehicle CRUD: 7 API endpoints with JWT auth, filter/sort/paginate - mobile.de: push/update/delete listings, field mapping, retry logic - MobileDeListing model for sync status tracking - Frontend: VehicleList, VehicleForm, VehicleDetail, MobileDeStatus - 73 backend tests (82% coverage), 16 frontend tests
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
import { apiFetch, type PaginatedResponse } from './api';
|
||||
|
||||
export interface VehicleResponse {
|
||||
id: string;
|
||||
make: string;
|
||||
model: string;
|
||||
fin: string;
|
||||
year?: number;
|
||||
first_registration?: string;
|
||||
power_kw?: number;
|
||||
power_hp?: number;
|
||||
fuel_type?: string;
|
||||
transmission?: string;
|
||||
color?: string;
|
||||
condition: string;
|
||||
location?: string;
|
||||
availability: string;
|
||||
price: number;
|
||||
vehicle_type: string;
|
||||
lkw_type?: string;
|
||||
machine_type?: string;
|
||||
body_type?: string;
|
||||
operating_hours?: number;
|
||||
operating_hours_unit?: string;
|
||||
mileage_km?: number;
|
||||
description?: string;
|
||||
created_at?: string;
|
||||
updated_at?: string;
|
||||
deleted_at?: string | null;
|
||||
}
|
||||
|
||||
export interface VehicleCreateData {
|
||||
make: string;
|
||||
model: string;
|
||||
fin: string;
|
||||
year?: number;
|
||||
first_registration?: string;
|
||||
power_kw?: number;
|
||||
fuel_type?: string;
|
||||
transmission?: string;
|
||||
color?: string;
|
||||
condition?: string;
|
||||
location?: string;
|
||||
availability?: string;
|
||||
price: number;
|
||||
vehicle_type: string;
|
||||
lkw_type?: string;
|
||||
machine_type?: string;
|
||||
body_type?: string;
|
||||
operating_hours?: number;
|
||||
operating_hours_unit?: string;
|
||||
mileage_km?: number;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export interface VehicleUpdateData {
|
||||
make?: string;
|
||||
model?: string;
|
||||
fin?: string;
|
||||
year?: number;
|
||||
first_registration?: string;
|
||||
power_kw?: number;
|
||||
fuel_type?: string;
|
||||
transmission?: string;
|
||||
color?: string;
|
||||
condition?: string;
|
||||
location?: string;
|
||||
availability?: string;
|
||||
price?: number;
|
||||
vehicle_type?: string;
|
||||
lkw_type?: string;
|
||||
machine_type?: string;
|
||||
body_type?: string;
|
||||
operating_hours?: number;
|
||||
operating_hours_unit?: string;
|
||||
mileage_km?: number;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export interface VehicleListParams {
|
||||
page?: number;
|
||||
page_size?: number;
|
||||
type?: string;
|
||||
availability?: string;
|
||||
min_price?: number;
|
||||
max_price?: number;
|
||||
search?: string;
|
||||
sort?: string;
|
||||
}
|
||||
|
||||
export interface MobileDeStatusResponse {
|
||||
synced: boolean;
|
||||
ad_id?: string;
|
||||
synced_at?: string;
|
||||
sync_status: string;
|
||||
error_log?: string;
|
||||
}
|
||||
|
||||
export interface MobileDePushResponse {
|
||||
message: string;
|
||||
vehicle_id: string;
|
||||
listing_id?: string;
|
||||
}
|
||||
|
||||
export async function listVehicles(params: VehicleListParams = {}): Promise<PaginatedResponse<VehicleResponse>> {
|
||||
const query = new URLSearchParams();
|
||||
if (params.page) query.set('page', String(params.page));
|
||||
if (params.page_size) query.set('page_size', String(params.page_size));
|
||||
if (params.type) query.set('type', params.type);
|
||||
if (params.availability) query.set('availability', params.availability);
|
||||
if (params.min_price !== undefined) query.set('min_price', String(params.min_price));
|
||||
if (params.max_price !== undefined) query.set('max_price', String(params.max_price));
|
||||
if (params.search) query.set('search', params.search);
|
||||
if (params.sort) query.set('sort', params.sort);
|
||||
const qs = query.toString();
|
||||
return apiFetch<PaginatedResponse<VehicleResponse>>(`/vehicles/${qs ? `?${qs}` : ''}`);
|
||||
}
|
||||
|
||||
export async function getVehicle(id: string): Promise<VehicleResponse> {
|
||||
return apiFetch<VehicleResponse>(`/vehicles/${id}`);
|
||||
}
|
||||
|
||||
export async function createVehicle(data: VehicleCreateData): Promise<VehicleResponse> {
|
||||
return apiFetch<VehicleResponse>('/vehicles/', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateVehicle(id: string, data: VehicleUpdateData): Promise<VehicleResponse> {
|
||||
return apiFetch<VehicleResponse>(`/vehicles/${id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
}
|
||||
|
||||
export async function deleteVehicle(id: string): Promise<VehicleResponse> {
|
||||
return apiFetch<VehicleResponse>(`/vehicles/${id}`, { method: 'DELETE' });
|
||||
}
|
||||
|
||||
export async function pushToMobileDe(vehicleId: string): Promise<MobileDePushResponse> {
|
||||
return apiFetch<MobileDePushResponse>(`/vehicles/${vehicleId}/mobile-de/push`, {
|
||||
method: 'POST',
|
||||
});
|
||||
}
|
||||
|
||||
export async function getMobileDeStatus(vehicleId: string): Promise<MobileDeStatusResponse> {
|
||||
return apiFetch<MobileDeStatusResponse>(`/vehicles/${vehicleId}/mobile-de/status`);
|
||||
}
|
||||
Reference in New Issue
Block a user