Skip to content

Commit 96cdd00

Browse files
authored
Merge pull request #81 from Team-StackUp/feature/enhance-workspace-ui/ux
feat : workspace ui/ux 개선
2 parents c756efc + ee8e6d3 commit 96cdd00

16 files changed

Lines changed: 473 additions & 184 deletions

File tree

frontend/src/app/router/index.tsx

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createBrowserRouter } from 'react-router-dom'
1+
import { createBrowserRouter, Navigate } from 'react-router-dom'
22
import { RequireAuth } from '@/features/auth'
33
import HomePage from '@/pages/Home'
44
import LoginPage from '@/pages/Login'
@@ -7,7 +7,6 @@ import WorkspacePage from '@/pages/Workspace'
77
import InterviewSetupPage from '@/pages/InterviewSetup'
88
import InterviewSessionPage from '@/pages/InterviewSession'
99
import SessionFeedbackPage from '@/pages/SessionFeedback'
10-
import HistoryPage from '@/pages/History'
1110
import SharedFeedbackPage from '@/pages/SharedFeedback'
1211

1312
export const router = createBrowserRouter([
@@ -23,6 +22,22 @@ export const router = createBrowserRouter([
2322
</RequireAuth>
2423
),
2524
},
25+
{
26+
path: '/workspace/resumes',
27+
element: (
28+
<RequireAuth>
29+
<WorkspacePage />
30+
</RequireAuth>
31+
),
32+
},
33+
{
34+
path: '/workspace/repos',
35+
element: (
36+
<RequireAuth>
37+
<WorkspacePage />
38+
</RequireAuth>
39+
),
40+
},
2641
{
2742
path: '/sessions/new',
2843
element: (
@@ -48,13 +63,14 @@ export const router = createBrowserRouter([
4863
),
4964
},
5065
{
51-
path: '/history',
66+
path: '/workspace/history',
5267
element: (
5368
<RequireAuth>
54-
<HistoryPage />
69+
<WorkspacePage />
5570
</RequireAuth>
5671
),
5772
},
73+
{ path: '/history', element: <Navigate to="/workspace/history" replace /> },
5874
{
5975
path: '/design-system/*',
6076
lazy: async () => {

frontend/src/features/analysis/ui/DocumentList.tsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ const SOURCE_LABEL: Record<AnalysisSourceType, string> = {
2424

2525
type Props = {
2626
filter?: DocumentFilter
27+
// 클라이언트에서 소스 유형으로 한정 (탭별 분석 결과 분리용).
28+
sourceType?: AnalysisSourceType
2729
}
2830

29-
export function DocumentList({ filter = {} }: Props) {
31+
export function DocumentList({ filter = {}, sourceType }: Props) {
3032
const { data = [], isPending, isError, error } = useDocuments(filter)
3133

3234
if (isPending) {
@@ -39,20 +41,26 @@ export function DocumentList({ filter = {} }: Props) {
3941
</p>
4042
)
4143
}
42-
if (data.length === 0) {
44+
45+
const docs = sourceType
46+
? data.filter((doc) => doc.sourceType === sourceType)
47+
: data
48+
49+
if (docs.length === 0) {
50+
const subject = sourceType ? SOURCE_LABEL[sourceType] : '이력서·레포'
4351
return (
4452
<div className="rounded-xl border border-dashed border-border-strong bg-surface p-10 text-center">
4553
<p className="text-body text-fg-muted">아직 분석된 문서가 없습니다.</p>
4654
<p className="text-caption text-fg-subtle mt-2">
47-
이력서·레포 분석이 완료되면 요약과 기술 스택이 여기에 표시됩니다.
55+
{subject} 분석이 완료되면 요약과 기술 스택이 여기에 표시됩니다.
4856
</p>
4957
</div>
5058
)
5159
}
5260

5361
return (
5462
<ul className="flex flex-col gap-3">
55-
{data.map((doc) => (
63+
{docs.map((doc) => (
5664
<DocumentRow key={doc.id} doc={doc} />
5765
))}
5866
</ul>

frontend/src/pages/CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ pages/Workspace/
4040
| `Workspace` | `/workspace` | `features/resume`, `features/repo` (도입 예정) |
4141
| `Interview` | `/sessions/new`, `/sessions/:id` | `features/interview` |
4242
| `Interview (Feedback)` | `/sessions/:id/feedback` | `features/feedback` |
43-
| `History` | `/history`, `/history/:id` | `features/history` (도입 예정) |
43+
| `History` | `/workspace/history` (구 `/history` → 리다이렉트) | `features/history` |
4444

4545
---
4646

frontend/src/pages/History/index.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

frontend/src/pages/History/ui/HistoryPage.tsx

Lines changed: 0 additions & 34 deletions
This file was deleted.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import {
2+
ScoreTrend,
3+
SessionHistoryList,
4+
StatsSummary,
5+
useUserStats,
6+
} from '@/features/history'
7+
8+
export function HistoryView() {
9+
const { data: stats } = useUserStats()
10+
11+
return (
12+
<div className="space-y-8">
13+
{stats && (
14+
<div className="grid gap-4 md:grid-cols-2">
15+
<StatsSummary stats={stats} />
16+
<ScoreTrend stats={stats} />
17+
</div>
18+
)}
19+
20+
<section className="flex flex-col gap-3">
21+
<h2 className="text-h6 text-fg">지난 면접</h2>
22+
<SessionHistoryList />
23+
</section>
24+
</div>
25+
)
26+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import { Link } from 'react-router-dom'
2+
import {
3+
ScoreTrend,
4+
StatsSummary,
5+
useUserStats,
6+
} from '@/features/history'
7+
import { Button } from '@/shared/ui/Button'
8+
9+
export function HomeView() {
10+
const { data: stats } = useUserStats()
11+
const hasSessions = (stats?.totalSessionCount ?? 0) > 0
12+
13+
return (
14+
<div className="space-y-8">
15+
<section className="overflow-hidden rounded-2xl border border-border bg-sage-600 p-8 text-white">
16+
<p className="text-caption uppercase tracking-[0.08em] text-white/60">
17+
맞춤 모의 면접
18+
</p>
19+
<h2 className="mt-2 font-heading text-h4 font-bold">
20+
이력서·레포 기반 맞춤 면접을 시작하세요
21+
</h2>
22+
<p className="mt-2 max-w-xl text-body text-white/70">
23+
면접 모드와 직군을 고르면 AI가 질문을 생성하고, 실시간으로 답변을
24+
주고받습니다.
25+
</p>
26+
<div className="mt-6 flex flex-wrap gap-3">
27+
<Link to="/sessions/new">
28+
<Button size="lg" variant="secondary">
29+
새 면접 시작
30+
</Button>
31+
</Link>
32+
<Link to="/workspace/resumes">
33+
<Button
34+
size="lg"
35+
variant="ghost"
36+
className="text-white hover:bg-white/10"
37+
>
38+
자료 준비하기
39+
</Button>
40+
</Link>
41+
</div>
42+
</section>
43+
44+
<div className="grid gap-4 md:grid-cols-3">
45+
<QuickLink
46+
to="/workspace/resumes"
47+
title="이력서"
48+
description="이력서를 업로드하고 분석 결과를 확인하세요."
49+
/>
50+
<QuickLink
51+
to="/workspace/repos"
52+
title="레포지토리"
53+
description="GitHub 레포를 등록하고 분석 결과를 확인하세요."
54+
/>
55+
<QuickLink
56+
to="/workspace/history"
57+
title="면접 히스토리"
58+
description="지난 면접 기록과 점수 추이를 확인하세요."
59+
/>
60+
</div>
61+
62+
{hasSessions && stats && (
63+
<section className="space-y-3">
64+
<h2 className="text-h6 text-fg">한눈에 보기</h2>
65+
<div className="grid gap-4 md:grid-cols-2">
66+
<StatsSummary stats={stats} />
67+
<ScoreTrend stats={stats} />
68+
</div>
69+
</section>
70+
)}
71+
</div>
72+
)
73+
}
74+
75+
function QuickLink({
76+
to,
77+
title,
78+
description,
79+
}: {
80+
to: string
81+
title: string
82+
description: string
83+
}) {
84+
return (
85+
<Link
86+
to={to}
87+
className="group flex items-center justify-between gap-4 rounded-xl border border-border bg-surface-raised p-5 transition-colors duration-fast hover:border-border-strong hover:bg-surface"
88+
>
89+
<div>
90+
<h3 className="font-heading text-h6 font-bold text-fg-strong">
91+
{title}
92+
</h3>
93+
<p className="mt-1 text-caption text-fg-muted">{description}</p>
94+
</div>
95+
<span
96+
aria-hidden
97+
className="text-fg-muted transition-transform duration-fast group-hover:translate-x-0.5"
98+
>
99+
100+
</span>
101+
</Link>
102+
)
103+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { WorkspaceSection } from '@/widgets/workspace-section'
2+
import { RepoList, RepoPicker } from '@/features/repo'
3+
import { DocumentList } from '@/features/analysis'
4+
5+
export function ReposView() {
6+
return (
7+
<div className="space-y-10">
8+
<WorkspaceSection
9+
title="내 GitHub 레포지토리"
10+
description="등록한 레포를 기반으로 코드 맥락에 맞는 질문이 생성됩니다."
11+
>
12+
<div className="space-y-4">
13+
<RepoPicker />
14+
<RepoList />
15+
</div>
16+
</WorkspaceSection>
17+
18+
<WorkspaceSection
19+
title="레포지토리 분석 결과"
20+
description="등록한 레포의 요약과 추출된 기술 스택입니다."
21+
>
22+
<DocumentList sourceType="REPOSITORY" />
23+
</WorkspaceSection>
24+
</div>
25+
)
26+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { WorkspaceSection } from '@/widgets/workspace-section'
2+
import { ResumeList, ResumeUploader } from '@/features/resume'
3+
import { DocumentList } from '@/features/analysis'
4+
5+
export function ResumesView() {
6+
return (
7+
<div className="space-y-10">
8+
<WorkspaceSection
9+
title="내 이력서"
10+
description="PDF 이력서를 업로드하면 AI가 분석해 면접 질문 풀에 반영합니다."
11+
action={<ResumeUploader />}
12+
>
13+
<ResumeList />
14+
</WorkspaceSection>
15+
16+
<WorkspaceSection
17+
title="이력서 분석 결과"
18+
description="업로드한 이력서의 요약과 추출된 기술 스택입니다."
19+
>
20+
<DocumentList sourceType="RESUME" />
21+
</WorkspaceSection>
22+
</div>
23+
)
24+
}

0 commit comments

Comments
 (0)