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: "" }, +];