Switch StreetDealsCard от /street-deals к /sales-vs-listings. В каждой
строке ДКП-сделки теперь показан linked исторический ASK с источником
(Avito/Cian/Yandex/N1), ценой listing, сроком до сделки и discount_pct
в цвете (зелёный = торг, красный = overshoot). В шапке секции —
linkage_rate % сделок имеют match + медианный торг по pairs с listing.
Changes:
- types/trade-in.ts: SalesListingPair + SalesVsListingsResponse
- lib/trade-in-api.ts: useSalesVsListings hook (TanStack, staleTime 10m)
- components/StreetDealsCard.tsx: rewrite — switch endpoint, add listing
column, compute aggregates client-side (count/median/range), extract
<ListingBadge> subcomponent
- components/trade-in.css: token-based styles (.linkage-hint, .discount-pos/neg,
.listing-cell, .listing-link, .listing-source-badge) + mobile breakpoint
Decisions:
- Endpoint replacement (не parallel fetch) — /sales-vs-listings суперсет
- Period default 24 мес (от endpoint default) — больше data для pairing
- Discount sign: var(--success) при <0 (торг), var(--danger) при >0
- safeUrl() guard для listing URLs (XSS) + target="_blank" rel="noopener"
- Mobile <720px — listing column stacks vertically
- linkage_rate=0 → listing column скрыт целиком (`hasAnyListing` flag)
Tests: tsc --noEmit clean. No new deps.
Out of scope: useStreetDeals hook deprecated, можно убрать в cleanup PR.
Closes#564 Phase 2.