st: feat: 수식 다이얼로그 컬럼 검색 추가

This commit is contained in:
2026-03-30 16:26:36 +09:00
parent 28681969e2
commit a73265eac6
@@ -10,6 +10,7 @@ import {
DialogClose,
Textarea,
Skeleton,
Input,
} from "@common/components";
import { CodeSelect } from "@/entities/code";
@@ -41,6 +42,9 @@ const FomulaDialog = ({ open, onOpenChange, data, trgtStatsCd, trgtStatsNm, onCo
const [showCommonColumns, setShowCommonColumns] = useState<boolean>(true);
const [showTargetColumns, setShowTargetColumns] = useState<boolean>(true);
const [showRefColumns, setShowRefColumns] = useState<boolean>(true);
const [commonColumnSearchValue, setCommonColumnSearchValue] = useState<string>('');
const [targetColumnSearchValue, setTargetColumnSearchValue] = useState<string>('');
const [refColumnSearchValue, setRefColumnSearchValue] = useState<string>('');
/** 참조 통계 - 다이얼로그 내부에서만 사용. 열 때마다 해당 행(data)의 저장값으로 초기화, 저장 시에만 부모에 반영 예정 */
const [refStatsCdLocal, setRefStatsCdLocal] = useState<string>('');
/** 수식 = 토큰 배열. 한글명 중복 시 출처(공통/대상/참조)별 engColNm 보존 */
@@ -207,7 +211,7 @@ const FomulaDialog = ({ open, onOpenChange, data, trgtStatsCd, trgtStatsNm, onCo
refStatsCd: data.refStatsCd,
});
}
if (response?.status === 'success') {
setColumnInfo(response.data);
@@ -359,10 +363,57 @@ const FomulaDialog = ({ open, onOpenChange, data, trgtStatsCd, trgtStatsNm, onCo
setFormulaSaveError(null);
setSelectedColumnInfo(null);
setRefStatsCdLocal('');
setCommonColumnSearchValue('');
setTargetColumnSearchValue('');
setRefColumnSearchValue('');
}
onOpenChange?.(nextOpen);
};
const handleSearchColumn = (value: string, type: string) => {
if (type === 'common') {
setCommonColumnSearchValue(value);
} else if (type === 'target') {
setTargetColumnSearchValue(value);
} else {
setRefColumnSearchValue(value);
}
};
const normalizeSearch = (v: string) => v.replace(/\s+/g, "").toLowerCase();
const commonSearch = normalizeSearch(commonColumnSearchValue);
const commonColumns = columnInfo?.commonColumnInfo ?? [];
const filteredCommonColumns =
commonSearch.length > 0
? commonColumns.filter((c) => {
const korn = normalizeSearch(c.kornColNm ?? '');
const eng = normalizeSearch(c.engColNm ?? '');
return korn.includes(commonSearch) || eng.includes(commonSearch);
})
: commonColumns;
const targetSearch = normalizeSearch(targetColumnSearchValue);
const targetColumns = columnInfo?.targetColumnInfo?.colList ?? [];
const filteredTargetColumns =
targetSearch.length > 0
? targetColumns.filter((t) => {
const korn = normalizeSearch(t.kornColNm ?? '');
const eng = normalizeSearch(t.engColNm ?? '');
return korn.includes(targetSearch) || eng.includes(targetSearch);
})
: targetColumns;
const refSearch = normalizeSearch(refColumnSearchValue);
const filterdRefColumns =
refSearch.length > 0
? refColList.filter((r) => {
const korn = normalizeSearch(r.kornColNm ?? '');
const eng = normalizeSearch(r.engColNm ?? '');
return korn.includes(refSearch) || eng.includes(refSearch);
})
: refColList;
return (
<Dialog open={open} onOpenChange={handleOpenChange}>
<DialogContent aria-describedby={undefined} className="max-w-[100rem] w-full max-h-[90%] overflow-auto">
@@ -446,21 +497,30 @@ const FomulaDialog = ({ open, onOpenChange, data, trgtStatsCd, trgtStatsNm, onCo
{showCommonColumns ? "접기" : "펼치기"}
</Button>
</div>
{showCommonColumns &&
<div className="mb-2">
<Input
className="w-[20rem] rounded-sm !text-[1.3rem] focus-visible:ring-0 focus-visible:ring-offset-0"
value={commonColumnSearchValue}
onChange={(e) => handleSearchColumn(e.target.value, 'common')}
placeholder="검색어를 입력하세요."
/>
</div>}
{showCommonColumns ? (
<div className="flex flex-wrap gap-2">
{columnInfo?.commonColumnInfo?.length && columnInfo.commonColumnInfo.length > 0 ?
columnInfo.commonColumnInfo.map((c) => (
<Button
key={c.engColNm}
type="button"
value={c.engColNm}
size="sm"
color="lightGray"
onClick={() => handleFormulaColumn(c.kornColNm, c.engColNm)}
>
{c.kornColNm}
</Button>
))
filteredCommonColumns.map((c) => (
<Button
key={c.engColNm}
type="button"
value={c.engColNm}
size="sm"
color="lightGray"
onClick={() => handleFormulaColumn(c.kornColNm, c.engColNm)}
>
{c.kornColNm}
</Button>
))
:
<Skeleton className="h-[12rem] w-full rounded-xl" />
}
@@ -479,20 +539,30 @@ const FomulaDialog = ({ open, onOpenChange, data, trgtStatsCd, trgtStatsNm, onCo
{showTargetColumns ? "접기" : "펼치기"}
</Button>
</div>
{showTargetColumns &&
<div className="mb-2">
<Input
className="w-[20rem] rounded-sm !text-[1.3rem] focus-visible:ring-0 focus-visible:ring-offset-0"
value={targetColumnSearchValue}
onChange={(e) => handleSearchColumn(e.target.value, 'target')}
placeholder="검색어를 입력하세요."
/>
</div>
}
{showTargetColumns ? (
<div className="flex flex-wrap gap-2">
{columnInfo?.targetColumnInfo?.colList.length && columnInfo.targetColumnInfo.colList.length > 0 ?
columnInfo.targetColumnInfo.colList.map((t) => (
<Button
key={t.engColNm}
type="button"
value={t.engColNm}
size="sm"
onClick={() => handleFormulaColumn(t.kornColNm, t.engColNm)}
>
{t.kornColNm}
</Button>
))
filteredTargetColumns.map((t) => (
<Button
key={t.engColNm}
type="button"
value={t.engColNm}
size="sm"
onClick={() => handleFormulaColumn(t.kornColNm, t.engColNm)}
>
{t.kornColNm}
</Button>
))
:
<Skeleton className="h-[12rem] w-full rounded-xl" />
}
@@ -529,10 +599,20 @@ const FomulaDialog = ({ open, onOpenChange, data, trgtStatsCd, trgtStatsNm, onCo
{refStatsChangeNotice}
</p>
)}
{(refStatsCdLocal && showRefColumns) &&
<div className="mb-2">
<Input
className="w-[20rem] rounded-sm !text-[1.3rem] focus-visible:ring-0 focus-visible:ring-offset-0"
value={refColumnSearchValue}
onChange={(e) => handleSearchColumn(e.target.value, 'ref')}
placeholder="검색어를 입력하세요."
/>
</div>
}
{showRefColumns ? (
<div className="flex flex-wrap gap-2">
{(refColList?.length ?? 0) > 0 ?
refColList.map((r) => (
{(filterdRefColumns?.length ?? 0) > 0 ?
filterdRefColumns.map((r) => (
<Button
key={r.engColNm}
type="button"