From 244d6ce9834f78722cdbdb2c05572e75a347ac71 Mon Sep 17 00:00:00 2001 From: choi Date: Wed, 27 Nov 2024 13:58:38 +0900 Subject: [PATCH] =?UTF-8?q?=EC=9C=A0=EC=A0=80=20=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=EB=B6=88=EB=9F=AC=EC=98=A4=EA=B8=B0=20=EC=88=98=EC=A0=95=20+?= =?UTF-8?q?=20=EB=8D=94=EB=B3=B4=EA=B8=B0=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 17 ++ package.json | 2 + src/app/more/album/page.tsx | 199 +++++++++++++++++ src/app/more/artist/page.tsx | 137 ++++++++++++ src/app/more/playlist/page.tsx | 201 ++++++++++++++++++ src/app/more/track/page.tsx | 0 src/components/container/square-container.tsx | 2 +- src/components/ui/floating-dock.tsx | 8 +- src/features/main/bar.tsx | 2 +- src/features/main/main-album.tsx | 46 ++-- src/features/main/main-artist.tsx | 20 +- src/features/main/main-playlist.tsx | 20 +- src/features/main/main-track.tsx | 16 +- src/features/main/topbar.tsx | 4 +- src/lib/axios.ts | 25 +-- 15 files changed, 648 insertions(+), 51 deletions(-) create mode 100644 src/app/more/album/page.tsx create mode 100644 src/app/more/artist/page.tsx create mode 100644 src/app/more/playlist/page.tsx create mode 100644 src/app/more/track/page.tsx diff --git a/package-lock.json b/package-lock.json index f49fa49..1ee8d73 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,11 +18,13 @@ "@radix-ui/react-tabs": "^1.1.1", "@radix-ui/react-toast": "^1.2.1", "@tabler/icons-react": "^3.19.0", + "@types/js-cookie": "^3.0.6", "axios": "^1.7.7", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "cookie": "^1.0.1", "framer-motion": "^11.9.0", + "js-cookie": "^3.0.5", "lucide-react": "^0.446.0", "next": "14.2.13", "next-themes": "^0.3.0", @@ -1904,6 +1906,12 @@ "react": ">= 16" } }, + "node_modules/@types/js-cookie": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-3.0.6.tgz", + "integrity": "sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==", + "license": "MIT" + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -4819,6 +4827,15 @@ "jiti": "bin/jiti.js" } }, + "node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", diff --git a/package.json b/package.json index 1a3c098..3195231 100644 --- a/package.json +++ b/package.json @@ -19,11 +19,13 @@ "@radix-ui/react-tabs": "^1.1.1", "@radix-ui/react-toast": "^1.2.1", "@tabler/icons-react": "^3.19.0", + "@types/js-cookie": "^3.0.6", "axios": "^1.7.7", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "cookie": "^1.0.1", "framer-motion": "^11.9.0", + "js-cookie": "^3.0.5", "lucide-react": "^0.446.0", "next": "14.2.13", "next-themes": "^0.3.0", diff --git a/src/app/more/album/page.tsx b/src/app/more/album/page.tsx new file mode 100644 index 0000000..cffb027 --- /dev/null +++ b/src/app/more/album/page.tsx @@ -0,0 +1,199 @@ +"use client"; + +import { useState } from "react"; +import SquareContainer from "@/components/container/square-container"; +import { + IconChevronRight, + IconDotsVertical, + IconHeart, + IconInfoCircle, + IconPlayerPlayFilled, + IconShare, +} from "@tabler/icons-react"; +import Image from "next/image"; +import { useRouter } from "next/navigation"; +import useStreamingBar from "@/hooks/modal/use-streaming-bar"; + +interface Album { + id: number; + name: string; + src: string; + onClickName: () => void; + onClickDescription: () => void; + description?: string; +} + +export default function MoreAlbumPage() { + const router = useRouter(); + const streamingBar = useStreamingBar(); + + const albums: Album[] = [ + { + id: 1, + name: "Get Up", + src: "/images/albumcover.png", + onClickName: () => router.push("/album/123"), + onClickDescription: () => router.push("/user/123"), + description: "2023 NewJeans", + }, + { + id: 2, + name: "Drama", + src: "/images/albumcover.png", + onClickName: () => router.push("/album/123"), + onClickDescription: () => router.push("/user/123"), + description: "2024 aespa", + }, + { + id: 3, + name: "JORDI", + src: "/images/albumcover.png", + onClickName: () => router.push("/album/123"), + onClickDescription: () => router.push("/user/123"), + description: "2021 Maroon 5", + }, + { + id: 4, + name: "Love Sux", + src: "/images/albumcover.png", + onClickName: () => router.push("/album/123"), + onClickDescription: () => router.push("/user/123"), + description: "2022 Avril Lavigne", + }, + { + id: 5, + name: "The Winning", + src: "/images/albumcover.png", + onClickName: () => router.push("/album/123"), + onClickDescription: () => router.push("/user/123"), + description: "2024 IU", + }, + { + id: 6, + name: "Remember Us", + src: "/images/albumcover.png", + onClickName: () => router.push("/album/123"), + onClickDescription: () => router.push("/user/123"), + description: "2018 DAY6", + }, + ]; + + const dummy = [ + { + id: 1, + title: "피곤해", + }, + { + id: 2, + title: "피곤해", + }, + { + id: 3, + title: "피곤해", + }, + { + id: 4, + title: "피곤해", + }, + ]; + + const [selectedAlbum, setSelectedAlbum] = useState(albums[0]); + + const handleAlbumSelect = (album: Album) => { + setSelectedAlbum(album); + }; + + return ( +
+
+ {/* 왼쪽 프로필 섹션 */} +
+
+ {selectedAlbum.name} +

+ {selectedAlbum.name} +

+

router.push("/user/123")} + className="mt-4 tracking-wide uppercase truncate font-bold text-lg text-gray-700 dark:text-white hover:underline cursor-pointer" + > + {selectedAlbum.description} +

+
+
+ + 13.1k +
+
+ + + +
+
+ +
+ {dummy.map((song) => ( +
+
+
+ {song.id} +
+
streamingBar.onOpen()} + className="hidden group-hover:flex text-[#FF239C]" + > + +
+
+
+ {song.title} +
+
+ ))} +
+ +
+ +
+
+
+ + {/* 오른쪽 아티스트 그리드 섹션 */} +
+
+ {albums.map((album) => ( +
handleAlbumSelect(album)} + > + +
+ ))} +
+
+
+
+ ); +} diff --git a/src/app/more/artist/page.tsx b/src/app/more/artist/page.tsx new file mode 100644 index 0000000..0c6dcfd --- /dev/null +++ b/src/app/more/artist/page.tsx @@ -0,0 +1,137 @@ +'use client' + +import { useState } from "react"; +import SquareContainer from "@/components/container/square-container"; +import { IconChevronRight } from "@tabler/icons-react"; +import Image from "next/image"; +import { useRouter } from "next/navigation"; + +interface Artist { + id: number; + name: string; + src: string; + onClickName: () => void; + followers?: string; + description?: string; +} + +export default function MoreArtistPage() { + const router = useRouter(); + + const artists: Artist[] = [ + { + id: 1, + name: "NewJeans", + src: "/images/albumcover.png", + onClickName: () => router.push("/user/123"), + followers: "1.5M", + description: "Hello! My name is NewJeans, and I'm passionate about exploring new ideas and cultures. I enjoy reading, traveling, and meeting new people...", + }, + { + id: 2, + name: "AESPA", + src: "/images/albumcover.png", + onClickName: () => router.push("/user/123"), + followers: "2.1M", + description: "We are AESPA! Known for our unique blend of K-pop and virtual reality concepts...", + }, + { + id: 3, + name: "MAROON 5", + src: "/images/albumcover.png", + onClickName: () => router.push("/user/123"), + followers: "3.2M", + description: "MAROON 5 is an American pop rock band that was formed in 1994 in Los Angeles, California...", + }, + { + id: 4, + name: "AVRIL LAVIGNE", + src: "/images/albumcover.png", + onClickName: () => router.push("/user/123"), + followers: "4.5M", + description: "AVRIL LAVIGNE is a Canadian singer, songwriter, and actress. She rose to fame with her debut album 'Let Go'...", + }, + { + id: 5, + name: "IU", + src: "/images/albumcover.png", + onClickName: () => router.push("/user/123"), + followers: "5.2M", + description: "IU is a South Korean singer, songwriter, and actress. She gained popularity with her albums 'IU...' and 'Palette'...", + }, + { + id: 6, + name: "DAY6", + src: "/images/albumcover.png", + onClickName: () => router.push("/user/123"), + followers: "2.8M", + description: "DAY6 is a South Korean boy band that debuted in 2015. They gained popularity with their album 'The Day'...", + }, + ]; + + const [selectedArtist, setSelectedArtist] = useState(artists[0]); + + const handleArtistSelect = (artist: Artist) => { + setSelectedArtist(artist); + }; + + return ( +
+
+ {/* 왼쪽 프로필 섹션 */} +
+
+ {selectedArtist.name} +

{selectedArtist.name}

+
+ + +
+

+ {selectedArtist.description} + +

+
+ +
+
+
+ + {/* 오른쪽 아티스트 그리드 섹션 */} +
+
+ {artists.map((artist) => ( +
handleArtistSelect(artist)} + > + +
+ ))} +
+
+
+
+ ); +} diff --git a/src/app/more/playlist/page.tsx b/src/app/more/playlist/page.tsx new file mode 100644 index 0000000..f7075d1 --- /dev/null +++ b/src/app/more/playlist/page.tsx @@ -0,0 +1,201 @@ +"use client"; + +import { useState } from "react"; +import SquareContainer from "@/components/container/square-container"; +import { + IconChevronRight, + IconDotsVertical, + IconHeart, + IconInfoCircle, + IconPlayerPlayFilled, + IconShare, +} from "@tabler/icons-react"; +import Image from "next/image"; +import { useRouter } from "next/navigation"; +import useStreamingBar from "@/hooks/modal/use-streaming-bar"; + +interface Playlist { + id: number; + name: string; + description?: string; + src: string; + onClickName: () => void; + onClickDescription: () => void; +} + +export default function MorePlaylistPage() { + const router = useRouter(); + const streamingBar = useStreamingBar(); + + const playlists: Playlist[] = [ + { + id: 1, + name: "K-pop 최신곡 모음", + description: "RARO", + src: "/images/albumcover.png", + onClickName: () => router.push("/playlist/123"), + onClickDescription: () => router.push("/user/123"), + }, + { + id: 2, + name: "드라이브 플레이리스트", + src: "/images/albumcover.png", + onClickName: () => router.push("/playlist/123"), + onClickDescription: () => router.push("/user/123"), + description: "RARO", + }, + { + id: 3, + name: "공부할 때 듣기 좋은 노래", + src: "/images/albumcover.png", + onClickName: () => router.push("/playlist/123"), + onClickDescription: () => router.push("/user/123"), + description: "RARO", + }, + { + id: 4, + name: "운동할 때 듣는 노래", + src: "/images/albumcover.png", + onClickName: () => router.push("/playlist/123"), + onClickDescription: () => router.push("/user/123"), + description: "RARO", + }, + { + id: 5, + name: "감성 발라드 모음", + src: "/images/albumcover.png", + onClickName: () => router.push("/playlist/123"), + onClickDescription: () => router.push("/user/123"), + description: "RARO", + }, + { + id: 6, + name: "인디음악 플레이리스트", + src: "/images/albumcover.png", + onClickName: () => router.push("/playlist/123"), + onClickDescription: () => router.push("/user/123"), + description: "인디음악팬", + }, + ]; + + const dummy = [ + { + id: 1, + title: "피곤해", + }, + { + id: 2, + title: "피곤해", + }, + { + id: 3, + title: "피곤해", + }, + { + id: 4, + title: "피곤해", + }, + ]; + + const [selectedPlaylist, setSelectedPlaylist] = useState( + playlists[0] + ); + + const handlePlaylistSelect = (playlist: Playlist) => { + setSelectedPlaylist(playlist); + }; + + return ( +
+
+ {/* 왼쪽 프로필 섹션 */} +
+
+ {selectedPlaylist.name} +

+ {selectedPlaylist.name} +

+

router.push("/user/123")} + className="mt-4 tracking-wide uppercase truncate font-bold text-lg text-gray-700 dark:text-white hover:underline cursor-pointer" + > + {selectedPlaylist.description} +

+
+
+ + 13.1k +
+
+ + + +
+
+ +
+ {dummy.map((song) => ( +
+
+
+ {song.id} +
+
streamingBar.onOpen()} + className="hidden group-hover:flex text-[#FF239C]" + > + +
+
+
+ {song.title} +
+
+ ))} +
+ +
+ +
+
+
+ + {/* 오른쪽 아티스트 그리드 섹션 */} +
+
+ {playlists.map((playlist) => ( +
handlePlaylistSelect(playlist)} + > + +
+ ))} +
+
+
+
+ ); +} diff --git a/src/app/more/track/page.tsx b/src/app/more/track/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/container/square-container.tsx b/src/components/container/square-container.tsx index 96eca94..4e3b40c 100644 --- a/src/components/container/square-container.tsx +++ b/src/components/container/square-container.tsx @@ -25,7 +25,7 @@ const SquareContainer = ({ return (
-
+
profile {hovered && ( {title} diff --git a/src/features/main/bar.tsx b/src/features/main/bar.tsx index 7abacd0..62c818d 100644 --- a/src/features/main/bar.tsx +++ b/src/features/main/bar.tsx @@ -104,7 +104,7 @@ export function Bar() { {user?.name ? ( user.name.charAt(0).toUpperCase() ) : ( - + )} diff --git a/src/features/main/main-album.tsx b/src/features/main/main-album.tsx index eca7d6e..41d6805 100644 --- a/src/features/main/main-album.tsx +++ b/src/features/main/main-album.tsx @@ -18,7 +18,7 @@ const MainAlbum = () => { const data = await getAllAlbums(0, 10); setAlbums(data); } catch (error) { - console.error('앨범 로딩 실패:', error); + console.error("앨범 로딩 실패:", error); } }; @@ -31,24 +31,36 @@ const MainAlbum = () => { return (
-
-

- {user?.name || "U"} -

-

님을 위한 앨범

+
+
+

+ {user?.name || "U"} +

+

님을 위한 앨범

+
+
+ +
- {albums.map(({ albumResponseDto: album, profileResponseDto: profile }) => ( - router.push(`/album/${album.uuid}`)} - onClickDescription={() => router.push(`/user/${profile.name}`)} - /> - ))} + {albums.map( + ({ albumResponseDto: album, profileResponseDto: profile }) => ( + router.push(`/album/${album.uuid}`)} + onClickDescription={() => router.push(`/user/${profile.name}`)} + /> + ) + )}
); diff --git a/src/features/main/main-artist.tsx b/src/features/main/main-artist.tsx index 34a0770..11e4066 100644 --- a/src/features/main/main-artist.tsx +++ b/src/features/main/main-artist.tsx @@ -37,11 +37,21 @@ const MainArtist = () => { return (
-
-

- {user?.name || "U"} -

-

님을 위한 아티스트

+
+
+

+ {user?.name || "U"} +

+

님을 위한 아티스트

+
+
+ +
{dummy.map((item) => ( diff --git a/src/features/main/main-playlist.tsx b/src/features/main/main-playlist.tsx index 23b803e..5b1cf2f 100644 --- a/src/features/main/main-playlist.tsx +++ b/src/features/main/main-playlist.tsx @@ -61,11 +61,21 @@ const MainPlaylist = () => { return (
-
-

- {user?.name || "U"} -

-

님을 위한 플레이리스트

+
+
+

+ {user?.name || "U"} +

+

님을 위한 플레이리스트

+
+
+ +
{dummy.map((item) => ( diff --git a/src/features/main/main-track.tsx b/src/features/main/main-track.tsx index e012db7..9031953 100644 --- a/src/features/main/main-track.tsx +++ b/src/features/main/main-track.tsx @@ -46,8 +46,20 @@ const MainTrack = () => { return (
-
-

TRACK

+
+
+

+ TRACK +

+
+
+ +
{dummy.map((item) => ( diff --git a/src/features/main/topbar.tsx b/src/features/main/topbar.tsx index e94914d..6214085 100644 --- a/src/features/main/topbar.tsx +++ b/src/features/main/topbar.tsx @@ -19,7 +19,7 @@ export default function Topbar() {
diff --git a/src/lib/axios.ts b/src/lib/axios.ts index bf7f45a..f8fe981 100644 --- a/src/lib/axios.ts +++ b/src/lib/axios.ts @@ -1,26 +1,23 @@ -import axios, { AxiosInstance } from 'axios'; +import axios, { AxiosInstance } from "axios"; +import Cookies from "js-cookie"; // 쿠키 처리를 위해 js-cookie 라이브러리 추천 const createAxiosInstance = (): AxiosInstance => { const instance = axios.create({ - baseURL: process.env.NEXT_PUBLIC_API_BASE_URL || '', + baseURL: process.env.NEXT_PUBLIC_API_BASE_URL || "", headers: { - 'Content-Type': 'application/json', + "Content-Type": "application/json", }, + withCredentials: true, }); instance.interceptors.request.use( (config) => { - const cookies = document.cookie; - const access_token = cookies - .split(';') - .map(cookie => cookie.trim()) - .find(cookie => cookie.startsWith('access_token=')) - ?.split('=')[1]; - - if (access_token) { - config.headers.Authorization = `Bearer ${access_token}`; + const accessToken = Cookies.get("access_token"); + + if (accessToken) { + config.headers["Authorization"] = `Bearer ${accessToken}`; } - + return config; }, (error) => { @@ -31,4 +28,4 @@ const createAxiosInstance = (): AxiosInstance => { return instance; }; -export const api = createAxiosInstance(); \ No newline at end of file +export default createAxiosInstance;