From 40c43bab16ed8490c5bae48a97189ccc9cabc53c Mon Sep 17 00:00:00 2001 From: SeongHyun Kim Date: Thu, 4 Dec 2025 13:28:13 +0900 Subject: [PATCH] =?UTF-8?q?feat(numbering-rule):=20=EC=B1=84=EB=B2=88?= =?UTF-8?q?=EA=B7=9C=EC=B9=99=20=EA=B5=AC=EB=B6=84=EC=9E=90=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SeparatorType 타입 및 SEPARATOR_OPTIONS 상수 추가 - 구분자 선택 UI 추가 (없음, -, _, ., /, 직접입력) - 직접 입력 시 최대 2자 제한 - 새 규칙 생성 시 기본값 하이픈(-) - Select 빈 문자열 에러 해결 (value: "" -> "none") --- .../numbering-rule/NumberingRuleDesigner.tsx | 89 ++++++++++++++++++- frontend/types/numbering-rule.ts | 21 +++++ 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/frontend/components/numbering-rule/NumberingRuleDesigner.tsx b/frontend/components/numbering-rule/NumberingRuleDesigner.tsx index bfdb69c2..b23d85de 100644 --- a/frontend/components/numbering-rule/NumberingRuleDesigner.tsx +++ b/frontend/components/numbering-rule/NumberingRuleDesigner.tsx @@ -8,7 +8,7 @@ import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Plus, Save, Edit2, Trash2 } from "lucide-react"; import { toast } from "sonner"; -import { NumberingRuleConfig, NumberingRulePart } from "@/types/numbering-rule"; +import { NumberingRuleConfig, NumberingRulePart, SEPARATOR_OPTIONS, SeparatorType } from "@/types/numbering-rule"; import { NumberingRuleCard } from "./NumberingRuleCard"; import { NumberingRulePreview } from "./NumberingRulePreview"; import { @@ -47,6 +47,10 @@ export const NumberingRuleDesigner: React.FC = ({ const [rightTitle, setRightTitle] = useState("규칙 편집"); const [editingLeftTitle, setEditingLeftTitle] = useState(false); const [editingRightTitle, setEditingRightTitle] = useState(false); + + // 구분자 관련 상태 + const [separatorType, setSeparatorType] = useState("-"); + const [customSeparator, setCustomSeparator] = useState(""); useEffect(() => { loadRules(); @@ -87,6 +91,50 @@ export const NumberingRuleDesigner: React.FC = ({ } }, [currentRule, onChange]); + // currentRule이 변경될 때 구분자 상태 동기화 + useEffect(() => { + if (currentRule) { + const sep = currentRule.separator ?? "-"; + // 빈 문자열이면 "none" + if (sep === "") { + setSeparatorType("none"); + setCustomSeparator(""); + return; + } + // 미리 정의된 구분자인지 확인 (none, custom 제외) + const predefinedOption = SEPARATOR_OPTIONS.find( + opt => opt.value !== "custom" && opt.value !== "none" && opt.displayValue === sep + ); + if (predefinedOption) { + setSeparatorType(predefinedOption.value); + setCustomSeparator(""); + } else { + // 직접 입력된 구분자 + setSeparatorType("custom"); + setCustomSeparator(sep); + } + } + }, [currentRule?.ruleId]); // ruleId가 변경될 때만 실행 (규칙 선택/생성 시) + + // 구분자 변경 핸들러 + const handleSeparatorChange = useCallback((type: SeparatorType) => { + setSeparatorType(type); + if (type !== "custom") { + const option = SEPARATOR_OPTIONS.find(opt => opt.value === type); + const newSeparator = option?.displayValue ?? ""; + setCurrentRule((prev) => prev ? { ...prev, separator: newSeparator } : null); + setCustomSeparator(""); + } + }, []); + + // 직접 입력 구분자 변경 핸들러 + const handleCustomSeparatorChange = useCallback((value: string) => { + // 최대 2자 제한 + const trimmedValue = value.slice(0, 2); + setCustomSeparator(trimmedValue); + setCurrentRule((prev) => prev ? { ...prev, separator: trimmedValue } : null); + }, []); + const handleAddPart = useCallback(() => { if (!currentRule) return; @@ -372,7 +420,44 @@ export const NumberingRuleDesigner: React.FC = ({ - {/* 두 번째 줄: 자동 감지된 테이블 정보 표시 */} + {/* 두 번째 줄: 구분자 설정 */} +
+
+ + +
+ {separatorType === "custom" && ( +
+ + handleCustomSeparatorChange(e.target.value)} + className="h-9" + placeholder="최대 2자" + maxLength={2} + /> +
+ )} +

+ 규칙 사이에 들어갈 문자입니다 +

+
+ + {/* 세 번째 줄: 자동 감지된 테이블 정보 표시 */} {currentTableName && (
diff --git a/frontend/types/numbering-rule.ts b/frontend/types/numbering-rule.ts index 9cd81bdb..c44e2354 100644 --- a/frontend/types/numbering-rule.ts +++ b/frontend/types/numbering-rule.ts @@ -123,3 +123,24 @@ export const RESET_PERIOD_OPTIONS: Array<{ { value: "monthly", label: "월별 초기화" }, { value: "yearly", label: "연별 초기화" }, ]; + +/** + * 구분자 옵션 + * - 규칙과 규칙 사이에 들어가는 문자 + * - "none"은 구분자 없음 + * - "custom"은 직접 입력 (최대 2자) + */ +export type SeparatorType = "none" | "-" | "_" | "." | "/" | "custom"; + +export const SEPARATOR_OPTIONS: Array<{ + value: SeparatorType; + label: string; + displayValue: string; +}> = [ + { value: "none", label: "없음", displayValue: "" }, + { value: "-", label: "하이픈 (-)", displayValue: "-" }, + { value: "_", label: "언더스코어 (_)", displayValue: "_" }, + { value: ".", label: "점 (.)", displayValue: "." }, + { value: "/", label: "슬래시 (/)", displayValue: "/" }, + { value: "custom", label: "직접입력", displayValue: "" }, +];