777 lines
27 KiB
TypeScript
777 lines
27 KiB
TypeScript
"use client";
|
||
|
||
import React, { useState, useEffect } from "react";
|
||
import { SignupClient } from "@/shared/api/signup-client";
|
||
import { BASE_URL, ENDPOINT } from "@/shared/config";
|
||
import type { UserSaveData } from "@/entities/user";
|
||
import "./user-signup-modal.css";
|
||
|
||
interface UserSignupModalProps {
|
||
open: boolean;
|
||
onClose: () => void;
|
||
onSuccess: () => void;
|
||
}
|
||
|
||
interface UserSignupData {
|
||
userId: string;
|
||
userName: string;
|
||
email?: string;
|
||
password: string;
|
||
pswdHnt: string;
|
||
pswdAns?: string;
|
||
mphn?: string;
|
||
telno?: string;
|
||
zip?: string;
|
||
addr?: string;
|
||
daddr?: string;
|
||
laeSeCd: string;
|
||
ogdpSeCd: string;
|
||
instSeCd?: string;
|
||
dtlInstCd?: string;
|
||
enoCd?: string;
|
||
}
|
||
|
||
|
||
|
||
// 익명 사용자용 CodeSelect 컴포넌트
|
||
interface AnonymousCodeSelectProps {
|
||
upCd: string;
|
||
value: string;
|
||
onValueChange: (value: string) => void;
|
||
disabled?: boolean;
|
||
placeholder?: string;
|
||
}
|
||
|
||
function AnonymousCodeSelect({ upCd, value, onValueChange, disabled, placeholder = "선택" }: AnonymousCodeSelectProps) {
|
||
const [codes, setCodes] = useState<Array<{ lwpoCd: string; lwpoCdNm: string }>>([]);
|
||
const [isLoading, setIsLoading] = useState(false);
|
||
|
||
useEffect(() => {
|
||
const fetchCodes = async () => {
|
||
if (!upCd) return;
|
||
|
||
setIsLoading(true);
|
||
try {
|
||
const signupClient = SignupClient.getInstance({
|
||
baseURL: BASE_URL
|
||
});
|
||
|
||
const response = await signupClient.get(
|
||
`${ENDPOINT.CMS_SERVICE.CODE}/${upCd}`
|
||
);
|
||
|
||
if (response.data && Array.isArray(response.data)) {
|
||
setCodes(response.data);
|
||
} else {
|
||
setCodes([]);
|
||
}
|
||
} catch (error) {
|
||
console.error(`공통 코드 로드 실패 (${upCd}):`, error);
|
||
setCodes([]);
|
||
} finally {
|
||
setIsLoading(false);
|
||
}
|
||
};
|
||
|
||
fetchCodes();
|
||
}, [upCd]);
|
||
|
||
return (
|
||
<select
|
||
value={value}
|
||
onChange={(e) => onValueChange(e.target.value)}
|
||
disabled={disabled || isLoading}
|
||
className="user-signup-select"
|
||
>
|
||
<option value="">{isLoading ? "로딩 중..." : placeholder}</option>
|
||
{codes.map((code) => (
|
||
<option key={code.lwpoCd} value={code.lwpoCd}>
|
||
{code.lwpoCdNm}
|
||
</option>
|
||
))}
|
||
</select>
|
||
);
|
||
}
|
||
|
||
function UserSignupModal({ open, onClose, onSuccess }: UserSignupModalProps) {
|
||
const [currentStep, setCurrentStep] = useState<'agreement' | 'signup'>('agreement');
|
||
const [agreed, setAgreed] = useState(false);
|
||
const [formData, setFormData] = useState({
|
||
userId: "",
|
||
userName: "",
|
||
email: "",
|
||
password: "",
|
||
confirmPassword: "",
|
||
pswdHnt: "",
|
||
pswdAns: "",
|
||
mphn: "",
|
||
telno: "",
|
||
zip: "",
|
||
addr: "",
|
||
daddr: "",
|
||
laeSeCd: "",
|
||
ogdpSeCd: "",
|
||
instSeCd: "",
|
||
dtlInstCd: "",
|
||
enoCd: "",
|
||
});
|
||
|
||
const [errors, setErrors] = useState<Record<string, string>>({});
|
||
const [isLoading, setIsLoading] = useState(false);
|
||
const [isCheckingId, setIsCheckingId] = useState(false);
|
||
const [isCheckingEmail, setIsCheckingEmail] = useState(false);
|
||
const [idAvailable, setIdAvailable] = useState<boolean | null>(null);
|
||
const [emailAvailable, setEmailAvailable] = useState<boolean | null>(null);
|
||
|
||
// 모달이 닫힐 때 초기화
|
||
useEffect(() => {
|
||
if (!open) {
|
||
setCurrentStep('agreement');
|
||
setAgreed(false);
|
||
setFormData({
|
||
userId: "",
|
||
userName: "",
|
||
email: "",
|
||
password: "",
|
||
confirmPassword: "",
|
||
pswdHnt: "",
|
||
pswdAns: "",
|
||
mphn: "",
|
||
telno: "",
|
||
zip: "",
|
||
addr: "",
|
||
daddr: "",
|
||
laeSeCd: "",
|
||
ogdpSeCd: "",
|
||
instSeCd: "",
|
||
dtlInstCd: "",
|
||
enoCd: "",
|
||
});
|
||
setErrors({});
|
||
setIdAvailable(null);
|
||
setEmailAvailable(null);
|
||
}
|
||
}, [open]);
|
||
|
||
const handleAgreementChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||
setAgreed(e.target.checked);
|
||
};
|
||
|
||
const handleNextStep = () => {
|
||
if (agreed) {
|
||
setCurrentStep('signup');
|
||
}
|
||
};
|
||
|
||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
|
||
const { name, value } = e.target;
|
||
setFormData(prev => ({ ...prev, [name]: value }));
|
||
|
||
// 에러 초기화
|
||
if (errors[name]) {
|
||
setErrors(prev => ({ ...prev, [name]: "" }));
|
||
}
|
||
};
|
||
|
||
const validateForm = () => {
|
||
const newErrors: Record<string, string> = {};
|
||
|
||
console.log("폼 검증 시작:", formData);
|
||
|
||
// 필수 필드 검증
|
||
if (!formData.userId) newErrors.userId = "아이디를 입력해주세요.";
|
||
if (!formData.userName) newErrors.userName = "이름을 입력해주세요.";
|
||
if (!formData.password) newErrors.password = "비밀번호를 입력해주세요.";
|
||
if (!formData.confirmPassword) newErrors.confirmPassword = "비밀번호 확인을 입력해주세요.";
|
||
if (!formData.pswdHnt) newErrors.pswdHnt = "비밀번호 힌트를 선택해주세요.";
|
||
if (!formData.laeSeCd) newErrors.laeSeCd = "법인구분을 선택해주세요.";
|
||
if (!formData.ogdpSeCd) newErrors.ogdpSeCd = "기관구분을 선택해주세요.";
|
||
|
||
// 비밀번호 확인
|
||
if (formData.password && formData.confirmPassword && formData.password !== formData.confirmPassword) {
|
||
newErrors.confirmPassword = "비밀번호가 일치하지 않습니다.";
|
||
}
|
||
|
||
// 비밀번호 정규식 검증
|
||
const passwordRegex = /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]).{8,20}$/;
|
||
if (formData.password && !passwordRegex.test(formData.password)) {
|
||
newErrors.password = "비밀번호는 8~20자, 영문/숫자/특수기호를 모두 포함해야 합니다.";
|
||
}
|
||
|
||
// 이메일 형식 검증
|
||
if (formData.email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
|
||
newErrors.email = "올바른 이메일 형식을 입력해주세요.";
|
||
}
|
||
|
||
// 중복 체크 검증
|
||
if (idAvailable === false) newErrors.userId = "이미 사용 중인 아이디입니다.";
|
||
if (emailAvailable === false) newErrors.email = "이미 사용 중인 이메일입니다.";
|
||
|
||
setErrors(newErrors);
|
||
const isValid = Object.keys(newErrors).length === 0;
|
||
console.log("폼 검증 결과:", { isValid, errors: newErrors, formData });
|
||
return isValid;
|
||
};
|
||
|
||
const checkUserIdDuplicate = async () => {
|
||
if (!formData.userId) {
|
||
setErrors(prev => ({ ...prev, userId: "아이디를 입력해주세요." }));
|
||
return;
|
||
}
|
||
|
||
setIsCheckingId(true);
|
||
try {
|
||
const signupClient = SignupClient.getInstance({
|
||
baseURL: BASE_URL,
|
||
});
|
||
const response = await signupClient.post<boolean>(
|
||
`${ENDPOINT.USER_SERVICE.USERS}/existsUserId`,
|
||
{ userId: formData.userId }
|
||
);
|
||
|
||
const exists = response.data;
|
||
setIdAvailable(!exists);
|
||
if (exists) {
|
||
setErrors(prev => ({ ...prev, userId: "이미 사용 중인 아이디입니다." }));
|
||
} else {
|
||
setErrors(prev => ({ ...prev, userId: "" }));
|
||
}
|
||
} catch (error) {
|
||
console.error("아이디 중복 체크 오류:", error);
|
||
setErrors(prev => ({ ...prev, userId: "아이디 중복 체크 중 오류가 발생했습니다." }));
|
||
} finally {
|
||
setIsCheckingId(false);
|
||
}
|
||
};
|
||
|
||
const checkEmailDuplicate = async () => {
|
||
if (!formData.email) {
|
||
setErrors(prev => ({ ...prev, email: "이메일을 입력해주세요." }));
|
||
return;
|
||
}
|
||
|
||
setIsCheckingEmail(true);
|
||
try {
|
||
const signupClient = SignupClient.getInstance({
|
||
baseURL: BASE_URL,
|
||
});
|
||
const response = await signupClient.post<boolean>(
|
||
`${ENDPOINT.USER_SERVICE.USERS}/exists`,
|
||
{ email: formData.email }
|
||
);
|
||
|
||
const exists = response.data;
|
||
setEmailAvailable(!exists);
|
||
if (exists) {
|
||
setErrors(prev => ({ ...prev, email: "이미 사용 중인 이메일입니다." }));
|
||
} else {
|
||
setErrors(prev => ({ ...prev, email: "" }));
|
||
}
|
||
} catch (error) {
|
||
console.error("이메일 중복 체크 오류:", error);
|
||
setErrors(prev => ({ ...prev, email: "이메일 중복 체크 중 오류가 발생했습니다." }));
|
||
} finally {
|
||
setIsCheckingEmail(false);
|
||
}
|
||
};
|
||
|
||
const handleSubmit = async (e: React.FormEvent) => {
|
||
e.preventDefault();
|
||
console.log("회원가입 버튼 클릭됨 - handleSubmit");
|
||
console.log("현재 폼 데이터:", formData);
|
||
|
||
if (!validateForm()) {
|
||
console.log("폼 검증 실패");
|
||
return;
|
||
}
|
||
|
||
console.log("폼 검증 성공, 회원가입 API 호출 시작");
|
||
setIsLoading(true);
|
||
try {
|
||
const signupData: UserSignupData = {
|
||
userId: formData.userId,
|
||
userName: formData.userName,
|
||
email: formData.email || undefined,
|
||
password: formData.password,
|
||
pswdHnt: formData.pswdHnt,
|
||
pswdAns: formData.pswdAns || undefined,
|
||
mphn: formData.mphn || undefined,
|
||
telno: formData.telno || undefined,
|
||
zip: formData.zip || undefined,
|
||
addr: formData.addr || undefined,
|
||
daddr: formData.daddr || undefined,
|
||
laeSeCd: formData.laeSeCd,
|
||
ogdpSeCd: formData.ogdpSeCd,
|
||
instSeCd: formData.instSeCd || undefined,
|
||
dtlInstCd: formData.dtlInstCd || undefined,
|
||
enoCd: formData.enoCd || undefined,
|
||
};
|
||
|
||
// SignupClient를 통해 익명사용자 회원가입 API 호출
|
||
console.log("SignupClient 생성 및 API 호출:", {
|
||
baseURL: BASE_URL,
|
||
endpoint: ENDPOINT.USER_SERVICE.USER_JOIN,
|
||
data: signupData
|
||
});
|
||
|
||
const signupClient = SignupClient.getInstance({
|
||
baseURL: BASE_URL
|
||
});
|
||
const response = await signupClient.post(
|
||
ENDPOINT.USER_SERVICE.USER_JOIN,
|
||
signupData
|
||
);
|
||
|
||
console.log("회원가입 성공:", response.data);
|
||
|
||
// 성공 시 모달 닫기 및 콜백 호출
|
||
onSuccess();
|
||
onClose();
|
||
|
||
// 폼 초기화
|
||
setFormData({
|
||
userId: "",
|
||
userName: "",
|
||
email: "",
|
||
password: "",
|
||
confirmPassword: "",
|
||
pswdHnt: "",
|
||
pswdAns: "",
|
||
mphn: "",
|
||
telno: "",
|
||
zip: "",
|
||
addr: "",
|
||
daddr: "",
|
||
laeSeCd: "",
|
||
ogdpSeCd: "",
|
||
instSeCd: "",
|
||
dtlInstCd: "",
|
||
enoCd: "",
|
||
});
|
||
setErrors({});
|
||
setIdAvailable(null);
|
||
setEmailAvailable(null);
|
||
|
||
} catch (error: unknown) {
|
||
console.error("회원가입 오류:", error);
|
||
if (error instanceof Error) {
|
||
setErrors(prev => ({ ...prev, submit: error.message }));
|
||
} else {
|
||
setErrors(prev => ({ ...prev, submit: "회원가입에 실패했습니다." }));
|
||
}
|
||
} finally {
|
||
setIsLoading(false);
|
||
}
|
||
};
|
||
|
||
if (!open) return null;
|
||
|
||
return (
|
||
<div className="user-signup-modal-overlay">
|
||
<div className="user-signup-modal-content">
|
||
<div className="user-signup-modal-header">
|
||
<h2>{currentStep === 'agreement' ? '개인정보제공동의' : '회원가입'}</h2>
|
||
<button className="user-signup-close-button" onClick={onClose}>×</button>
|
||
</div>
|
||
|
||
{currentStep === 'agreement' ? (
|
||
<div className="user-signup-agreement-content">
|
||
<div className="user-signup-agreement-text">
|
||
<h3>개인정보 수집 및 이용 동의</h3>
|
||
<p>회원가입을 위해 다음과 같이 개인정보를 수집 및 이용합니다.</p>
|
||
|
||
<h4>1. 수집하는 개인정보 항목</h4>
|
||
<ul>
|
||
<li>필수항목: 아이디, 이름, 비밀번호, 비밀번호 힌트, 법인구분, 기관구분</li>
|
||
<li>선택항목: 이메일, 휴대폰번호, 전화번호, 주소, 기관코드, 상세기관코드, 사업자등록번호</li>
|
||
</ul>
|
||
|
||
<h4>2. 개인정보의 수집 및 이용목적</h4>
|
||
<ul>
|
||
<li>회원가입 및 관리</li>
|
||
<li>서비스 제공 및 운영</li>
|
||
<li>고객상담 및 문의응답</li>
|
||
</ul>
|
||
|
||
<h4>3. 개인정보의 보유 및 이용기간</h4>
|
||
<p>회원탈퇴 시까지 (단, 관련 법령에 따라 보존이 필요한 경우 해당 기간까지)</p>
|
||
|
||
<h4>4. 동의 거부권 및 거부 시 불이익</h4>
|
||
<p>개인정보 수집 및 이용에 대한 동의를 거부할 수 있으며, 동의 거부 시 회원가입이 제한됩니다.</p>
|
||
</div>
|
||
|
||
<div className="user-signup-agreement-checkbox">
|
||
<label>
|
||
<input
|
||
type="checkbox"
|
||
checked={agreed}
|
||
onChange={handleAgreementChange}
|
||
/>
|
||
<span>개인정보 수집 및 이용에 동의합니다.</span>
|
||
</label>
|
||
</div>
|
||
|
||
<div className="user-signup-agreement-actions">
|
||
<button
|
||
type="button"
|
||
onClick={onClose}
|
||
className="user-signup-cancel-button"
|
||
>
|
||
취소
|
||
</button>
|
||
<button
|
||
type="button"
|
||
onClick={handleNextStep}
|
||
className="user-signup-next-button"
|
||
disabled={!agreed}
|
||
>
|
||
다음
|
||
</button>
|
||
</div>
|
||
</div>
|
||
) : (
|
||
<form onSubmit={handleSubmit} className="user-signup-form">
|
||
<div className="user-signup-form-section">
|
||
<h3>기본 정보</h3>
|
||
|
||
<div className="user-signup-form-row">
|
||
<div className="user-signup-form-group">
|
||
<label htmlFor="userId">아이디 *</label>
|
||
<div className="user-signup-input-with-button">
|
||
<input
|
||
type="text"
|
||
id="userId"
|
||
name="userId"
|
||
value={formData.userId}
|
||
onChange={handleInputChange}
|
||
placeholder="아이디를 입력하세요"
|
||
maxLength={12}
|
||
disabled={isLoading}
|
||
/>
|
||
<button
|
||
type="button"
|
||
onClick={checkUserIdDuplicate}
|
||
disabled={isCheckingId || isLoading || !formData.userId}
|
||
className="user-signup-check-button"
|
||
>
|
||
{isCheckingId ? "확인중..." : "중복확인"}
|
||
</button>
|
||
</div>
|
||
{idAvailable === true && <span className="user-signup-success-message">사용 가능한 아이디입니다.</span>}
|
||
{errors.userId && <span className="user-signup-error-message">{errors.userId}</span>}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="user-signup-form-row">
|
||
<div className="user-signup-form-group">
|
||
<label htmlFor="userName">이름 *</label>
|
||
<input
|
||
type="text"
|
||
id="userName"
|
||
name="userName"
|
||
value={formData.userName}
|
||
onChange={handleInputChange}
|
||
placeholder="이름을 입력하세요"
|
||
disabled={isLoading}
|
||
/>
|
||
{errors.userName && <span className="user-signup-error-message">{errors.userName}</span>}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="user-signup-form-row">
|
||
<div className="user-signup-form-group">
|
||
<label htmlFor="email">이메일</label>
|
||
<div className="user-signup-input-with-button">
|
||
<input
|
||
type="email"
|
||
id="email"
|
||
name="email"
|
||
value={formData.email}
|
||
onChange={handleInputChange}
|
||
placeholder="이메일을 입력하세요"
|
||
disabled={isLoading}
|
||
/>
|
||
<button
|
||
type="button"
|
||
onClick={checkEmailDuplicate}
|
||
disabled={isCheckingEmail || isLoading || !formData.email}
|
||
className="user-signup-check-button"
|
||
>
|
||
{isCheckingEmail ? "확인중..." : "중복확인"}
|
||
</button>
|
||
</div>
|
||
{emailAvailable === true && <span className="user-signup-success-message">사용 가능한 이메일입니다.</span>}
|
||
{errors.email && <span className="user-signup-error-message">{errors.email}</span>}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="user-signup-form-row">
|
||
<div className="user-signup-form-group">
|
||
<label htmlFor="password">비밀번호 *</label>
|
||
<input
|
||
type="password"
|
||
id="password"
|
||
name="password"
|
||
value={formData.password}
|
||
onChange={handleInputChange}
|
||
placeholder="8~20자, 영문/숫자/특수기호 포함"
|
||
maxLength={20}
|
||
disabled={isLoading}
|
||
/>
|
||
{errors.password && <span className="user-signup-error-message">{errors.password}</span>}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="user-signup-form-row">
|
||
<div className="user-signup-form-group">
|
||
<label htmlFor="confirmPassword">비밀번호 확인 *</label>
|
||
<input
|
||
type="password"
|
||
id="confirmPassword"
|
||
name="confirmPassword"
|
||
value={formData.confirmPassword}
|
||
onChange={handleInputChange}
|
||
placeholder="비밀번호를 다시 입력하세요"
|
||
maxLength={20}
|
||
disabled={isLoading}
|
||
/>
|
||
{errors.confirmPassword && <span className="user-signup-error-message">{errors.confirmPassword}</span>}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="user-signup-form-row">
|
||
<div className="user-signup-form-group">
|
||
<label htmlFor="pswdHnt">비밀번호 힌트 *</label>
|
||
<AnonymousCodeSelect
|
||
upCd="PSWDHNT"
|
||
value={formData.pswdHnt}
|
||
onValueChange={(value: string) => setFormData(prev => ({ ...prev, pswdHnt: value }))}
|
||
disabled={isLoading}
|
||
placeholder="비밀번호 힌트를 선택하세요"
|
||
/>
|
||
{errors.pswdHnt && <span className="user-signup-error-message">{errors.pswdHnt}</span>}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="user-signup-form-row">
|
||
<div className="user-signup-form-group">
|
||
<label htmlFor="pswdAns">비밀번호 답변</label>
|
||
<input
|
||
type="text"
|
||
id="pswdAns"
|
||
name="pswdAns"
|
||
value={formData.pswdAns}
|
||
onChange={handleInputChange}
|
||
placeholder="비밀번호 답변을 입력하세요"
|
||
maxLength={100}
|
||
disabled={isLoading}
|
||
/>
|
||
{errors.pswdAns && <span className="user-signup-error-message">{errors.pswdAns}</span>}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="user-signup-form-section">
|
||
<h3>연락처 정보</h3>
|
||
|
||
<div className="user-signup-form-row">
|
||
<div className="user-signup-form-group">
|
||
<label htmlFor="mphn">휴대폰 번호</label>
|
||
<input
|
||
type="tel"
|
||
id="mphn"
|
||
name="mphn"
|
||
value={formData.mphn}
|
||
onChange={handleInputChange}
|
||
placeholder="휴대폰 번호를 입력하세요"
|
||
maxLength={11}
|
||
disabled={isLoading}
|
||
/>
|
||
{errors.mphn && <span className="user-signup-error-message">{errors.mphn}</span>}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="user-signup-form-row">
|
||
<div className="user-signup-form-group">
|
||
<label htmlFor="telno">전화번호</label>
|
||
<input
|
||
type="tel"
|
||
id="telno"
|
||
name="telno"
|
||
value={formData.telno}
|
||
onChange={handleInputChange}
|
||
placeholder="전화번호를 입력하세요"
|
||
maxLength={11}
|
||
disabled={isLoading}
|
||
/>
|
||
{errors.telno && <span className="user-signup-error-message">{errors.telno}</span>}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="user-signup-form-section">
|
||
<h3>주소 정보</h3>
|
||
|
||
<div className="user-signup-form-row">
|
||
<div className="user-signup-form-group">
|
||
<label htmlFor="zip">우편번호</label>
|
||
<input
|
||
type="text"
|
||
id="zip"
|
||
name="zip"
|
||
value={formData.zip}
|
||
onChange={handleInputChange}
|
||
placeholder="우편번호를 입력하세요"
|
||
maxLength={5}
|
||
disabled={isLoading}
|
||
/>
|
||
{errors.zip && <span className="user-signup-error-message">{errors.zip}</span>}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="user-signup-form-row">
|
||
<div className="user-signup-form-group">
|
||
<label htmlFor="addr">주소</label>
|
||
<input
|
||
type="text"
|
||
id="addr"
|
||
name="addr"
|
||
value={formData.addr}
|
||
onChange={handleInputChange}
|
||
placeholder="주소를 입력하세요"
|
||
maxLength={200}
|
||
disabled={isLoading}
|
||
/>
|
||
{errors.addr && <span className="user-signup-error-message">{errors.addr}</span>}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="user-signup-form-row">
|
||
<div className="user-signup-form-group">
|
||
<label htmlFor="daddr">상세주소</label>
|
||
<input
|
||
type="text"
|
||
id="daddr"
|
||
name="daddr"
|
||
value={formData.daddr}
|
||
onChange={handleInputChange}
|
||
placeholder="상세주소를 입력하세요"
|
||
maxLength={200}
|
||
disabled={isLoading}
|
||
/>
|
||
{errors.daddr && <span className="user-signup-error-message">{errors.daddr}</span>}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="user-signup-form-section">
|
||
<h3>기관 정보</h3>
|
||
|
||
<div className="user-signup-form-row">
|
||
<div className="user-signup-form-group">
|
||
<label htmlFor="laeSeCd">법인구분 *</label>
|
||
<AnonymousCodeSelect
|
||
upCd="LAESECD"
|
||
value={formData.laeSeCd}
|
||
onValueChange={(value: string) => setFormData(prev => ({ ...prev, laeSeCd: value }))}
|
||
disabled={isLoading}
|
||
placeholder="법인구분을 선택하세요"
|
||
/>
|
||
{errors.laeSeCd && <span className="user-signup-error-message">{errors.laeSeCd}</span>}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="user-signup-form-row">
|
||
<div className="user-signup-form-group">
|
||
<label htmlFor="ogdpSeCd">기관구분 *</label>
|
||
<AnonymousCodeSelect
|
||
upCd="OGDPSECD"
|
||
value={formData.ogdpSeCd}
|
||
onValueChange={(value: string) => setFormData(prev => ({ ...prev, ogdpSeCd: value }))}
|
||
disabled={isLoading}
|
||
placeholder="기관구분을 선택하세요"
|
||
/>
|
||
{errors.ogdpSeCd && <span className="user-signup-error-message">{errors.ogdpSeCd}</span>}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="user-signup-form-row">
|
||
<div className="user-signup-form-group">
|
||
<label htmlFor="instSeCd">기관코드</label>
|
||
<input
|
||
type="text"
|
||
id="instSeCd"
|
||
name="instSeCd"
|
||
value={formData.instSeCd}
|
||
onChange={handleInputChange}
|
||
placeholder="기관코드를 입력하세요"
|
||
maxLength={10}
|
||
disabled={isLoading}
|
||
/>
|
||
{errors.instSeCd && <span className="user-signup-error-message">{errors.instSeCd}</span>}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="user-signup-form-row">
|
||
<div className="user-signup-form-group">
|
||
<label htmlFor="dtlInstCd">상세기관코드</label>
|
||
<input
|
||
type="text"
|
||
id="dtlInstCd"
|
||
name="dtlInstCd"
|
||
value={formData.dtlInstCd}
|
||
onChange={handleInputChange}
|
||
placeholder="상세기관코드를 입력하세요"
|
||
maxLength={10}
|
||
disabled={isLoading}
|
||
/>
|
||
{errors.dtlInstCd && <span className="user-signup-error-message">{errors.dtlInstCd}</span>}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{errors.submit && (
|
||
<div className="user-signup-form-row">
|
||
<div className="user-signup-error-message user-signup-submit-error">{errors.submit}</div>
|
||
</div>
|
||
)}
|
||
|
||
<div className="user-signup-form-actions">
|
||
<button
|
||
type="button"
|
||
onClick={() => setCurrentStep('agreement')}
|
||
className="user-signup-back-button"
|
||
disabled={isLoading}
|
||
>
|
||
이전
|
||
</button>
|
||
<button
|
||
type="button"
|
||
onClick={onClose}
|
||
className="user-signup-cancel-button"
|
||
disabled={isLoading}
|
||
>
|
||
취소
|
||
</button>
|
||
<button
|
||
type="submit"
|
||
className="user-signup-submit-button"
|
||
disabled={isLoading}
|
||
onClick={(e) => {
|
||
e.preventDefault();
|
||
console.log("회원가입 버튼 클릭됨 - onClick");
|
||
handleSubmit(e);
|
||
}}
|
||
>
|
||
{isLoading ? "가입 중..." : "회원가입"}
|
||
</button>
|
||
</div>
|
||
</form>
|
||
)}
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export default UserSignupModal;
|