Files
portal/app/resources/js/api/dashboard.ts
T
Дмитрий 1cb3b56f70
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
fix(dashboard): верхняя строка дашборда — настоящие числа вместо заглушки — F5
Строка-приветствие показывала захардкоженную рыбу: +3 новых лида с утра,
сегодня 11 / вчера 38, средняя стоимость 2 248 руб. Числа ни к чему не были
привязаны — остаток прототипа Sprint 4.

Бэкенд: DashboardController.summary отдаёт avg_lead_cost_rub — среднее
фактически списанных rub-сумм за окно периода: AVG price_per_lead_kopecks
WHERE charge_source rub делить на 100; null если в окне нет rub-списаний.
Тот же источник, что карточка сделки F2.

Фронт: DashboardPageHead принимает пропы сегодня/вчера/средняя; сегодня и
вчера берутся из activity.points последняя точка сегодня; средняя из
avg_lead_cost_rub, прочерк при null. Размытое +3 с утра убрано.

TDD: 2 Pest DashboardSummaryTest 10/10 + 4 vitest DashboardPageHead;
полная фронт-сюита 959 passed / 3 skipped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 16:02:04 +03:00

29 lines
1.2 KiB
TypeScript

import { apiClient } from './client';
/**
* API-клиент дашборда (audit C1/J3). Эндпоинт GET /api/dashboard/summary.
* На MVP без auth — tenant_id параметром (на prod возьмётся из middleware).
*/
export type DeltaDir = 'up' | 'down' | 'neutral';
export type DashboardRange = 'today' | '7d' | '30d';
export interface DashboardSummary {
range: string;
leads_received: { value: number; delta_pct: number; delta_dir: DeltaDir };
conversion: { value: number; delta_pp: number; delta_dir: DeltaDir };
active_projects: { active: number; limit: number };
balance: { amount_rub: string; runway_days: number; runway_leads: number };
activity: { points: number[]; labels: string[]; max: number };
funnel: Record<string, number>;
/** Средняя стоимость лида (₽) за окно периода; null — если в окне нет rub-списаний. */
avg_lead_cost_rub: number | null;
}
export async function getDashboardSummary(tenantId: number, range: DashboardRange): Promise<DashboardSummary> {
const { data } = await apiClient.get<DashboardSummary>('/api/dashboard/summary', {
params: { tenant_id: tenantId, range },
});
return data;
}