diff --git a/app/resources/js/api/deals.ts b/app/resources/js/api/deals.ts index 6c19c1d8..35de5937 100644 --- a/app/resources/js/api/deals.ts +++ b/app/resources/js/api/deals.ts @@ -260,10 +260,12 @@ export interface ApiProject { } export async function listProjects(tenantId: number): Promise { - const { data } = await apiClient.get<{ projects: ApiProject[] }>('/api/projects', { + // ProjectController::index() отдаёт { data: ProjectResource::collection(...) }. + // `?? []` — защита от undefined.map в DealsView при нештатном ответе. + const { data } = await apiClient.get<{ data: ApiProject[] }>('/api/projects', { params: { tenant_id: tenantId }, }); - return data.projects; + return data.data ?? []; } /** diff --git a/app/tests/Frontend/DealDetailHero.spec.ts b/app/tests/Frontend/DealDetailHero.spec.ts index d0b0d451..8c7d4ae0 100644 --- a/app/tests/Frontend/DealDetailHero.spec.ts +++ b/app/tests/Frontend/DealDetailHero.spec.ts @@ -8,9 +8,9 @@ import type { LeadStatus } from '../../resources/js/composables/leadStatuses'; const vuetify = createVuetify(); const statuses: LeadStatus[] = [ - { slug: 'new', nameRu: 'Новая сделка', colorHex: '#5b2db2', order: 1 } as LeadStatus, - { slug: 'viewed', nameRu: 'Просмотрено', colorHex: '#5a2db2', order: 2 } as LeadStatus, - { slug: 'won', nameRu: 'Куплено', colorHex: '#00A36C', order: 3 } as LeadStatus, + { slug: 'new', nameRu: 'Новая сделка', isSystem: true, sortOrder: 1, colorHex: '#5b2db2' }, + { slug: 'viewed', nameRu: 'Просмотрено', isSystem: true, sortOrder: 2, colorHex: '#5a2db2' }, + { slug: 'won', nameRu: 'Куплено', isSystem: true, sortOrder: 3, colorHex: '#00A36C' }, ]; function makeDeal(over: Partial = {}): MockDeal { diff --git a/app/tests/Frontend/deals-api.spec.ts b/app/tests/Frontend/deals-api.spec.ts index b0489839..b3e78128 100644 --- a/app/tests/Frontend/deals-api.spec.ts +++ b/app/tests/Frontend/deals-api.spec.ts @@ -168,12 +168,21 @@ describe('api/deals', () => { expect(r).toHaveLength(1); }); - it('listProjects() GET /api/projects + unwraps data.projects', async () => { + it('listProjects() GET /api/projects + unwraps { data: [...] } (JsonResource collection)', async () => { + // ProjectController::index() отдаёт response()->json(['data' => ProjectResource::collection(...)]). vi.mocked(apiClient.get).mockResolvedValue({ - data: { projects: [{ id: 1, name: 'P', tag: 'site', type: 'webhook' }] }, + data: { data: [{ id: 1, name: 'B1_Окна СПб' }, { id: 2, name: 'B2_Двери' }] }, }); const r = await listProjects(1); expect(apiClient.get).toHaveBeenCalledWith('/api/projects', { params: { tenant_id: 1 } }); - expect(r[0].name).toBe('P'); + expect(Array.isArray(r)).toBe(true); + expect(r).toHaveLength(2); + expect(r[0].name).toBe('B1_Окна СПб'); + }); + + it('listProjects() возвращает [] при ответе без массива (защита от undefined.map)', async () => { + vi.mocked(apiClient.get).mockResolvedValue({ data: {} }); + const r = await listProjects(1); + expect(r).toEqual([]); }); });