fix(analytics): клиентские каналы согласования подписаны, а не сырыми ключами

Каналы из ссылки (sms/client/push/messenger) в блоках «Воронка коммуникаций» и «Путь заказа» выводились ключами БД; добавлены подписи + тесты.
This commit is contained in:
Hermes 2026-10-02 15:24:29 +02:00
parent f2a9249bba
commit 6dba84f22a
5 changed files with 64 additions and 1 deletions

View File

@ -1,7 +1,7 @@
const isLocalhost = self.location.hostname === "localhost" || self.location.hostname === "127.0.0.1";
if (!isLocalhost) {
const STATIC_CACHE = "construction-delivery-static-v132";
const STATIC_CACHE = "construction-delivery-static-v133";
const RUNTIME_CACHE = "construction-delivery-runtime-v119";
const APP_SHELL_URLS = ["/", "/client", "/index.html", "/manifest.webmanifest", "/icons/icon-192.png", "/icons/icon-512.png"];

View File

@ -26,6 +26,11 @@ const CHANNEL_LABELS = {
manual: 'Менеджер',
link: 'Ссылка из SMS',
automation: 'Автоматически',
// Клиентские каналы из ссылки (/delivery/{hash}?src=...) — до 29.09.2026 не писались.
sms: 'SMS-ссылка',
client: 'Ссылка (прямой заход)',
push: 'Push',
messenger: 'Мессенджер',
};
const STATUS_LABELS = {

View File

@ -80,6 +80,31 @@ describe("CommsFunnelBlock", () => {
expect(html).toContain("Ссылка из SMS");
});
it("подписывает клиентские каналы ссылки, а не показывает ключи БД", () => {
const clientChannels = renderToStaticMarkup(
<CommsFunnelBlock
funnel={{
...funnel,
channels: [
{ source: "sms", count: 12 },
{ source: "client", count: 5 },
{ source: "push", count: 2 },
{ source: "messenger", count: 1 },
],
}}
mobile={false}
periodLabel="7 дней"
/>,
);
expect(clientChannels).toContain("SMS-ссылка");
expect(clientChannels).toContain("Ссылка (прямой заход)");
expect(clientChannels).toContain("Push");
expect(clientChannels).toContain("Мессенджер");
// сырые ключи источника наружу не уходят
expect(clientChannels).not.toContain(">client<");
expect(clientChannels).not.toContain(">messenger<");
});
it("перечисляет тех, кто не берёт трубку, и тех, кто открыл ссылку без подтверждения", () => {
expect(html).toContain("Не поднимают трубку");
expect(html).toContain("9787617568");

View File

@ -34,6 +34,12 @@ const SOURCE_LABELS = {
link: 'Ссылка из SMS',
automation: 'Автоматически',
none: 'В обход (без даты)',
// Клиентские каналы из ссылки (/delivery/{hash}?src=...) — до 29.09.2026 не писались,
// поэтому в старых строках стоит пустой источник («В обход (без даты)»).
sms: 'SMS-ссылка',
client: 'Ссылка (прямой заход)',
push: 'Push',
messenger: 'Мессенджер',
};
const FunnelTooltip = ({ active, payload }) => {

View File

@ -65,6 +65,33 @@ describe("OrderPathFunnelBlock", () => {
expect(html).toContain("Доставка");
});
it("подписывает клиентские источники даты, а не показывает ключи БД", () => {
const withClientSources = renderToStaticMarkup(
<OrderPathFunnelBlock
funnel={{
...funnel,
order_path: {
...funnel.order_path,
sources: [
{ source: "sms", count: 20 },
{ source: "client", count: 9 },
{ source: "push", count: 4 },
{ source: "messenger", count: 2 },
],
},
}}
mobile={false}
periodLabel="7 дней"
/>,
);
expect(withClientSources).toContain("SMS-ссылка");
expect(withClientSources).toContain("Ссылка (прямой заход)");
expect(withClientSources).toContain("Push");
expect(withClientSources).toContain("Мессенджер");
expect(withClientSources).not.toContain(">client<");
expect(withClientSources).not.toContain(">messenger<");
});
it("на пустом периоде пишет заглушку", () => {
const e = renderToStaticMarkup(<OrderPathFunnelBlock funnel={empty} mobile periodLabel="Сегодня" />);
expect(e).toContain("За период заказов нет");