From 5dbcc45b343d10aba83ef4232f628999388b422c Mon Sep 17 00:00:00 2001 From: bot-backend Date: Mon, 1 Jun 2026 01:17:00 +0300 Subject: [PATCH] =?UTF-8?q?feat(trade-in):=20OfferCard=20=E2=80=94=20?= =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D1=82=D1=8C=20=D1=80=D0=B5=D0=B4=D0=B0?= =?UTF-8?q?=D0=BA=D1=82=D0=B8=D1=80=D1=83=D0=B5=D0=BC=D1=83=D1=8E=20=D1=86?= =?UTF-8?q?=D0=B5=D0=BD=D1=83=20+=20=D0=BF=D0=BE=D0=BB=D0=B7=D1=83=D0=BD?= =?UTF-8?q?=D0=BE=D0=BA=20=D1=82=D0=BE=D1=80=D0=B3=D0=B0,=20=D1=80=D0=B0?= =?UTF-8?q?=D0=B7=D0=B1=D0=B8=D0=B2=D0=BA=D0=B0=20=D0=BD=D0=B0=20=D0=B4?= =?UTF-8?q?=D0=B5=D1=84=D0=BE=D0=BB=D1=82=D0=B0=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/trade-in/OfferCard.tsx | 89 ++----------------- .../src/components/trade-in/trade-in.css | 48 ---------- 2 files changed, 7 insertions(+), 130 deletions(-) diff --git a/tradein-mvp/frontend/src/components/trade-in/OfferCard.tsx b/tradein-mvp/frontend/src/components/trade-in/OfferCard.tsx index 1110131c..5032cbee 100644 --- a/tradein-mvp/frontend/src/components/trade-in/OfferCard.tsx +++ b/tradein-mvp/frontend/src/components/trade-in/OfferCard.tsx @@ -2,9 +2,8 @@ /** * OfferCard — Секция 4 «Оффер» (commercial — Brusnika p.4 «формирование - * выкупной стоимости»). Интерактивный КАЛЬКУЛЯТОР ВЫГОДЫ: web-преимущество - * над PDF — менеджер двигает цену в объявлении / % торга и сразу видит, как - * меняются издержки самостоятельной продажи и «ваша выгода» через trade-in. + * выкупной стоимости»). Показывает разбивку издержек самостоятельной продажи + * на фиксированных дефолтных ставках (median_price_rub + DEFAULT_BARGAIN_PCT). * * NB: сама ВЫКУПНАЯ цена (сколько платит девелопер) НЕ рассчитывается — это * коммерческое решение «Практики» (нет параметров haircut/маржи/срока). @@ -14,11 +13,10 @@ * TODO(commercial): подставить реальные условия «Практики» в DEFAULT_OFFER_RATES * (offer-rates.ts) — единственное место для смены ставок. */ -import { useMemo, useState } from "react"; +import { useMemo } from "react"; import type { AggregatedEstimate } from "@/types/trade-in"; import { API_BASE_URL } from "@/lib/api"; import { - BARGAIN_SLIDER, DEFAULT_OFFER_RATES, computeBreakdown, } from "./offer-rates"; @@ -45,36 +43,12 @@ export function OfferCard({ estimate, brandSlug }: Props) { // PDF endpoint (api/v1/trade_in.py) уже honor'ит ?brand= для white-label. const pdfQuery = brandSlug ? `?brand=${encodeURIComponent(brandSlug)}` : ""; - // ── Интерактивные входы ── - // asking median_price_rub — стартовая цена в объявлении (редактируемая). - const [askingPrice, setAskingPrice] = useState( - Math.round(estimate.median_price_rub), - ); - const [bargainPct, setBargainPct] = useState(DEFAULT_BARGAIN_PCT); - - // ── LIVE-пересчёт: входы → разбивка издержек (pure-функция в offer-rates.ts) ── + // ── Разбивка на фиксированных дефолтах ── + const fixedPrice = Math.round(estimate.median_price_rub); const breakdown = useMemo( - () => computeBreakdown(askingPrice, bargainPct, DEFAULT_OFFER_RATES), - [askingPrice, bargainPct], + () => computeBreakdown(fixedPrice, DEFAULT_BARGAIN_PCT, DEFAULT_OFFER_RATES), + [fixedPrice], ); - - const askingMln = askingPrice / 1_000_000; - - function onPriceInput(e: React.ChangeEvent) { - // Только цифры: пользователь может стереть/набрать новую цену. - const digits = e.target.value.replace(/\D/g, ""); - setAskingPrice(digits === "" ? 0 : Number(digits)); - } - - function resetPrice() { - setAskingPrice(Math.round(estimate.median_price_rub)); - setBargainPct(DEFAULT_BARGAIN_PCT); - } - - const isCustomPrice = - Math.round(estimate.median_price_rub) !== askingPrice || - bargainPct !== DEFAULT_BARGAIN_PCT; - return (
@@ -93,55 +67,6 @@ export function OfferCard({ estimate, brandSlug }: Props) {
- {/* ── Интерактивные контролы калькулятора ── */} -
-
- -
- - -
-
≈ {askingMln.toFixed(2)} млн ₽
-
- -
- - setBargainPct(Number(e.target.value))} - aria-label="Доля торга с покупателем" - /> -
- {pct(bargainPct)} ≈ {fmtRub(askingPrice * bargainPct)} ₽ -
-
- - {isCustomPrice && ( - - )} -
- {/* ── Прайм-блок: ваша выгода ── */}
Ваша выгода через Trade-In
diff --git a/tradein-mvp/frontend/src/components/trade-in/trade-in.css b/tradein-mvp/frontend/src/components/trade-in/trade-in.css index caed0313..4f6c1a4f 100644 --- a/tradein-mvp/frontend/src/components/trade-in/trade-in.css +++ b/tradein-mvp/frontend/src/components/trade-in/trade-in.css @@ -1184,52 +1184,6 @@ OFFER Section (4) ============================================================ */ - /* ── Interactive benefit-calculator controls ── */ - .offer-calc-controls { - display: grid; - grid-template-columns: 1fr 1fr auto; - gap: 20px; - align-items: end; - padding: 18px 22px; - background: var(--surface-2); - border-bottom: 1px solid var(--border); - } - .occ-field { display: flex; flex-direction: column; gap: 8px; min-width: 0; } - .occ-label { - font-size: 12px; - font-weight: 600; - color: var(--fg); - display: flex; - flex-direction: column; - gap: 2px; - } - .occ-label .occ-hint { - font-size: 11px; - font-weight: 400; - color: var(--muted-2); - } - .occ-price-input { width: 100%; } - .occ-sub { font-size: 11px; color: var(--muted); } - .occ-sub b { color: var(--fg); font-weight: 600; } - .occ-slider { - width: 100%; - margin: 8px 0 2px; - accent-color: var(--accent); - cursor: pointer; - } - .occ-reset { - align-self: end; - font-size: 12px; - padding: 9px 14px; - border: 1px solid var(--border-strong); - border-radius: var(--radius-sm); - background: var(--surface); - color: var(--muted); - cursor: pointer; - white-space: nowrap; - } - .occ-reset:hover { color: var(--fg); border-color: var(--accent); } - /* ── Prominent «Ваша выгода» block ── */ .offer-benefit { margin: 18px 22px 4px; @@ -1428,8 +1382,6 @@ .offer-cta-buttons .btn { flex: 1; } .card-head { flex-direction: column; align-items: flex-start; } .card-head .card-meta { text-align: left; } - .offer-calc-controls { grid-template-columns: 1fr; gap: 16px; } - .occ-reset { align-self: stretch; text-align: center; } .offer-benefit .ob-value { font-size: 24px; } } -- 2.45.3