gc-wing/apps/web/src/widgets/aisInfo/AisInfoPanel.tsx
htlee cc807bb5f6 feat: KST 타임스탬프 포맷 유틸 적용
shared/lib/datetime.ts에 KST 고정 포맷 함수 추가.
AIS 정보, 선박 목록, 대시보드 등의 날짜 표시를
로컬 포맷에서 KST 명시적 포맷으로 통일.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 12:12:43 +09:00

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>
);
}