Skip to content

Commit

Permalink
✨ feat: 유학생 문서 컨펌, 최종 생성 시 로딩 ui 적용 Team-inglo#127
Browse files Browse the repository at this point in the history
  • Loading branch information
naarang committed Jan 22, 2025
1 parent 89ebc87 commit b548748
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 47 deletions.
20 changes: 18 additions & 2 deletions src/components/Document/DocumentCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type DocumentCardProps = {
title: string;
type: string;
onNext?: () => void;
setIsLoading: (value: boolean) => void;
};

const TemporarySaveCard = ({
Expand Down Expand Up @@ -331,9 +332,24 @@ const DocumentCardDispenser = ({
documentInfo,
title,
type,
setIsLoading,
}: DocumentCardProps) => {
const { mutate: submitDocument } = usePatchStatusSubmission();
const { mutate: confirmDocument } = usePatchDocumentsStatusConfirmation();
const { mutate: submitDocument } = usePatchStatusSubmission({
onMutate: () => {
setIsLoading(true);
},
onSettled: () => {
setIsLoading(false);
},
});
const { mutate: confirmDocument } = usePatchDocumentsStatusConfirmation({
onMutate: () => {
setIsLoading(true);
},
onSettled: () => {
setIsLoading(false);
},
});
const navigate = useNavigate();
const { updateCurrentDocumentId } = useCurrentDocumentIdStore();
const handleDownload = (url: string) => {
Expand Down
55 changes: 35 additions & 20 deletions src/components/Document/DocumentCardList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ import {
usePatchDocumentsStatusConfirmation,
usePatchStatusSubmission,
} from '@/hooks/api/useDocument';
import { useState } from 'react';
import LoadingItem from '../Common/LoadingItem';

const DocumentCardList = ({
documents,
}: {
documents: DocumentsSummaryResponse;
}) => {
const documentTypes = Object.values(DocumentType);
const [isLoading, setIsLoading] = useState(false);
// patch api mutate 설정 (8.15 유학생이 서류 제출하기)
const { mutate: patchStatusSubmission } = usePatchStatusSubmission();

Expand All @@ -31,27 +34,39 @@ const DocumentCardList = ({
};

return (
<div className="flex flex-col w-full px-6 gap-2 pb-[8rem]">
{documentTypes.map((property, index) =>
documents[property] ? (
<DocumentCardDispenser
key={`${index}_${property}`}
documentInfo={documents[property]}
title={DocumentTypeInfo[property].name}
type={property}
// null 체크 추가
onNext={() => {
const document = documents[property];
if (document && document.status) {
handleOnNext(document.id, document.status);
}
}}
/>
) : (
<MakeDocumentButton type={property} key={`${index}_${property}`} />
),
<>
{isLoading && (
<div
className="fixed inset-0 z-50 flex items-center justify-center bg-white bg-opacity-50 overflow-hidden"
style={{ touchAction: 'none' }}
onClick={(e) => e.preventDefault()}
>
<LoadingItem />
</div>
)}
</div>
<div className="flex flex-col w-full px-6 gap-2 pb-[8rem]">
{documentTypes.map((property, index) =>
documents[property] ? (
<DocumentCardDispenser
key={`${index}_${property}`}
documentInfo={documents[property]}
title={DocumentTypeInfo[property].name}
type={property}
// null 체크 추가
onNext={() => {
const document = documents[property];
if (document && document.status) {
handleOnNext(document.id, document.status);
}
}}
setIsLoading={(value: boolean) => setIsLoading(value)}
/>
) : (
<MakeDocumentButton type={property} key={`${index}_${property}`} />
),
)}
</div>
</>
);
};

Expand Down
13 changes: 5 additions & 8 deletions src/components/Information/StepIndicator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,20 @@ const StepIndicator = ({
length = 3,
currentStep = 1,
mainColor = '#FEF387',
backgroundColor = '#F4F4F9',
backgroundColor = '#FFFFFF',
borderColor = '#F4F4F9',
textColor = '#ffffff',
textColor = '#222',
inactiveTextColor = '#BDBDBD',
}: StepIndicatorProps) => {
const steps = Array.from({ length }, (_, i) => i + 1);

return (
<div
className="relative w-full flex flex-row items-center justify-center text-center body-3"
>
<div className="relative w-full flex flex-row items-center justify-center text-center body-3">
{steps.map((step, index) => (
<React.Fragment key={step}>
{/* Step Circle */}
<div
className="relative flex items-center justify-center w-6 h-6"
style={{
color: textColor ,
}}
>
<div
className="flex items-center justify-center w-5 h-5 rounded-full"
Expand All @@ -40,6 +36,7 @@ const StepIndicator = ({
currentStep >= step ? mainColor : backgroundColor,
border:
currentStep >= step ? 'none' : `1px solid ${borderColor}`,
color: currentStep >= step ? textColor : inactiveTextColor,
}}
>
{step}
Expand Down
9 changes: 6 additions & 3 deletions src/components/WriteDocuments/PartTimePermitWriteForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { phone } from '@/constants/information';
import EmployerInfoSection from '@/components/Document/write/EmployerInfoSection';
import BottomButtonPanel from '@/components/Common/BottomButtonPanel';
import Button from '@/components/Common/Button';
import { isNotEmpty } from '@/utils/document';
import { validatePartTimePermit } from '@/utils/document';
import { formatPhoneNumber, parsePhoneNumber } from '@/utils/information';
import {
usePostPartTimeEmployPermit,
Expand Down Expand Up @@ -265,8 +265,11 @@ const PartTimePermitWriteForm = ({
</div>

<BottomButtonPanel>
{/* 입력된 정보 중 빈 칸이 없다면 활성화 */}
{isNotEmpty(newDocumentData) && isNotEmpty(phoneNum) ? (
{/* 입력된 정보의 유효성 검사 통과 시 활성화 */}
{validatePartTimePermit({
...newDocumentData,
phone_number: formatPhoneNumber(phoneNum),
}) ? (
<Button
type="large"
bgColor="bg-[#fef387]"
Expand Down
20 changes: 11 additions & 9 deletions src/hooks/api/useDocument.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,9 @@ export const usePutIntegratedApplicants = (
};

// 8.15 (유학생) 서류 (근로계약서, 시간제 취업허가서, 통합 신청서) 제출하기 api hook
export const usePatchStatusSubmission = () => {
export const usePatchStatusSubmission = (
options?: UseMutationOptions<RESTYPE<null>, Error, number>,
) => {
return useMutation({
mutationFn: patchStatusSubmission,
onSuccess: () => {
Expand All @@ -265,16 +267,13 @@ export const usePatchStatusSubmission = () => {
onError: (error) => {
console.error('유학생의 서류 제출 실패', error);
},
...options,
});
};

// 8.16 (고용주) 서류 (근로계약서, 시간제 취업허가서, 통합 신청서) 제출하기 api hook
export const usePatchStatusSubmissionEmployer = (
options?: UseMutationOptions<
RESTYPE<null>,
Error,
number
>,
options?: UseMutationOptions<RESTYPE<null>, Error, number>,
) => {
return useMutation({
mutationFn: patchStatusSubmissionEmployer,
Expand All @@ -284,12 +283,14 @@ export const usePatchStatusSubmissionEmployer = (
onError: (error) => {
console.error('고용주의 서류 제출 실패', error);
},
...options
...options,
});
};

// 8.17 (유학생) 서류 (근로계약서, 시간제 취업허가서) 컴펌하기
export const usePatchDocumentsStatusConfirmation = () => {
// 8.17 (유학생) 서류 (근로계약서, 시간제 취업허가서) 컨펌하기
export const usePatchDocumentsStatusConfirmation = (
options?: UseMutationOptions<RESTYPE<null>, Error, number>,
) => {
return useMutation({
mutationFn: patchDocumentsStatusConfirmation,
onSuccess: () => {
Expand All @@ -298,6 +299,7 @@ export const usePatchDocumentsStatusConfirmation = () => {
onError: (error) => {
console.error('유학생의 서류 컨펌 실패', error);
},
...options,
});
};

Expand Down
56 changes: 51 additions & 5 deletions src/utils/document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import {
Insurance,
IntegratedApplicationData,
LaborContractEmployerInfo,
PartTimePermitFormRequest,
WorkDayTime,
} from '@/types/api/document';
import { Address } from '@/types/api/users';
import { extractNumbersAsNumber } from './post';
import { InsuranceInfo } from '@/constants/documents';
import { isValidPhoneNumber, parsePhoneNumber } from './information';
import { parsePhoneNumber } from './information';

export const MINIMUM_HOURLY_RATE = 10030;

Expand All @@ -31,6 +32,51 @@ export const isNotEmpty = (obj: Record<string, any>): boolean => {
});
};

// string data의 공백 여부를 확인하는 함수
const hasStringValue = (value: string): boolean => {
return value.trim().length > 0;
};

// 이메일 유효성 검사 함수
const isEmailValid = (email: string): boolean => {
const emailRegex = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/;
return emailRegex.test(email);
};

// 전화번호 유효성 검사 함수
const isValidPhoneNumber = (phone: string) => {
const phoneNum = parsePhoneNumber(phone);
return (
phoneNum.start !== '' &&
/^[0-9]{4}$/.test(phoneNum.middle) &&
/^[0-9]{4}$/.test(phoneNum.end)
);
};

// 이수학기 유효성 검사 함수
const isValidTermOfCompletion = (term: number): boolean => {
return !isNaN(term) && term > 0;
};

// (유학생) 시간제 근로 허가서 유효성 검사 함수
export const validatePartTimePermit = (
data: PartTimePermitFormRequest,
): boolean => {
// 필수 입력 항목 체크(이름, 성, 전화번호, 이메일, 이수학기, 전화번호)
if (
hasStringValue(data.first_name) &&
hasStringValue(data.last_name) &&
hasStringValue(data.phone_number) &&
isEmailValid(data.email) &&
isValidPhoneNumber(data.phone_number) &&
isValidTermOfCompletion(data.term_of_completion)
) {
return true;
}

return false;
};

export const workDayTimeToString = (workDayTimes: WorkDayTime[]): string => {
// 요일만 추출하여 배열로 만들기
const daysOfWeek = workDayTimes.map((wdt) => wdt.day_of_week);
Expand Down Expand Up @@ -239,10 +285,10 @@ export const validateIntegratedApplication = (

// 전화번호 필드들 검사
const isPhoneValid =
isValidPhoneNumber(parsePhoneNumber(data.tele_phone_number)) &&
isValidPhoneNumber(parsePhoneNumber(data.cell_phone_number)) &&
isValidPhoneNumber(parsePhoneNumber(data.school_phone_number)) &&
isValidPhoneNumber(parsePhoneNumber(data.new_work_place_phone_number));
isValidPhoneNumber(data.tele_phone_number) &&
isValidPhoneNumber(data.cell_phone_number) &&
isValidPhoneNumber(data.school_phone_number) &&
isValidPhoneNumber(data.new_work_place_phone_number);
// 나머지 필드 검사
const otherFieldsValid = Object.entries(data).every(([key, value]) => {
// 앞서 검사한 필드들은 스킵
Expand Down

0 comments on commit b548748

Please sign in to comment.