Files
frontend/apps/sn/app/(map-layout)/map/components/aged-pipe/aged-pipe-layer-setting-panel.tsx
T

136 lines
4.3 KiB
TypeScript

/**
* 화면명: 노후관로 레이어 설정
* 사업차수와 구조적·운영적 상태등급별 지도 표시 조건을 설정한다.
*/
"use client";
import { useEffect, useState } from "react";
import { useAlertStore } from "@/shared/lib";
import { validateElapsedYears, type AgedPipeFilters } from "@/entities/facility/lib/aged-pipe-utils";
import LayerSettingCard from "../layer-setting/layer-setting-card";
type MaybePromise<T = void> = T | Promise<T>;
type Props = {
filters: AgedPipeFilters;
onFiltersChange: (filters: AgedPipeFilters) => void;
onApply: (filters?: AgedPipeFilters) => MaybePromise;
compact?: boolean;
enabled?: boolean;
onEnabledChange?: (enabled: boolean) => void;
onClose?: () => void;
};
export default function AgedPipeLayerSettingPanel({
filters,
onFiltersChange,
onApply,
compact = false,
enabled = true,
onEnabledChange = () => {},
onClose = () => {},
}: Props) {
const alert = useAlertStore((state) => state.setMessage);
const [isCollapsed, setIsCollapsed] = useState(false);
const [elapsedYearsText, setElapsedYearsText] = useState(
String(filters.elapsedYears ?? ""),
);
useEffect(() => {
setElapsedYearsText(String(filters.elapsedYears ?? ""));
}, [filters.elapsedYears]);
const commitElapsedYears = async () => {
const elapsedYears =
elapsedYearsText === "" ? NaN : Number(elapsedYearsText);
if (!validateElapsedYears(elapsedYears)) {
alert("경과년도는 1년~100년 범위 내에서 입력해주세요.");
return;
}
const nextFilters = {
...filters,
elapsedYears,
};
onFiltersChange(nextFilters);
await onApply(nextFilters);
alert(`노후관로 경과년도 ${elapsedYears}년으로 반영되었습니다.`);
};
const inputClass =
"h-[26px] !rounded border border-input bg-background px-2 py-0 text-center text-[12px] leading-none text-foreground";
const numberInputClass = inputClass + " min-w-0 flex-1";
const applyButtonClass =
"h-[26px] shrink-0 rounded border border-[#A9C5E5] bg-[#EDF4FC] px-2 py-0 text-[12px] font-medium leading-none text-[#2463A6]";
const settingRow = (
<div className="flex min-h-[26px] flex-col items-stretch gap-1.5 whitespace-nowrap text-[1.15rem] font-medium text-label">
<div className="flex min-w-0 items-center">
<label htmlFor="aged-pipe-elapsed-years" className="shrink-0">
노후관로 경과년도(년)
</label>
</div>
<div className="flex w-full items-center gap-1">
<input
id="aged-pipe-elapsed-years"
className={numberInputClass}
type="text"
inputMode="numeric"
pattern="[0-9]*"
autoComplete="off"
value={elapsedYearsText}
onFocus={(event) => event.currentTarget.select()}
onChange={(event) => {
const digits = event.target.value.replace(/[^0-9]/g, "");
setElapsedYearsText(digits);
}}
onKeyDown={(event) => {
if (event.key === "Enter") void commitElapsedYears();
}}
/>
<button
type="button"
className={applyButtonClass}
onClick={() => void commitElapsedYears()}
title="적용"
aria-label="경과년도 적용"
>
확인
</button>
</div>
</div>
);
if (compact) {
return (
<LayerSettingCard
title="노후관로"
enabled={enabled}
onEnabledChange={onEnabledChange}
onClose={onClose}
>
{settingRow}
</LayerSettingCard>
);
}
return (
<div className="w-full overflow-hidden rounded-sm border border-red-100 bg-red-50/35">
<div className="relative flex min-h-[30px] items-center justify-center border-b border-red-100 bg-background px-8">
<button
type="button"
className="absolute left-2 top-1/2 h-[18px] w-[18px] -translate-y-1/2 bg-transparent text-[1.2rem] leading-none text-muted-foreground"
onClick={() => setIsCollapsed((value) => !value)}
title={isCollapsed ? "펼치기" : "접기"}
>
{isCollapsed ? "+" : "-"}
</button>
<span className="text-[1.2rem] font-semibold text-red-700">
노후관로 설정
</span>
</div>
{!isCollapsed && <div className="px-2 py-2">{settingRow}</div>}
</div>
);
}