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("Воронка коммуникаций");