Files
frontend/apps/sn/app/(map-layout)/map/components/agedPipe/AgedPipeLayerSettingPanel.tsx
T

125 lines
4.0 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
import { useAlertStore } from "@/shared/lib";
import { validateElapsedYears, type AgedPipeFilters } from "./agedPipeUtils";
type MaybePromise<T = void> = T | Promise<T>;
type Props = {
filters: AgedPipeFilters;
onFiltersChange: (filters: AgedPipeFilters) => void;
onApply: (filters?: AgedPipeFilters) => MaybePromise;
compact?: boolean;
};
export default function AgedPipeLayerSettingPanel({
filters,
onFiltersChange,
onApply,
compact = false,
}: 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-[22px] border border-input bg-background px-[2px] text-center text-[1rem] leading-none text-foreground";
const numberInputClass = inputClass + " w-[40px]";
const applyButtonClass =
"grid h-[20px] w-[20px] shrink-0 place-items-center rounded-full bg-primary text-[0.95rem] font-bold leading-none text-primary-foreground";
const indicator = (
<span className="h-2 w-2 shrink-0 rounded-full bg-primary" />
);
const settingRow = (
<div className="flex min-h-[25px] items-center gap-1 whitespace-nowrap text-[1.05rem] font-medium text-label">
<div className="flex min-w-0 items-center gap-1">
{indicator}
<label htmlFor="aged-pipe-elapsed-years" className="shrink-0">
노후관로 경과년도(년)
</label>
</div>
<div className="ml-auto flex shrink-0 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 (
<div className="w-full rounded-[6px] border border-border bg-background px-[6px] py-2 shadow-blur">
{settingRow}
</div>
);
}
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>
);
}