From c8b70c163ef8c90d1da66b5358adab8362af05e4 Mon Sep 17 00:00:00 2001 From: cindy-chaewon Date: Tue, 27 Jan 2026 17:10:28 +0900 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=EA=B4=80=EB=A6=AC=EC=9E=90=20?= =?UTF-8?q?=EB=A9=B4=EC=A0=91=ED=8F=89=EA=B0=80=20UI=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=20(#205)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ApplicantHeader/ApplicantHeader.tsx | 2 +- .../ApplicantToggle/ApplicantToggle.css.ts | 2 +- .../ApplicantToggle/ApplicantToggle.tsx | 4 + .../[time]/ApplicantDetailClient.tsx | 245 ++++++++++++------ .../[date]/application/[time]/page.css.ts | 19 +- 5 files changed, 194 insertions(+), 78 deletions(-) diff --git a/apps/web/src/app/(main)/interview-management/_components/ApplicantHeader/ApplicantHeader.tsx b/apps/web/src/app/(main)/interview-management/_components/ApplicantHeader/ApplicantHeader.tsx index a82c9a4f..7c72fefb 100644 --- a/apps/web/src/app/(main)/interview-management/_components/ApplicantHeader/ApplicantHeader.tsx +++ b/apps/web/src/app/(main)/interview-management/_components/ApplicantHeader/ApplicantHeader.tsx @@ -12,7 +12,7 @@ import ApplicantToggle, { export interface ApplicantSliderHeaderProps { name: string; current: number; - onViewApplication: () => void; + onViewApplication?: () => void; isOtherUser?: boolean; applicants: ApplicantItem[]; currentId: number; diff --git a/apps/web/src/app/(main)/interview-management/_components/ApplicantToggle/ApplicantToggle.css.ts b/apps/web/src/app/(main)/interview-management/_components/ApplicantToggle/ApplicantToggle.css.ts index a9b3d01c..9b6591c3 100644 --- a/apps/web/src/app/(main)/interview-management/_components/ApplicantToggle/ApplicantToggle.css.ts +++ b/apps/web/src/app/(main)/interview-management/_components/ApplicantToggle/ApplicantToggle.css.ts @@ -57,7 +57,7 @@ export const countBadge = style({ justifyContent: 'center', border: `1px solid ${vars.colors.grayscale20}`, marginLeft: '-12px', - zIndex: 1, + //zIndex: 1, flexShrink: 0, ...fontStyles.md2_text_medium }); diff --git a/apps/web/src/app/(main)/interview-management/_components/ApplicantToggle/ApplicantToggle.tsx b/apps/web/src/app/(main)/interview-management/_components/ApplicantToggle/ApplicantToggle.tsx index f256d360..46c9fbcc 100644 --- a/apps/web/src/app/(main)/interview-management/_components/ApplicantToggle/ApplicantToggle.tsx +++ b/apps/web/src/app/(main)/interview-management/_components/ApplicantToggle/ApplicantToggle.tsx @@ -3,6 +3,7 @@ import * as styles from './ApplicantToggle.css'; import { Profile } from '@repo/ui/Profile'; import { Divider, Flex, Text } from '@repo/ui'; import { IcArrowDown } from '@repo/ui/icons/mono'; +import { style } from '@vanilla-extract/css'; export interface ApplicantItem { id: number; @@ -75,11 +76,14 @@ const ApplicantToggle: React.FC = ({ >
+
+
+ {otherCount > 0 && (
+{otherCount}
diff --git a/apps/web/src/app/(main)/interview-management/timetable/[tab]/[date]/application/[time]/ApplicantDetailClient.tsx b/apps/web/src/app/(main)/interview-management/timetable/[tab]/[date]/application/[time]/ApplicantDetailClient.tsx index e2bb3eca..5f7d7c35 100644 --- a/apps/web/src/app/(main)/interview-management/timetable/[tab]/[date]/application/[time]/ApplicantDetailClient.tsx +++ b/apps/web/src/app/(main)/interview-management/timetable/[tab]/[date]/application/[time]/ApplicantDetailClient.tsx @@ -11,6 +11,13 @@ import { Applicant } from '@web/constants/timetable'; import { getOriginalFileName } from '@web/components/FileUpload/FileUpload'; import { useRecruitmentDetailQuery } from '@web/store/query/useRecruitmentDetailQuery'; import { ApplicantItem } from '@web/app/(main)/interview-management/_components/ApplicantToggle/ApplicantToggle'; +import { useApplicationDetailQuery } from '@web/store/query/useApplicationDetailQuery'; +import { CompletedEvaluator } from '@web/constants/document'; +import * as styles from './page.css'; +import { RelationCard } from '@web/app/(main)/apply-management/[tab]/[id]/_components/RelationCard/RelationCard'; +import { EvaluationCommentCard } from '@web/app/(main)/apply-management/[tab]/[id]/_components/EvaluationCommentCard/EvaluationCommentCard'; +import { EvaluationScoreCard } from '@web/app/(main)/apply-management/[tab]/[id]/_components/EvaluationScoreCard/EvaluationScoreCard'; +import ApplicantDetail from '@web/app/(main)/apply-management/[tab]/[id]/_components/ApplicantDetail/ApplicantDetail'; export default function ApplicantDetailClient() { const router = useRouter(); @@ -24,92 +31,180 @@ export default function ApplicantDetailClient() { const timeSlotId = Number(sp.get('timeSlotId')); const recruitmentId = Number(sp.get('recruitmentId')); - const { data: apps } = useTimeSlotApplicationsQuery({ timeSlotId }); + const { data: applicants = [], isLoading: listLoading } = + useTimeSlotApplicationsQuery({ timeSlotId }); - const { data: recruitmentDetail } = useRecruitmentDetailQuery({ - recruitmentId, - }); +const [current, setCurrent] = useState(0); - const [current, setCurrent] = useState(0); +useEffect(() => { + setCurrent(0); +}, [timeSlotId]); - useEffect(() => { - setCurrent(0); - }, [date, rawTime, timeSlotId, apps?.length]); +const applicant = applicants[current]; +if (!applicant) return null; + +const applicationId = applicant.applicationId; + +// 2️⃣ 지원서 상세 +const { + data: data, + isLoading: detailLoading, + isError, +} = useApplicationDetailQuery({ applicationId }); + +// 3️⃣ 모집 정보 +const { data: rec, isLoading: recLoading } = + useRecruitmentDetailQuery({ recruitmentId }); + +if (listLoading || detailLoading || recLoading) return null; +if (!data || !rec || isError) return null; + +// ====================== +// ✅ 카드 데이터 (ApplicationDetailClient와 동일) +// ====================== + +const documentCompletedForCard: CompletedEvaluator[] = + (data.documentCompleted ?? []).map((c) => ({ + evaluator: { + userId: c.evaluator.userId, + name: c.evaluator.name, + profileColor: c.evaluator.profileColor, + profileImageUrl: c.evaluator.profileImageUrl ?? null, + }, + totalScore: c.totalScore, + })); + +const interviewCompletedForCard: CompletedEvaluator[] = + (data.interviewCompleted ?? []).map((c) => ({ + evaluator: { + userId: c.evaluator.userId, + name: c.evaluator.name, + profileColor: c.evaluator.profileColor, + profileImageUrl: c.evaluator.profileImageUrl ?? null, + }, + totalScore: c.totalScore, + })); + +const documentEvalStatus = [ + ...(data.documentPending ?? []).map((p) => ({ + evaluator: p.name, + status: 'pending' as const, + score: null, + color: p.profileColor, + })), + ...(data.documentCompleted ?? []).map((p) => ({ + evaluator: p.evaluator.name, + status: 'complete' as const, + score: null, + color: p.evaluator.profileColor, + })), +]; + +const interviewEvalStatus = [ + ...(data.interviewPending ?? []).map((p) => ({ + evaluator: p.name, + status: 'pending' as const, + score: null, + color: p.profileColor, + })), + ...(data.interviewCompleted ?? []).map((p) => ({ + evaluator: p.evaluator.name, + status: 'complete' as const, + score: null, + color: p.evaluator.profileColor, + })), +]; + +const handleSelectApplicant = (id: number) => { + const index = applicants.findIndex((a) => a.applicationId === id); + if (index !== -1) setCurrent(index); +}; - if (!apps || apps.length === 0) { - return ( - - 이 회차에 지원자가 없습니다. - - ); - } - - const applications = apps; - const app = applications[current]; - - if (!app) { - return null; - } - - const toggleApplicants: ApplicantItem[] = applications.map((a) => { - const imgUrl = - (a as any).profileImageUrl || 'https://via.placeholder.com/150?text=User'; - - return { - id: a.applicationId, - name: a.name, - imageUrl: imgUrl, - }; - }); - - const handleToggleSelect = (selectedId: number) => { - const index = applications.findIndex((a) => a.applicationId === selectedId); - if (index !== -1) { - setCurrent(index); - } - }; - const portfolioAnswer = app.documentAnswers.find((d) => !!d.fileUrl); - const portfolioUrl = portfolioAnswer?.fileUrl ?? ''; - const portfolioFile = portfolioUrl - ? { - name: getOriginalFileName(portfolioUrl, true), - size: portfolioAnswer?.fileSize ?? 0, - downloadUrl: portfolioUrl, - } - : undefined; - - const detail: Applicant = { - id: app.applicationId.toString(), - name: app.name, - selfIntroductionContent: { title: '자기소개서', content: [] }, - ...(portfolioFile && { portfolioFile }), - interviewQuestions: [], - docsComments: [], - interviewComments: [], - interviewContent: { title: '면접 평가', content: [] }, - }; return ( -
+
{date.slice(5).replace('-', '/')} | {startTime}~{endTime} |{' '} - {applications.map((a) => a.name).join(', ')} + {applicants.map((a) => a.name).join(', ')} - - { - router.push( - `/apply-management/interviews/${app.applicationId}?recruitmentId=${recruitmentId}` - ); - }} - applicants={toggleApplicants} - currentId={app.applicationId} - onSelect={handleToggleSelect} + ({ + id: a.applicationId, + name: a.name, + imageUrl: '', + }))} + currentId={applicant.applicationId} + onSelect={handleSelectApplicant} + /> + + + {/* 좌측: 지원자 상세 */} + - + + {/* 우측: 카드 영역 (완전히 동일) */} +
+ + + + + ({ + evaluator: c.user.name, + comment: c.content, + profileColor: c.user.profileColor, + profileUrl: c.user.profileImageUrl, + }))} + /> + + ({ + evaluator: c.user.name, + comment: c.content, + profileColor: c.user.profileColor, + profileUrl: c.user.profileImageUrl, + }))} + /> + + ({ + evaluator: q.user.name, + comment: q.content, + profileColor: q.user.profileColor, + profileUrl: q.user.profileImageUrl, + }))} + /> + + ({ + name: a.name, + profileColor: a.profileColor, + profileUrl: a.profileImageUrl ?? null, + }))} + /> +
); diff --git a/apps/web/src/app/(main)/interview-management/timetable/[tab]/[date]/application/[time]/page.css.ts b/apps/web/src/app/(main)/interview-management/timetable/[tab]/[date]/application/[time]/page.css.ts index ab67b9c6..b76eebf3 100644 --- a/apps/web/src/app/(main)/interview-management/timetable/[tab]/[date]/application/[time]/page.css.ts +++ b/apps/web/src/app/(main)/interview-management/timetable/[tab]/[date]/application/[time]/page.css.ts @@ -1,5 +1,22 @@ +import { vars } from "@repo/theme"; import { style } from "@vanilla-extract/css"; export const pageContainer = style({ width: '100%' -}) \ No newline at end of file +}) + + +export const container1 = style({ + width: '100%', + backgroundColor: vars.colors.bg, + display: 'flex', + //gap: '4rem', + flexDirection: 'column', + }); + + export const rightSection = style({ + display: 'flex', + flexDirection: 'column', + gap: '2rem', + }); + \ No newline at end of file From b9e90aa37e972706f152c70602457e0294232b44 Mon Sep 17 00:00:00 2001 From: cindy-chaewon Date: Tue, 27 Jan 2026 17:12:53 +0900 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20=EA=B4=80=EB=A6=AC=EC=9E=90=20?= =?UTF-8?q?=EB=A9=B4=EC=A0=91=20UI=20=EC=88=98=EC=A0=95=20(#205)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../[date]/application/[time]/ApplicantDetailClient.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/web/src/app/(main)/interview-management/timetable/[tab]/[date]/application/[time]/ApplicantDetailClient.tsx b/apps/web/src/app/(main)/interview-management/timetable/[tab]/[date]/application/[time]/ApplicantDetailClient.tsx index 5f7d7c35..9f6fbe40 100644 --- a/apps/web/src/app/(main)/interview-management/timetable/[tab]/[date]/application/[time]/ApplicantDetailClient.tsx +++ b/apps/web/src/app/(main)/interview-management/timetable/[tab]/[date]/application/[time]/ApplicantDetailClient.tsx @@ -45,24 +45,20 @@ if (!applicant) return null; const applicationId = applicant.applicationId; -// 2️⃣ 지원서 상세 +// 2지원서 상세 const { data: data, isLoading: detailLoading, isError, } = useApplicationDetailQuery({ applicationId }); -// 3️⃣ 모집 정보 +// 모집 정보 const { data: rec, isLoading: recLoading } = useRecruitmentDetailQuery({ recruitmentId }); if (listLoading || detailLoading || recLoading) return null; if (!data || !rec || isError) return null; -// ====================== -// ✅ 카드 데이터 (ApplicationDetailClient와 동일) -// ====================== - const documentCompletedForCard: CompletedEvaluator[] = (data.documentCompleted ?? []).map((c) => ({ evaluator: {