공통코드 관리 시스템 개선 완료

This commit is contained in:
hyeonsu
2025-09-03 11:20:43 +09:00
parent 14eb0b62e7
commit 63c7b80391
12 changed files with 665 additions and 41 deletions

View File

@@ -1,6 +1,6 @@
"use client";
import { useEffect } from "react";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
@@ -11,7 +11,9 @@ import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import { LoadingSpinner } from "@/components/common/LoadingSpinner";
import { ValidationMessage } from "@/components/common/ValidationMessage";
import { useCodes, useCreateCode, useUpdateCode } from "@/hooks/queries/useCodes";
import { useCheckCodeDuplicate } from "@/hooks/queries/useValidation";
import { createCodeSchema, updateCodeSchema, type CreateCodeData, type UpdateCodeData } from "@/lib/schemas/commonCode";
import type { CodeInfo } from "@/types/commonCode";
import type { FieldError } from "react-hook-form";
@@ -37,6 +39,47 @@ export function CodeFormModal({ isOpen, onClose, categoryCode, editingCode }: Co
const isEditing = !!editingCode;
// 검증 상태 관리
const [validationStates, setValidationStates] = useState({
codeValue: { enabled: false, value: "" },
codeName: { enabled: false, value: "" },
codeNameEng: { enabled: false, value: "" },
});
// 중복 검사 훅들
const codeValueCheck = useCheckCodeDuplicate(
categoryCode,
"codeValue",
validationStates.codeValue.value,
isEditing ? editingCode?.code_value : undefined,
validationStates.codeValue.enabled,
);
const codeNameCheck = useCheckCodeDuplicate(
categoryCode,
"codeName",
validationStates.codeName.value,
isEditing ? editingCode?.code_value : undefined,
validationStates.codeName.enabled,
);
const codeNameEngCheck = useCheckCodeDuplicate(
categoryCode,
"codeNameEng",
validationStates.codeNameEng.value,
isEditing ? editingCode?.code_value : undefined,
validationStates.codeNameEng.enabled,
);
// 중복 검사 결과 확인
const hasDuplicateErrors =
(codeValueCheck.data?.isDuplicate && validationStates.codeValue.enabled) ||
(codeNameCheck.data?.isDuplicate && validationStates.codeName.enabled) ||
(codeNameEngCheck.data?.isDuplicate && validationStates.codeNameEng.enabled);
// 중복 검사 로딩 중인지 확인
const isDuplicateChecking = codeValueCheck.isLoading || codeNameCheck.isLoading || codeNameEngCheck.isLoading;
// 폼 스키마 선택 (생성/수정에 따라)
const schema = isEditing ? updateCodeSchema : createCodeSchema;
@@ -126,10 +169,26 @@ export function CodeFormModal({ isOpen, onClose, categoryCode, editingCode }: Co
disabled={isLoading || isEditing} // 수정 시에는 비활성화
placeholder="코드값을 입력하세요"
className={(form.formState.errors as any)?.codeValue ? "border-red-500" : ""}
onBlur={(e) => {
const value = e.target.value.trim();
if (value && !isEditing) {
setValidationStates((prev) => ({
...prev,
codeValue: { enabled: true, value },
}));
}
}}
/>
{(form.formState.errors as any)?.codeValue && (
<p className="text-sm text-red-600">{getErrorMessage((form.formState.errors as any)?.codeValue)}</p>
)}
{!isEditing && !(form.formState.errors as any)?.codeValue && (
<ValidationMessage
message={codeValueCheck.data?.message}
isValid={!codeValueCheck.data?.isDuplicate}
isLoading={codeValueCheck.isLoading}
/>
)}
</div>
{/* 코드명 */}
@@ -141,10 +200,26 @@ export function CodeFormModal({ isOpen, onClose, categoryCode, editingCode }: Co
disabled={isLoading}
placeholder="코드명을 입력하세요"
className={form.formState.errors.codeName ? "border-red-500" : ""}
onBlur={(e) => {
const value = e.target.value.trim();
if (value) {
setValidationStates((prev) => ({
...prev,
codeName: { enabled: true, value },
}));
}
}}
/>
{form.formState.errors.codeName && (
<p className="text-sm text-red-600">{getErrorMessage(form.formState.errors.codeName)}</p>
)}
{!form.formState.errors.codeName && (
<ValidationMessage
message={codeNameCheck.data?.message}
isValid={!codeNameCheck.data?.isDuplicate}
isLoading={codeNameCheck.isLoading}
/>
)}
</div>
{/* 영문명 */}
@@ -156,10 +231,26 @@ export function CodeFormModal({ isOpen, onClose, categoryCode, editingCode }: Co
disabled={isLoading}
placeholder="코드 영문명을 입력하세요"
className={form.formState.errors.codeNameEng ? "border-red-500" : ""}
onBlur={(e) => {
const value = e.target.value.trim();
if (value) {
setValidationStates((prev) => ({
...prev,
codeNameEng: { enabled: true, value },
}));
}
}}
/>
{form.formState.errors.codeNameEng && (
<p className="text-sm text-red-600">{getErrorMessage(form.formState.errors.codeNameEng)}</p>
)}
{!form.formState.errors.codeNameEng && (
<ValidationMessage
message={codeNameEngCheck.data?.message}
isValid={!codeNameEngCheck.data?.isDuplicate}
isLoading={codeNameEngCheck.isLoading}
/>
)}
</div>
{/* 설명 */}
@@ -212,7 +303,10 @@ export function CodeFormModal({ isOpen, onClose, categoryCode, editingCode }: Co
<Button type="button" variant="outline" onClick={onClose} disabled={isLoading}>
</Button>
<Button type="submit" disabled={isLoading || !form.formState.isValid}>
<Button
type="submit"
disabled={isLoading || !form.formState.isValid || hasDuplicateErrors || isDuplicateChecking}
>
{isLoading ? (
<>
<LoadingSpinner size="sm" className="mr-2" />