feat(tradein): /scrapers/avito — 6-я секция Расписание (in-app scheduler UI) #483

Merged
lekss361 merged 1 commit from feat/tradein-frontend-scheduler into main 2026-05-23 14:55:32 +00:00
Owner

Summary

UI для in-app scheduler (parallel PR feat/tradein-scheduler-backend). Шестая секция на /trade-in/scrapers/avito с status preview, формой настройки окна, и UTC↔МСК конвертацией для удобного ввода.

LOC: 2 files (page.tsx modify + CSS append).

Changes

app/scrapers/avito/page.tsx

  • 2 hooks: useSchedules (GET с polling 30s) + useUpdateSchedule (PUT mutation с query invalidate)
  • TS interfaces: ScheduleConfig, ScheduleConfigUpdate
  • Local state: enabled, mskStart, mskEnd, pages, topN, delay, radius, enrich_houses (init из query через useEffect)
  • 6-я секция "Расписание автозапуска (in-app scheduler)":
    • Status preview: enabled badge, window (МСК + UTC), next_run_at, last_run_at + run_id
    • Edit form: enabled toggle, window from/to (ввод в МСК!), pages/anchor, detail top-N, delay, radius, enrich_houses
    • Submit → PUT /admin/scrape/schedules/avito_city_sweep
    • Success/error feedback
  • Helpers: utcToMsk, mskToUtc, formatMskRange — UI всегда показывает МСК, backend хранит UTC

CSS

  • .scraper-section--schedule — зелёный success border (отличается от city sweep синего)
  • .schedule-status — preview block с label/value grid
  • .run-muted reused from city sweep section

Verify

  • tsc --noEmit clean
  • next build pass — /scrapers/avito 5.96 kB, all 9 routes

Test plan

  • tsc strict
  • next build
  • Deploy parallel backend PR + this PR → visit /scrapers/avito → scroll до секции 6 → verify status показывает defaults
  • Edit window МСК (например 04:00-07:00) → save → verify backend сохранил 01-04 UTC (МСК-3)
  • Toggle enabled off → verify status badge → "отключено"
  • Wait до next_run_at → verify auto-triggered run появляется в секции 5 (city sweep runs table)

Behavior

State UI
Loading "Загрузка…"
Error red error panel
Disabled Status badge "отключено" (оранжевый), форма редактируема
Enabled Status badge "включено" (синий), next_run_at displayed

UTC↔МСК

  • Backend хранит часы в UTC (universal, без DST)
  • UI всегда показывает в МСК (UTC+3, no DST в РФ since 2014)
  • Преобразование: mskHour = (utcHour + 3) % 24, utcHour = (mskHour - 3 + 24) % 24

Refs

  • Backend contract: parallel PR feat/tradein-scheduler-backend (migration 052 + 2 endpoints + scheduler service)
## Summary UI для in-app scheduler (parallel PR `feat/tradein-scheduler-backend`). Шестая секция на `/trade-in/scrapers/avito` с status preview, формой настройки окна, и UTC↔МСК конвертацией для удобного ввода. LOC: 2 files (page.tsx modify + CSS append). ## Changes ### `app/scrapers/avito/page.tsx` - 2 hooks: `useSchedules` (GET с polling 30s) + `useUpdateSchedule` (PUT mutation с query invalidate) - TS interfaces: `ScheduleConfig`, `ScheduleConfigUpdate` - Local state: enabled, mskStart, mskEnd, pages, topN, delay, radius, enrich_houses (init из query через useEffect) - **6-я секция** "Расписание автозапуска (in-app scheduler)": - **Status preview**: enabled badge, window (МСК + UTC), next_run_at, last_run_at + run_id - **Edit form**: enabled toggle, window from/to (ввод **в МСК!**), pages/anchor, detail top-N, delay, radius, enrich_houses - Submit → PUT `/admin/scrape/schedules/avito_city_sweep` - Success/error feedback - Helpers: `utcToMsk`, `mskToUtc`, `formatMskRange` — UI всегда показывает МСК, backend хранит UTC ### CSS - `.scraper-section--schedule` — зелёный success border (отличается от city sweep синего) - `.schedule-status` — preview block с label/value grid - `.run-muted` reused from city sweep section ## Verify - ✅ `tsc --noEmit` clean - ✅ `next build` pass — `/scrapers/avito` 5.96 kB, all 9 routes ## Test plan - [x] tsc strict - [x] next build - [ ] Deploy parallel backend PR + this PR → visit `/scrapers/avito` → scroll до секции 6 → verify status показывает defaults - [ ] Edit window МСК (например 04:00-07:00) → save → verify backend сохранил 01-04 UTC (МСК-3) - [ ] Toggle enabled off → verify status badge → "отключено" - [ ] Wait до next_run_at → verify auto-triggered run появляется в секции 5 (city sweep runs table) ## Behavior | State | UI | |---|---| | Loading | "Загрузка…" | | Error | red error panel | | Disabled | Status badge "отключено" (оранжевый), форма редактируема | | Enabled | Status badge "включено" (синий), next_run_at displayed | ## UTC↔МСК - Backend хранит часы в UTC (universal, без DST) - UI всегда показывает в МСК (UTC+3, no DST в РФ since 2014) - Преобразование: `mskHour = (utcHour + 3) % 24`, `utcHour = (mskHour - 3 + 24) % 24` ## Refs - Backend contract: parallel PR `feat/tradein-scheduler-backend` (migration 052 + 2 endpoints + scheduler service)
lekss361 added 1 commit 2026-05-23 14:51:50 +00:00
UI для backend scheduler (parallel PR feat/tradein-scheduler-backend) — заменяет
manual SSH crontab setup на UI-managed config в БД.

- 2 hooks: useSchedules (poll 30s) + useUpdateSchedule (PUT с invalidate)
- Local TS interfaces: ScheduleConfig, ScheduleConfigUpdate
- 6-я секция 'Расписание автозапуска (in-app scheduler)':
  * Status preview: enabled badge, window (МСК + UTC), next_run_at, last_run_at + run_id
  * Edit form: enabled checkbox, window start/end (вход в МСК!), pages/anchor, detail top-N,
    delay, radius, enrich_houses checkbox
  * Submit → PUT /admin/scrape/schedules/avito_city_sweep
- UTC ↔ МСК конвертация: utcToMsk / mskToUtc / formatMskRange helpers
- CSS: .scraper-section--schedule (зелёный success border), .schedule-status grid

Backend хранит часы UTC, UI ввод/отображение — МСК (UTC+3).
Default из migration 052: 02:00-05:00 UTC = 05:00-08:00 МСК.
lekss361 merged commit fd3cb4e6ed into main 2026-05-23 14:55:32 +00:00
Author
Owner

Merged via deep-code-reviewer — verdict APPROVE (MINOR follow-ups noted).

UTC↔MSK math verified across edge cases (cross-midnight, MSK 00:00→UTC 21:00, MSK 02:00→UTC 23:00, round-trip stable). Backend contract on main since #482 merged seconds earlier — no 404 risk.

MINOR follow-ups (not blocking, OK to address in separate PR):

  1. useEffect([schedulesQ.data]) overwrites user input every 30s when poll refetches. Recommend gating with useRef "form is dirty" flag or pausing refetchInterval while form has unsaved changes.
  2. parseInt(e.target.value, 10) returns NaN when user clears the input → controlled value={NaN} triggers React warning. Guard with Number.isNaN(v) ? 0 : v or fallback to previous state.
  3. Optional: optimistic UI on save (set local state immediately, rollback on error) for snappier feel.

Status preview, badge colour mapping, CSS tokens (--success, --success-soft, run-badge--cancelled) all reuse existing design system — no new tokens introduced.

Merged via deep-code-reviewer — verdict APPROVE (MINOR follow-ups noted). UTC↔MSK math verified across edge cases (cross-midnight, MSK 00:00→UTC 21:00, MSK 02:00→UTC 23:00, round-trip stable). Backend contract on main since #482 merged seconds earlier — no 404 risk. MINOR follow-ups (not blocking, OK to address in separate PR): 1. `useEffect([schedulesQ.data])` overwrites user input every 30s when poll refetches. Recommend gating with `useRef` "form is dirty" flag or pausing `refetchInterval` while form has unsaved changes. 2. `parseInt(e.target.value, 10)` returns NaN when user clears the input → controlled `value={NaN}` triggers React warning. Guard with `Number.isNaN(v) ? 0 : v` or fallback to previous state. 3. Optional: optimistic UI on save (set local state immediately, rollback on error) for snappier feel. Status preview, badge colour mapping, CSS tokens (`--success`, `--success-soft`, `run-badge--cancelled`) all reuse existing design system — no new tokens introduced.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#483
No description provided.