|
1 | | -"use client"; |
2 | | - |
3 | | -import Link from "next/link"; |
4 | 1 | import { ArtistListItem } from "@/types/artists"; |
5 | | -import Image from "next/image"; |
6 | | -import { Heart } from "lucide-react"; |
7 | | -import { Button } from "@/components/ui/button"; |
8 | | -import { twMerge } from "tailwind-merge"; |
9 | | -import { likeArtist } from "@/lib/artists/artists"; |
10 | | -import { toast } from "sonner"; |
11 | 2 | import React from "react"; |
12 | | - |
13 | | -// TODO: |
14 | | -// - 아티스트 좋아요(팔로우) 상태를 서버에서 함께 내려받아 초기 상태로 관리해야 함 |
15 | | -// - 좋아요 상태에 따라 하트 아이콘을 빨간색(fill-red-500)으로 표시 |
16 | | -// - 이미 좋아요된 상태에서 버튼 클릭 시 좋아요 취소(unlike) API 호출하도록 분기 처리 |
17 | | -// - 좋아요/취소 시 optimistic update 적용 검토 |
| 3 | +import ArtistListCard from "@/components/artist/list/ArtistListCard"; |
18 | 4 |
|
19 | 5 | export default function ArtistListItems({ artists }: { artists: ArtistListItem[] }) { |
20 | | - // TODO: |
21 | | - // - 현재는 likeArtist만 호출 중 |
22 | | - // - 추후 isLiked 상태에 따라 |
23 | | - // - true -> unlikeArtist(id) 호출 |
24 | | - // - false -> likeArtist(id) 호출 |
25 | | - // - 서버에서 내려주는 msg에 따라 toast 메시지 분기 처리 |
26 | | - const likeArtistAction = async (id: number) => { |
27 | | - try { |
28 | | - // TODO: isLiked 상태에 따라 like / unlike 분기 필요 |
29 | | - await likeArtist(id); |
30 | | - toast.success("아티스트를 좋아요 했어요!"); |
31 | | - } catch (err) { |
32 | | - if (err instanceof Error) { |
33 | | - toast.error(err.message); |
34 | | - } else { |
35 | | - toast.error("알 수 없는 오류가 발생했습니다."); |
36 | | - } |
37 | | - } |
38 | | - }; |
39 | | - |
40 | | - const handleLikeClick = async (e: React.MouseEvent<HTMLButtonElement>, id: number) => { |
41 | | - e.preventDefault(); |
42 | | - e.stopPropagation(); |
43 | | - |
44 | | - // TODO: |
45 | | - // - 중복 클릭 방지를 위한 loading 상태 추가 |
46 | | - // - 요청 중에는 버튼 disabled 처리 |
47 | | - await likeArtistAction(id); |
48 | | - }; |
49 | | - |
50 | 6 | return ( |
51 | 7 | <div className="grid gap-x-8 gap-y-12 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5"> |
52 | 8 | {artists.map((artist) => ( |
53 | | - <Link |
54 | | - key={artist.id} |
55 | | - href={`/artists/${artist.id}`} |
56 | | - className="group flex flex-col gap-5 transition hover:opacity-90" |
57 | | - > |
58 | | - <div className="border-border/60 relative aspect-square overflow-hidden rounded-lg border"> |
59 | | - <Image |
60 | | - src={artist.imageUrl || "/images/artist-placeholder.png"} |
61 | | - alt="Concert Poster" |
62 | | - fill |
63 | | - sizes="(min-width: 1024px) 20vw, (min-width: 768px) 25vw, 50vw" |
64 | | - className="object-cover" |
65 | | - /> |
66 | | - <Button |
67 | | - onClick={(e) => handleLikeClick(e, artist.id)} |
68 | | - type="button" |
69 | | - aria-label="아티스트 좋아요" |
70 | | - className="absolute top-2 right-2 h-9 w-9 scale-90 rounded-full bg-black/20 opacity-0 backdrop-blur-sm transition-all duration-200 group-hover:scale-100 group-hover:opacity-100" |
71 | | - > |
72 | | - <Heart |
73 | | - className={twMerge( |
74 | | - "h-5 w-5 transition", |
75 | | - // TODO: isLiked === true 일 때 fill-red-500 text-red-500 적용 |
76 | | - // TODO: isLiked === false 일 때 fill-white text-white 적용 |
77 | | - "fill-white text-white" |
78 | | - )} |
79 | | - strokeWidth={0} |
80 | | - /> |
81 | | - </Button> |
82 | | - </div> |
83 | | - <strong className="line-clamp-1 text-2xl">{artist.artistName}</strong> |
84 | | - </Link> |
| 9 | + <ArtistListCard key={artist.id} artist={artist} /> |
85 | 10 | ))} |
86 | 11 | </div> |
87 | 12 | ); |
|
0 commit comments