173 lines
5.3 KiB
TypeScript
173 lines
5.3 KiB
TypeScript
import { useDmStore } from "@/app/store";
|
|
import type { DemandCompType } from "@/app/store/sdmMng";
|
|
import { BZNM_TOT_NO, FormField, FormUi } from "@common/business_components";
|
|
import { Button, Input } from "@common/components";
|
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
import { sha512 } from 'js-sha512';
|
|
import { useEffect, useState, useMemo } from "react";
|
|
import { FormProvider, useForm, type ControllerRenderProps } from "react-hook-form";
|
|
import * as z from "zod";
|
|
|
|
export function SdmLoginForm() {
|
|
const { actionLogin, initializeCommonData } = useDmStore((state) => state);
|
|
const [isBznmTotNoDisabled, setIsBznmTotNoDisabled] = useState(true);
|
|
|
|
const formatBusinessNumber = (value: string) => {
|
|
// 숫자만 추출
|
|
const digitsOnly = value.replace(/\D/g, "");
|
|
|
|
// 10자리까지만 처리
|
|
const limitedDigits = digitsOnly.slice(0, 10);
|
|
|
|
// 3-2-5 형식으로 포맷팅
|
|
if (limitedDigits.length <= 3) {
|
|
return limitedDigits;
|
|
} else if (limitedDigits.length <= 5) {
|
|
return `${limitedDigits.slice(0, 3)}-${limitedDigits.slice(3)}`;
|
|
} else {
|
|
return `${limitedDigits.slice(0, 3)}-${limitedDigits.slice(3, 5)}-${limitedDigits.slice(5)}`;
|
|
}
|
|
};
|
|
|
|
// 스키마를 useMemo로 최적화
|
|
const sdmLoginFormSchema = useMemo(() => z.object({
|
|
dmdInfoId: z.string()
|
|
.min(1, "사업자등록번호를 입력해주세요")
|
|
.regex(/^\d{10}$/, "사업자등록번호는 10자리 숫자만 입력 가능합니다"),
|
|
bznmTotNo: isBznmTotNoDisabled
|
|
? z.string().optional()
|
|
: z.string().length(4, "종사업자등록번호는 4자리 숫자만 입력 가능합니다"),
|
|
password: z.string()
|
|
.min(1, "비밀번호를 입력해주세요")
|
|
.min(8, "비밀번호는 8자 이상 입력해주세요")
|
|
.max(16, "비밀번호는 16자 이내로 입력해주세요"),
|
|
rgtr: z.string().optional(),
|
|
dmdAplyPswd: z.string().optional(),
|
|
}), [isBznmTotNoDisabled]);
|
|
|
|
type FormData = z.infer<typeof sdmLoginFormSchema>;
|
|
type FieldComponent = (field: ControllerRenderProps<FormData, keyof FormData>) => JSX.Element;
|
|
|
|
const formSchema = sdmLoginFormSchema;
|
|
|
|
useEffect(() => {
|
|
initializeCommonData();
|
|
}, [initializeCommonData]);
|
|
|
|
const defaultValues: FormData = {
|
|
dmdInfoId: '',
|
|
bznmTotNo: '',
|
|
password: '',
|
|
rgtr: '',
|
|
dmdAplyPswd: '',
|
|
};
|
|
|
|
const form = useForm<FormData>({
|
|
resolver: zodResolver(formSchema),
|
|
defaultValues,
|
|
mode: "onChange",
|
|
});
|
|
|
|
const handleCheckboxChange = (checked: boolean) => {
|
|
setIsBznmTotNoDisabled(checked);
|
|
};
|
|
|
|
const handleLogin = () => {
|
|
const data = form.getValues();
|
|
const passwordStr = sha512.hex(data.password)
|
|
data.dmdAplyPswd = passwordStr;
|
|
const param = {
|
|
dmdInfoId: data.dmdInfoId + (isBznmTotNoDisabled ? '0000' : data.bznmTotNo),
|
|
dmdAplyPswd: data.dmdAplyPswd,
|
|
}
|
|
actionLogin(param as unknown as DemandCompType);
|
|
};
|
|
|
|
const formFields: Array<{
|
|
name: keyof FormData;
|
|
label: string;
|
|
component: FieldComponent | undefined;
|
|
}> = [
|
|
{
|
|
name: "dmdInfoId",
|
|
label: "사업자등록번호",
|
|
component: (field) => (
|
|
<Input
|
|
placeholder="사업자등록번호를 입력하세요"
|
|
type="text"
|
|
className="!mt-5 !mb-5 !text-xl text-gray-600"
|
|
{...field}
|
|
value={formatBusinessNumber(field.value as string)}
|
|
onChange={(e) => {
|
|
const dmdId = e.target.value.replace(/\D/g, "").slice(0, 10);
|
|
field.onChange(dmdId);
|
|
}}
|
|
/>
|
|
)
|
|
},
|
|
{
|
|
name: "bznmTotNo",
|
|
label: BZNM_TOT_NO || "종사업자등록번호",
|
|
component: (field) => (
|
|
<FormUi
|
|
label="종사업자등록번호"
|
|
onCheckboxChange={handleCheckboxChange}
|
|
isDisabled={isBznmTotNoDisabled}
|
|
>
|
|
<Input
|
|
placeholder="여러사업장이 있을 경우 입력해주세요"
|
|
type="text"
|
|
className="!mt-5 !text-xl text-gray-600"
|
|
disabled={isBznmTotNoDisabled}
|
|
{...field}
|
|
/>
|
|
</FormUi>
|
|
)
|
|
},
|
|
{
|
|
name: "password",
|
|
label: "비밀번호",
|
|
component: (field) => (
|
|
<Input
|
|
placeholder="비밀번호를 입력하세요"
|
|
type="password"
|
|
className="!mt-5 !mb-5 !text-xl text-gray-600"
|
|
{...field}
|
|
/>
|
|
)
|
|
}
|
|
];
|
|
|
|
return (
|
|
<>
|
|
<div>
|
|
<FormProvider {...form}>
|
|
{formFields.map(({ name, label, component }) => (
|
|
<FormField
|
|
key={name}
|
|
control={form.control}
|
|
name={name}
|
|
render={({ field }) => (
|
|
label==='종사업자등록번호' ?
|
|
<>
|
|
{component && component(field)}
|
|
</>
|
|
: <FormUi label={label}>
|
|
{component && component(field)}
|
|
</FormUi>
|
|
)}
|
|
/>
|
|
))}
|
|
</FormProvider>
|
|
<div className="flex justify-center pt-4">
|
|
<Button
|
|
onClick={handleLogin}
|
|
className="w-32 bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-4 rounded-md transition-colors duration-200"
|
|
>
|
|
로그인
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
} |