veza/apps/web/src/services/gearService.ts
senke 6fad0ad68d fix: stabilize frontend — 98 TS errors to 0, align API endpoints, optimize bundle
- 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>
2026-03-24 21:18:49 +01:00

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;
}