fix: clarify empty fishing plan shares
This commit is contained in:
@@ -31,7 +31,13 @@ import Layout from "../layouts/Layout.astro";
|
||||
catch { return []; }
|
||||
};
|
||||
const shared = new URLSearchParams(location.search).get("plan");
|
||||
if (shared) { try { const imported = normalisePlan(JSON.parse(shared)); if (imported.length) localStorage.setItem(planStorageKey, JSON.stringify(imported)); } catch { if (shareStatus) shareStatus.textContent = "Ссылка плана не распознана"; } }
|
||||
if (shared) {
|
||||
try {
|
||||
const imported = normalisePlan(JSON.parse(shared));
|
||||
if (imported.length) localStorage.setItem(planStorageKey, JSON.stringify(imported));
|
||||
else if (shareStatus) shareStatus.textContent = "В ссылке нет сохранённых точек";
|
||||
} catch { if (shareStatus) shareStatus.textContent = "Ссылка плана не распознана"; }
|
||||
}
|
||||
const render = () => {
|
||||
if (!list || !empty) return;
|
||||
const plan = readPlan();
|
||||
@@ -52,7 +58,9 @@ import Layout from "../layouts/Layout.astro";
|
||||
});
|
||||
};
|
||||
document.querySelector<HTMLButtonElement>("[data-plan-share]")?.addEventListener("click", async () => {
|
||||
const url = new URL(location.href); url.search = ""; url.searchParams.set("plan", JSON.stringify(readPlan()));
|
||||
const plan = readPlan();
|
||||
if (!plan.length) { if (shareStatus) shareStatus.textContent = "Сначала добавьте точку в план"; return; }
|
||||
const url = new URL(location.href); url.search = ""; url.searchParams.set("plan", JSON.stringify(plan));
|
||||
try {
|
||||
if (navigator.share) await navigator.share({ title: "Мой план рыбалки RF4", url: url.toString() });
|
||||
else await navigator.clipboard.writeText(url.toString());
|
||||
|
||||
@@ -94,3 +94,16 @@ test("plan import deduplicates the same point before applying the five-item cap"
|
||||
"/spots/vyunok-7450x7451",
|
||||
]);
|
||||
});
|
||||
|
||||
test("plan explains empty and malformed share states", async ({ page }) => {
|
||||
await page.goto("/plan");
|
||||
await page.getByRole("button", { name: "Поделиться планом" }).click();
|
||||
await expect(page.locator("[data-plan-share-status]")).toHaveText("Сначала добавьте точку в план");
|
||||
|
||||
await page.goto("/plan?plan=not-json");
|
||||
await expect(page.locator("[data-plan-share-status]")).toHaveText("Ссылка плана не распознана");
|
||||
|
||||
const emptyPlan = encodeURIComponent(JSON.stringify([]));
|
||||
await page.goto(`/plan?plan=${emptyPlan}`);
|
||||
await expect(page.locator("[data-plan-share-status]")).toHaveText("В ссылке нет сохранённых точек");
|
||||
});
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@
|
||||
- [ ] **U02 · Главный сценарий «рыба → водоём → точка → снасть».** Главная сохраняет рыбу, водоём, период и сортировку в shareable URL, явно показывает контекст запроса и даёт текстовый CTA «Открыть точку» на каждой карточке, включая mobile; первый экран ограничен пятью вариантами, а остальные доступны через сохраняющую query-контекст серверную пагинацию; empty-state предлагает вернуться к полному набору данных. Осталось добавить режим map. Acceptance: первый полезный вариант виден без регистрации, back/refresh сохраняют контекст, mobile не теряет фильтры.
|
||||
- [ ] **U03 · Evidence/trust card.** Общий evidence-контракт используется на activity-карточках, detail точки, водоёма и карточках снастей: freshness с текстовым `Свежо`/`Устарело`, явный период расчёта, completeness, confidence/статус, source badges и доступные доменные поля; при выборке меньше 3 явно показано отдельное состояние `Недостаточно данных`, ограниченный источник не смешивается с неполными полями, а явно переданные provenance-конфликты видны текстом. Targeted E2E и API-тест проверяют публичные пути, период, 48-часовой порог и конфликт источников; единый `passportDisplayStatus` дополнительно закрепляет приоритет `conflict` → `stale` → исходный статус unit-регрессией.
|
||||
- [ ] **U04 · List/map и progressive disclosure.** List остаётся честным базовым режимом: фильтры, сортировка, URL-состояние и evidence-карточки уже работают без имитации координатной карты. Следующий шаг — единый list/map-контракт после подтверждения геометрии; на mobile карта должна открываться отдельным действием. Вторичные raw/provenance-поля не исчезают и раскрываются по запросу.
|
||||
- [ ] **U05 · Mobile-first и сохранённый план рыбалки.** `/plan` поддерживает список до 5 уникальных локальных вариантов, удаление, очистку, переход к точке, print/PDF и восстановление из shareable URL; кнопка «Поделиться планом» использует native share или clipboard fallback. Detail-кнопка сохраняет данные с `aria-pressed` и восстанавливается после reload. Print/mobile-контракт проверяет 320/390 px, лимит импорта и отсутствие горизонтального overflow; импорт дедуплицирует точки, нормализует длины локальных текстовых полей, не теряет реальное значение confidence `0`, а карточка плана сравнивает подтверждённые метод/проводку и явно показывает риск по выборке/уверенности.
|
||||
- [ ] **U05 · Mobile-first и сохранённый план рыбалки.** `/plan` поддерживает список до 5 уникальных локальных вариантов, удаление, очистку, переход к точке, print/PDF и восстановление из shareable URL; кнопка «Поделиться планом» использует native share или clipboard fallback и явно сообщает, если план пуст или share-ссылка повреждена. Detail-кнопка сохраняет данные с `aria-pressed` и восстанавливается после reload. Print/mobile-контракт проверяет 320/390 px, лимит импорта и отсутствие горизонтального overflow; импорт дедуплицирует точки, нормализует длины локальных текстовых полей, не теряет реальное значение confidence `0`, а карточка плана сравнивает подтверждённые метод/проводку и явно показывает риск по выборке/уверенности.
|
||||
- [ ] **U06 · Контентная и визуальная иерархия.** Для detail точки действие «Что взять» выделено отдельным заголовком, provenance и качество собраны в общем паспорте данных, а подтверждённые метод/проводка видны рядом с последними уловами; статусы дополнительно передаются текстом, малая выборка не маркируется как готовая рекомендация, а дублирующие catches/players/confidence убраны из вторичной колонки activity-карточки. Mobile route-contract проверяет первый ответ и действие на home, spot, waterbody, plan и tackle, а task regression требует source/evidence-поля; остаётся ручной review визуальных деталей по [ux-task-review-2026-09-21.md](ux-task-review-2026-09-21.md).
|
||||
- [ ] **U07 · UX-приёмка и измерения.** Playwright-контракты уже покрывают query journey, сквозной task journey, evidence states, saved plan, share/print, accessibility и visual matrix; unit-контракт добавил детерминированные stale- и blocked-подписи, а insufficient-data теперь отделён от incomplete в публичном паспорте. `/status` явно сообщает, что при ограничении источника опубликованные данные сохранены. Visual-matrix regression теперь проверяет `204` комбинации, включая spot detail, plan и tackle analytics; representative review зафиксирован в `docs/ux-reference-review-2026-09-21.md`. Остаётся получить production Lighthouse/CLS/INP/time-to-first-useful-answer после пилота и принять решение о долговременном хранении screenshots.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user