101 lines
3.3 KiB
TypeScript
101 lines
3.3 KiB
TypeScript
"use client";
|
||
|
||
import { useEstimatePlacementHistory } from "@/lib/trade-in-api";
|
||
import type { PlacementHistoryItem } from "@/types/trade-in";
|
||
|
||
type Props = { estimateId: string };
|
||
|
||
const fmtPrice = (n: number | null): string =>
|
||
n == null ? "—" : `${(n / 1_000_000).toFixed(2)} М ₽`;
|
||
|
||
const fmtDate = (d: string | null): string => {
|
||
if (!d) return "—";
|
||
try {
|
||
return new Date(d).toLocaleDateString("ru-RU");
|
||
} catch {
|
||
return d;
|
||
}
|
||
};
|
||
|
||
function lotLabel(it: PlacementHistoryItem): string {
|
||
if (it.title) return it.title;
|
||
const rooms = it.rooms != null ? `${it.rooms}к` : "?к";
|
||
const area = it.area_m2 != null ? `${it.area_m2} м²` : "? м²";
|
||
const floor =
|
||
it.floor != null && it.total_floors != null
|
||
? `, эт. ${it.floor}/${it.total_floors}`
|
||
: "";
|
||
return `${rooms}, ${area}${floor}`;
|
||
}
|
||
|
||
export function PlacementHistoryCard({ estimateId }: Props) {
|
||
const { data: items, isPending, isError } = useEstimatePlacementHistory(estimateId);
|
||
|
||
if (isPending || isError) return null;
|
||
if (!items || items.length === 0) return null;
|
||
|
||
const visible = items.slice(0, 20);
|
||
|
||
return (
|
||
<article className="card" style={{ marginTop: 16 }}>
|
||
<header className="card-head">
|
||
<h3 style={{ margin: 0, fontSize: 15 }}>История продаж в этом доме</h3>
|
||
<small style={{ color: "var(--muted, #6b7280)" }}>
|
||
{items.length} лот{items.length === 1 ? "" : "ов"}
|
||
</small>
|
||
</header>
|
||
<div style={{ padding: "8px 16px 16px" }}>
|
||
<table
|
||
style={{ width: "100%", fontSize: 13, borderCollapse: "collapse" }}
|
||
>
|
||
<thead>
|
||
<tr
|
||
style={{
|
||
borderBottom: "1px solid var(--border, #e5e7eb)",
|
||
textAlign: "left",
|
||
}}
|
||
>
|
||
<th style={{ padding: "6px 8px" }}>Лот</th>
|
||
<th style={{ padding: "6px 8px" }}>Цена нач. → посл.</th>
|
||
<th style={{ padding: "6px 8px" }}>Дата</th>
|
||
<th style={{ padding: "6px 8px" }}>Экспозиция</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{visible.map((it) => (
|
||
<tr
|
||
key={it.id}
|
||
style={{
|
||
borderBottom: "1px solid var(--border-soft, #f3f4f6)",
|
||
}}
|
||
>
|
||
<td style={{ padding: "6px 8px" }}>{lotLabel(it)}</td>
|
||
<td style={{ padding: "6px 8px", whiteSpace: "nowrap" }}>
|
||
{fmtPrice(it.start_price)} →{" "}
|
||
<strong>{fmtPrice(it.last_price)}</strong>
|
||
</td>
|
||
<td style={{ padding: "6px 8px", whiteSpace: "nowrap" }}>
|
||
{fmtDate(it.last_price_date ?? it.start_price_date)}
|
||
</td>
|
||
<td style={{ padding: "6px 8px" }}>
|
||
{it.exposure_days ?? "—"} дн.
|
||
</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
{items.length > 20 && (
|
||
<small
|
||
style={{
|
||
color: "var(--muted, #6b7280)",
|
||
display: "block",
|
||
marginTop: 8,
|
||
}}
|
||
>
|
||
показано 20 из {items.length}
|
||
</small>
|
||
)}
|
||
</div>
|
||
</article>
|
||
);
|
||
}
|