# Active Context — Strava Frontend ## Task State - task_id: TASK-ROUTE-FIX - status: success - parent_task: — - summary: **FIX: Route.vue — багфикс GPX-генератора (for...in, дубликаты, фейковый ele) + фильтр близлежащих точек 5м. Snap to road убран (GraphHopper 401, риск блокировки OSM в РФ).** - next task: — ## ✅ CODER SUCCESS REPORT — TASK-ROUTE-FIX (final) - Изменён файл: `src/pages/routes/Route.vue` - `toGPX()`: `var date` → `const date`, `for...in` → index-based loop, `${i}` → `0` - `handleMapClick`: синхронная (не async), фильтр < 5м до последней точки (игнор клика), push без snap - `SNAP_THRESHOLD_M` → `MIN_DISTANCE_M` - Убран import `snapToRoad` (файл `src/services/roadSnap.ts` остался в репо, но не используется) - Поведение: клик < 5м от последней точки → игнорируется; клик в другом месте → точка добавляется как есть; GPX генерируется корректно (index loop, ele=0) - `yarn lint`: exit 0 - `yarn build`: exit 0 (vue-tsc --noEmit 0 ошибок, vite build ✓ 6.58s) ## TASK-LINK1 — TODO (delegate to Coder) - [x] `src/pages/workouts/components/WorkoutItem.vue`, секция «Ссылки на описание» (~строка 183): добавить `v-if="dzenLink || isPrivate"` на внешний `div.workout-item-params` секции. Внутренняя логика без изменений: `v-if="dzenLink"` → `Дзен` + `VaIcon edit v-if="isPrivate"`; `v-else` → «Добавить» (теперь достижим только при isPrivate, т.к. секция скрыта иначе). - [x] Файлы трогать ДРУГИЕ НЕЛЬЗЯ: только `src/pages/workouts/components/WorkoutItem.vue`. - [x] Acceptance: `yarn lint` exit 0, `yarn build` exit 0. Поведение: публичная страница без ссылки → секции нет вообще; публичная со ссылкой → видна ссылка «Дзен» без иконки edit; приватная без ссылки → «Добавить» (открывает модалку, PATCH работает); приватная со ссылкой → «Дзен» + иконка edit. ## ✅ CODER SUCCESS REPORT — TASK-LINK1 - Изменен файл (единственный): `src/pages/workouts/components/WorkoutItem.vue` — одна строка: на внешний `div.workout-item-params` секции «Ссылки на описание» (стр. 183) добавлен `v-if="dzenLink || isPrivate"`. Внутренняя логика секции не тронута. - Поведение после фикса: публичная страница без ссылки → секция полностью скрыта; публичная со ссылкой → только «Дзен» (иконка edit уже была `v-if="isPrivate"`); приватная без ссылки → «Добавить» (модалка `v-if="isPrivate"` доступна, PATCH работает); приватная со ссылкой → «Дзен» + иконка edit. - `yarn lint`: exit 0 (prettier: файлы без изменений, eslint 0 ошибок). - `yarn build`: exit 0 (`vue-tsc --noEmit` 0 ошибок, `vite build` ✓ built in 5.41s; warning о chunk >500kB — предсуществующий). ## TASK-F1 — TODO - [x] `src/pages/workouts/Definitions.vue`: тип `WorkoutPhoto` + `photos?: Array` в `WorkoutItem` (fetch менять не нужно — бэкенд уже присылает `workout.photos`). - [x] `src/pages/workouts/components/WorkoutItem.vue`: `photos` ref (из `workoutItem?.photos`), `photosWithCoords` computed, `` для фото с координатами (порядок `[lon, lat]` как у `clickCoordinates`, `color: 'blue'`, onClick → `window.open(photo.url, "_blank")`). - [x] `src/pages/workouts/components/WorkoutItem.vue`: секция `#workout-photos` под `#workout-container` — grid ``, «Добавить фото» (`v-if="isPrivate"`, скрытый `input[type=file] accept="image/*" multiple`, `axiosAuth.post` multipart поле `file`, `Promise.allSettled`, ответ в `photos`, VaButton `:loading`), «Удалить» (`v-if="isPrivate"`, `axiosAuth.delete` → убрать из массива), ошибки/успех — `useToast`. - [x] `src/pages/workouts/components/WorkoutItem.vue`: `isPrivate` добавлен в деструктуризацию `defineProps`; стили `.workout-photos-*` (grid auto-fill 160px, img 120px object-fit cover, кнопка удаления absolute). - [x] `WorkoutListItem.vue` НЕ тронут (по ТЗ). - [x] Верификация: `npm run build` exit 0 (vue-tsc --noEmit + vite, ~8–12s), `npm run lint` exit 0 (prettier+eslint --fix). ## ✅ CODER SUCCESS REPORT — TASK-F1 - Изменены файлы: `src/pages/workouts/Definitions.vue` (+8 строк: тип `WorkoutPhoto`, поле `photos?`), `src/pages/workouts/components/WorkoutItem.vue` (+163 строки: маркеры фото, галерея, upload/delete, стили). - `photos` — локальный `ref>` (иниц. из пропса), все мутации только по нему; `axiosAuth` — существующий `inject("axiosAuth")`. - Маркеры: `` с `coordinates: [lon, lat] as LngLat` (тот же порядок, что у `clickCoordinates`), `color: 'blue'` для отличия от серых маркеров кликов; onClick → `window.open(photo.url, "_blank")`. - Загрузка: `Promise.allSettled` по каждому файлу (multipart, поле `file`); успех → push в `photos` + toast success; частичная неудача → toast error «Не удалось загрузить часть фото.»; `:loading` на кнопке. - Удаление: `axiosAuth.delete` → filter из `photos`; ошибка → toast «Не удалось удалить фото.» - Кнопки «Добавить фото»/«Удалить» и `v-if` секции только при `isPrivate` (владелец); на публичной странице (`WorkoutPublicItem.vue`, `isPrivate=false`) фото видны только-чтение без управления. - `npm run build`: exit 0, `✓ built in 11.71s` (vue-tsc 0 ошибок; warning о chunk >500kB — предсуществующий). - `npm run lint`: exit 0 (prettier: `WorkoutItem.vue` переформатирован, eslint 0 ошибок). - Ручные проверки (сценарии для QA): фото с GPS → в галерее + синий маркер на карте; фото без GPS → только в галерее; добавление нескольких файлов сразу → все добавлены, `:loading` на кнопке во время; удаление → исчезло из галерее и с карты; публичная страница → фото видны, кнопок нет; клик по фото/маркеру → opens в новой вкладке. ## W3 acceptance criteria - `eslint` 9.x + `typescript-eslint` 8.x in yarn.lock; legacy `@typescript-eslint/eslint-plugin@6` + `@typescript-eslint/parser@6` removed (superseded by the `typescript-eslint` 8 meta-package); NO other package moved to a new major - `yarn lint` 0 errors + `yarn build` green - `eslint.config.mjs` adjustments minimal and documented (flat config already in use — migration should be trivial) - Memory Bank: status `success` + Success Report ## W3 notes for the Coder - Current state: `eslint@8.57.1` (flat config works on 8.57), `typescript-eslint@7.18.0`, legacy `@typescript-eslint/eslint-plugin@^6.11.0` + `@typescript-eslint/parser@^6.11.0` still in package.json (redundant with the meta-package but currently unused by eslint.config.mjs). - Target: `yarn add -D eslint@^9 typescript-eslint@^8`, then `yarn remove @typescript-eslint/eslint-plugin @typescript-eslint/parser` ONLY if eslint.config.mjs does not import them directly (check first). - eslint 9 removes some legacy config options — if `eslint.config.mjs` breaks, apply the minimal migration (documented). - `eslint-plugin-prettier`/`@vue/eslint-config-prettier` are NOT part of W3 — leave versions as-is. ## W2d acceptance criteria - `package.json`: no `storybook`/`@storybook/*`/`eslint-plugin-storybook` deps, no `storybook`/`build-storybook` scripts - yarn.lock: no `@storybook/vue3-vite` entry, no nested `@vitejs/plugin-vue@4` install - `yarn lint` 0 errors + `yarn build` green - `eslint.config.mjs` — no references to storybook plugin (verify; add minimal fix if present) - Memory Bank: status `success` + Success Report (removed list, install-size delta if measurable) ## W2b acceptance criteria - `vue-tsc` resolved to 2.x and `typescript` to 5.8.x in yarn.lock; NO other package moved to a new major - `yarn lint` — 0 errors; `yarn build` — green (vue-tsc 2 type-check 0 errors, bundle built) - Minimal type-only fixes in `src/` allowed only if required by the stricter checker; each documented with justification - Memory Bank: status `success` + Success Report (old/new versions, full list of src/ fixes with justification) ## Wave plan (each wave = one atomic task, verified independently) - **W0a (TASK-DEPS-UPDATE-W0a, success)**: Fix everything that hard-blocks `yarn build`: - `LineWithLineChart.ts(41)` TS2532 "Object is possibly 'undefined'" (labels can be undefined) — fix via non-null assertion or guarded length. - SFC parsing errors: `src/pages/workouts/components/WorkoutItem.vue:260` (`Unexpected token {`) and `WorkoutListItem.vue:60` (`'interface' is reserved`). Root-cause candidates: TS syntax in a plain `