Files
frontend/apps/st/src/components/statistics/verification/generalVerification/OperatorsComponents.tsx
T
2026-08-20 11:48:18 +09:00

101 lines
3.0 KiB
TypeScript

import { useEffect, useState } from "react";
import { generalverificationApiService } from '@/entities/statistics/api/general-verification-service';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@common/components";
type OperatorItem = {
opertSn: string;
opertSymbl: string;
opertKornNm: string;
};
// opertSeCd 별 operators 목록을 전역 캐싱해서, 수식 블록이 여러 개여도 중복 요청이 발생하지 않게 한다.
const operatorsCache: Map<
string,
OperatorItem[] | Promise<OperatorItem[]>
> = new Map();
interface OperatorsComponentsProps {
cmprOpert?: string | null;
onValueChange?: (value: string) => void;
placeholder?: string;
opertSeCd?: string;
}
const OperatorsComponents = ({
cmprOpert,
onValueChange,
placeholder = "연산자 없음",
opertSeCd = "opertSeCd=CMPR"
}: OperatorsComponentsProps) => {
const [operators, setOperators] = useState<OperatorItem[]>([]);
const [localValue, setLocalValue] = useState<string>(cmprOpert ?? "");
useEffect(() => {
setLocalValue(cmprOpert ?? "");
}, [cmprOpert]);
useEffect(() => {
const cached = operatorsCache.get(opertSeCd);
if (Array.isArray(cached)) {
setOperators(cached);
return;
}
const promise =
cached ??
(async (): Promise<OperatorItem[]> => {
const response =
await generalverificationApiService.getVrfcOperators(
opertSeCd,
);
if (response.status === "success" && response.data) {
return response.data as OperatorItem[];
}
return [];
})();
operatorsCache.set(opertSeCd, promise);
void promise.then((items) => {
operatorsCache.set(opertSeCd, items);
setOperators(items);
});
}, [opertSeCd]);
// onValueChange가 있으면 부모가 제어(controlled), 없으면 내부 state로 표시
const isControlled = onValueChange !== undefined;
const value = (isControlled ? (cmprOpert ?? "") : localValue) || "";
return (
<Select
value={value}
onValueChange={(v) => {
setLocalValue(v);
onValueChange?.(v);
}}
>
<SelectTrigger className="!w-[150px] min-w-[150px] max-w-[150px] h-[4rem] overflow-hidden focus:outline-none focus:ring-0">
<SelectValue placeholder={placeholder} />
</SelectTrigger>
<SelectContent className="w-[150px]">
<SelectItem value='none'>
연산자 없음
</SelectItem>
{operators.map((op) => (
<SelectItem key={op.opertSn} value={op.opertSymbl}>
{op.opertKornNm}
</SelectItem>
))}
</SelectContent>
</Select>
);
};
export default OperatorsComponents;