Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/#90 이력서 열람 페이지 구현 #100

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ const Section = styled.div`
align-items: center;
margin-bottom: 52px;
`;
```
```
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/apis/apiPath.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const APIPath = {
registerCompany: `${BASE_URL}/company`,
apply: '/api/application/',
recruitmentsDetail: '/api/recruitments/:postId',
getApplicantProfile: '/api/resumes/:resumeId/:applyId',
closeRecruitment: `${BASE_URL}/recruitment/hiringClose/:recruitmentId`,
};

Expand All @@ -27,6 +28,8 @@ export const getDynamicAPIPath = {
APIPath.getMyApplicants.replace(':recruitmentId', recruitmentId.toString()),
getForeigner: (userId: number) => APIPath.getForeigner.replace(':userId', userId.toString()),
recruitmentsDetail: (postId: string) => APIPath.recruitmentsDetail.replace(':postId', postId.toString()),
getApplicantProfile: (resumeId: number, applyId: number) =>
APIPath.getApplicantProfile.replace(':resumeId', resumeId.toString()).replace(':applyId', applyId.toString()),
closeRecruitment: (recruitmentId: number) =>
APIPath.closeRecruitment.replace(':recruitmentId', recruitmentId.toString()),
};
19 changes: 19 additions & 0 deletions src/apis/applicants/hooks/useGetProfileInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { getDynamicAPIPath } from '@/apis/apiPath';
import { clientInstance } from '@/apis/instance';
import { useQuery } from '@tanstack/react-query';

type IdProps = {
resumeId: number;
applyId: number;
};

export const getProfileInfo = async ({ resumeId, applyId }: IdProps) => {
const response = await clientInstance.get(getDynamicAPIPath.getApplicantProfile(resumeId, applyId));
return response.data;
};

export const useGetProfileInfo = ({ resumeId, applyId }: IdProps) =>
useQuery({
queryKey: [getDynamicAPIPath.getApplicantProfile(resumeId, applyId)],
queryFn: () => getProfileInfo({ resumeId, applyId }),
});
18 changes: 18 additions & 0 deletions src/apis/applicants/mocks/getApplicantProfile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { http, HttpResponse } from 'msw';
import { APIPath } from '@/apis/apiPath';

const mockData = {
applicantName: '임세빈',
address: '충남대학교',
phoneNumber: '010-1111-1111',
career: `카페에서 1년 알바했습니다. 클럽에서 30년 근무했습니다.`,
koreanLanguageLevel: '고급',
introduction: `맡은 업무에 항상 최선을 다하는 인재입니다. 안녕하세용안녕하세용안녕하세용안녕하세용안녕하세용안녕하세용`,
motivation: '돈',
};

export const getProfileInfoHandler = [
http.get(APIPath.getApplicantProfile, () => {
return HttpResponse.json(mockData);
}),
];
2 changes: 2 additions & 0 deletions src/mocks/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { postApplyMockHandler } from '@apis/apply/postApply.mock';
import { recruitmentsDetailMockHandler } from '@apis/recruitmentsDetail/recruitmentsDetailMockHandler';
import { registerCompanyMockHandler } from '@/apis/registerCompany/registerCompany.mock';
import { contractsMockHandler } from '@/apis/contract/mock/contract.mock';
import { getProfileInfoHandler } from '@/apis/applicants/mocks/getApplicantProfile';
import { closeRecruitmentMockHandler } from '@/apis/recruitments/mocks/closeRecruitmentMockHandler';

export const handlers = [
Expand All @@ -29,5 +30,6 @@ export const handlers = [
...recruitmentsDetailMockHandler,
...registerCompanyMockHandler,
...contractsMockHandler,
...getProfileInfoHandler,
...closeRecruitmentMockHandler,
];
60 changes: 60 additions & 0 deletions src/pages/applicantsPage/ApplicantList/ApplicantProfile.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { useGetProfileInfo } from '@/apis/applicants/hooks/useGetProfileInfo';
import { Flex, Typo } from '@/components/common';
import styled from '@emotion/styled';
import { Spinner } from '@/components/common';

type ProfileInfoProps = {
title: string;
content: string;
};
function ProfileInfo({ title, content }: ProfileInfoProps) {
return (
<>
<Flex>
<Flex direction="column" gap={{ y: '20px' }}>
<Typo bold={true}>{title}</Typo>
<Typo>{content}</Typo>
</Flex>
</Flex>
<Divider />
</>
);
}

export default function ApplicantProfile({ resumeId, applyId }: { resumeId: number; applyId: number }) {
const { data, isLoading } = useGetProfileInfo({ resumeId, applyId });

if (isLoading) {
return <Spinner />;
}
return (
<Flex css={{ padding: '10px', width: '100%' }} direction="column">
<Typo bold={true} size="18px">
{data.applicantName}님의 지원서입니다.
</Typo>
<Flex gap={{ x: '10px' }} css={{ marginTop: '20px' }}>
<Flex direction="column" gap={{ y: '5px' }} css={{ flex: 2 }}>
<Typo>연락처</Typo>
<Typo>주소</Typo>
</Flex>
<Flex direction="column" gap={{ y: '5px' }} css={{ flex: 8 }}>
<Typo>{data.phoneNumber}</Typo>
<Typo>{data.address}</Typo>
</Flex>
</Flex>
<Divider />
<ProfileInfo title="한국어 실력" content={data.koreanLanguageLevel} />
<ProfileInfo title="경력" content={data.career} />
<ProfileInfo title="자기소개서" content={data.introduction} />
<ProfileInfo title="지원동기" content={data.motivation} />
</Flex>
);
}

const Divider = styled.div`
width: 100%;
height: 1px;
opacity: 0.7;
margin: 20px 0;
background-color: #e9e9e9;
`;
35 changes: 33 additions & 2 deletions src/pages/applicantsPage/ApplicantList/ApplicantsTable.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
import { Button, Flex, List, Table, Td, Th } from '@/components/common';
import { Button, Flex, List, Table, Td, Th, Modal } from '@/components/common';
import { useState } from 'react';
import ContractModal from './Contract/ContractModal';
import { ApplicantData } from '@/types';
import { buttonGroupStyle, buttonsCellStyle, buttonStyle } from './ApplicantsTable.styles';
import ApplicantProfile from '../ApplicantList/ApplicantProfile';
import useToggle from '@/hooks/useToggle';

type IdProps = {
resumeId: number;
applyId: number;
};
type Props = {
applicantList: ApplicantData[];
};

export default function ApplicantsTable({ applicantList }: Props) {
const [isModalOpen, setIsModalOpen] = useState(false);
const [IdInfo, setIdInfo] = useState<IdProps | null>(null);
const [selectedUserId, setSelectedUserId] = useState<number | null>(null);
const [isToggle, toggle] = useToggle();
const [selectedApplyId, setSelectedApplyId] = useState<number | null>(null);

const openModal = (userId: number, applyId: number) => {
Expand All @@ -25,6 +33,10 @@ export default function ApplicantsTable({ applicantList }: Props) {
setSelectedApplyId(null);
};

const profileOpenModal = ({ resumeId, applyId }: IdProps) => {
setIdInfo((prev) => ({ ...prev, resumeId, applyId }));
toggle();
};
return (
<>
<Table>
Expand All @@ -46,7 +58,12 @@ export default function ApplicantsTable({ applicantList }: Props) {
<Td>{applicant.korean}</Td>
<Td css={buttonsCellStyle}>
<Flex justifyContent="flex-end" alignItems="center" gap={{ x: '20px' }} css={buttonGroupStyle}>
<Button css={buttonStyle}>지원서</Button>
<Button
onClick={() => profileOpenModal({ resumeId: applicant.resumeId, applyId: applicant.applyId })}
css={buttonStyle}
>
지원서
</Button>
<Button css={buttonStyle} onClick={() => openModal(applicant.userId, applicant.applyId)}>
계약하기
</Button>
Expand All @@ -60,6 +77,20 @@ export default function ApplicantsTable({ applicantList }: Props) {
{selectedUserId && selectedApplyId && (
<ContractModal isOpen={isModalOpen} close={closeModal} userId={selectedUserId} applyId={selectedApplyId} />
)}
{isToggle && IdInfo && (
<Modal
css={{
width: '100%',
maxWidth: '450px',
'@media (max-width: 480px)': {
width: '90%',
},
}}
textChildren={<ApplicantProfile resumeId={IdInfo.resumeId} applyId={IdInfo.applyId} />}
buttonChildren={<Button onClick={toggle}>닫기</Button>}
onClose={toggle}
/>
)}
</>
);
}
Loading