From 21657abb388bc6bdf7272c49918bd8bcfa9fc17b Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Sun, 15 Oct 2023 18:57:25 +0900 Subject: [PATCH 01/38] =?UTF-8?q?test:=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=EC=97=90=EC=84=9C=20=EB=A7=88=EC=9D=B4=20?= =?UTF-8?q?=ED=8C=8C=ED=8A=B8=20msw=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20?= =?UTF-8?q?=EC=A2=8B=EC=95=84=EC=9A=94=ED=95=9C=20=ED=8C=8C=ED=8A=B8=20?= =?UTF-8?q?=EC=97=94=EB=93=9C=ED=8F=AC=EC=9D=B8=ED=8A=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/mocks/handlers/memberHandlers.ts | 192 +++++++++++++++++- 1 file changed, 191 insertions(+), 1 deletion(-) diff --git a/frontend/src/mocks/handlers/memberHandlers.ts b/frontend/src/mocks/handlers/memberHandlers.ts index 4cf177928..a5abea6a4 100644 --- a/frontend/src/mocks/handlers/memberHandlers.ts +++ b/frontend/src/mocks/handlers/memberHandlers.ts @@ -3,7 +3,7 @@ import { rest } from 'msw'; const { BASE_URL } = process.env; export const memberHandlers = [ - rest.get(`${BASE_URL}/my-page`, (req, res, ctx) => { + rest.get(`${BASE_URL}/my-page/like-parts`, (req, res, ctx) => { return res( ctx.json([ { @@ -68,6 +68,196 @@ export const memberHandlers = [ start: 66, end: 76, }, + { + songId: 7, + title: 'Super Shy', + singer: 'New Jeans', + albumCoverUrl: + 'https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize', + partId: 16, + start: 66, + end: 76, + }, + { + songId: 8, + title: 'Super Shy', + singer: 'New Jeans', + albumCoverUrl: + 'https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize', + partId: 16, + start: 66, + end: 76, + }, + { + songId: 9, + title: 'Super Shy', + singer: 'New Jeans', + albumCoverUrl: + 'https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize', + partId: 16, + start: 66, + end: 76, + }, + { + songId: 10, + title: 'Super Shy', + singer: 'New Jeans', + albumCoverUrl: + 'https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize', + partId: 16, + start: 66, + end: 76, + }, + { + songId: 11, + title: 'Super Shy', + singer: 'New Jeans', + albumCoverUrl: + 'https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize', + partId: 16, + start: 66, + end: 76, + }, + ]) + ); + }), + + rest.get(`${BASE_URL}/my-page/member-parts`, (req, res, ctx) => { + return res( + ctx.json([ + { + songId: 1, + title: '후라이의 꿈', + singer: 'AKMU (악뮤)', + albumCoverUrl: + 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', + partId: 11, + start: 1, + end: 11, + }, + { + songId: 2, + title: + '제목이 너무 길다면 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데?', + singer: + '가수 이름도 너무 길다면 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데?', + albumCoverUrl: + 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', + partId: 12, + start: 13, + end: 23, + }, + { + songId: 3, + title: '후라이의 꿈', + singer: 'AKMU (악뮤)', + albumCoverUrl: + 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', + partId: 13, + start: 36, + end: 46, + }, + { + songId: 4, + title: '후라이의 꿈', + singer: 'AKMU (악뮤)', + albumCoverUrl: + 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', + partId: 14, + start: 77, + end: 87, + }, + { + songId: 5, + title: '후라이의 꿈', + singer: 'AKMU (악뮤)', + albumCoverUrl: + 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', + partId: 15, + start: 102, + end: 112, + }, + { + songId: 6, + title: '후라이의 꿈', + singer: 'AKMU (악뮤)', + albumCoverUrl: + 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', + partId: 16, + start: 190, + end: 200, + }, + { + songId: 7, + title: '후라이의 꿈', + singer: 'AKMU (악뮤)', + albumCoverUrl: + 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', + partId: 16, + start: 190, + end: 200, + }, + + { + songId: 8, + title: '후라이의 꿈', + singer: 'AKMU (악뮤)', + albumCoverUrl: + 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', + partId: 16, + start: 190, + end: 200, + }, + { + songId: 9, + title: '후라이의 꿈', + singer: 'AKMU (악뮤)', + albumCoverUrl: + 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', + partId: 16, + start: 190, + end: 200, + }, + { + songId: 10, + title: '후라이의 꿈', + singer: 'AKMU (악뮤)', + albumCoverUrl: + 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', + partId: 16, + start: 190, + end: 200, + }, + { + songId: 11, + title: '후라이의 꿈', + singer: 'AKMU (악뮤)', + albumCoverUrl: + 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', + partId: 16, + start: 190, + end: 200, + }, + { + songId: 12, + title: '후라이의 꿈', + singer: 'AKMU (악뮤)', + albumCoverUrl: + 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', + partId: 16, + start: 190, + end: 200, + }, + { + songId: 13, + title: '후라이의 꿈', + singer: 'AKMU (악뮤)', + albumCoverUrl: + 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', + partId: 16, + start: 190, + end: 200, + }, ]) ); }), From ef5effb27ca22e5b58656fea253ee5cd4d339639 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Sun, 15 Oct 2023 19:03:41 +0900 Subject: [PATCH 02/38] =?UTF-8?q?feat:=20LikePartItem=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=EB=A5=BC=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 컴포넌트 이름 변경: PartItem (좋아요와 마이파트 모두 사용) --- .../features/member/components/PartItem.tsx | 129 ++++++++++++++++++ frontend/src/pages/MyPage.tsx | 125 +---------------- 2 files changed, 131 insertions(+), 123 deletions(-) create mode 100644 frontend/src/features/member/components/PartItem.tsx diff --git a/frontend/src/features/member/components/PartItem.tsx b/frontend/src/features/member/components/PartItem.tsx new file mode 100644 index 000000000..a17a62133 --- /dev/null +++ b/frontend/src/features/member/components/PartItem.tsx @@ -0,0 +1,129 @@ +import { useNavigate } from 'react-router-dom'; +import styled from 'styled-components'; +import link from '@/assets/icon/link.svg'; +import shook from '@/assets/icon/shook.svg'; +import { useAuthContext } from '@/features/auth/components/AuthProvider'; +import Thumbnail from '@/features/songs/components/Thumbnail'; +import Spacing from '@/shared/components/Spacing'; +import useToastContext from '@/shared/components/Toast/hooks/useToastContext'; +import { GA_ACTIONS, GA_CATEGORIES } from '@/shared/constants/GAEventName'; +import sendGAEvent from '@/shared/googleAnalytics/sendGAEvent'; +import { secondsToMinSec, toPlayingTimeText } from '@/shared/utils/convertTime'; +import copyClipboard from '@/shared/utils/copyClipBoard'; +import type { LikeKillingPart } from './MyPartList'; + +type PartItemProps = LikeKillingPart & { + rank: number; +}; + +const PartItem = ({ songId, albumCoverUrl, title, singer, start, end }: PartItemProps) => { + const { showToast } = useToastContext(); + const { user } = useAuthContext(); + const navigate = useNavigate(); + + const shareUrl: React.MouseEventHandler = (e) => { + e.stopPropagation(); + sendGAEvent({ + action: GA_ACTIONS.COPY_URL, + category: GA_CATEGORIES.MY_PAGE, + memberId: user?.memberId, + }); + + copyClipboard(`${process.env.BASE_URL?.replace('/api', '')}/songs/${songId}/ALL`); + showToast('클립보드에 영상링크가 복사되었습니다.'); + }; + + const goToListenSong = () => { + navigate(`/songs/${songId}/ALL`); + }; + + const { minute: startMin, second: startSec } = secondsToMinSec(start); + const { minute: endMin, second: endSec } = secondsToMinSec(end); + + return ( + + + {title} + {singer} + + + +

+ {toPlayingTimeText(start, end)} +

+ +
+ + + +
+ ); +}; + +const Grid = styled.button` + display: grid; + grid-template: + 'thumbnail title _' 26px + 'thumbnail singer share' 26px + 'thumbnail info share' 18px + / 70px auto 26px; + column-gap: 8px; + + width: 100%; + padding: 6px 0; + + color: ${({ theme: { color } }) => color.white}; + text-align: start; +`; + +const SongTitle = styled.div` + overflow: hidden; + grid-area: title; + + font-size: 16px; + font-weight: 800; + text-overflow: ellipsis; + white-space: nowrap; +`; + +const Singer = styled.div` + overflow: hidden; + grid-area: singer; + + font-size: 12px; + text-overflow: ellipsis; + white-space: nowrap; +`; + +const TimeWrapper = styled.div` + display: flex; + grid-area: info; + + font-size: 14px; + font-weight: 700; + color: ${({ theme: { color } }) => color.primary}; + letter-spacing: 1px; +`; + +const ShareButton = styled.button` + grid-area: share; + width: 26px; + height: 26px; +`; + +const Share = styled.img` + padding: 2px; + background-color: white; + border-radius: 50%; +`; + +const Shook = styled.img` + width: 16px; + height: 18px; + border-radius: 50%; +`; + +export default PartItem; diff --git a/frontend/src/pages/MyPage.tsx b/frontend/src/pages/MyPage.tsx index 8824e2fad..94afd5675 100644 --- a/frontend/src/pages/MyPage.tsx +++ b/frontend/src/pages/MyPage.tsx @@ -1,25 +1,18 @@ import { useNavigate } from 'react-router-dom'; import { styled } from 'styled-components'; -import link from '@/assets/icon/link.svg'; -import shook from '@/assets/icon/shook.svg'; import shookshook from '@/assets/icon/shookshook.svg'; import { useAuthContext } from '@/features/auth/components/AuthProvider'; -import Thumbnail from '@/features/songs/components/Thumbnail'; +import PartItem from '@/features/member/components/PartItem'; import Flex from '@/shared/components/Flex'; import Spacing from '@/shared/components/Spacing'; import SRHeading from '@/shared/components/SRHeading'; -import useToastContext from '@/shared/components/Toast/hooks/useToastContext'; import { GA_ACTIONS, GA_CATEGORIES } from '@/shared/constants/GAEventName'; import ROUTE_PATH from '@/shared/constants/path'; import sendGAEvent from '@/shared/googleAnalytics/sendGAEvent'; import useFetch from '@/shared/hooks/useFetch'; import fetcher from '@/shared/remotes'; -import { secondsToMinSec, toPlayingTimeText } from '@/shared/utils/convertTime'; -import copyClipboard from '@/shared/utils/copyClipBoard'; import type { KillingPart, SongDetail } from '@/shared/types/song'; -const { BASE_URL } = process.env; - const introductions = [ '아무 노래나 일단 틀어', '또 물보라를 일으켜', @@ -91,7 +84,7 @@ const MyPage = () => { {likes.map(({ songId, title, singer, albumCoverUrl, partId, start, end }, i) => { return (
  • - theme.color.white}; `; - -type LikePartItemProps = LikeKillingPart & { - rank: number; -}; - -const LikePartItem = ({ songId, albumCoverUrl, title, singer, start, end }: LikePartItemProps) => { - const { showToast } = useToastContext(); - const { user } = useAuthContext(); - const navigate = useNavigate(); - - const shareUrl: React.MouseEventHandler = (e) => { - e.stopPropagation(); - sendGAEvent({ - action: GA_ACTIONS.COPY_URL, - category: GA_CATEGORIES.MY_PAGE, - memberId: user?.memberId, - }); - - copyClipboard(`${BASE_URL?.replace('/api', '')}/songs/${songId}/ALL`); - showToast('클립보드에 영상링크가 복사되었습니다.'); - }; - - const goToListenSong = () => { - navigate(`/songs/${songId}/ALL`); - }; - - const { minute: startMin, second: startSec } = secondsToMinSec(start); - const { minute: endMin, second: endSec } = secondsToMinSec(end); - - return ( - - - {title} - {singer} - - - -

    - {toPlayingTimeText(start, end)} -

    - -
    - - - -
    - ); -}; - -const Grid = styled.button` - display: grid; - grid-template: - 'thumbnail title _' 26px - 'thumbnail singer share' 26px - 'thumbnail info share' 18px - / 70px auto 26px; - column-gap: 8px; - - width: 100%; - padding: 6px 0; - - color: ${({ theme: { color } }) => color.white}; - text-align: start; -`; - -const SongTitle = styled.div` - overflow: hidden; - grid-area: title; - - font-size: 16px; - font-weight: 800; - text-overflow: ellipsis; - white-space: nowrap; -`; - -const Singer = styled.div` - overflow: hidden; - grid-area: singer; - - font-size: 12px; - text-overflow: ellipsis; - white-space: nowrap; -`; - -const TimeWrapper = styled.div` - display: flex; - grid-area: info; - - font-size: 14px; - font-weight: 700; - color: ${({ theme: { color } }) => color.primary}; - letter-spacing: 1px; -`; - -const ShareButton = styled.button` - grid-area: share; - width: 26px; - height: 26px; -`; - -const Share = styled.img` - padding: 2px; - background-color: white; - border-radius: 50%; -`; From 1e6ca3912f1a973c8a02ea0998bc97a081213c02 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Sun, 15 Oct 2023 19:11:18 +0900 Subject: [PATCH 03/38] =?UTF-8?q?feat:=20PartList=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 탭 전환시 스크롤이 상단으로 이동하도록 구현 --- .../features/member/components/PartList.tsx | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 frontend/src/features/member/components/PartList.tsx diff --git a/frontend/src/features/member/components/PartList.tsx b/frontend/src/features/member/components/PartList.tsx new file mode 100644 index 000000000..94511821a --- /dev/null +++ b/frontend/src/features/member/components/PartList.tsx @@ -0,0 +1,60 @@ +import { useEffect } from 'react'; +import styled from 'styled-components'; +import PartItem from './PartItem'; +import type { LikeKillingPart } from './MyPartList'; + +interface PartListProps { + parts: LikeKillingPart[]; +} + +const PART_LIST_SCROLL_TOP = 148; + +const PartList = ({ parts }: PartListProps) => { + useEffect(() => { + if (window.scrollY > PART_LIST_SCROLL_TOP) { + window.scrollTo({ top: PART_LIST_SCROLL_TOP, behavior: 'smooth' }); + } + }, [parts]); + + return ( + + {parts.map(({ songId, title, singer, albumCoverUrl, partId, start, end }, i) => { + return ( +
  • + +
  • + ); + })} + + ); +}; + +export default PartList; + +const PopularSongList = styled.ol` + display: flex; + flex-direction: column; + gap: 12px; + align-items: flex-start; + + width: 100%; +`; + +const Li = styled.li` + width: 100%; + padding: 0 10px; + + &:hover, + &:focus { + background-color: ${({ theme }) => theme.color.secondary}; + } +`; From 1903827968dd649af5ef5bd158cd3ba916a0ac4d Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Sun, 15 Oct 2023 19:12:36 +0900 Subject: [PATCH 04/38] =?UTF-8?q?feat:=20PartList=EA=B0=80=20=ED=8F=AC?= =?UTF-8?q?=ED=95=A8=EB=90=9C=20=ED=83=AD=EC=9D=84=20=EC=84=A4=EC=A0=95?= =?UTF-8?q?=ED=95=98=EB=8A=94=20MyPartList=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../features/member/components/MyPartList.tsx | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 frontend/src/features/member/components/MyPartList.tsx diff --git a/frontend/src/features/member/components/MyPartList.tsx b/frontend/src/features/member/components/MyPartList.tsx new file mode 100644 index 000000000..f8d59fdfe --- /dev/null +++ b/frontend/src/features/member/components/MyPartList.tsx @@ -0,0 +1,84 @@ +import { useState } from 'react'; +import styled from 'styled-components'; +import Spacing from '@/shared/components/Spacing'; +import useFetch from '@/shared/hooks/useFetch'; +import fetcher from '@/shared/remotes'; +import PartList from './PartList'; +import type { KillingPart, SongDetail } from '@/shared/types/song'; + +export type LikeKillingPart = Pick & + Pick & { + songId: number; + partId: number; + }; + +const MyPartList = () => { + const [tab, setTab] = useState<'Like' | 'MyKillingPart'>('Like'); + + const { data: likes } = useFetch(() => fetcher('/my-page/like-parts', 'get')); + const { data: myParts } = useFetch(() => + fetcher('/my-page/member-parts', 'get') + ); + + if (!likes || !myParts) return null; + + const partList: { tab: 'Like' | 'MyKillingPart'; parts: LikeKillingPart[] }[] = [ + { tab: 'Like', parts: likes }, + { tab: 'MyKillingPart', parts: myParts }, + ]; + + const [selectedParts] = partList.filter((p) => p.tab === tab); + + return ( + <> + + setTab('Like')}> + 좋아요 한 킬링파트 + + setTab('MyKillingPart')}> + 내 킬링파트 + + + + + + + + ); +}; + +export default MyPartList; + +const Tabs = styled.ul` + position: sticky; + top: ${({ theme }) => theme.headerHeight.desktop}; + display: flex; + background-color: ${({ theme: { color } }) => color.black}; + + @media (max-width: ${({ theme }) => theme.breakPoints.xs}) { + top: ${({ theme }) => theme.headerHeight.mobile}; + } + + @media (max-width: ${({ theme }) => theme.breakPoints.xxs}) { + top: ${({ theme }) => theme.headerHeight.xxs}; + } +`; + +const TabItem = styled.li<{ $isActive?: boolean }>` + cursor: pointer; + + flex-shrink: 1; + + width: 100%; + padding: 15px 20px; + + color: ${({ $isActive, theme: { color } }) => ($isActive ? color.white : color.disabled)}; + text-align: center; + + border-bottom: 2px solid + ${({ $isActive, theme: { color } }) => ($isActive ? color.white : color.disabled)}; + + transition: + color 0.3s, + border 0.3s; +`; From 3ee7f920e769e1ed923f56b00d6d0f3cf48f37d3 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Sun, 15 Oct 2023 19:13:34 +0900 Subject: [PATCH 05/38] =?UTF-8?q?feat:=20=EC=A2=8B=EC=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=ED=82=AC=EB=A7=81=ED=8C=8C=ED=8A=B8=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=A2=8B=EC=95=84=EC=9A=94=EC=99=80=20=EB=A7=88?= =?UTF-8?q?=EC=9D=B4=ED=8C=8C=ED=8A=B8=EA=B0=80=20=ED=8F=AC=ED=95=A8?= =?UTF-8?q?=EB=90=9C=20MyPartList=EB=A5=BC=20=EB=B3=B4=EC=97=AC=EC=A3=BC?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/pages/MyPage.tsx | 63 ++--------------------------------- 1 file changed, 3 insertions(+), 60 deletions(-) diff --git a/frontend/src/pages/MyPage.tsx b/frontend/src/pages/MyPage.tsx index 94afd5675..05154bdfd 100644 --- a/frontend/src/pages/MyPage.tsx +++ b/frontend/src/pages/MyPage.tsx @@ -2,16 +2,13 @@ import { useNavigate } from 'react-router-dom'; import { styled } from 'styled-components'; import shookshook from '@/assets/icon/shookshook.svg'; import { useAuthContext } from '@/features/auth/components/AuthProvider'; -import PartItem from '@/features/member/components/PartItem'; +import MyPartList from '@/features/member/components/MyPartList'; import Flex from '@/shared/components/Flex'; import Spacing from '@/shared/components/Spacing'; import SRHeading from '@/shared/components/SRHeading'; import { GA_ACTIONS, GA_CATEGORIES } from '@/shared/constants/GAEventName'; import ROUTE_PATH from '@/shared/constants/path'; import sendGAEvent from '@/shared/googleAnalytics/sendGAEvent'; -import useFetch from '@/shared/hooks/useFetch'; -import fetcher from '@/shared/remotes'; -import type { KillingPart, SongDetail } from '@/shared/types/song'; const introductions = [ '아무 노래나 일단 틀어', @@ -21,15 +18,8 @@ const introductions = [ '우린 참 별나고 이상한 사이야', ]; -type LikeKillingPart = Pick & - Pick & { - songId: number; - partId: number; - }; - const MyPage = () => { const { user, logout } = useAuthContext(); - const { data: likes } = useFetch(() => fetcher('/my-page', 'get')); const navigate = useNavigate(); const logoutRedirect = () => { @@ -52,8 +42,6 @@ const MyPage = () => { navigate(`/${ROUTE_PATH.EDIT_PROFILE}`); }; - if (!likes) return null; - return ( 마이 페이지 @@ -74,30 +62,11 @@ const MyPage = () => { - + - 좋아요한 킬링파트 {likes.length.toLocaleString('ko-KR')}개 + - - - {likes.map(({ songId, title, singer, albumCoverUrl, partId, start, end }, i) => { - return ( -
  • - -
  • - ); - })} -
    ); }; @@ -124,16 +93,6 @@ const Box = styled.div` width: 100%; `; -const Li = styled.li` - width: 100%; - padding: 0 10px; - - &:hover, - &:focus { - background-color: ${({ theme }) => theme.color.secondary}; - } -`; - const Title = styled.h2` align-self: flex-start; font-size: 20px; @@ -141,15 +100,6 @@ const Title = styled.h2` color: white; `; -const PopularSongList = styled.ol` - display: flex; - flex-direction: column; - gap: 12px; - align-items: flex-start; - - width: 100%; -`; - const SpaceBetween = styled(Flex)` justify-content: space-between; `; @@ -169,10 +119,3 @@ const Button = styled.button` border: 1.6px solid ${({ theme }) => theme.color.secondary}; border-radius: 12px; `; - -const Subtitle = styled.div` - width: 100%; - height: 36px; - font-size: 18px; - border-bottom: 1px solid ${({ theme }) => theme.color.white}; -`; From 4909fe9f3e445728b33b7d85154f2a9216b09ae1 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Sun, 15 Oct 2023 19:14:48 +0900 Subject: [PATCH 06/38] =?UTF-8?q?test:=20songEntries=20mock=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=EC=97=90=20myPart=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=B0=8F=20songHandler=EC=97=90=20=EB=A7=88=EC=9D=B4=20?= =?UTF-8?q?=ED=8C=8C=ED=8A=B8=EB=A5=BC=20=EC=82=AD=EC=A0=9C=ED=95=98?= =?UTF-8?q?=EB=8A=94=20msw=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/mocks/fixtures/songEntries.json | 12 +++++++++++- frontend/src/mocks/handlers/songsHandlers.ts | 4 ++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/frontend/src/mocks/fixtures/songEntries.json b/frontend/src/mocks/fixtures/songEntries.json index 568dc6cce..0b8ad7b53 100644 --- a/frontend/src/mocks/fixtures/songEntries.json +++ b/frontend/src/mocks/fixtures/songEntries.json @@ -439,7 +439,17 @@ "partLength": 10, "likeStatus": false } - ] + ], + "myPart": { + "id": 70, + "rank": 1, + "likeCount": 0, + "start": 22, + "end": 32, + "partVideoUrl": "https://youtu.be/haCpjUXIhrI?start=30&end=40", + "partLength": 10, + "likeStatus": true + } }, "nextSongs": [ { diff --git a/frontend/src/mocks/handlers/songsHandlers.ts b/frontend/src/mocks/handlers/songsHandlers.ts index 882f13936..3bd8892c3 100644 --- a/frontend/src/mocks/handlers/songsHandlers.ts +++ b/frontend/src/mocks/handlers/songsHandlers.ts @@ -57,4 +57,8 @@ export const songsHandlers = [ rest.get(`${BASE_URL}/voting-songs`, (req, res, ctx) => { return res(ctx.status(200), ctx.json(votingSongs)); }), + + rest.delete(`${BASE_URL}/member-parts/:partId`, (req, res, ctx) => { + return res(ctx.status(204)); + }), ]; From 160dfae1969dfe0c013ed530208150c4273d2e3d Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Sun, 15 Oct 2023 19:16:44 +0900 Subject: [PATCH 07/38] =?UTF-8?q?feat:=20=EB=A7=88=EC=9D=B4=ED=8C=8C?= =?UTF-8?q?=ED=8A=B8=20=EC=82=AD=EC=A0=9C=EB=A5=BC=20=ED=99=95=EC=9D=B8?= =?UTF-8?q?=ED=95=98=EB=8A=94=20MyPartModal=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../features/songs/components/MyPartModal.tsx | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 frontend/src/features/songs/components/MyPartModal.tsx diff --git a/frontend/src/features/songs/components/MyPartModal.tsx b/frontend/src/features/songs/components/MyPartModal.tsx new file mode 100644 index 000000000..ae472ddc2 --- /dev/null +++ b/frontend/src/features/songs/components/MyPartModal.tsx @@ -0,0 +1,57 @@ +import styled from 'styled-components'; +import Modal from '@/shared/components/Modal/Modal'; +import Spacing from '@/shared/components/Spacing'; + +interface MyPartModalProps { + isOpen: boolean; + closeModal: () => void; + onDelete: () => void; +} + +const MyPartModal = ({ isOpen, closeModal, onDelete }: MyPartModalProps) => { + return ( + + 정말 삭제하시겠습니까? + + + + 취소 + + + 삭제 + + + + ); +}; + +const ModalTitle = styled.h3``; + +const Button = styled.button` + cursor: pointer; + + height: 36px; + + color: ${({ theme: { color } }) => color.white}; + + border: none; + border-radius: 10px; +`; + +const CancelButton = styled(Button)` + flex: 1; + background-color: ${({ theme: { color } }) => color.secondary}; +`; + +const DeleteButton = styled(Button)` + flex: 1; + background-color: ${({ theme: { color } }) => color.primary}; +`; + +const ButtonContainer = styled.div` + display: flex; + gap: 16px; + width: 100%; +`; + +export default MyPartModal; From 70c242c952e971d38ab0bc569278737173ae28e0 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Sun, 15 Oct 2023 19:17:59 +0900 Subject: [PATCH 08/38] =?UTF-8?q?feat:=20=EB=A7=88=EC=9D=B4=ED=8C=8C?= =?UTF-8?q?=ED=8A=B8=20=EB=93=B1=EB=A1=9D=EA=B3=BC=20=EC=A0=9C=EA=B1=B0=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/assets/icon/trash.svg | 59 ++++++++++++++ .../songs/components/KillingPartInterface.tsx | 4 +- .../songs/components/KillingPartTrack.tsx | 77 +++++++++++++----- .../songs/components/KillingPartTrackList.tsx | 79 +++++++++++++++---- .../songs/components/SongDetailItem.tsx | 4 +- frontend/src/shared/types/song.ts | 1 + 6 files changed, 188 insertions(+), 36 deletions(-) create mode 100644 frontend/src/assets/icon/trash.svg diff --git a/frontend/src/assets/icon/trash.svg b/frontend/src/assets/icon/trash.svg new file mode 100644 index 000000000..c7f4afe42 --- /dev/null +++ b/frontend/src/assets/icon/trash.svg @@ -0,0 +1,59 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/frontend/src/features/songs/components/KillingPartInterface.tsx b/frontend/src/features/songs/components/KillingPartInterface.tsx index b2aec0997..6db0598f4 100644 --- a/frontend/src/features/songs/components/KillingPartInterface.tsx +++ b/frontend/src/features/songs/components/KillingPartInterface.tsx @@ -11,12 +11,13 @@ import type { KillingPart, SongDetail } from '@/shared/types/song'; interface KillingPartInterfaceProps { killingParts: SongDetail['killingParts']; + myPart: SongDetail['myPart']; songId: number; } const DEFAULT_PART_ID = -1; -const KillingPartInterface = ({ killingParts, songId }: KillingPartInterfaceProps) => { +const KillingPartInterface = ({ killingParts, songId, myPart }: KillingPartInterfaceProps) => { const [nowPlayingTrack, setNowPlayingTrack] = useState(DEFAULT_PART_ID); const [commentsPartId, setCommentsPartId] = useState(DEFAULT_PART_ID); const [isRepeat, setIsRepeat] = useState(false); @@ -140,6 +141,7 @@ const KillingPartInterface = ({ killingParts, songId }: KillingPartInterfaceProp >; setCommentsPartId: React.Dispatch>; + isMyKillingPart?: boolean; } const KillingPartTrack = ({ @@ -32,6 +37,7 @@ const KillingPartTrack = ({ isNowPlayingTrack, setNowPlayingTrack, setCommentsPartId, + isMyKillingPart, }: KillingPartTrackProps) => { const { showToast } = useToastContext(); const { seekTo, pause, playerState } = useVideoPlayerContext(); @@ -42,7 +48,16 @@ const KillingPartTrack = ({ partId, }); const { countedTime: currentPlayTime } = useTimerContext(); - const { isOpen, closeModal, openModal } = useModal(); + const { + isOpen: isLoginModalOpen, + closeModal: closeLoginModal, + openModal: openLoginModal, + } = useModal(); + const { + isOpen: isMyPartModal, + closeModal: closeMyPartModal, + openModal: openMyPartModal, + } = useModal(); const { user } = useAuthContext(); const isLoggedIn = user !== null; @@ -111,6 +126,17 @@ const KillingPartTrack = ({ toggleKillingPartLikes(); }; + const { mutateData: deleteMemberPart } = useMutation(() => + fetcher(`/member-parts/${partId}`, 'DELETE') + ); + + const deleteMyPart = async () => { + await deleteMemberPart(); + + closeMyPartModal(); + showToast('내 파트가 삭제되었습니다.'); + }; + return ( - {ordinalRank} + {isMyKillingPart ? 'MY' : ordinalRank} {playingTime} - - - {`${calculatedLikeCount} Likes`} - - - - Share - + {isMyKillingPart ? ( + + + + ) : ( + <> + + + {`${calculatedLikeCount} Likes`} + + + + Share + + + )} {isNowPlayingTrack && ( ); @@ -220,6 +257,10 @@ const ButtonWithIcon = css` width: 44px; `; +const DeleteButton = styled.button` + ${ButtonWithIcon} +`; + const LikeButton = styled.button` ${ButtonWithIcon} `; diff --git a/frontend/src/features/songs/components/KillingPartTrackList.tsx b/frontend/src/features/songs/components/KillingPartTrackList.tsx index 0f59cbf71..d84354cfe 100644 --- a/frontend/src/features/songs/components/KillingPartTrackList.tsx +++ b/frontend/src/features/songs/components/KillingPartTrackList.tsx @@ -1,9 +1,15 @@ +import { useNavigate } from 'react-router-dom'; import { styled } from 'styled-components'; +import { useAuthContext } from '@/features/auth/components/AuthProvider'; +import LoginModal from '@/features/auth/components/LoginModal'; +import useModal from '@/shared/components/Modal/hooks/useModal'; +import ROUTE_PATH from '@/shared/constants/path'; import KillingPartTrack from './KillingPartTrack'; import type { KillingPart, SongDetail } from '@/shared/types/song'; interface KillingPartTrackListProps { killingParts: SongDetail['killingParts']; + myPart: SongDetail['myPart']; songId: number; nowPlayingTrack: KillingPart['id']; setNowPlayingTrack: React.Dispatch>; @@ -12,28 +18,55 @@ interface KillingPartTrackListProps { const KillingPartTrackList = ({ killingParts, + myPart, songId, nowPlayingTrack, setNowPlayingTrack, setCommentsPartId, }: KillingPartTrackListProps) => { + const hasMyPart = myPart !== undefined; + + const { user } = useAuthContext(); + const navigate = useNavigate(); + + const isLoggedIn = !!user; + const goToPartCollectingPage = () => navigate(`/${ROUTE_PATH.COLLECT}/${songId}`); + + const { isOpen, openModal, closeModal } = useModal(); + return ( - {killingParts.map((killingPart) => { - const { id } = killingPart; - const isNowPlayingTrack = id === nowPlayingTrack; - - return ( - - ); - })} + {killingParts.map((killingPart) => ( + + ))} + + {hasMyPart ? ( + + ) : ( + + + My Part + + )} + + ); }; @@ -45,3 +78,19 @@ export const TrackList = styled.div` flex-direction: column; gap: 10px; `; + +const PartRegisterButton = styled.button` + display: flex; + align-items: center; + justify-content: center; + + height: 60px; + padding: 0 12px; + + background-color: ${({ theme: { color } }) => color.secondary}; + border-radius: 4px; + + @media (max-width: ${({ theme }) => theme.breakPoints.xxs}) { + height: 46px; + } +`; diff --git a/frontend/src/features/songs/components/SongDetailItem.tsx b/frontend/src/features/songs/components/SongDetailItem.tsx index b69d40b14..1f9f693b4 100644 --- a/frontend/src/features/songs/components/SongDetailItem.tsx +++ b/frontend/src/features/songs/components/SongDetailItem.tsx @@ -17,7 +17,7 @@ import type { SongDetail } from '@/shared/types/song'; interface SongDetailItemProps extends SongDetail {} const SongDetailItem = forwardRef( - ({ id, killingParts, singer, title, songVideoId, albumCoverUrl }, ref) => { + ({ id, killingParts, singer, title, songVideoId, albumCoverUrl, myPart }, ref) => { const navigate = useNavigate(); const { genre } = useValidParams(); @@ -61,7 +61,7 @@ const SongDetailItem = forwardRef( - + diff --git a/frontend/src/shared/types/song.ts b/frontend/src/shared/types/song.ts index b5e080184..dddf660e5 100644 --- a/frontend/src/shared/types/song.ts +++ b/frontend/src/shared/types/song.ts @@ -12,6 +12,7 @@ export interface SongDetail { songVideoId: string; albumCoverUrl: string; killingParts: KillingPart[]; + myPart: KillingPart; } export interface KillingPart { From f4e6bcc1af224766abe421708275a76aa0ef61c8 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Sun, 15 Oct 2023 19:28:58 +0900 Subject: [PATCH 09/38] =?UTF-8?q?test:=20=EC=8A=A4=ED=86=A0=EB=A6=AC?= =?UTF-8?q?=EB=B6=81=EC=97=90=20myPart=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20?= =?UTF-8?q?TimerProvider=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 재생되지 않는 버그를 주석으로 남김 --- .../components/KillingPartTrack.stories.tsx | 1 + .../KillingPartTrackList.stories.tsx | 20 ++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/frontend/src/features/songs/components/KillingPartTrack.stories.tsx b/frontend/src/features/songs/components/KillingPartTrack.stories.tsx index 69f2ef8c5..dcb09e89d 100644 --- a/frontend/src/features/songs/components/KillingPartTrack.stories.tsx +++ b/frontend/src/features/songs/components/KillingPartTrack.stories.tsx @@ -6,6 +6,7 @@ import KillingPartTrack from './KillingPartTrack'; import type { KillingPart } from '@/shared/types/song'; import type { Meta, StoryObj } from '@storybook/react'; +// FIXME: 재생시 `YT is not defined` 에러 발생 const meta = { component: KillingPartTrack, title: 'KillingPartTrack', diff --git a/frontend/src/features/songs/components/KillingPartTrackList.stories.tsx b/frontend/src/features/songs/components/KillingPartTrackList.stories.tsx index e3fc9a9e5..c12f19561 100644 --- a/frontend/src/features/songs/components/KillingPartTrackList.stories.tsx +++ b/frontend/src/features/songs/components/KillingPartTrackList.stories.tsx @@ -1,10 +1,12 @@ import { useState } from 'react'; import { VideoPlayerProvider } from '@/features/youtube/components/VideoPlayerProvider'; +import TimerProvider from '@/shared/components/Timer/TimerProvider'; import ToastProvider from '@/shared/components/Toast/ToastProvider'; import KillingPartTrackList from './KillingPartTrackList'; import type { KillingPart } from '@/shared/types/song'; import type { Meta, StoryObj } from '@storybook/react'; +// FIXME: 재생시 `YT is not defined` 에러 발생 const meta = { component: KillingPartTrackList, title: 'KillingPartTrackList', @@ -13,7 +15,10 @@ const meta = { return ( - + {/* FIXME: time prop을 KillingPartTrack 스토리북 컴포넌트를 보고 임의로 똑같이 넣었습니다. */} + + + ); @@ -60,6 +65,18 @@ const killingPart3: KillingPart = { partLength: 10, }; +const myPart: KillingPart = { + id: 4, + rank: 3, + voteCount: 0, + start: 70, + end: 80, + partVideoUrl: 'https://youtu.be/ArmDp-zijuc?start=105&end=115', + likeCount: 12, + likeStatus: false, + partLength: 10, +}; + const KillingPartTrackListWithHooks = () => { const [nowPlayingTrack, setNowPlayingTrack] = useState(-1); // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -67,6 +84,7 @@ const KillingPartTrackListWithHooks = () => { return ( Date: Sun, 15 Oct 2023 19:29:40 +0900 Subject: [PATCH 10/38] =?UTF-8?q?style:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=BD=94=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../songs/components/CollectionCarousel.tsx | 22 +++++++++---------- .../src/features/songs/constants/genres.ts | 1 - 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/frontend/src/features/songs/components/CollectionCarousel.tsx b/frontend/src/features/songs/components/CollectionCarousel.tsx index 81c214f25..86e286ecc 100644 --- a/frontend/src/features/songs/components/CollectionCarousel.tsx +++ b/frontend/src/features/songs/components/CollectionCarousel.tsx @@ -31,18 +31,16 @@ const CollectionCarousel = ({ children }: CarouselProps) => { }, [currentIndex, numberOfItems]); return ( - <> - - - {children} - - - {Array.from({ length: numberOfItems }, (_, idx) => ( - - ))} - - - + + + {children} + + + {Array.from({ length: numberOfItems }, (_, idx) => ( + + ))} + + ); }; diff --git a/frontend/src/features/songs/constants/genres.ts b/frontend/src/features/songs/constants/genres.ts index 04b09b261..a885de3f5 100644 --- a/frontend/src/features/songs/constants/genres.ts +++ b/frontend/src/features/songs/constants/genres.ts @@ -15,6 +15,5 @@ const GENRES = { EDM: 'EDM', ETC: '기타', } as const; -` `; export default GENRES; From 78e77fb6746bfce551ebace805e477fbcee8e05c Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Sun, 15 Oct 2023 20:33:31 +0900 Subject: [PATCH 11/38] =?UTF-8?q?refactor:=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=EC=97=90=EC=84=9C=20=EA=B8=B0=EB=B3=B8=20?= =?UTF-8?q?=EC=9E=90=EA=B8=B0=EC=86=8C=EA=B0=9C=20=EB=B6=80=EB=B6=84=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20=ED=95=A8=EC=88=98=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/features/member/constants/introductions.ts | 10 ++++++++++ .../features/member/utils/getRandomIntroduction.ts | 7 +++++++ frontend/src/pages/MyPage.tsx | 11 ++--------- 3 files changed, 19 insertions(+), 9 deletions(-) create mode 100644 frontend/src/features/member/constants/introductions.ts create mode 100644 frontend/src/features/member/utils/getRandomIntroduction.ts diff --git a/frontend/src/features/member/constants/introductions.ts b/frontend/src/features/member/constants/introductions.ts new file mode 100644 index 000000000..149052ec5 --- /dev/null +++ b/frontend/src/features/member/constants/introductions.ts @@ -0,0 +1,10 @@ +export const introductions = [ + '아무 노래나 일단 틀어', + '또 물보라를 일으켜', + '난 내가 말야, 스무살쯤엔 요절할 천재일줄만 알고', + 'You make me feel special', + '우린 참 별나고 이상한 사이야', + '난 차라리 꽉 눌러붙을래, 날 재촉한다면', + 'So lovely day so lovely Errday with you so lovely', + 'Weight of the world on your shoulders', +]; diff --git a/frontend/src/features/member/utils/getRandomIntroduction.ts b/frontend/src/features/member/utils/getRandomIntroduction.ts new file mode 100644 index 000000000..4994465d3 --- /dev/null +++ b/frontend/src/features/member/utils/getRandomIntroduction.ts @@ -0,0 +1,7 @@ +import { introductions } from '../constants/introductions'; + +const getRandomIntroduction = (index = Math.floor(Math.random() * introductions.length)) => { + return introductions[index]; +}; + +export default getRandomIntroduction; diff --git a/frontend/src/pages/MyPage.tsx b/frontend/src/pages/MyPage.tsx index 05154bdfd..772947eed 100644 --- a/frontend/src/pages/MyPage.tsx +++ b/frontend/src/pages/MyPage.tsx @@ -3,6 +3,7 @@ import { styled } from 'styled-components'; import shookshook from '@/assets/icon/shookshook.svg'; import { useAuthContext } from '@/features/auth/components/AuthProvider'; import MyPartList from '@/features/member/components/MyPartList'; +import getRandomIntroduction from '@/features/member/utils/getRandomIntroduction'; import Flex from '@/shared/components/Flex'; import Spacing from '@/shared/components/Spacing'; import SRHeading from '@/shared/components/SRHeading'; @@ -10,14 +11,6 @@ import { GA_ACTIONS, GA_CATEGORIES } from '@/shared/constants/GAEventName'; import ROUTE_PATH from '@/shared/constants/path'; import sendGAEvent from '@/shared/googleAnalytics/sendGAEvent'; -const introductions = [ - '아무 노래나 일단 틀어', - '또 물보라를 일으켜', - '난 내가 말야, 스무살쯤엔 요절할 천재일줄만 알고', - 'You make me feel special', - '우린 참 별나고 이상한 사이야', -]; - const MyPage = () => { const { user, logout } = useAuthContext(); const navigate = useNavigate(); @@ -50,7 +43,7 @@ const MyPage = () => { {user?.nickname} - {introductions[Math.floor(Math.random() * introductions.length)]} + {getRandomIntroduction()} From 6a19f5dafa6302eeb15b9b11cf8deefe8067a566 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Sun, 15 Oct 2023 20:36:17 +0900 Subject: [PATCH 12/38] =?UTF-8?q?design:=20=EC=9E=90=EA=B8=B0=EC=86=8C?= =?UTF-8?q?=EA=B0=9C=EA=B0=80=203=EC=A4=84=20=EC=A0=95=EB=8F=84=EB=A7=8C?= =?UTF-8?q?=20=EB=B3=B4=EC=9D=B4=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 모바일 기준 대략(72자) --- frontend/src/pages/MyPage.tsx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/MyPage.tsx b/frontend/src/pages/MyPage.tsx index 772947eed..abb4c427e 100644 --- a/frontend/src/pages/MyPage.tsx +++ b/frontend/src/pages/MyPage.tsx @@ -43,7 +43,7 @@ const MyPage = () => { {user?.nickname} - {getRandomIntroduction()} + {getRandomIntroduction()} @@ -93,6 +93,17 @@ const Title = styled.h2` color: white; `; +const Introduction = styled(Box)` + overflow: hidden; + display: -webkit-box; + + text-overflow: ellipsis; + word-break: break-word; + + -webkit-box-orient: vertical; + -webkit-line-clamp: 3; +`; + const SpaceBetween = styled(Flex)` justify-content: space-between; `; From 9a2b2e7d8e72ca3ff55c0d1a134f7684730f8332 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Sun, 15 Oct 2023 20:42:21 +0900 Subject: [PATCH 13/38] =?UTF-8?q?refactor:=20=EC=A2=8B=EC=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=ED=8C=8C=ED=8A=B8=EC=99=80=20=EB=A7=88=EC=9D=B4?= =?UTF-8?q?=ED=8C=8C=ED=8A=B8=EB=A5=BC=20=EA=B0=80=EC=A0=B8=EC=98=A4?= =?UTF-8?q?=EB=8A=94=20fetch=20=EB=A1=9C=EC=A7=81=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/features/member/components/MyPartList.tsx | 8 +++----- frontend/src/features/member/remotes/myPage.ts | 5 +++++ 2 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 frontend/src/features/member/remotes/myPage.ts diff --git a/frontend/src/features/member/components/MyPartList.tsx b/frontend/src/features/member/components/MyPartList.tsx index f8d59fdfe..5631f6777 100644 --- a/frontend/src/features/member/components/MyPartList.tsx +++ b/frontend/src/features/member/components/MyPartList.tsx @@ -2,7 +2,7 @@ import { useState } from 'react'; import styled from 'styled-components'; import Spacing from '@/shared/components/Spacing'; import useFetch from '@/shared/hooks/useFetch'; -import fetcher from '@/shared/remotes'; +import { getLikeParts, getMyParts } from '../remotes/myPage'; import PartList from './PartList'; import type { KillingPart, SongDetail } from '@/shared/types/song'; @@ -15,10 +15,8 @@ export type LikeKillingPart = Pick { const [tab, setTab] = useState<'Like' | 'MyKillingPart'>('Like'); - const { data: likes } = useFetch(() => fetcher('/my-page/like-parts', 'get')); - const { data: myParts } = useFetch(() => - fetcher('/my-page/member-parts', 'get') - ); + const { data: likes } = useFetch(getLikeParts); + const { data: myParts } = useFetch(getMyParts); if (!likes || !myParts) return null; diff --git a/frontend/src/features/member/remotes/myPage.ts b/frontend/src/features/member/remotes/myPage.ts new file mode 100644 index 000000000..e1d4154c5 --- /dev/null +++ b/frontend/src/features/member/remotes/myPage.ts @@ -0,0 +1,5 @@ +import fetcher from '@/shared/remotes'; + +export const getLikeParts = () => fetcher('/my-page/like-parts', 'get'); + +export const getMyParts = () => fetcher('/my-page/member-parts', 'get'); From 7445fe03984036644a8bebac4c95155b7d239543 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Sun, 15 Oct 2023 20:46:46 +0900 Subject: [PATCH 14/38] =?UTF-8?q?refactor:=20=EB=A7=88=EC=9D=B4=ED=8C=8C?= =?UTF-8?q?=ED=8A=B8=20=EC=A0=9C=EA=B1=B0=20fetch=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/features/member/remotes/memberParts.ts | 3 +++ frontend/src/features/songs/components/KillingPartTrack.tsx | 6 ++---- 2 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 frontend/src/features/member/remotes/memberParts.ts diff --git a/frontend/src/features/member/remotes/memberParts.ts b/frontend/src/features/member/remotes/memberParts.ts new file mode 100644 index 000000000..28ef36132 --- /dev/null +++ b/frontend/src/features/member/remotes/memberParts.ts @@ -0,0 +1,3 @@ +import fetcher from '@/shared/remotes'; + +export const deleteMemberParts = (partId: number) => fetcher(`/member-parts/${partId}`, 'DELETE'); diff --git a/frontend/src/features/songs/components/KillingPartTrack.tsx b/frontend/src/features/songs/components/KillingPartTrack.tsx index 5fa409f1b..926424b22 100644 --- a/frontend/src/features/songs/components/KillingPartTrack.tsx +++ b/frontend/src/features/songs/components/KillingPartTrack.tsx @@ -6,6 +6,7 @@ import shareIcon from '@/assets/icon/share.svg'; import trashIcon from '@/assets/icon/trash.svg'; import { useAuthContext } from '@/features/auth/components/AuthProvider'; import LoginModal from '@/features/auth/components/LoginModal'; +import { deleteMemberParts } from '@/features/member/remotes/memberParts'; import useVideoPlayerContext from '@/features/youtube/hooks/useVideoPlayerContext'; import useModal from '@/shared/components/Modal/hooks/useModal'; import useTimerContext from '@/shared/components/Timer/hooks/useTimerContext'; @@ -13,7 +14,6 @@ import useToastContext from '@/shared/components/Toast/hooks/useToastContext'; import { GA_ACTIONS, GA_CATEGORIES } from '@/shared/constants/GAEventName'; import sendGAEvent from '@/shared/googleAnalytics/sendGAEvent'; import { useMutation } from '@/shared/hooks/useMutation'; -import fetcher from '@/shared/remotes'; import { toPlayingTimeText } from '@/shared/utils/convertTime'; import copyClipboard from '@/shared/utils/copyClipBoard'; import formatOrdinals from '@/shared/utils/formatOrdinals'; @@ -126,9 +126,7 @@ const KillingPartTrack = ({ toggleKillingPartLikes(); }; - const { mutateData: deleteMemberPart } = useMutation(() => - fetcher(`/member-parts/${partId}`, 'DELETE') - ); + const { mutateData: deleteMemberPart } = useMutation(() => deleteMemberParts(partId)); const deleteMyPart = async () => { await deleteMemberPart(); From dea67f752c343072f90e29971ce6bb9af50955d7 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Tue, 17 Oct 2023 20:17:16 +0900 Subject: [PATCH 15/38] =?UTF-8?q?design:=20=EC=A2=8B=EC=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=ED=82=AC=EB=A7=81=ED=8C=8C=ED=8A=B8=EC=99=80=20?= =?UTF-8?q?=EB=82=98=EC=9D=98=20=ED=82=AC=EB=A7=81=ED=8C=8C=ED=8A=B8?= =?UTF-8?q?=EB=A5=BC=20=ED=8F=AC=ED=95=A8=ED=95=98=EB=8A=94=20=ED=83=AD?= =?UTF-8?q?=EC=9D=98=20=EC=83=89=EC=83=81=EC=9D=84=20=EB=8D=94=20=EC=A7=84?= =?UTF-8?q?=ED=95=98=EA=B2=8C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/features/member/components/MyPartList.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/features/member/components/MyPartList.tsx b/frontend/src/features/member/components/MyPartList.tsx index 5631f6777..ffb2999a5 100644 --- a/frontend/src/features/member/components/MyPartList.tsx +++ b/frontend/src/features/member/components/MyPartList.tsx @@ -70,7 +70,8 @@ const TabItem = styled.li<{ $isActive?: boolean }>` width: 100%; padding: 15px 20px; - color: ${({ $isActive, theme: { color } }) => ($isActive ? color.white : color.disabled)}; + color: ${({ $isActive, theme: { color } }) => + $isActive ? color.white : color.disabledBackground}; text-align: center; border-bottom: 2px solid From 7933937a1052538aaad8a63ff85c25939bb07170 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Tue, 17 Oct 2023 20:19:10 +0900 Subject: [PATCH 16/38] =?UTF-8?q?refactor:=20PartItem=EC=9D=98=20props?= =?UTF-8?q?=EB=A5=BC=20=EC=8A=A4=ED=94=84=EB=A0=88=EB=93=9C=EB=A1=9C=20?= =?UTF-8?q?=EA=B0=84=EB=8B=A8=ED=95=98=EA=B2=8C=20=ED=91=9C=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/features/member/components/PartList.tsx | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/frontend/src/features/member/components/PartList.tsx b/frontend/src/features/member/components/PartList.tsx index 94511821a..9e470cd96 100644 --- a/frontend/src/features/member/components/PartList.tsx +++ b/frontend/src/features/member/components/PartList.tsx @@ -18,19 +18,10 @@ const PartList = ({ parts }: PartListProps) => { return ( - {parts.map(({ songId, title, singer, albumCoverUrl, partId, start, end }, i) => { + {parts.map((part, i) => { return ( -
  • - +
  • +
  • ); })} From 28956d815a4aab148be73bef516e2ee476d2a2b7 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Tue, 17 Oct 2023 20:40:28 +0900 Subject: [PATCH 17/38] =?UTF-8?q?refactor:=20PartItem=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=83=81=EC=88=98=20=EC=82=AC=EC=9A=A9=20=EB=B0=8F=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/features/member/components/PartItem.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/frontend/src/features/member/components/PartItem.tsx b/frontend/src/features/member/components/PartItem.tsx index a17a62133..35976046b 100644 --- a/frontend/src/features/member/components/PartItem.tsx +++ b/frontend/src/features/member/components/PartItem.tsx @@ -4,14 +4,18 @@ import link from '@/assets/icon/link.svg'; import shook from '@/assets/icon/shook.svg'; import { useAuthContext } from '@/features/auth/components/AuthProvider'; import Thumbnail from '@/features/songs/components/Thumbnail'; +import GENRES from '@/features/songs/constants/genres'; import Spacing from '@/shared/components/Spacing'; import useToastContext from '@/shared/components/Toast/hooks/useToastContext'; import { GA_ACTIONS, GA_CATEGORIES } from '@/shared/constants/GAEventName'; +import ROUTE_PATH from '@/shared/constants/path'; import sendGAEvent from '@/shared/googleAnalytics/sendGAEvent'; import { secondsToMinSec, toPlayingTimeText } from '@/shared/utils/convertTime'; import copyClipboard from '@/shared/utils/copyClipBoard'; import type { LikeKillingPart } from './MyPartList'; +const { BASE_URL } = process.env; + type PartItemProps = LikeKillingPart & { rank: number; }; @@ -29,12 +33,14 @@ const PartItem = ({ songId, albumCoverUrl, title, singer, start, end }: PartItem memberId: user?.memberId, }); - copyClipboard(`${process.env.BASE_URL?.replace('/api', '')}/songs/${songId}/ALL`); + copyClipboard( + `${BASE_URL?.replace('/api', '')}/${ROUTE_PATH.SONG_DETAILS}${songId}/${GENRES.ALL}` + ); showToast('클립보드에 영상링크가 복사되었습니다.'); }; const goToListenSong = () => { - navigate(`/songs/${songId}/ALL`); + navigate(`/${ROUTE_PATH.SONG_DETAILS}${songId}/${GENRES.ALL}`); }; const { minute: startMin, second: startSec } = secondsToMinSec(start); From 726937bcc797ced66bd266431595a900b7dd930f Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Tue, 17 Oct 2023 20:47:32 +0900 Subject: [PATCH 18/38] =?UTF-8?q?fix:=20fetch=EC=9D=98=20method=EB=A5=BC?= =?UTF-8?q?=20=EB=8C=80=EB=AC=B8=EC=9E=90=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/features/member/remotes/myPage.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/features/member/remotes/myPage.ts b/frontend/src/features/member/remotes/myPage.ts index e1d4154c5..351002a87 100644 --- a/frontend/src/features/member/remotes/myPage.ts +++ b/frontend/src/features/member/remotes/myPage.ts @@ -1,5 +1,5 @@ import fetcher from '@/shared/remotes'; -export const getLikeParts = () => fetcher('/my-page/like-parts', 'get'); +export const getLikeParts = () => fetcher('/my-page/like-parts', 'GET'); -export const getMyParts = () => fetcher('/my-page/member-parts', 'get'); +export const getMyParts = () => fetcher('/my-page/member-parts', 'GET'); From 0534145b929a788194ec08477c1e7e10580349c7 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Tue, 17 Oct 2023 21:39:56 +0900 Subject: [PATCH 19/38] =?UTF-8?q?design:=20PartList=EC=9D=98=20scrollTop?= =?UTF-8?q?=EC=9D=84=20=EC=9D=BC=EC=A0=95=ED=95=98=EA=B2=8C=20=EC=9C=A0?= =?UTF-8?q?=EC=A7=80=EC=8B=9C=ED=82=A4=EA=B8=B0=20=EC=9C=84=ED=95=9C=20?= =?UTF-8?q?=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../features/member/components/PartList.tsx | 2 +- frontend/src/pages/MyPage.tsx | 27 ++++++++++--------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/frontend/src/features/member/components/PartList.tsx b/frontend/src/features/member/components/PartList.tsx index 9e470cd96..f2fd08b7b 100644 --- a/frontend/src/features/member/components/PartList.tsx +++ b/frontend/src/features/member/components/PartList.tsx @@ -7,7 +7,7 @@ interface PartListProps { parts: LikeKillingPart[]; } -const PART_LIST_SCROLL_TOP = 148; +const PART_LIST_SCROLL_TOP = 180; const PartList = ({ parts }: PartListProps) => { useEffect(() => { diff --git a/frontend/src/pages/MyPage.tsx b/frontend/src/pages/MyPage.tsx index abb4c427e..45ab0a03b 100644 --- a/frontend/src/pages/MyPage.tsx +++ b/frontend/src/pages/MyPage.tsx @@ -4,7 +4,7 @@ import shookshook from '@/assets/icon/shookshook.svg'; import { useAuthContext } from '@/features/auth/components/AuthProvider'; import MyPartList from '@/features/member/components/MyPartList'; import getRandomIntroduction from '@/features/member/utils/getRandomIntroduction'; -import Flex from '@/shared/components/Flex'; +import Flex from '@/shared/components/Flex/Flex'; import Spacing from '@/shared/components/Spacing'; import SRHeading from '@/shared/components/SRHeading'; import { GA_ACTIONS, GA_CATEGORIES } from '@/shared/constants/GAEventName'; @@ -39,21 +39,24 @@ const MyPage = () => { 마이 페이지 - + - {user?.nickname} + {user?.nickname ?? 'shook'} {getRandomIntroduction()} - - + + + + + - + - + - + @@ -86,6 +89,10 @@ const Box = styled.div` width: 100%; `; +const ProfileFlex = styled(Flex)` + height: 108px; +`; + const Title = styled.h2` align-self: flex-start; font-size: 20px; @@ -104,10 +111,6 @@ const Introduction = styled(Box)` -webkit-line-clamp: 3; `; -const SpaceBetween = styled(Flex)` - justify-content: space-between; -`; - const Avatar = styled.img` width: 60px; height: 60px; From 2538e6db80145870672595e62442a012c3519a52 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Tue, 17 Oct 2023 21:51:00 +0900 Subject: [PATCH 20/38] =?UTF-8?q?refactor:=20PartList=EC=9D=98=20li=20?= =?UTF-8?q?=ED=83=9C=EA=B7=B8=EB=A5=BC=20PartItem=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 스타일드 컴포넌트 이름 변경 - 스타일 및 태그 수정 --- .../features/member/components/PartItem.tsx | 11 ++++++-- .../features/member/components/PartList.tsx | 26 +++++-------------- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/frontend/src/features/member/components/PartItem.tsx b/frontend/src/features/member/components/PartItem.tsx index 35976046b..fd7613908 100644 --- a/frontend/src/features/member/components/PartItem.tsx +++ b/frontend/src/features/member/components/PartItem.tsx @@ -69,7 +69,9 @@ const PartItem = ({ songId, albumCoverUrl, title, singer, start, end }: PartItem ); }; -const Grid = styled.button` +const Grid = styled.li` + cursor: pointer; + display: grid; grid-template: 'thumbnail title _' 26px @@ -79,10 +81,15 @@ const Grid = styled.button` column-gap: 8px; width: 100%; - padding: 6px 0; + padding: 6px 10px; color: ${({ theme: { color } }) => color.white}; text-align: start; + + &:hover, + &:focus { + background-color: ${({ theme }) => theme.color.secondary}; + } `; const SongTitle = styled.div` diff --git a/frontend/src/features/member/components/PartList.tsx b/frontend/src/features/member/components/PartList.tsx index f2fd08b7b..64311eb89 100644 --- a/frontend/src/features/member/components/PartList.tsx +++ b/frontend/src/features/member/components/PartList.tsx @@ -17,21 +17,17 @@ const PartList = ({ parts }: PartListProps) => { }, [parts]); return ( - - {parts.map((part, i) => { - return ( -
  • - -
  • - ); - })} -
    + + {parts.map((part, i) => ( + + ))} + ); }; export default PartList; -const PopularSongList = styled.ol` +const PartListContainer = styled.ol` display: flex; flex-direction: column; gap: 12px; @@ -39,13 +35,3 @@ const PopularSongList = styled.ol` width: 100%; `; - -const Li = styled.li` - width: 100%; - padding: 0 10px; - - &:hover, - &:focus { - background-color: ${({ theme }) => theme.color.secondary}; - } -`; From dabb0e2768429e4946b7a75d2ba1fd72948d58b0 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Tue, 17 Oct 2023 21:56:27 +0900 Subject: [PATCH 21/38] =?UTF-8?q?refactor:=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=EC=9D=98=20=ED=83=AD=20=ED=83=80=EC=9E=85=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/features/member/components/MyPartList.tsx | 5 +++-- frontend/src/features/member/types/myPage.ts | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 frontend/src/features/member/types/myPage.ts diff --git a/frontend/src/features/member/components/MyPartList.tsx b/frontend/src/features/member/components/MyPartList.tsx index ffb2999a5..bda198621 100644 --- a/frontend/src/features/member/components/MyPartList.tsx +++ b/frontend/src/features/member/components/MyPartList.tsx @@ -4,6 +4,7 @@ import Spacing from '@/shared/components/Spacing'; import useFetch from '@/shared/hooks/useFetch'; import { getLikeParts, getMyParts } from '../remotes/myPage'; import PartList from './PartList'; +import type { MyPageTab } from '../types/myPage'; import type { KillingPart, SongDetail } from '@/shared/types/song'; export type LikeKillingPart = Pick & @@ -13,14 +14,14 @@ export type LikeKillingPart = Pick { - const [tab, setTab] = useState<'Like' | 'MyKillingPart'>('Like'); + const [tab, setTab] = useState('Like'); const { data: likes } = useFetch(getLikeParts); const { data: myParts } = useFetch(getMyParts); if (!likes || !myParts) return null; - const partList: { tab: 'Like' | 'MyKillingPart'; parts: LikeKillingPart[] }[] = [ + const partList: { tab: MyPageTab; parts: LikeKillingPart[] }[] = [ { tab: 'Like', parts: likes }, { tab: 'MyKillingPart', parts: myParts }, ]; diff --git a/frontend/src/features/member/types/myPage.ts b/frontend/src/features/member/types/myPage.ts new file mode 100644 index 000000000..f82ab8ee5 --- /dev/null +++ b/frontend/src/features/member/types/myPage.ts @@ -0,0 +1 @@ +export type MyPageTab = 'Like' | 'MyKillingPart'; From 1eb6d7807fbfe17e01006615ed0fdcd5aa6e5cde Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Tue, 17 Oct 2023 22:17:52 +0900 Subject: [PATCH 22/38] =?UTF-8?q?style:=20=ED=95=A8=EC=88=98=EB=AA=85=20?= =?UTF-8?q?=EB=B0=8F=20=EC=8A=A4=ED=83=80=EC=9D=BC=EB=93=9C=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/features/member/components/PartItem.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/features/member/components/PartItem.tsx b/frontend/src/features/member/components/PartItem.tsx index fd7613908..57ae517c6 100644 --- a/frontend/src/features/member/components/PartItem.tsx +++ b/frontend/src/features/member/components/PartItem.tsx @@ -39,7 +39,7 @@ const PartItem = ({ songId, albumCoverUrl, title, singer, start, end }: PartItem showToast('클립보드에 영상링크가 복사되었습니다.'); }; - const goToListenSong = () => { + const goToSongDetailListPage = () => { navigate(`/${ROUTE_PATH.SONG_DETAILS}${songId}/${GENRES.ALL}`); }; @@ -47,7 +47,7 @@ const PartItem = ({ songId, albumCoverUrl, title, singer, start, end }: PartItem const { minute: endMin, second: endSec } = secondsToMinSec(end); return ( - + {title} {singer} @@ -65,11 +65,11 @@ const PartItem = ({ songId, albumCoverUrl, title, singer, start, end }: PartItem - + ); }; -const Grid = styled.li` +const PartItemGrid = styled.li` cursor: pointer; display: grid; From 4be4363882906204d1feb95eb9ba6163ce2dffc4 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Tue, 17 Oct 2023 22:18:22 +0900 Subject: [PATCH 23/38] =?UTF-8?q?design:=20font-weight=20700=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/features/member/components/PartItem.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/features/member/components/PartItem.tsx b/frontend/src/features/member/components/PartItem.tsx index 57ae517c6..171e42c52 100644 --- a/frontend/src/features/member/components/PartItem.tsx +++ b/frontend/src/features/member/components/PartItem.tsx @@ -97,7 +97,7 @@ const SongTitle = styled.div` grid-area: title; font-size: 16px; - font-weight: 800; + font-weight: 700; text-overflow: ellipsis; white-space: nowrap; `; From bc88c8b61993bc3688059383aa382bffcae8b270 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Tue, 17 Oct 2023 22:22:14 +0900 Subject: [PATCH 24/38] =?UTF-8?q?refactor:=20=EC=83=81=EC=88=98=20const=20?= =?UTF-8?q?assertion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/features/member/constants/introductions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/features/member/constants/introductions.ts b/frontend/src/features/member/constants/introductions.ts index 149052ec5..854ec3376 100644 --- a/frontend/src/features/member/constants/introductions.ts +++ b/frontend/src/features/member/constants/introductions.ts @@ -7,4 +7,4 @@ export const introductions = [ '난 차라리 꽉 눌러붙을래, 날 재촉한다면', 'So lovely day so lovely Errday with you so lovely', 'Weight of the world on your shoulders', -]; +] as const; From f9b85f100f74a0b9da0ba062c79e3b443039edce Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Tue, 17 Oct 2023 22:29:48 +0900 Subject: [PATCH 25/38] =?UTF-8?q?refactor:=20PartItem=EC=97=90=20rank=20pr?= =?UTF-8?q?op=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/features/member/components/PartItem.tsx | 4 +--- frontend/src/features/member/components/PartList.tsx | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/frontend/src/features/member/components/PartItem.tsx b/frontend/src/features/member/components/PartItem.tsx index 171e42c52..28aafb0fc 100644 --- a/frontend/src/features/member/components/PartItem.tsx +++ b/frontend/src/features/member/components/PartItem.tsx @@ -16,9 +16,7 @@ import type { LikeKillingPart } from './MyPartList'; const { BASE_URL } = process.env; -type PartItemProps = LikeKillingPart & { - rank: number; -}; +type PartItemProps = LikeKillingPart; const PartItem = ({ songId, albumCoverUrl, title, singer, start, end }: PartItemProps) => { const { showToast } = useToastContext(); diff --git a/frontend/src/features/member/components/PartList.tsx b/frontend/src/features/member/components/PartList.tsx index 64311eb89..2be95a59b 100644 --- a/frontend/src/features/member/components/PartList.tsx +++ b/frontend/src/features/member/components/PartList.tsx @@ -18,8 +18,8 @@ const PartList = ({ parts }: PartListProps) => { return ( - {parts.map((part, i) => ( - + {parts.map((part) => ( + ))} ); From c907719c6695625f59d8f5750a56cb88223c1e6a Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Tue, 17 Oct 2023 22:40:10 +0900 Subject: [PATCH 26/38] =?UTF-8?q?refactor:=20=ED=83=AD=EA=B3=BC=20?= =?UTF-8?q?=EB=B3=B4=EC=97=AC=EC=A4=84=20=EC=BB=A8=ED=85=90=EC=B8=A0?= =?UTF-8?q?=EB=A5=BC=20=EB=8F=99=EC=A0=81=EC=9C=BC=EB=A1=9C=20=EB=8A=98?= =?UTF-8?q?=EB=A6=B4=20=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../features/member/components/MyPartList.tsx | 33 +++++++++++-------- .../features/member/components/PartList.tsx | 9 +++-- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/frontend/src/features/member/components/MyPartList.tsx b/frontend/src/features/member/components/MyPartList.tsx index bda198621..2a0a8c143 100644 --- a/frontend/src/features/member/components/MyPartList.tsx +++ b/frontend/src/features/member/components/MyPartList.tsx @@ -19,29 +19,34 @@ const MyPartList = () => { const { data: likes } = useFetch(getLikeParts); const { data: myParts } = useFetch(getMyParts); - if (!likes || !myParts) return null; + if (!likes || !myParts) { + return null; + } - const partList: { tab: MyPageTab; parts: LikeKillingPart[] }[] = [ - { tab: 'Like', parts: likes }, - { tab: 'MyKillingPart', parts: myParts }, + const partTabItems: { tab: MyPageTab; title: string; parts: LikeKillingPart[] }[] = [ + { tab: 'Like', title: '좋아요 한 킬링파트', parts: likes }, + { tab: 'MyKillingPart', title: '내 킬링파트', parts: myParts }, ]; - const [selectedParts] = partList.filter((p) => p.tab === tab); - return ( <> - - setTab('Like')}> - 좋아요 한 킬링파트 - - setTab('MyKillingPart')}> - 내 킬링파트 - + + {partTabItems.map((option) => ( + setTab(option.tab)} + > + {option.title} + + ))} - + {partTabItems.map((option) => ( + + ))} ); }; diff --git a/frontend/src/features/member/components/PartList.tsx b/frontend/src/features/member/components/PartList.tsx index 2be95a59b..498ffbb07 100644 --- a/frontend/src/features/member/components/PartList.tsx +++ b/frontend/src/features/member/components/PartList.tsx @@ -5,16 +5,21 @@ import type { LikeKillingPart } from './MyPartList'; interface PartListProps { parts: LikeKillingPart[]; + isShow: boolean; } const PART_LIST_SCROLL_TOP = 180; -const PartList = ({ parts }: PartListProps) => { +const PartList = ({ parts, isShow }: PartListProps) => { useEffect(() => { if (window.scrollY > PART_LIST_SCROLL_TOP) { window.scrollTo({ top: PART_LIST_SCROLL_TOP, behavior: 'smooth' }); } - }, [parts]); + }, [isShow]); + + if (!isShow) { + return null; + } return ( From 59c967d6f00fca635f32ec6e66d3384a51734cfc Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Tue, 17 Oct 2023 22:54:17 +0900 Subject: [PATCH 27/38] =?UTF-8?q?feat:=20=ED=82=AC=EB=A7=81=ED=8C=8C?= =?UTF-8?q?=ED=8A=B8=20=ED=8A=B8=EB=9E=99=EA=B3=BC=20=EB=A7=88=EC=9D=B4?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=EC=97=90=EC=84=9C=20=ED=83=AD?= =?UTF-8?q?=EC=9D=98=20=EC=A0=91=EA=B7=BC=EC=84=B1=20=ED=96=A5=EC=83=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/features/member/components/MyPartList.tsx | 10 ++++++++++ .../src/features/songs/components/KillingPartTrack.tsx | 6 +++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/frontend/src/features/member/components/MyPartList.tsx b/frontend/src/features/member/components/MyPartList.tsx index 2a0a8c143..8ca35f592 100644 --- a/frontend/src/features/member/components/MyPartList.tsx +++ b/frontend/src/features/member/components/MyPartList.tsx @@ -28,14 +28,24 @@ const MyPartList = () => { { tab: 'MyKillingPart', title: '내 킬링파트', parts: myParts }, ]; + const pressEnterChangeTab = (tab: MyPageTab) => (event: React.KeyboardEvent) => { + if (event.key === 'Enter') { + setTab(tab); + } + }; + return ( <> {partTabItems.map((option) => ( setTab(option.tab)} + onKeyDown={pressEnterChangeTab(option.tab)} + tabIndex={0} > {option.title} diff --git a/frontend/src/features/songs/components/KillingPartTrack.tsx b/frontend/src/features/songs/components/KillingPartTrack.tsx index 926424b22..1798de881 100644 --- a/frontend/src/features/songs/components/KillingPartTrack.tsx +++ b/frontend/src/features/songs/components/KillingPartTrack.tsx @@ -141,7 +141,7 @@ const KillingPartTrack = ({ htmlFor={`play-${songId}-${partId}`} tabIndex={0} role="radio" - aria-label={`${rank}등 킬링파트 재생하기`} + aria-label={isMyKillingPart ? '나의 킬링파트 재생하기' : `${rank}등 킬링파트 재생하기`} > {isMyKillingPart ? 'MY' : ordinalRank} @@ -158,8 +158,8 @@ const KillingPartTrack = ({ {isMyKillingPart ? ( - - + + ) : ( <> From 12208bc385cb48636455d7a02e46aadb55198d06 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Wed, 18 Oct 2023 09:06:22 +0900 Subject: [PATCH 28/38] =?UTF-8?q?fix:=20=ED=82=AC=EB=A7=81=ED=8C=8C?= =?UTF-8?q?=ED=8A=B8=20id=EC=99=80=20=EB=A7=88=EC=9D=B4=ED=8C=8C=ED=8A=B8?= =?UTF-8?q?=20id=EA=B0=80=20=EA=B2=B9=EC=B3=90=20=EC=9E=AC=EC=83=9D?= =?UTF-8?q?=ED=95=A0=20=EC=88=98=20=EC=97=86=EB=8A=94=20=ED=98=84=EC=83=81?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../songs/components/KillingPartInterface.tsx | 2 +- .../components/KillingPartTrack.stories.tsx | 1 + .../songs/components/KillingPartTrack.tsx | 23 +++++++++++++++---- .../songs/components/KillingPartTrackList.tsx | 18 ++++++++++----- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/frontend/src/features/songs/components/KillingPartInterface.tsx b/frontend/src/features/songs/components/KillingPartInterface.tsx index 6db0598f4..26194ad2f 100644 --- a/frontend/src/features/songs/components/KillingPartInterface.tsx +++ b/frontend/src/features/songs/components/KillingPartInterface.tsx @@ -18,7 +18,7 @@ interface KillingPartInterfaceProps { const DEFAULT_PART_ID = -1; const KillingPartInterface = ({ killingParts, songId, myPart }: KillingPartInterfaceProps) => { - const [nowPlayingTrack, setNowPlayingTrack] = useState(DEFAULT_PART_ID); + const [nowPlayingTrack, setNowPlayingTrack] = useState(DEFAULT_PART_ID); const [commentsPartId, setCommentsPartId] = useState(DEFAULT_PART_ID); const [isRepeat, setIsRepeat] = useState(false); const { videoPlayer, playerState, seekTo, pause } = useVideoPlayerContext(); diff --git a/frontend/src/features/songs/components/KillingPartTrack.stories.tsx b/frontend/src/features/songs/components/KillingPartTrack.stories.tsx index dcb09e89d..625d62858 100644 --- a/frontend/src/features/songs/components/KillingPartTrack.stories.tsx +++ b/frontend/src/features/songs/components/KillingPartTrack.stories.tsx @@ -50,6 +50,7 @@ const KillingPartTrackWithHook = () => { return ( >; + setNowPlayingTrack: React.Dispatch>; setCommentsPartId: React.Dispatch>; isMyKillingPart?: boolean; + hideMyPart?: () => void; } const KillingPartTrack = ({ + order, killingPart: { id: partId, rank, start, end, likeCount, likeStatus }, songId, isNowPlayingTrack, setNowPlayingTrack, setCommentsPartId, isMyKillingPart, + hideMyPart, }: KillingPartTrackProps) => { const { showToast } = useToastContext(); const { seekTo, pause, playerState } = useVideoPlayerContext(); @@ -93,8 +97,13 @@ const KillingPartTrack = ({ const playTrack = () => { seekTo(start); - setNowPlayingTrack(partId); - setCommentsPartId(partId); + setNowPlayingTrack(order); + + if (order !== 4) { + setCommentsPartId(partId); + } else { + setCommentsPartId(-1); + } }; const stopTrack = () => { @@ -129,8 +138,12 @@ const KillingPartTrack = ({ const { mutateData: deleteMemberPart } = useMutation(() => deleteMemberParts(partId)); const deleteMyPart = async () => { + if (!hideMyPart) return; + await deleteMemberPart(); + hideMyPart(); + pause(); closeMyPartModal(); showToast('내 파트가 삭제되었습니다.'); }; @@ -138,7 +151,7 @@ const KillingPartTrack = ({ return ( {isMyKillingPart ? 'MY' : ordinalRank} >; + setNowPlayingTrack: React.Dispatch>; setCommentsPartId: React.Dispatch>; } @@ -24,7 +25,7 @@ const KillingPartTrackList = ({ setNowPlayingTrack, setCommentsPartId, }: KillingPartTrackListProps) => { - const hasMyPart = myPart !== undefined; + const [myPartDetail, setMyPartDetail] = useState(myPart); const { user } = useAuthContext(); const navigate = useNavigate(); @@ -34,27 +35,32 @@ const KillingPartTrackList = ({ const { isOpen, openModal, closeModal } = useModal(); + const hideMyPart = () => setMyPartDetail(null); + return ( - {killingParts.map((killingPart) => ( + {killingParts.map((killingPart, i) => ( ))} - {hasMyPart ? ( + {myPartDetail ? ( ) : ( From 15449dd97fa806b9781e4822c206e4addf3aa2ea Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Wed, 18 Oct 2023 11:07:43 +0900 Subject: [PATCH 29/38] =?UTF-8?q?fix=20=EB=A7=88=EC=9D=B4=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=EC=9D=98=20=EB=82=B4=20=ED=82=AC=EB=A7=81?= =?UTF-8?q?=ED=8C=8C=ED=8A=B8=20=EC=A1=B0=ED=9A=8C=20api=20=EC=97=94?= =?UTF-8?q?=EB=93=9C=ED=8F=AC=EC=9D=B8=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/features/member/remotes/myPage.ts | 2 +- frontend/src/mocks/handlers/memberHandlers.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/features/member/remotes/myPage.ts b/frontend/src/features/member/remotes/myPage.ts index 351002a87..b0ab55df8 100644 --- a/frontend/src/features/member/remotes/myPage.ts +++ b/frontend/src/features/member/remotes/myPage.ts @@ -2,4 +2,4 @@ import fetcher from '@/shared/remotes'; export const getLikeParts = () => fetcher('/my-page/like-parts', 'GET'); -export const getMyParts = () => fetcher('/my-page/member-parts', 'GET'); +export const getMyParts = () => fetcher('/my-page/my-parts', 'GET'); diff --git a/frontend/src/mocks/handlers/memberHandlers.ts b/frontend/src/mocks/handlers/memberHandlers.ts index a5abea6a4..84fe2c989 100644 --- a/frontend/src/mocks/handlers/memberHandlers.ts +++ b/frontend/src/mocks/handlers/memberHandlers.ts @@ -122,7 +122,7 @@ export const memberHandlers = [ ); }), - rest.get(`${BASE_URL}/my-page/member-parts`, (req, res, ctx) => { + rest.get(`${BASE_URL}/my-page/my-parts`, (req, res, ctx) => { return res( ctx.json([ { From 9b35f7d05ca29a56508fa4a7fb3b5a2da0d8cb15 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Wed, 18 Oct 2023 11:08:24 +0900 Subject: [PATCH 30/38] =?UTF-8?q?test:=20msw=20=EB=8D=B0=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=20fixture=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/mocks/fixtures/likeParts.json | 101 +++++++ frontend/src/mocks/fixtures/myParts.json | 120 ++++++++ frontend/src/mocks/handlers/memberHandlers.ts | 257 +----------------- 3 files changed, 225 insertions(+), 253 deletions(-) create mode 100644 frontend/src/mocks/fixtures/likeParts.json create mode 100644 frontend/src/mocks/fixtures/myParts.json diff --git a/frontend/src/mocks/fixtures/likeParts.json b/frontend/src/mocks/fixtures/likeParts.json new file mode 100644 index 000000000..c6553970b --- /dev/null +++ b/frontend/src/mocks/fixtures/likeParts.json @@ -0,0 +1,101 @@ +[ + { + "songId": 1, + "title": "Super Shy", + "singer": "New Jeans", + "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize", + "partId": 11, + "start": 10, + "end": 20 + }, + { + "songId": 2, + "title": "제목이 너무 길다면 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데?", + "singer": "가수 이름도 너무 길다면 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데?", + "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize", + "partId": 12, + "start": 5, + "end": 15 + }, + { + "songId": 3, + "title": "Super Shy", + "singer": "New Jeans", + "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize", + "partId": 13, + "start": 66, + "end": 71 + }, + { + "songId": 4, + "title": "Super Shy", + "singer": "New Jeans", + "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize", + "partId": 14, + "start": 100, + "end": 115 + }, + { + "songId": 5, + "title": "Super Shy", + "singer": "New Jeans", + "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize", + "partId": 15, + "start": 72, + "end": 82 + }, + { + "songId": 6, + "title": "Super Shy", + "singer": "New Jeans", + "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize", + "partId": 16, + "start": 66, + "end": 76 + }, + { + "songId": 7, + "title": "Super Shy", + "singer": "New Jeans", + "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize", + "partId": 16, + "start": 66, + "end": 76 + }, + { + "songId": 8, + "title": "Super Shy", + "singer": "New Jeans", + "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize", + "partId": 16, + "start": 66, + "end": 76 + }, + { + "songId": 9, + "title": "Super Shy", + "singer": "New Jeans", + "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize", + "partId": 16, + "start": 66, + "end": 76 + }, + { + "songId": 10, + "title": "Super Shy", + "singer": "New Jeans", + "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize", + "partId": 16, + "start": 66, + "end": 76 + }, + { + "songId": 11, + "title": "Super Shy", + "singer": "New Jeans", + "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize", + "partId": 16, + "start": 66, + "end": 76 + } +] diff --git a/frontend/src/mocks/fixtures/myParts.json b/frontend/src/mocks/fixtures/myParts.json new file mode 100644 index 000000000..e229523e6 --- /dev/null +++ b/frontend/src/mocks/fixtures/myParts.json @@ -0,0 +1,120 @@ +[ + { + "songId": 1, + "title": "후라이의 꿈", + "singer": "AKMU (악뮤)", + "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", + "partId": 11, + "start": 1, + "end": 11 + }, + { + "songId": 2, + "title": "제목이 너무 길다면 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데?", + "singer": "가수 이름도 너무 길다면 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데?", + "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", + "partId": 12, + "start": 13, + "end": 23 + }, + { + "songId": 3, + "title": "후라이의 꿈", + "singer": "AKMU (악뮤)", + "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", + "partId": 13, + "start": 36, + "end": 46 + }, + { + "songId": 4, + "title": "후라이의 꿈", + "singer": "AKMU (악뮤)", + "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", + "partId": 14, + "start": 77, + "end": 87 + }, + { + "songId": 5, + "title": "후라이의 꿈", + "singer": "AKMU (악뮤)", + "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", + "partId": 15, + "start": 102, + "end": 112 + }, + { + "songId": 6, + "title": "후라이의 꿈", + "singer": "AKMU (악뮤)", + "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", + "partId": 16, + "start": 190, + "end": 200 + }, + { + "songId": 7, + "title": "후라이의 꿈", + "singer": "AKMU (악뮤)", + "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", + "partId": 16, + "start": 190, + "end": 200 + }, + + { + "songId": 8, + "title": "후라이의 꿈", + "singer": "AKMU (악뮤)", + "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", + "partId": 16, + "start": 190, + "end": 200 + }, + { + "songId": 9, + "title": "후라이의 꿈", + "singer": "AKMU (악뮤)", + "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", + "partId": 16, + "start": 190, + "end": 200 + }, + { + "songId": 10, + "title": "후라이의 꿈", + "singer": "AKMU (악뮤)", + "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", + "partId": 16, + "start": 190, + "end": 200 + }, + { + "songId": 11, + "title": "후라이의 꿈", + "singer": "AKMU (악뮤)", + "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", + "partId": 16, + "start": 190, + "end": 200 + }, + { + "songId": 12, + "title": "후라이의 꿈", + "singer": "AKMU (악뮤)", + "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", + "partId": 16, + "start": 190, + "end": 200 + }, + { + "songId": 13, + "title": "후라이의 꿈", + "singer": "AKMU (악뮤)", + "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", + "partId": 16, + "start": 190, + "end": 200 + } +] diff --git a/frontend/src/mocks/handlers/memberHandlers.ts b/frontend/src/mocks/handlers/memberHandlers.ts index 84fe2c989..c82cfe9b8 100644 --- a/frontend/src/mocks/handlers/memberHandlers.ts +++ b/frontend/src/mocks/handlers/memberHandlers.ts @@ -1,264 +1,15 @@ import { rest } from 'msw'; +import likeParts from '@/mocks/fixtures/likeParts.json'; +import myParts from '@/mocks/fixtures/myParts.json'; const { BASE_URL } = process.env; export const memberHandlers = [ rest.get(`${BASE_URL}/my-page/like-parts`, (req, res, ctx) => { - return res( - ctx.json([ - { - songId: 1, - title: 'Super Shy', - singer: 'New Jeans', - albumCoverUrl: - 'https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize', - partId: 11, - start: 10, - end: 20, - }, - { - songId: 2, - title: - '제목이 너무 길다면 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데?', - singer: - '가수 이름도 너무 길다면 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데?', - albumCoverUrl: - 'https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize', - partId: 12, - start: 5, - end: 15, - }, - { - songId: 3, - title: 'Super Shy', - singer: 'New Jeans', - albumCoverUrl: - 'https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize', - partId: 13, - start: 66, - end: 71, - }, - { - songId: 4, - title: 'Super Shy', - singer: 'New Jeans', - albumCoverUrl: - 'https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize', - partId: 14, - start: 100, - end: 115, - }, - { - songId: 5, - title: 'Super Shy', - singer: 'New Jeans', - albumCoverUrl: - 'https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize', - partId: 15, - start: 72, - end: 82, - }, - { - songId: 6, - title: 'Super Shy', - singer: 'New Jeans', - albumCoverUrl: - 'https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize', - partId: 16, - start: 66, - end: 76, - }, - { - songId: 7, - title: 'Super Shy', - singer: 'New Jeans', - albumCoverUrl: - 'https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize', - partId: 16, - start: 66, - end: 76, - }, - { - songId: 8, - title: 'Super Shy', - singer: 'New Jeans', - albumCoverUrl: - 'https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize', - partId: 16, - start: 66, - end: 76, - }, - { - songId: 9, - title: 'Super Shy', - singer: 'New Jeans', - albumCoverUrl: - 'https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize', - partId: 16, - start: 66, - end: 76, - }, - { - songId: 10, - title: 'Super Shy', - singer: 'New Jeans', - albumCoverUrl: - 'https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize', - partId: 16, - start: 66, - end: 76, - }, - { - songId: 11, - title: 'Super Shy', - singer: 'New Jeans', - albumCoverUrl: - 'https://cdnimg.melon.co.kr/cm2/album/images/112/81/456/11281456_20230706180841_500.jpg/melon/resize/120/quality/80/optimize', - partId: 16, - start: 66, - end: 76, - }, - ]) - ); + return res(ctx.json(likeParts)); }), rest.get(`${BASE_URL}/my-page/my-parts`, (req, res, ctx) => { - return res( - ctx.json([ - { - songId: 1, - title: '후라이의 꿈', - singer: 'AKMU (악뮤)', - albumCoverUrl: - 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', - partId: 11, - start: 1, - end: 11, - }, - { - songId: 2, - title: - '제목이 너무 길다면 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데?', - singer: - '가수 이름도 너무 길다면 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데? 어떻게 할 건데?', - albumCoverUrl: - 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', - partId: 12, - start: 13, - end: 23, - }, - { - songId: 3, - title: '후라이의 꿈', - singer: 'AKMU (악뮤)', - albumCoverUrl: - 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', - partId: 13, - start: 36, - end: 46, - }, - { - songId: 4, - title: '후라이의 꿈', - singer: 'AKMU (악뮤)', - albumCoverUrl: - 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', - partId: 14, - start: 77, - end: 87, - }, - { - songId: 5, - title: '후라이의 꿈', - singer: 'AKMU (악뮤)', - albumCoverUrl: - 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', - partId: 15, - start: 102, - end: 112, - }, - { - songId: 6, - title: '후라이의 꿈', - singer: 'AKMU (악뮤)', - albumCoverUrl: - 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', - partId: 16, - start: 190, - end: 200, - }, - { - songId: 7, - title: '후라이의 꿈', - singer: 'AKMU (악뮤)', - albumCoverUrl: - 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', - partId: 16, - start: 190, - end: 200, - }, - - { - songId: 8, - title: '후라이의 꿈', - singer: 'AKMU (악뮤)', - albumCoverUrl: - 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', - partId: 16, - start: 190, - end: 200, - }, - { - songId: 9, - title: '후라이의 꿈', - singer: 'AKMU (악뮤)', - albumCoverUrl: - 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', - partId: 16, - start: 190, - end: 200, - }, - { - songId: 10, - title: '후라이의 꿈', - singer: 'AKMU (악뮤)', - albumCoverUrl: - 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', - partId: 16, - start: 190, - end: 200, - }, - { - songId: 11, - title: '후라이의 꿈', - singer: 'AKMU (악뮤)', - albumCoverUrl: - 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', - partId: 16, - start: 190, - end: 200, - }, - { - songId: 12, - title: '후라이의 꿈', - singer: 'AKMU (악뮤)', - albumCoverUrl: - 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', - partId: 16, - start: 190, - end: 200, - }, - { - songId: 13, - title: '후라이의 꿈', - singer: 'AKMU (악뮤)', - albumCoverUrl: - 'https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize', - partId: 16, - start: 190, - end: 200, - }, - ]) - ); + return res(ctx.json(myParts)); }), ]; From b18023b94ca3cd5f614efa78c154ca7ab8f53c2e Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Wed, 18 Oct 2023 14:25:50 +0900 Subject: [PATCH 31/38] =?UTF-8?q?fix:=20=EB=B0=98=EB=B3=B5=20=EB=93=A3?= =?UTF-8?q?=EA=B8=B0=EA=B0=80=20=EB=90=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20?= =?UTF-8?q?=ED=98=84=EC=83=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../songs/components/KillingPartInterface.tsx | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/frontend/src/features/songs/components/KillingPartInterface.tsx b/frontend/src/features/songs/components/KillingPartInterface.tsx index 26194ad2f..5f20e824c 100644 --- a/frontend/src/features/songs/components/KillingPartInterface.tsx +++ b/frontend/src/features/songs/components/KillingPartInterface.tsx @@ -35,10 +35,16 @@ const KillingPartInterface = ({ killingParts, songId, myPart }: KillingPartInter } }, [videoPlayer, playerState]); + const trackList = [...killingParts, myPart].map((part, i) => ({ part, order: i + 1 })); + useEffect(() => { - const part = killingParts.find((part) => part.id === nowPlayingTrack); - if (!part || !videoPlayer.current) return; + if (nowPlayingTrack === DEFAULT_PART_ID) return; + + const track = trackList.find(({ order }) => order === nowPlayingTrack); + + if (!track || !videoPlayer.current) return; + const { part } = track; const partLength = (part.end - part.start) * 1000; const remainingTime = partLength - countedTime * 1000; @@ -69,16 +75,7 @@ const KillingPartInterface = ({ killingParts, songId, myPart }: KillingPartInter window.clearTimeout(timeoutId2); window.clearInterval(intervalIds); }; - }, [ - killingParts, - isRepeat, - nowPlayingTrack, - videoPlayer, - pause, - resetTimer, - seekTo, - countedTime, - ]); + }, [trackList, isRepeat, nowPlayingTrack, videoPlayer, pause, resetTimer, seekTo, countedTime]); useEffect(() => { resetTimer(); From b8622c056c5c14242cc60e4c3836d8cd66e371f5 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Wed, 18 Oct 2023 15:55:05 +0900 Subject: [PATCH 32/38] =?UTF-8?q?fix:=20=EC=9E=98=EB=AA=BB=EB=90=9C=20?= =?UTF-8?q?=EA=B2=BD=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/features/member/components/PartItem.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/frontend/src/features/member/components/PartItem.tsx b/frontend/src/features/member/components/PartItem.tsx index 28aafb0fc..7dc50aaab 100644 --- a/frontend/src/features/member/components/PartItem.tsx +++ b/frontend/src/features/member/components/PartItem.tsx @@ -31,14 +31,12 @@ const PartItem = ({ songId, albumCoverUrl, title, singer, start, end }: PartItem memberId: user?.memberId, }); - copyClipboard( - `${BASE_URL?.replace('/api', '')}/${ROUTE_PATH.SONG_DETAILS}${songId}/${GENRES.ALL}` - ); + copyClipboard(`${BASE_URL?.replace('/api', '')}/${ROUTE_PATH.SONG_DETAILS}${songId}/ALL`); showToast('클립보드에 영상링크가 복사되었습니다.'); }; const goToSongDetailListPage = () => { - navigate(`/${ROUTE_PATH.SONG_DETAILS}${songId}/${GENRES.ALL}`); + navigate(`/${ROUTE_PATH.SONG_DETAILS}/${songId}/ALL`); }; const { minute: startMin, second: startSec } = secondsToMinSec(start); From abba1df780af88ae8695a242bb83460a79127794 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Wed, 18 Oct 2023 16:02:15 +0900 Subject: [PATCH 33/38] =?UTF-8?q?fix:=20myPart=EB=A5=BC=20memberPart?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/features/member/components/PartItem.tsx | 1 - .../features/songs/components/KillingPartInterface.tsx | 8 ++++---- .../songs/components/KillingPartTrackList.stories.tsx | 4 ++-- .../features/songs/components/KillingPartTrackList.tsx | 8 ++++---- frontend/src/features/songs/components/SongDetailItem.tsx | 8 ++++++-- frontend/src/shared/types/song.ts | 2 +- 6 files changed, 17 insertions(+), 14 deletions(-) diff --git a/frontend/src/features/member/components/PartItem.tsx b/frontend/src/features/member/components/PartItem.tsx index 7dc50aaab..1b9557c25 100644 --- a/frontend/src/features/member/components/PartItem.tsx +++ b/frontend/src/features/member/components/PartItem.tsx @@ -4,7 +4,6 @@ import link from '@/assets/icon/link.svg'; import shook from '@/assets/icon/shook.svg'; import { useAuthContext } from '@/features/auth/components/AuthProvider'; import Thumbnail from '@/features/songs/components/Thumbnail'; -import GENRES from '@/features/songs/constants/genres'; import Spacing from '@/shared/components/Spacing'; import useToastContext from '@/shared/components/Toast/hooks/useToastContext'; import { GA_ACTIONS, GA_CATEGORIES } from '@/shared/constants/GAEventName'; diff --git a/frontend/src/features/songs/components/KillingPartInterface.tsx b/frontend/src/features/songs/components/KillingPartInterface.tsx index 5f20e824c..449b7b9b4 100644 --- a/frontend/src/features/songs/components/KillingPartInterface.tsx +++ b/frontend/src/features/songs/components/KillingPartInterface.tsx @@ -11,13 +11,13 @@ import type { KillingPart, SongDetail } from '@/shared/types/song'; interface KillingPartInterfaceProps { killingParts: SongDetail['killingParts']; - myPart: SongDetail['myPart']; + memberPart: SongDetail['memberPart']; songId: number; } const DEFAULT_PART_ID = -1; -const KillingPartInterface = ({ killingParts, songId, myPart }: KillingPartInterfaceProps) => { +const KillingPartInterface = ({ killingParts, songId, memberPart }: KillingPartInterfaceProps) => { const [nowPlayingTrack, setNowPlayingTrack] = useState(DEFAULT_PART_ID); const [commentsPartId, setCommentsPartId] = useState(DEFAULT_PART_ID); const [isRepeat, setIsRepeat] = useState(false); @@ -35,7 +35,7 @@ const KillingPartInterface = ({ killingParts, songId, myPart }: KillingPartInter } }, [videoPlayer, playerState]); - const trackList = [...killingParts, myPart].map((part, i) => ({ part, order: i + 1 })); + const trackList = [...killingParts, memberPart].map((part, i) => ({ part, order: i + 1 })); useEffect(() => { if (nowPlayingTrack === DEFAULT_PART_ID) return; @@ -138,7 +138,7 @@ const KillingPartInterface = ({ killingParts, songId, myPart }: KillingPartInter { return ( >; @@ -19,13 +19,13 @@ interface KillingPartTrackListProps { const KillingPartTrackList = ({ killingParts, - myPart, + memberPart, songId, nowPlayingTrack, setNowPlayingTrack, setCommentsPartId, }: KillingPartTrackListProps) => { - const [myPartDetail, setMyPartDetail] = useState(myPart); + const [myPartDetail, setMyPartDetail] = useState(memberPart); const { user } = useAuthContext(); const navigate = useNavigate(); @@ -54,7 +54,7 @@ const KillingPartTrackList = ({ {myPartDetail ? ( ( - ({ id, killingParts, singer, title, songVideoId, albumCoverUrl, myPart }, ref) => { + ({ id, killingParts, singer, title, songVideoId, albumCoverUrl, memberPart }, ref) => { const navigate = useNavigate(); const { genre } = useValidParams(); @@ -61,7 +61,11 @@ const SongDetailItem = forwardRef( - + diff --git a/frontend/src/shared/types/song.ts b/frontend/src/shared/types/song.ts index dddf660e5..5eb81d5a7 100644 --- a/frontend/src/shared/types/song.ts +++ b/frontend/src/shared/types/song.ts @@ -12,7 +12,7 @@ export interface SongDetail { songVideoId: string; albumCoverUrl: string; killingParts: KillingPart[]; - myPart: KillingPart; + memberPart: KillingPart; } export interface KillingPart { From 505d5572f5062ada1cc1de2c7da202448daa75bc Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Wed, 18 Oct 2023 18:42:45 +0900 Subject: [PATCH 34/38] =?UTF-8?q?test:=20msw=20=EB=8D=B0=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=20=ED=95=84=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/mocks/fixtures/songEntries.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/mocks/fixtures/songEntries.json b/frontend/src/mocks/fixtures/songEntries.json index 0b8ad7b53..44c78a6e2 100644 --- a/frontend/src/mocks/fixtures/songEntries.json +++ b/frontend/src/mocks/fixtures/songEntries.json @@ -440,7 +440,7 @@ "likeStatus": false } ], - "myPart": { + "memberPart": { "id": 70, "rank": 1, "likeCount": 0, From 908d6810ebf0f9907ba4f01a1cfb70970c3e1594 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Wed, 18 Oct 2023 18:43:00 +0900 Subject: [PATCH 35/38] =?UTF-8?q?feat:=20=EB=A7=88=EC=9D=B4=ED=8C=8C?= =?UTF-8?q?=ED=8A=B8=EC=97=90=20=EA=B3=B5=EC=9C=A0=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../songs/components/KillingPartTrack.tsx | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/frontend/src/features/songs/components/KillingPartTrack.tsx b/frontend/src/features/songs/components/KillingPartTrack.tsx index dee94f07e..73547b418 100644 --- a/frontend/src/features/songs/components/KillingPartTrack.tsx +++ b/frontend/src/features/songs/components/KillingPartTrack.tsx @@ -44,7 +44,7 @@ const KillingPartTrack = ({ hideMyPart, }: KillingPartTrackProps) => { const { showToast } = useToastContext(); - const { seekTo, pause, playerState } = useVideoPlayerContext(); + const { seekTo, pause, playerState, videoPlayer } = useVideoPlayerContext(); const { calculatedLikeCount, heartIcon, toggleKillingPartLikes } = useKillingPartLikes({ likeCount, likeStatus, @@ -80,6 +80,17 @@ const KillingPartTrack = ({ showToast('영상 링크가 복사되었습니다.'); }; + const copyMyPartUrl = async () => { + sendGAEvent({ + action: GA_ACTIONS.COPY_URL, + category: GA_CATEGORIES.SONG_DETAIL, + memberId: user?.memberId, + }); + + await copyClipboard(`${videoPlayer.current?.getVideoUrl()}&t=${start}s`); + showToast('영상 링크가 복사되었습니다.'); + }; + const getPlayIcon = useCallback(() => { if (!isNowPlayingTrack || playerState === YT.PlayerState.PAUSED) { return emptyPlayIcon; @@ -171,9 +182,20 @@ const KillingPartTrack = ({ {isMyKillingPart ? ( - - - + <> + + + Delete + + + + Share + + ) : ( <> {`${calculatedLikeCount} Likes`} From bebe44f09edf1238da68e8ebeae5d236a3761357 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Wed, 18 Oct 2023 20:34:48 +0900 Subject: [PATCH 36/38] =?UTF-8?q?test:=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=EC=97=90=EC=84=9C=20=EB=A7=88=EC=9D=B4=20?= =?UTF-8?q?=ED=8C=8C=ED=8A=B8=20msw=EC=97=90=20songVideoId=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/mocks/fixtures/myParts.json | 39 ++++++++++++++++-------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/frontend/src/mocks/fixtures/myParts.json b/frontend/src/mocks/fixtures/myParts.json index e229523e6..b2d25df18 100644 --- a/frontend/src/mocks/fixtures/myParts.json +++ b/frontend/src/mocks/fixtures/myParts.json @@ -6,7 +6,8 @@ "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", "partId": 11, "start": 1, - "end": 11 + "end": 11, + "songVideoId": "3kGAlp_PNUg" }, { "songId": 2, @@ -15,7 +16,8 @@ "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", "partId": 12, "start": 13, - "end": 23 + "end": 23, + "songVideoId": "3kGAlp_PNUg" }, { "songId": 3, @@ -24,7 +26,8 @@ "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", "partId": 13, "start": 36, - "end": 46 + "end": 46, + "songVideoId": "3kGAlp_PNUg" }, { "songId": 4, @@ -33,7 +36,8 @@ "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", "partId": 14, "start": 77, - "end": 87 + "end": 87, + "songVideoId": "3kGAlp_PNUg" }, { "songId": 5, @@ -42,7 +46,8 @@ "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", "partId": 15, "start": 102, - "end": 112 + "end": 112, + "songVideoId": "3kGAlp_PNUg" }, { "songId": 6, @@ -51,7 +56,8 @@ "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", "partId": 16, "start": 190, - "end": 200 + "end": 200, + "songVideoId": "3kGAlp_PNUg" }, { "songId": 7, @@ -60,7 +66,8 @@ "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", "partId": 16, "start": 190, - "end": 200 + "end": 200, + "songVideoId": "3kGAlp_PNUg" }, { @@ -70,7 +77,8 @@ "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", "partId": 16, "start": 190, - "end": 200 + "end": 200, + "songVideoId": "3kGAlp_PNUg" }, { "songId": 9, @@ -79,7 +87,8 @@ "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", "partId": 16, "start": 190, - "end": 200 + "end": 200, + "songVideoId": "3kGAlp_PNUg" }, { "songId": 10, @@ -88,7 +97,8 @@ "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", "partId": 16, "start": 190, - "end": 200 + "end": 200, + "songVideoId": "3kGAlp_PNUg" }, { "songId": 11, @@ -97,7 +107,8 @@ "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", "partId": 16, "start": 190, - "end": 200 + "end": 200, + "songVideoId": "3kGAlp_PNUg" }, { "songId": 12, @@ -106,7 +117,8 @@ "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", "partId": 16, "start": 190, - "end": 200 + "end": 200, + "songVideoId": "3kGAlp_PNUg" }, { "songId": 13, @@ -115,6 +127,7 @@ "albumCoverUrl": "https://cdnimg.melon.co.kr/cm2/album/images/113/09/190/11309190_20230818161008_500.jpg/melon/resize/120/quality/80/optimize", "partId": 16, "start": 190, - "end": 200 + "end": 200, + "songVideoId": "3kGAlp_PNUg" } ] From eb9d592b340be789e98d828f74ffd11f1d7f1fd4 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Wed, 18 Oct 2023 20:34:59 +0900 Subject: [PATCH 37/38] =?UTF-8?q?feat:=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=EC=97=90=EC=84=9C=20=EB=82=98=EC=9D=98=20?= =?UTF-8?q?=ED=82=AC=EB=A7=81=ED=8C=8C=ED=8A=B8=EB=8A=94=20=EC=9C=A0?= =?UTF-8?q?=ED=8A=9C=EB=B8=8C=20=EB=A7=81=ED=81=AC=20=EA=B3=B5=EC=9C=A0?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../features/member/components/MyPartList.tsx | 12 ++++++++-- .../features/member/components/PartItem.tsx | 23 ++++++++++++++++--- .../features/member/components/PartList.tsx | 6 +++-- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/frontend/src/features/member/components/MyPartList.tsx b/frontend/src/features/member/components/MyPartList.tsx index 8ca35f592..fb95df958 100644 --- a/frontend/src/features/member/components/MyPartList.tsx +++ b/frontend/src/features/member/components/MyPartList.tsx @@ -7,7 +7,10 @@ import PartList from './PartList'; import type { MyPageTab } from '../types/myPage'; import type { KillingPart, SongDetail } from '@/shared/types/song'; -export type LikeKillingPart = Pick & +export type LikeKillingPart = Pick< + SongDetail, + 'title' | 'singer' | 'albumCoverUrl' | 'songVideoId' +> & Pick & { songId: number; partId: number; @@ -55,7 +58,12 @@ const MyPartList = () => { {partTabItems.map((option) => ( - + ))} ); diff --git a/frontend/src/features/member/components/PartItem.tsx b/frontend/src/features/member/components/PartItem.tsx index 1b9557c25..dfeaa0edb 100644 --- a/frontend/src/features/member/components/PartItem.tsx +++ b/frontend/src/features/member/components/PartItem.tsx @@ -12,12 +12,24 @@ import sendGAEvent from '@/shared/googleAnalytics/sendGAEvent'; import { secondsToMinSec, toPlayingTimeText } from '@/shared/utils/convertTime'; import copyClipboard from '@/shared/utils/copyClipBoard'; import type { LikeKillingPart } from './MyPartList'; +import type { MyPageTab } from '../types/myPage'; const { BASE_URL } = process.env; -type PartItemProps = LikeKillingPart; +type PartItemProps = LikeKillingPart & { + tab: MyPageTab; +}; -const PartItem = ({ songId, albumCoverUrl, title, singer, start, end }: PartItemProps) => { +const PartItem = ({ + songId, + albumCoverUrl, + title, + singer, + start, + end, + songVideoId, + tab, +}: PartItemProps) => { const { showToast } = useToastContext(); const { user } = useAuthContext(); const navigate = useNavigate(); @@ -30,7 +42,12 @@ const PartItem = ({ songId, albumCoverUrl, title, singer, start, end }: PartItem memberId: user?.memberId, }); - copyClipboard(`${BASE_URL?.replace('/api', '')}/${ROUTE_PATH.SONG_DETAILS}${songId}/ALL`); + const shareLink = + tab === 'Like' + ? `${BASE_URL?.replace('/api', '')}/${ROUTE_PATH.SONG_DETAILS}${songId}/ALL` + : `https://youtu.be/${songVideoId}?start=${start}`; + + copyClipboard(shareLink); showToast('클립보드에 영상링크가 복사되었습니다.'); }; diff --git a/frontend/src/features/member/components/PartList.tsx b/frontend/src/features/member/components/PartList.tsx index 498ffbb07..6b3a45fca 100644 --- a/frontend/src/features/member/components/PartList.tsx +++ b/frontend/src/features/member/components/PartList.tsx @@ -2,15 +2,17 @@ import { useEffect } from 'react'; import styled from 'styled-components'; import PartItem from './PartItem'; import type { LikeKillingPart } from './MyPartList'; +import type { MyPageTab } from '../types/myPage'; interface PartListProps { parts: LikeKillingPart[]; isShow: boolean; + tab: MyPageTab; } const PART_LIST_SCROLL_TOP = 180; -const PartList = ({ parts, isShow }: PartListProps) => { +const PartList = ({ parts, isShow, tab }: PartListProps) => { useEffect(() => { if (window.scrollY > PART_LIST_SCROLL_TOP) { window.scrollTo({ top: PART_LIST_SCROLL_TOP, behavior: 'smooth' }); @@ -24,7 +26,7 @@ const PartList = ({ parts, isShow }: PartListProps) => { return ( {parts.map((part) => ( - + ))} ); From 725ea97a0409019d6d0bca6defef23da6edb1fd3 Mon Sep 17 00:00:00 2001 From: cruelladevil Date: Thu, 19 Oct 2023 11:41:17 +0900 Subject: [PATCH 38/38] =?UTF-8?q?fix:=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=EC=9D=98=20=EC=A2=8B=EC=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=ED=8C=8C=ED=8A=B8=20=EA=B3=B5=EC=9C=A0=20=EB=A7=81?= =?UTF-8?q?=ED=81=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/features/member/components/PartItem.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/features/member/components/PartItem.tsx b/frontend/src/features/member/components/PartItem.tsx index dfeaa0edb..03ba600ca 100644 --- a/frontend/src/features/member/components/PartItem.tsx +++ b/frontend/src/features/member/components/PartItem.tsx @@ -44,7 +44,7 @@ const PartItem = ({ const shareLink = tab === 'Like' - ? `${BASE_URL?.replace('/api', '')}/${ROUTE_PATH.SONG_DETAILS}${songId}/ALL` + ? `${BASE_URL?.replace('/api', '')}/${ROUTE_PATH.SONG_DETAILS}/${songId}/ALL` : `https://youtu.be/${songVideoId}?start=${start}`; copyClipboard(shareLink);