gendesign/tradein-mvp/frontend/src/app/ui-preview/estimate/page.tsx
lekss361 a357aedb45 fix(tradein): preview обёрнут в .page/.result-col (desktop-раскладка, не «мобильная») (#801)
Голый <main maxWidth:920> без layout-классов реальной страницы → карточки
рендерились узко/одной колонкой («мобильный» вид). Обёрнуто в .page > .result-col
(как page.tsx) — flex-column gap, --container ширина.

Refs #801.
2026-05-30 22:30:59 +03:00

86 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
/**
* #801: dev/CI-only preview-маршрут «денежного экрана» на статичной фикстуре.
*
* Зачем: a11y (axe) и lighthouse требуют отрендеренную контентную страницу.
* Live trade-in за auth-gate, а локальный фронт без бэкенда = белый экран
* (RouteGuard висит на pending /me). Эта страница рендерит реальные компоненты
* результата (HeroSummary + карточки/чарты) полностью оффлайн — без сети.
*
* Включается ТОЛЬКО при NEXT_PUBLIC_ENABLE_PREVIEW=1 (иначе notFound) — в проде
* по умолчанию недоступна. RouteGuard пропускает /ui-preview/* под тем же флагом.
* (Папка НЕ может начинаться с "_" — Next трактует такие как private/non-routable.)
*
* Локально: echo NEXT_PUBLIC_ENABLE_PREVIEW=1 > .env.local && npm run dev
* → http://localhost:3000/ui-preview/estimate
* CI: собрать с флагом, поднять next start, навести axe/lighthouse.
*/
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { notFound } from "next/navigation";
import { useState } from "react";
import "@/components/trade-in/trade-in.css";
import { CianValuationCard } from "@/components/trade-in/CianValuationCard";
import { DealsCard } from "@/components/trade-in/DealsCard";
import { DistributionCard } from "@/components/trade-in/DistributionCard";
import { ExposureCard } from "@/components/trade-in/ExposureCard";
import { HeroSummary } from "@/components/trade-in/HeroSummary";
import { PriceTrendCard } from "@/components/trade-in/PriceTrendCard";
import { StreetDealsCard } from "@/components/trade-in/StreetDealsCard";
import { ME_QUERY_KEY, type UserScope } from "@/lib/useMe";
import { FIXTURE_ESTIMATE, FIXTURE_INPUT } from "./fixture";
const ENABLED = process.env.NEXT_PUBLIC_ENABLE_PREVIEW === "1";
// Фейковый authorized-юзер: засеивается в QueryClient → useMe/useBrand резолвятся
// оффлайн (никакого /me, /quota, /brand), generic-бренд (brand=null).
const PREVIEW_USER: UserScope = {
username: "preview",
role: "admin",
allowed_paths: ["/**"],
deny_paths: [],
brand: null,
};
function PreviewContent() {
const [client] = useState(() => {
const qc = new QueryClient({
defaultOptions: {
queries: { retry: false, staleTime: Infinity, refetchOnWindowFocus: false },
},
});
qc.setQueryData(ME_QUERY_KEY, PREVIEW_USER);
return qc;
});
return (
<QueryClientProvider client={client}>
{/* Те же layout-классы, что у реальной страницы (page.tsx): .page → .result-col
(flex-column gap, --container ширина). Без них карточки рендерились узко/«мобильно». */}
<main className="page">
<section className="result-col">
<HeroSummary
estimate={FIXTURE_ESTIMATE}
input={FIXTURE_INPUT}
onResubmit={() => {}}
isResubmitting={false}
/>
<CianValuationCard data={FIXTURE_ESTIMATE.cian_valuation} />
<DistributionCard estimate={FIXTURE_ESTIMATE} />
<DealsCard estimate={FIXTURE_ESTIMATE} />
<StreetDealsCard estimate={FIXTURE_ESTIMATE} />
<ExposureCard estimate={FIXTURE_ESTIMATE} />
<PriceTrendCard estimate={FIXTURE_ESTIMATE} />
</section>
</main>
</QueryClientProvider>
);
}
export default function PreviewEstimatePage() {
if (!ENABLED) notFound();
return <PreviewContent />;
}