fix(deals): читать проекты из конверта { data } + чинить фикстуры LeadStatus
DealsView крашился (Cannot read properties of undefined reading 'map'): listProjects() читал data.projects, но ProjectController::index() отдаёт { data: [...] } после миграции на JsonResource — availableProjects=undefined ломал .map, фильтр «Проект» был пуст. Фикс: читать data.data ?? []. + deals-api.spec.ts тест на новый конверт + защитный []. + DealDetailHero.spec.ts: фикстуры LeadStatus (isSystem/sortOrder вместо order) — устранён pre-existing type-check error.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -260,10 +260,12 @@ export interface ApiProject {
|
||||
}
|
||||
|
||||
export async function listProjects(tenantId: number): Promise<ApiProject[]> {
|
||||
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 ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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> = {}): MockDeal {
|
||||
|
||||
@@ -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([]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user