Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature-067: 더미 영상 API 연동 #74

Merged
merged 6 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/apis/category.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const putSubToOtherTop = async (
topCategoryId: number,
) => {
const response = await axiosInstance.put(
`/category/${categoryId}/${topCategoryId}`,
`/category/move/${categoryId}/${topCategoryId}`,
);
return response.data;
};
Expand Down Expand Up @@ -72,3 +72,14 @@ export const updateCategoryName = async (name: string, categoryId: number) => {
const response = await axiosInstance.put(`/category/${categoryId}`, { name });
return response.data;
};

// 비디오의 카테고리 위치 수정 API
export const putVideoToOtherCategory = async (
videoId: number,
categoryId: number,
) => {
const response = await axiosInstance.patch(
`/videos/${videoId}/${categoryId}/update`,
);
return response.data;
};
18 changes: 18 additions & 0 deletions src/apis/videos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,21 @@ export const createVideoSummaryAPI = (videoId: number, content: string[]) => {
export const deleteVideoSummaryAPI = (summaryId: number) => {
return axios.delete<APIBaseResponse>(PREFIX + `/${summaryId}/deleteSummary`);
};

export const getDummyVideos = async (): Promise<
APIResponse<Record<'videos', IVideoProps[]>>
> => {
const response = await axiosInstance.get('/videos/dummyVideos/unRead');
return response.data;
};

export const createDummyVideoToMine = async (
videoId: number,
categoryId: number,
) => {
const response = await axiosInstance.post(
`/videos/dummyVideos/${videoId}/${categoryId}/newVideo`,
);

return response.data;
};
44 changes: 32 additions & 12 deletions src/components/Home/InsightVideos.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,53 @@ import Card from '../category/Card';
import { IVideoProps } from 'types/videos';
import { CardContainer } from '@/styles/category/Card.style';
import successImg from '@/assets/success.png';
import { createDummyVideoToMine, getDummyVideos } from '@/apis/videos';

interface InsightVideosProps {
username: string;
popularHashtags: string[];
dummyVideos: IVideoProps[];
setDummyVideos: React.Dispatch<React.SetStateAction<IVideoProps[]>>;
}

const InsightVideos: React.FC<InsightVideosProps> = ({
username,
popularHashtags,
dummyVideos,
setDummyVideos,
}) => {
const formattedHashtags = popularHashtags.map((tag) => '#' + tag);
const [categoryItems] = useState<IVideoProps[]>([]);
const [checkedItems, setCheckedItems] = useState<number[]>([]);
const [showEndMessage, setShowEndMessage] = useState(false);

const endBox = useRef<HTMLDivElement>(null);

const onFileClick = (e: React.MouseEvent) => {
const onFileClick = async (
e: React.MouseEvent,
videoId: number,
categoryId: number,
) => {
e.stopPropagation();
// 비디오 카테고리로 저장 API 호출 후 이런 인사이트는 어때요 API 재호출로 최신화하기
const res = await createDummyVideoToMine(videoId, categoryId);
if (res.isSuccess)
await getDummyVideos().then((res) => setDummyVideos(res.result.videos));
};

useEffect(() => {
const handleIntersect = (entries: IntersectionObserverEntry[]) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
setShowEndMessage(true);
setTimeout(() => {
const timer: NodeJS.Timeout = setTimeout(() => {
setShowEndMessage(false);
clearTimeout(timer);
}, 2000);
}
});
};

const observer = new IntersectionObserver(handleIntersect, {
threshold: 1.0,
threshold: 1.0,
});

const endBoxElement = endBox.current;
Expand All @@ -66,23 +77,32 @@ const InsightVideos: React.FC<InsightVideosProps> = ({
</div>
<div className="insight-videos">
<CardContainer>
{categoryItems.map((video) => (
{dummyVideos.map((video) => (
<Card
mode="recommend"
video={video}
checkedVideos={checkedItems}
setCheckedVideos={setCheckedItems}
onFileClick={onFileClick}
key={video.category_id}
key={video.video_id}
/>
))}
</CardContainer>
</div>
<div ref={endBox} className='end-message'>
<div className='end-wrapper' style={{ display: showEndMessage ? 'block' : 'none' }}>
<img src={successImg} alt='successImg' width={87.11} height={87.11}/>
<h4 className='end-text'>
마지막 영상이에요!<br />더 많은 영상 변환하러 가볼까요?
<div ref={endBox} className="end-message">
<div
className="end-wrapper"
style={{ display: showEndMessage ? 'block' : 'none' }}
>
<img
src={successImg}
alt="successImg"
width={87.11}
height={87.11}
/>
<h4 className="end-text">
마지막 영상이에요!
<br />더 많은 영상 변환하러 가볼까요?
</h4>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Home/RecentVideos.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const RecentVideos = ({ videos }: IRecentVideosProp) => {
{videos.length > 0 && (
<CardContainer>
{videos.slice(0, 3).map((video) => (
<Card key={video.category_id} mode="default" video={video} />
<Card key={video.video_id} mode="default" video={video} />
))}
</CardContainer>
)}
Expand Down
19 changes: 14 additions & 5 deletions src/components/category/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ interface ICardProps {
video: IVideoProps;
checkedVideos?: number[];
setCheckedVideos?: (value: number[]) => void;
onFileClick?: (e: React.MouseEvent) => void;
onFileClick?: (
e: React.MouseEvent,
videoId: number,
categoryId: number,
) => void;
}

const Card: React.FC<ICardProps> = ({
Expand All @@ -31,6 +35,9 @@ const Card: React.FC<ICardProps> = ({
category.length ? category[0].categoryId : -1,
);

const onFileClickWithProps = (e: React.MouseEvent) =>
onFileClick && onFileClick(e, video.video_id, selectedCategoryId);

const handleSelectCategory = (categoryId: number) => {
setSelectedCategoryId(categoryId);
};
Expand All @@ -44,10 +51,12 @@ const Card: React.FC<ICardProps> = ({
};
return (
<CardStyles.Wrap
mode={mode}
onMouseEnter={() => setIsOpen(true)}
onMouseLeave={() => setIsOpen(false)}
>
<CardStyles.Image source={video.image}>
<div style={{ display: 'flex' }}>
<CardStyles.Image src={video.image} alt="카드 이미지" />
{mode === 'category' && (
<CardStyles.CheckBoxWrap
className={checkedVideos!.length > 0 ? 'activated' : ''}
Expand All @@ -59,13 +68,13 @@ const Card: React.FC<ICardProps> = ({
/>
</CardStyles.CheckBoxWrap>
)}
</CardStyles.Image>
</div>

<CardStyles.Content to={`/summary/${video.video_id}`}>
<CardStyles.Title>{video.title}</CardStyles.Title>
<CardStyles.Summary>{video.description}</CardStyles.Summary>
<CardStyles.ChipWrap>
{video.tag.map((tag) => (
{video.tag.slice(0, 3).map((tag) => (
<Chip key={tag.name} name={tag.name} />
))}
</CardStyles.ChipWrap>
Expand All @@ -75,7 +84,7 @@ const Card: React.FC<ICardProps> = ({
<CategorySelectBox
selectedCategoryId={selectedCategoryId}
onSelect={handleSelectCategory}
onFileClick={onFileClick}
onFileClick={onFileClickWithProps}
/>
</CardStyles.DropdownWrap>
)}
Expand Down
20 changes: 12 additions & 8 deletions src/components/category/VideoSelectMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as CategoryPageStyles from '@/styles/category/index.style';
import GarbageSvg from '@/assets/icons/garbage.svg?react';
import CloseSvg from '@/assets/icons/close.svg?react';
import { useState } from 'react';
import { CategorySelectBox } from '../SummaryPage/SummaryDetailBox/CategorySelectBox';
import { useState } from 'react';
import { IFolderProps } from 'types/category';

interface IVideoSelectMenuProps {
Expand All @@ -12,6 +12,11 @@ interface IVideoSelectMenuProps {
setCheckedVideos: React.Dispatch<React.SetStateAction<number[]>>;
handleDeleteVideos: () => void;
allCheckBtnHandler: () => void;
onFileClick?: (
e: React.MouseEvent,
videoId: number,
categoryId: number,
) => void;
}

const VideoSelectMenu = ({
Expand All @@ -21,19 +26,18 @@ const VideoSelectMenu = ({
setCheckedVideos,
handleDeleteVideos,
allCheckBtnHandler,
onFileClick,
}: IVideoSelectMenuProps) => {
const [selectedCategoryId, setSelectedCategoryId] = useState(
categories.length ? categories[0].categoryId : -1,
);

const handleSelectCategory = (categoryId: number) => {
const onSelect = (categoryId: number) => {
setSelectedCategoryId(categoryId);
};

const onFileClick = (e: React.MouseEvent) => {
e.stopPropagation();
// 비디오 이동 API 호출 후 모든 비디오 받아오는 API 재호출로 최신화하기
};
const onFileClickWithProps = (e: React.MouseEvent) =>
onFileClick && onFileClick(e, checkedVideos[0], selectedCategoryId);
return (
<CategoryPageStyles.SelectModeWrap>
<div>
Expand All @@ -48,8 +52,8 @@ const VideoSelectMenu = ({
<CategoryPageStyles.DropdownWrap>
<CategorySelectBox
selectedCategoryId={selectedCategoryId}
onSelect={handleSelectCategory}
onFileClick={onFileClick}
onSelect={onSelect}
onFileClick={onFileClickWithProps}
/>
</CategoryPageStyles.DropdownWrap>
<CategoryPageStyles.ManagementBoxGray onClick={handleDeleteVideos}>
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/chip/Chip.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import styled from 'styled-components';
export const ChipContainer = styled.div`
cursor: pointer;
margin-right: 18px;
margin-bottom: 18px;
margin-bottom: 12px;
padding: 3px 9.5px;
background-color: ${theme.color.gray100};
border-radius: 8px;
Expand Down
2 changes: 1 addition & 1 deletion src/components/layout/sideBar/UserMode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const UserMode = () => {
} else if (grabedCategory.current?.topCategoryId === null) {
response = await topToOtherTop(grabedCategory, dropedCategory);
} else {
response = await subToOtherTop(topId, grabedCategory);
response = await subToOtherTop(dropedCategory.current!, grabedCategory);
}
// 잡은 카테고리, 놓은 카테고리 초기화
if (response) {
Expand Down
50 changes: 30 additions & 20 deletions src/pages/CategoryPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ import { useRecoilValue } from 'recoil';
import { categoryState } from '@/stores/category';
import { ISubFolderProps, ITagProps } from 'types/category';
import EmptyCard from '@/components/category/EmptyCard';
import { deleteVideos, getRecentVideos } from '@/apis/videos';
import { deleteVideos } from '@/apis/videos';
import { IVideoProps } from 'types/videos';
import { sortVideos } from '@/utils/sortVideos';
import { CardContainer } from '@/styles/category/Card.style';
import handleVideo from '@/utils/handleVideo';
import VideoSelectMenu from '@/components/category/VideoSelectMenu';
import DefaultMenu from '@/components/category/DefaultMenu';
import { putVideoToOtherCategory } from '@/apis/category';
import handleVideo from '@/utils/handleVideo';

const CategoryPage = () => {
const params = useParams();
Expand All @@ -31,24 +32,14 @@ const CategoryPage = () => {
const sortedVideos = sortVideos(videos, recentRegisterMode);

useEffect(() => {
if (!params.top_folder) {
getRecentVideos()
.then((res) => {
setVideos(res.result.videos);
setName('최근 읽은 영상');
setMenus([]);
})
.catch((err) => console.log(err));
} else {
handleVideo(
categories,
params.top_folder,
params.sub_folder!,
setMenus,
setName,
setVideos,
);
}
handleVideo(
categories,
params.top_folder,
params.sub_folder,
setMenus,
setName,
setVideos,
);
setCheckedVideos([]);
}, [categories, params.sub_folder, params.top_folder]);

Expand All @@ -72,6 +63,24 @@ const CategoryPage = () => {
setCheckedVideos(videos.map((video) => video.video_id));
}
};
const onFileClick = async (
e: React.MouseEvent,
videoId: number,
categoryId: number,
) => {
e.stopPropagation();
const res = await putVideoToOtherCategory(videoId, categoryId);
if (res.isSuccess) {
handleVideo(
categories,
params.top_folder,
params.sub_folder,
setMenus,
setName,
setVideos,
);
}
};

return (
<CategoryPageStyles.Container>
Expand All @@ -85,6 +94,7 @@ const CategoryPage = () => {
setCheckedVideos={setCheckedVideos}
handleDeleteVideos={handleDeleteVideos}
allCheckBtnHandler={allCheckBtnHandler}
onFileClick={onFileClick}
/>
) : (
<DefaultMenu
Expand Down
Loading
Loading