Skip to content

Commit 727f753

Browse files
bebuslclaude
andcommitted
feat: [FN-348] 나의 학습 카드셋 UI 개선 및 카드셋 상세 페이지 이동 기능 추가
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent ce873f8 commit 727f753

1 file changed

Lines changed: 84 additions & 62 deletions

File tree

src/features/my-study/components/my-study-page.tsx

Lines changed: 84 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,78 @@
1-
import { Card, CardContent } from "@/shared/components/card";
21
import { Button } from "@/shared/components/button";
3-
import { Bookmark, Heart, BookOpen } from "lucide-react";
4-
import { CardGridSkeleton } from "@/shared/components/skeletons";
2+
import { Bookmark, Heart, BookOpen, ChevronRight } from "lucide-react";
3+
import { CardSetListSkeleton } from "@/shared/components/skeletons";
54
import { useMyBookmarkedCardSets } from "@/domain/study/hooks/use-my-bookmarked-card-sets";
65
import { useMyLikedCardSets } from "@/domain/study/hooks/use-my-liked-card-sets";
76
import type { CardSetWithBookmark, CardSetWithLike } from "@/domain/study/types";
87
import { formatDistanceToNow } from "date-fns";
98
import { ko } from "date-fns/locale";
109
import ErrorDisplay from "@/shared/components/error-display";
1110
import { EmptyState } from "@/shared/components/empty-state";
11+
import { Link } from "@tanstack/react-router";
12+
13+
type CardSetItem = CardSetWithBookmark | CardSetWithLike;
14+
15+
const CardSetListItem = ({
16+
cardSet,
17+
timestamp,
18+
}: {
19+
cardSet: CardSetItem;
20+
timestamp: string;
21+
}) => (
22+
<Link
23+
to="/groups/$groupId/cardsets/$cardsetId"
24+
params={{
25+
groupId: String(cardSet.groupId),
26+
cardsetId: String(cardSet.cardSetId),
27+
}}
28+
className="flex items-center justify-between px-4 py-3 rounded-lg hover:bg-muted transition-colors group"
29+
>
30+
<div className="flex items-center gap-3 min-w-0">
31+
<BookOpen className="w-4 h-4 text-muted-foreground shrink-0" />
32+
<span className="text-sm font-medium text-gray-900 truncate group-hover:text-primary transition-colors">
33+
{cardSet.name}
34+
</span>
35+
</div>
36+
<div className="flex items-center gap-2 shrink-0 ml-3">
37+
<span className="text-xs text-muted-foreground">
38+
{formatDistanceToNow(new Date(timestamp), {
39+
addSuffix: true,
40+
locale: ko,
41+
})}
42+
</span>
43+
<ChevronRight className="w-4 h-4 text-muted-foreground group-hover:text-primary transition-colors" />
44+
</div>
45+
</Link>
46+
);
47+
48+
const renderCardSetList = (
49+
cardSets: CardSetItem[],
50+
timestampKey: "bookmarkedAt" | "likedAt"
51+
) => {
52+
if (cardSets.length === 0) {
53+
return (
54+
<EmptyState
55+
icon={<BookOpen className="w-8 h-8" />}
56+
title="카드셋이 없습니다"
57+
/>
58+
);
59+
}
60+
61+
return (
62+
<div className="divide-y divide-border rounded-lg border">
63+
{cardSets.map((cardSet) => {
64+
const timestamp = (cardSet as unknown as Record<string, string>)[timestampKey];
65+
return (
66+
<CardSetListItem
67+
key={cardSet.cardSetId}
68+
cardSet={cardSet}
69+
timestamp={timestamp}
70+
/>
71+
);
72+
})}
73+
</div>
74+
);
75+
};
1276

1377
export const MyStudyPage = () => {
1478
const {
@@ -34,70 +98,29 @@ export const MyStudyPage = () => {
3498
const bookmarkedCardSets = bookmarkedData?.bookmarks ?? [];
3599
const likedCardSets = likedData?.likes ?? [];
36100

37-
const renderCardSetGrid = (
38-
cardSets: CardSetWithBookmark[] | CardSetWithLike[],
39-
timestampKey: "bookmarkedAt" | "likedAt"
40-
) => {
41-
if (cardSets.length === 0) {
42-
return (
43-
<EmptyState
44-
icon={<BookOpen className="w-8 h-8" />}
45-
title="카드셋이 없습니다"
46-
/>
47-
);
48-
}
49-
50-
return (
51-
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3">
52-
{cardSets.map((cardSet) => {
53-
const timestamp = (cardSet as unknown as Record<string, string>)[timestampKey];
54-
return (
55-
<Card
56-
key={cardSet.cardSetId}
57-
className="hover:shadow-md transition-shadow cursor-default"
58-
>
59-
<CardContent className="p-4 flex flex-col gap-2">
60-
<p className="font-medium text-gray-900 line-clamp-2 leading-snug">
61-
{cardSet.name}
62-
</p>
63-
<p className="text-xs text-muted-foreground">
64-
{formatDistanceToNow(new Date(timestamp), {
65-
addSuffix: true,
66-
locale: ko,
67-
})}
68-
</p>
69-
</CardContent>
70-
</Card>
71-
);
72-
})}
73-
</div>
74-
);
75-
};
76-
77101
return (
78-
<div className="space-y-12">
102+
<div className="space-y-10">
79103
{/* 즐겨찾기 섹션 */}
80-
<section className="space-y-4">
104+
<section className="space-y-3">
81105
<div className="flex items-center gap-2">
82-
<Bookmark className="w-6 h-6 text-primary" />
83-
<h2 className="text-2xl font-semibold text-gray-900">
84-
즐겨찾기 카드셋
85-
</h2>
106+
<Bookmark className="w-5 h-5 text-primary" />
107+
<h2 className="text-lg font-semibold text-gray-900">즐겨찾기 카드셋</h2>
86108
</div>
87109

88110
{isLoadingBookmarks ? (
89-
<CardGridSkeleton />
111+
<CardSetListSkeleton />
90112
) : bookmarksError ? (
91113
<ErrorDisplay onRetry={() => refetchBookmarks()} />
92114
) : (
93115
<>
94-
{renderCardSetGrid(bookmarkedCardSets, "bookmarkedAt")}
116+
{renderCardSetList(bookmarkedCardSets, "bookmarkedAt")}
95117
{hasNextBookmarks && (
96-
<div className="flex justify-center pt-4">
118+
<div className="flex justify-center pt-2">
97119
<Button
98120
onClick={() => fetchNextBookmarks()}
99121
disabled={isFetchingNextBookmarks}
100-
variant="outline"
122+
variant="ghost"
123+
size="sm"
101124
>
102125
{isFetchingNextBookmarks ? "로딩 중..." : "더 보기"}
103126
</Button>
@@ -108,27 +131,26 @@ export const MyStudyPage = () => {
108131
</section>
109132

110133
{/* 좋아요 섹션 */}
111-
<section className="space-y-4">
134+
<section className="space-y-3">
112135
<div className="flex items-center gap-2">
113-
<Heart className="w-6 h-6 text-red-500" />
114-
<h2 className="text-2xl font-semibold text-gray-900">
115-
좋아요한 카드셋
116-
</h2>
136+
<Heart className="w-5 h-5 text-red-500" />
137+
<h2 className="text-lg font-semibold text-gray-900">좋아요한 카드셋</h2>
117138
</div>
118139

119140
{isLoadingLikes ? (
120-
<CardGridSkeleton />
141+
<CardSetListSkeleton />
121142
) : likesError ? (
122143
<ErrorDisplay onRetry={() => refetchLikes()} />
123144
) : (
124145
<>
125-
{renderCardSetGrid(likedCardSets, "likedAt")}
146+
{renderCardSetList(likedCardSets, "likedAt")}
126147
{hasNextLikes && (
127-
<div className="flex justify-center pt-4">
148+
<div className="flex justify-center pt-2">
128149
<Button
129150
onClick={() => fetchNextLikes()}
130151
disabled={isFetchingNextLikes}
131-
variant="outline"
152+
variant="ghost"
153+
size="sm"
132154
>
133155
{isFetchingNextLikes ? "로딩 중..." : "더 보기"}
134156
</Button>

0 commit comments

Comments
 (0)