Files
frontend/packages/common/business_components/src/ui/sdmInsertForm/index.tsx
T
2026-07-06 17:37:28 +09:00

204 lines
7.2 KiB
TypeScript

"use client";
import { SdmRegForm, type DemandCompType } from "./form";
import { Button } from "@common/components/ui";
import { zodResolver } from "@hookform/resolvers/zod";
import { useCallback, useEffect, useState } from "react";
import { FormProvider, useForm, type SubmitHandler } from "react-hook-form";
import { toast, Toaster } from "sonner";
import * as z from "zod";
import type { SelectDataType } from "../search_input_select";
import { getCookie } from "@common/components/lib";
type thisProps = {
selectSidoData: SelectDataType[];
selectSigunData: SelectDataType[];
dataList: DemandCompType[];
rtnValue: (searchText: string, pageCnt: number) => void;
rtnInputData: (data: DemandCompType) => void;
bodyClassNm?: string;
updateList?:DemandCompType;
readOnly?:boolean;
openNetwork:boolean;
}
const createFormSchema = (isBznmTotNoDisabled: boolean, isDuplicate: boolean ,updateList?:DemandCompType) => z.object({
ctpvCd: z.string().min(1, "시/도를 선택해주세요"),
sggCd: z.string().min(1, "시/군/구를 선택해주세요"),
dmdCoNm: z.string()
.min(1, "회사명을 입력해주세요")
.max(20, "회사명은 20자 이내로 입력해주세요"),
dmdInfoId: z.string()
.min(1, "사업자등록번호를 입력해주세요")
.regex(/^\d{10}$/, "사업자등록번호는 10자리 숫자만 입력 가능합니다")
.refine(() => isBznmTotNoDisabled ? !isDuplicate : true, "이미 등록된 사업자등록번호입니다"),
zip: z.string().optional(),
bznmTotNo: isBznmTotNoDisabled
? z.string().optional()
: z.string()
.length(4, "종사업자등록번호는 4자리 숫자만 입력 가능합니다")
.refine(() => !isDuplicate, "이미 등록된 사업자등록번호입니다"),
daddr: z.string()
.min(1, "주소를 입력해주세요")
// .min(6, "주소는 6자 이상 입력해주세요")
.max(40, "주소는 40자 이내로 입력해주세요"),
daddr2: z.string().optional(),
telno: z.string()
.min(8, "전화번호는 8자 이상 입력해주세요")
.max(11, "전화번호는 11자 이내로 입력해주세요")
.regex(/^[0-9]+$/, "전화번호는 숫자만 입력 가능합니다"),
rgtr: z.string().optional(),
mdfr: z.string().nullish(),
dmdAplyPswd : updateList?.dmdInfoId // 업데이트일경우
? z.string().optional() // 패스워드는 선택 사항이며 길이 제한 없음
: z.string().optional()
.refine((val) => !val || (val.length >= 8 && val.length <= 16), "패스워드는 8자 이상 16자 이내로 입력해주세요"),
dmdAplyPswdConfirm: updateList?.dmdInfoId // 업데이트일경우
? z.string().optional() // 패스워드는 선택 사항이며 길이 제한 없음
:z.string()
.min(1, "패스워드확인을 입력해주세요"),
}).refine((data) => {
// 패스워드 확인 검증
if (data.dmdAplyPswd && data.dmdAplyPswdConfirm) {
return data.dmdAplyPswd === data.dmdAplyPswdConfirm;
}
return true;
}, {
message: "패스워드가 일치하지 않습니다",
path: ["dmdAplyPswdConfirm"], // 에러를 패스워드 확인 필드에 표시
});
type FormSchema = z.infer<ReturnType<typeof createFormSchema>>;
const defaultValues: FormSchema = {
ctpvCd: '',
sggCd: '',
dmdCoNm: '',
dmdInfoId: '',
zip: '',
bznmTotNo: '',
daddr: '',
daddr2: '',
telno: '',
rgtr: '',
mdfr: '',
dmdAplyPswd: '',
dmdAplyPswdConfirm: '',
};
/**
* 수요처 등록 폼
* @param selectSidoData 시/도 데이터
* @param selectSigunData 시/군/구 데이터
* @param dataList 수요처 목록
* @param rtnValue 검색 결과(텍스트) 콜백
* @param rtnInputData 수요처관리 콜백 : 등록/수정 처리
* @returns
*/
export default function SdmInsertForm({selectSidoData, selectSigunData, dataList, rtnValue, rtnInputData
, bodyClassNm, updateList, readOnly, openNetwork}: thisProps) {
const [isBznmTotNoDisabled, setIsBznmTotNoDisabled] = useState(false); // 종사업자등록번호 해당없음
const [isDuplicate, setIsDuplicate] = useState(false);
const formSchema = createFormSchema(isBznmTotNoDisabled, isDuplicate, updateList );
const form = useForm<FormSchema>({
resolver: zodResolver(formSchema),
defaultValues,
mode: "onChange",
criteriaMode: "all",
shouldFocusError: false,
shouldUnregister: false
});
// 체크박스 상태가 변경될 때마다 bznmTotNo 필드의 에러를 초기화
useEffect(() => {
if (isBznmTotNoDisabled===true) {
form.clearErrors('bznmTotNo');
form.setValue('bznmTotNo', '');
}
}, [isBznmTotNoDisabled, form]);
const setRtnValue = useCallback((searchText: string, pageCnt: number) => {
rtnValue(searchText, pageCnt);
}, [rtnValue]);
const onSubmit: SubmitHandler<FormSchema> = async (data) => {
try {
// form 에러 체크
const formErrors = form.formState.errors;
const myUUID = getCookie('token-id') ||'c475824c-0e82-4a06-a282-2b55a20df265';
if (Object.keys(formErrors).length > 0 ) {
const errorMessage = Object.values(formErrors)[0]?.message || '입력값을 확인해주세요.';
toast.error(errorMessage);
return;
}
const dmdInfoId = data.dmdInfoId + (data.bznmTotNo || '0000');
const formData = {
...data,
dmdCoSn: updateList?.dmdCoSn ?? "",
dmdInfoId,
bzmnNo: data.dmdInfoId,
daddr: data.daddr?.trim() || "",
daddr2: data.daddr2?.trim() || "",
rgtr: myUUID ,
};
/* await insertSdmData(formData); */
rtnInputData(formData as unknown as DemandCompType); // 수요처 등록/수정 처리
//router.push(`/pages/sdmMng/sdmInfoInsert?${queryParams.toString()}`);
} catch (error) {
console.error('Error submitting form:', error);
}
};
return (
<>
<div className="mb-8">
<h2 className="px-[1.8rem] pt-[2rem] text-[2.4rem] font-semibold text-title">
{!updateList ? '수요처 등록' : readOnly == true ? '수요처 상세정보' : '수요처 수정'}
</h2>
</div>
<div className= {bodyClassNm?bodyClassNm:"!max-w-3xl mx-auto bg-white rounded-lg shadow-md p-6"}>
<FormProvider {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
<SdmRegForm
form={form}
onCheckboxChange={setIsBznmTotNoDisabled}
selectSidoData={selectSidoData}
selectSigunData={selectSigunData}
dataList={dataList}
rtnValue={setRtnValue}
setIsDuplicate={setIsDuplicate}
updateList={updateList}
readOnly={readOnly}
openNetwork={openNetwork}
/>
<div className="flex justify-center pt-4">
{readOnly==true?<>
</>:
<Button
type="submit"
className="w-32 bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-4 rounded-md transition-colors duration-200"
>
{updateList ?'수정' :'등록'}
</Button>
}
</div>
</form>
</FormProvider>
</div>
<Toaster position="top-center" />
</>
);
}