From 6c213522c3c650c6b905b22842a68b70b6808211 Mon Sep 17 00:00:00 2001 From: choi Date: Mon, 23 Dec 2024 21:35:28 +0900 Subject: [PATCH] =?UTF-8?q?=ED=94=84=EB=A1=9C=ED=95=84=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EA=B8=B0=EB=8A=A5,=20=ED=94=84=EB=A1=9C=ED=95=84?= =?UTF-8?q?=20=EB=82=B4=20=EC=95=A8=EB=B2=94=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 31 +++++++ package.json | 1 + src/app/album/[albumId]/page.tsx | 4 +- src/app/user/[userId]/page.tsx | 33 +++++-- src/components/modal/confirm-modal.tsx | 118 +++++++++++++++++++++++++ src/components/ui/checkbox.tsx | 29 ++++++ src/features/user/user-album.tsx | 81 +++++++---------- src/hooks/modal/use-confirm-modal.ts | 17 ++++ src/services/albumService.ts | 19 ++++ src/services/profileService.ts | 23 +++++ 10 files changed, 297 insertions(+), 59 deletions(-) create mode 100644 src/components/modal/confirm-modal.tsx create mode 100644 src/components/ui/checkbox.tsx create mode 100644 src/hooks/modal/use-confirm-modal.ts diff --git a/package-lock.json b/package-lock.json index 0a83bb6..853bdda 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@hookform/resolvers": "^3.9.0", "@radix-ui/react-avatar": "^1.1.1", + "@radix-ui/react-checkbox": "^1.1.3", "@radix-ui/react-dialog": "^1.1.1", "@radix-ui/react-dropdown-menu": "^2.1.2", "@radix-ui/react-icons": "^1.3.0", @@ -950,6 +951,36 @@ } } }, + "node_modules/@radix-ui/react-checkbox": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.1.3.tgz", + "integrity": "sha512-HD7/ocp8f1B3e6OHygH0n7ZKjONkhciy1Nh0yuBgObqThc3oyx+vuMfFHKAknXRHHWVE9XvXStxJFyjUmB8PIw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-use-size": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-collection": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.1.tgz", diff --git a/package.json b/package.json index e64e41b..adbae75 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "dependencies": { "@hookform/resolvers": "^3.9.0", "@radix-ui/react-avatar": "^1.1.1", + "@radix-ui/react-checkbox": "^1.1.3", "@radix-ui/react-dialog": "^1.1.1", "@radix-ui/react-dropdown-menu": "^2.1.2", "@radix-ui/react-icons": "^1.3.0", diff --git a/src/app/album/[albumId]/page.tsx b/src/app/album/[albumId]/page.tsx index 02b6414..a58f849 100644 --- a/src/app/album/[albumId]/page.tsx +++ b/src/app/album/[albumId]/page.tsx @@ -95,7 +95,7 @@ export default function AlbumPage() {
{albumProfile && (
router.push(`/profile/${albumProfile.name}`)} + onClick={() => router.push(`/user/${albumProfile.uuid}`)} className="flex gap-x-2 items-center" > @@ -172,7 +172,7 @@ export default function AlbumPage() { {song.title} - {song.title} + {song.duration} diff --git a/src/app/user/[userId]/page.tsx b/src/app/user/[userId]/page.tsx index 4a57991..4a71c85 100644 --- a/src/app/user/[userId]/page.tsx +++ b/src/app/user/[userId]/page.tsx @@ -17,6 +17,9 @@ import { DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuTrigger, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, } from "@/components/ui/dropdown-menu"; import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; @@ -31,10 +34,12 @@ import { Profile, getProfile } from "@/services/profileService"; import useProfileModal from "@/hooks/modal/use-profile-modal"; import { useUser } from "@/provider/userProvider"; import useProfileEditModal from "@/hooks/modal/use-profileEdit-modal"; +import useConfirmModal from "@/hooks/modal/use-confirm-modal"; export default function UserPage() { const streamingBar = useStreamingBar(); const profileModal = useProfileModal(); + const confirmModal = useConfirmModal(); const profileEditModal = useProfileEditModal(); const isMobile = useMediaQuery({ maxWidth: 768 }); @@ -58,6 +63,10 @@ export default function UserPage() { fetchProfile(); }, [user]); + const handleConfirm = (uuid: string) => { + confirmModal.onOpen(uuid); + }; + const tabs = [ { id: "track", label: "트랙", icon: IconMusic, onClick: () => {} }, { id: "album", label: "앨범", icon: IconDisc, onClick: () => {} }, @@ -94,12 +103,24 @@ export default function UserPage() {
{profileData?.name || "U"}
-
- -
+ + + + + + 프로필 설정 + + + 프로필 편집 + + handleConfirm(profileData?.uuid || "")} + > + 프로필 삭제 + + +
+ +
+
+ + ); +}; + +export default ConfirmModal; diff --git a/src/components/ui/checkbox.tsx b/src/components/ui/checkbox.tsx new file mode 100644 index 0000000..f941ea7 --- /dev/null +++ b/src/components/ui/checkbox.tsx @@ -0,0 +1,29 @@ +"use client" + +import * as React from "react" +import * as CheckboxPrimitive from "@radix-ui/react-checkbox" +import { cn } from "@/lib/utils" +import { CheckIcon } from "@radix-ui/react-icons" + +const Checkbox = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + + +)) +Checkbox.displayName = CheckboxPrimitive.Root.displayName + +export { Checkbox } \ No newline at end of file diff --git a/src/features/user/user-album.tsx b/src/features/user/user-album.tsx index e010e6e..041d8c1 100644 --- a/src/features/user/user-album.tsx +++ b/src/features/user/user-album.tsx @@ -1,67 +1,46 @@ 'use client' +import { useEffect, useState } from "react"; +import { usePathname, useRouter } from "next/navigation"; + +import { Album, getAlbumByProfileUUID } from "@/services/albumService"; import SquareContainer from "@/components/container/square-container"; -import { useRouter } from "next/navigation"; const UserAlbum = () => { + const [albums, setAlbums] = useState([]); + const router = useRouter(); + const pathname = usePathname(); + const profileUUID = String(pathname.split("/").pop()); + + useEffect(() => { + const getAlbums = async () => { + try { + const data = await getAlbumByProfileUUID(profileUUID); + setAlbums(data); + } catch (error) { + console.error("앨범 로딩 실패:", error); + } + }; - const dummy = [ - { - id: 1, - src: "/images/music1.png", - name: "ROCK-STAR", - description: "2024 · IPCGRDN", - onClickName: () => router.push("/album/123"), - }, - { - id: 2, - src: "/images/music1.png", - name: "ROCK-STAR", - description: "2024 · IPCGRDN", - onClickName: () => router.push("/album/123"), - }, - { - id: 3, - src: "/images/music1.png", - name: "ROCK-STAR", - description: "2024 · IPCGRDN", - onClickName: () => router.push("/album/123"), - }, - { - id: 4, - src: "/images/music1.png", - name: "BREAK", - description: "2018 · PALM", - onClickName: () => router.push("/album/123"), - }, - { - id: 5, - src: "/images/music1.png", - name: "Thirsty", - description: "1988 · RARO", - onClickName: () => router.push("/album/123"), - }, - { - id: 6, - src: "/images/music1.png", - name: "산책", - description: "EP · BDD", - onClickName: () => router.push("/album/123"), - }, - ]; + getAlbums(); + }, [profileUUID]); + if (!albums.length) { + return null; + } + return (
- {dummy.map((item) => ( + {albums.map((album) => ( router.push(`/album/${album.uuid}`)} /> ))}
diff --git a/src/hooks/modal/use-confirm-modal.ts b/src/hooks/modal/use-confirm-modal.ts new file mode 100644 index 0000000..ee90896 --- /dev/null +++ b/src/hooks/modal/use-confirm-modal.ts @@ -0,0 +1,17 @@ +import { create } from "zustand"; + +interface ConfirmModalState { + isOpen: boolean; + uuid: string | null; + onOpen: (uuid: string) => void; + onClose: () => void; +} + +const useConfirmModal = create((set) => ({ + isOpen: false, + uuid: null, + onOpen: (uuid: string) => set({ isOpen: true, uuid }), + onClose: () => set({ isOpen: false, uuid: null }), +})); + +export default useConfirmModal; \ No newline at end of file diff --git a/src/services/albumService.ts b/src/services/albumService.ts index a84da99..6636c93 100644 --- a/src/services/albumService.ts +++ b/src/services/albumService.ts @@ -13,10 +13,12 @@ export interface Track { uuid: string; title: string; lyric: string; + duration: number; artUrl: string; } export interface Profile { + uuid: string; name: string; description: string; link1: string; @@ -71,4 +73,21 @@ export const getAlbumById = async (uuid: string): Promise => { } throw error; } +}; + +export const getAlbumByProfileUUID = async (uuid: string): Promise => { + try { + const response = await api.get(`/profile/${uuid}/album`); + return response.data; + } catch (error) { + if (axios.isAxiosError(error)) { + console.error( + `프로필 앨범 데이터 조회 실패: ${error.response?.status}`, + error.message + ); + } else { + console.error("프로필 앨범 데이터 조회 중 알 수 없는 오류 발생:", error); + } + throw error; + } } \ No newline at end of file diff --git a/src/services/profileService.ts b/src/services/profileService.ts index d731262..b9cbe23 100644 --- a/src/services/profileService.ts +++ b/src/services/profileService.ts @@ -2,6 +2,7 @@ import { api } from "@/lib/axios"; import axios from "axios"; export interface Profile { + uuid: string; name: string; description: string; link1: string; @@ -31,3 +32,25 @@ export const getProfile = async (): Promise => { return null; } }; + +export const deleteProfile = async (uuid: string) => { + try { + const response = await api.delete(`/profile/${uuid}`); + + if (response.status >= 200 && response.status < 300) { + return response.data; + } + + return null; + } catch (error) { + if (axios.isAxiosError(error)) { + console.error( + `프로필 삭제 실패: ${error.response?.status}`, + error.message + ); + } else { + console.error("프로필 삭제 중 알 수 없는 오류 발생:", error); + } + return false; + } +}