Skip to content

Commit 0ad93b5

Browse files
authored
Merge pull request #31 from Leets-Official/feat/#30/job-bookmarks-page
2 parents 4515bfb + 0c359cc commit 0ad93b5

14 files changed

Lines changed: 541 additions & 61 deletions

src/components/common/Tab.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { type ComponentPropsWithRef } from 'react';
33
import { cn } from '@/utils/cn';
44

55
const tabVariants = cva(
6-
'flex cursor-pointer items-center justify-center text-[18px] leading-normal font-bold text-text-primary',
6+
'flex cursor-pointer items-center justify-center text-[18px] leading-normal font-bold text-text-primary transition-[color,border-color] duration-150 motion-reduce:transition-none',
77
{
88
variants: {
99
variant: {
@@ -18,6 +18,7 @@ const tabVariants = cva(
1818
compoundVariants: [
1919
{ variant: 'filled', active: true, className: 'bg-primary-400 text-white' },
2020
{ variant: 'underline', active: true, className: 'border-primary-400' },
21+
{ variant: 'underline', active: false, className: 'text-text-tertiary' },
2122
],
2223
defaultVariants: {
2324
variant: 'filled',

src/features/recommendations/components/RecommendationCompletion.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,26 +25,26 @@ export default function RecommendationCompletion({
2525
return (
2626
<section
2727
ref={ref}
28-
className={cn('flex flex-col items-center gap-6 text-center', className)}
28+
className={cn('flex flex-col items-center gap-5 text-center', className)}
2929
{...props}
3030
>
31-
<div className="flex flex-col items-center gap-2">
32-
<h1 className="text-heading-large font-bold text-text-primary">
31+
<div className="flex flex-col items-center gap-5">
32+
<h1 className="text-display-medium leading-[1.2] font-bold text-text-primary">
3333
오늘의 레터를 다 보셨어요.
3434
</h1>
35-
<p className="text-body-large font-medium text-text-secondary">
35+
<p className="text-heading-medium font-medium text-text-secondary">
3636
저장 {savedCount}건 · 관심 없음 {dismissedCount}건 · 열람 {viewedCount}
3737
</p>
3838
</div>
39-
<div className="flex items-center gap-3">
40-
<Button className="w-45" onClick={onViewSaved}>
39+
<div className="flex items-center gap-15">
40+
<Button className="w-62.5" onClick={onViewSaved}>
4141
저장 목록 보기
4242
</Button>
43-
<Button variant="outline" className="w-45" onClick={onExplore}>
43+
<Button variant="outline" className="w-62.5" onClick={onExplore}>
4444
탐색 둘러보기
4545
</Button>
4646
</div>
47-
<p className="text-body-small font-medium text-text-tertiary">{nextLetterNotice}</p>
47+
<p className="text-heading-small font-medium text-text-tertiary">{nextLetterNotice}</p>
4848
</section>
4949
);
5050
}

src/features/recommendations/components/RecommendationFlowContent.tsx

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export type RecommendationScreen =
2424
| 'deck'
2525
| 'news'
2626
| 'complete'
27-
| 'revisit'
27+
| 'archive'
2828
| 'empty-candidates'
2929
| 'empty-signup'
3030
| 'empty-before-send';
@@ -168,21 +168,26 @@ export default function RecommendationFlowContent({
168168
dismissedCount={dismissedCount}
169169
viewedCount={viewedCount}
170170
nextLetterNotice="내일 오전 7시 30분경, 다음 레터가 도착해요."
171-
onViewSaved={() => navigate('/recommendations/revisit')}
171+
onViewSaved={() => navigate('/recommendations/archive')}
172172
onExplore={() => navigate('/explore')}
173173
/>
174174
</ScreenLayout>
175175
);
176176
}
177177

178-
if (screen === 'revisit') {
178+
if (screen === 'archive') {
179179
const displayIndex = Math.min(cardIndex, Math.max(filteredLetters.length - 1, 0));
180180
const letter = filteredLetters[displayIndex];
181+
const contentKey = letter?.id ?? `empty-${activeStatus}`;
181182
return (
182183
<ScreenLayout>
183184
<RecommendationLetterCarousel
185+
key={activeStatus}
186+
className="gap-5"
184187
current={filteredLetters.length === 0 ? 0 : displayIndex + 1}
185188
total={filteredLetters.length}
189+
contentKey={contentKey}
190+
enableStackTransition
186191
onPrev={() => setCardIndex(Math.max(displayIndex - 1, 0))}
187192
onNext={() => setCardIndex(Math.min(displayIndex + 1, filteredLetters.length - 1))}
188193
prevDisabled={displayIndex === 0}
@@ -198,20 +203,22 @@ export default function RecommendationFlowContent({
198203
/>
199204
}
200205
>
201-
{letter ? (
202-
<RecommendationLetterCard
203-
{...letter}
204-
onExpand={() => navigate(`/jobs/${letter.id}`)}
205-
onSave={() => setStatus(letter.id, 'saved')}
206-
onDismiss={() => setStatus(letter.id, 'dismissed')}
207-
/>
208-
) : (
209-
<div className="flex w-full max-w-130 flex-col items-center gap-2 rounded-sm border border-gray-200 bg-white p-10 text-center">
210-
<p className="text-body-large font-medium text-text-secondary">
211-
{EMPTY_MESSAGE[activeStatus]}
212-
</p>
213-
</div>
214-
)}
206+
<div key={activeStatus} className="page-content-enter">
207+
{letter ? (
208+
<RecommendationLetterCard
209+
{...letter}
210+
onExpand={() => navigate(`/jobs/${letter.id}`)}
211+
onSave={() => setStatus(letter.id, 'saved')}
212+
onDismiss={() => setStatus(letter.id, 'dismissed')}
213+
/>
214+
) : (
215+
<div className="flex min-h-142 w-190 items-center justify-center rounded-md border border-gray-200 bg-white p-6 text-center">
216+
<p className="text-heading-small font-medium text-text-secondary">
217+
{EMPTY_MESSAGE[activeStatus]}
218+
</p>
219+
</div>
220+
)}
221+
</div>
215222
</RecommendationLetterCarousel>
216223
</ScreenLayout>
217224
);
@@ -262,10 +269,10 @@ export default function RecommendationFlowContent({
262269
description={notice.description}
263270
footNote={notice.footNote}
264271
>
265-
<Button className="w-[414px]" onClick={handlePrimaryAction}>
272+
<Button className="w-103.5" onClick={handlePrimaryAction}>
266273
{notice.primary}
267274
</Button>
268-
<Button className="w-[414px]" variant="outline" onClick={() => navigate('/explore')}>
275+
<Button className="w-103.5" variant="outline" onClick={() => navigate('/explore')}>
269276
탐색 둘러보기
270277
</Button>
271278
</RecommendationNoticePanel>

src/features/recommendations/components/RecommendationLetterCard.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@ export default function RecommendationLetterCard({
4242
<div className={cn('relative w-190', className)}>
4343
<div
4444
aria-hidden="true"
45-
className="absolute inset-0 translate-x-6 rounded-md border border-gray-200 bg-white"
45+
className="absolute inset-0 translate-x-10.5 rounded-md border border-gray-200 bg-white"
4646
/>
4747
<div
4848
aria-hidden="true"
49-
className="absolute inset-0 translate-x-3 rounded-md border border-gray-200 bg-white"
49+
className="absolute inset-0 translate-x-5.25 rounded-md border border-gray-200 bg-white"
5050
/>
5151
<article
5252
ref={ref}
@@ -86,7 +86,7 @@ export default function RecommendationLetterCard({
8686

8787
<div className="flex w-full flex-col gap-1 rounded-sm bg-gray-200 p-4">
8888
<p className="text-label-small font-bold text-text-tertiary">{noteTitle}</p>
89-
<p className="min-h-[42px] text-body-small leading-normal font-medium text-text-secondary">
89+
<p className="min-h-10.5 text-body-small leading-normal font-medium text-text-secondary">
9090
{note}
9191
</p>
9292
</div>

src/features/recommendations/components/RecommendationLetterCarousel.tsx

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export default function RecommendationLetterCarousel({
3232
enableStackTransition = false,
3333
className,
3434
}: RecommendationLetterCarouselProps) {
35+
const hasItems = total > 0;
3536
const [activeContent, setActiveContent] = useState({ key: contentKey, node: children });
3637
const activeContentRef = useRef(activeContent);
3738
const previousCurrentRef = useRef(current);
@@ -80,16 +81,14 @@ export default function RecommendationLetterCarousel({
8081
};
8182

8283
return (
83-
<div className={cn('flex flex-col items-center gap-4', className)}>
84+
<div aria-busy={isAnimating} className={cn('flex flex-col items-center gap-4', className)}>
8485
{filterSlot}
8586
<div className="flex items-center gap-16">
86-
<CarouselArrow
87-
direction="left"
88-
onClick={handlePrev}
89-
disabled={prevDisabled || isAnimating}
90-
/>
87+
{hasItems && (
88+
<CarouselArrow direction="left" onClick={handlePrev} disabled={prevDisabled} />
89+
)}
9190
{enableStackTransition ? (
92-
<div className="relative flex min-h-[524px] w-196 items-center overflow-x-clip">
91+
<div className="relative flex min-h-[524px] w-[802px] translate-x-[21px] items-center overflow-x-clip">
9392
{leavingContent && (
9493
<div
9594
aria-hidden="true"
@@ -123,22 +122,29 @@ export default function RecommendationLetterCarousel({
123122
) : (
124123
children
125124
)}
126-
<CarouselArrow
127-
direction="right"
128-
onClick={handleNext}
129-
disabled={nextDisabled || isAnimating}
130-
/>
131-
</div>
132-
<div className="flex items-center gap-2">
133-
<CarouselIndicator variant="number" current={current} total={total} />
134-
<CarouselIndicator variant="dot" total={total} activeIndex={current - 1} />
125+
{hasItems && (
126+
<CarouselArrow direction="right" onClick={handleNext} disabled={nextDisabled} />
127+
)}
135128
</div>
136-
<p
137-
aria-hidden={!footNote}
138-
className="min-h-6 text-body-medium font-medium text-text-tertiary"
139-
>
140-
{footNote}
141-
</p>
129+
{hasItems ? (
130+
<>
131+
<div className="flex items-center gap-2">
132+
<CarouselIndicator variant="number" current={current} total={total} />
133+
<CarouselIndicator variant="dot" total={total} activeIndex={current - 1} />
134+
</div>
135+
<p
136+
aria-hidden={!footNote}
137+
className="min-h-6 text-heading-medium font-medium text-text-tertiary"
138+
>
139+
{footNote}
140+
</p>
141+
</>
142+
) : (
143+
<>
144+
<div aria-hidden="true" className="h-10" />
145+
<div aria-hidden="true" className="h-9" />
146+
</>
147+
)}
142148
</div>
143149
);
144150
}

src/features/recommendations/components/RecommendationStatusTabs.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@ export default function RecommendationStatusTabs({
1414
className,
1515
}: RecommendationStatusTabsProps) {
1616
return (
17-
<div className={cn('inline-flex items-center gap-3', className)}>
17+
<div
18+
className={cn(
19+
'flex w-190 items-center justify-center gap-2.5 overflow-hidden rounded-xs p-2.5',
20+
className,
21+
)}
22+
>
1823
{tabs.map((label, index) => {
1924
const active = index === activeIndex;
2025

@@ -24,10 +29,10 @@ export default function RecommendationStatusTabs({
2429
type="button"
2530
onClick={() => onChange?.(index)}
2631
className={cn(
27-
'flex h-12 items-center justify-center rounded-full px-6 text-[18px] font-bold whitespace-nowrap',
32+
'flex h-10 items-center justify-center rounded-full border border-transparent px-3 text-label-large font-medium whitespace-nowrap transition-[background-color,border-color] duration-150 motion-reduce:transition-none',
2833
active
2934
? 'bg-primary-600 text-gray-900'
30-
: 'border border-gray-200 bg-white text-text-primary hover:bg-gray-50',
35+
: 'border-gray-200 bg-white text-text-primary hover:bg-gray-50',
3136
)}
3237
>
3338
{label}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import Button from '@/components/common/Button';
2+
import { ResultIcon } from '@/components/feedback';
3+
4+
interface SavedJobsEmptyStateProps {
5+
title: string;
6+
description: string;
7+
onBrowseRecommendations: () => void;
8+
onExplore: () => void;
9+
}
10+
11+
export default function SavedJobsEmptyState({
12+
title,
13+
description,
14+
onBrowseRecommendations,
15+
onExplore,
16+
}: SavedJobsEmptyStateProps) {
17+
return (
18+
<div className="flex min-h-150 w-full max-w-285 self-center flex-col items-center justify-center gap-5">
19+
<ResultIcon variant="warning" />
20+
<p className="text-center text-heading-medium font-semibold text-text-primary">{title}</p>
21+
<p className="text-center text-label-medium font-medium text-text-secondary">{description}</p>
22+
<div className="w-174 border-t border-gray-200" />
23+
<Button className="h-14 w-62.5" onClick={onBrowseRecommendations}>
24+
오늘의 추천 보기
25+
</Button>
26+
<button
27+
type="button"
28+
className="cursor-pointer text-label-large font-medium text-text-tertiary underline decoration-from-font [text-underline-position:from-font]"
29+
onClick={onExplore}
30+
>
31+
탐색 둘러보기
32+
</button>
33+
</div>
34+
);
35+
}

0 commit comments

Comments
 (0)