diff --git a/src/api/applicant.api.ts b/src/api/applicant.api.ts
index 1feba80e..b1bf3110 100644
--- a/src/api/applicant.api.ts
+++ b/src/api/applicant.api.ts
@@ -26,3 +26,10 @@ export const patchPassNonPassStatus = async (
);
return response.data;
};
+
+export const getPassNonPassList = async (projectId: number) => {
+ const response = await httpClient.get(
+ `/project/${projectId}/applicant/summary`
+ );
+ return response.data;
+};
diff --git a/src/components/common/noContent/NoContent.tsx b/src/components/common/noContent/NoContent.tsx
index 55e36c8e..47eb3349 100644
--- a/src/components/common/noContent/NoContent.tsx
+++ b/src/components/common/noContent/NoContent.tsx
@@ -2,13 +2,14 @@ import * as S from './NoContent.styled';
import { DocumentTextIcon } from '@heroicons/react/24/outline';
interface NoContentProps {
- type: 'projects' | 'applicants';
+ type: 'projects' | 'applicants' | 'passNonPass';
}
export default function NoContent({ type }: NoContentProps) {
const INPUT_CONTENT = {
projects: '공고가',
applicants: '지원자가',
+ passNonPass: '합/불합격자 리스트가',
};
return (
diff --git a/src/components/manageProjects/ProjectHeader.styled.ts b/src/components/manageProjects/ProjectHeader.styled.ts
new file mode 100644
index 00000000..d762ddc7
--- /dev/null
+++ b/src/components/manageProjects/ProjectHeader.styled.ts
@@ -0,0 +1,15 @@
+import styled from 'styled-components';
+
+export const TitleWrapper = styled.div`
+ display: flex;
+ justify-content: start;
+ align-items: center;
+ width: 100%;
+`;
+
+export const RecruitmentEnd = styled.h3`
+ margin-left: 1.2rem;
+ font-size: 1rem;
+ font-weight: 400;
+ color: ${({ theme }) => theme.color.red};
+`;
diff --git a/src/components/manageProjects/ProjectHeader.tsx b/src/components/manageProjects/ProjectHeader.tsx
new file mode 100644
index 00000000..d9f8133d
--- /dev/null
+++ b/src/components/manageProjects/ProjectHeader.tsx
@@ -0,0 +1,21 @@
+import * as S from './ProjectHeader.styled';
+import Title from '../common/title/Title';
+import { ProjectDetailExtended } from '../../models/projectDetail';
+import RecruitmentDate from './RecruitmentDate';
+interface ProjectHeaderProps {
+ projectData: ProjectDetailExtended;
+}
+
+function ProjectHeader({ projectData }: ProjectHeaderProps) {
+ return (
+ <>
+
+ {projectData && {projectData.title} }
+ {projectData?.isDone && 공고 마감}
+
+ {projectData && }
+ >
+ );
+}
+
+export default ProjectHeader;
diff --git a/src/components/manageProjects/passNonPassList/PassNonPassItem.styled.ts b/src/components/manageProjects/passNonPassList/PassNonPassItem.styled.ts
new file mode 100644
index 00000000..13826de6
--- /dev/null
+++ b/src/components/manageProjects/passNonPassList/PassNonPassItem.styled.ts
@@ -0,0 +1,28 @@
+import styled from 'styled-components';
+
+export const ItemWrapper = styled.li`
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ width: 100%;
+ padding: 1rem;
+ border: 1px solid ${({ theme }) => theme.color.grey};
+ border-radius: ${({ theme }) => theme.borderRadius.primary};
+ &:hover {
+ background-color: ${({ theme }) => theme.color.navy};
+ color: ${({ theme }) => theme.color.white};
+ }
+
+ svg {
+ color: #e69191;
+ width: 1.2rem;
+ height: 1.2rem;
+ }
+`;
+
+export const NickName = styled.p`
+ font-size: ${({ theme }) => theme.heading.small.fontSize};
+ font-weight: 400;
+`;
+
+export const DeleteButton = styled.button``;
diff --git a/src/components/manageProjects/passNonPassList/PassNonPassItem.tsx b/src/components/manageProjects/passNonPassList/PassNonPassItem.tsx
new file mode 100644
index 00000000..61089540
--- /dev/null
+++ b/src/components/manageProjects/passNonPassList/PassNonPassItem.tsx
@@ -0,0 +1,20 @@
+import { ApplicantInfo } from '../../../models/applicant';
+import * as S from './PassNonPassItem.styled';
+import { XCircleIcon } from '@heroicons/react/24/outline';
+
+interface PassNonPassItemProps {
+ userInfo: ApplicantInfo;
+}
+
+function PassNonPassItem({ userInfo }: PassNonPassItemProps) {
+ return (
+
+ {userInfo.User.nickname}
+
+
+
+
+ );
+}
+
+export default PassNonPassItem;
diff --git a/src/components/manageProjects/passNonPassList/PassNonPassList.styled.ts b/src/components/manageProjects/passNonPassList/PassNonPassList.styled.ts
new file mode 100644
index 00000000..5493e4d2
--- /dev/null
+++ b/src/components/manageProjects/passNonPassList/PassNonPassList.styled.ts
@@ -0,0 +1,20 @@
+import styled from 'styled-components';
+
+export const Wrapper = styled.ul`
+ width: 100%;
+ height: 27rem;
+ min-width: 22rem;
+ border-radius: ${({ theme }) => theme.borderRadius.primary};
+ border: 1px solid ${({ theme }) => theme.color.border};
+ padding: 1.6rem 2rem;
+ gap: 1rem;
+ display: flex;
+ flex-direction: column;
+ justify-content: start;
+ align-items: center;
+ overflow: hidden;
+ overflow-y: auto;
+ &::-webkit-scrollbar {
+ display: none;
+ }
+`;
diff --git a/src/components/manageProjects/passNonPassList/PassNonPassList.tsx b/src/components/manageProjects/passNonPassList/PassNonPassList.tsx
new file mode 100644
index 00000000..c6bbdf48
--- /dev/null
+++ b/src/components/manageProjects/passNonPassList/PassNonPassList.tsx
@@ -0,0 +1,19 @@
+import { ApplicantInfo } from '../../../models/applicant';
+import PassNonPassItem from './PassNonPassItem';
+import * as S from './PassNonPassList.styled';
+
+interface PassNonPassListProps {
+ passNonPassListData: ApplicantInfo[];
+}
+
+function PassNonPassList({ passNonPassListData }: PassNonPassListProps) {
+ return (
+
+ {passNonPassListData.map((data) => (
+
+ ))}
+
+ );
+}
+
+export default PassNonPassList;
diff --git a/src/hooks/queries/keys.ts b/src/hooks/queries/keys.ts
index 5683f6e3..fb9d9247 100644
--- a/src/hooks/queries/keys.ts
+++ b/src/hooks/queries/keys.ts
@@ -5,6 +5,7 @@ export const managedProjectsKey = {
export const applicantKey = {
all: ['applicantList'],
info: ['applicantInfo'],
+ passNonPass: ['passNonPassList'],
};
export const myInfoKey = {
diff --git a/src/hooks/usePassNonPassList.ts b/src/hooks/usePassNonPassList.ts
new file mode 100644
index 00000000..6ef277ca
--- /dev/null
+++ b/src/hooks/usePassNonPassList.ts
@@ -0,0 +1,13 @@
+import { useQuery } from '@tanstack/react-query';
+import { applicantKey } from './queries/keys';
+import { getPassNonPassList } from '../api/applicant.api';
+
+export const usePassNonPassList = (projectId: number) => {
+ const { data } = useQuery({
+ queryKey: applicantKey.passNonPass,
+ queryFn: () => getPassNonPassList(projectId),
+ staleTime: 1 * 60 * 1000,
+ });
+
+ return { passNonPassListData: data };
+};
diff --git a/src/hooks/usePassNonPass.ts b/src/hooks/usePassNonPassMutation.ts
similarity index 96%
rename from src/hooks/usePassNonPass.ts
rename to src/hooks/usePassNonPassMutation.ts
index 1d1d6bd2..3692beab 100644
--- a/src/hooks/usePassNonPass.ts
+++ b/src/hooks/usePassNonPassMutation.ts
@@ -9,7 +9,7 @@ interface useMutationParams {
userId: number;
}
-export const usePassNonPass = (
+export const usePassNonPassMutation = (
projectId: number,
openModal: (message: string) => void
) => {
diff --git a/src/mock/applicant.ts b/src/mock/applicant.ts
index a6827322..864a7bcd 100644
--- a/src/mock/applicant.ts
+++ b/src/mock/applicant.ts
@@ -1,6 +1,7 @@
import { http, HttpResponse } from 'msw';
import mockApplicantsData from './mockApplicantsData.json';
import mockApplicantData from './mockApplicantData.json';
+import mockPassNonPassListData from './mockPassNonPassListData.json';
export const applicantList = http.get(
`${import.meta.env.VITE_API_BASE_URL}/project/:projectId/applicant`,
@@ -20,6 +21,15 @@ export const applicantInfo = http.get(
}
);
+export const passNonPassList = http.get(
+ `${import.meta.env.VITE_API_BASE_URL}/project/:projectId/applicant/summary`,
+ () => {
+ return HttpResponse.json(mockPassNonPassListData, {
+ status: 200,
+ });
+ }
+);
+
export const passNonPass = http.patch(
`${
import.meta.env.VITE_API_BASE_URL
diff --git a/src/mock/browser.ts b/src/mock/browser.ts
index c3c24032..efe033dd 100644
--- a/src/mock/browser.ts
+++ b/src/mock/browser.ts
@@ -1,6 +1,11 @@
import { setupWorker } from 'msw/browser';
import { myProjectList } from './manageProjectList';
-import { applicantInfo, applicantList, passNonPass } from './applicant';
+import {
+ applicantInfo,
+ applicantList,
+ passNonPass,
+ passNonPassList,
+} from './applicant';
import { projectDetail } from './projectDetail';
export const handlers = [
@@ -9,6 +14,7 @@ export const handlers = [
projectDetail,
applicantInfo,
passNonPass,
+ passNonPassList,
];
export const worker = setupWorker(...handlers);
diff --git a/src/mock/mockPassNonPassListData.json b/src/mock/mockPassNonPassListData.json
new file mode 100644
index 00000000..d32458ab
--- /dev/null
+++ b/src/mock/mockPassNonPassListData.json
@@ -0,0 +1,182 @@
+{
+ "accepted": [
+ {
+ "id": 18,
+ "userId": 1,
+ "projectId": 72,
+ "message": null,
+ "email": null,
+ "phoneNumber": null,
+ "career": null,
+ "status": "ACCEPTED",
+ "createdAt": "2025-01-23T09:08:13.000Z",
+ "updatedAt": "2025-01-23T09:08:13.000Z",
+ "User": {
+ "id": 1,
+ "nickname": "Jeny"
+ }
+ },
+ {
+ "id": 18,
+ "userId": 2,
+ "projectId": 72,
+ "message": null,
+ "email": null,
+ "phoneNumber": null,
+ "career": null,
+ "status": "ACCEPTED",
+ "createdAt": "2025-01-23T09:08:13.000Z",
+ "updatedAt": "2025-01-23T09:08:13.000Z",
+ "User": {
+ "id": 2,
+ "nickname": "Jeny1"
+ }
+ },
+ {
+ "id": 18,
+ "userId": 3,
+ "projectId": 72,
+ "message": null,
+ "email": null,
+ "phoneNumber": null,
+ "career": null,
+ "status": "ACCEPTED",
+ "createdAt": "2025-01-23T09:08:13.000Z",
+ "updatedAt": "2025-01-23T09:08:13.000Z",
+ "User": {
+ "id": 3,
+ "nickname": "Jeny3"
+ }
+ },
+ {
+ "id": 18,
+ "userId": 4,
+ "projectId": 72,
+ "message": null,
+ "email": null,
+ "phoneNumber": null,
+ "career": null,
+ "status": "ACCEPTED",
+ "createdAt": "2025-01-23T09:08:13.000Z",
+ "updatedAt": "2025-01-23T09:08:13.000Z",
+ "User": {
+ "id": 4,
+ "nickname": "Jeny"
+ }
+ },
+ {
+ "id": 18,
+ "userId": 5,
+ "projectId": 72,
+ "message": null,
+ "email": null,
+ "phoneNumber": null,
+ "career": null,
+ "status": "ACCEPTED",
+ "createdAt": "2025-01-23T09:08:13.000Z",
+ "updatedAt": "2025-01-23T09:08:13.000Z",
+ "User": {
+ "id": 5,
+ "nickname": "Jeny1"
+ }
+ },
+ {
+ "id": 18,
+ "userId": 6,
+ "projectId": 72,
+ "message": null,
+ "email": null,
+ "phoneNumber": null,
+ "career": null,
+ "status": "ACCEPTED",
+ "createdAt": "2025-01-23T09:08:13.000Z",
+ "updatedAt": "2025-01-23T09:08:13.000Z",
+ "User": {
+ "id": 6,
+ "nickname": "Jeny"
+ }
+ },
+ {
+ "id": 18,
+ "userId": 7,
+ "projectId": 72,
+ "message": null,
+ "email": null,
+ "phoneNumber": null,
+ "career": null,
+ "status": "ACCEPTED",
+ "createdAt": "2025-01-23T09:08:13.000Z",
+ "updatedAt": "2025-01-23T09:08:13.000Z",
+ "User": {
+ "id": 7,
+ "nickname": "Jeny1"
+ }
+ },
+ {
+ "id": 18,
+ "userId": 8,
+ "projectId": 72,
+ "message": null,
+ "email": null,
+ "phoneNumber": null,
+ "career": null,
+ "status": "ACCEPTED",
+ "createdAt": "2025-01-23T09:08:13.000Z",
+ "updatedAt": "2025-01-23T09:08:13.000Z",
+ "User": {
+ "id": 8,
+ "nickname": "Jeny"
+ }
+ },
+ {
+ "id": 18,
+ "userId": 9,
+ "projectId": 72,
+ "message": null,
+ "email": null,
+ "phoneNumber": null,
+ "career": null,
+ "status": "ACCEPTED",
+ "createdAt": "2025-01-23T09:08:13.000Z",
+ "updatedAt": "2025-01-23T09:08:13.000Z",
+ "User": {
+ "id": 9,
+ "nickname": "Jeny1"
+ }
+ }
+ ],
+ "rejected": [
+ {
+ "id": 19,
+ "userId": 10,
+ "projectId": 72,
+ "message": null,
+ "email": null,
+ "phoneNumber": null,
+ "career": null,
+ "status": "REJECTED",
+ "createdAt": "2025-01-23T09:08:20.000Z",
+ "updatedAt": "2025-01-23T09:08:20.000Z",
+ "User": {
+ "id": 10,
+ "nickname": "룰루"
+ }
+ },
+ {
+ "id": 20,
+ "userId": 11,
+ "projectId": 72,
+ "message": null,
+ "email": null,
+ "phoneNumber": null,
+ "career": null,
+ "status": "REJECTED",
+ "createdAt": "2025-01-23T09:08:25.000Z",
+ "updatedAt": "2025-01-23T09:08:25.000Z",
+ "User": {
+ "id": 11,
+ "nickname": "종다리"
+ }
+ }
+ ]
+}
diff --git a/src/pages/manage/myProjectParticipantsPass/MyProjectVolunteersPass.styled.ts b/src/pages/manage/myProjectParticipantsPass/MyProjectVolunteersPass.styled.ts
index c3389834..f2d324db 100644
--- a/src/pages/manage/myProjectParticipantsPass/MyProjectVolunteersPass.styled.ts
+++ b/src/pages/manage/myProjectParticipantsPass/MyProjectVolunteersPass.styled.ts
@@ -1,3 +1,27 @@
import styled from 'styled-components';
-export const Container = styled.div``;
+export const Container = styled.div`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+`;
+
+export const Title = styled.h1`
+ font-size: 1.25rem;
+ font-weight: 700;
+ color: ${({ theme }) => theme.color.deepGrey};
+ margin-left: 1rem;
+ margin-bottom: 1rem;
+`;
+
+export const ResultContainer = styled.div`
+ display: flex;
+ width: 100%;
+ justify-content: space-between;
+ margin-top: 3.5rem;
+`;
+
+export const ListWrapper = styled.div`
+ width: 100%;
+ margin-right: 1rem;
+`;
diff --git a/src/pages/manage/myProjectParticipantsPass/MyProjectVolunteersPass.tsx b/src/pages/manage/myProjectParticipantsPass/MyProjectVolunteersPass.tsx
index 4a97ce56..261c0171 100644
--- a/src/pages/manage/myProjectParticipantsPass/MyProjectVolunteersPass.tsx
+++ b/src/pages/manage/myProjectParticipantsPass/MyProjectVolunteersPass.tsx
@@ -1,35 +1,47 @@
import * as S from './MyProjectVolunteersPass.styled';
import Sidebar from '../../../components/common/sidebar/Sidebar';
-import {
- DocumentTextIcon,
- PencilSquareIcon,
- UserIcon,
-} from '@heroicons/react/24/outline';
-import { ROUTES } from '../../../constants/routes';
import { useParams } from 'react-router-dom';
-
+import { applicantsMenuItems } from '../../../constants/sidebarItems';
+import InfoCard from '../../../components/common/infoCard/InfoCard';
+import MainLogo from '../../../assets/mainlogo.svg';
+import { usePassNonPassList } from '../../../hooks/usePassNonPassList';
+import useGetProjectData from '../../../hooks/useJoinProject';
+import ProjectHeader from '../../../components/manageProjects/ProjectHeader';
+import PassNonPassList from '../../../components/manageProjects/passNonPassList/PassNonPassList';
+import NoContent from '../../../components/common/noContent/NoContent';
const MyProjectVolunteersPass = () => {
const { projectId } = useParams();
- const menuItems = [
- {
- label: '지원자 보기',
- path: `${ROUTES.manageProjectsRoot}/${projectId}`,
- icon: ,
- },
- {
- label: '지원자 합/불 관리',
- path: `${ROUTES.manageProjectsPassNonPass}/${projectId}`,
- icon: ,
- },
- {
- label: '공고 관리',
- path: '/mypage/apply-projects',
- icon: ,
- },
- ];
+ const { data: projectData } = useGetProjectData(Number(projectId));
+ const { passNonPassListData } = usePassNonPassList(Number(projectId));
+
return (
-
+
+
+ {projectData && }
+ {passNonPassListData?.accepted.length > 0 ||
+ passNonPassListData?.rejected.length > 0 ? (
+
+
+ 합격자 리스트
+
+
+
+ 불 합격자 리스트
+
+
+
+ ) : (
+
+ )}
+
);
};
diff --git a/src/pages/manage/myProjectVolunteer/MyProjectVolunteer.styled.ts b/src/pages/manage/myProjectVolunteer/MyProjectVolunteer.styled.ts
index 36c7462f..c0ada979 100644
--- a/src/pages/manage/myProjectVolunteer/MyProjectVolunteer.styled.ts
+++ b/src/pages/manage/myProjectVolunteer/MyProjectVolunteer.styled.ts
@@ -31,20 +31,6 @@ export const Title = styled.h1`
margin-bottom: 1rem;
`;
-export const TitleWrapper = styled.div`
- display: flex;
- justify-content: start;
- align-items: center;
- width: 100%;
-`;
-
-export const RecruitmentEnd = styled.h3`
- margin-left: 1.2rem;
- font-size: 1rem;
- font-weight: 400;
- color: ${({ theme }) => theme.color.red};
-`;
-
export const ButtonWrapper = styled.div`
display: flex;
`;
diff --git a/src/pages/manage/myProjectVolunteer/MyProjectVolunteer.tsx b/src/pages/manage/myProjectVolunteer/MyProjectVolunteer.tsx
index 6f9866bb..05590ce7 100644
--- a/src/pages/manage/myProjectVolunteer/MyProjectVolunteer.tsx
+++ b/src/pages/manage/myProjectVolunteer/MyProjectVolunteer.tsx
@@ -3,10 +3,8 @@ import { useParams } from 'react-router-dom';
import * as S from './MyProjectVolunteer.styled';
import Sidebar from '../../../components/common/sidebar/Sidebar';
import InfoCard from '../../../components/common/infoCard/InfoCard';
-import Title from '../../../components/common/title/Title';
import ApplicantList from '../../../components/manageProjects/applicantList/ApplicantList';
import ApplicantInfo from '../../../components/manageProjects/applicantInfo/ApplicantInfo';
-import RecruitmentDate from '../../../components/manageProjects/RecruitmentDate';
import useGetProjectData from '../../../hooks/useJoinProject';
import { useApllicantList } from '../../../hooks/useApllicantList';
@@ -14,19 +12,20 @@ import { useApllicantList } from '../../../hooks/useApllicantList';
import { applicantsMenuItems } from '../../../constants/sidebarItems';
import { useApplicantInfo } from '../../../hooks/useApplicantInfo';
import PassNonPassButton from '../../../components/manageProjects/applicantList/PassNonPassButton';
-import { usePassNonPass } from '../../../hooks/usePassNonPass';
+import { usePassNonPassMutation } from '../../../hooks/usePassNonPassMutation';
import NoContent from '../../../components/common/noContent/NoContent';
import MainLogo from '../../../assets/mainlogo.svg';
import Modal from '../../../components/common/modal/Modal';
import { useModal } from '../../../hooks/useModal';
+import ProjectHeader from '../../../components/manageProjects/ProjectHeader';
const MyProjectVolunteer = () => {
const { projectId } = useParams();
const sidebarMenuItem = applicantsMenuItems(Number(projectId));
const { data: projectData } = useGetProjectData(Number(projectId));
const { isOpen, handleModalClose, handleModalOpen, message } = useModal();
- const { handlePassNonPassStatus } = usePassNonPass(
+ const { handlePassNonPassStatus } = usePassNonPassMutation(
Number(projectId),
handleModalOpen
);
@@ -40,16 +39,9 @@ const MyProjectVolunteer = () => {
-
- {projectData && {projectData.title} }
- {projectData?.isDone && (
- 공고 마감
- )}
-
- {projectData && }
+ {projectData && }
- {isApplicantLoading ||
- (applicantsData && applicantsData?.length > 0) ? (
+ {isApplicantLoading || (applicantsData && applicantsData.length > 0) ? (
지원자 리스트
diff --git a/src/routes/AppRoutes.tsx b/src/routes/AppRoutes.tsx
index 5ad5674e..4cd6a827 100644
--- a/src/routes/AppRoutes.tsx
+++ b/src/routes/AppRoutes.tsx
@@ -209,11 +209,11 @@ const AppRoutes = () => {
path: `${ROUTES.manageProjectsPassNonPass}/:projectId`,
element: (
-
- }>
+ }>
+
-
-
+
+
),
},