Files
dc-observatio/services/pcp-tgu-ui-service/src/features/tgu-requests/RequestDetailsPanel.tsx
T

173 lines
6.1 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 { useEffect, useState } from "react";
import type { RequestAtPoint } from "../tgu-map-2d/Tgu2DMapRequestsPanel";
import { formatLocalDateTime, parseLocal } from "../../utils/localTime";
type Props = {
requests: RequestAtPoint[];
selectedPolygonId?: string;
deleting: boolean;
deleteError?: string;
onHover: (polygonId: string | undefined) => void;
onSelect: (polygonId: string) => void;
onDelete: (requestId: string) => void;
onClose: () => void;
};
export function RequestDetailsPanel({
requests,
selectedPolygonId,
deleting,
deleteError,
onHover,
onSelect,
onDelete,
onClose
}: Props) {
const selectedEntry = selectedPolygonId
? requests.find((r) => r.polygon.id === selectedPolygonId)
: requests.length === 1
? requests[0]
: undefined;
// Второй шаг подтверждения удаления. Сбрасываем при смене выбранной заявки,
// чтобы открытый запрос на удаление не «переезжал» на другую заявку.
const [confirmingDelete, setConfirmingDelete] = useState(false);
useEffect(() => {
setConfirmingDelete(false);
}, [selectedEntry?.item.id]);
return (
<aside className="tgu-map-requests-panel">
<div className="tgu-panel-heading">
<span>Заявки в точке ({requests.length})</span>
<button className="tgu-link-button" type="button" onClick={onClose}>
Закрыть
</button>
</div>
{requests.length > 1 && (
<div className="tgu-map-requests-list">
{requests.map(({ polygon, item }) => (
<button
key={polygon.id}
className={`tgu-map-request-row ${polygon.id === selectedEntry?.polygon.id ? "is-selected" : ""}`}
type="button"
onMouseEnter={() => onHover(polygon.id)}
onMouseLeave={() => onHover(undefined)}
onClick={() => onSelect(polygon.id)}
>
<i className={`tgu-map-request-row__type req-${item.surveyType.toLowerCase()}`} />
<span className="tgu-map-request-row__body">
<span className="tgu-map-request-row__name">{item.name || item.id}</span>
<span className="tgu-map-request-row__meta">
{formatDateTime(item.beginDateTime)} · {item.surveyType} · {item.status}
</span>
</span>
</button>
))}
</div>
)}
{selectedEntry && (
<div className="tgu-map-request-details" style={{ flex: 1 }}>
<div className="tgu-map-panel__label">Детали заявки</div>
<dl className="tgu-map-request-details__grid">
<dt>ID</dt>
<dd className="mono">{selectedEntry.item.id}</dd>
<dt>Название</dt>
<dd>{selectedEntry.item.name || "—"}</dd>
<dt>Статус</dt>
<dd>{selectedEntry.item.status}</dd>
<dt>Тип съёмки</dt>
<dd>{surveyTypeLabel(selectedEntry.item.surveyType)}</dd>
<dt>Начало</dt>
<dd className="mono">{formatDateTime(selectedEntry.item.beginDateTime)}</dd>
<dt>Конец</dt>
<dd className="mono">{formatDateTime(selectedEntry.item.endDateTime)}</dd>
<dt>Важность</dt>
<dd className="mono">{selectedEntry.item.importance}</dd>
<dt>Покрытие</dt>
<dd className="mono">
{selectedEntry.item.coveragePercent != null ? `${selectedEntry.item.coveragePercent.toFixed(1)} %` : "—"}
</dd>
<dt>КПП</dt>
<dd className="mono">{selectedEntry.item.kpp?.join(", ") || "—"}</dd>
<dt>Приоритет передачи</dt>
<dd>{selectedEntry.item.highPriorityTransmit ? "Да" : "Нет"}</dd>
<dt>Создано</dt>
<dd className="mono">{formatDateTime(selectedEntry.item.createdAt)}</dd>
<dt>Изменено</dt>
<dd className="mono">{formatDateTime(selectedEntry.item.updatedAt)}</dd>
</dl>
{deleteError && <div className="tgu-alert tgu-alert--danger tgu-alert--compact">{deleteError}</div>}
{confirmingDelete ? (
<div className="tgu-requests-confirm">
<div className="tgu-requests-confirm__title">Удалить заявку?</div>
<div className="tgu-requests-confirm__subtitle">{selectedEntry.item.name || selectedEntry.item.id}</div>
<div className="tgu-requests-form__actions">
<button
className="tgu-button tgu-button--reject"
type="button"
disabled={deleting}
onClick={() => onDelete(selectedEntry.item.id)}
>
{deleting ? "Удаление..." : "Да, удалить"}
</button>
<button
className="tgu-button"
type="button"
disabled={deleting}
onClick={() => setConfirmingDelete(false)}
>
Нет, не удалять
</button>
</div>
</div>
) : (
<div className="tgu-requests-form__actions">
<button
className="tgu-button tgu-button--reject"
type="button"
disabled={deleting}
onClick={() => setConfirmingDelete(true)}
>
Удалить заявку
</button>
</div>
)}
</div>
)}
</aside>
);
}
function formatDateTime(value: string): string {
return formatLocalDateTime(parseLocal(value));
}
function surveyTypeLabel(surveyType: string): string {
switch (surveyType) {
case "OPTICS":
return "Оптическая";
case "RSA":
return "Радиолокационная (РСА)";
case "COMBINED":
return "Комбинированная";
default:
return surveyType;
}
}