136 lines
4.3 KiB
TypeScript
136 lines
4.3 KiB
TypeScript
/**
|
|
* 화면명: 노후관로 레이어 설정
|
|
* 사업차수와 구조적·운영적 상태등급별 지도 표시 조건을 설정한다.
|
|
*/
|
|
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { useAlertStore } from "@/shared/lib";
|
|
import { validateElapsedYears, type AgedPipeFilters } from "./agedPipeUtils";
|
|
import LayerSettingCard from "../layerSetting/LayerSettingCard";
|
|
|
|
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>
|
|
);
|
|
}
|