From 271b5daeeaf914d1219a03e8ae54982db324eb1a Mon Sep 17 00:00:00 2001 From: lekss361 Date: Sat, 23 May 2026 23:01:50 +0300 Subject: [PATCH] =?UTF-8?q?fix(tradein-ui):=20#488=20BLOCK=20=E2=80=94=20s?= =?UTF-8?q?craper-settings=20response=20wrapper=20+=20PUT=20source=20field?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit deep-code-reviewer caught 2 critical bugs in both yandex/page.tsx (#488) and cian/page.tsx (#486 already merged): 1. useScraperSettings types response as ScraperSetting[] but backend returns {settings: [...]} -> .find is not a function -> settings panel never renders, slider input never auto-populates from DB. Fix: unwrap .settings in queryFn. 2. PUT body missing required `source` field -- backend Pydantic ScraperSettingPayload validates source==path source. Result: 422 on every save. Fix: include {source, ...payload} in PUT body. Plus M (non-blocking): useEffect race -- refetch every 30s clobbered user input mid-edit. Guarded with initializedRef first-load-only flag. Refs PR #488 review (deep-code-reviewer, 2026-05-23). --- .../frontend/src/app/scrapers/yandex/page.tsx | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/tradein-mvp/frontend/src/app/scrapers/yandex/page.tsx b/tradein-mvp/frontend/src/app/scrapers/yandex/page.tsx index cfb6dd29..ef9059c9 100644 --- a/tradein-mvp/frontend/src/app/scrapers/yandex/page.tsx +++ b/tradein-mvp/frontend/src/app/scrapers/yandex/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import "@/components/trade-in/trade-in.css"; @@ -17,6 +17,7 @@ interface ScraperSetting { } interface ScraperSettingUpdate { + source: string; request_delay_sec: number; } @@ -79,7 +80,10 @@ interface YandexValuationTriggerResp { function useScraperSettings() { return useQuery({ queryKey: ["scraper-settings"], - queryFn: () => apiFetch("/api/v1/admin/scraper-settings"), + queryFn: () => + apiFetch<{ settings: ScraperSetting[] }>("/api/v1/admin/scraper-settings").then( + (r) => r.settings, + ), refetchInterval: 30_000, }); } @@ -89,12 +93,12 @@ function useUpdateScraperSetting() { return useMutation< ScraperSetting, Error, - { source: string; payload: ScraperSettingUpdate } + { source: string; payload: Omit } >({ mutationFn: ({ source, payload }) => apiFetch(`/api/v1/admin/scraper-settings/${source}`, { method: "PUT", - body: JSON.stringify(payload), + body: JSON.stringify({ source, ...payload }), }), onSuccess: () => { qc.invalidateQueries({ queryKey: ["scraper-settings"] }); @@ -212,10 +216,14 @@ export default function YandexScraperPage() { const settingsQ = useScraperSettings(); const updateSettingMut = useUpdateScraperSetting(); const [delayInput, setDelayInput] = useState("5.0"); + const delayInitializedRef = useRef(false); useEffect(() => { const yandex = settingsQ.data?.find((s) => s.source === "yandex"); - if (yandex) setDelayInput(String(yandex.request_delay_sec)); + if (yandex && !delayInitializedRef.current) { + setDelayInput(String(yandex.request_delay_sec)); + delayInitializedRef.current = true; + } }, [settingsQ.data]); // Around