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/#69 API 연동 #80

Merged
merged 9 commits into from
Oct 29, 2024
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
4,243 changes: 2,545 additions & 1,698 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"axios": "^1.7.7",
"buffer": "^6.0.3",
"csstype": "^3.1.3",
"jquery": "^3.7.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-error-boundary": "^4.1.2",
Expand Down
15 changes: 12 additions & 3 deletions public/mockServiceWorker.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
* - Please do NOT serve this file on production.
*/

const PACKAGE_VERSION = '2.4.6';
const INTEGRITY_CHECKSUM = '26357c79639bfa20d64c0efca2a87423';
const PACKAGE_VERSION = '2.5.2';
const INTEGRITY_CHECKSUM = '07a8241b182f8a246a7cd39894799a9e';
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse');
const activeClientIds = new Set();

Expand Down Expand Up @@ -61,7 +61,12 @@ self.addEventListener('message', async function (event) {

sendToClient(client, {
type: 'MOCKING_ENABLED',
payload: true,
payload: {
client: {
id: client.id,
frameType: client.frameType,
},
},
});
break;
}
Expand Down Expand Up @@ -154,6 +159,10 @@ async function handleRequest(event, requestId) {
async function resolveMainClient(event) {
const client = await self.clients.get(event.clientId);

if (activeClientIds.has(event.clientId)) {
return client;
}

if (client?.frameType === 'top-level') {
return client;
}
Expand Down
11 changes: 11 additions & 0 deletions src/apis/apiPath.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
const BASE_URL = '/api';

export const APIPath = {
postNotice: '/api/recruitments',
allApplication: '/api/application/all',
signEmployeeContract: '/api/contract',
makeEmployerContract: '/api/categories',
downloadContract: '/api/contract/:applyId/download',
registerSign: '/api/sign',
getMyCompanies: `${BASE_URL}/company`,
getMyRecruitments: `${BASE_URL}/recruitments/company/:companyId`,
getMyApplicants: `${BASE_URL}/application/:recruitmentId`,
getForeigner: `${BASE_URL}/visa/:userId`,
setVisa: `${BASE_URL}/visa`,
apply: '/api/application/',
};

export const getDynamicAPIPath = {
downloadContract: (applyId: number) => APIPath.downloadContract.replace(':applyId', applyId.toString()),
getMyRecruitments: (companyId: number) => APIPath.getMyRecruitments.replace(':companyId', companyId.toString()),
getMyApplicants: (recruitmentId: number) =>
APIPath.getMyApplicants.replace(':recruitmentId', recruitmentId.toString()),
getForeigner: (userId: number) => APIPath.getForeigner.replace(':userId', userId.toString()),
};
14 changes: 14 additions & 0 deletions src/apis/applicants/hooks/useGetForeigner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { getDynamicAPIPath } from '@/apis/apiPath';
import { clientInstance } from '@/apis/instance';
import { useQuery } from '@tanstack/react-query';

const getForeigner = async (userId: number) => {
const res = await clientInstance.get(getDynamicAPIPath.getForeigner(userId));
return res.data;
};

export const useGetForeigner = (userId: number) =>
useQuery({
queryKey: ['foreigner', userId],
queryFn: () => getForeigner(userId),
});
14 changes: 14 additions & 0 deletions src/apis/applicants/hooks/useGetMyApplicants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { getDynamicAPIPath } from '@/apis/apiPath';
import { clientInstance } from '@/apis/instance';
import { useQuery } from '@tanstack/react-query';

const getMyApplicants = async (recruitmentId: number) => {
const res = await clientInstance.get(getDynamicAPIPath.getMyApplicants(recruitmentId));
return res.data;
};

export const useGetMyApplicants = (recruitmentId: number) =>
useQuery({
queryKey: ['myApplicants'],
queryFn: () => getMyApplicants(recruitmentId),
});
16 changes: 16 additions & 0 deletions src/apis/applicants/hooks/useRegisterVisaInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { APIPath } from '@/apis/apiPath';
import { clientInstance } from '@/apis/instance';
import { ForeignerData } from '@/types';
import { useMutation } from '@tanstack/react-query';

type VisaRequest = Pick<ForeignerData, 'foreignerIdNumber' | 'visaGenerateDate'>;

const registerVisaInfo = async (req: VisaRequest) => {
const res = await clientInstance.put(APIPath.setVisa, req);
return res.data;
};

export const useRegisterVisaInfo = () =>
useMutation({
mutationFn: registerVisaInfo,
});
5 changes: 5 additions & 0 deletions src/apis/applicants/mocks/foreignerMockHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { APIPath } from '@/apis/apiPath';
import { foreigner } from '@/features/applicants/ApplicantList/ContractModal/index.mock';
import { http, HttpResponse } from 'msw';

export const foreignerMockHandler = [http.get(APIPath.getForeigner, () => HttpResponse.json(foreigner))];
5 changes: 5 additions & 0 deletions src/apis/applicants/mocks/myApplicantsMockHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { APIPath } from '@/apis/apiPath';
import { applicantList } from '@/pages/applicants/index.mock';
import { http, HttpResponse } from 'msw';

export const myApplicantsMockHandler = [http.get(APIPath.getMyApplicants, () => HttpResponse.json(applicantList))];
9 changes: 9 additions & 0 deletions src/apis/applicants/mocks/visaMockHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { APIPath } from '@/apis/apiPath';
import { http, HttpResponse } from 'msw';

export const visaMockHandler = [
http.put(APIPath.setVisa, async ({ request }) => {
const req = await request.json();
return HttpResponse.json(req, { status: 200 });
}),
];
14 changes: 14 additions & 0 deletions src/apis/companies/hooks/useGetMyCompanies.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { APIPath } from '@/apis/apiPath';
import { clientInstance } from '@/apis/instance';
import { useQuery } from '@tanstack/react-query';

const getMyCompanies = async () => {
const res = await clientInstance.get(APIPath.getMyCompanies);
return res.data;
};

export const useGetMyCompanies = () =>
useQuery({
queryKey: ['myCompanies'],
queryFn: getMyCompanies,
});
5 changes: 5 additions & 0 deletions src/apis/companies/mocks/myCompaniesMockHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { APIPath } from '@/apis/apiPath';
import { companyList } from '@/pages/myAccount/employer/index.mock';
import { http, HttpResponse } from 'msw';

export const myCompaniesMockHandler = [http.get(APIPath.getMyCompanies, () => HttpResponse.json(companyList))];
14 changes: 14 additions & 0 deletions src/apis/recruitments/hooks/useGetMyRecruitments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { getDynamicAPIPath } from '@/apis/apiPath';
import { clientInstance } from '@/apis/instance';
import { useQuery } from '@tanstack/react-query';

const getMyRecruitments = async (companyId: number) => {
const res = await clientInstance.get(getDynamicAPIPath.getMyRecruitments(companyId));
return res.data;
};

export const useGetMyRecruitments = (companyId: number) =>
useQuery({
queryKey: ['myRecruitments'],
queryFn: () => getMyRecruitments(companyId),
});
7 changes: 7 additions & 0 deletions src/apis/recruitments/mocks/myRecruitmentsMockHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { APIPath } from '@/apis/apiPath';
import { recruitmentList } from '@/pages/myCompany/index.mock';
import { http, HttpResponse } from 'msw';

export const myRecruitmentsMockHandler = [
http.get(APIPath.getMyRecruitments, () => HttpResponse.json(recruitmentList)),
];
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ type Props = {

export default function ApplicantsTable({ applicantList }: Props) {
const [isModalOpen, setIsModalOpen] = useState(false);
const [selectedUserId, setSelectedUserId] = useState<number | null>(null);

const handleOpenModal = () => {
const handleOpenModal = (userId: number) => {
setSelectedUserId(userId);
setIsModalOpen(true);
};

const handleCloseModal = () => {
setIsModalOpen(false);
setSelectedUserId(null);
};

return (
Expand All @@ -42,7 +45,7 @@ export default function ApplicantsTable({ applicantList }: Props) {
<Flex justifyContent="flex-end" alignItems="center" gap={{ x: '20px' }} css={buttonGroupStyle}>
<Button css={buttonStyle}>이력서</Button>
<Button css={buttonStyle}>지원서</Button>
<Button css={buttonStyle} onClick={handleOpenModal}>
<Button css={buttonStyle} onClick={() => handleOpenModal(applicant.userId)}>
계약하기
</Button>
</Flex>
Expand All @@ -52,7 +55,7 @@ export default function ApplicantsTable({ applicantList }: Props) {
/>
</tbody>
</Table>
<ContractModal isOpen={isModalOpen} onClose={handleCloseModal} />
{selectedUserId && <ContractModal isOpen={isModalOpen} onClose={handleCloseModal} userId={selectedUserId} />}
</>
);
}
10 changes: 6 additions & 4 deletions src/features/applicants/ApplicantList/ContractModal/index.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import { Button, Flex, Icon, Modal, Typo } from '@/components/common';
import ModalText from './ModalText';
import { foreigner } from './index.mock';
import { buttonTextStyle, customButtonStyle, modalStyle } from './index.styles';
import { useGetForeigner } from '@/apis/applicants/hooks/useGetForeigner';

interface ContractModalProps {
isOpen: boolean;
onClose: () => void;
userId: number;
}

export default function ContractModal({ isOpen, onClose }: ContractModalProps) {
export default function ContractModal({ isOpen, onClose, userId }: ContractModalProps) {
const { data: foreigner } = useGetForeigner(userId);

return (
<>
{isOpen && (
{isOpen && foreigner && (
<Modal
textChildren={
<ModalText foreignerIdNumber={foreigner.foreignerIdNumber} visaGenerateDate={foreigner.visaGenerateDate} />
Expand All @@ -29,7 +32,6 @@ export default function ContractModal({ isOpen, onClose }: ContractModalProps) {
</Button>
</Flex>
}
/* onClose 부분 추후 수정 예정 */
onClose={onClose}
style={modalStyle}
/>
Expand Down
12 changes: 10 additions & 2 deletions src/features/companies/CompanyList/CompaniesTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,20 @@ import { Button, Flex, Icon, List, Image, Table, Th, Td } from '@/components/com
import { CompanyData } from '@/types';
import CompanyInfo from '@/features/companies/CompanyInfo';
import { cellStyle, imageSize, imageStyle } from './index.styles';
import { useNavigate } from 'react-router-dom';
import ROUTE_PATH from '@/routes/path';

type Props = {
companyList: CompanyData[];
};

export default function CompaniesTable({ companyList }: Props) {
const navigate = useNavigate();

const handleCompanyClick = (companyId: number) => {
navigate(ROUTE_PATH.MY_COMPANY.replace(':companyId', companyId.toString()));
};

return (
<Table>
<thead>
Expand All @@ -19,7 +27,7 @@ export default function CompaniesTable({ companyList }: Props) {
<List
items={companyList}
renderItem={(company) => (
<tr key={company.id}>
<tr key={company.companyId}>
<Td>
<Flex justifyContent="space-between" alignItems="center" gap={{ x: '100px' }} css={cellStyle}>
<Image url={company.logoImage} size={imageSize} css={imageStyle} />
Expand All @@ -30,7 +38,7 @@ export default function CompaniesTable({ companyList }: Props) {
brand={company.brand}
revenuePerYear={company.revenuePerYear}
/>
<Button design="textbutton">
<Button design="textbutton" onClick={() => handleCompanyClick(company.companyId)}>
<Icon.Arrow.BigRightBlue />
</Button>
</Flex>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
import { Button, Flex, List, Table, Td, Th, Typo } from '@/components/common';
import { RecruitmentItem } from '@/types';
import { buttonGroupStyle, buttonStyle, recruitmentStyle, recruitmentTitleStyle } from './index.styles';
import { useNavigate, useParams } from 'react-router-dom';
import ROUTE_PATH from '@/routes/path';

type Props = {
recruitmentList: RecruitmentItem[];
};

export default function RecruitmentsTable({ recruitmentList }: Props) {
const navigate = useNavigate();
const { companyId } = useParams();

const handleApplicantClick = (companyId: string, recruitmentId: number) => {
navigate(
ROUTE_PATH.APPLICANTS.replace(':companyId', companyId).replace(':recruitmentId', recruitmentId.toString()),
);
};

return (
<Table>
<thead>
Expand All @@ -32,7 +43,12 @@ export default function RecruitmentsTable({ recruitmentList }: Props) {
</Typo>
</Flex>
<Flex css={buttonGroupStyle}>
<Button css={buttonStyle}>지원자 보러가기</Button>
<Button
css={buttonStyle}
onClick={() => handleApplicantClick(companyId!, recruitment.recruitmentId)}
>
지원자 보러가기
</Button>
<Button css={buttonStyle}>마감하기</Button>
</Flex>
</Flex>
Expand Down
22 changes: 18 additions & 4 deletions src/features/visaRegistration/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ import { Button, Flex, Input, Modal } from '@/components/common';
import { ChangeEvent, useMemo, useState } from 'react';
import { buttonStyle, ErrorMessage, Form, inputStyle } from './index.styles';
import { validateForeignerNumber } from './validateForeignerNumber';
import { useRegisterVisaInfo } from '@/apis/applicants/hooks/useRegisterVisaInfo';

export default function VisaRegistrationForm() {
const [foreignerNumber, setForeignerNumber] = useState('');
const [foreignerIdNumber, setForeignerNumber] = useState('');
const [visaGenerateDate, setVisaGenerateDate] = useState('');
const [error, setError] = useState('');
const [isModalOpen, setIsModalOpen] = useState(false);
const formValid = useMemo(() => !error, [error]);

const registerVisaMutation = useRegisterVisaInfo();

const handleForeignerNumberChange = (e: ChangeEvent<HTMLInputElement>) => {
const { value } = e.target;
if (!validateForeignerNumber(value) && value !== '') {
Expand All @@ -22,7 +25,19 @@ export default function VisaRegistrationForm() {

const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setIsModalOpen(true);
registerVisaMutation.mutate(
{ foreignerIdNumber, visaGenerateDate },
{
onSuccess: () => {
setForeignerNumber('');
setVisaGenerateDate('');
setIsModalOpen(true);
},
onError: (err) => {
console.error(err);
},
},
);
};

const closeModal = () => {
Expand All @@ -36,7 +51,7 @@ export default function VisaRegistrationForm() {
<Input
label="외국인 번호"
type="text"
value={foreignerNumber}
value={foreignerIdNumber}
onChange={handleForeignerNumberChange}
css={inputStyle}
required
Expand All @@ -63,7 +78,6 @@ export default function VisaRegistrationForm() {
<Modal
textChildren="등록이 완료되었습니다."
buttonChildren={<Button onClick={closeModal}>확인</Button>}
/* onClose 부분 추후 수정 예정 */
onClose={closeModal}
/>
)}
Expand Down
Loading
Loading