Restore school tabs and filters after refresh.

The URL keeps the open school and current view; sessionStorage keeps list filters and searches so F5 and re-entry do not dump the player on an empty map.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Leonid Pershin
2026-08-20 12:03:04 +03:00
co-authored by Cursor
parent d8a2c2903c
commit 36ec5e9f8e
16 changed files with 1104 additions and 62 deletions
+32
View File
@@ -143,3 +143,35 @@
Ручной `CHANGELOG.md`. Запись на пользователе в `users.json`. Вызов git из бегущего процесса.
Бамп версии сокета. Окно внутри открытой школы.
## Состояние экрана
### Зачем
Менеджер — списки с фильтрами. Сейчас они живут только в RAM: F5 всегда меню, повторный вход
сбрасывает вкладки и запросы. Игрок сравнивает людей и соискателей; потерять «ученики 5А» на
обновлении — дырка в уже живых экранах, не новая фича.
### Было / Стало / Почему
**Было.** SPA без адреса. `GameScreen.show` и `PeoplePanel.show` обнуляют вкладки, фильтры и
выбор. Язык уже в `localStorage`; игровые часы — на сервере.
**Стало.** Query URL держит *где я*: школа, обзор/управление, карта/люди, выбранные комната и
человек. `sessionStorage` по `schoolId` держит фильтры, поиски, сорт, страницу, вкладку карточки
и класс сетки — и последний маршрут, чтобы вход с меню поднял то же место. F5 с `?school=`
шлёт тот же `OpenSchool`, что карточка. Вход/выход — `pushState`; смена вкладки и фильтра —
`replaceState`, чтобы «назад» не листал каждый клик.
**Почему.** Сервер не знает про вкладки; класть их в сейв — лишний HTTP. `localStorage` как у
языка держал бы «5А» через месяц. URL без фильтров остаётся коротким и копируемым.
### Что видит игрок
F5 внутри школы — та же школа, те же вкладки и фильтры. Назад — меню. Снова открыть ту же
школу — не сброс на карту. Гость не входит в управление по ссылке. Скорость часов, пауза,
открытый пул соискателей и мастер создания не вспоминаются.
### Что не входит
Поиск по имени в списках, где его нет. Роутер-библиотека. Состояние на сервере. Бамп протокола.
+46
View File
@@ -0,0 +1,46 @@
# Фаза 55. Состояние экрана
## Зависимости
Нет. Оболочка, люди, управление и соискатели уже на экране.
## Зачем
F5 и выход в меню не должны выкидывать игрока на карту с пустыми фильтрами. Школа, вкладки и
уже существующие поиски/фильтры восстанавливаются; сервер по-прежнему единственный источник
игровых данных.
## Задачи
- [x] Query URL: `school`, `mode`, `tab`, `node`, `person`, `inspect`. F5 с `school=` снова
открывает эту школу (`OpenSchool` как с карточки меню). Нет школы / не в списках — меню,
URL чистится. Гость с `mode=manage` остаётся в обзоре
- [x] `sessionStorage` ключ `h-school.view.{id}`: фильтры и пейджер людей, поиск/фильтры
соискателей, вкладка и поиски карточки, вкладка управления и выбранный класс сетки,
последний `mode`/`tab`/выбор — чтобы повторный вход с меню поднял то же место
- [x] `history.pushState` только вход и выход; смена вкладки и фильтров — `replaceState`.
«Назад» из школы — меню. Протокол, HTTP и сейв не трогать; роутер не добавлять
- [x] Подписи через `t(...)` не нужны: новых строк нет. `docs/design/off-queue.md` и эта фаза —
в том же коммите, что и код
## Тесты, без которых фаза не закрыта
- [x] Разбор и сборка query: валидные поля, мусорный `mode`/`school` → обзор / меню
- [x] Chrome в `sessionStorage` пишется и читается по школе; битый JSON → значения по умолчанию
- [x] Школа из списка: своя, чужая (`mine: false`), нет id → `null`
- [x] Панель людей: `show` поднимает сохранённые фильтры в запрос; смена фильтра пишет storage
- [x] Экран школы: URL `tab=people` открывает людей; гость игнорирует `mode=manage`
- [x] Управление: новая панель на той же школе открывает сохранённую вкладку «Правила»
## Критерий готовности
- Открыть школу, вкладка «Люди», фильтр «ученики / 5», карточка. F5 — снова эта школа, те же
фильтры и человек. Назад — меню. Снова открыть ту же школу с меню — те же вкладка и фильтры
- Гость не попадает в «Управление» по URL
- `npm --prefix src/HSchool.Client test` проходит на затронутых тестах
## Стоп
Не класть состояние на сервер. Не бампить протокол. Не добавлять поиск по имени в списки, где
его нет. Не держать открытым диалог соискателей и мастер создания. Не трогать скорость часов и
паузу — они уже на сервере.
+2 -1
View File
@@ -231,7 +231,7 @@
Склейка уже живых систем и мелкий DX, не новый кусок игры. Номера не спорят со срезом 10.
После каждой игровой фазы школа целая. 50–52 стоят на 48; 53 — на 18 и 32, можно параллельно
с 48. 49 и 54 от них не зависят. Баг в уже сделанном — [`../bugs/README.md`](../bugs/README.md).
с 48. 49, 54 и 55 от них не зависят. Баг в уже сделанном — [`../bugs/README.md`](../bugs/README.md).
| Фаза | Статус | Зачем |
| --- | --- | --- |
@@ -242,3 +242,4 @@
| [52. Учебник на уроке](52-textbook-lesson.md) | ✅ | Нет в сумке — половинный рост |
| [53. Погода на дороге](53-weather-commute.md) | ✅ | Снег и дождь добавляют минуты к приходу |
| [54. Что нового](54-whats-new.md) | ✅ | После входа — окно коммитов с прошлого визита |
| [55. Состояние экрана](55-view-state.md) | 🔄 | F5 и переходы не сбрасывают школу, вкладки и фильтры |