From 5d6d0448bcff19801b4331e3acf5f7a3b89937cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8C=E1=85=A5=E1=86=BC=E1=84=89=E1=85=A5=E1=86=BC?= =?UTF-8?q?=E1=84=92=E1=85=B1?= Date: Mon, 12 Feb 2024 14:31:49 +0900 Subject: [PATCH 01/21] =?UTF-8?q?feature-059:=20=EC=B9=B4=EC=B9=B4?= =?UTF-8?q?=EC=98=A4=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20API=20=ED=8C=8C?= =?UTF-8?q?=EB=9D=BC=EB=AF=B8=ED=84=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/social-account.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/apis/social-account.ts b/src/apis/social-account.ts index daaa2e1..84670be 100644 --- a/src/apis/social-account.ts +++ b/src/apis/social-account.ts @@ -1,5 +1,5 @@ import axios from './config/instance'; -export const kakaoLoginAPI = (token: string) => { - return axios.get(`/kakao-login?token=${token}`); +export const kakaoLoginAPI = (code: string) => { + return axios.get(`/kakao-login?code=${code}`); }; From aa3d177d91eda0a6275501ce419bceb7e1dcd553 Mon Sep 17 00:00:00 2001 From: gs0428 Date: Mon, 12 Feb 2024 16:02:02 +0900 Subject: [PATCH 02/21] =?UTF-8?q?feature-060:=20=EC=82=AC=EC=9D=B4?= =?UTF-8?q?=EB=93=9C=EB=B0=94=20=EC=8A=A4=ED=83=80=EC=9D=BC=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 --- src/styles/layout/sideBar/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/styles/layout/sideBar/index.ts b/src/styles/layout/sideBar/index.ts index be25c00..bba5b70 100644 --- a/src/styles/layout/sideBar/index.ts +++ b/src/styles/layout/sideBar/index.ts @@ -5,8 +5,9 @@ export const Container = styled.div` display: flex; flex-direction: column; margin: 60px 0px 0px 60px; + padding-right: 20px; width: 288px; - box-shadow: 4px 0px 40px 0px rgba(0, 0, 0, 0.05); + box-shadow: 4px 0px 10px rgba(0, 0, 0, 0.05); z-index: 0; `; From b85d07b8fab3512741993ee775ce0e412ae93155 Mon Sep 17 00:00:00 2001 From: gs0428 Date: Mon, 12 Feb 2024 16:24:59 +0900 Subject: [PATCH 03/21] =?UTF-8?q?feature-060:=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=ED=9B=84=20=EC=B9=B4=ED=85=8C=EA=B3=A0=EB=A6=AC=20?= =?UTF-8?q?=EC=82=AC=EC=9D=B4=EB=93=9C=20=EB=B0=94=20=EC=B5=9C=EC=8B=A0?= =?UTF-8?q?=ED=99=94=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/SignInPage.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/SignInPage.tsx b/src/pages/SignInPage.tsx index 5af90c3..116592f 100644 --- a/src/pages/SignInPage.tsx +++ b/src/pages/SignInPage.tsx @@ -22,6 +22,7 @@ import { LoginRequest } from '@/models/user'; import { userTokenState } from '@/stores/user'; import { BlurBackground } from '@/styles/modals/common.style'; +import useUpdateCategories from '@/hooks/useUpdateCategories'; const SignInPage: React.FC = () => { const navigate = useNavigate(); @@ -30,6 +31,7 @@ const SignInPage: React.FC = () => { const [isOpenErrorModal, setIsOpenErrorModal] = useState(false); const [isOpenSignUpModal, setIsOpenSignUpModal] = useState(false); const setUserToken = useSetRecoilState(userTokenState); + const { updateCategories } = useUpdateCategories(); const [loginInfo, setLoginInfo] = useState({ email: '', @@ -63,7 +65,7 @@ const SignInPage: React.FC = () => { const handleClickLoginButton = async () => { try { const { token } = (await loginAPI(loginInfo)).data.result; - + await updateCategories(); setUserToken(token); navigate('/'); } catch (error) { From 6a58cc7e67c18ab54ef7adef9476ae5b390dfe6c Mon Sep 17 00:00:00 2001 From: gs0428 Date: Mon, 12 Feb 2024 16:33:58 +0900 Subject: [PATCH 04/21] =?UTF-8?q?feature-060:=20=EC=98=81=EC=83=81=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC=ED=95=B4=EB=B3=B4=EA=B8=B0=20=ED=81=B4?= =?UTF-8?q?=EB=A6=AD=20=EC=8B=9C=20=ED=99=88=EC=9C=BC=EB=A1=9C=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/category/EmptyCard.tsx | 2 +- src/hooks/useMoveCategory.ts | 42 ++++++++++++++++++-------- src/styles/category/EmptyCard.style.ts | 7 +++-- 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/src/components/category/EmptyCard.tsx b/src/components/category/EmptyCard.tsx index 1278d61..5febd81 100644 --- a/src/components/category/EmptyCard.tsx +++ b/src/components/category/EmptyCard.tsx @@ -13,7 +13,7 @@ const EmptyCard = () => { 관련 영상들을 모아보세요 - 영상 정리해보기 + 영상 정리해보기 ); }; diff --git a/src/hooks/useMoveCategory.ts b/src/hooks/useMoveCategory.ts index 4902cc5..0b19138 100644 --- a/src/hooks/useMoveCategory.ts +++ b/src/hooks/useMoveCategory.ts @@ -8,10 +8,12 @@ import handleCategory from '@/utils/handleCategory'; import { useNavigate } from 'react-router-dom'; import { useRecoilState } from 'recoil'; import { ISubFolderProps } from 'types/category'; +import useUpdateCategories from './useUpdateCategories'; const useMoveCategory = () => { const [categories, setCategories] = useRecoilState(categoryState); const navigate = useNavigate(); + const { updateCategories } = useUpdateCategories(); const { deleteSubCategory, deleteTopCategory, @@ -19,7 +21,7 @@ const useMoveCategory = () => { insertSubToTopCategory, } = handleCategory(); - const subToOtherTop = ( + const subToOtherTop = async ( topId: number, grabedCategory: React.MutableRefObject, ) => { @@ -39,13 +41,20 @@ const useMoveCategory = () => { grabedCategory.current?.topCategoryId, grabedCategory.current!, ); - putSubToOtherTop(grabedCategory.current!.categoryId, topId); - setCategories([...insertResponse]); - navigate(`/category/${grabedCategory.current?.topCategoryId}`); - console.log(grabedCategory.current?.name); + const res = await putSubToOtherTop( + grabedCategory.current!.categoryId, + topId, + ); + if (res.isSuccess) { + updateCategories(); + setCategories([...insertResponse]); + navigate(`/category/${grabedCategory.current?.topCategoryId}`); + } else { + alert('카테고리를 옮기는데 오류가 발생했습니다.'); + } }; - const subToTop = ( + const subToTop = async ( topId: number, grabedCategory: React.MutableRefObject, dropedCategory: React.MutableRefObject, @@ -66,11 +75,16 @@ const useMoveCategory = () => { dropedCategory.current, grabedCategory.current!, ); - putSubToTop(grabedCategory.current!.categoryId); - setCategories([...insertResponse]); + const res = await putSubToTop(grabedCategory.current!.categoryId); + if (res.isSuccess) { + updateCategories(); + setCategories([...insertResponse]); + } else { + alert('카테고리를 옮기는데 오류가 발생했습니다.'); + } }; - const topToOtherTop = ( + const topToOtherTop = async ( grabedCategory: React.MutableRefObject, dropedCategory: React.MutableRefObject, ) => { @@ -89,12 +103,16 @@ const useMoveCategory = () => { topCategoryId: dropedCategory.current!, }, ); - putTopToOtherTop( + const res = await putTopToOtherTop( grabedCategory.current!.categoryId, dropedCategory.current!, ); - setCategories(insertResponse); - navigate(`/category/${dropedCategory.current}`); + if (res.isSuccess) { + setCategories(insertResponse); + navigate(`/category/${dropedCategory.current}`); + } else { + alert('카테고리를 옮기는데 오류가 발생했습니다.'); + } }; return { subToOtherTop, subToTop, topToOtherTop }; diff --git a/src/styles/category/EmptyCard.style.ts b/src/styles/category/EmptyCard.style.ts index 4d07b2d..547027d 100644 --- a/src/styles/category/EmptyCard.style.ts +++ b/src/styles/category/EmptyCard.style.ts @@ -1,5 +1,6 @@ import styled from 'styled-components'; import theme from '../theme'; +import { Link } from 'react-router-dom'; export const Container = styled.div` display: flex; @@ -17,11 +18,11 @@ export const Content = styled.p` ${theme.typography.Subheader2} `; -export const Button = styled.button` - cursor: pointer; - border: 0; +export const Button = styled(Link)` background-color: ${theme.color.gray500}; color: ${theme.color.white}; + text-decoration: none; + text-align: center; border-radius: 100px; padding: 12px 32px; ${theme.typography.Subheader2} From c75467a89e3e0fe5d536d6a4eaca107a9efbb2e5 Mon Sep 17 00:00:00 2001 From: gs0428 Date: Mon, 12 Feb 2024 17:32:04 +0900 Subject: [PATCH 05/21] =?UTF-8?q?feature-060:=20=EC=B9=B4=EB=93=9C=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Home/InsightVideos.tsx | 6 +- src/components/category/Card.tsx | 90 +++++++++------------------ src/pages/CategoryPage.tsx | 37 +++++------ src/styles/category/Card.style.ts | 84 +++++++++++++++---------- 4 files changed, 102 insertions(+), 115 deletions(-) diff --git a/src/components/Home/InsightVideos.tsx b/src/components/Home/InsightVideos.tsx index 6075a38..254e0d1 100644 --- a/src/components/Home/InsightVideos.tsx +++ b/src/components/Home/InsightVideos.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import { InsightVideosContainer } from '@/styles/HomepageStyle'; import Card from '../category/Card'; -import { cardDummy } from '../category/Card'; +import { IVideoProps } from '../category/Card'; interface InsightVideosProps { username: string; @@ -13,8 +13,8 @@ const InsightVideos: React.FC = ({ popularHashtags, }) => { const formattedHashtags = popularHashtags.map((tag) => '#' + tag); - const [categoryItems] = useState([]); - const [checkedItems, setCheckedItems] = useState([]); + const [categoryItems] = useState([]); + const [checkedItems, setCheckedItems] = useState([]); return ( diff --git a/src/components/category/Card.tsx b/src/components/category/Card.tsx index 7239bc4..f07f41c 100644 --- a/src/components/category/Card.tsx +++ b/src/components/category/Card.tsx @@ -1,8 +1,7 @@ -import React, { useEffect, useState } from 'react'; -import VideoTag from '../common/videoTag'; +import React, { useEffect } from 'react'; import * as CardStyles from '@/styles/category/Card.style'; -export interface cardDummy { +export interface IVideoProps { video_id: number; category_id: number; title: string; @@ -15,9 +14,9 @@ export interface cardDummy { } interface ICardProps { - videos: cardDummy[]; - checkedVideos: boolean[]; - setCheckedVideos: (value: boolean[]) => void; + videos: IVideoProps[]; + checkedVideos: number[]; + setCheckedVideos: (value: number[]) => void; } const Card: React.FC = ({ @@ -25,62 +24,35 @@ const Card: React.FC = ({ checkedVideos, setCheckedVideos, }) => { - const [isShadow, setIsShadow] = useState(new Array(6).fill(false)); + useEffect(() => {}, [checkedVideos]); - useEffect(() => { - if (checkedVideos.includes(true)) { - // 1개 이상 클릭 시 모든 hover event 활성화 - setIsShadow(isShadow.map(() => true)); - } else if (!isShadow.includes(false)) { - //모든 hover 활성화, 모든 체크 비활성화 시 모든 hover 활성화 제거 - setIsShadow(isShadow.map(() => false)); - } - }, [checkedVideos]); - - const handleMouseEnter = (id: number) => { - const prev = checkedVideos.includes(true) - ? [...isShadow] - : new Array(isShadow.length).fill(false); - // 체크박스 미선택 이동 시 isshadow 중복 작동으로 인해 방식 변경 - prev[id] = true; - setIsShadow(prev); - }; - - const handleMouseLeave = (id: number) => { - if (!checkedVideos.includes(true)) { - // 선택되면 유지 - const prev = [...isShadow]; - prev[id] = false; - setIsShadow(prev); + const handleCheckBox = (videoId: number) => { + if (checkedVideos.includes(videoId)) { + setCheckedVideos(checkedVideos.filter((id) => id !== videoId)); + } else { + setCheckedVideos([...checkedVideos, videoId]); } }; - - const checkBoxHandler = (id: number) => { - const prev = [...checkedVideos]; - prev[id] = !prev[id]; - setCheckedVideos(prev); - }; return ( - {videos.map((video, idx) => ( - handleMouseEnter(idx)} - onMouseLeave={() => handleMouseLeave(idx)} - > - - {isShadow[idx] && ( - checkBoxHandler(idx)} - /> - )} - + {videos.map((video) => ( + + + 0 ? 'activated' : ''} + > + handleCheckBox(video.video_id)} + /> + + + + {video.title} @@ -88,14 +60,14 @@ const Card: React.FC = ({ {video.description} - {video.tag.map((tag) => ( + {/* {video.tag.map((tag) => ( - ))} + ))} */} diff --git a/src/pages/CategoryPage.tsx b/src/pages/CategoryPage.tsx index eda9aa3..8e8167d 100644 --- a/src/pages/CategoryPage.tsx +++ b/src/pages/CategoryPage.tsx @@ -7,7 +7,7 @@ import GarbageSvg from '@/assets/icons/garbage.svg?react'; import FolderSvg from '@/assets/icons/open-file.svg?react'; import CloseSvg from '@/assets/icons/close.svg?react'; import * as CategoryPageStyles from '@/styles/category/index.style'; -import Card from '@/components/category/Card'; +import Card, { IVideoProps } from '@/components/category/Card'; import axiosInstance from '@/apis/config/instance'; import { useRecoilValue } from 'recoil'; import { categoryState } from '@/stores/category'; @@ -18,9 +18,9 @@ const CategoryPage = () => { const params = useParams(); const [name, setName] = useState(''); const [menus, setMenus] = useState([]); - const [videos, setVideos] = useState([]); + const [videos, setVideos] = useState([]); const [recentRegisterMode, setRecentRegisterMode] = useState(false); - const [checkedVideos, setCheckedVideos] = useState([]); + const [checkedVideos, setCheckedVideos] = useState([]); const categories = useRecoilValue(categoryState); const toggleRecentRegisterMode = () => @@ -47,41 +47,38 @@ const CategoryPage = () => { }, [categories, params.top_folder]); const allCheckBtnHandler = () => { - if (checkedVideos.includes(false)) { - setCheckedVideos(checkedVideos.map(() => true)); + if (checkedVideos.length === videos.length) { + // 삭제 API 요청 + console.log('모두 삭제'); + setCheckedVideos([]); } else { - // 모두 삭제 + console.log('모두 선택'); + setCheckedVideos(videos.map((video) => video.video_id)); } }; const dirMoveHanlder = () => { - checkedVideos.map((value, id) => { - if (value === true) { - console.log('이동해야할 index : ', id); - } - }); + console.log(checkedVideos); }; const garbageHandler = () => { - checkedVideos.map((value, id) => { - if (value === true) { - console.log('삭제해야할 index : ', id); - } - }); + console.log(checkedVideos); }; return ( - {checkedVideos.includes(true) ? ( + {checkedVideos.length > 0 ? ( <>
- {!checkedVideos.includes(false) ? '모두 삭제' : '모두 선택'} + {checkedVideos.length === videos.length + ? '모두 삭제' + : '모두 선택'} - {checkedVideos.filter((bool) => bool === true).length}개 선택 + {checkedVideos.length}개 선택
@@ -101,7 +98,7 @@ const CategoryPage = () => { width={28} height={28} onClick={() => { - setCheckedVideos(checkedVideos.map(() => false)); + setCheckedVideos([]); }} /> diff --git a/src/styles/category/Card.style.ts b/src/styles/category/Card.style.ts index e18abd1..1a0f975 100644 --- a/src/styles/category/Card.style.ts +++ b/src/styles/category/Card.style.ts @@ -2,7 +2,45 @@ import styled from 'styled-components'; import theme from '../theme'; import checkIcon from '@/assets/icons/check.svg'; import checkedIcon from '@/assets/icons/checked.svg'; +import { Link } from 'react-router-dom'; +export const CheckBoxWrap = styled.div` + background-color: rgba(0, 0, 0, 0.5); + display: none; + + flex-direction: row-reverse; + width: 100%; + height: 100%; + + &.activated { + display: flex; + } +`; + +export const CheckBox = styled.input` + appearance: none; + -webkit-appearance: none; + -moz-appearance: none; + + width: 24px; + height: 24px; + border-radius: 100%; + background-color: ${theme.color.gray300}; + background-image: url(${checkIcon}); + background-repeat: no-repeat; + background-position: center; + border: 1.5px solid ${theme.color.white}; + color: ${theme.color.white}; + margin: 12px; + + &:checked { + border: 1.5px solid ${theme.color.green300}; + background-color: ${theme.color.green300}; + background-image: url(${checkedIcon}); + background-repeat: no-repeat; + background-position: center; + } +`; export const Container = styled.div` display: grid; grid-template-columns: repeat(3, auto); @@ -17,9 +55,16 @@ export const Wrap = styled.div` border-radius: 16px; overflow: hidden; box-shadow: 0px 4px 40px 0px rgba(0, 0, 0, 0.05); + + &:hover { + ${CheckBoxWrap} { + display: flex; + } + } `; -export const Content = styled.div` +export const Content = styled(Link)` + text-decoration: none; display: flex; flex-direction: column; padding: 24px 20px; @@ -42,36 +87,9 @@ export const ChipWrap = styled.div` flex-wrap: wrap; `; -export const CheckBox = styled.input` - appearance: none; - -webkit-appearance: none; - -moz-appearance: none; - - width: 24px; - height: 24px; - border-radius: 50%; - background-color: ${theme.color.gray300}; - background-image: url(${checkIcon}); - background-repeat: no-repeat; - background-position: center; - border: 1.5px solid ${theme.color.white}; - color: ${theme.color.white}; - - position: absolute; - margin-left: 252px; - margin-top: 13px; - - &:checked { - border: 1.5px solid ${theme.color.green300}; - background-color: ${theme.color.green300}; - background-image: url(${checkedIcon}); - background-repeat: no-repeat; - background-position: center; - } -`; - -export const Image = styled.img` - &:hover { - filter: brightness(50%); - } +export const Image = styled.div<{ source: string }>` + background-image: url(${(props) => props.source}); + width: 290px; + height: 163px; + background-size: 100%; `; From fe5e7a4442ac177ddd7d69afa7039c1a9ab9b6b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8C=E1=85=A5=E1=86=BC=E1=84=89=E1=85=A5=E1=86=BC?= =?UTF-8?q?=E1=84=92=E1=85=B1?= Date: Mon, 12 Feb 2024 22:40:18 +0900 Subject: [PATCH 06/21] =?UTF-8?q?feature-059:=20=EC=86=8C=EC=85=9C=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=ED=9B=84=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/social-account.ts | 5 ++++- src/pages/SocialAccountPage.tsx | 9 ++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/apis/social-account.ts b/src/apis/social-account.ts index 84670be..1159a81 100644 --- a/src/apis/social-account.ts +++ b/src/apis/social-account.ts @@ -1,5 +1,8 @@ +import { APIResponse } from '@/models/config/axios'; +import { LoginResponse } from '@/models/user'; + import axios from './config/instance'; export const kakaoLoginAPI = (code: string) => { - return axios.get(`/kakao-login?code=${code}`); + return axios.get>(`/kakao-login?code=${code}`); }; diff --git a/src/pages/SocialAccountPage.tsx b/src/pages/SocialAccountPage.tsx index 49e8293..e8014a6 100644 --- a/src/pages/SocialAccountPage.tsx +++ b/src/pages/SocialAccountPage.tsx @@ -1,15 +1,22 @@ import { useEffect } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; +import { useSetRecoilState } from 'recoil'; import { kakaoLoginAPI } from '@/apis/social-account'; +import { userTokenState } from '@/stores/user'; + const SocialAccountPage = () => { const navigate = useNavigate(); const { search } = useLocation(); + const setUserToken = useSetRecoilState(userTokenState); const callAPI = async (code: string) => { try { - console.log(await kakaoLoginAPI(code)); + const { token } = (await kakaoLoginAPI(code)).data.result; + + setUserToken(token); + navigate('/'); } catch (e) { console.error(e); navigate('/sign-in'); From 36a4af69041d9b7cd8e07da5cc7ac3e7f86c5689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8C=E1=85=A5=E1=86=BC=E1=84=89=E1=85=A5=E1=86=BC?= =?UTF-8?q?=E1=84=92=E1=85=B1?= Date: Tue, 13 Feb 2024 01:27:59 +0900 Subject: [PATCH 07/21] =?UTF-8?q?feature-059:=20API=20=EC=9A=94=EC=B2=AD?= =?UTF-8?q?=20=EC=8B=9C=20Client-Host=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/config/instance.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/apis/config/instance.ts b/src/apis/config/instance.ts index 1bdae5f..d650d54 100644 --- a/src/apis/config/instance.ts +++ b/src/apis/config/instance.ts @@ -10,6 +10,7 @@ const axiosInstance = axios.create({ baseURL }); axiosInstance.interceptors.request.use((config) => { config.withCredentials = true; config.headers['Access-Control-Allow-Origin'] = '*'; + config.headers['Client-Host'] = location.origin; if (localStorage.vino) { const storage = JSON.parse(localStorage.vino); From 928790efc8ba5b3deedb13abbeb3f58e97fbd01e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8C=E1=85=A5=E1=86=BC=E1=84=89=E1=85=A5=E1=86=BC?= =?UTF-8?q?=E1=84=92=E1=85=B1?= Date: Tue, 13 Feb 2024 13:49:25 +0900 Subject: [PATCH 08/21] =?UTF-8?q?feature-059:=20Client-Host=20=EB=A1=A4?= =?UTF-8?q?=EB=B0=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/config/instance.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/apis/config/instance.ts b/src/apis/config/instance.ts index d650d54..1bdae5f 100644 --- a/src/apis/config/instance.ts +++ b/src/apis/config/instance.ts @@ -10,7 +10,6 @@ const axiosInstance = axios.create({ baseURL }); axiosInstance.interceptors.request.use((config) => { config.withCredentials = true; config.headers['Access-Control-Allow-Origin'] = '*'; - config.headers['Client-Host'] = location.origin; if (localStorage.vino) { const storage = JSON.parse(localStorage.vino); From 0f920b55acb82b6f589336f9d713dd4ddfe7199b Mon Sep 17 00:00:00 2001 From: gs0428 Date: Tue, 13 Feb 2024 14:49:31 +0900 Subject: [PATCH 09/21] =?UTF-8?q?feature-060:=20=EC=B9=B4=ED=85=8C?= =?UTF-8?q?=EA=B3=A0=EB=A6=AC=20=EC=9D=B4=EB=8F=99=20API=20=EC=97=B0?= =?UTF-8?q?=EB=8F=99=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/category/Card.tsx | 5 +- .../layout/header/profile/ProfileDetail.tsx | 1 + src/components/layout/sideBar/UserMode.tsx | 15 +++-- src/hooks/useMoveCategory.ts | 63 +++---------------- 4 files changed, 21 insertions(+), 63 deletions(-) diff --git a/src/components/category/Card.tsx b/src/components/category/Card.tsx index f07f41c..4e97d49 100644 --- a/src/components/category/Card.tsx +++ b/src/components/category/Card.tsx @@ -1,5 +1,6 @@ import React, { useEffect } from 'react'; import * as CardStyles from '@/styles/category/Card.style'; +import VideoTag from '../common/videoTag'; export interface IVideoProps { video_id: number; @@ -60,14 +61,14 @@ const Card: React.FC = ({ {video.description} - {/* {video.tag.map((tag) => ( + {video.tag.map((tag) => ( - ))} */} + ))}
diff --git a/src/components/layout/header/profile/ProfileDetail.tsx b/src/components/layout/header/profile/ProfileDetail.tsx index 13b5c6f..44a54cd 100644 --- a/src/components/layout/header/profile/ProfileDetail.tsx +++ b/src/components/layout/header/profile/ProfileDetail.tsx @@ -27,6 +27,7 @@ const ProfileDetail = ({ onClose }: Props) => { const handleClickLogoutButton = () => { setUserToken(null); + navigate('/'); onClose(); }; diff --git a/src/components/layout/sideBar/UserMode.tsx b/src/components/layout/sideBar/UserMode.tsx index 9b5fe42..b2ed517 100644 --- a/src/components/layout/sideBar/UserMode.tsx +++ b/src/components/layout/sideBar/UserMode.tsx @@ -47,16 +47,21 @@ const UserMode = () => { }; const putCategoryFolder = async () => { + let response; if (grabedCategory.current?.topCategoryId === -1) { - subToTop(topId, grabedCategory, dropedCategory); + response = await subToTop(grabedCategory); } else if (grabedCategory.current?.topCategoryId === null) { - topToOtherTop(grabedCategory, dropedCategory); + response = await topToOtherTop(grabedCategory, dropedCategory); } else { - subToOtherTop(topId, grabedCategory); + response = await subToOtherTop(topId, grabedCategory); } // 잡은 카테고리, 놓은 카테고리 초기화 - grabedCategory.current = undefined; - dropedCategory.current = undefined; + if (response) { + grabedCategory.current = undefined; + dropedCategory.current = undefined; + } else { + alert('카테고리를 옮기는데 오류가 발생했습니다.'); + } }; return ( <> diff --git a/src/hooks/useMoveCategory.ts b/src/hooks/useMoveCategory.ts index 0b19138..3be900b 100644 --- a/src/hooks/useMoveCategory.ts +++ b/src/hooks/useMoveCategory.ts @@ -3,23 +3,13 @@ import { putSubToTop, putTopToOtherTop, } from '@/apis/category'; -import { categoryState } from '@/stores/category'; -import handleCategory from '@/utils/handleCategory'; import { useNavigate } from 'react-router-dom'; -import { useRecoilState } from 'recoil'; import { ISubFolderProps } from 'types/category'; import useUpdateCategories from './useUpdateCategories'; const useMoveCategory = () => { - const [categories, setCategories] = useRecoilState(categoryState); const navigate = useNavigate(); const { updateCategories } = useUpdateCategories(); - const { - deleteSubCategory, - deleteTopCategory, - insertCategory, - insertSubToTopCategory, - } = handleCategory(); const subToOtherTop = async ( topId: number, @@ -31,33 +21,20 @@ const useMoveCategory = () => { } // 하위에 있는 폴더를 다른 상위 폴더로 이동하는 기능 // 카테고리 이동1 - const deleteResponse = deleteSubCategory( - categories, - topId, - grabedCategory.current?.categoryId, - ); - const insertResponse = insertCategory( - deleteResponse, - grabedCategory.current?.topCategoryId, - grabedCategory.current!, - ); const res = await putSubToOtherTop( grabedCategory.current!.categoryId, topId, ); + console.log(res); if (res.isSuccess) { - updateCategories(); - setCategories([...insertResponse]); + await updateCategories(); navigate(`/category/${grabedCategory.current?.topCategoryId}`); - } else { - alert('카테고리를 옮기는데 오류가 발생했습니다.'); } + return res.isSuccess; }; const subToTop = async ( - topId: number, grabedCategory: React.MutableRefObject, - dropedCategory: React.MutableRefObject, ) => { if (grabedCategory.current?.name === '기타') { alert(`'기타' 폴더는 이동할 수 없습니다.`); @@ -65,23 +42,11 @@ const useMoveCategory = () => { } // 하위에 있는 폴더를 상위로 올리는 기능 // 카테고리 이동2 - const deleteResponse = deleteSubCategory( - categories, - topId, - grabedCategory.current?.categoryId, - ); - const insertResponse = insertSubToTopCategory( - deleteResponse, - dropedCategory.current, - grabedCategory.current!, - ); const res = await putSubToTop(grabedCategory.current!.categoryId); if (res.isSuccess) { - updateCategories(); - setCategories([...insertResponse]); - } else { - alert('카테고리를 옮기는데 오류가 발생했습니다.'); + await updateCategories(); } + return res.isSuccess; }; const topToOtherTop = async ( @@ -90,29 +55,15 @@ const useMoveCategory = () => { ) => { // 상위에 있는 폴더를 다른 상위 폴더로 넣는 기능 // 카테고리 이동3 - const deleteResponse = deleteTopCategory( - categories, - grabedCategory.current!.categoryId, - ); - const insertResponse = insertCategory( - deleteResponse, - dropedCategory.current!, - { - categoryId: grabedCategory.current!.categoryId, - name: grabedCategory.current!.name, - topCategoryId: dropedCategory.current!, - }, - ); const res = await putTopToOtherTop( grabedCategory.current!.categoryId, dropedCategory.current!, ); if (res.isSuccess) { - setCategories(insertResponse); + await updateCategories(); navigate(`/category/${dropedCategory.current}`); - } else { - alert('카테고리를 옮기는데 오류가 발생했습니다.'); } + return res.isSuccess; }; return { subToOtherTop, subToTop, topToOtherTop }; From 039f80230eda3a716974028c7776988fa9a7812f Mon Sep 17 00:00:00 2001 From: gs0428 Date: Tue, 13 Feb 2024 15:34:24 +0900 Subject: [PATCH 10/21] =?UTF-8?q?feature-060:=20=EB=B9=84=EB=94=94?= =?UTF-8?q?=EC=98=A4=20=EC=82=AD=EC=A0=9C=20API=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/videos.ts | 8 ++++++++ src/pages/CategoryPage.tsx | 29 ++++++++++++++++++++--------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/apis/videos.ts b/src/apis/videos.ts index 9fea94c..6cf2828 100644 --- a/src/apis/videos.ts +++ b/src/apis/videos.ts @@ -2,6 +2,7 @@ import { APIResponse } from '@/models/config/axios'; import { IVideo, VideoVersionType } from '@/models/video'; import axios from './config/instance'; +import axiosInstance from './config/instance'; const PREFIX = '/videos'; @@ -11,3 +12,10 @@ export const getVideoAPI = ( ) => { return axios.get>(PREFIX + `/${videoId}/${versionId}`); }; + +export const deleteVideos = async (videos: number[]) => { + const response = await axiosInstance.delete('/videos/selectDelete', { + data: { videos }, + }); + return response.data; +}; diff --git a/src/pages/CategoryPage.tsx b/src/pages/CategoryPage.tsx index 8e8167d..a11a17f 100644 --- a/src/pages/CategoryPage.tsx +++ b/src/pages/CategoryPage.tsx @@ -13,6 +13,7 @@ import { useRecoilValue } from 'recoil'; import { categoryState } from '@/stores/category'; import { ISubFolderProps } from 'types/category'; import EmptyCard from '@/components/category/EmptyCard'; +import { deleteVideos } from '@/apis/videos'; const CategoryPage = () => { const params = useParams(); @@ -46,11 +47,22 @@ const CategoryPage = () => { } }, [categories, params.top_folder]); - const allCheckBtnHandler = () => { - if (checkedVideos.length === videos.length) { - // 삭제 API 요청 - console.log('모두 삭제'); + const handleDeleteVideos = async () => { + const res = await deleteVideos(checkedVideos); + if (res.isSuccess) { + const existVideos = videos.filter( + (video) => !checkedVideos.includes(video.video_id), + ); + setVideos(existVideos); setCheckedVideos([]); + } else { + alert('비디오를 삭제하는데 실패했습니다.'); + } + }; + + const allCheckBtnHandler = async () => { + if (checkedVideos.length === videos.length) { + handleDeleteVideos(); } else { console.log('모두 선택'); setCheckedVideos(videos.map((video) => video.video_id)); @@ -60,10 +72,7 @@ const CategoryPage = () => { const dirMoveHanlder = () => { console.log(checkedVideos); }; - - const garbageHandler = () => { - console.log(checkedVideos); - }; + console.log(videos); return ( @@ -90,7 +99,9 @@ const CategoryPage = () => { - + From 1002b6b44a6c26d90f3f915689dc3a3710a4582c Mon Sep 17 00:00:00 2001 From: gs0428 Date: Mon, 12 Feb 2024 16:02:02 +0900 Subject: [PATCH 11/21] =?UTF-8?q?feature-060:=20=EC=82=AC=EC=9D=B4?= =?UTF-8?q?=EB=93=9C=EB=B0=94=20=EC=8A=A4=ED=83=80=EC=9D=BC=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 --- src/styles/layout/sideBar/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/styles/layout/sideBar/index.ts b/src/styles/layout/sideBar/index.ts index be25c00..bba5b70 100644 --- a/src/styles/layout/sideBar/index.ts +++ b/src/styles/layout/sideBar/index.ts @@ -5,8 +5,9 @@ export const Container = styled.div` display: flex; flex-direction: column; margin: 60px 0px 0px 60px; + padding-right: 20px; width: 288px; - box-shadow: 4px 0px 40px 0px rgba(0, 0, 0, 0.05); + box-shadow: 4px 0px 10px rgba(0, 0, 0, 0.05); z-index: 0; `; From 089ae2e47a9c72b67e5f7a943734a925a4d1dcb2 Mon Sep 17 00:00:00 2001 From: gs0428 Date: Mon, 12 Feb 2024 16:24:59 +0900 Subject: [PATCH 12/21] =?UTF-8?q?feature-060:=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=ED=9B=84=20=EC=B9=B4=ED=85=8C=EA=B3=A0=EB=A6=AC=20?= =?UTF-8?q?=EC=82=AC=EC=9D=B4=EB=93=9C=20=EB=B0=94=20=EC=B5=9C=EC=8B=A0?= =?UTF-8?q?=ED=99=94=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/SignInPage.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/SignInPage.tsx b/src/pages/SignInPage.tsx index 5af90c3..116592f 100644 --- a/src/pages/SignInPage.tsx +++ b/src/pages/SignInPage.tsx @@ -22,6 +22,7 @@ import { LoginRequest } from '@/models/user'; import { userTokenState } from '@/stores/user'; import { BlurBackground } from '@/styles/modals/common.style'; +import useUpdateCategories from '@/hooks/useUpdateCategories'; const SignInPage: React.FC = () => { const navigate = useNavigate(); @@ -30,6 +31,7 @@ const SignInPage: React.FC = () => { const [isOpenErrorModal, setIsOpenErrorModal] = useState(false); const [isOpenSignUpModal, setIsOpenSignUpModal] = useState(false); const setUserToken = useSetRecoilState(userTokenState); + const { updateCategories } = useUpdateCategories(); const [loginInfo, setLoginInfo] = useState({ email: '', @@ -63,7 +65,7 @@ const SignInPage: React.FC = () => { const handleClickLoginButton = async () => { try { const { token } = (await loginAPI(loginInfo)).data.result; - + await updateCategories(); setUserToken(token); navigate('/'); } catch (error) { From 2b2510ccd5c43a2900974b6b5c6a06a140316145 Mon Sep 17 00:00:00 2001 From: gs0428 Date: Mon, 12 Feb 2024 16:33:58 +0900 Subject: [PATCH 13/21] =?UTF-8?q?feature-060:=20=EC=98=81=EC=83=81=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC=ED=95=B4=EB=B3=B4=EA=B8=B0=20=ED=81=B4?= =?UTF-8?q?=EB=A6=AD=20=EC=8B=9C=20=ED=99=88=EC=9C=BC=EB=A1=9C=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/category/EmptyCard.tsx | 2 +- src/hooks/useMoveCategory.ts | 42 ++++++++++++++++++-------- src/styles/category/EmptyCard.style.ts | 7 +++-- 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/src/components/category/EmptyCard.tsx b/src/components/category/EmptyCard.tsx index 1278d61..5febd81 100644 --- a/src/components/category/EmptyCard.tsx +++ b/src/components/category/EmptyCard.tsx @@ -13,7 +13,7 @@ const EmptyCard = () => { 관련 영상들을 모아보세요 - 영상 정리해보기 + 영상 정리해보기 ); }; diff --git a/src/hooks/useMoveCategory.ts b/src/hooks/useMoveCategory.ts index 4902cc5..0b19138 100644 --- a/src/hooks/useMoveCategory.ts +++ b/src/hooks/useMoveCategory.ts @@ -8,10 +8,12 @@ import handleCategory from '@/utils/handleCategory'; import { useNavigate } from 'react-router-dom'; import { useRecoilState } from 'recoil'; import { ISubFolderProps } from 'types/category'; +import useUpdateCategories from './useUpdateCategories'; const useMoveCategory = () => { const [categories, setCategories] = useRecoilState(categoryState); const navigate = useNavigate(); + const { updateCategories } = useUpdateCategories(); const { deleteSubCategory, deleteTopCategory, @@ -19,7 +21,7 @@ const useMoveCategory = () => { insertSubToTopCategory, } = handleCategory(); - const subToOtherTop = ( + const subToOtherTop = async ( topId: number, grabedCategory: React.MutableRefObject, ) => { @@ -39,13 +41,20 @@ const useMoveCategory = () => { grabedCategory.current?.topCategoryId, grabedCategory.current!, ); - putSubToOtherTop(grabedCategory.current!.categoryId, topId); - setCategories([...insertResponse]); - navigate(`/category/${grabedCategory.current?.topCategoryId}`); - console.log(grabedCategory.current?.name); + const res = await putSubToOtherTop( + grabedCategory.current!.categoryId, + topId, + ); + if (res.isSuccess) { + updateCategories(); + setCategories([...insertResponse]); + navigate(`/category/${grabedCategory.current?.topCategoryId}`); + } else { + alert('카테고리를 옮기는데 오류가 발생했습니다.'); + } }; - const subToTop = ( + const subToTop = async ( topId: number, grabedCategory: React.MutableRefObject, dropedCategory: React.MutableRefObject, @@ -66,11 +75,16 @@ const useMoveCategory = () => { dropedCategory.current, grabedCategory.current!, ); - putSubToTop(grabedCategory.current!.categoryId); - setCategories([...insertResponse]); + const res = await putSubToTop(grabedCategory.current!.categoryId); + if (res.isSuccess) { + updateCategories(); + setCategories([...insertResponse]); + } else { + alert('카테고리를 옮기는데 오류가 발생했습니다.'); + } }; - const topToOtherTop = ( + const topToOtherTop = async ( grabedCategory: React.MutableRefObject, dropedCategory: React.MutableRefObject, ) => { @@ -89,12 +103,16 @@ const useMoveCategory = () => { topCategoryId: dropedCategory.current!, }, ); - putTopToOtherTop( + const res = await putTopToOtherTop( grabedCategory.current!.categoryId, dropedCategory.current!, ); - setCategories(insertResponse); - navigate(`/category/${dropedCategory.current}`); + if (res.isSuccess) { + setCategories(insertResponse); + navigate(`/category/${dropedCategory.current}`); + } else { + alert('카테고리를 옮기는데 오류가 발생했습니다.'); + } }; return { subToOtherTop, subToTop, topToOtherTop }; diff --git a/src/styles/category/EmptyCard.style.ts b/src/styles/category/EmptyCard.style.ts index 4d07b2d..547027d 100644 --- a/src/styles/category/EmptyCard.style.ts +++ b/src/styles/category/EmptyCard.style.ts @@ -1,5 +1,6 @@ import styled from 'styled-components'; import theme from '../theme'; +import { Link } from 'react-router-dom'; export const Container = styled.div` display: flex; @@ -17,11 +18,11 @@ export const Content = styled.p` ${theme.typography.Subheader2} `; -export const Button = styled.button` - cursor: pointer; - border: 0; +export const Button = styled(Link)` background-color: ${theme.color.gray500}; color: ${theme.color.white}; + text-decoration: none; + text-align: center; border-radius: 100px; padding: 12px 32px; ${theme.typography.Subheader2} From f7a99403729c4c0c078ef2fc250fe4df40429f6c Mon Sep 17 00:00:00 2001 From: gs0428 Date: Mon, 12 Feb 2024 17:32:04 +0900 Subject: [PATCH 14/21] =?UTF-8?q?feature-060:=20=EC=B9=B4=EB=93=9C=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Home/InsightVideos.tsx | 6 +- src/components/category/Card.tsx | 90 +++++++++------------------ src/pages/CategoryPage.tsx | 37 +++++------ src/styles/category/Card.style.ts | 84 +++++++++++++++---------- 4 files changed, 102 insertions(+), 115 deletions(-) diff --git a/src/components/Home/InsightVideos.tsx b/src/components/Home/InsightVideos.tsx index 6075a38..254e0d1 100644 --- a/src/components/Home/InsightVideos.tsx +++ b/src/components/Home/InsightVideos.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import { InsightVideosContainer } from '@/styles/HomepageStyle'; import Card from '../category/Card'; -import { cardDummy } from '../category/Card'; +import { IVideoProps } from '../category/Card'; interface InsightVideosProps { username: string; @@ -13,8 +13,8 @@ const InsightVideos: React.FC = ({ popularHashtags, }) => { const formattedHashtags = popularHashtags.map((tag) => '#' + tag); - const [categoryItems] = useState([]); - const [checkedItems, setCheckedItems] = useState([]); + const [categoryItems] = useState([]); + const [checkedItems, setCheckedItems] = useState([]); return ( diff --git a/src/components/category/Card.tsx b/src/components/category/Card.tsx index 7239bc4..f07f41c 100644 --- a/src/components/category/Card.tsx +++ b/src/components/category/Card.tsx @@ -1,8 +1,7 @@ -import React, { useEffect, useState } from 'react'; -import VideoTag from '../common/videoTag'; +import React, { useEffect } from 'react'; import * as CardStyles from '@/styles/category/Card.style'; -export interface cardDummy { +export interface IVideoProps { video_id: number; category_id: number; title: string; @@ -15,9 +14,9 @@ export interface cardDummy { } interface ICardProps { - videos: cardDummy[]; - checkedVideos: boolean[]; - setCheckedVideos: (value: boolean[]) => void; + videos: IVideoProps[]; + checkedVideos: number[]; + setCheckedVideos: (value: number[]) => void; } const Card: React.FC = ({ @@ -25,62 +24,35 @@ const Card: React.FC = ({ checkedVideos, setCheckedVideos, }) => { - const [isShadow, setIsShadow] = useState(new Array(6).fill(false)); + useEffect(() => {}, [checkedVideos]); - useEffect(() => { - if (checkedVideos.includes(true)) { - // 1개 이상 클릭 시 모든 hover event 활성화 - setIsShadow(isShadow.map(() => true)); - } else if (!isShadow.includes(false)) { - //모든 hover 활성화, 모든 체크 비활성화 시 모든 hover 활성화 제거 - setIsShadow(isShadow.map(() => false)); - } - }, [checkedVideos]); - - const handleMouseEnter = (id: number) => { - const prev = checkedVideos.includes(true) - ? [...isShadow] - : new Array(isShadow.length).fill(false); - // 체크박스 미선택 이동 시 isshadow 중복 작동으로 인해 방식 변경 - prev[id] = true; - setIsShadow(prev); - }; - - const handleMouseLeave = (id: number) => { - if (!checkedVideos.includes(true)) { - // 선택되면 유지 - const prev = [...isShadow]; - prev[id] = false; - setIsShadow(prev); + const handleCheckBox = (videoId: number) => { + if (checkedVideos.includes(videoId)) { + setCheckedVideos(checkedVideos.filter((id) => id !== videoId)); + } else { + setCheckedVideos([...checkedVideos, videoId]); } }; - - const checkBoxHandler = (id: number) => { - const prev = [...checkedVideos]; - prev[id] = !prev[id]; - setCheckedVideos(prev); - }; return ( - {videos.map((video, idx) => ( - handleMouseEnter(idx)} - onMouseLeave={() => handleMouseLeave(idx)} - > - - {isShadow[idx] && ( - checkBoxHandler(idx)} - /> - )} - + {videos.map((video) => ( + + + 0 ? 'activated' : ''} + > + handleCheckBox(video.video_id)} + /> + + + + {video.title} @@ -88,14 +60,14 @@ const Card: React.FC = ({ {video.description} - {video.tag.map((tag) => ( + {/* {video.tag.map((tag) => ( - ))} + ))} */} diff --git a/src/pages/CategoryPage.tsx b/src/pages/CategoryPage.tsx index eda9aa3..8e8167d 100644 --- a/src/pages/CategoryPage.tsx +++ b/src/pages/CategoryPage.tsx @@ -7,7 +7,7 @@ import GarbageSvg from '@/assets/icons/garbage.svg?react'; import FolderSvg from '@/assets/icons/open-file.svg?react'; import CloseSvg from '@/assets/icons/close.svg?react'; import * as CategoryPageStyles from '@/styles/category/index.style'; -import Card from '@/components/category/Card'; +import Card, { IVideoProps } from '@/components/category/Card'; import axiosInstance from '@/apis/config/instance'; import { useRecoilValue } from 'recoil'; import { categoryState } from '@/stores/category'; @@ -18,9 +18,9 @@ const CategoryPage = () => { const params = useParams(); const [name, setName] = useState(''); const [menus, setMenus] = useState([]); - const [videos, setVideos] = useState([]); + const [videos, setVideos] = useState([]); const [recentRegisterMode, setRecentRegisterMode] = useState(false); - const [checkedVideos, setCheckedVideos] = useState([]); + const [checkedVideos, setCheckedVideos] = useState([]); const categories = useRecoilValue(categoryState); const toggleRecentRegisterMode = () => @@ -47,41 +47,38 @@ const CategoryPage = () => { }, [categories, params.top_folder]); const allCheckBtnHandler = () => { - if (checkedVideos.includes(false)) { - setCheckedVideos(checkedVideos.map(() => true)); + if (checkedVideos.length === videos.length) { + // 삭제 API 요청 + console.log('모두 삭제'); + setCheckedVideos([]); } else { - // 모두 삭제 + console.log('모두 선택'); + setCheckedVideos(videos.map((video) => video.video_id)); } }; const dirMoveHanlder = () => { - checkedVideos.map((value, id) => { - if (value === true) { - console.log('이동해야할 index : ', id); - } - }); + console.log(checkedVideos); }; const garbageHandler = () => { - checkedVideos.map((value, id) => { - if (value === true) { - console.log('삭제해야할 index : ', id); - } - }); + console.log(checkedVideos); }; return ( - {checkedVideos.includes(true) ? ( + {checkedVideos.length > 0 ? ( <>
- {!checkedVideos.includes(false) ? '모두 삭제' : '모두 선택'} + {checkedVideos.length === videos.length + ? '모두 삭제' + : '모두 선택'} - {checkedVideos.filter((bool) => bool === true).length}개 선택 + {checkedVideos.length}개 선택
@@ -101,7 +98,7 @@ const CategoryPage = () => { width={28} height={28} onClick={() => { - setCheckedVideos(checkedVideos.map(() => false)); + setCheckedVideos([]); }} />
diff --git a/src/styles/category/Card.style.ts b/src/styles/category/Card.style.ts index e18abd1..1a0f975 100644 --- a/src/styles/category/Card.style.ts +++ b/src/styles/category/Card.style.ts @@ -2,7 +2,45 @@ import styled from 'styled-components'; import theme from '../theme'; import checkIcon from '@/assets/icons/check.svg'; import checkedIcon from '@/assets/icons/checked.svg'; +import { Link } from 'react-router-dom'; +export const CheckBoxWrap = styled.div` + background-color: rgba(0, 0, 0, 0.5); + display: none; + + flex-direction: row-reverse; + width: 100%; + height: 100%; + + &.activated { + display: flex; + } +`; + +export const CheckBox = styled.input` + appearance: none; + -webkit-appearance: none; + -moz-appearance: none; + + width: 24px; + height: 24px; + border-radius: 100%; + background-color: ${theme.color.gray300}; + background-image: url(${checkIcon}); + background-repeat: no-repeat; + background-position: center; + border: 1.5px solid ${theme.color.white}; + color: ${theme.color.white}; + margin: 12px; + + &:checked { + border: 1.5px solid ${theme.color.green300}; + background-color: ${theme.color.green300}; + background-image: url(${checkedIcon}); + background-repeat: no-repeat; + background-position: center; + } +`; export const Container = styled.div` display: grid; grid-template-columns: repeat(3, auto); @@ -17,9 +55,16 @@ export const Wrap = styled.div` border-radius: 16px; overflow: hidden; box-shadow: 0px 4px 40px 0px rgba(0, 0, 0, 0.05); + + &:hover { + ${CheckBoxWrap} { + display: flex; + } + } `; -export const Content = styled.div` +export const Content = styled(Link)` + text-decoration: none; display: flex; flex-direction: column; padding: 24px 20px; @@ -42,36 +87,9 @@ export const ChipWrap = styled.div` flex-wrap: wrap; `; -export const CheckBox = styled.input` - appearance: none; - -webkit-appearance: none; - -moz-appearance: none; - - width: 24px; - height: 24px; - border-radius: 50%; - background-color: ${theme.color.gray300}; - background-image: url(${checkIcon}); - background-repeat: no-repeat; - background-position: center; - border: 1.5px solid ${theme.color.white}; - color: ${theme.color.white}; - - position: absolute; - margin-left: 252px; - margin-top: 13px; - - &:checked { - border: 1.5px solid ${theme.color.green300}; - background-color: ${theme.color.green300}; - background-image: url(${checkedIcon}); - background-repeat: no-repeat; - background-position: center; - } -`; - -export const Image = styled.img` - &:hover { - filter: brightness(50%); - } +export const Image = styled.div<{ source: string }>` + background-image: url(${(props) => props.source}); + width: 290px; + height: 163px; + background-size: 100%; `; From aae5f9ab93a4a00e674827e343b7658d3cda4cf1 Mon Sep 17 00:00:00 2001 From: gs0428 Date: Tue, 13 Feb 2024 14:49:31 +0900 Subject: [PATCH 15/21] =?UTF-8?q?feature-060:=20=EC=B9=B4=ED=85=8C?= =?UTF-8?q?=EA=B3=A0=EB=A6=AC=20=EC=9D=B4=EB=8F=99=20API=20=EC=97=B0?= =?UTF-8?q?=EB=8F=99=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/category/Card.tsx | 5 +- .../layout/header/profile/ProfileDetail.tsx | 1 + src/components/layout/sideBar/UserMode.tsx | 15 +++-- src/hooks/useMoveCategory.ts | 63 +++---------------- 4 files changed, 21 insertions(+), 63 deletions(-) diff --git a/src/components/category/Card.tsx b/src/components/category/Card.tsx index f07f41c..4e97d49 100644 --- a/src/components/category/Card.tsx +++ b/src/components/category/Card.tsx @@ -1,5 +1,6 @@ import React, { useEffect } from 'react'; import * as CardStyles from '@/styles/category/Card.style'; +import VideoTag from '../common/videoTag'; export interface IVideoProps { video_id: number; @@ -60,14 +61,14 @@ const Card: React.FC = ({ {video.description} - {/* {video.tag.map((tag) => ( + {video.tag.map((tag) => ( - ))} */} + ))} diff --git a/src/components/layout/header/profile/ProfileDetail.tsx b/src/components/layout/header/profile/ProfileDetail.tsx index 13b5c6f..44a54cd 100644 --- a/src/components/layout/header/profile/ProfileDetail.tsx +++ b/src/components/layout/header/profile/ProfileDetail.tsx @@ -27,6 +27,7 @@ const ProfileDetail = ({ onClose }: Props) => { const handleClickLogoutButton = () => { setUserToken(null); + navigate('/'); onClose(); }; diff --git a/src/components/layout/sideBar/UserMode.tsx b/src/components/layout/sideBar/UserMode.tsx index 9b5fe42..b2ed517 100644 --- a/src/components/layout/sideBar/UserMode.tsx +++ b/src/components/layout/sideBar/UserMode.tsx @@ -47,16 +47,21 @@ const UserMode = () => { }; const putCategoryFolder = async () => { + let response; if (grabedCategory.current?.topCategoryId === -1) { - subToTop(topId, grabedCategory, dropedCategory); + response = await subToTop(grabedCategory); } else if (grabedCategory.current?.topCategoryId === null) { - topToOtherTop(grabedCategory, dropedCategory); + response = await topToOtherTop(grabedCategory, dropedCategory); } else { - subToOtherTop(topId, grabedCategory); + response = await subToOtherTop(topId, grabedCategory); } // 잡은 카테고리, 놓은 카테고리 초기화 - grabedCategory.current = undefined; - dropedCategory.current = undefined; + if (response) { + grabedCategory.current = undefined; + dropedCategory.current = undefined; + } else { + alert('카테고리를 옮기는데 오류가 발생했습니다.'); + } }; return ( <> diff --git a/src/hooks/useMoveCategory.ts b/src/hooks/useMoveCategory.ts index 0b19138..3be900b 100644 --- a/src/hooks/useMoveCategory.ts +++ b/src/hooks/useMoveCategory.ts @@ -3,23 +3,13 @@ import { putSubToTop, putTopToOtherTop, } from '@/apis/category'; -import { categoryState } from '@/stores/category'; -import handleCategory from '@/utils/handleCategory'; import { useNavigate } from 'react-router-dom'; -import { useRecoilState } from 'recoil'; import { ISubFolderProps } from 'types/category'; import useUpdateCategories from './useUpdateCategories'; const useMoveCategory = () => { - const [categories, setCategories] = useRecoilState(categoryState); const navigate = useNavigate(); const { updateCategories } = useUpdateCategories(); - const { - deleteSubCategory, - deleteTopCategory, - insertCategory, - insertSubToTopCategory, - } = handleCategory(); const subToOtherTop = async ( topId: number, @@ -31,33 +21,20 @@ const useMoveCategory = () => { } // 하위에 있는 폴더를 다른 상위 폴더로 이동하는 기능 // 카테고리 이동1 - const deleteResponse = deleteSubCategory( - categories, - topId, - grabedCategory.current?.categoryId, - ); - const insertResponse = insertCategory( - deleteResponse, - grabedCategory.current?.topCategoryId, - grabedCategory.current!, - ); const res = await putSubToOtherTop( grabedCategory.current!.categoryId, topId, ); + console.log(res); if (res.isSuccess) { - updateCategories(); - setCategories([...insertResponse]); + await updateCategories(); navigate(`/category/${grabedCategory.current?.topCategoryId}`); - } else { - alert('카테고리를 옮기는데 오류가 발생했습니다.'); } + return res.isSuccess; }; const subToTop = async ( - topId: number, grabedCategory: React.MutableRefObject, - dropedCategory: React.MutableRefObject, ) => { if (grabedCategory.current?.name === '기타') { alert(`'기타' 폴더는 이동할 수 없습니다.`); @@ -65,23 +42,11 @@ const useMoveCategory = () => { } // 하위에 있는 폴더를 상위로 올리는 기능 // 카테고리 이동2 - const deleteResponse = deleteSubCategory( - categories, - topId, - grabedCategory.current?.categoryId, - ); - const insertResponse = insertSubToTopCategory( - deleteResponse, - dropedCategory.current, - grabedCategory.current!, - ); const res = await putSubToTop(grabedCategory.current!.categoryId); if (res.isSuccess) { - updateCategories(); - setCategories([...insertResponse]); - } else { - alert('카테고리를 옮기는데 오류가 발생했습니다.'); + await updateCategories(); } + return res.isSuccess; }; const topToOtherTop = async ( @@ -90,29 +55,15 @@ const useMoveCategory = () => { ) => { // 상위에 있는 폴더를 다른 상위 폴더로 넣는 기능 // 카테고리 이동3 - const deleteResponse = deleteTopCategory( - categories, - grabedCategory.current!.categoryId, - ); - const insertResponse = insertCategory( - deleteResponse, - dropedCategory.current!, - { - categoryId: grabedCategory.current!.categoryId, - name: grabedCategory.current!.name, - topCategoryId: dropedCategory.current!, - }, - ); const res = await putTopToOtherTop( grabedCategory.current!.categoryId, dropedCategory.current!, ); if (res.isSuccess) { - setCategories(insertResponse); + await updateCategories(); navigate(`/category/${dropedCategory.current}`); - } else { - alert('카테고리를 옮기는데 오류가 발생했습니다.'); } + return res.isSuccess; }; return { subToOtherTop, subToTop, topToOtherTop }; From 932d9725575ae06e8f7fa433fca229cc0b88726e Mon Sep 17 00:00:00 2001 From: gs0428 Date: Tue, 13 Feb 2024 15:34:24 +0900 Subject: [PATCH 16/21] =?UTF-8?q?feature-060:=20=EB=B9=84=EB=94=94?= =?UTF-8?q?=EC=98=A4=20=EC=82=AD=EC=A0=9C=20API=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/videos.ts | 8 ++++++++ src/pages/CategoryPage.tsx | 29 ++++++++++++++++++++--------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/apis/videos.ts b/src/apis/videos.ts index 9fea94c..6cf2828 100644 --- a/src/apis/videos.ts +++ b/src/apis/videos.ts @@ -2,6 +2,7 @@ import { APIResponse } from '@/models/config/axios'; import { IVideo, VideoVersionType } from '@/models/video'; import axios from './config/instance'; +import axiosInstance from './config/instance'; const PREFIX = '/videos'; @@ -11,3 +12,10 @@ export const getVideoAPI = ( ) => { return axios.get>(PREFIX + `/${videoId}/${versionId}`); }; + +export const deleteVideos = async (videos: number[]) => { + const response = await axiosInstance.delete('/videos/selectDelete', { + data: { videos }, + }); + return response.data; +}; diff --git a/src/pages/CategoryPage.tsx b/src/pages/CategoryPage.tsx index 8e8167d..a11a17f 100644 --- a/src/pages/CategoryPage.tsx +++ b/src/pages/CategoryPage.tsx @@ -13,6 +13,7 @@ import { useRecoilValue } from 'recoil'; import { categoryState } from '@/stores/category'; import { ISubFolderProps } from 'types/category'; import EmptyCard from '@/components/category/EmptyCard'; +import { deleteVideos } from '@/apis/videos'; const CategoryPage = () => { const params = useParams(); @@ -46,11 +47,22 @@ const CategoryPage = () => { } }, [categories, params.top_folder]); - const allCheckBtnHandler = () => { - if (checkedVideos.length === videos.length) { - // 삭제 API 요청 - console.log('모두 삭제'); + const handleDeleteVideos = async () => { + const res = await deleteVideos(checkedVideos); + if (res.isSuccess) { + const existVideos = videos.filter( + (video) => !checkedVideos.includes(video.video_id), + ); + setVideos(existVideos); setCheckedVideos([]); + } else { + alert('비디오를 삭제하는데 실패했습니다.'); + } + }; + + const allCheckBtnHandler = async () => { + if (checkedVideos.length === videos.length) { + handleDeleteVideos(); } else { console.log('모두 선택'); setCheckedVideos(videos.map((video) => video.video_id)); @@ -60,10 +72,7 @@ const CategoryPage = () => { const dirMoveHanlder = () => { console.log(checkedVideos); }; - - const garbageHandler = () => { - console.log(checkedVideos); - }; + console.log(videos); return ( @@ -90,7 +99,9 @@ const CategoryPage = () => { - + From 91310464e9ee2d3836e8d68a8d9e799fee1c2918 Mon Sep 17 00:00:00 2001 From: gs0428 Date: Tue, 13 Feb 2024 18:12:11 +0900 Subject: [PATCH 17/21] =?UTF-8?q?feature-062:=20=EC=B5=9C=EA=B7=BC=20?= =?UTF-8?q?=EC=9D=BD=EC=9D=80=20=EC=98=81=EC=83=81=20API=20=EC=97=B0?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/videos.ts | 15 +++++++++++++++ src/pages/CategoryPage.tsx | 31 +++++++++++++++---------------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/apis/videos.ts b/src/apis/videos.ts index 6cf2828..37a21a9 100644 --- a/src/apis/videos.ts +++ b/src/apis/videos.ts @@ -3,6 +3,7 @@ import { IVideo, VideoVersionType } from '@/models/video'; import axios from './config/instance'; import axiosInstance from './config/instance'; +import { IVideoProps } from '@/components/category/Card'; const PREFIX = '/videos'; @@ -19,3 +20,17 @@ export const deleteVideos = async (videos: number[]) => { }); return response.data; }; + +export const getRecentVideos = async (): Promise< + APIResponse> +> => { + const response = await axiosInstance.get('/videos/recent'); + return response.data; +}; + +export const getVideoById = async ( + videoId: number, +): Promise>> => { + const response = await axiosInstance.get(`/videos/${videoId}`); + return response.data; +}; diff --git a/src/pages/CategoryPage.tsx b/src/pages/CategoryPage.tsx index a11a17f..131674f 100644 --- a/src/pages/CategoryPage.tsx +++ b/src/pages/CategoryPage.tsx @@ -8,12 +8,11 @@ import FolderSvg from '@/assets/icons/open-file.svg?react'; import CloseSvg from '@/assets/icons/close.svg?react'; import * as CategoryPageStyles from '@/styles/category/index.style'; import Card, { IVideoProps } from '@/components/category/Card'; -import axiosInstance from '@/apis/config/instance'; import { useRecoilValue } from 'recoil'; import { categoryState } from '@/stores/category'; import { ISubFolderProps } from 'types/category'; import EmptyCard from '@/components/category/EmptyCard'; -import { deleteVideos } from '@/apis/videos'; +import { deleteVideos, getRecentVideos, getVideoById } from '@/apis/videos'; const CategoryPage = () => { const params = useParams(); @@ -30,20 +29,21 @@ const CategoryPage = () => { useEffect(() => { if (!params.top_folder) { // 최근 동영상 가져오는 로직 - setName('최근 읽은 영상'); + getRecentVideos() + .then((res) => { + setVideos(res.result.videos); + setName('최근 읽은 영상'); + }) + .catch((err) => console.log(err)); } else { - (async () => - await axiosInstance - .get(`/videos/${params.top_folder}`) - .then((res) => { - const index = categories.findIndex( - (category) => category.categoryId === Number(params.top_folder), - ); - setVideos(res.data.result.videos); - setName(categories[index].name); - setMenus(categories[index].subFolders); - }) - .catch((err) => console.log(err)))(); + getVideoById(Number(params.top_folder)).then((res) => { + const index = categories.findIndex( + (category) => category.categoryId === Number(params.top_folder), + ); + setVideos(res.result.videos); + setName(categories[index].name); + setMenus(categories[index].subFolders); + }); } }, [categories, params.top_folder]); @@ -72,7 +72,6 @@ const CategoryPage = () => { const dirMoveHanlder = () => { console.log(checkedVideos); }; - console.log(videos); return ( From bec7e11017b7b6fd231067f22ac4d89f7c04f10b Mon Sep 17 00:00:00 2001 From: gs0428 Date: Tue, 13 Feb 2024 18:13:57 +0900 Subject: [PATCH 18/21] =?UTF-8?q?feature-062:=EB=B9=84=EB=94=94=EC=98=A4?= =?UTF-8?q?=20type=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/videos.ts | 2 +- src/components/category/Card.tsx | 13 +------------ src/pages/CategoryPage.tsx | 3 ++- types/videos.ts | 11 +++++++++++ 4 files changed, 15 insertions(+), 14 deletions(-) create mode 100644 types/videos.ts diff --git a/src/apis/videos.ts b/src/apis/videos.ts index 37a21a9..9c649b1 100644 --- a/src/apis/videos.ts +++ b/src/apis/videos.ts @@ -3,7 +3,7 @@ import { IVideo, VideoVersionType } from '@/models/video'; import axios from './config/instance'; import axiosInstance from './config/instance'; -import { IVideoProps } from '@/components/category/Card'; +import { IVideoProps } from 'types/videos'; const PREFIX = '/videos'; diff --git a/src/components/category/Card.tsx b/src/components/category/Card.tsx index 4e97d49..1366a74 100644 --- a/src/components/category/Card.tsx +++ b/src/components/category/Card.tsx @@ -1,18 +1,7 @@ import React, { useEffect } from 'react'; import * as CardStyles from '@/styles/category/Card.style'; import VideoTag from '../common/videoTag'; - -export interface IVideoProps { - video_id: number; - category_id: number; - title: string; - description: string; - image: string; - link: string; - created_at: string; - youtube_created_at: string; - tag: [{ name: string }]; -} +import { IVideoProps } from 'types/videos'; interface ICardProps { videos: IVideoProps[]; diff --git a/src/pages/CategoryPage.tsx b/src/pages/CategoryPage.tsx index 131674f..fb4fc88 100644 --- a/src/pages/CategoryPage.tsx +++ b/src/pages/CategoryPage.tsx @@ -7,12 +7,13 @@ import GarbageSvg from '@/assets/icons/garbage.svg?react'; import FolderSvg from '@/assets/icons/open-file.svg?react'; import CloseSvg from '@/assets/icons/close.svg?react'; import * as CategoryPageStyles from '@/styles/category/index.style'; -import Card, { IVideoProps } from '@/components/category/Card'; +import Card from '@/components/category/Card'; import { useRecoilValue } from 'recoil'; import { categoryState } from '@/stores/category'; import { ISubFolderProps } from 'types/category'; import EmptyCard from '@/components/category/EmptyCard'; import { deleteVideos, getRecentVideos, getVideoById } from '@/apis/videos'; +import { IVideoProps } from 'types/videos'; const CategoryPage = () => { const params = useParams(); diff --git a/types/videos.ts b/types/videos.ts new file mode 100644 index 0000000..9dd7e32 --- /dev/null +++ b/types/videos.ts @@ -0,0 +1,11 @@ +export interface IVideoProps { + video_id: number; + category_id: number; + title: string; + description: string; + image: string; + link: string; + created_at: string; + youtube_created_at: string; + tag: [{ name: string }]; +} From 535eed3f41519487c240bd094caa7804acd556a6 Mon Sep 17 00:00:00 2001 From: gs0428 Date: Tue, 13 Feb 2024 18:47:35 +0900 Subject: [PATCH 19/21] =?UTF-8?q?feature-062:=20=EC=B5=9C=EA=B7=BC?= =?UTF-8?q?=EB=93=B1=EB=A1=9D=EC=88=9C/=EC=B5=9C=EA=B7=BC=EC=98=81?= =?UTF-8?q?=EC=83=81=EC=88=9C=20=EA=B8=B0=EC=A4=80=20=EC=A0=95=EB=A0=AC=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 --- src/pages/CategoryPage.tsx | 16 ++++++++++------ src/utils/sortVideos.ts | 21 +++++++++++++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 src/utils/sortVideos.ts diff --git a/src/pages/CategoryPage.tsx b/src/pages/CategoryPage.tsx index fb4fc88..609554f 100644 --- a/src/pages/CategoryPage.tsx +++ b/src/pages/CategoryPage.tsx @@ -14,6 +14,7 @@ import { ISubFolderProps } from 'types/category'; import EmptyCard from '@/components/category/EmptyCard'; import { deleteVideos, getRecentVideos, getVideoById } from '@/apis/videos'; import { IVideoProps } from 'types/videos'; +import { sortVideos } from '@/utils/sortVideos'; const CategoryPage = () => { const params = useParams(); @@ -27,9 +28,10 @@ const CategoryPage = () => { const toggleRecentRegisterMode = () => setRecentRegisterMode(!recentRegisterMode); + const sortedVideos = sortVideos(videos, recentRegisterMode); + useEffect(() => { if (!params.top_folder) { - // 최근 동영상 가져오는 로직 getRecentVideos() .then((res) => { setVideos(res.result.videos); @@ -76,13 +78,13 @@ const CategoryPage = () => { return ( - + {checkedVideos.length > 0 ? ( <>
- {checkedVideos.length === videos.length + {checkedVideos.length === sortedVideos.length ? '모두 삭제' : '모두 선택'} @@ -145,10 +147,12 @@ const CategoryPage = () => { )} - {(videos.length === 0 || videos === undefined) && } - {videos.length > 0 && ( + {(sortedVideos.length === 0 || sortedVideos === undefined) && ( + + )} + {sortedVideos.length > 0 && ( diff --git a/src/utils/sortVideos.ts b/src/utils/sortVideos.ts new file mode 100644 index 0000000..c711277 --- /dev/null +++ b/src/utils/sortVideos.ts @@ -0,0 +1,21 @@ +import { IVideoProps } from 'types/videos'; + +export const sortVideos = ( + videos: IVideoProps[], + isRecentRegisterMode: boolean, +) => { + const sortedVideos = videos.sort((prevVideo, nextVideo) => { + if ( + prevVideo[isRecentRegisterMode ? 'created_at' : 'youtube_created_at'] > + nextVideo[isRecentRegisterMode ? 'created_at' : 'youtube_created_at'] + ) + return 1; + if ( + prevVideo[isRecentRegisterMode ? 'created_at' : 'youtube_created_at'] === + nextVideo[isRecentRegisterMode ? 'created_at' : 'youtube_created_at'] + ) + return 0; + return -1; + }); + return sortedVideos; +}; From fdf928ab941980258a5e9faf09383b9cf69dc860 Mon Sep 17 00:00:00 2001 From: gs0428 Date: Tue, 13 Feb 2024 18:48:07 +0900 Subject: [PATCH 20/21] =?UTF-8?q?feature-062:=20=ED=8F=B4=EB=8D=94?= =?UTF-8?q?=EA=B0=80=20=EA=B0=99=EC=9D=80=20=EA=B3=B3=EC=97=90=20=EB=86=93?= =?UTF-8?q?=EC=95=84=EC=A7=88=20=EA=B2=BD=EC=9A=B0=20API=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EB=A7=89=EC=9D=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/layout/sideBar/UserMode.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/layout/sideBar/UserMode.tsx b/src/components/layout/sideBar/UserMode.tsx index b2ed517..7457cba 100644 --- a/src/components/layout/sideBar/UserMode.tsx +++ b/src/components/layout/sideBar/UserMode.tsx @@ -47,6 +47,8 @@ const UserMode = () => { }; const putCategoryFolder = async () => { + if (grabedCategory.current?.categoryId === dropedCategory.current) return; + let response; if (grabedCategory.current?.topCategoryId === -1) { response = await subToTop(grabedCategory); From 1b8e29845e9e2874791848a20c7c1dd0cf1e5099 Mon Sep 17 00:00:00 2001 From: gs0428 Date: Tue, 13 Feb 2024 18:50:30 +0900 Subject: [PATCH 21/21] =?UTF-8?q?feature-062:=20=EB=B9=A0=EC=A7=84=20type?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Home/InsightVideos.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Home/InsightVideos.tsx b/src/components/Home/InsightVideos.tsx index 254e0d1..5f3328a 100644 --- a/src/components/Home/InsightVideos.tsx +++ b/src/components/Home/InsightVideos.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import { InsightVideosContainer } from '@/styles/HomepageStyle'; import Card from '../category/Card'; -import { IVideoProps } from '../category/Card'; +import { IVideoProps } from 'types/videos'; interface InsightVideosProps { username: string;