diff --git a/public/service-worker.js b/public/service-worker.js index e646b7e..cad0fda 100644 --- a/public/service-worker.js +++ b/public/service-worker.js @@ -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-v124"; + const STATIC_CACHE = "construction-delivery-static-v125"; const RUNTIME_CACHE = "construction-delivery-runtime-v119"; const APP_SHELL_URLS = ["/", "/client", "/index.html", "/manifest.webmanifest", "/icons/icon-192.png", "/icons/icon-512.png"]; diff --git a/src/components/admin/analytics/CommsFunnelBlock.jsx b/src/components/admin/analytics/CommsFunnelBlock.jsx index 1159462..49a0dd8 100644 --- a/src/components/admin/analytics/CommsFunnelBlock.jsx +++ b/src/components/admin/analytics/CommsFunnelBlock.jsx @@ -207,7 +207,10 @@ export const CommsFunnelBlock = ({ funnel, isLoading, mobile = false, periodLabe {a.attempt}-я {a.total} - {a.answered} ({a.answered_pct}%) + {a.answered} + {mobile + ?
{a.answered_pct}%
+ : ({a.answered_pct}%)} {a.confirmed} {a.no_answer} @@ -237,6 +240,34 @@ export const CommsFunnelBlock = ({ funnel, isLoading, mobile = false, periodLabe
Не поднимают трубку
+ {mobile ? ( + noAnswer.length === 0 ? ( +
+ Нет таких номеров за период +
+ ) : ( +
+ {noAnswer.map((n) => ( +
+
+ {n.phone} + + попыток: {n.attempts} + +
+
+ {n.town} · {KIND_LABELS[n.kind] || n.kind} · {STATUS_LABELS[n.status] || n.status || '—'} +
+
+ последний звонок {fmtDateTime(n.last_call)} +
+
+ ))} +
+ ) + ) : ( @@ -263,6 +294,7 @@ export const CommsFunnelBlock = ({ funnel, isLoading, mobile = false, periodLabe ))}
+ )} {/* ── Открыли ссылку, но не подтвердили ───────────────────────────── */} @@ -270,6 +302,32 @@ export const CommsFunnelBlock = ({ funnel, isLoading, mobile = false, periodLabe
Открыли ссылку, но не подтвердили
+ {mobile ? ( + openedNoConfirm.length === 0 ? ( +
+ Все, кто открыл ссылку, подтвердили +
+ ) : ( +
+ {openedNoConfirm.map((o) => ( +
+
+ {o.num} + открытий: {o.opens} +
+
+ {o.name} · {o.phone} +
+
+ последнее открытие {fmtDateTime(o.opened)} +
+
+ ))} +
+ ) + ) : ( @@ -294,6 +352,7 @@ export const CommsFunnelBlock = ({ funnel, isLoading, mobile = false, periodLabe ))}
+ )} ); diff --git a/src/components/admin/analytics/CommsFunnelBlock.test.jsx b/src/components/admin/analytics/CommsFunnelBlock.test.jsx index 6cb115c..68f0f54 100644 --- a/src/components/admin/analytics/CommsFunnelBlock.test.jsx +++ b/src/components/admin/analytics/CommsFunnelBlock.test.jsx @@ -97,6 +97,18 @@ describe("CommsFunnelBlock", () => { expect(empty).toContain("Подтверждений за период нет"); }); + it("на мобильном списки «не берут трубку» и «открыли без подтверждения» раскладываются без прокрутки", () => { + const m = renderToStaticMarkup(); + expect(m).toContain("попыток: 2"); + expect(m).toContain("Севастополь · самовывоз · В ручной работе"); + expect(m).toContain("последний звонок"); + expect(m).toContain("открытий: 14"); + expect(m).toContain("ЗАКАЗЧИК · 9788324113"); + // на мобильном процент по попыткам уходит во вторую строку, а не в скобках + expect(m).not.toContain("(65.6%)"); + expect(m).toContain("65.6%"); + }); + it("показывает заглушку загрузки, пока данных нет", () => { const loading = renderToStaticMarkup(); expect(loading).toContain("Воронка коммуникаций");