Skip to content

feat(tasks): экран «Сегодня» — просроченные и сегодняшние задачи - #38

Merged
MegaBadCoder merged 11 commits into
mainfrom
feat/today-view
Aug 26, 2026
Merged

feat(tasks): экран «Сегодня» — просроченные и сегодняшние задачи#38
MegaBadCoder merged 11 commits into
mainfrom
feat/today-view

Conversation

@MegaBadCoder

Copy link
Copy Markdown
Owner

Экран «Сегодня» по образцу Todoist: отдельный пункт в сайдбаре задач, просроченные и сегодняшние в двух сворачиваемых группах, счётчик у пункта, массовый перенос и быстрое добавление с предзаполненной датой.

Задача целиком (Design → Plan → Verify → Conclusion) — в docs/tasks/today-view.md.

Что появилось

  • Роут /tasks/today + views/TodayView.vue — группы «Просрочено» и «26 авг. · Сегодня · Среда», задачи из всех проектов с ярлыком проекта.
  • features/tasks/lib/today.ts — чистая логика разбиения (splitTodayBuckets, countTodayTasks, shiftToSameTimeToday), написана по TDD.
  • Счётчик у пункта сайдбара — сумма обеих групп.
  • «Перенести» в шапке «Просрочено» — массовый перенос всей группы на сегодня.
  • Быстрое добавление внизу экрана стартует с датой «сегодня».

Два решения, которые стоит знать при ревью

Task.isOverdue — это «заморожена», а не «просрочена по дате». Флаг ставит ночная джоба только повторяющимся задачам с onMissed: 'freeze'; такие инстансы иммутабельны — бэкенд кидает BadRequestException на любой PATCH. Поэтому «Просрочено» здесь считается как !completed && dueDate < начало сегодня, а isOverdue работает фильтром-исключением: замороженные не показываются и не входят в счётчик. Экран остаётся списком действий — всё видимое можно перенести или закрыть. Семантика задокументирована в CLAUDE.md, в кодбазе её описания не было.

NavLink.count — тунк (now: Date) => number, а не число. Массивы ссылок (router/*-nav.ts) собираются на уровне модуля, до подъёма Pinia, и useTaskStore() там падает. Стор трогается только внутри тунка, который SidebarNav разворачивает уже в setup-контексте; now идёт аргументом, иначе счётчик застревает на вчерашнем дне после полуночи. Регрессия — tests/router/tasks-nav.spec.ts импортирует модуль без активной Pinia.

Совместимость

Чистое дополнение фронта. Оба изменения общих контрактов — NavLink.count и TaskForm.defaultDueDate — опциональные поля со значением undefined по умолчанию; TasksView.vue и TaskListOptionsMenu.vue не тронуты, новых эндпоинтов нет, «Перенести» бьёт в существующий PATCH /tasks/:id с rescheduleScope: 'this'.

Проверка

  • 470 тестов в 72 файлах, vue-tsc --noEmit чистый.
  • Смоук в браузере на изолированной копии БД: счётчик 5, «Просрочено 3», три замороженные скрыты, консоль чистая. «Перенести» → три PATCH с 200, задачи уехали на сегодня с сохранённым временем суток, группа схлопнулась.

Известные особенности

  • SidebarNav монтируется дважды (десктопный <aside> + мобильный Teleport), поэтому useNow() держит два минутных интервала — ровно как уже существующий CurrentTaskWidget.
  • Счётчик читает taskStore.tasks: при холодном входе прямо на /tasks/today бейдж пуст до конца fetchTasks().

Вне объёма

«Предстоящее», пользовательские фильтры и обобщённый движок фильтров — к нему стоит вернуться на втором фильтре, не на первом.

@MegaBadCoder
MegaBadCoder merged commit d80f9c2 into main Aug 26, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant