From 02b1cf005cf3e1df64183d20ba42930eb2767a9f Mon Sep 17 00:00:00 2001 From: dujinkim Date: Thu, 21 Aug 2025 06:57:36 +0000 Subject: (대표님, 최겸) 설계메뉴추가, 작업사항 업데이트 설계메뉴 - 문서관리 설계메뉴 - 벤더 데이터 gtc 메뉴 업데이트 정보시스템 - 메뉴리스트 및 정보 업데이트 파일 라우트 업데이트 엑셀임포트 개선 기본계약 개선 벤더 가입과정 변경 및 개선 벤더 기본정보 - pq 돌체 오류 수정 및 개선 벤더 로그인 과정 이메일 오류 수정 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/signup/join-form.tsx | 143 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 134 insertions(+), 9 deletions(-) (limited to 'components/signup') diff --git a/components/signup/join-form.tsx b/components/signup/join-form.tsx index 71ecbd1c..999b87dc 100644 --- a/components/signup/join-form.tsx +++ b/components/signup/join-form.tsx @@ -114,6 +114,8 @@ interface VendorData { items: string; taxId: string; address: string; + addressDetail: string; + postalCode: string; email: string; phone: string; country: string; @@ -165,6 +167,46 @@ const getCountryData = (lng: string): CountryOption[] => { const MAX_FILE_SIZE = 3e9; +// ========== 전화번호 정규화 함수 ========== + +/** + * 전화번호를 E.164 형식으로 정규화 (저장용) + */ +function normalizePhoneForStorage(phoneNumber: string, countryCode: string): string | null { + try { + if (!phoneNumber || !countryCode) return null; + + const parsed = parsePhoneNumberFromString(phoneNumber, countryCode); + + if (!parsed || !parsed.isValid()) { + return null; + } + + // E.164 형식으로 반환 (+821012345678) + return parsed.format('E.164'); + } catch (error) { + console.error('Phone normalization error:', error); + return null; + } +} + +/** + * E.164 형식의 전화번호를 표시용으로 포맷팅 + */ +function formatPhoneForDisplay(phoneNumber: string): string { + try { + if (!phoneNumber) return ''; + + const parsed = parsePhoneNumberFromString(phoneNumber); + if (parsed) { + return parsed.formatNational(); // 국내 형식으로 표시 + } + return phoneNumber; + } catch { + return phoneNumber; + } +} + // ========== 전화번호 처리 유틸리티 함수들 ========== /** @@ -338,8 +380,10 @@ function PhoneInput({ const formatPhone = usePhoneFormatter(countryCode); useEffect(() => { - setLocalValue(value || ''); - }, [value]); + // E.164 형식으로 저장된 번호를 표시용으로 변환 + const displayValue = value ? formatPhoneForDisplay(value) : ''; + setLocalValue(displayValue); + }, [value, countryCode]); const validation = validatePhoneNumber(localValue, countryCode, t); @@ -432,6 +476,8 @@ export default function JoinForm() { items: "", taxId: defaultTaxId, address: "", + addressDetail: "", + postalCode: "", email: "", phone: "", country: "", @@ -686,12 +732,23 @@ function AccountStep({ setIsLoading(true); setEmailCheckError(''); + try { + // 전화번호 정규화 + const normalizedPhone = normalizePhoneForStorage(data.phone, data.country); + if (!normalizedPhone) { + setEmailCheckError('전화번호 형식이 올바르지 않습니다'); + return; + } + const isUsed = await checkEmailExists(data.email); if (isUsed) { setEmailCheckError(t('emailAlreadyInUse')); return; } + + // 정규화된 전화번호로 데이터 업데이트 + onChange(prev => ({ ...prev, phone: normalizedPhone })); onNext(); } catch (error) { setEmailCheckError(t('emailCheckError')); @@ -914,6 +971,7 @@ function CompleteVendorForm({ const creditReportHandler = createFileUploadHandler(setCreditReportFiles, creditReportFiles); const bankAccountHandler = createFileUploadHandler(setBankAccountFiles, bankAccountFiles); + // 유효성 검사 const validateRequiredFiles = (): string[] => { const errors: string[] = []; @@ -945,10 +1003,10 @@ function CompleteVendorForm({ contact.contactPhone ? validatePhoneNumber(contact.contactPhone, data.country, t).isValid : true ); - const isFormValid = data.vendorName && data.vendorTypeId && data.items && + const isFormValid = data.vendorName && data.vendorTypeId && data.items && data.country && data.phone && vendorPhoneValidation.isValid && data.email && contactsValid && - validateRequiredFiles().length === 0; + validateRequiredFiles().length === 0 // 최종 제출 const handleSubmit = async () => { @@ -964,12 +1022,51 @@ function CompleteVendorForm({ setIsSubmitting(true); try { + // 업체 전화번호 정규화 + const normalizedVendorPhone = normalizePhoneForStorage(data.phone, data.country); + if (!normalizedVendorPhone) { + toast({ + variant: "destructive", + title: t('error'), + description: '업체 전화번호 형식이 올바르지 않습니다', + }); + return; + } + + // 담당자 전화번호들 정규화 + const normalizedContacts = data.contacts.map(contact => { + if (contact.contactPhone) { + const normalizedContactPhone = normalizePhoneForStorage(contact.contactPhone, data.country); + if (!normalizedContactPhone) { + throw new Error(`담당자 ${contact.contactName}의 전화번호 형식이 올바르지 않습니다`); + } + return { ...contact, contactPhone: normalizedContactPhone }; + } + return contact; + }); + + // 대표자 전화번호 정규화 (한국 업체인 경우) + let normalizedRepresentativePhone = data.representativePhone; + if (data.country === "KR" && data.representativePhone) { + const normalized = normalizePhoneForStorage(data.representativePhone, "KR"); + if (!normalized) { + throw new Error('대표자 전화번호 형식이 올바르지 않습니다'); + } + normalizedRepresentativePhone = normalized; + } + const formData = new FormData(); const completeData = { - account: accountData, + account: { + ...accountData, + // accountData.phone은 이미 AccountStep에서 정규화됨 + }, vendor: { ...data, + phone: normalizedVendorPhone, + representativePhone: normalizedRepresentativePhone, + contacts: normalizedContacts, email: data.email || accountData.email, }, consents: { @@ -1004,7 +1101,7 @@ function CompleteVendorForm({ if (data.country !== "KR") { bankAccountFiles.forEach(file => { - formData.append('bankAccountCopy', file); + formData.append('bankAccount', file); }); } @@ -1032,8 +1129,8 @@ function CompleteVendorForm({ console.error(error); toast({ variant: "destructive", - title: t('serverError'), - description: t('errorOccurred'), + title: t('error'), + description: error instanceof Error ? error.message : t('errorOccurred'), }); } finally { setIsSubmitting(false); @@ -1152,7 +1249,9 @@ function CompleteVendorForm({ {/* 주소 */}
- + handleInputChange('address', e.target.value)} @@ -1160,6 +1259,32 @@ function CompleteVendorForm({ />
+ {/* 상세주소 */} +
+ + handleInputChange('addressDetail', e.target.value)} + disabled={isSubmitting} + placeholder="상세주소를 입력해주세요" + /> +
+ + {/* 우편번호 */} +
+ + handleInputChange('postalCode', e.target.value)} + disabled={isSubmitting} + placeholder="우편번호를 입력해주세요" + /> +
+ {/* 국가 */}