1- import { Card , CardContent } from "@/shared/components/card" ;
21import { 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" ;
54import { useMyBookmarkedCardSets } from "@/domain/study/hooks/use-my-bookmarked-card-sets" ;
65import { useMyLikedCardSets } from "@/domain/study/hooks/use-my-liked-card-sets" ;
76import type { CardSetWithBookmark , CardSetWithLike } from "@/domain/study/types" ;
87import { formatDistanceToNow } from "date-fns" ;
98import { ko } from "date-fns/locale" ;
109import ErrorDisplay from "@/shared/components/error-display" ;
1110import { 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
1377export 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