gendesign/frontend/src/components/analytics/ObjectDocumentsList.tsx
lekss361 f8c382f885
All checks were successful
Deploy / changes (push) Successful in 5s
Deploy / build-backend (push) Successful in 1m35s
Deploy / build-worker (push) Successful in 2m37s
Deploy / build-frontend (push) Successful in 3m2s
Deploy / deploy (push) Successful in 56s
feat(22k): object page — full exposure 9 blocks (sales/quartirography/metro/photos/docs/specs/checks) (#310)
2026-05-17 15:56:39 +00:00

106 lines
3.2 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.

import type { ObjectDocumentRow } from "@/types/analytics";
function safeUrl(url: string): string {
try {
const parsed = new URL(url);
if (parsed.protocol === "https:" || parsed.protocol === "http:") {
return url;
}
} catch {
// fall through
}
return "#";
}
function fmtSize(bytes: number | null): string {
if (bytes === null) return "";
if (bytes < 1024) return `${bytes} Б`;
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)} КБ`;
return `${(bytes / (1024 * 1024)).toFixed(1)} МБ`;
}
const DOC_TYPE_ORDER: Record<string, number> = {
декларация: 1,
разрешение: 2,
проектная: 3,
отчётность: 4,
прочее: 5,
};
export function ObjectDocumentsList({ docs }: { docs: ObjectDocumentRow[] }) {
if (docs.length === 0) {
return (
<p style={{ color: "#9ca3af", fontSize: 13 }}>Документы отсутствуют.</p>
);
}
// Group by doc_type
const byType = new Map<string, ObjectDocumentRow[]>();
for (const d of docs) {
const group = byType.get(d.doc_type) ?? [];
group.push(d);
byType.set(d.doc_type, group);
}
const sortedTypes = [...byType.keys()].sort((a, b) => {
const oa = DOC_TYPE_ORDER[a.toLowerCase()] ?? 99;
const ob = DOC_TYPE_ORDER[b.toLowerCase()] ?? 99;
return oa - ob || a.localeCompare(b, "ru");
});
return (
<div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
{sortedTypes.map((type) => {
const group = byType.get(type)!;
return (
<div key={type}>
<div
style={{
fontSize: 12,
textTransform: "uppercase",
letterSpacing: 0.5,
color: "#5b6066",
marginBottom: 6,
}}
>
{type}
</div>
<div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
{group.map((doc, i) => (
<div
key={`${doc.doc_type}-${doc.doc_num ?? i}`}
style={{
display: "flex",
alignItems: "baseline",
gap: 8,
fontSize: 13,
}}
>
<span style={{ fontSize: 16, lineHeight: 1 }}>📄</span>
<a
href={safeUrl(doc.file_url)}
target="_blank"
rel="noopener noreferrer"
style={{ color: "#1e40af", textDecoration: "none" }}
>
{doc.doc_num ? `${doc.doc_num}` : `Документ ${i + 1}`}
</a>
{doc.posted_at ? (
<span style={{ color: "#9ca3af", fontSize: 12 }}>
{doc.posted_at.slice(0, 10)}
</span>
) : null}
{doc.size_bytes ? (
<span style={{ color: "#9ca3af", fontSize: 12 }}>
{fmtSize(doc.size_bytes)}
</span>
) : null}
</div>
))}
</div>
</div>
);
})}
</div>
);
}