Files
kkpab-site/frontend/app/documents/page.tsx
T
ogrechkoandClaude Sonnet 5 ea6c43f5af Fix production build: npm registry flakiness, stray package-lock.json dir, TS error
- registry.npmjs.org was intermittently ETIMEDOUT mid-download from this
  host; switched to registry.npmmirror.com (also raised npm's own retry
  budget as a second line of defense).
- frontend/package-lock.json on disk was actually an empty directory
  (untracked, root-owned — a stray artifact, likely from an old bad
  bind-mount), which broke `COPY . .` once npm install got past it.
- documents/page.tsx had a real type error (selectedItem.file narrowing
  didn't survive into the .map() closure) that `next dev` never
  surfaced but `next build`'s stricter check does — fixed by hoisting
  the narrowed array into selectedFiles once instead of re-narrowing
  selectedItem.file at each use.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gh2UXUQUVBWroWEnn1FLFG
2026-09-03 05:18:49 +00:00

190 lines
9.4 KiB
TypeScript

import Link from "next/link";
import { Download, ExternalLink, Eye, FileText } from "lucide-react";
type DocumentItem = {
id: number;
title: string;
file?: string | string[];
mode: "preview" | "download" | "disabled";
};
const documentItems: DocumentItem[] = [
{ id: 1, title: "Скачать договор на обслуживание", file: "doc_on_out.doc", mode: "download" },
{ id: 2, title: "Правила о предоставлении платных услуг", file: "pravila_o_pred.pdf", mode: "preview" },
{ id: 3, title: "Перечень платных медицинских услуг", file: "price_site.pdf", mode: "preview" },
{ id: 4, title: "Лицензия", file: "lic.pdf", mode: "preview" },
{ id: 5, title: "Правила внутреннего распорядка", file: "Indoor_rule.pdf", mode: "preview" },
{ id: 6, title: "Лекарственное обеспечение", file: "jnvlp.pdf", mode: "preview" },
{ id: 7, title: "О правилах и сроках госпитализации", file: "o_pravilah_gospitalizacii.pdf", mode: "preview" },
{ id: 8, title: "Территориальная программа ОМС СК", file: "ter-prog.pdf", mode: "preview" },
{ id: 9, title: "О правилах подготовки к диагностическим исследованиям", file: "o_diagnostike.pdf", mode: "preview" },
{ id: 10, title: "О порядке, объеме и условиях оказания медицинской помощи", file: "ob_obyome.pdf", mode: "preview" },
{ id: 11, title: "Правила записи на первичный прием", file: "pravilo_zapisi_na_perviy_priem.pdf", mode: "preview" },
{ id: 12, title: "О государственной поддержке развития медицинской промышленности", file: "postanovlenie.pdf", mode: "preview" },
{ id: 13, title: "Информация для пациентов", file: ["pacient1.pdf", "pacient2.pdf"], mode: "preview" },
{ id: 14, title: "Нормативно-правовые документы", file: ["npd1.pdf", "npd2.pdf", "npd3.pdf", "npd5.pdf", "npd7.pdf", "npd8.pdf", "npd9.pdf", "npd10.pdf"], mode: "preview" },
{ id: 15, title: "Права и обязанности гражданина в сфере охраны здоровья", file: "piog.pdf", mode: "preview" },
{ id: 16, title: "Перечень ЖНВЛП", file: "jnvlp.pdf", mode: "preview" },
{ id: 17, title: "Работа с персональными данными", file: "rpd.pdf", mode: "preview" },
];
export default async function DocumentsPage({
searchParams,
}: {
// Добавляем параметр fileIndex для отслеживания выбранного файла в массиве
searchParams: Promise<{ doc?: string; fileIndex?: string }>;
}) {
const params = await searchParams;
const selectedId = Number(params.doc);
const selectedIndex = Number(params.fileIndex) || 0; // По умолчанию 0 (первый файл)
const firstPreviewable =
documentItems.find((item) => item.mode === "preview" && item.file) ?? null;
const selectedItem =
documentItems.find((item) => item.id === selectedId && item.mode === "preview" && item.file) ??
firstPreviewable;
// Логика определения конкретного файла для отображения
let fileForLink: string | null = null;
let previewUrl: string | null = null;
const selectedFiles: string[] | null = Array.isArray(selectedItem?.file) ? selectedItem.file : null;
if (selectedItem?.file) {
if (Array.isArray(selectedItem.file)) {
// Защита от неверного индекса в URL
const validIndex = selectedIndex >= 0 && selectedIndex < selectedItem.file.length ? selectedIndex : 0;
fileForLink = selectedItem.file[validIndex];
} else {
fileForLink = selectedItem.file;
}
previewUrl = `/documents/${fileForLink}#toolbar=0&navpanes=0&scrollbar=1`;
}
return (
<div className="container">
<section className="page-hero">
<span className="eyebrow">Документы</span>
<h1>Лицензии и официальные сведения</h1>
<p className="page-intro">
Для удобства документы переведены в PDF-формат для встроенного просмотра. Первый пункт
остаётся отдельной кнопкой скачивания договора.
</p>
</section>
<section className="section">
<div className="documents-layout">
<aside className="documents-sidebar">
<div className="documents-sidebar__panel">
{documentItems.map((item) => {
if (item.mode === "download" && item.file) {
// Для скачивания всегда берем первый файл, если это массив
const fileStr = Array.isArray(item.file) ? item.file[0] : item.file;
return (
<a
key={item.id}
href={`/documents/${fileStr}`}
download
className="documents-link documents-link--download"
>
<Download size={16} />
<span>{item.title}</span>
</a>
);
}
if (item.mode === "disabled") {
return (
<div key={item.id} className="documents-link documents-link--disabled">
<FileText size={16} />
<span>{item.title}</span>
</div>
);
}
return (
<Link
key={item.id}
// При клике в сайдбаре сбрасываем fileIndex, чтобы всегда открывался первый файл новой категории
href={`/documents?doc=${item.id}`}
className={`documents-link documents-link--button${
selectedItem?.id === item.id ? " documents-link--active" : ""
}`}
>
<Eye size={16} />
<span>{item.title}</span>
</Link>
);
})}
</div>
</aside>
<div className="documents-content">
<article className="page-panel documents-preview">
<div className="documents-preview__header">
<div style={{ flex: 1 }}>
<span className="eyebrow">Просмотр документа</span>
<h2>{selectedItem?.title ?? "Документ не выбран"}</h2>
{/* Вывод списка кнопок, если файлов несколько */}
{selectedFiles && selectedFiles.length > 1 && (
<div style={{ display: "flex", gap: "8px", flexWrap: "wrap", marginTop: "12px" }}>
{selectedFiles.map((fileName, idx) => {
const validCurrentIndex = selectedIndex < selectedFiles.length ? selectedIndex : 0;
const isActive = validCurrentIndex === idx;
return (
<Link
key={fileName}
href={`/documents?doc=${selectedItem?.id}&fileIndex=${idx}`}
className={`documents-link documents-link--button ${
isActive ? "documents-link--active" : ""
}`}
style={{ padding: "6px 12px", width: "auto", fontSize: "0.85rem" }}
>
<FileText size={14} />
<span>Файл {idx + 1}</span>
</Link>
);
})}
</div>
)}
</div>
{fileForLink ? (
<a
href={`/documents/${fileForLink}`}
target="_blank"
rel="noreferrer"
className="documents-preview__note"
>
<ExternalLink size={18} />
<span>Открыть в отдельной вкладке</span>
</a>
) : (
<div className="documents-preview__note">
<FileText size={18} />
<span>Документ недоступен</span>
</div>
)}
</div>
{previewUrl ? (
<div className="documents-preview__frame">
<iframe
// Важно: key={fileForLink} заставит iframe перезагрузиться при смене файла
key={fileForLink}
src={previewUrl}
title={selectedItem?.title ?? "Документ"}
className="documents-preview__iframe"
/>
</div>
) : (
<div className="documents-preview__empty">Документ не выбран.</div>
)}
</article>
</div>
</div>
</section>
</div>
);
}