shared/lib/datetime.ts에 KST 고정 포맷 함수 추가. AIS 정보, 선박 목록, 대시보드 등의 날짜 표시를 로컬 포맷에서 KST 명시적 포맷으로 통일. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
98 lines
3.9 KiB
TypeScript
98 lines
3.9 KiB
TypeScript
import type { AisTarget } from "../../entities/aisTarget/model/types";
|
|
import type { LegacyVesselInfo } from "../../entities/legacyVessel/model/types";
|
|
import { fmtIsoFull } from "../../shared/lib/datetime";
|
|
|
|
type Props = {
|
|
target: AisTarget;
|
|
legacy?: LegacyVesselInfo | null;
|
|
onClose: () => void;
|
|
};
|
|
|
|
export function AisInfoPanel({ target: t, legacy, onClose }: Props) {
|
|
const name = (t.name || "").trim() || "(no name)";
|
|
return (
|
|
<div className="map-info">
|
|
<button className="close-btn" onClick={onClose} aria-label="close">
|
|
✕
|
|
</button>
|
|
|
|
<div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 8 }}>
|
|
<div>
|
|
<div style={{ fontSize: 16, fontWeight: 900, color: "var(--accent)" }}>{name}</div>
|
|
<div style={{ fontSize: 10, color: "var(--muted)" }}>
|
|
MMSI {t.mmsi} · {t.vesselType || "Unknown"} · Class {t.classType || "?"}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{legacy ? (
|
|
<div style={{ marginBottom: 8, padding: "8px 8px", borderRadius: 8, border: "1px solid rgba(245,158,11,.35)", background: "rgba(245,158,11,.06)" }}>
|
|
<div style={{ fontSize: 10, fontWeight: 900, color: "#F59E0B", marginBottom: 4 }}>CN Permit Match</div>
|
|
<div style={{ fontSize: 10, color: "var(--text)", lineHeight: 1.5 }}>
|
|
<div>
|
|
<span style={{ color: "var(--muted)" }}>업종</span> <b>{legacy.shipCode}</b> ·{" "}
|
|
<span style={{ color: "var(--muted)" }}>허가번호</span> <b>{legacy.permitNo}</b>
|
|
</div>
|
|
<div>
|
|
<span style={{ color: "var(--muted)" }}>허가수역</span> <b>{legacy.workSeaArea || "-"}</b> ·{" "}
|
|
<span style={{ color: "var(--muted)" }}>톤수</span> <b>{legacy.ton ?? "-"}</b>
|
|
</div>
|
|
{legacy.ownerCn || legacy.ownerRoman ? (
|
|
<div>
|
|
<span style={{ color: "var(--muted)" }}>소유주</span>{" "}
|
|
<b>{legacy.ownerCn || legacy.ownerRoman}</b>
|
|
{legacy.ownerCn && legacy.ownerRoman ? <span style={{ color: "var(--muted)" }}> ({legacy.ownerRoman})</span> : null}
|
|
</div>
|
|
) : null}
|
|
{legacy.pairPermitNo ? (
|
|
<div>
|
|
<span style={{ color: "var(--muted)" }}>짝</span> <b>{legacy.pairPermitNo}</b>
|
|
{legacy.pairShipNameCn ? <span style={{ color: "var(--muted)" }}> · {legacy.pairShipNameCn}</span> : null}
|
|
</div>
|
|
) : null}
|
|
</div>
|
|
</div>
|
|
) : null}
|
|
|
|
<div className="ir">
|
|
<span className="il">SOG</span>
|
|
<span className="iv">{t.sog ?? "?"} kt</span>
|
|
</div>
|
|
<div className="ir">
|
|
<span className="il">COG</span>
|
|
<span className="iv">{t.cog ?? "?"}°</span>
|
|
</div>
|
|
<div className="ir">
|
|
<span className="il">Heading</span>
|
|
<span className="iv">{t.heading ?? "?"}°</span>
|
|
</div>
|
|
<div className="ir">
|
|
<span className="il">Status</span>
|
|
<span className="iv">{t.status || "N/A"}</span>
|
|
</div>
|
|
<div className="ir">
|
|
<span className="il">Position</span>
|
|
<span className="iv">
|
|
{Number.isFinite(t.lat) ? t.lat.toFixed(5) : "?"}, {Number.isFinite(t.lon) ? t.lon.toFixed(5) : "?"}
|
|
</span>
|
|
</div>
|
|
<div className="ir">
|
|
<span className="il">Dest</span>
|
|
<span className="iv">{(t.destination || "").trim() || "-"}</span>
|
|
</div>
|
|
<div className="ir">
|
|
<span className="il">ETA</span>
|
|
<span className="iv">{t.eta || "-"}</span>
|
|
</div>
|
|
<div className="ir">
|
|
<span className="il">Msg TS</span>
|
|
<span className="iv">{fmtIsoFull(t.messageTimestamp)}</span>
|
|
</div>
|
|
<div className="ir">
|
|
<span className="il">Received</span>
|
|
<span className="iv">{fmtIsoFull(t.receivedDate)}</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|