diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 71c0e5e0d..5e2e23096 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -18,7 +18,7 @@ import PrivateRoute from '@/pages/AdminPage/auth/PrivateRoute/PrivateRoute';
import PhotoEditTab from '@/pages/AdminPage/tabs/PhotoEditTab/PhotoEditTab';
import ApplicationFormPage from './pages/ApplicationFormPage/ApplicationFormPage';
import ApplicantsTab from './pages/AdminPage/tabs/ApplicantsTab/ApplicantsTab';
-import ApplicantDetailPage from './pages/AdminPage/tabs/ApplicantsTab/ApplicantDetailPage';
+import ApplicantDetailPage from './pages/AdminPage/tabs/ApplicantsTab/ApplicantDetailPage/ApplicantDetailPage';
const queryClient = new QueryClient();
@@ -78,11 +78,11 @@ const App = () => {
path='application-edit'
element={}
/>
- }
/>
- }
/>
diff --git a/frontend/src/assets/images/icons/applicant_drop.svg b/frontend/src/assets/images/icons/applicant_drop.svg
new file mode 100644
index 000000000..810f11bf2
--- /dev/null
+++ b/frontend/src/assets/images/icons/applicant_drop.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/src/assets/images/icons/back_arrow_icon.svg b/frontend/src/assets/images/icons/back_arrow_icon.svg
deleted file mode 100644
index 0a00b873e..000000000
--- a/frontend/src/assets/images/icons/back_arrow_icon.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/frontend/src/assets/images/icons/forward_arrow_icon.svg b/frontend/src/assets/images/icons/forward_arrow_icon.svg
deleted file mode 100644
index 96483cd33..000000000
--- a/frontend/src/assets/images/icons/forward_arrow_icon.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/frontend/src/assets/images/icons/next_applicant.svg b/frontend/src/assets/images/icons/next_applicant.svg
new file mode 100644
index 000000000..88790aeb2
--- /dev/null
+++ b/frontend/src/assets/images/icons/next_applicant.svg
@@ -0,0 +1,4 @@
+
diff --git a/frontend/src/assets/images/icons/prev_applicant.svg b/frontend/src/assets/images/icons/prev_applicant.svg
new file mode 100644
index 000000000..b3715b669
--- /dev/null
+++ b/frontend/src/assets/images/icons/prev_applicant.svg
@@ -0,0 +1,4 @@
+
diff --git a/frontend/src/pages/AdminPage/components/SideBar/SideBar.tsx b/frontend/src/pages/AdminPage/components/SideBar/SideBar.tsx
index 24f8270e0..07776e311 100644
--- a/frontend/src/pages/AdminPage/components/SideBar/SideBar.tsx
+++ b/frontend/src/pages/AdminPage/components/SideBar/SideBar.tsx
@@ -15,7 +15,7 @@ const tabs = [
{ label: '모집 정보 수정', path: '/admin/recruit-edit' },
{ label: '활동 사진 수정', path: '/admin/photo-edit' },
{ label: '지원서 관리', path: '/admin/application-edit' },
- { label: '지원자 관리', path: '/admin/applicants' },
+ { label: '지원자 현황', path: '/admin/applicants' },
{ label: '계정 관리', path: '/admin/account-edit' },
];
@@ -41,7 +41,11 @@ const SideBar = ({ clubLogo, clubName }: SideBarProps) => {
if (!confirmed) return;
try {
- if (document.cookie.split(';').some((cookie) => cookie.trim().startsWith('refreshToken='))) {
+ if (
+ document.cookie
+ .split(';')
+ .some((cookie) => cookie.trim().startsWith('refreshToken='))
+ ) {
await logout();
}
localStorage.removeItem('accessToken');
diff --git a/frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantDetailPage/ApplicantDetailPage.styles.ts b/frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantDetailPage/ApplicantDetailPage.styles.ts
new file mode 100644
index 000000000..f0b4a38be
--- /dev/null
+++ b/frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantDetailPage/ApplicantDetailPage.styles.ts
@@ -0,0 +1,156 @@
+import styled from 'styled-components';
+import * as ApplicationFormPageStyles from '@/pages/ApplicationFormPage/ApplicationFormPage.styles';
+import DropdownArrow from '@/assets/images/icons/applicant_drop.svg';
+
+export const Wrapper = styled.div`
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 20px;
+ margin-bottom: 10px;
+`;
+
+export const HeaderContainer = styled.div`
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ width: 100%;
+ height: 58px;
+`;
+
+export const ApplicantContainer = styled.div`
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ gap: 240px;
+ width: 82%;
+ height: 100%;
+ border: none;
+ border-radius: 10px;
+ background: var(--f5, #f5f5f5);
+
+ select {
+ font-size: 24px;
+ font-style: normal;
+ font-weight: 700;
+ border: none;
+ background-color: transparent;
+
+ background-image: url(${DropdownArrow});
+ background-repeat: no-repeat;
+ background-position: right 8px center;
+ background-size: 11px 11px;
+
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ }
+`;
+
+export const StatusSelect = styled.select<{ $backgroundColor: string }>`
+ border: none;
+ border-radius: 10px;
+ padding: 8px 12px;
+ width: 18%;
+ height: 100%;
+ cursor: pointer;
+
+ color: var(--4B, #4b4b4b);
+ text-align: center;
+ font-size: 16px;
+ font-style: normal;
+ font-weight: 600;
+
+ background-color: ${(props) => props.$backgroundColor};
+
+ background-image: url(${DropdownArrow});
+ background-repeat: no-repeat;
+ background-position: right 15px center;
+ padding-right: 30px;
+ background-size: 9px 9px;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+
+ &:focus {
+ outline: none;
+ }
+`;
+
+export const MemoContainer = styled.div`
+ display: flex;
+ flex-direction: row;
+ align-items: flex-start;
+ width: 100%;
+ gap: 24px;
+ padding: 12px 12px;
+ min-height: 100px;
+ background: var(--f5, #f5f5f5);
+ border-radius: 10px;
+`;
+
+export const MemoLabel = styled.label`
+ position: relative;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ align-self: flex-start;
+ width: 60px;
+ height: 32px;
+ background: #fff;
+ border-radius: 10px;
+ padding: 6px 14px;
+ color: var(--, #111);
+ font-size: 16px;
+ font-style: normal;
+ font-weight: 600;
+
+ &::after {
+ content: '';
+ position: absolute;
+ right: -20px;
+ top: 30%;
+ height: 40%;
+ width: 4px;
+ height: 14px;
+ background: #d9d9d9;
+ }
+`;
+
+export const MemoTextarea = styled.textarea`
+ flex: 1;
+ min-height: 80px;
+ border: none;
+ border-radius: 10px;
+ background: var(--f5, #f5f5f5);
+ padding: 12px;
+ resize: none;
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 400;
+ color: var(--4B, #4b4b4b);
+
+ &:focus {
+ outline: none;
+ }
+`;
+
+export const ApplicantInfoContainer = styled.div`
+ display: block;
+ width: 100%;
+ padding: 10px 30px;
+ border-radius: 10px;
+ border: 1px solid #f2f2f2;
+`;
+
+export const QuestionsWrapper = styled(
+ ApplicationFormPageStyles.QuestionsWrapper,
+)`
+ cursor: default;
+`;
+
+export const NavigationButton = styled.img`
+ cursor: pointer;
+`;
diff --git a/frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantDetailPage.tsx b/frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantDetailPage/ApplicantDetailPage.tsx
similarity index 61%
rename from frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantDetailPage.tsx
rename to frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantDetailPage/ApplicantDetailPage.tsx
index 4ee8c92b2..9e5b8994d 100644
--- a/frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantDetailPage.tsx
+++ b/frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantDetailPage/ApplicantDetailPage.tsx
@@ -1,26 +1,39 @@
import React, { useEffect, useMemo, useState } from 'react';
+import * as Styled from './ApplicantDetailPage.styles';
import { useParams, useNavigate } from 'react-router-dom';
import { useAdminClubContext } from '@/context/AdminClubContext';
import Header from '@/components/common/Header/Header';
-import { PageContainer } from '@/styles/PageContainer.styles';
-import * as Styled from '@/pages/ApplicationFormPage/ApplicationFormPage.styles';
import QuestionContainer from '@/pages/ApplicationFormPage/components/QuestionContainer/QuestionContainer';
import QuestionAnswerer from '@/pages/ApplicationFormPage/components/QuestionAnswerer/QuestionAnswerer';
-import { useGetApplication } from '@/hooks/queries/application/useGetApplication';
import Spinner from '@/components/common/Spinner/Spinner';
-import BackButton from '@/assets/images/icons/back_arrow_icon.svg';
-import ForwardButton from '@/assets/images/icons/forward_arrow_icon.svg';
import debounce from '@/utils/debounce';
import updateApplicantMemo from '@/apis/application/updateApplicantDetail';
+import { useGetApplication } from '@/hooks/queries/application/useGetApplication';
import { ApplicationStatus } from '@/types/applicants';
import mapStatusToGroup from '@/utils/mapStatusToGroup';
import { Question } from '@/types/application';
+import PrevApplicantButton from '@/assets/images/icons/prev_applicant.svg';
+import NextApplicantButton from '@/assets/images/icons/next_applicant.svg';
const AVAILABLE_STATUSES = [
- ApplicationStatus.SCREENING, // 서류검토
+ ApplicationStatus.SCREENING, // 서류검토 (SUBMITTED 포함)
ApplicationStatus.INTERVIEW_SCHEDULED, // 면접예정
ApplicationStatus.ACCEPTED, // 합격
-];
+] as const;
+
+const getStatusColor = (status: ApplicationStatus | undefined): string => {
+ switch (status) {
+ case ApplicationStatus.ACCEPTED:
+ return 'var(--f5, #F5F5F5)';
+ case ApplicationStatus.SCREENING:
+ case ApplicationStatus.SUBMITTED:
+ return '#E5F6FF';
+ case ApplicationStatus.INTERVIEW_SCHEDULED:
+ return '#E9FFF1';
+ default:
+ return 'var(--f5, #F5F5F5)';
+ }
+};
const ApplicantDetailPage = () => {
const { questionId } = useParams<{ questionId: string }>();
@@ -32,7 +45,8 @@ const ApplicantDetailPage = () => {
const { data: formData, isLoading, isError } = useGetApplication(clubId!);
const { applicant, applicantIndex } = useMemo(() => {
- const index = applicantsData?.applicants.findIndex((a) => a.id === questionId) ?? -1;
+ const index =
+ applicantsData?.applicants.findIndex((a) => a.id === questionId) ?? -1;
const _applicant = applicantsData?.applicants[index];
return { applicant: _applicant, applicantIndex: index };
@@ -48,7 +62,12 @@ const ApplicantDetailPage = () => {
const updateApplicantDetail = useMemo(
() =>
debounce((memo: any, status: any) => {
- updateApplicantMemo(memo as string, status as ApplicationStatus, clubId!, questionId!);
+ updateApplicantMemo(
+ memo as string,
+ status as ApplicationStatus,
+ clubId!,
+ questionId!,
+ );
}, 400),
[clubId, questionId],
);
@@ -71,7 +90,10 @@ const ApplicantDetailPage = () => {
.map((ans) => ans.value);
};
- const updateApplicantInContext = (memo: string, status: ApplicationStatus) => {
+ const updateApplicantInContext = (
+ memo: string,
+ status: ApplicationStatus,
+ ) => {
if (!applicantsData || applicantIndex === -1) return;
const updatedApplicants = [...applicantsData.applicants];
@@ -111,43 +133,56 @@ const ApplicantDetailPage = () => {
return (
<>
-
-
-

-
-

-
-
-
-
- {AVAILABLE_STATUSES.map((status) => (
-
- ))}
-
-
+
+
+
+
+ 메모
+
+
+
+
+
{formData.questions.map((q: Question, i: number) => (
@@ -159,9 +194,9 @@ const ApplicantDetailPage = () => {
))}
-
+
>
);
};
-export default ApplicantDetailPage;
\ No newline at end of file
+export default ApplicantDetailPage;
diff --git a/frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsTab.styles.ts b/frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsTab.styles.ts
index b2190cddd..72933b873 100644
--- a/frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsTab.styles.ts
+++ b/frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsTab.styles.ts
@@ -141,7 +141,7 @@ export const ApplicantTableHeader = styled.th<{
color: var(--78, #787878);
width: ${({ width }) => (width ? `${width}px` : 'auto')};
text-align: ${({ isMemo }) => (isMemo ? 'left' : 'center')};
- padding-left: ${({ isMemo }) => (isMemo ? '30px' : 'none')};
+ padding-left: ${({ isMemo }) => (isMemo ? '30px' : '8px')};
${({ borderLeft }) =>
borderLeft &&
@@ -171,7 +171,7 @@ export const ApplicantTableCol = styled.td<{ isMemo?: boolean }>`
padding: 12px 8px;
font-size: 16px;
text-align: ${({ isMemo }) => (isMemo ? 'left' : 'center')};
- padding-left: ${({ isMemo }) => (isMemo ? '30px' : 'none')};
+ padding-left: ${({ isMemo }) => (isMemo ? '30px' : '8px')};
`;
export const ApplicantTableCheckbox = styled.input.attrs({ type: 'checkbox' })`