Files
frontend/apps/sn/app/(map-layout)/map/components/fldngHstry/FldngHstryDetailPanel.tsx
T

157 lines
4.8 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.
"use client";
import { useMemo, useState } from "react";
import {
formatFloodArea,
formatFloodDepth,
type FldngHstryItem,
} from "./fldngHstryTypes";
type Props = {
detail: FldngHstryItem;
onClose: () => void;
position: {
left: number;
top: number;
};
};
type DetailTab = "year" | "disaster" | "rainfall";
const renderRows = (rows: Array<[string, string]>) => (
<table className="w-full table-fixed border-collapse">
<colgroup>
<col className="w-[42%]" />
<col className="w-[58%]" />
</colgroup>
<tbody>
{rows.map(([label, value], index) => (
<tr key={`${label}-${index}`}>
<th className="border border-border bg-secondary px-3 py-[7px] text-left text-[1.02rem] font-semibold text-label">
{label}
</th>
<td className="border border-border bg-background px-3 py-[7px] text-[1.02rem] text-foreground">
{value}
</td>
</tr>
))}
</tbody>
</table>
);
export default function FldngHstryDetailPanel({
detail,
onClose,
position,
}: Props) {
// 지도에서 침수흔적도 polygon을 클릭했을 때, 상세정보는 업무 의미 기준으로 3개 탭에 나눠 보여준다.
const [activeTab, setActiveTab] = useState<DetailTab>("year");
const yearRows = useMemo(
() =>
[
["침수심", `${detail.floodDepthM.toFixed(2)} m`],
["침수면적", formatFloodArea(detail.floodAreaHa)],
["침수년도", `${detail.floodYear}년`],
["등급", detail.gradeLabel],
["침수구역", detail.districtName],
] as Array<[string, string]>,
[detail],
);
const disasterRows = useMemo(
() =>
[
["침수재해명", detail.disasterName],
["침수면적", formatFloodArea(detail.floodAreaHa)],
["침수원인상세명", detail.causeDetailName],
["침수시작년월일", detail.startDate],
["침수종료년월일", detail.endDate],
["침수시작시간", detail.startTime],
] as Array<[string, string]>,
[detail],
);
const rainfallRows = useMemo(
() =>
[
["침수시작일자", detail.startDate],
["침수종료일자", detail.endDate],
["침수시작시간", detail.startTime],
["침수종료시간", detail.endTime],
["침수시간", detail.floodHour],
["강우시작시간", detail.rainStartTime],
["강우종료시간", detail.rainEndTime],
["총강우량(mm)", `${detail.totalRainfallMm.toFixed(0)}`],
["강우강도(mm/hr)", `${detail.rainfallIntensityMmHr.toFixed(0)}`],
["침수시간", detail.floodHour],
["침수원인상세코드", detail.causeDetailCode],
["피해금액", detail.damageAmount],
] as Array<[string, string]>,
[detail],
);
const currentRows =
activeTab === "year"
? yearRows
: activeTab === "disaster"
? disasterRows
: rainfallRows;
return (
<div
className="absolute z-[70] w-[248px] overflow-hidden rounded-[8px] border border-border bg-background shadow-blur"
style={{
left: `${position.left}px`,
top: `${position.top}px`,
}}
>
<div className="flex h-[28px] items-center justify-between border-b border-border bg-secondary px-[10px]">
<div className="text-[10px] font-bold tracking-[-0.01em] text-label">
상세정보
</div>
<button
type="button"
className="rounded-[4px] px-[4px] text-[13px] leading-none text-muted-foreground transition hover:bg-accent hover:text-accent-foreground"
onClick={onClose}
>
×
</button>
</div>
<div className="border-b border-border bg-secondary px-[6px] pt-[6px]">
<div className="flex gap-[4px]">
{[
["year", "년도탭"],
["disaster", "재해명탭"],
["rainfall", "침수발생강우탭"],
].map(([tabId, label]) => {
const isActive = activeTab === tabId;
return (
<button
key={tabId}
type="button"
className={`h-[24px] flex-1 rounded-t-[6px] border px-[6px] text-[9px] font-semibold leading-none transition ${
isActive
? "border-primary border-b-background bg-background text-primary"
: "border-border bg-secondary text-muted-foreground hover:bg-accent"
}`}
onClick={() => setActiveTab(tabId as DetailTab)}
>
{label}
</button>
);
})}
</div>
</div>
<div className="bg-background p-[6px]">
<div className="overflow-hidden rounded-[6px] border border-border bg-background">
{renderRows(currentRows)}
</div>
</div>
</div>
);
}