125 lines
4.0 KiB
TypeScript
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>
|
|
);
|
|
}
|