- Telephone No.
+ canDelete={false}
+ />
-
-
setPhoneNum({ ...phoneNum, start: value })}
- />
+ {/* 전공 입력 */}
+
+
+
+ Department (major)
+
+ *
+
+
setPhoneNum({ ...phoneNum, middle: value })}
+ placeholder="Major"
+ value={newDocumentData.major}
+ onChange={(value) =>
+ setNewDocumentData({ ...newDocumentData, major: value })
+ }
canDelete={false}
/>
+
+ {/* 이수 학기 입력 */}
+
+
+
+ Term of completion
+
+ *
+
+
+
setPhoneNum({ ...phoneNum, end: value })}
+ placeholder="Term of completion"
+ value={String(newDocumentData.term_of_completion)}
+ onChange={(value) => {
+ if (typeof value === 'string' && !isNaN(Number(value))) {
+ setNewDocumentData({
+ ...newDocumentData,
+ term_of_completion: Number(value),
+ });
+ }
+ }}
canDelete={false}
/>
-
- {/* 이메일 입력 */}
-
-
-
- Email
-
- *
+ {/* 전화번호 입력 */}
+
-
- setNewDocumentData({
- ...newDocumentData,
- email: value,
- })
- }
- canDelete={false}
- />
+ {/* 이메일 입력 */}
+
+
+
+ setNewDocumentData({
+ ...newDocumentData,
+ email: value,
+ })
+ }
+ canDelete={false}
+ />
+
+ {/* 고용주 정보가 있다면 표시 */}
+ {document?.employer_information && (
+
+ )}
- {/* 고용주 정보가 있다면 표시 */}
- {document?.employer_information && (
-
- )}
-
-
- {/* 입력된 정보 중 빈 칸이 없다면 활성화 */}
- {isNotEmpty(newDocumentData) && isNotEmpty(phoneNum) ? (
-
- ) : (
-
- )}
-
-
+
+ {/* 입력된 정보 중 빈 칸이 없다면 활성화 */}
+ {isNotEmpty(newDocumentData) && isNotEmpty(phoneNum) ? (
+
+ ) : (
+
+ )}
+
+
+ >
);
};
diff --git a/src/hooks/api/useDocument.ts b/src/hooks/api/useDocument.ts
index 9446b94..bbc3928 100644
--- a/src/hooks/api/useDocument.ts
+++ b/src/hooks/api/useDocument.ts
@@ -20,11 +20,13 @@ import {
} from '@/api/document';
import {
DocumentType,
+ EmployerInformation,
IntegratedApplicationData,
LaborContractDataResponse,
LaborContractEmployeeInfo,
LaborContractEmployerInfo,
PartTimePermitData,
+ PartTimePermitFormRequest,
SearchSchoolResponse,
} from '@/types/api/document';
import {
@@ -52,7 +54,14 @@ export const useGetDocumentsEmployer = (id: number) => {
};
// 시간제취업허가서 작성 api 통신 커스텀 훅
-export const usePostPartTimeEmployPermit = (id: number) => {
+export const usePostPartTimeEmployPermit = (
+ id: number,
+ options?: UseMutationOptions<
+ RESTYPE<{ id: number }>,
+ Error,
+ { id: number; document: PartTimePermitFormRequest }
+ >,
+) => {
const navigate = useNavigate();
return useMutation({
mutationFn: postPartTimeEmployPermit,
@@ -65,12 +74,20 @@ export const usePostPartTimeEmployPermit = (id: number) => {
type: DocumentType.PART_TIME_PERMIT,
},
}),
+ ...options,
});
};
// 8.10 (유학생)시간제취업허가서 수정 api 통신 커스텀 훅
//TODO: ID값 사용해 redirect 해야
-export const usePutPartTimeEmployPermit = (id: number) => {
+export const usePutPartTimeEmployPermit = (
+ id: number,
+ options?: UseMutationOptions<
+ RESTYPE
,
+ Error,
+ { id: number; document: PartTimePermitFormRequest }
+ >,
+) => {
const navigate = useNavigate();
return useMutation({
mutationFn: putPartTimeEmployPermit,
@@ -83,11 +100,19 @@ export const usePutPartTimeEmployPermit = (id: number) => {
type: DocumentType.PART_TIME_PERMIT,
},
}),
+ ...options,
});
};
// 8.11 (고용주)시간제취업허가서 수정 api 통신 커스텀 훅
-export const usePutPartTimeEmployPermitEmployer = (id: number) => {
+export const usePutPartTimeEmployPermitEmployer = (
+ id: number,
+ options?: UseMutationOptions<
+ RESTYPE,
+ Error,
+ { id: number; document: EmployerInformation }
+ >,
+) => {
const navigate = useNavigate();
return useMutation({
mutationFn: putPartTimeEmployPermitEmployer,
@@ -100,6 +125,7 @@ export const usePutPartTimeEmployPermitEmployer = (id: number) => {
type: DocumentType.PART_TIME_PERMIT,
},
}),
+ ...options,
});
};
From 44331c8899f4784b7fc075ea7c881ea2a64e82f2 Mon Sep 17 00:00:00 2001
From: Savien/Woo Jun Han <49388937+MrMirror21@users.noreply.github.com>
Date: Sun, 22 Dec 2024 03:01:38 +0900
Subject: [PATCH 6/9] =?UTF-8?q?=E2=9C=A8=20feat:=20=EA=B3=A0=EC=9A=A9?=
=?UTF-8?q?=EC=A3=BC=20=EC=84=9C=EB=A5=98=20=EC=9E=91=EC=84=B1=20=EB=A1=9C?=
=?UTF-8?q?=EB=94=A9=20UI=20=EC=B2=98=EB=A6=AC=20#127?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../EmployerLaborContractForm.tsx | 914 +++++++++---------
.../EmployerPartTimePermitForm.tsx | 491 +++++-----
2 files changed, 738 insertions(+), 667 deletions(-)
diff --git a/src/components/Employer/WriteDocument/EmployerLaborContractForm.tsx b/src/components/Employer/WriteDocument/EmployerLaborContractForm.tsx
index 0adbf6d..4b4459d 100644
--- a/src/components/Employer/WriteDocument/EmployerLaborContractForm.tsx
+++ b/src/components/Employer/WriteDocument/EmployerLaborContractForm.tsx
@@ -37,6 +37,7 @@ import WorkDayTimeWithRestBottomSheet from '@/components/Common/WorkDayTimeWithR
import RadioButton from '@/components/Information/RadioButton';
import CheckIcon from '@/assets/icons/CheckOfBoxIcon.svg?react';
import { useCurrentDocumentIdStore } from '@/store/url';
+import LoadingItem from '@/components/Common/LoadingItem';
type LaborContractFormProps = {
document?: LaborContractDataResponse;
@@ -73,6 +74,7 @@ const EmployerLaborContractForm = ({
lat: 0,
lon: 0,
});
+ const [isLoading, setIsLoading] = useState(false);
const [isInvalid, setIsInvalid] = useState(false);
// 근무시간, 요일 선택 모달 활성화 플래그
const [isModal, setIsModal] = useState(false);
@@ -83,6 +85,14 @@ const EmployerLaborContractForm = ({
// 입력 완료 시 제출
const { mutate: putDocument } = usePutLaborContractEmployer(
Number(currentDocumentId),
+ {
+ onMutate: () => {
+ setIsLoading(true);
+ },
+ onSettled: () => {
+ setIsLoading(false);
+ },
+ },
);
useEffect(() => {
if (isEdit && document?.employer_information) {
@@ -202,507 +212,537 @@ const EmployerLaborContractForm = ({
};
return (
-
-
- {/* 회사/점포명 입력 */}
-
-
- setNewDocumentData({
- ...newDocumentData,
- company_name: value,
- })
- }
- canDelete={false}
- />
-
- {/* 사업자등록번호 입력 */}
-
-
- setNewDocumentData({
- ...newDocumentData,
- company_registration_number: value,
- })
- }
- canDelete={false}
- />
-
- {/* 사업체 전화 번호 입력 */}
-
-
-
- setPhoneNum({ ...phoneNum, start: value })}
- />
-
+ <>
+ {isLoading && (
+
e.preventDefault()}
+ >
+
+
+ )}
+
+
+ {/* 회사/점포명 입력 */}
+
setPhoneNum({ ...phoneNum, middle: value })}
+ placeholder="회사/점포명을 작성해주세요"
+ value={newDocumentData.company_name}
+ onChange={(value) =>
+ setNewDocumentData({
+ ...newDocumentData,
+ company_name: value,
+ })
+ }
canDelete={false}
/>
+
+ {/* 사업자등록번호 입력 */}
+
setPhoneNum({ ...phoneNum, end: value })}
+ placeholder="000/00/00000"
+ value={newDocumentData.company_registration_number}
+ onChange={(value) =>
+ setNewDocumentData({
+ ...newDocumentData,
+ company_registration_number: value,
+ })
+ }
canDelete={false}
/>
-
-
- {/* 근무 시작일 선택 입력 */}
-
-
- setNewDocumentData({
- ...newDocumentData,
- start_date: formatDateToDash(value),
- })
- }
- />
-
- {/* 근무 종료일 선택 입력 */}
-
-
- setNewDocumentData({
- ...newDocumentData,
- end_date: formatDateToDash(value),
- })
- }
- />
-
- {/* 대표자 이름 입력 */}
-
-
- setNewDocumentData({
- ...newDocumentData,
- name: value,
- })
- }
- canDelete={false}
- />
-
-
- {/* 주소 검색 입력 input */}
-
+
+ {/* 사업체 전화 번호 입력 */}
+
+
+
+ {/* 근무 시작일 선택 입력 */}
+
+
+ setNewDocumentData({
+ ...newDocumentData,
+ start_date: formatDateToDash(value),
+ })
+ }
+ />
+
+ {/* 근무 종료일 선택 입력 */}
+
+
+ setNewDocumentData({
+ ...newDocumentData,
+ end_date: formatDateToDash(value),
+ })
+ }
+ />
+
+ {/* 대표자 이름 입력 */}
+
handleAddressSearch(value)}
+ inputType={InputType.TEXT}
+ placeholder="이름을 작성해주세요"
+ value={newDocumentData.name}
+ onChange={(value) =>
+ setNewDocumentData({
+ ...newDocumentData,
+ name: value,
+ })
+ }
canDelete={false}
/>
- {/* 주소 검색 결과 보여주는 dropdown modal */}
- {addressSearchResult && addressSearchResult.length !== 0 && (
-
- address.address_type !==
- (AddressType.REGION_ADDR || AddressType.ROAD_ADDR),
- ),
- (address) => address.address_name,
- )}
- onSelect={handleAddressSelect}
+
+
+ {/* 상세요강 입력 */}
+
+
- {/* 검색한 위치를 보여주는 지도 */}
-
-
+
+ 원하는 근무 시간을 추가해주세요.
+
+
+
+ {newDocumentData.work_day_time_list.length > 0 &&
+ newDocumentData.work_day_time_list.map(
+ (workdaytime, index) => (
+
+
+ {workDayTimeToString(workdaytime)}
+
+
+ ),
+ )}
+
+
+ setIsModal(true)}
>
-
-
-
-
+
+
+
+ {/* 매주 주휴일 선택 */}
+
+
+ 다중 선택 가능합니다.
+
+
+ {Object.keys(DAYS).map((value, index) => (
+
+ handleClickDayOfWeek(
+ Object.values(DAYS)[index] as DayOfWeek,
+ )
+ }
+ >
+ {value}
+
+ ))}
+
+
+ {/* 시급 입력 */}
+
setNewDocumentData({
...newDocumentData,
- address: {
- ...newDocumentData.address,
- address_detail: value,
- },
+ hourly_rate: parseStringToSafeNumber(value),
})
}
canDelete={false}
+ isUnit
+ unit="원"
/>
-
- {/* 상세요강 입력 */}
-
-
-
-
- {/* 근로일 및 근로일별 근로 시간 선택 */}
-
-
- 원하는 근무 시간을 추가해주세요.
-
-
-
- {newDocumentData.work_day_time_list.length > 0 &&
- newDocumentData.work_day_time_list.map((workdaytime, index) => (
-
-
- {workDayTimeToString(workdaytime)}
-
-
- ))}
-
-
- setIsModal(true)}
- >
-
-
-
- {/* 매주 주휴일 선택 */}
-
-
- 다중 선택 가능합니다.
-
-
- {Object.keys(DAYS).map((value, index) => (
-
- handleClickDayOfWeek(Object.values(DAYS)[index] as DayOfWeek)
+ )}
+
+ {/* 기타급여(제수당 등) 입력 */}
+
+
+
+ setNewDocumentData({
+ ...newDocumentData,
+ additional_salary: 0,
+ })
}
- >
- {value}
-
- ))}
-
-
- {/* 시급 입력 */}
-
-
- setNewDocumentData({
- ...newDocumentData,
- hourly_rate: parseStringToSafeNumber(value),
- })
- }
- canDelete={false}
- isUnit
- unit="원"
- />
-
- {/* 상여급 입력 */}
-
-
-
- setNewDocumentData({ ...newDocumentData, bonus: 0 })
- }
- isOn={newDocumentData.bonus !== null}
- />
-
- setNewDocumentData({ ...newDocumentData, bonus: null })
- }
- isOn={newDocumentData.bonus === null}
- />
-
- {newDocumentData.bonus !== null && (
-
-
+ isOn={newDocumentData.additional_salary !== null}
+ />
+
setNewDocumentData({
...newDocumentData,
- bonus: parseStringToSafeNumber(value),
+ additional_salary: null,
})
}
- canDelete={false}
- isUnit
- unit="원"
+ isOn={newDocumentData.additional_salary === null}
/>
- )}
-
- {/* 기타급여(제수당 등) 입력 */}
-
-
- {newDocumentData.additional_salary !== null && (
-
-
+
+ {/* 임금 지급방법 입력 */}
+
+
+
setNewDocumentData({
...newDocumentData,
- additional_salary: parseStringToSafeNumber(value),
+ payment_method: PaymentMethod.DIRECT,
})
}
- canDelete={false}
- isUnit
- unit="원"
+ isOn={newDocumentData.payment_method === PaymentMethod.DIRECT}
+ />
+
+ setNewDocumentData({
+ ...newDocumentData,
+ payment_method: PaymentMethod.BANK_TRANSFER,
+ })
+ }
+ isOn={
+ newDocumentData.payment_method === PaymentMethod.BANK_TRANSFER
+ }
/>
- )}
-
- {/* 초과근로에 대한 가산임금률 입력 */}
-
-
- {
- "단시간근로자와 사용자 사이에 근로하기로 정한 시간을 초과하여 근로하면 법정근로시간 내라도 통상임금의 100분의 50% 이상의 가산임금 지급('14.9.19 시행)"
- }
-
-
- setNewDocumentData({
- ...newDocumentData,
- wage_rate: parseStringToSafeNumber(value),
- })
- }
- canDelete={false}
- isUnit
- unit="%"
- />
-
- {/* 임금 지급일 입력 */}
-
-
- setNewDocumentData({
- ...newDocumentData,
- payment_day: parseStringToSafeNumber(value),
- })
- }
- canDelete={false}
- isPrefix
- prefix="매월"
- isUnit
- unit="일"
- />
-
- {/* 임금 지급방법 입력 */}
-
-
-
+
+ {/* 사회보험 적용 여부 입력 */}
+
+
+ {Object.entries(InsuranceInfo).map(
+ ([insuranceType, info], index) => (
+
+
+
{
+ const newInsurance =
+ newDocumentData.insurance.includes(
+ info.key as Insurance,
+ )
+ ? newDocumentData.insurance.filter(
+ (insurance) => insurance !== info.key,
+ )
+ : [
+ ...newDocumentData.insurance,
+ info.key as Insurance,
+ ];
+
+ setNewDocumentData({
+ ...newDocumentData,
+ insurance: newInsurance,
+ });
+ }}
+ >
+
+
+
+
+ {info.name}
+
+
+ ),
+ )}
+
+
+ {/* 서명 입력 */}
+
+
setNewDocumentData({
...newDocumentData,
- payment_method: PaymentMethod.DIRECT,
+ signature_base64: signature,
})
}
- isOn={newDocumentData.payment_method === PaymentMethod.DIRECT}
- />
-
+ onReset={() =>
setNewDocumentData({
...newDocumentData,
- payment_method: PaymentMethod.BANK_TRANSFER,
+ signature_base64: '',
})
}
- isOn={
- newDocumentData.payment_method === PaymentMethod.BANK_TRANSFER
- }
+ isKorean
+ previewImg={newDocumentData.signature_base64}
/>
-
-
- {/* 사회보험 적용 여부 입력 */}
-
-
- {Object.entries(InsuranceInfo).map(
- ([insuranceType, info], index) => (
-
-
-
{
- const newInsurance = newDocumentData.insurance.includes(
- info.key as Insurance,
- )
- ? newDocumentData.insurance.filter(
- (insurance) => insurance !== info.key,
- )
- : [
- ...newDocumentData.insurance,
- info.key as Insurance,
- ];
-
- setNewDocumentData({
- ...newDocumentData,
- insurance: newInsurance,
- });
- }}
- >
-
-
-
-
- {info.name}
-
-
- ),
- )}
-
-
- {/* 서명 입력 */}
-
-
- setNewDocumentData({
- ...newDocumentData,
- signature_base64: signature,
- })
+
+
+
+ {/* 정보 입력 시마다 유효성을 검사해 모든 값이 유효하면 버튼이 활성화 */}
+
+ putDocument({
+ id: Number(currentDocumentId),
+ document: {
+ ...newDocumentData,
+ phone_number: formatPhoneNumber(phoneNum),
+ },
+ })
}
- onReset={() =>
+ />
+
+ {isModal && (
+ {
setNewDocumentData({
...newDocumentData,
- signature_base64: '',
- })
- }
- isKorean
- previewImg={newDocumentData.signature_base64}
+ work_day_time_list: value,
+ });
+ setIsModal(false);
+ }}
+ isShowBottomsheet={isModal}
/>
-
+ )}
-
- {/* 정보 입력 시마다 유효성을 검사해 모든 값이 유효하면 버튼이 활성화 */}
-
- putDocument({
- id: Number(currentDocumentId),
- document: {
- ...newDocumentData,
- phone_number: formatPhoneNumber(phoneNum),
- },
- })
- }
- />
-
- {isModal && (
- {
- setNewDocumentData({
- ...newDocumentData,
- work_day_time_list: value,
- });
- setIsModal(false);
- }}
- isShowBottomsheet={isModal}
- />
- )}
-
+ >
);
};
diff --git a/src/components/Employer/WriteDocument/EmployerPartTimePermitForm.tsx b/src/components/Employer/WriteDocument/EmployerPartTimePermitForm.tsx
index 974d4fc..21df2d6 100644
--- a/src/components/Employer/WriteDocument/EmployerPartTimePermitForm.tsx
+++ b/src/components/Employer/WriteDocument/EmployerPartTimePermitForm.tsx
@@ -29,6 +29,7 @@ import {
} from '@/utils/document';
import { formatPhoneNumber, parsePhoneNumber } from '@/utils/information';
import { phone } from '@/constants/information';
+import LoadingItem from '@/components/Common/LoadingItem';
type PartTimePermitFormProps = {
document?: PartTimePermitData;
@@ -70,6 +71,7 @@ const EmployerPartTimePermitForm = ({
lat: 0,
lon: 0,
});
+ const [isLoading, setIsLoading] = useState(false);
const [isInvalid, setIsInvalid] = useState(false);
// 키워드로 주소 검색
const { searchAddress } = useSearchAddress({
@@ -78,6 +80,14 @@ const EmployerPartTimePermitForm = ({
// 입력 완료 시 제출
const { mutate: putDocument } = usePutPartTimeEmployPermitEmployer(
Number(id),
+ {
+ onMutate: () => {
+ setIsLoading(true);
+ },
+ onSettled: () => {
+ setIsLoading(false);
+ },
+ },
);
useEffect(() => {
@@ -94,7 +104,7 @@ const EmployerPartTimePermitForm = ({
.middle,
end: parsePhoneNumber(document?.employee_information.phone_number).end,
});
- setAddressInput(document.employer_information.address.address_name ?? '')
+ setAddressInput(document.employer_information.address.address_name ?? '');
}
}, [document, isEdit]);
@@ -184,263 +194,284 @@ const EmployerPartTimePermitForm = ({
};
return (
-
-
- {/* 업체명 입력 */}
-
-
- setNewDocumentData({
- ...newDocumentData,
- company_name: value,
- })
- }
- canDelete={false}
- />
-
- {/* 사업자등록번호 입력 */}
-
-
- setNewDocumentData({
- ...newDocumentData,
- company_registration_number: value,
- })
- }
- canDelete={false}
- />
-
- {/* 업직종 입력 */}
-
-
- setNewDocumentData({
- ...newDocumentData,
- job_type: value,
- })
- }
- canDelete={false}
- />
-
-
- {/* 주소 검색 입력 input */}
-
+ <>
+ {isLoading && (
+ e.preventDefault()}
+ >
+
+
+ )}
+
+
+ {/* 업체명 입력 */}
+
handleAddressSearch(value)}
+ inputType={InputType.TEXT}
+ placeholder="이름을 작성해주세요"
+ value={newDocumentData.company_name}
+ onChange={(value) =>
+ setNewDocumentData({
+ ...newDocumentData,
+ company_name: value,
+ })
+ }
+ canDelete={false}
+ />
+
+ {/* 사업자등록번호 입력 */}
+
+
+ setNewDocumentData({
+ ...newDocumentData,
+ company_registration_number: value,
+ })
+ }
canDelete={false}
/>
- {/* 주소 검색 결과 보여주는 dropdown modal */}
- {addressSearchResult && addressSearchResult.length !== 0 && (
-
- address.address_type !==
- (AddressType.REGION_ADDR || AddressType.ROAD_ADDR),
- ),
- (address) => address.address_name,
- )}
- onSelect={handleAddressSelect}
- />
- )}
- {/* 검색한 위치를 보여주는 지도 */}
-
- {/* 대표자 이름 입력 */}
-
-
- setNewDocumentData({
- ...newDocumentData,
- name: value,
- })
- }
- canDelete={false}
- />
-
- {/* 담당자 휴대폰 번호 입력 */}
-
-
-
-
setPhoneNum({ ...phoneNum, start: value })}
+ {/* 담당자 휴대폰 번호 입력 */}
+
+
+
+ {/* 서명 입력 */}
+
+
+ setNewDocumentData({
+ ...newDocumentData,
+ signature_base64: signature,
+ })
+ }
+ onReset={() =>
+ setNewDocumentData({
+ ...newDocumentData,
+ signature_base64: '',
+ })
+ }
+ isKorean
+ previewImg={newDocumentData.signature_base64}
+ />
+
+ {/* 근무 기간 입력 */}
+
+ {
+ setNewDocumentData({
+ ...newDocumentData,
+ work_period: getWorkPeriodKeyByName(value as string),
+ });
+ }}
+ />
+
+ {/* 시급 입력 */}
+
setPhoneNum({ ...phoneNum, middle: value })}
+ placeholder="시급을 입력해주세요"
+ value={String(newDocumentData.hourly_rate)}
+ onChange={(value) =>
+ setNewDocumentData({
+ ...newDocumentData,
+ hourly_rate: parseStringToSafeNumber(value),
+ })
+ }
canDelete={false}
+ isUnit
+ unit="원"
/>
+
+ 2024년 기준 최저시급은 9,860원입니다.
+
+
+ {/* 근무 시간(평일) 입력 */}
+
setPhoneNum({ ...phoneNum, end: value })}
+ placeholder="ex) 요일/00:00-00:00 혹은 휴무"
+ value={newDocumentData.work_days_weekdays}
+ onChange={(value) =>
+ setNewDocumentData({
+ ...newDocumentData,
+ work_days_weekdays: value,
+ })
+ }
canDelete={false}
/>
-
-
- {/* 서명 입력 */}
-
-
- setNewDocumentData({
- ...newDocumentData,
- signature_base64: signature,
- })
- }
- onReset={() =>
- setNewDocumentData({
- ...newDocumentData,
- signature_base64: '',
- })
- }
- isKorean
- previewImg={newDocumentData.signature_base64}
- />
-
- {/* 근무 기간 입력 */}
-
- {
- setNewDocumentData({
- ...newDocumentData,
- work_period: getWorkPeriodKeyByName(value as string),
- });
- }}
- />
-
- {/* 시급 입력 */}
-
-
- setNewDocumentData({
- ...newDocumentData,
- hourly_rate: parseStringToSafeNumber(value),
- })
- }
- canDelete={false}
- isUnit
- unit="원"
- />
-
- 2024년 기준 최저시급은 9,860원입니다.
-
-
- {/* 근무 시간(평일) 입력 */}
-
-
- setNewDocumentData({
- ...newDocumentData,
- work_days_weekdays: value,
- })
- }
- canDelete={false}
- />
-
- {/* 근무 시간(주말) 입력 */}
-
-
- setNewDocumentData({
- ...newDocumentData,
- work_days_weekends: value,
- })
+
+ {/* 근무 시간(주말) 입력 */}
+
+
+ setNewDocumentData({
+ ...newDocumentData,
+ work_days_weekends: value,
+ })
+ }
+ canDelete={false}
+ />
+
+
+
+ {/* 정보 입력 시마다 유효성을 검사해 모든 값이 유효하면 버튼이 활성화 */}
+
+ putDocument({
+ id: Number(id),
+ document: {
+ ...newDocumentData,
+ work_days_weekdays: newDocumentData.work_days_weekdays,
+ work_days_weekends: newDocumentData.work_days_weekends,
+ },
+ })
}
- canDelete={false}
/>
-
+
-
- {/* 정보 입력 시마다 유효성을 검사해 모든 값이 유효하면 버튼이 활성화 */}
-
- putDocument({
- id: Number(id),
- document: {
- ...newDocumentData,
- work_days_weekdays: newDocumentData.work_days_weekdays,
- work_days_weekends: newDocumentData.work_days_weekends,
- },
- })
- }
- />
-
-
+ >
);
};
From aaa048f351bbec55f1dbf9bcab26f1ff542e7da0 Mon Sep 17 00:00:00 2001
From: Savien/Woo Jun Han <49388937+MrMirror21@users.noreply.github.com>
Date: Sun, 22 Dec 2024 03:24:27 +0900
Subject: [PATCH 7/9] =?UTF-8?q?=E2=9C=A8=20feat:=20=EA=B3=A0=EC=9A=A9?=
=?UTF-8?q?=EC=A3=BC=20=EC=84=9C=EB=A5=98=20=EC=A0=9C=EC=B6=9C=20=EC=8B=9C?=
=?UTF-8?q?=20=EB=A1=9C=EB=94=A9=20UI=20=EC=B2=98=EB=A6=AC=20#127?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../DocumentCardDispenserEmployer.tsx | 14 +-
src/hooks/api/useDocument.ts | 9 +-
.../ApplicantDocumentsDetailPage.tsx | 130 +++++++++---------
3 files changed, 85 insertions(+), 68 deletions(-)
diff --git a/src/components/Employer/ApplicantDocumentsDetail/DocumentCardDispenserEmployer.tsx b/src/components/Employer/ApplicantDocumentsDetail/DocumentCardDispenserEmployer.tsx
index 4cc1fb9..18671d9 100644
--- a/src/components/Employer/ApplicantDocumentsDetail/DocumentCardDispenserEmployer.tsx
+++ b/src/components/Employer/ApplicantDocumentsDetail/DocumentCardDispenserEmployer.tsx
@@ -17,7 +17,7 @@ type DocumentCardProps = {
title: string;
type: string;
reason?: string;
- onNext?: () => void;
+ setIsLoading: (loadingStatus: boolean) => void;
};
const NullCard = ({ title }: { title: string }) => {
@@ -288,7 +288,7 @@ const ConfirmationCard = ({
}: {
title: string;
document: EmployDocumentInfo;
-
+
onDownload: (url: string) => void;
}) => {
return (
@@ -358,13 +358,21 @@ const DocumentCardDispenserEmployer = ({
title,
type,
reason,
+ setIsLoading,
}: DocumentCardProps) => {
const navigate = useNavigate();
const handleDownload = (url: string) => {
window.open(url, '_blank');
};
const { updateCurrentDocumentId } = useCurrentDocumentIdStore();
- const { mutate: submitDocument } = usePatchStatusSubmissionEmployer();
+ const { mutate: submitDocument } = usePatchStatusSubmissionEmployer({
+ onMutate: () => {
+ setIsLoading(true);
+ },
+ onSettled: () => {
+ setIsLoading(false);
+ },
+ });
if (!document.status) return ;
switch (document.status) {
case DocumentStatusEmployer.TEMPORARY_SAVE:
diff --git a/src/hooks/api/useDocument.ts b/src/hooks/api/useDocument.ts
index bbc3928..4ed6674 100644
--- a/src/hooks/api/useDocument.ts
+++ b/src/hooks/api/useDocument.ts
@@ -269,7 +269,13 @@ export const usePatchStatusSubmission = () => {
};
// 8.16 (고용주) 서류 (근로계약서, 시간제 취업허가서, 통합 신청서) 제출하기 api hook
-export const usePatchStatusSubmissionEmployer = () => {
+export const usePatchStatusSubmissionEmployer = (
+ options?: UseMutationOptions<
+ RESTYPE,
+ Error,
+ number
+ >,
+) => {
return useMutation({
mutationFn: patchStatusSubmissionEmployer,
onSuccess: () => {
@@ -278,6 +284,7 @@ export const usePatchStatusSubmissionEmployer = () => {
onError: (error) => {
console.error('고용주의 서류 제출 실패', error);
},
+ ...options
});
};
diff --git a/src/pages/Employer/WriteDocuments/ApplicantDocumentsDetailPage.tsx b/src/pages/Employer/WriteDocuments/ApplicantDocumentsDetailPage.tsx
index 30ea5d9..048cb51 100644
--- a/src/pages/Employer/WriteDocuments/ApplicantDocumentsDetailPage.tsx
+++ b/src/pages/Employer/WriteDocuments/ApplicantDocumentsDetailPage.tsx
@@ -3,24 +3,17 @@ import { DocumentTypeInfo } from '@/constants/documents';
import { DocumentType, EmployDocumentInfo } from '@/types/api/document';
import DocumentCardDispenserEmployer from '@/components/Employer/ApplicantDocumentsDetail/DocumentCardDispenserEmployer';
import { useNavigate } from 'react-router-dom';
-import {
- useGetDocumentsEmployer,
- usePatchStatusSubmissionEmployer,
-} from '@/hooks/api/useDocument';
+import { useGetDocumentsEmployer } from '@/hooks/api/useDocument';
import { useCurrentApplicantIdStore } from '@/store/url';
+import { useState } from 'react';
+import LoadingItem from '@/components/Common/LoadingItem';
const ApplicantDocumentsDetailPage = () => {
+ const [isLoading, setIsLoading] = useState(false);
const { currentApplicantId } = useCurrentApplicantIdStore();
const { data } = useGetDocumentsEmployer(Number(currentApplicantId));
const navigate = useNavigate();
- // patch api mutate 설정 (8.16 고용주가 서류 제출하기)
- const { mutate } = usePatchStatusSubmissionEmployer();
-
- const handleOnNext = async (id: number) => {
- mutate(id);
- };
-
{
/*
integrated_application: {
@@ -31,66 +24,75 @@ const ApplicantDocumentsDetailPage = () => {
*/
}
return (
-
-
- navigate('/employer/applicant/document-detail')
- }
- title="서류 관리"
- />
-
- {data && data?.data[DocumentType.PART_TIME_PERMIT] ? (
-
- handleOnNext(data.data[DocumentType.PART_TIME_PERMIT]?.id || 0)
- }
- />
- ) : (
-
-
-
-
- {DocumentTypeInfo[DocumentType.PART_TIME_PERMIT].name}
+ <>
+ {isLoading && (
+
e.preventDefault()}
+ >
+
+
+ )}
+
+
+ navigate('/employer/applicant/document-detail')
+ }
+ title="서류 관리"
+ />
+
+ {data && data?.data[DocumentType.PART_TIME_PERMIT] ? (
+
+ ) : (
+
+
+
+
+ {DocumentTypeInfo[DocumentType.PART_TIME_PERMIT].name}
+
-
- )}
- {data && data?.data[DocumentType.LABOR_CONTRACT] ? (
-
- handleOnNext(data.data[DocumentType.LABOR_CONTRACT]?.id || 0)
- }
- />
- ) : (
-
-
-
-
- {DocumentTypeInfo[DocumentType.LABOR_CONTRACT].name}
+ )}
+ {data && data?.data[DocumentType.LABOR_CONTRACT] ? (
+
+ ) : (
+
+
+
+
+ {DocumentTypeInfo[DocumentType.LABOR_CONTRACT].name}
+
-
- )}
+ )}
+
-
+ >
);
};
From 6db469ea86f3c7cc21721bc097abd0d0919a0f4d Mon Sep 17 00:00:00 2001
From: Savien/Woo Jun Han <49388937+MrMirror21@users.noreply.github.com>
Date: Sun, 22 Dec 2024 21:55:46 +0900
Subject: [PATCH 8/9] =?UTF-8?q?=F0=9F=90=9B=20fix,=20refactor:=20=EC=A7=80?=
=?UTF-8?q?=EC=97=AD=EA=B5=AC=20=EB=8B=A8=EC=9C=84=20=EA=B2=80=EC=83=89=20?=
=?UTF-8?q?=EC=8B=9C=20=EA=B2=B0=EA=B3=BC=20=EC=84=A0=ED=83=9D=20=EA=B0=80?=
=?UTF-8?q?=EB=8A=A5=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95,=20?=
=?UTF-8?q?=EC=A7=80=EB=8F=84=20=EA=B2=80=EC=83=89=20=EA=B4=80=EB=A0=A8=20?=
=?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=BB=A4=EC=8A=A4=ED=85=80=20=ED=9B=85?=
=?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B6=84=EB=A6=AC=20#127?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../EditProfile/EmployerEditInputSection.tsx | 95 ++++-----------
src/components/Employer/PostCreate/Step2.tsx | 105 ++++------------
.../Signup/InformationInputSection.tsx | 114 +++++-------------
.../EmployerLaborContractForm.tsx | 94 +++------------
.../EmployerPartTimePermitForm.tsx | 97 +++------------
src/components/Information/AddressStep.tsx | 90 +++-----------
.../IntegratedApplicationWriteForm.tsx | 94 +++------------
src/hooks/api/useAddressSearch.ts | 109 +++++++++++++++++
8 files changed, 258 insertions(+), 540 deletions(-)
create mode 100644 src/hooks/api/useAddressSearch.ts
diff --git a/src/components/Employer/EditProfile/EmployerEditInputSection.tsx b/src/components/Employer/EditProfile/EmployerEditInputSection.tsx
index 832674d..5252a61 100644
--- a/src/components/Employer/EditProfile/EmployerEditInputSection.tsx
+++ b/src/components/Employer/EditProfile/EmployerEditInputSection.tsx
@@ -2,11 +2,10 @@ import Dropdown, { DropdownModal } from '@/components/Common/Dropdown';
import Input from '@/components/Common/Input';
import InputLayout from '@/components/WorkExperience/InputLayout';
import { phone } from '@/constants/information';
-import { useGetGeoInfo, useSearchAddress } from '@/hooks/api/useKaKaoMap';
-import { AddressType, Document } from '@/types/api/map';
+import { useGetGeoInfo } from '@/hooks/api/useKaKaoMap';
+import { AddressType } from '@/types/api/map';
import { InputType } from '@/types/common/input';
-import { pick } from '@/utils/map';
-import { useCallback, useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { Map, MapMarker } from 'react-kakao-maps-sdk';
import FileAddIcon from '@/assets/icons/FileAddIcon.svg?react';
import CheckIcon from '@/assets/icons/CheckOfBoxIcon.svg?react';
@@ -14,6 +13,7 @@ import GiggleLogo from '@/assets/icons/GiggleLogo.svg?react';
import giggleLogoPng from '@/assets/images/GiggleLogo.png';
import { formatPhoneNumber } from '@/utils/information';
import { EmployerProfileRequestBody } from '@/types/api/profile';
+import { useAddressSearch } from '@/hooks/api/useAddressSearch';
type EmployerEditInputSectionProps = {
newEmployData: EmployerProfileRequestBody;
@@ -34,17 +34,15 @@ const EmployerEditInputSection = ({
setLogoFile,
initialPhonNum,
}: EmployerEditInputSectionProps) => {
- // 주소 검색용 input 저장하는 state
- const [addressInput, setAddressInput] = useState('');
- // 주소 검색 결과를 저장하는 array
- const [addressSearchResult, setAddressSearchResult] = useState(
- [],
- );
- // 지도에 표시할 핀에 사용되는 위/경도 좌표
- const [currentGeoInfo, setCurrentGeoInfo] = useState({
- lat: 0,
- lon: 0,
- });
+ const {
+ addressInput, // 주소 검색용 input 저장하는 state
+ addressSearchResult, // 주소 검색 결과를 저장하는 array
+ currentGeoInfo, // 지도에 표시할 핀에 사용되는 위/경도 좌표
+ setCurrentGeoInfo,
+ handleAddressSearch, // 검색할 주소 입력 시 실시간 검색
+ handleAddressSelect, // 검색 결과 중 원하는 주소를 선택할 시 state에 입력
+ setAddressInput,
+ } = useAddressSearch();
// 세 부분으로 나누어 입력받는 방식을 위해 전화번호만 별도의 state로 분리, 추후 유효성 검사 단에서 통합
const [phoneNum, setPhoneNum] = useState({
start: '',
@@ -67,10 +65,6 @@ const EmployerEditInputSection = ({
const [selectedImage, setSelectedImage] = useState();
// 현재 좌표 기준 주소 획득
const { data, isSuccess } = useGetGeoInfo(setCurrentGeoInfo);
- // 키워드로 주소 검색
- const { searchAddress } = useSearchAddress({
- onSuccess: (data) => setAddressSearchResult(data),
- });
// 첫 로딩 시 현재 사용자의 위치 파악 해 지도에 표기
useEffect(() => {
setNewEmployData({
@@ -92,68 +86,21 @@ const EmployerEditInputSection = ({
});
}, [phoneNum]);
- // 검색할 주소 입력 시 실시간 검색
- const handleAddressSearch = useCallback(
- (address: string) => {
- setAddressInput(address);
- if (address !== '') {
- searchAddress(address);
- } else {
- setAddressSearchResult([]);
- }
- },
- [searchAddress],
- );
- // 검색 결과 중 원하는 주소를 선택할 시 state에 입력
- const handleAddressSelect = (selectedAddressName: string) => {
- // 사용자가 선택한 주소와 일치하는 결과를 검색 결과를 저장하는 array에서 탐색
- const selectedAddress = addressSearchResult.find(
- (address) => address.address_name === selectedAddressName,
- ) as Document | undefined;
-
- if (!selectedAddress) return;
+ // 검색된 주소 선택 시 state에 반영
+ const handleAddressSelection = (selectedAddressName: string) => {
+ const result = handleAddressSelect(selectedAddressName);
+ if (!result) return;
- // 구 주소와 도로명 주소를 구분하기 위한 플래그(카카오에서 반환하는 속성 명이 달라짐)
- const isRegionAddr =
- selectedAddress.address_type === AddressType.REGION_ADDR;
- const addressData = isRegionAddr
- ? selectedAddress.address
- : selectedAddress.road_address;
-
- // 카카오에서 반환하는 데이터 중 필요한 속성들만 선택
- const selectedProperties = pick(addressData, [
- 'address_name',
- 'region_1depth_name',
- 'region_2depth_name',
- 'region_3depth_name',
- ]);
-
- let region4DepthName = ''; // optional property인 region4DeptName
- if (isRegionAddr) {
- region4DepthName = selectedAddress.address.region_3depth_h_name || '';
- } else {
- region4DepthName = selectedAddress.road_address.road_name || '';
- }
-
- // 선택한 데이터들을 state에 update
setNewEmployData({
...newEmployData,
address: {
...newEmployData.address,
- ...selectedProperties,
- region_4depth_name: region4DepthName,
- longitude: Number(addressData.x),
- latitude: Number(addressData.y),
+ ...result.addressData,
},
});
- setAddressInput(selectedAddress.address_name);
- setCurrentGeoInfo({
- lon: Number(selectedAddress.x),
- lat: Number(selectedAddress.y),
- });
- // 검색 결과 초기화
- setAddressSearchResult([]);
+ setAddressInput(result.selectedAddressName);
};
+
// 로고 선택
const handleImageChange = (e: React.ChangeEvent) => {
const file = e.target.files?.[0];
@@ -254,7 +201,7 @@ const EmployerEditInputSection = ({
),
(address) => address.address_name,
)}
- onSelect={handleAddressSelect}
+ onSelect={handleAddressSelection}
/>
)}
diff --git a/src/components/Employer/PostCreate/Step2.tsx b/src/components/Employer/PostCreate/Step2.tsx
index 2c554d7..fb003e8 100644
--- a/src/components/Employer/PostCreate/Step2.tsx
+++ b/src/components/Employer/PostCreate/Step2.tsx
@@ -3,16 +3,15 @@ import Button from '@/components/Common/Button';
import Dropdown, { DropdownModal } from '@/components/Common/Dropdown';
import Input from '@/components/Common/Input';
import InputLayout from '@/components/WorkExperience/InputLayout';
-import { useSearchAddress } from '@/hooks/api/useKaKaoMap';
-import { AddressType, Document } from '@/types/api/map';
+import { AddressType } from '@/types/api/map';
import { InputType } from '@/types/common/input';
import { JobPostingForm } from '@/types/postCreate/postCreate';
-import { pick } from '@/utils/map';
-import { useCallback, useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { Map, MapMarker } from 'react-kakao-maps-sdk';
import CheckIcon from '@/assets/icons/CheckOfBoxIcon.svg?react';
import { buttonTypeKeys } from '@/constants/components';
import { formatDateToDash } from '@/utils/editResume';
+import { useAddressSearch } from '@/hooks/api/useAddressSearch';
const Step2 = ({
postInfo,
@@ -27,96 +26,36 @@ const Step2 = ({
const [newPostInfo, setNewPostInfo] = useState(postInfo);
// 버튼 활성화 여부를 위한 플래그
const [isInvalid, setIsInvalid] = useState(true);
- // 주소 검색용 input 저장하는 state
- const [addressInput, setAddressInput] = useState(
- newPostInfo.body.address.address_name
- ? newPostInfo.body.address.address_name
- : '',
- );
- // 주소 검색 결과를 저장하는 array
- const [addressSearchResult, setAddressSearchResult] = useState(
- [],
- );
- // 지도에 표시할 핀에 사용되는 위/경도 좌표
- const [currentGeoInfo, setCurrentGeoInfo] = useState({
- lat: 0,
- lon: 0,
- });
-
- // 키워드로 주소 검색
- const { searchAddress } = useSearchAddress({
- onSuccess: (data) => setAddressSearchResult(data),
- });
- // 검색할 주소 입력 시 실시간 검색
- const handleAddressSearch = useCallback(
- (address: string) => {
- setAddressInput(address);
- if (address !== '') {
- searchAddress(address);
- } else {
- setAddressSearchResult([]);
- }
- },
- [searchAddress],
- );
-
- useEffect(() => {
- if(addressInput !== '') handleAddressSearch(addressInput);
- }, []);
-
- // 검색 결과 중 원하는 주소를 선택할 시 state에 입력
- const handleAddressSelect = (selectedAddressName: string) => {
- // 사용자가 선택한 주소와 일치하는 결과를 검색 결과를 저장하는 array에서 탐색
- const selectedAddress = addressSearchResult.find(
- (address) => address.address_name === selectedAddressName,
- ) as Document | undefined;
+ const {
+ addressInput, // 주소 검색용 input 저장하는 state
+ addressSearchResult, // 주소 검색 결과를 저장하는 array
+ currentGeoInfo, // 지도에 표시할 핀에 사용되는 위/경도 좌표
+ handleAddressSearch, // 검색할 주소 입력 시 실시간 검색
+ handleAddressSelect, // 검색 결과 중 원하는 주소를 선택할 시 state에 입력
+ setAddressInput,
+ } = useAddressSearch();
- if (!selectedAddress) return;
+ const handleAddressSelection = (selectedAddressName: string) => {
+ const result = handleAddressSelect(selectedAddressName);
+ if (!result) return;
- // 구 주소와 도로명 주소를 구분하기 위한 플래그(카카오에서 반환하는 속성 명이 달라짐)
- const isRegionAddr =
- selectedAddress.address_type === AddressType.REGION_ADDR;
- const addressData = isRegionAddr
- ? selectedAddress.address
- : selectedAddress.road_address;
-
- // 카카오에서 반환하는 데이터 중 필요한 속성들만 선택
- const selectedProperties = pick(addressData, [
- 'address_name',
- 'region_1depth_name',
- 'region_2depth_name',
- 'region_3depth_name',
- ]);
-
- let region4DepthName = ''; // optional property인 region4DeptName
- if (isRegionAddr) {
- region4DepthName = selectedAddress.address.region_3depth_h_name || '';
- } else {
- region4DepthName = selectedAddress.road_address.road_name || '';
- }
-
- // 선택한 데이터들을 state에 update
setNewPostInfo({
...newPostInfo,
body: {
...newPostInfo.body,
address: {
...newPostInfo.body.address,
- ...selectedProperties,
- region_4depth_name: region4DepthName,
- longitude: Number(addressData.x),
- latitude: Number(addressData.y),
+ ...result.addressData,
},
},
});
- setAddressInput(selectedAddress.address_name);
- setCurrentGeoInfo({
- lon: Number(selectedAddress.x),
- lat: Number(selectedAddress.y),
- });
- // 검색 결과 초기화
- setAddressSearchResult([]);
+ setAddressInput(result.selectedAddressName);
};
+
+ useEffect(() => {
+ if (addressInput !== '') handleAddressSearch(addressInput);
+ }, []);
+
/* 정보 입력 시마다 유효성을 검사해 모든 값이 유효하면 버튼이 활성화 */
useEffect(() => {
const { address } = newPostInfo.body;
@@ -150,7 +89,7 @@ const Step2 = ({
),
(address) => address.address_name,
)}
- onSelect={handleAddressSelect}
+ onSelect={handleAddressSelection}
/>
)}
diff --git a/src/components/Employer/Signup/InformationInputSection.tsx b/src/components/Employer/Signup/InformationInputSection.tsx
index 4945cee..6cdd95b 100644
--- a/src/components/Employer/Signup/InformationInputSection.tsx
+++ b/src/components/Employer/Signup/InformationInputSection.tsx
@@ -2,18 +2,18 @@ import Dropdown, { DropdownModal } from '@/components/Common/Dropdown';
import Input from '@/components/Common/Input';
import InputLayout from '@/components/WorkExperience/InputLayout';
import { phone } from '@/constants/information';
-import { useGetGeoInfo, useSearchAddress } from '@/hooks/api/useKaKaoMap';
+import { useGetGeoInfo} from '@/hooks/api/useKaKaoMap';
import { EmployerRegistrationRequestBody } from '@/types/api/employ';
-import { AddressType, Document } from '@/types/api/map';
+import { AddressType } from '@/types/api/map';
import { InputType } from '@/types/common/input';
-import { pick } from '@/utils/map';
-import { useCallback, useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { Map, MapMarker } from 'react-kakao-maps-sdk';
import FileAddIcon from '@/assets/icons/FileAddIcon.svg?react';
import CheckIcon from '@/assets/icons/CheckOfBoxIcon.svg?react';
import GiggleLogo from '@/assets/icons/GiggleLogo.svg?react';
import giggleLogoPng from '@/assets/images/GiggleLogo.png';
import { formatPhoneNumber } from '@/utils/information';
+import { useAddressSearch } from '@/hooks/api/useAddressSearch';
type InformationInputSectionProps = {
newEmployData: EmployerRegistrationRequestBody;
@@ -32,17 +32,15 @@ const InformationInputSection = ({
setNewEmployData,
setLogoFile,
}: InformationInputSectionProps) => {
- // 주소 검색용 input 저장하는 state
- const [addressInput, setAddressInput] = useState('');
- // 주소 검색 결과를 저장하는 array
- const [addressSearchResult, setAddressSearchResult] = useState(
- [],
- );
- // 지도에 표시할 핀에 사용되는 위/경도 좌표
- const [currentGeoInfo, setCurrentGeoInfo] = useState({
- lat: 0,
- lon: 0,
- });
+ const {
+ addressInput, // 주소 검색용 input 저장하는 state
+ addressSearchResult, // 주소 검색 결과를 저장하는 array
+ currentGeoInfo, // 지도에 표시할 핀에 사용되는 위/경도 좌표
+ setCurrentGeoInfo,
+ handleAddressSearch, // 검색할 주소 입력 시 실시간 검색
+ handleAddressSelect, // 검색 결과 중 원하는 주소를 선택할 시 state에 입력
+ setAddressInput,
+ } = useAddressSearch();
// 세 부분으로 나누어 입력받는 방식을 위해 전화번호만 별도의 state로 분리, 추후 유효성 검사 단에서 통합
const [phoneNum, setPhoneNum] = useState({
start: '',
@@ -52,11 +50,23 @@ const InformationInputSection = ({
const [logoStatus, setLogoStatus] = useState(LogoType.NONE);
const [selectedImage, setSelectedImage] = useState();
// 현재 좌표 기준 주소 획득
- const { data, isSuccess } = useGetGeoInfo(setCurrentGeoInfo);
- // 키워드로 주소 검색
- const { searchAddress } = useSearchAddress({
- onSuccess: (data) => setAddressSearchResult(data),
- });
+ const { data, isSuccess } = useGetGeoInfo(setCurrentGeoInfo);
+
+ // 검색된 주소 선택 시 state에 반영
+ const handleAddressSelection = (selectedAddressName: string) => {
+ const result = handleAddressSelect(selectedAddressName);
+ if (!result) return;
+
+ setNewEmployData({
+ ...newEmployData,
+ address: {
+ ...newEmployData.address,
+ ...result.addressData,
+ },
+ });
+ setAddressInput(result.selectedAddressName);
+ };
+
// 첫 로딩 시 현재 사용자의 위치 파악 해 지도에 표기
useEffect(() => {
setNewEmployData({
@@ -78,68 +88,6 @@ const InformationInputSection = ({
});
}, [phoneNum]);
- // 검색할 주소 입력 시 실시간 검색
- const handleAddressSearch = useCallback(
- (address: string) => {
- setAddressInput(address);
- if (address !== '') {
- searchAddress(address);
- } else {
- setAddressSearchResult([]);
- }
- },
- [searchAddress],
- );
- // 검색 결과 중 원하는 주소를 선택할 시 state에 입력
- const handleAddressSelect = (selectedAddressName: string) => {
- // 사용자가 선택한 주소와 일치하는 결과를 검색 결과를 저장하는 array에서 탐색
- const selectedAddress = addressSearchResult.find(
- (address) => address.address_name === selectedAddressName,
- ) as Document | undefined;
-
- if (!selectedAddress) return;
-
- // 구 주소와 도로명 주소를 구분하기 위한 플래그(카카오에서 반환하는 속성 명이 달라짐)
- const isRegionAddr =
- selectedAddress.address_type === AddressType.REGION_ADDR;
- const addressData = isRegionAddr
- ? selectedAddress.address
- : selectedAddress.road_address;
-
- // 카카오에서 반환하는 데이터 중 필요한 속성들만 선택
- const selectedProperties = pick(addressData, [
- 'address_name',
- 'region_1depth_name',
- 'region_2depth_name',
- 'region_3depth_name',
- ]);
-
- let region4DepthName = ''; // optional property인 region4DeptName
- if (isRegionAddr) {
- region4DepthName = selectedAddress.address.region_3depth_h_name || '';
- } else {
- region4DepthName = selectedAddress.road_address.road_name || '';
- }
-
- // 선택한 데이터들을 state에 update
- setNewEmployData({
- ...newEmployData,
- address: {
- ...newEmployData.address,
- ...selectedProperties,
- region_4depth_name: region4DepthName,
- longitude: Number(addressData.x),
- latitude: Number(addressData.y),
- },
- });
- setAddressInput(selectedAddress.address_name);
- setCurrentGeoInfo({
- lon: Number(selectedAddress.x),
- lat: Number(selectedAddress.y),
- });
- // 검색 결과 초기화
- setAddressSearchResult([]);
- };
// 로고 선택
const handleImageChange = (e: React.ChangeEvent) => {
const file = e.target.files?.[0];
@@ -240,7 +188,7 @@ const InformationInputSection = ({
),
(address) => address.address_name,
)}
- onSelect={handleAddressSelect}
+ onSelect={handleAddressSelection}
/>
)}
diff --git a/src/components/Employer/WriteDocument/EmployerLaborContractForm.tsx b/src/components/Employer/WriteDocument/EmployerLaborContractForm.tsx
index 7e9f39f..88acf01 100644
--- a/src/components/Employer/WriteDocument/EmployerLaborContractForm.tsx
+++ b/src/components/Employer/WriteDocument/EmployerLaborContractForm.tsx
@@ -6,7 +6,6 @@ import {
initialLaborContractEmployerInfo,
InsuranceInfo,
} from '@/constants/documents';
-import { useSearchAddress } from '@/hooks/api/useKaKaoMap';
import {
DayOfWeek,
Insurance,
@@ -15,10 +14,9 @@ import {
PaymentMethod,
WorkDayTimeWithRest,
} from '@/types/api/document';
-import { AddressType, Document } from '@/types/api/map';
+import { AddressType } from '@/types/api/map';
import { InputType } from '@/types/common/input';
-import { pick } from '@/utils/map';
-import { useCallback, useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { Map, MapMarker } from 'react-kakao-maps-sdk';
import SignaturePad from '@/components/Document/write/SignaturePad';
import { workDayTimeToString } from '@/utils/post';
@@ -38,6 +36,7 @@ import RadioButton from '@/components/Information/RadioButton';
import CheckIcon from '@/assets/icons/CheckOfBoxIcon.svg?react';
import { useCurrentDocumentIdStore } from '@/store/url';
import LoadingItem from '@/components/Common/LoadingItem';
+import { useAddressSearch } from '@/hooks/api/useAddressSearch';
type LaborContractFormProps = {
document?: LaborContractDataResponse;
@@ -63,25 +62,19 @@ const EmployerLaborContractForm = ({
? parsePhoneNumber(newDocumentData.phone_number).end
: '',
});
- // 주소 검색용 input 저장하는 state
- const [addressInput, setAddressInput] = useState('');
- // 주소 검색 결과를 저장하는 array
- const [addressSearchResult, setAddressSearchResult] = useState(
- [],
- );
- // 지도에 표시할 핀에 사용되는 위/경도 좌표
- const [currentGeoInfo, setCurrentGeoInfo] = useState({
- lat: 0,
- lon: 0,
- });
+ const {
+ addressInput, // 주소 검색용 input 저장하는 state
+ addressSearchResult, // 주소 검색 결과를 저장하는 array
+ currentGeoInfo, // 지도에 표시할 핀에 사용되는 위/경도 좌표
+ handleAddressSearch, // 검색할 주소 입력 시 실시간 검색
+ handleAddressSelect, // 검색 결과 중 원하는 주소를 선택할 시 state에 입력
+ setAddressInput,
+ } = useAddressSearch();
+
const [isLoading, setIsLoading] = useState(false);
const [isInvalid, setIsInvalid] = useState(false);
// 근무시간, 요일 선택 모달 활성화 플래그
const [isModal, setIsModal] = useState(false);
- // 키워드로 주소 검색
- const { searchAddress } = useSearchAddress({
- onSuccess: (data) => setAddressSearchResult(data),
- });
// 입력 완료 시 제출
const { mutate: putDocument } = usePutLaborContractEmployer(
Number(currentDocumentId),
@@ -130,68 +123,19 @@ const EmployerLaborContractForm = ({
);
}, [newDocumentData, phoneNum]);
- // 검색할 주소 입력 시 실시간 검색
- const handleAddressSearch = useCallback(
- (address: string) => {
- setAddressInput(address);
- if (address !== '') {
- searchAddress(address);
- } else {
- setAddressSearchResult([]);
- }
- },
- [searchAddress],
- );
-
- // 검색 결과 중 원하는 주소를 선택할 시 state에 입력
- const handleAddressSelect = (selectedAddressName: string) => {
- // 사용자가 선택한 주소와 일치하는 결과를 검색 결과를 저장하는 array에서 탐색
- const selectedAddress = addressSearchResult.find(
- (address) => address.address_name === selectedAddressName,
- ) as Document | undefined;
+ // 검색된 주소 선택 시 state에 반영
+ const handleAddressSelection = (selectedAddressName: string) => {
+ const result = handleAddressSelect(selectedAddressName);
+ if (!result) return;
- if (!selectedAddress) return;
-
- // 구 주소와 도로명 주소를 구분하기 위한 플래그(카카오에서 반환하는 속성 명이 달라짐)
- const isRegionAddr =
- selectedAddress.address_type === AddressType.REGION_ADDR;
- const addressData = isRegionAddr
- ? selectedAddress.address
- : selectedAddress.road_address;
-
- // 카카오에서 반환하는 데이터 중 필요한 속성들만 선택
- const selectedProperties = pick(addressData, [
- 'address_name',
- 'region_1depth_name',
- 'region_2depth_name',
- 'region_3depth_name',
- ]);
-
- let region4DepthName = ''; // optional property인 region4DeptName
- if (isRegionAddr) {
- region4DepthName = selectedAddress.address.region_3depth_h_name || '';
- } else {
- region4DepthName = selectedAddress.road_address.road_name || '';
- }
-
- // 선택한 데이터들을 state에 update
setNewDocumentData({
...newDocumentData,
address: {
...newDocumentData.address,
- ...selectedProperties,
- region_4depth_name: region4DepthName,
- longitude: Number(addressData.x),
- latitude: Number(addressData.y),
+ ...result.addressData,
},
});
- setAddressInput(selectedAddress.address_name);
- setCurrentGeoInfo({
- lon: Number(selectedAddress.x),
- lat: Number(selectedAddress.y),
- });
- // 검색 결과 초기화
- setAddressSearchResult([]);
+ setAddressInput(result.selectedAddressName);
};
// 주휴일 선택/선택 해제 핸들러
@@ -362,7 +306,7 @@ const EmployerLaborContractForm = ({
),
(address) => address.address_name,
)}
- onSelect={handleAddressSelect}
+ onSelect={handleAddressSelection}
/>
)}
diff --git a/src/components/Employer/WriteDocument/EmployerPartTimePermitForm.tsx b/src/components/Employer/WriteDocument/EmployerPartTimePermitForm.tsx
index 21df2d6..5b68900 100644
--- a/src/components/Employer/WriteDocument/EmployerPartTimePermitForm.tsx
+++ b/src/components/Employer/WriteDocument/EmployerPartTimePermitForm.tsx
@@ -6,16 +6,14 @@ import {
WorkPeriodInfo,
WorkPeriodNames,
} from '@/constants/documents';
-import { useSearchAddress } from '@/hooks/api/useKaKaoMap';
import {
EmployerInformation,
PartTimePermitData,
WorkPeriod,
} from '@/types/api/document';
-import { AddressType, Document } from '@/types/api/map';
+import { AddressType } from '@/types/api/map';
import { InputType } from '@/types/common/input';
-import { pick } from '@/utils/map';
-import { useCallback, useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { Map, MapMarker } from 'react-kakao-maps-sdk';
import SignaturePad from '@/components/Document/write/SignaturePad';
import { extractNumbersAsNumber, getWorkPeriodKeyByName } from '@/utils/post';
@@ -30,6 +28,7 @@ import {
import { formatPhoneNumber, parsePhoneNumber } from '@/utils/information';
import { phone } from '@/constants/information';
import LoadingItem from '@/components/Common/LoadingItem';
+import { useAddressSearch } from '@/hooks/api/useAddressSearch';
type PartTimePermitFormProps = {
document?: PartTimePermitData;
@@ -56,27 +55,16 @@ const EmployerPartTimePermitForm = ({
? parsePhoneNumber(newDocumentData.phone_number).end
: '',
});
- // 주소 검색용 input 저장하는 state
- const [addressInput, setAddressInput] = useState(
- document?.employer_information?.address.address_name
- ? document?.employer_information?.address.address_name
- : '',
- );
- // 주소 검색 결과를 저장하는 array
- const [addressSearchResult, setAddressSearchResult] = useState(
- [],
- );
- // 지도에 표시할 핀에 사용되는 위/경도 좌표
- const [currentGeoInfo, setCurrentGeoInfo] = useState({
- lat: 0,
- lon: 0,
- });
+ const {
+ addressInput, // 주소 검색용 input 저장하는 state
+ addressSearchResult, // 주소 검색 결과를 저장하는 array
+ currentGeoInfo, // 지도에 표시할 핀에 사용되는 위/경도 좌표
+ handleAddressSearch, // 검색할 주소 입력 시 실시간 검색
+ handleAddressSelect, // 검색 결과 중 원하는 주소를 선택할 시 state에 입력
+ setAddressInput,
+ } = useAddressSearch();
const [isLoading, setIsLoading] = useState(false);
const [isInvalid, setIsInvalid] = useState(false);
- // 키워드로 주소 검색
- const { searchAddress } = useSearchAddress({
- onSuccess: (data) => setAddressSearchResult(data),
- });
// 입력 완료 시 제출
const { mutate: putDocument } = usePutPartTimeEmployPermitEmployer(
Number(id),
@@ -129,68 +117,19 @@ const EmployerPartTimePermitForm = ({
);
}, [newDocumentData, phoneNum]);
- // 검색할 주소 입력 시 실시간 검색
- const handleAddressSearch = useCallback(
- (address: string) => {
- setAddressInput(address);
- if (address !== '') {
- searchAddress(address);
- } else {
- setAddressSearchResult([]);
- }
- },
- [searchAddress],
- );
-
- // 검색 결과 중 원하는 주소를 선택할 시 state에 입력
- const handleAddressSelect = (selectedAddressName: string) => {
- // 사용자가 선택한 주소와 일치하는 결과를 검색 결과를 저장하는 array에서 탐색
- const selectedAddress = addressSearchResult.find(
- (address) => address.address_name === selectedAddressName,
- ) as Document | undefined;
-
- if (!selectedAddress) return;
-
- // 구 주소와 도로명 주소를 구분하기 위한 플래그(카카오에서 반환하는 속성 명이 달라짐)
- const isRegionAddr =
- selectedAddress.address_type === AddressType.REGION_ADDR;
- const addressData = isRegionAddr
- ? selectedAddress.address
- : selectedAddress.road_address;
-
- // 카카오에서 반환하는 데이터 중 필요한 속성들만 선택
- const selectedProperties = pick(addressData, [
- 'address_name',
- 'region_1depth_name',
- 'region_2depth_name',
- 'region_3depth_name',
- ]);
+ // 검색된 주소 선택 시 state에 반영
+ const handleAddressSelection = (selectedAddressName: string) => {
+ const result = handleAddressSelect(selectedAddressName);
+ if (!result) return;
- let region4DepthName = ''; // optional property인 region4DeptName
- if (isRegionAddr) {
- region4DepthName = selectedAddress.address.region_3depth_h_name || '';
- } else {
- region4DepthName = selectedAddress.road_address.road_name || '';
- }
-
- // 선택한 데이터들을 state에 update
setNewDocumentData({
...newDocumentData,
address: {
...newDocumentData.address,
- ...selectedProperties,
- region_4depth_name: region4DepthName,
- longitude: Number(addressData.x),
- latitude: Number(addressData.y),
+ ...result.addressData,
},
});
- setAddressInput(selectedAddress.address_name);
- setCurrentGeoInfo({
- lon: Number(selectedAddress.x),
- lat: Number(selectedAddress.y),
- });
- // 검색 결과 초기화
- setAddressSearchResult([]);
+ setAddressInput(result.selectedAddressName);
};
return (
@@ -275,7 +214,7 @@ const EmployerPartTimePermitForm = ({
),
(address) => address.address_name,
)}
- onSelect={handleAddressSelect}
+ onSelect={handleAddressSelection}
/>
)}
diff --git a/src/components/Information/AddressStep.tsx b/src/components/Information/AddressStep.tsx
index 2b3d6f2..57ae386 100644
--- a/src/components/Information/AddressStep.tsx
+++ b/src/components/Information/AddressStep.tsx
@@ -6,14 +6,13 @@ import {
initialAddress,
UserInfoRequestBody,
} from '@/types/api/users';
-import { useCallback, useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import BottomButtonPanel from '@/components/Common/BottomButtonPanel';
-import { useGetGeoInfo, useSearchAddress } from '@/hooks/api/useKaKaoMap';
-import { Document } from '@/types/api/map';
+import { useGetGeoInfo} from '@/hooks/api/useKaKaoMap';
import { DropdownModal } from '@/components/Common/Dropdown';
import { AddressType } from '@/types/api/map';
-import { pick } from '@/utils/map';
import Button from '@/components/Common/Button';
+import { useAddressSearch } from '@/hooks/api/useAddressSearch';
type AddressStepProps = {
userInfo: UserInfoRequestBody;
@@ -22,19 +21,16 @@ type AddressStepProps = {
const AddressStep = ({ userInfo, onNext }: AddressStepProps) => {
const [newAddress, setNewAddress] = useState(initialAddress);
- const [addressInput, setAddressInput] = useState('');
- const [addressSearchResult, setAddressSearchResult] = useState(
- [],
- );
- const [currentGeoInfo, setCurrentGeoInfo] = useState({
- lat: 0,
- lon: 0,
- });
+ const {
+ addressInput, // 주소 검색용 input 저장하는 state
+ addressSearchResult, // 주소 검색 결과를 저장하는 array
+ currentGeoInfo, // 지도에 표시할 핀에 사용되는 위/경도 좌표
+ setCurrentGeoInfo,
+ handleAddressSearch, // 검색할 주소 입력 시 실시간 검색
+ handleAddressSelect, // 검색 결과 중 원하는 주소를 선택할 시 state에 입력
+ setAddressInput,
+ } = useAddressSearch();
const { data, isSuccess } = useGetGeoInfo(setCurrentGeoInfo); // 현재 좌표 기준 주소 획득
- // 키워드로 주소 검색
- const { searchAddress } = useSearchAddress({
- onSuccess: (data) => setAddressSearchResult(data),
- });
// 첫 로딩 시 현재 사용자의 위치 파악 해 지도에 표기
useEffect(() => {
@@ -47,61 +43,15 @@ const AddressStep = ({ userInfo, onNext }: AddressStepProps) => {
});
}, [isSuccess]);
- // 검색할 주소 입력 시 실시간 검색
- const handleAddressSearch = useCallback(
- (address: string) => {
- setAddressInput(address);
- if (address !== '') {
- searchAddress(address);
- } else {
- setAddressSearchResult([]);
- }
- },
- [searchAddress],
- );
-
- // 검색 결과 중 원하는 주소를 선택할 시 state에 입력
- const handleAddressSelect = (selectedAddressName: string) => {
- const selectedAddress = addressSearchResult.find(
- (address) => address.address_name === selectedAddressName,
- ) as Document | undefined;
-
- if (!selectedAddress) return;
-
- const isRegionAddr =
- selectedAddress.address_type === AddressType.REGION_ADDR;
- const addressData = isRegionAddr
- ? selectedAddress.address
- : selectedAddress.road_address;
-
- const selectedProperties = pick(addressData, [
- 'address_name',
- 'region_1depth_name',
- 'region_2depth_name',
- 'region_3depth_name',
- ]);
+ // 검색된 주소 선택 시 state에 반영
+ const handleAddressSelection = (selectedAddressName: string) => {
+ const result = handleAddressSelect(selectedAddressName);
+ if (!result) return;
- let region4DepthName = '';
- if (isRegionAddr) {
- region4DepthName = selectedAddress.address.region_3depth_h_name || '';
- } else {
- region4DepthName = selectedAddress.road_address.road_name || '';
- }
-
- setNewAddress({
- ...newAddress,
- ...selectedProperties,
- region_4depth_name: region4DepthName,
- longitude: Number(addressData.x),
- latitude: Number(addressData.y),
- });
- setAddressInput(selectedAddress.address_name);
- setCurrentGeoInfo({
- lon: Number(selectedAddress.x),
- lat: Number(selectedAddress.y),
- });
- setAddressSearchResult([]);
+ setNewAddress({...newAddress, ...result});
+ setAddressInput(result.selectedAddressName);
};
+
return (
@@ -131,7 +81,7 @@ const AddressStep = ({ userInfo, onNext }: AddressStepProps) => {
),
(address) => address.address_name,
)}
- onSelect={handleAddressSelect}
+ onSelect={handleAddressSelection}
/>
)}
diff --git a/src/components/WriteDocuments/IntegratedApplicationWriteForm.tsx b/src/components/WriteDocuments/IntegratedApplicationWriteForm.tsx
index 23a6655..92a42ab 100644
--- a/src/components/WriteDocuments/IntegratedApplicationWriteForm.tsx
+++ b/src/components/WriteDocuments/IntegratedApplicationWriteForm.tsx
@@ -1,9 +1,7 @@
import { initialIntegratedApplication } from '@/constants/documents';
-import { useSearchAddress } from '@/hooks/api/useKaKaoMap';
import { IntegratedApplicationData } from '@/types/api/document';
-import { AddressType, Document } from '@/types/api/map';
-import { pick } from '@/utils/map';
-import { useCallback, useEffect, useState } from 'react';
+import { AddressType } from '@/types/api/map';
+import { useEffect, useState } from 'react';
import Input from '@/components/Common/Input';
import { InputType } from '@/types/common/input';
import Dropdown, { DropdownModal } from '@/components/Common/Dropdown';
@@ -29,6 +27,7 @@ import {
import { formatPhoneNumber, parsePhoneNumber } from '@/utils/information';
import { useCurrentPostIdEmployeeStore } from '@/store/url';
import LoadingItem from '../Common/LoadingItem';
+import { useAddressSearch } from '@/hooks/api/useAddressSearch';
type IntegratedApplicationFormProps = {
document?: IntegratedApplicationData;
@@ -66,24 +65,16 @@ const IntegratedApplicationWriteForm = ({
middle: '',
end: '',
});
- // 주소 검색용 input 저장하는 state
- const [addressInput, setAddressInput] = useState('');
- // 주소 검색 결과를 저장하는 array
- const [addressSearchResult, setAddressSearchResult] = useState
(
- [],
- );
- // 지도에 표시할 핀에 사용되는 위/경도 좌표
- const [currentGeoInfo, setCurrentGeoInfo] = useState({
- lat: 0,
- lon: 0,
- });
+ const {
+ addressInput, // 주소 검색용 input 저장하는 state
+ addressSearchResult, // 주소 검색 결과를 저장하는 array
+ currentGeoInfo, // 지도에 표시할 핀에 사용되는 위/경도 좌표
+ handleAddressSearch, // 검색할 주소 입력 시 실시간 검색
+ handleAddressSelect, // 검색 결과 중 원하는 주소를 선택할 시 state에 입력
+ setAddressInput,
+ } = useAddressSearch();
// 학교 선택 모달 출현 여부 관리 state
const [isModalOpen, setIsModalOpen] = useState(false);
-
- // 키워드로 주소 검색
- const { searchAddress } = useSearchAddress({
- onSuccess: (data) => setAddressSearchResult(data),
- });
const { mutate: postDocument } = usePostIntegratedApplicants(
Number(currentPostId),
{
@@ -148,68 +139,19 @@ const IntegratedApplicationWriteForm = ({
workPlacePhoneNum,
]);
- // 검색할 주소 입력 시 실시간 검색
- const handleAddressSearch = useCallback(
- (address: string) => {
- setAddressInput(address);
- if (address !== '') {
- searchAddress(address);
- } else {
- setAddressSearchResult([]);
- }
- },
- [searchAddress],
- );
-
- // 검색 결과 중 원하는 주소를 선택할 시 state에 입력
- const handleAddressSelect = (selectedAddressName: string) => {
- // 사용자가 선택한 주소와 일치하는 결과를 검색 결과를 저장하는 array에서 탐색
- const selectedAddress = addressSearchResult.find(
- (address) => address.address_name === selectedAddressName,
- ) as Document | undefined;
+ // 검색된 주소 선택 시 state에 반영
+ const handleAddressSelection = (selectedAddressName: string) => {
+ const result = handleAddressSelect(selectedAddressName);
+ if (!result) return;
- if (!selectedAddress) return;
-
- // 구 주소와 도로명 주소를 구분하기 위한 플래그(카카오에서 반환하는 속성 명이 달라짐)
- const isRegionAddr =
- selectedAddress.address_type === AddressType.REGION_ADDR;
- const addressData = isRegionAddr
- ? selectedAddress.address
- : selectedAddress.road_address;
-
- // 카카오에서 반환하는 데이터 중 필요한 속성들만 선택
- const selectedProperties = pick(addressData, [
- 'address_name',
- 'region_1depth_name',
- 'region_2depth_name',
- 'region_3depth_name',
- ]);
-
- let region4DepthName = ''; // optional property인 region4DeptName
- if (isRegionAddr) {
- region4DepthName = selectedAddress.address.region_3depth_h_name || '';
- } else {
- region4DepthName = selectedAddress.road_address.road_name || '';
- }
-
- // 선택한 데이터들을 state에 update
setNewDocumentData({
...newDocumentData,
address: {
...newDocumentData.address,
- ...selectedProperties,
- region_4depth_name: region4DepthName,
- longitude: Number(addressData.x),
- latitude: Number(addressData.y),
+ ...result.addressData,
},
});
- setAddressInput(selectedAddress.address_name);
- setCurrentGeoInfo({
- lon: Number(selectedAddress.x),
- lat: Number(selectedAddress.y),
- });
- // 검색 결과 초기화
- setAddressSearchResult([]);
+ setAddressInput(result.selectedAddressName);
};
// 문서 작성 완료 핸들러 함수
@@ -348,7 +290,7 @@ const IntegratedApplicationWriteForm = ({
),
(address) => address.address_name,
)}
- onSelect={handleAddressSelect}
+ onSelect={handleAddressSelection}
/>
)}
diff --git a/src/hooks/api/useAddressSearch.ts b/src/hooks/api/useAddressSearch.ts
new file mode 100644
index 0000000..75e0602
--- /dev/null
+++ b/src/hooks/api/useAddressSearch.ts
@@ -0,0 +1,109 @@
+import { useSearchAddress } from '@/hooks/api/useKaKaoMap';
+import { Document, AddressType, GeoPosition } from '@/types/api/map';
+import { pick } from '@/utils/map';
+import { Dispatch, SetStateAction, useCallback, useState } from 'react';
+
+interface UseAddressSearchReturn {
+ addressInput: string;
+ addressSearchResult: Document[];
+ currentGeoInfo: {
+ lat: number;
+ lon: number;
+ };
+ handleAddressSearch: (address: string) => void;
+ handleAddressSelect: (selectedAddressName: string) => {
+ addressData: {
+ address_name: string;
+ region_1depth_name: string;
+ region_2depth_name: string;
+ region_3depth_name: string;
+ region_4depth_name: string;
+ longitude: number;
+ latitude: number;
+ };
+ selectedAddressName: string;
+ };
+ setAddressInput: (address: string) => void;
+ setCurrentGeoInfo: Dispatch>;
+}
+
+export const useAddressSearch = (): UseAddressSearchReturn => {
+ const [addressInput, setAddressInput] = useState('');
+ const [addressSearchResult, setAddressSearchResult] = useState([]);
+ const [currentGeoInfo, setCurrentGeoInfo] = useState({
+ lat: 0,
+ lon: 0,
+ });
+
+ const { searchAddress } = useSearchAddress({
+ onSuccess: (data) => setAddressSearchResult(data),
+ });
+
+ const handleAddressSearch = useCallback(
+ (address: string) => {
+ setAddressInput(address);
+ if (address !== '') {
+ searchAddress(address);
+ } else {
+ setAddressSearchResult([]);
+ }
+ },
+ [searchAddress],
+ );
+
+ const handleAddressSelect = (selectedAddressName: string) => {
+ const selectedAddress = addressSearchResult.find(
+ (address) => address.address_name === selectedAddressName,
+ );
+
+ if (!selectedAddress) return;
+
+ const isRoadAddr = selectedAddress.address_type === AddressType.ROAD_ADDR;
+ const addressData = isRoadAddr
+ ? selectedAddress.road_address
+ : selectedAddress.address;
+
+ const selectedProperties = pick(addressData, [
+ 'address_name',
+ 'region_1depth_name',
+ 'region_2depth_name',
+ 'region_3depth_name',
+ ]);
+
+ const region4DepthName = isRoadAddr
+ ? selectedAddress.road_address.road_name || ''
+ : selectedAddress.address.region_3depth_h_name || '';
+
+ setCurrentGeoInfo({
+ lon: Number(selectedAddress.x),
+ lat: Number(selectedAddress.y),
+ });
+ setAddressSearchResult([]);
+ setAddressInput(selectedAddress.address_name);
+ return {
+ addressData: {
+ ...selectedProperties,
+ region_4depth_name: region4DepthName,
+ longitude: Number(addressData.x),
+ latitude: Number(addressData.y),
+ },
+ selectedAddressName,
+ };
+ };
+
+ return {
+ addressInput,
+ addressSearchResult,
+ currentGeoInfo,
+ handleAddressSearch,
+ handleAddressSelect: (selectedAddressName: string) => {
+ const result = handleAddressSelect(selectedAddressName);
+ if (!result) {
+ throw new Error('주소를 찾을 수 없습니다');
+ }
+ return result;
+ },
+ setAddressInput,
+ setCurrentGeoInfo,
+ };
+};
\ No newline at end of file
From ad61e6d7b639028ec8a466766c42b7674793d339 Mon Sep 17 00:00:00 2001
From: Savien/Woo Jun Han <49388937+MrMirror21@users.noreply.github.com>
Date: Sun, 22 Dec 2024 22:05:51 +0900
Subject: [PATCH 9/9] =?UTF-8?q?=F0=9F=90=9B=20fix:=20=EC=8B=9C=EA=B8=89=20?=
=?UTF-8?q?=EC=9E=85=EB=A0=A5=20=EC=8B=9C=20=EC=B5=9C=EC=A0=80=EC=9E=84?=
=?UTF-8?q?=EA=B8=88=20=EC=9D=B4=EC=83=81=EC=9D=B8=EC=A7=80=20=EA=B2=80?=
=?UTF-8?q?=EC=A6=9D=20#127?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/utils/document.ts | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/utils/document.ts b/src/utils/document.ts
index 685810b..1ff6ba4 100644
--- a/src/utils/document.ts
+++ b/src/utils/document.ts
@@ -177,8 +177,10 @@ export const validateLaborContractEmployerInformation = (
// number만 가능한 필드에서 NaN 입력으로 input이 멈추지 않게 값 검증
export const parseStringToSafeNumber = (value: string): number => {
const numberValue = Number(value);
+ const minimumWage2025 = 10030;
if (isNaN(numberValue)) return 0;
+ if (!isNaN(numberValue) && numberValue < minimumWage2025) return 0;
else return numberValue;
};