From 9fb7c9170abeca6cea85462055d35ea6d06677e0 Mon Sep 17 00:00:00 2001 From: mtm1018 Date: Mon, 6 Oct 2025 22:42:31 +0900 Subject: [PATCH 01/10] =?UTF-8?q?[feat]=20=ED=83=AD=EB=B3=84=EA=B0=9C?= =?UTF-8?q?=EC=9D=B8=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/mypage/my-active/my-comment/page.tsx | 4 +- src/app/mypage/my-active/my-like/page.tsx | 3 +- src/app/mypage/my-active/my-post/page.tsx | 4 +- src/app/mypage/my-alarm/page.tsx | 7 +- src/app/mypage/my-bar/page.tsx | 17 +--- src/domains/mypage/api/fetchProfile.ts | 35 +++++++++ src/domains/mypage/components/Alarm.tsx | 11 ++- .../mypage/components/EditNickName.tsx | 35 ++++++++- .../components/pages/my-active/MyComment.tsx | 34 ++++++++ .../components/pages/my-active/MyLike.tsx | 32 ++++++++ .../components/pages/my-active/MyPost.tsx | 25 ++++++ .../components/pages/my-alarm/MyAlarm.tsx | 42 ++++++++++ .../mypage/components/pages/my-bar/MyBar.tsx | 50 ++++++++++++ src/domains/mypage/hook/useProfileSsury.tsx | 22 ++++++ src/domains/mypage/main/MyAbv.tsx | 5 +- src/domains/mypage/main/MyNav.tsx | 2 +- src/domains/mypage/main/MyProfile.tsx | 78 ++++++++++++------- src/domains/mypage/main/MySetting.tsx | 27 ++++++- src/domains/mypage/main/SsuryImage.tsx | 9 +++ 19 files changed, 375 insertions(+), 67 deletions(-) create mode 100644 src/domains/mypage/api/fetchProfile.ts create mode 100644 src/domains/mypage/components/pages/my-active/MyComment.tsx create mode 100644 src/domains/mypage/components/pages/my-active/MyLike.tsx create mode 100644 src/domains/mypage/components/pages/my-active/MyPost.tsx create mode 100644 src/domains/mypage/components/pages/my-alarm/MyAlarm.tsx create mode 100644 src/domains/mypage/components/pages/my-bar/MyBar.tsx create mode 100644 src/domains/mypage/hook/useProfileSsury.tsx create mode 100644 src/domains/mypage/main/SsuryImage.tsx diff --git a/src/app/mypage/my-active/my-comment/page.tsx b/src/app/mypage/my-active/my-comment/page.tsx index c69e1e6d..480939f8 100644 --- a/src/app/mypage/my-active/my-comment/page.tsx +++ b/src/app/mypage/my-active/my-comment/page.tsx @@ -1,4 +1,4 @@ -// import CommentList from '@/domains/shared/components/comment/CommentList'; +import MyComment from '@/domains/mypage/components/pages/my-active/MyComment'; import { Metadata } from 'next'; export const metadata: Metadata = { @@ -7,6 +7,6 @@ export const metadata: Metadata = { }; function Page() { - return <>{/* */}; + return ; } export default Page; diff --git a/src/app/mypage/my-active/my-like/page.tsx b/src/app/mypage/my-active/my-like/page.tsx index 0a8e73e1..25e60259 100644 --- a/src/app/mypage/my-active/my-like/page.tsx +++ b/src/app/mypage/my-active/my-like/page.tsx @@ -1,4 +1,5 @@ // import PostCard from '@/domains/community/main/PostCard'; +import MyLike from '@/domains/mypage/components/pages/my-active/MyLike'; import { Metadata } from 'next'; export const metadata: Metadata = { @@ -7,6 +8,6 @@ export const metadata: Metadata = { }; function Page() { - return
{/* */}
; + return ; } export default Page; diff --git a/src/app/mypage/my-active/my-post/page.tsx b/src/app/mypage/my-active/my-post/page.tsx index 70c47d80..775ac070 100644 --- a/src/app/mypage/my-active/my-post/page.tsx +++ b/src/app/mypage/my-active/my-post/page.tsx @@ -1,4 +1,4 @@ -// import PostCard from '@/domains/community/main/PostCard'; +import MyPost from '@/domains/mypage/components/pages/my-active/MyPost'; import { Metadata } from 'next'; export const metadata: Metadata = { @@ -7,6 +7,6 @@ export const metadata: Metadata = { }; function Page() { - return
{/* */}
; + return ; } export default Page; diff --git a/src/app/mypage/my-alarm/page.tsx b/src/app/mypage/my-alarm/page.tsx index ec9e77c1..c094bd4d 100644 --- a/src/app/mypage/my-alarm/page.tsx +++ b/src/app/mypage/my-alarm/page.tsx @@ -1,4 +1,4 @@ -import Alarm from '@/domains/mypage/components/Alarm'; +import MyAlarm from '@/domains/mypage/components/pages/my-alarm/MyAlarm'; import { Metadata } from 'next'; @@ -10,10 +10,7 @@ export const metadata: Metadata = { function Page() { return (
- - - - +
); } diff --git a/src/app/mypage/my-bar/page.tsx b/src/app/mypage/my-bar/page.tsx index 4c12cc42..54fa638d 100644 --- a/src/app/mypage/my-bar/page.tsx +++ b/src/app/mypage/my-bar/page.tsx @@ -1,4 +1,4 @@ -import CocktailCard from '@/domains/shared/components/cocktail-card/CocktailCard'; +import MyBar from '@/domains/mypage/components/pages/my-bar/MyBar'; import { Metadata } from 'next'; export const metadata: Metadata = { @@ -7,19 +7,6 @@ export const metadata: Metadata = { }; function Page() { - return ( -
- -
- ); + return ; } export default Page; diff --git a/src/domains/mypage/api/fetchProfile.ts b/src/domains/mypage/api/fetchProfile.ts new file mode 100644 index 00000000..54b08a79 --- /dev/null +++ b/src/domains/mypage/api/fetchProfile.ts @@ -0,0 +1,35 @@ +'use client'; +import { getApi } from '@/app/api/config/appConfig'; +import { useEffect, useState } from 'react'; + +interface Profile { + abvDegree: number; + abvLabel: string; + abvLevel: number; + email?: string; + id: number; + myCommentCount: number; + myKeepCount: number; + myLikedPostCount: number; + myPostCount: number; + nickname: string; +} + +function useFetchProfile() { + const [profile, setProfile] = useState(null); + + const fetchProfile = async () => { + const res = await fetch(`${getApi}/me/profile`, { + method: 'GET', + credentials: 'include', + }); + const json = await res.json(); + setProfile(json.data); + }; + useEffect(() => { + fetchProfile(); + }, []); + + return { profile }; +} +export default useFetchProfile; diff --git a/src/domains/mypage/components/Alarm.tsx b/src/domains/mypage/components/Alarm.tsx index 9031a732..880c11cd 100644 --- a/src/domains/mypage/components/Alarm.tsx +++ b/src/domains/mypage/components/Alarm.tsx @@ -4,7 +4,12 @@ import clsx from 'clsx'; import Image from 'next/image'; import { useState } from 'react'; -function Alarm() { +interface Props { + title: string; + content: string; +} + +function Alarm({ title, content }: Props) { const [isClick, setIsClick] = useState(false); const handleClick = () => { @@ -27,8 +32,8 @@ function Alarm() {

10분 전

-

새로운 좋아요 알림

-

User님이 내 글에 좋아요를 누르셨습니다.

+

{title}

+

{content}

diff --git a/src/domains/mypage/components/EditNickName.tsx b/src/domains/mypage/components/EditNickName.tsx index e1d744b5..0d5e9343 100644 --- a/src/domains/mypage/components/EditNickName.tsx +++ b/src/domains/mypage/components/EditNickName.tsx @@ -1,3 +1,4 @@ +import { getApi } from '@/app/api/config/appConfig'; import Button from '@/shared/components/button/Button'; import TextButton from '@/shared/components/button/TextButton'; import Input from '@/shared/components/Input-box/Input'; @@ -6,22 +7,50 @@ import ModalLayout from '@/shared/components/modal-pop/ModalLayout'; interface Props { open: boolean; onClose: () => void; + nickname: string; + setNickName: (v: string) => void; } -function EditNickName({ open, onClose }: Props) { +function EditNickName({ open, onClose, setNickName, nickname }: Props) { + const handlesave = async () => { + const res = await fetch(`${getApi}/me/profile`, { + method: 'PATCH', + credentials: 'include', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + nickname: nickname, + }), + }); + }; + + const handleChange = (e: React.ChangeEvent) => { + setNickName(e.target.value); + }; + return ( 저장} + buttons={ + + } >
- + 기존 이름으로 돌아가기
diff --git a/src/domains/mypage/components/pages/my-active/MyComment.tsx b/src/domains/mypage/components/pages/my-active/MyComment.tsx new file mode 100644 index 00000000..1fb5adf2 --- /dev/null +++ b/src/domains/mypage/components/pages/my-active/MyComment.tsx @@ -0,0 +1,34 @@ +'use client'; +import { getApi } from '@/app/api/config/appConfig'; +import { CommentType } from '@/domains/community/types/post'; +import CommentList from '@/domains/shared/components/comment/CommentList'; +import { useEffect, useState } from 'react'; + +function MyComment() { + const [myComment, setMyComment] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const fetchComment = async () => { + const res = await fetch(`${getApi}/me/comments`, { + method: 'GET', + credentials: 'include', + }); + const json = await res.json(); + console.log(json); + setMyComment(json.data.items); + }; + + useEffect(() => { + fetchComment(); + }, []); + + return ( +
+ {CommentList.length !== 0 ? ( + + ) : ( +
작성한 댓글이 없습니다.
+ )} +
+ ); +} +export default MyComment; diff --git a/src/domains/mypage/components/pages/my-active/MyLike.tsx b/src/domains/mypage/components/pages/my-active/MyLike.tsx new file mode 100644 index 00000000..610c1eb8 --- /dev/null +++ b/src/domains/mypage/components/pages/my-active/MyLike.tsx @@ -0,0 +1,32 @@ +'use client'; +import { getApi } from '@/app/api/config/appConfig'; +import PostCard from '@/domains/community/main/PostCard'; +import { useEffect, useState } from 'react'; + +interface MyLike { + postId: number; + title: string; + likedAt: Date; + posetCreatedAt: Date; +} + +function MyLike() { + const [myLike, setMyLike] = useState([]); + const [isLoading, setIsLoading] = useState(false); + + const fetchLike = async () => { + const res = await fetch(`${getApi}/me/likes/posts`, { + method: 'GET', + credentials: 'include', + }); + const json = await res.json(); + setMyLike(json.data.items); + }; + + useEffect(() => { + fetchLike(); + }, []); + + return ; +} +export default MyLike; diff --git a/src/domains/mypage/components/pages/my-active/MyPost.tsx b/src/domains/mypage/components/pages/my-active/MyPost.tsx new file mode 100644 index 00000000..24515b32 --- /dev/null +++ b/src/domains/mypage/components/pages/my-active/MyPost.tsx @@ -0,0 +1,25 @@ +'use client'; +import { getApi } from '@/app/api/config/appConfig'; +import PostCard from '@/domains/community/main/PostCard'; +import { useEffect, useState } from 'react'; + +function MyPost() { + const [myPost, setMyPost] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const fetchPost = async () => { + const res = await fetch(`${getApi}/me/posts`, { + method: 'GET', + credentials: 'include', + }); + const json = await res.json(); + setMyPost(json.data.items); + }; + + useEffect(() => { + console.log(myPost); + fetchPost(); + }, []); + + return ; +} +export default MyPost; diff --git a/src/domains/mypage/components/pages/my-alarm/MyAlarm.tsx b/src/domains/mypage/components/pages/my-alarm/MyAlarm.tsx new file mode 100644 index 00000000..72fdd556 --- /dev/null +++ b/src/domains/mypage/components/pages/my-alarm/MyAlarm.tsx @@ -0,0 +1,42 @@ +'use client'; +import { useEffect, useState } from 'react'; +import Alarm from '../../Alarm'; +import { getApi } from '@/app/api/config/appConfig'; + +interface MyAlarm { + notificationId: number; + title: string; + content: string; + isRead: boolean; + createdAt: Date; +} + +function MyAlarm() { + const [myAlarm, setMyAlarm] = useState([]); + + const fetchAlarm = async () => { + const res = await fetch(`${getApi}/me/notifications`, { + method: 'GET', + credentials: 'include', + }); + const json = await res.json(); + setMyAlarm(json.data.items); + }; + + useEffect(() => { + fetchAlarm(); + }, []); + + return ( +
+ {myAlarm.length !== 0 ? ( + myAlarm.map(({ notificationId, title, content }) => ( + + )) + ) : ( +
알림이 없습니다
+ )} +
+ ); +} +export default MyAlarm; diff --git a/src/domains/mypage/components/pages/my-bar/MyBar.tsx b/src/domains/mypage/components/pages/my-bar/MyBar.tsx new file mode 100644 index 00000000..4bb372e3 --- /dev/null +++ b/src/domains/mypage/components/pages/my-bar/MyBar.tsx @@ -0,0 +1,50 @@ +'use client'; +import { getApi } from '@/app/api/config/appConfig'; +import CocktailCard from '@/domains/shared/components/cocktail-card/CocktailCard'; +import { useEffect, useState } from 'react'; + +interface MyCocktail { + cocktailId: number; + cocktailName: string; + id: number; + imageUrl: string; +} + +function MyBar() { + const [myCocktail, setMyCocktail] = useState([]); + const fetchData = async () => { + const res = await fetch(`${getApi}/me/bar`, { + method: 'GET', + credentials: 'include', + }); + const json = await res.json(); + setMyCocktail(json.data.items ?? []); + }; + + useEffect(() => { + fetchData(); + }, []); + + return ( +
+ {myCocktail ? ( + myCocktail.map(({ cocktailId, cocktailName, imageUrl }) => ( + + )) + ) : ( +
칵테일을 담아보세요
+ )} +
+ ); +} +export default MyBar; diff --git a/src/domains/mypage/hook/useProfileSsury.tsx b/src/domains/mypage/hook/useProfileSsury.tsx new file mode 100644 index 00000000..d683fb66 --- /dev/null +++ b/src/domains/mypage/hook/useProfileSsury.tsx @@ -0,0 +1,22 @@ +import Ssury1 from '@/shared/assets/ssury/ssury_level1.webp'; +import Ssury2 from '@/shared/assets/ssury/ssury_level2.webp'; +import Ssury3 from '@/shared/assets/ssury/ssury_level3.webp'; +import Ssury4 from '@/shared/assets/ssury/ssury_level4.webp'; +import Ssury5 from '@/shared/assets/ssury/ssury_level5.webp'; +import Ssury6 from '@/shared/assets/ssury/ssury_level6.webp'; +import Image, { StaticImageData } from 'next/image'; + +const SSURY_MAP: Record = { + 1: Ssury1, + 2: Ssury2, + 3: Ssury3, + 4: Ssury4, + 5: Ssury5, + 6: Ssury6, +}; + +function useProfileSsury(level: number) { + const src = SSURY_MAP[level] ?? Ssury1; + return src; +} +export default useProfileSsury; diff --git a/src/domains/mypage/main/MyAbv.tsx b/src/domains/mypage/main/MyAbv.tsx index fd2dc317..0b1d88b9 100644 --- a/src/domains/mypage/main/MyAbv.tsx +++ b/src/domains/mypage/main/MyAbv.tsx @@ -3,10 +3,11 @@ import Help from '@/shared/assets/icons/help_24.svg'; import ToolTip from '@/shared/components/tool-tip/ToolTip'; import useMedia from '../hook/useMedia'; -function MyAbv() { +function MyAbv({ abv }: { abv: number }) { const isMd = useMedia('(min-width:768px)'); const position = isMd ? 'leftTop' : 'top'; const viewPoint = isMd ? 'web' : 'mobileLongText'; + const fixedAbv = abv.toFixed(1); return (
@@ -22,7 +23,7 @@ function MyAbv() {
- 83% + {fixedAbv}%
); diff --git a/src/domains/mypage/main/MyNav.tsx b/src/domains/mypage/main/MyNav.tsx index bff0acab..fac49fd5 100644 --- a/src/domains/mypage/main/MyNav.tsx +++ b/src/domains/mypage/main/MyNav.tsx @@ -9,7 +9,7 @@ import { usePathname } from 'next/navigation'; const MAIN_TABMENU = [ { title: '나만의 BAR', - href: '/mypage/mybar', + href: '/mypage/my-bar', }, { title: '내 활동', diff --git a/src/domains/mypage/main/MyProfile.tsx b/src/domains/mypage/main/MyProfile.tsx index 11f17609..16648ff0 100644 --- a/src/domains/mypage/main/MyProfile.tsx +++ b/src/domains/mypage/main/MyProfile.tsx @@ -1,41 +1,61 @@ -import Image from 'next/image'; -import Ssury from '@/shared/assets/ssury/ssury_level4.webp'; +'use client'; + import AbvGraph from '@/domains/shared/components/abv-graph/AbvGraph'; import MyAbv from './MyAbv'; +import SsuryImage from './SsuryImage'; +import useFetchProfile from '../api/fetchProfile'; function MyProfile() { + const { profile } = useFetchProfile(); + + if (!profile) return; + const { + nickname, + abvLevel, + myLikedPostCount, + myPostCount, + myCommentCount, + myKeepCount, + abvDegree, + } = profile; + return (
-
-
- -

UserName

-
-
    -
  • -

    좋아요 0

    -
  • - | -
  • -

    글 0

    -
  • - | -
  • -

    댓글 0

    -
  • - | -
  • -

    칵테일 킵 0

    -
  • -
-
- + {profile && ( + <> +
+
+ +

{nickname}

+
+
    +
  • +

    좋아요 {myLikedPostCount}

    +
  • + | +
  • +

    글 {myPostCount}

    +
  • + | +
  • +

    댓글 {myCommentCount}

    +
  • + | +
  • +

    칵테일 킵 {myKeepCount}

    +
  • +
+
+ + + )}
); } + export default MyProfile; diff --git a/src/domains/mypage/main/MySetting.tsx b/src/domains/mypage/main/MySetting.tsx index f50e9ac1..0d340c37 100644 --- a/src/domains/mypage/main/MySetting.tsx +++ b/src/domains/mypage/main/MySetting.tsx @@ -4,19 +4,38 @@ import ToggleBtn from '@/domains/mypage/components/ToggleBtn'; import WithdrawModal from '@/domains/mypage/components/WithdrawModal'; import Button from '@/shared/components/button/Button'; import TextButton from '@/shared/components/button/TextButton'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; +import useFetchProfile from '../api/fetchProfile'; function MySetting() { + const { profile } = useFetchProfile(); const [isOpen, setIsOpen] = useState(false); const [isQuit, setIsQuit] = useState(false); + const [nickname, setNickName] = useState(''); + + const handleEditNickName = async () => { + setIsOpen(!isOpen); + }; + + useEffect(() => { + if (profile) setNickName(profile?.nickname); + }, [nickname]); + return (
- {isOpen && setIsOpen(!isOpen)} />} + {isOpen && ( + setIsOpen(!isOpen)} + setNickName={setNickName} + nickname={nickname ?? ''} + /> + )} {isQuit && setIsQuit(!isQuit)} />}
-
닉네임 : UserName
- setIsOpen(!isOpen)}>수정하기 +
닉네임 : {nickname}
+ 수정하기

알람설정

diff --git a/src/domains/mypage/main/SsuryImage.tsx b/src/domains/mypage/main/SsuryImage.tsx new file mode 100644 index 00000000..e6fdb49c --- /dev/null +++ b/src/domains/mypage/main/SsuryImage.tsx @@ -0,0 +1,9 @@ +import useProfileSsury from '../hook/useProfileSsury'; +import Image from 'next/image'; + +function SsuryImage({ abvLevel }: { abvLevel: number }) { + const profileImage = useProfileSsury(abvLevel); + + return ; +} +export default SsuryImage; From 48f8b78463e11b228107ada763bd0bc18d67ea6c Mon Sep 17 00:00:00 2001 From: mtm1018 Date: Tue, 7 Oct 2025 17:31:06 +0900 Subject: [PATCH 02/10] =?UTF-8?q?[feat]=EC=95=8C=EB=A6=BC=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/domains/mypage/api/fetchProfile.ts | 3 +- .../mypage/components/EditNickName.tsx | 34 ++++++++++++---- src/domains/mypage/components/ToggleBtn.tsx | 40 +++++++++++++++++-- .../mypage/components/WithdrawModal.tsx | 3 ++ src/domains/mypage/main/MyProfile.tsx | 6 ++- src/domains/mypage/main/MySetting.tsx | 9 +++-- src/shared/components/Input-box/Input.tsx | 2 +- 7 files changed, 80 insertions(+), 17 deletions(-) diff --git a/src/domains/mypage/api/fetchProfile.ts b/src/domains/mypage/api/fetchProfile.ts index 54b08a79..6dbc620f 100644 --- a/src/domains/mypage/api/fetchProfile.ts +++ b/src/domains/mypage/api/fetchProfile.ts @@ -26,10 +26,11 @@ function useFetchProfile() { const json = await res.json(); setProfile(json.data); }; + useEffect(() => { fetchProfile(); }, []); - return { profile }; + return { profile, fetchProfile }; } export default useFetchProfile; diff --git a/src/domains/mypage/components/EditNickName.tsx b/src/domains/mypage/components/EditNickName.tsx index 0d5e9343..0e92de87 100644 --- a/src/domains/mypage/components/EditNickName.tsx +++ b/src/domains/mypage/components/EditNickName.tsx @@ -3,30 +3,50 @@ import Button from '@/shared/components/button/Button'; import TextButton from '@/shared/components/button/TextButton'; import Input from '@/shared/components/Input-box/Input'; import ModalLayout from '@/shared/components/modal-pop/ModalLayout'; +import { useToast } from '@/shared/hook/useToast'; +import { Dispatch, SetStateAction } from 'react'; interface Props { open: boolean; onClose: () => void; - nickname: string; setNickName: (v: string) => void; + setIsOpen: Dispatch>; + editNickName: string; + setEditNickName: Dispatch>; } -function EditNickName({ open, onClose, setNickName, nickname }: Props) { +function EditNickName({ + open, + onClose, + setNickName, + setIsOpen, + editNickName, + setEditNickName, +}: Props) { + const { toastError } = useToast(); const handlesave = async () => { - const res = await fetch(`${getApi}/me/profile`, { + if (editNickName.length <= 1) { + toastError('닉네임은 2글자 이상 입력해야합니다'); + return; + } + + await setNickName(editNickName); + + await fetch(`${getApi}/me/profile`, { method: 'PATCH', credentials: 'include', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ - nickname: nickname, + nickname: editNickName, }), }); + await setIsOpen(false); }; const handleChange = (e: React.ChangeEvent) => { - setNickName(e.target.value); + setEditNickName(e.target.value); }; return ( @@ -36,7 +56,7 @@ function EditNickName({ open, onClose, setNickName, nickname }: Props) { open={open} onClose={onClose} buttons={ - } @@ -46,7 +66,7 @@ function EditNickName({ open, onClose, setNickName, nickname }: Props) { 닉네임변경 handleChange(e)} placeholder="8글자 이내로 입력해주세요" id="editNickName" className="w-full" diff --git a/src/domains/mypage/components/ToggleBtn.tsx b/src/domains/mypage/components/ToggleBtn.tsx index 447bb1cd..d6fda4a0 100644 --- a/src/domains/mypage/components/ToggleBtn.tsx +++ b/src/domains/mypage/components/ToggleBtn.tsx @@ -1,13 +1,45 @@ 'use client'; +import { getApi } from '@/app/api/config/appConfig'; +import { useToast } from '@/shared/hook/useToast'; import clsx from 'clsx'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; function ToggleBtn() { - const [isClick, setIsClick] = useState(false); + const [isClick, setIsClick] = useState(null); + const { toastSuccess } = useToast(); - const handleClick = () => { - setIsClick(!isClick); + useEffect(() => { + const fetchToggle = async () => { + try { + const res = await fetch(`${getApi}/me/notification-setting`, { + method: 'GET', + credentials: 'include', + }); + const json = await res.json(); + setIsClick(json.data.enabled); + } catch { + console.error(); + } + }; + fetchToggle(); + }, []); + + const handleClick = async () => { + if (isClick === null) return; + const next = !isClick; + setIsClick(next); + + await fetch(`${getApi}/me/notification-setting`, { + method: 'PATCH', + credentials: 'include', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + enabled: next, + }), + }); + next ? toastSuccess('알림이 설정되었습니다.') : toastSuccess('알림이 해제되었습니다'); }; + return (
); diff --git a/src/domains/mypage/components/pages/my-bar/MyBar.tsx b/src/domains/mypage/components/pages/my-bar/MyBar.tsx index 4bb372e3..c20b0e2c 100644 --- a/src/domains/mypage/components/pages/my-bar/MyBar.tsx +++ b/src/domains/mypage/components/pages/my-bar/MyBar.tsx @@ -26,23 +26,27 @@ function MyBar() { }, []); return ( -
- {myCocktail ? ( - myCocktail.map(({ cocktailId, cocktailName, imageUrl }) => ( - - )) + > + {myCocktail.map(({ cocktailId, cocktailName, imageUrl }) => ( + + ))} +
) : ( -
칵테일을 담아보세요
+
+

아직 저장하신 칵테일이 없습니다.

+
)} ); diff --git a/src/domains/mypage/main/MyProfile.tsx b/src/domains/mypage/main/MyProfile.tsx index 519c14d5..b3206ecb 100644 --- a/src/domains/mypage/main/MyProfile.tsx +++ b/src/domains/mypage/main/MyProfile.tsx @@ -53,7 +53,7 @@ function MyProfile() { )} diff --git a/src/domains/shared/components/abv-graph/AbvGraph.tsx b/src/domains/shared/components/abv-graph/AbvGraph.tsx index bbe99c12..31291b18 100644 --- a/src/domains/shared/components/abv-graph/AbvGraph.tsx +++ b/src/domains/shared/components/abv-graph/AbvGraph.tsx @@ -1,11 +1,26 @@ +import tw from '@/shared/utills/tw'; +import { cva } from 'class-variance-authority'; import clsx from 'clsx'; interface Props { max?: number; abv?: number; + type?: 'myAbv' | 'cocktail'; } -function AbvGraph({ max, abv }: Props) { +export const abvClass = cva( + `h-3 rounded-full overflow-hidden border-[0.5px] border-gray relative`, + { + variants: { + type: { + myAbv: 'w-full md:w-55 ', + cocktail: 'w-45', + }, + }, + } +); + +function AbvGraph({ max, abv, type = 'cocktail' }: Props) { if (!abv) return; const safeMax = Math.max(0, max || 0.0001); const rawPct = (abv / safeMax) * 100; @@ -19,7 +34,7 @@ function AbvGraph({ max, abv }: Props) { return (
Date: Wed, 8 Oct 2025 15:30:55 +0900 Subject: [PATCH 04/10] =?UTF-8?q?[feat]=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EA=B0=9C=EC=9D=B8=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/domains/mypage/components/pages/my-active/MyComment.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/domains/mypage/components/pages/my-active/MyComment.tsx b/src/domains/mypage/components/pages/my-active/MyComment.tsx index 02497688..c52be8b8 100644 --- a/src/domains/mypage/components/pages/my-active/MyComment.tsx +++ b/src/domains/mypage/components/pages/my-active/MyComment.tsx @@ -23,13 +23,13 @@ function MyComment() { return (
- {CommentList.length !== 0 ? ( + {/* {CommentList.length !== 0 ? ( ) : (

작성한 댓글이 없습니다.

- )} + )} */}
); } From ca41408732e9195f880247214f6c8eef1f0f827d Mon Sep 17 00:00:00 2001 From: mtm1018 Date: Wed, 8 Oct 2025 16:04:19 +0900 Subject: [PATCH 05/10] =?UTF-8?q?[chore]=EB=AF=B8=EA=B0=9C=EB=B0=9C=20?= =?UTF-8?q?=EB=B6=80=EB=B6=84=20=EC=A3=BC=EC=84=9D=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/domains/mypage/components/pages/my-active/MyLike.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/domains/mypage/components/pages/my-active/MyLike.tsx b/src/domains/mypage/components/pages/my-active/MyLike.tsx index 610c1eb8..7785690f 100644 --- a/src/domains/mypage/components/pages/my-active/MyLike.tsx +++ b/src/domains/mypage/components/pages/my-active/MyLike.tsx @@ -20,13 +20,13 @@ function MyLike() { credentials: 'include', }); const json = await res.json(); - setMyLike(json.data.items); + // setMyLike(json.data.items); }; useEffect(() => { fetchLike(); }, []); - return ; + // return ; } export default MyLike; From b310c7cc08a6c5c4bf7ee2a0d76058565f63ab3e Mon Sep 17 00:00:00 2001 From: mtm1018 Date: Wed, 8 Oct 2025 16:09:59 +0900 Subject: [PATCH 06/10] =?UTF-8?q?[chore]=EB=AF=B8=EA=B0=9C=EB=B0=9C=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=A3=BC=EC=84=9D?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/mypage/my-active/my-like/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/mypage/my-active/my-like/page.tsx b/src/app/mypage/my-active/my-like/page.tsx index 25e60259..fb9205a4 100644 --- a/src/app/mypage/my-active/my-like/page.tsx +++ b/src/app/mypage/my-active/my-like/page.tsx @@ -8,6 +8,6 @@ export const metadata: Metadata = { }; function Page() { - return ; + // return ; } export default Page; From a7564035bfaeb5803d88d08f7854a0b1f00b6c0d Mon Sep 17 00:00:00 2001 From: mtm1018 Date: Thu, 9 Oct 2025 01:05:15 +0900 Subject: [PATCH 07/10] =?UTF-8?q?[refactor]=EC=95=8C=EB=A6=BC=20=EC=BB=A8?= =?UTF-8?q?=ED=8E=8C=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mypage/components/EditNickName.tsx | 19 +++---- src/domains/mypage/components/ToggleBtn.tsx | 57 ++++++++++--------- .../pages/my-alarm/AlarmConfirm.tsx | 27 +++++++++ src/domains/mypage/hook/useConfirm.ts | 27 +++++++++ src/domains/mypage/main/MySetting.tsx | 2 + src/shared/components/Input-box/Input.tsx | 5 +- 6 files changed, 96 insertions(+), 41 deletions(-) create mode 100644 src/domains/mypage/components/pages/my-alarm/AlarmConfirm.tsx create mode 100644 src/domains/mypage/hook/useConfirm.ts diff --git a/src/domains/mypage/components/EditNickName.tsx b/src/domains/mypage/components/EditNickName.tsx index e5ed8774..05a7c419 100644 --- a/src/domains/mypage/components/EditNickName.tsx +++ b/src/domains/mypage/components/EditNickName.tsx @@ -9,7 +9,7 @@ import { Dispatch, SetStateAction, useEffect, useState } from 'react'; interface Props { open: boolean; onClose: () => void; - nickname:string + nickname: string; setNickName: (v: string) => void; setIsOpen: Dispatch>; editNickName: string; @@ -25,14 +25,14 @@ function EditNickName({ editNickName, setEditNickName, }: Props) { - const [defaultNickname,setDefaultNickname] = useState(nickname) - const { toastSuccess,toastError } = useToast(); + const [defaultNickname, setDefaultNickname] = useState(nickname); + const { toastSuccess, toastError } = useToast(); useEffect(() => { - setEditNickName(nickname) - setDefaultNickname(nickname) - }, [nickname,setEditNickName]) - + setEditNickName(nickname); + setDefaultNickname(nickname); + }, [nickname, setEditNickName]); + const handlesave = async () => { if (editNickName.length <= 1 || editNickName.length >= 8) { toastError('닉네임은 2글자 이상 입력해야합니다'); @@ -57,12 +57,11 @@ function EditNickName({ const handleChange = (e: React.ChangeEvent) => { setEditNickName(e.target.value); - }; const handleDefaultNickname = () => { - setEditNickName(defaultNickname) - } + setEditNickName(defaultNickname); + }; return ( (null); - const { toastSuccess } = useToast(); + const [isAlarm, setIsAlarm] = useState(null); + const [isClick, setIsClick] = useState(false); useEffect(() => { const fetchToggle = async () => { @@ -16,7 +16,8 @@ function ToggleBtn() { credentials: 'include', }); const json = await res.json(); - setIsClick(json.data.enabled); + console.log(json); + setIsAlarm(json.data.enabled); } catch { console.error(); } @@ -25,36 +26,36 @@ function ToggleBtn() { }, []); const handleClick = async () => { - if (isClick === null) return; - const next = !isClick; - setIsClick(next); - - await fetch(`${getApi}/me/notification-setting`, { - method: 'PATCH', - credentials: 'include', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - enabled: next, - }), - }); - next ? toastSuccess('알림이 설정되었습니다.') : toastSuccess('알림이 해제되었습니다'); + setIsClick(true); }; return ( - + onClick={handleClick} + > +
+ +
); } export default ToggleBtn; diff --git a/src/domains/mypage/components/pages/my-alarm/AlarmConfirm.tsx b/src/domains/mypage/components/pages/my-alarm/AlarmConfirm.tsx new file mode 100644 index 00000000..0d875b9b --- /dev/null +++ b/src/domains/mypage/components/pages/my-alarm/AlarmConfirm.tsx @@ -0,0 +1,27 @@ +import { useConfirm } from '@/domains/mypage/hook/useConfirm'; +import ConfirmModal from '@/shared/components/modal-pop/ConfirmModal'; +import { Dispatch, SetStateAction } from 'react'; + +interface Props { + open: boolean; + onClose: () => void; + state: boolean | null; + cancle: () => void; + setIsAlarm: Dispatch>; + setIsClick: Dispatch>; +} + +function AlarmConfirm({ open, onClose, state, cancle, setIsAlarm, setIsClick }: Props) { + const { patchAlarm } = useConfirm(state, setIsAlarm, setIsClick); + + return ( + + ); +} +export default AlarmConfirm; diff --git a/src/domains/mypage/hook/useConfirm.ts b/src/domains/mypage/hook/useConfirm.ts new file mode 100644 index 00000000..8967fec6 --- /dev/null +++ b/src/domains/mypage/hook/useConfirm.ts @@ -0,0 +1,27 @@ +import { getApi } from '@/app/api/config/appConfig'; +import { useToast } from '@/shared/hook/useToast'; +import { Dispatch, SetStateAction } from 'react'; + +export function useConfirm( + state: boolean | null, + setIsAlarm: Dispatch>, + setIsClick: Dispatch> +) { + const { toastSuccess } = useToast(); + const next = !state; + const patchAlarm = async () => { + await fetch(`${getApi}/me/notification-setting`, { + method: 'PATCH', + credentials: 'include', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + enabled: next, + }), + }); + setIsAlarm(next); + setIsClick(false); + + (await next) ? toastSuccess('알림이 설정되었습니다.') : toastSuccess('알림이 해제되었습니다'); + }; + return { patchAlarm }; +} diff --git a/src/domains/mypage/main/MySetting.tsx b/src/domains/mypage/main/MySetting.tsx index e1599bf9..9eb15d02 100644 --- a/src/domains/mypage/main/MySetting.tsx +++ b/src/domains/mypage/main/MySetting.tsx @@ -5,6 +5,7 @@ import WithdrawModal from '@/domains/mypage/components/WithdrawModal'; import TextButton from '@/shared/components/button/TextButton'; import { useEffect, useState } from 'react'; import useFetchProfile from '../api/fetchProfile'; +import AlarmConfirm from '../components/pages/my-alarm/AlarmConfirm'; function MySetting() { const { profile } = useFetchProfile(); @@ -42,6 +43,7 @@ function MySetting() {

알람설정

+
diff --git a/src/shared/components/Input-box/Input.tsx b/src/shared/components/Input-box/Input.tsx index 8c3389ec..faefd257 100644 --- a/src/shared/components/Input-box/Input.tsx +++ b/src/shared/components/Input-box/Input.tsx @@ -13,7 +13,7 @@ import Button from '../button/Button'; interface Props { placeholder: string; - value?: string + value?: string; type?: HTMLInputTypeAttribute; ref?: Ref; @@ -44,7 +44,7 @@ function Input({ type, ref, value, - + size, variant = 'default', className, @@ -62,7 +62,6 @@ function Input({ className={`outline-none w-full flex-1 leading-${size}`} ref={ref} value={value} - onChange={onChange} {...rest} /> From 7b2d9bcde67a7452461133f535069d0ae5c2c8e2 Mon Sep 17 00:00:00 2001 From: mtm1018 Date: Thu, 9 Oct 2025 01:30:18 +0900 Subject: [PATCH 08/10] =?UTF-8?q?[refactor]=20=EC=95=8C=EC=BD=9C=EB=8F=84?= =?UTF-8?q?=EC=88=98=20=EB=8F=84=EC=88=98=20=EC=83=89=20=EB=B3=80=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mypage/components/pages/my-bar/MyBar.tsx | 18 ++++++++++-------- src/domains/mypage/main/MyAbv.tsx | 17 ++++++++++++++++- src/domains/mypage/main/MySetting.tsx | 1 - .../shared/components/abv-graph/AbvGraph.tsx | 2 +- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/domains/mypage/components/pages/my-bar/MyBar.tsx b/src/domains/mypage/components/pages/my-bar/MyBar.tsx index 6965048d..bb96e8b2 100644 --- a/src/domains/mypage/components/pages/my-bar/MyBar.tsx +++ b/src/domains/mypage/components/pages/my-bar/MyBar.tsx @@ -1,6 +1,7 @@ 'use client'; import { getApi } from '@/app/api/config/appConfig'; import CocktailCard from '@/domains/shared/components/cocktail-card/CocktailCard'; +import Link from 'next/link'; import { useEffect, useState } from 'react'; interface MyCocktail { @@ -37,14 +38,15 @@ function MyBar() { " > {myCocktail.map(({ cocktailId, cocktailName, imageUrl }) => ( - + + + ))} ) : ( diff --git a/src/domains/mypage/main/MyAbv.tsx b/src/domains/mypage/main/MyAbv.tsx index 0b1d88b9..b840bf55 100644 --- a/src/domains/mypage/main/MyAbv.tsx +++ b/src/domains/mypage/main/MyAbv.tsx @@ -9,6 +9,18 @@ function MyAbv({ abv }: { abv: number }) { const viewPoint = isMd ? 'web' : 'mobileLongText'; const fixedAbv = abv.toFixed(1); + const t = Math.min(1, Math.max(0, abv / 100)); + + // HEX → RGB + const from = [255, 202, 141]; // FFCA8D + const to = [250, 36, 36]; // FA2424 + + // RGB + const r = Math.round(from[0] + (to[0] - from[0]) * t); + const g = Math.round(from[1] + (to[1] - from[1]) * t); + const b = Math.round(from[2] + (to[2] - from[2]) * t); + const color = `rgb(${r}, ${g}, ${b})`; + return (
@@ -23,7 +35,10 @@ function MyAbv({ abv }: { abv: number }) {
- {fixedAbv}% + + {fixedAbv} + + %
); diff --git a/src/domains/mypage/main/MySetting.tsx b/src/domains/mypage/main/MySetting.tsx index 9eb15d02..f5d01c93 100644 --- a/src/domains/mypage/main/MySetting.tsx +++ b/src/domains/mypage/main/MySetting.tsx @@ -5,7 +5,6 @@ import WithdrawModal from '@/domains/mypage/components/WithdrawModal'; import TextButton from '@/shared/components/button/TextButton'; import { useEffect, useState } from 'react'; import useFetchProfile from '../api/fetchProfile'; -import AlarmConfirm from '../components/pages/my-alarm/AlarmConfirm'; function MySetting() { const { profile } = useFetchProfile(); diff --git a/src/domains/shared/components/abv-graph/AbvGraph.tsx b/src/domains/shared/components/abv-graph/AbvGraph.tsx index 31291b18..d93c4915 100644 --- a/src/domains/shared/components/abv-graph/AbvGraph.tsx +++ b/src/domains/shared/components/abv-graph/AbvGraph.tsx @@ -28,7 +28,7 @@ function AbvGraph({ max, abv, type = 'cocktail' }: Props) { const bandClass = clsx( 'h-full rounded-full transition-[width] duration-500', - 'bg-gradient-to-r from-amber-300 to-red-500', // 기본 그라데이션 + 'bg-gradient-to-r from-[#FFCA8D] to-[#FA2424]', // 기본 그라데이션 pct >= 80 && 'shadow-[0_0_12px_rgba(250,36,36,0.45)]' ); From e82822effc55062a1265e37570b3c7c8c61b9c99 Mon Sep 17 00:00:00 2001 From: mtm1018 Date: Thu, 9 Oct 2025 01:47:03 +0900 Subject: [PATCH 09/10] =?UTF-8?q?[fix]=20=EC=B9=B5=ED=85=8C=EC=9D=BC=20?= =?UTF-8?q?=EB=93=9C=EB=A1=AD=EB=8B=A4=EC=9A=B4=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/domains/recipe/details/DetailItem.tsx | 6 +++--- src/domains/shared/components/keep/Keep.tsx | 4 ++++ src/shared/components/select-box/SelectBox.tsx | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/domains/recipe/details/DetailItem.tsx b/src/domains/recipe/details/DetailItem.tsx index 88c17c5f..64f10910 100644 --- a/src/domains/recipe/details/DetailItem.tsx +++ b/src/domains/recipe/details/DetailItem.tsx @@ -35,16 +35,16 @@ function DetailItem({ name, nameKo, story, src, abv, glassType }: Props) {
{alcoholTitle &&

- + {name} - + {nameKo}

-

+

{story}

diff --git a/src/domains/shared/components/keep/Keep.tsx b/src/domains/shared/components/keep/Keep.tsx index 5c36cb86..bc306688 100644 --- a/src/domains/shared/components/keep/Keep.tsx +++ b/src/domains/shared/components/keep/Keep.tsx @@ -4,6 +4,7 @@ import KeepIcon from '@/shared/assets/icons/keep_36.svg'; import KeepIconActive from '@/shared/assets/icons/keep_active_36.svg'; import { useState } from 'react'; import { deleteKeep, postKeep } from '../../api/keep/keep'; +import { useToast } from '@/shared/hook/useToast'; interface Props { className?: string; @@ -13,6 +14,7 @@ interface Props { // 만약 타입 안맞는다면 그냥 두셔도 됩니다. function Keep({ className, cocktailId }: Props) { + const { toastSuccess } = useToast(); const [isClick, setIsClick] = useState(false); const handleClick = async (e: React.MouseEvent) => { @@ -25,8 +27,10 @@ function Keep({ className, cocktailId }: Props) { if (!cocktailId) return; if (!isClick) { await postKeep(cocktailId); + toastSuccess('저장에 성공하셨습니다.'); } else { await deleteKeep(cocktailId); + toastSuccess('저장을 취소하셨습니다.'); } } catch (err) { console.error(err); diff --git a/src/shared/components/select-box/SelectBox.tsx b/src/shared/components/select-box/SelectBox.tsx index 7a74b3d9..994d1897 100644 --- a/src/shared/components/select-box/SelectBox.tsx +++ b/src/shared/components/select-box/SelectBox.tsx @@ -88,7 +88,7 @@ function SelectBox({ id, groupKey, ref, option, title, value, onChange, use }: P
    handleChoose(v)} aria-selected={v === select} > From 58fdc76d688d9637b06d36d13a44de29be3fc8dd Mon Sep 17 00:00:00 2001 From: mtm1018 Date: Fri, 10 Oct 2025 11:31:18 +0900 Subject: [PATCH 10/10] =?UTF-8?q?[style]=20=EC=95=8C=EC=BD=9C=EB=8F=84?= =?UTF-8?q?=EC=88=98=EC=99=80=20%=ED=91=9C=EC=8B=9C=EB=9D=84=EC=9B=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/domains/mypage/main/MyAbv.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/domains/mypage/main/MyAbv.tsx b/src/domains/mypage/main/MyAbv.tsx index b840bf55..d07ac7bb 100644 --- a/src/domains/mypage/main/MyAbv.tsx +++ b/src/domains/mypage/main/MyAbv.tsx @@ -34,7 +34,7 @@ function MyAbv({ abv }: { abv: number }) { -
    +
    {fixedAbv}