diff --git a/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/page.tsx b/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/page.tsx index 8d7e32c66..0c3ad9dce 100644 --- a/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/page.tsx @@ -70,6 +70,8 @@ export default function PublicReuseFaciltyInsert() { // defaultValues: { items: pbnstRegArrayZod.parse([]) }, mode: "onChange", }); + const { isDirty } = form.formState; + const { fields: items, append, @@ -87,7 +89,11 @@ export default function PublicReuseFaciltyInsert() { }, [pbnst.isInit, pubHasuInit]); const onSubmit = async (valuse: { items: PbnstRegArrrayType }) => { - const data = writeRgtrAndMdfr(valuse.items); + + if (!isDirty) { + toast.error("변경사항이 없습니다."); // 변경사항이 없으면 메시지 표시 + return; + } const data = writeRgtrAndMdfr(valuse.items); let bizs = [] as fcBizType[]; data.forEach((fclt) => { bizs = [...bizs, ...fclt.fcBizs]; @@ -110,78 +116,58 @@ export default function PublicReuseFaciltyInsert() { }; // 폼 유효성 검사 실패 시 호출될 함수 - const onInvalid = ( - errors: FieldErrors<{ items: z.infer[] }> - ) => { - // 재귀 함수를 사용해 중첩된 에러 객체에서 모든 에러 메시지와 경로를 찾습니다. + const onInvalid = (errors: FieldErrors<{ items: z.infer[] }>) => { + console.log("errors:", errors); + const findAllErrors = ( errorObject: any, path: (string | number)[] = [] ): { message: string; path: (string | number)[] }[] => { if (!errorObject) return []; - - // Zod에서 배열 에러는 바로 배열로 전달됨 (예: items: [ {}, {...}, ... ]) - if (Array.isArray(errorObject)) { - return errorObject.flatMap((entry, index) => - findAllErrors(entry, [...path, index]) - ); - } - - if (typeof errorObject === "object") { - const entries: { message: string; path: (string | number)[] }[] = []; - - if (typeof errorObject.message === "string") { - entries.push({ message: errorObject.message, path }); - } - - if (Array.isArray(errorObject._errors)) { - for (const msg of errorObject._errors) { - entries.push({ message: msg, path }); + + return Object.keys(errorObject).flatMap((key) => { + const value = errorObject[key]; + const currentKey = !isNaN(parseInt(key)) ? parseInt(key) : key; + const newPath = [...path, currentKey]; + + if (value && typeof value === "object") { + if (value.message) { + return [{ message: value.message, path: newPath }]; } + + return findAllErrors(value, newPath); } - - const keys = Object.keys(errorObject).filter( - (k) => k !== "message" && k !== "_errors" - ); - - for (const key of keys) { - entries.push(...findAllErrors(errorObject[key], [...path, key])); - } - - return entries; - } - - return []; + return []; + }); }; + const errorList = findAllErrors(errors); - - console.log(' errors ', errors) + if (errorList.length > 0) { errorList.forEach((errorInfo) => { const { message, path } = errorInfo; let prefix = ""; + const itemsIndex = path.indexOf("items"); - + if (itemsIndex > -1 && path.length > itemsIndex + 1) { const itemIdx = path[itemsIndex + 1] as number; - const facilityName = form.getValues( - `items.${itemIdx}.ruseUtztnFcltNm` - ); + const facilityName = form.getValues(`items.${itemIdx}.ruseUtztnFcltNm`); if (facilityName) { prefix += `[${facilityName}] `; } - + const fcBizsIndex = path.indexOf("fcBizs"); if (fcBizsIndex > -1 && path.length > fcBizsIndex + 1) { const bizIdx = path[fcBizsIndex + 1] as number; - const cycle = form.getValues( - `items.${itemIdx}.fcBizs.${bizIdx}.cycl` - ); + const cycle = form.getValues(`items.${itemIdx}.fcBizs.${bizIdx}.cycl`); if (cycle) { prefix += `[${cycle}차수] `; } } } + + // 최종 오류 메시지 출력 toast.error(`${prefix}${message}`); }); } @@ -214,7 +200,14 @@ export default function PublicReuseFaciltyInsert() { useEffect(() => { if (pbnst.pbnstRes && pbnst.pbnstRes?.length > 0) { - form.reset({ items: pbnstRegArrayZod.parse(pbnst.pbnstRes) }); + // form.reset({ + // items: pbnstRegArrayZod.parse(pbnst.pbnstRes), + // }); + + form.reset({ items: pbnst.pbnstRes }); + + //form.reset({ items: pbnst.pbnstRes }); + } else { form.reset({ items: [] }); } @@ -249,7 +242,7 @@ export default function PublicReuseFaciltyInsert() { // ] as fcBizType[], // }) // ); - append(createDefaultPbnstItem(selecTableRow, pbnstRes.length)); + append(createDefaultPbnstItem(selecTableRow, pbnstRes.length)); setIsRuseReg({ isModal: true }); } @@ -428,7 +421,7 @@ export default function PublicReuseFaciltyInsert() { form={form} // form prop 전달 setPbnstInsert={(data) => { if (data) { - // pbnstInsert(data); // pbnstInsert 함수 호출 + pbnstInsert(data); // pbnstInsert 함수 호출 setIsRuseReg({ isModal: false }); } }} diff --git a/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/utilsZod.tsx b/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/utilsZod.tsx index 14224fce2..3433a62c5 100644 --- a/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/utilsZod.tsx +++ b/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/utilsZod.tsx @@ -10,12 +10,12 @@ export function createDefaultPbnstItem( pbnstRuseFcltPk: pk, swtrmtFcltFk: "", ruseUtztnFcltNm: "", // 필수 입력이므로 빈 문자열로 - fcltCpct: 0, - ruseCpct: 0, - splyExtraCpct: 0, + fcltCpct: 0, + ruseCpct: 0, + splyExtraCpct: 0, regDt: null, rgtr: "test", - mdfcnDt: null, + mdfcnDt: null, mdfr: "test", fcFiles: [], fcBizs: [ diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx index a111b6c10..2ef1c6d2f 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx @@ -238,22 +238,23 @@ export const pbnstRegZod = z.object({ swtrmtFcltFk: z.string().default(""), ruseUtztnFcltNm: z .preprocess( - (v) => (v != null ? String(v).trim() : ""), - z.string() - ) - .refine((val) => val.length > 0, { - message: "시설 이름을 입력하세요", - }), - fcltCpct: z.number(), - ruseCpct: z.number(), - splyExtraCpct: z.number(), + (v) => (v !== null && v !== undefined ? String(v).trim() : ""), // null/undefined → "", 공백 제거 + z.string().min(1, "시설 이름을 입력하세요")), + fcltCpct: zNumDefaultZero, + ruseCpct: zNumDefaultZero, + splyExtraCpct: zNumDefaultZero, regDt: zDateDefaultNow, rgtr: z.string().default("test"), mdfcnDt: zDateDefaultNow, mdfr: z.string().default("test"), fcFiles: z.array(fcFileSchema).default([]).nullish(), fcBizs: z.array(fcBizSchema).default([]), - fcOpers: z.array(fcOperSchema).default([]).nullish(), + fcOpers: z + .array(fcOperSchema) + .refine((val) => val.length >= 1, { + message: "재이용시설의 운영정보를 최소 하나를 등록해주세요", + }) + .default([]), // 기본값 설정 }); export const pbnstRegArrayZod = z.array(pbnstRegZod); diff --git a/apps/wr/components/ui/modal/fcltReg/pbnstRegModal/pbnstRegModal.tsx b/apps/wr/components/ui/modal/fcltReg/pbnstRegModal/pbnstRegModal.tsx index a7987577b..34bc71a46 100644 --- a/apps/wr/components/ui/modal/fcltReg/pbnstRegModal/pbnstRegModal.tsx +++ b/apps/wr/components/ui/modal/fcltReg/pbnstRegModal/pbnstRegModal.tsx @@ -42,6 +42,8 @@ export function PbnstRegModal({ const [currentTab, setCurrentTab] = useState("mng"); const [indexMng, setIndexMng] = useState(0); const [indexBiz, setIndexBiz] = useState(0); + + const onSubmit = async (valuse: { items: PbnstRegArrrayType }) => { const item = valuse.items[indexMng]; const data = item ? writeRgtrAndMdfr([item]) : []; @@ -53,6 +55,8 @@ export function PbnstRegModal({ errors: FieldErrors<{ items: z.infer[] }> ) => { // 재귀 함수를 사용해 중첩된 에러 객체에서 모든 에러 메시지와 경로를 찾습니다. + + const findAllErrors = ( errorObject: any, path: (string | number)[] = [] @@ -72,13 +76,18 @@ export function PbnstRegModal({ return []; }); }; + + const errorList = findAllErrors(errors); + + if (errorList.length > 0) { errorList.forEach((errorInfo) => { const { message, path } = errorInfo; let prefix = ""; const itemsIndex = path.indexOf("items"); + if (itemsIndex > -1 && path.length > itemsIndex + 1) { const itemIdx = path[itemsIndex + 1] as number; const facilityName = form.getValues( @@ -99,6 +108,8 @@ export function PbnstRegModal({ } } } + + toast.error(`${prefix}${message}`); }); }