- Fix 98 TypeScript errors across 37 files: - Service layer double-unwrapping (subscriptionService, distributionService, gearService) - Self-referencing variables in SearchPageResults - FeedView/ExploreView .posts→.items alignment - useQueueSync Zustand subscribe API - AdminAuditLogsView missing interface fields - Toast proxy type, interceptor type narrowing - 22 unused imports/variables removed - 5 storybook mock data fixes - Align frontend API calls with backend endpoints: - Analytics: useAnalyticsView now calls /creator/analytics/dashboard (was /analytics) - Chat: chatService uses /conversations (was mock data), WS URL from backend token - Dashboard StatsSection: uses real /dashboard API data (was hardcoded zeros) - Settings: suppress 2FA toast error when endpoint unavailable - Fix marketplace products: seed uses 'active' status (was 'published') - Enrich seed: admin follows all creators (feed has content) - Optimize bundle: vendor catch-all 793KB→318KB gzip (-60%) Split into vendor-charts, vendor-emoji, vendor-swagger, vendor-media, etc. - Clean repo: remove ~100 orphaned screenshots, audit reports, logs from root Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
173 lines
5.6 KiB
TypeScript
173 lines
5.6 KiB
TypeScript
/**
|
|
* Gear Service
|
|
* Equipment/gear inventory management — calls backend API
|
|
*/
|
|
|
|
import { apiClient } from './api/client';
|
|
import type { GearItem } from '@/types';
|
|
|
|
function mapApiItemToGearItem(api: Record<string, unknown>): GearItem {
|
|
const purchaseDate = api.purchaseDate as string | undefined;
|
|
const warrantyExpire = api.warrantyExpire as string | undefined;
|
|
return {
|
|
id: String(api.id ?? ''),
|
|
name: String(api.name ?? ''),
|
|
category: String(api.category ?? ''),
|
|
brand: String(api.brand ?? ''),
|
|
model: String(api.model ?? ''),
|
|
serialNumber: api.serialNumber as string | undefined,
|
|
image: api.image as string | undefined,
|
|
images: Array.isArray(api.images) ? (api.images as string[]) : undefined,
|
|
status: (api.status as GearItem['status']) ?? 'Active',
|
|
condition: (api.condition as GearItem['condition']) ?? 'Good',
|
|
purchaseDate: purchaseDate ?? '',
|
|
purchasePrice: Number(api.purchasePrice ?? 0),
|
|
currency: (api.currency as GearItem['currency']) ?? 'USD',
|
|
vendor: api.vendor as string | undefined,
|
|
orderNumber: api.orderNumber as string | undefined,
|
|
warrantyExpire,
|
|
warrantyType: api.warrantyType as GearItem['warrantyType'],
|
|
supportContact: api.supportContact as string | undefined,
|
|
specs: (api.specs as GearItem['specs']) ?? undefined,
|
|
notes: api.notes as string | undefined,
|
|
documents: (api.documents as GearItem['documents']) ?? undefined,
|
|
maintenanceHistory: (api.maintenanceHistory as GearItem['maintenanceHistory']) ?? undefined,
|
|
};
|
|
}
|
|
|
|
export const gearService = {
|
|
async list(): Promise<GearItem[]> {
|
|
const response = await apiClient.get<{ items: Record<string, unknown>[] }>(
|
|
'/inventory/gear',
|
|
);
|
|
const items = response.data?.items ?? [];
|
|
return Array.isArray(items) ? items.map(mapApiItemToGearItem) : [];
|
|
},
|
|
|
|
async getAll(): Promise<GearItem[]> {
|
|
return this.list();
|
|
},
|
|
|
|
async get(id: string): Promise<GearItem | null> {
|
|
const response = await apiClient.get<{ item: Record<string, unknown> }>(
|
|
`/inventory/gear/${id}`,
|
|
);
|
|
const item = response.data?.item;
|
|
if (!item) return null;
|
|
return mapApiItemToGearItem(item);
|
|
},
|
|
|
|
async getById(id: string): Promise<GearItem | null> {
|
|
return this.get(id);
|
|
},
|
|
|
|
async create(item: Partial<GearItem>): Promise<GearItem> {
|
|
const response = await apiClient.post<{ item: Record<string, unknown> }>(
|
|
'/inventory/gear',
|
|
item,
|
|
);
|
|
const created = response.data?.item;
|
|
if (!created) throw new Error('Invalid response from create gear');
|
|
return mapApiItemToGearItem(created);
|
|
},
|
|
|
|
async update(id: string, item: Partial<GearItem>): Promise<GearItem> {
|
|
const response = await apiClient.put<{ item: Record<string, unknown> }>(
|
|
`/inventory/gear/${id}`,
|
|
item,
|
|
);
|
|
const updated = response.data?.item;
|
|
if (!updated) throw new Error('Invalid response from update gear');
|
|
return mapApiItemToGearItem(updated);
|
|
},
|
|
|
|
async delete(id: string): Promise<void> {
|
|
await apiClient.delete(`/inventory/gear/${id}`);
|
|
},
|
|
|
|
async listDocuments(gearId: string): Promise<GearDocument[]> {
|
|
const response = await apiClient.get<{ documents: GearDocument[] }>(
|
|
`/inventory/gear/${gearId}/documents`,
|
|
);
|
|
const data = response.data as { documents?: GearDocument[] } | undefined;
|
|
const docs = data?.documents;
|
|
return Array.isArray(docs) ? docs : [];
|
|
},
|
|
|
|
async uploadDocument(
|
|
gearId: string,
|
|
file: File,
|
|
type = 'invoice',
|
|
): Promise<GearDocument> {
|
|
const formData = new FormData();
|
|
formData.append('file', file);
|
|
formData.append('type', type);
|
|
const response = await apiClient.post<{ document: GearDocument }>(
|
|
`/inventory/gear/${gearId}/documents`,
|
|
formData,
|
|
{ headers: { 'Content-Type': 'multipart/form-data' } },
|
|
);
|
|
const docData = response.data as { document?: GearDocument } | undefined;
|
|
const doc = docData?.document;
|
|
if (!doc) throw new Error('Invalid response from upload document');
|
|
return doc;
|
|
},
|
|
|
|
async deleteDocument(gearId: string, docId: string): Promise<void> {
|
|
await apiClient.delete(`/inventory/gear/${gearId}/documents/${docId}`);
|
|
},
|
|
|
|
async listRepairs(gearId: string): Promise<GearRepair[]> {
|
|
const response = await apiClient.get<{ repairs: GearRepair[] }>(
|
|
`/inventory/gear/${gearId}/repairs`,
|
|
);
|
|
const repairsData = response.data as { repairs?: GearRepair[] } | undefined;
|
|
const repairs = repairsData?.repairs;
|
|
return Array.isArray(repairs) ? repairs : [];
|
|
},
|
|
|
|
async createRepair(gearId: string, data: CreateRepairInput): Promise<GearRepair> {
|
|
const response = await apiClient.post<{ repair: GearRepair }>(
|
|
`/inventory/gear/${gearId}/repairs`,
|
|
data,
|
|
);
|
|
const repairData = response.data as { repair?: GearRepair } | undefined;
|
|
const repair = repairData?.repair;
|
|
if (!repair) throw new Error('Invalid response from create repair');
|
|
return repair;
|
|
},
|
|
|
|
async deleteRepair(gearId: string, repairId: string): Promise<void> {
|
|
await apiClient.delete(`/inventory/gear/${gearId}/repairs/${repairId}`);
|
|
},
|
|
};
|
|
|
|
export interface GearDocument {
|
|
id: string;
|
|
gear_id: string;
|
|
type: string;
|
|
storage_key: string;
|
|
filename: string;
|
|
uploaded_at: string;
|
|
}
|
|
|
|
export interface GearRepair {
|
|
id: string;
|
|
gear_id: string;
|
|
repair_date: string;
|
|
description: string;
|
|
cost_cents: number;
|
|
currency: string;
|
|
provider: string;
|
|
notes: string;
|
|
created_at: string;
|
|
}
|
|
|
|
export interface CreateRepairInput {
|
|
repair_date: string;
|
|
description?: string;
|
|
cost_cents?: number;
|
|
currency?: string;
|
|
provider?: string;
|
|
notes?: string;
|
|
}
|