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

[NDD-147] 마이페이지 영상 삭제 기능 구현 (1h/2h) #96

Merged
merged 5 commits into from
Nov 22, 2023
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
10 changes: 10 additions & 0 deletions FE/src/GlobalSvgProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,16 @@ const spliteSvgCode = (
fill="#9299A1"
/>
</symbol>
<symbol id="trash" viewBox="0 0 24 24">
<path
d="M21.0697 5.23C19.4597 5.07 17.8497 4.95 16.2297 4.86V4.85L16.0097 3.55C15.8597 2.63 15.6397 1.25 13.2997 1.25H10.6797C8.34967 1.25 8.12967 2.57 7.96967 3.54L7.75967 4.82C6.82967 4.88 5.89967 4.94 4.96967 5.03L2.92967 5.23C2.50967 5.27 2.20967 5.64 2.24967 6.05C2.28967 6.46 2.64967 6.76 3.06967 6.72L5.10967 6.52C10.3497 6 15.6297 6.2 20.9297 6.73C20.9597 6.73 20.9797 6.73 21.0097 6.73C21.3897 6.73 21.7197 6.44 21.7597 6.05C21.7897 5.64 21.4897 5.27 21.0697 5.23Z"
fill="#E05241"
/>
<path
d="M19.2297 8.14C18.9897 7.89 18.6597 7.75 18.3197 7.75H5.67975C5.33975 7.75 4.99975 7.89 4.76975 8.14C4.53975 8.39 4.40975 8.73 4.42975 9.08L5.04975 19.34C5.15975 20.86 5.29975 22.76 8.78975 22.76H15.2097C18.6997 22.76 18.8397 20.87 18.9497 19.34L19.5697 9.09C19.5897 8.73 19.4597 8.39 19.2297 8.14ZM13.6597 17.75H10.3297C9.91975 17.75 9.57975 17.41 9.57975 17C9.57975 16.59 9.91975 16.25 10.3297 16.25H13.6597C14.0697 16.25 14.4097 16.59 14.4097 17C14.4097 17.41 14.0697 17.75 13.6597 17.75ZM14.4997 13.75H9.49975C9.08975 13.75 8.74975 13.41 8.74975 13C8.74975 12.59 9.08975 12.25 9.49975 12.25H14.4997C14.9097 12.25 15.2497 12.59 15.2497 13C15.2497 13.41 14.9097 13.75 14.4997 13.75Z"
fill="#E05241"
/>
</symbol>
</svg>
);

Expand Down
12 changes: 9 additions & 3 deletions FE/src/components/foundation/CardCover/CardCover.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { css } from '@emotion/react';
import { HTMLElementTypes } from '@/types/utils';

type CardCoverProps = {
children: React.ReactNode;
borderRadius: string;
};
} & HTMLElementTypes<HTMLDivElement>;

const CardCover: React.FC<CardCoverProps> = ({ children, borderRadius }) => {
const CardCover: React.FC<CardCoverProps> = ({
children,
borderRadius,
...args
}) => {
return (
<div
css={css`
Expand All @@ -19,11 +24,12 @@ const CardCover: React.FC<CardCoverProps> = ({ children, borderRadius }) => {
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.2);
background-color: rgba(0, 0, 0, 0.3);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[p-5] 저희 디자인 시스템도 한번 정의가 필요할 듯 하네요 ㅠㅠ 저도 저렇게 썼는데 슬슬 디자인 시스템에서 하나씩 엇나가는게 보이네요

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

인정합니다! 현재 검정색 투명도 조절 색상이 많아서 이것도 테마에 추가해야겠네요!

border-radius: ${borderRadius};
z-index: 1;
}
`}
{...args}
>
{children}
</div>
Expand Down
41 changes: 41 additions & 0 deletions FE/src/components/myPage/DeleteCheckModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import Modal from '@foundation/Modal';
import React from 'react';
import Typography from '@foundation/Typography/Typography';
import Button from '@foundation/Button/Button';
import LightButton from '@common/LightButton/LightButton';
import { css } from '@emotion/react';

type DeleteCheckModalProps = {
isOpen: boolean;
content: string;
closeModal: () => void;
confirmModal: () => void;
};
const DeleteCheckModal: React.FC<DeleteCheckModalProps> = ({
isOpen,
content,
closeModal,
confirmModal,
}) => {
return (
<Modal isOpen={isOpen} closeModal={closeModal}>
<Modal.content>
<Typography variant="title4">{content}</Typography>
</Modal.content>
<Modal.footer>
<div
css={css`
display: flex;
justify-content: flex-end;
column-gap: 0.5rem;
`}
>
<LightButton onClick={closeModal}>취소</LightButton>
<Button onClick={confirmModal}>확인</Button>
</div>
</Modal.footer>
</Modal>
);
};

export default DeleteCheckModal;
36 changes: 28 additions & 8 deletions FE/src/components/myPage/TabPanel/VideoListTabPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,28 @@ import Box from '@foundation/Box/Box';
import { css } from '@emotion/react';
import VideoItem from '@components/myPage/VideoItem/VideoItem';
import Thumbnail from '@components/myPage/Thumbnail';
import CardCover from '@foundation/CardCover/CardCover';
import useVideoListQuery from '@hooks/queries/video/useVideoListQuery';
import { PATH } from '@constants/path';
import { theme } from '@styles/theme';
import useDeleteVideoMutation from '@hooks/mutations/video/useDeleteVideoMutation';
import DeleteCheckModal from '@components/myPage/DeleteCheckModal';
import { useState } from 'react';

const VideoListTabPanel: React.FC = () => {
const { data } = useVideoListQuery();
const { mutate } = useDeleteVideoMutation();
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [selectedVideoId, setSelectVideoId] = useState<number | null>(null);

const handleDeleteIconClick = (videoId: number) => {
setIsDeleteModalOpen(true);
setSelectVideoId(videoId);
};

const handleConfirmModal = () => {
selectedVideoId && mutate(selectedVideoId);
setIsDeleteModalOpen(false);
};

if (!data) return <div>로딩중</div>;

Expand All @@ -34,15 +49,20 @@ const VideoListTabPanel: React.FC = () => {
date={dayjs(Number(video.createdAt)).format('YYYY-MM-DD')}
path={`${PATH.INTERVIEW_VIDEO(video.id)}`}
>
<CardCover borderRadius="1rem">
<Thumbnail
image={video.thumbnail}
videoName={video.videoName}
videoLength={video.videoLength}
/>
</CardCover>
<Thumbnail
image={video.thumbnail}
videoName={video.videoName}
videoLength={video.videoLength}
onDeleteIconClick={() => handleDeleteIconClick(video.id)}
/>
</VideoItem>
))}
<DeleteCheckModal
isOpen={isDeleteModalOpen}
content="영상을 삭제 하시겠습니까?"
closeModal={() => setIsDeleteModalOpen(false)}
confirmModal={handleConfirmModal}
/>
</Box>
);
};
Expand Down
85 changes: 60 additions & 25 deletions FE/src/components/myPage/Thumbnail.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,84 @@
import { theme } from '@styles/theme';
import { css } from '@emotion/react';
import Icon from '@foundation/Icon/Icon';
import React, { MouseEventHandler } from 'react';
import CardCover from '@foundation/CardCover/CardCover';

type ThumbnailProps = {
image: string;
videoLength: string;
videoName: string;
onDeleteIconClick: () => void;
};

const Thumbnail: React.FC<ThumbnailProps> = ({
videoName,
videoLength,
image,
onDeleteIconClick,
}) => {
const handleDeleteIconClick: MouseEventHandler = (e) => {
e.preventDefault(); //상위 요소의 Link 이벤트를 막기 위해
onDeleteIconClick();
};
return (
<div
<CardCover
borderRadius="1rem"
css={css`
position: relative;
display: inline-block;

&::after {
content: '${videoLength}';
position: absolute;
right: 0.75rem;
bottom: 0.75rem;
//TODO 이 부분 색상은 성인님 작업 부분과 겹칠 것 같아 일단 하드코딩했습니다.
background: rgba(0, 0, 0, 0.7);
font-size: 0.875rem;
color: ${theme.colors.text.white};
padding: 0.25rem;
border-radius: 0.25rem;
&:hover .delete {
display: block;
}
`}
>
<img
src={image}
alt={videoName}
<div
className="thumbnail"
css={css`
aspect-ratio: 3 / 2;
width: 100%;
height: auto;
object-fit: cover;
border-radius: 1rem;
position: relative;
display: inline-block;

&::after {
content: '${videoLength}';
position: absolute;
right: 0.75rem;
bottom: 0.75rem;
//TODO 이 부분 색상은 성인님 작업 부분과 겹칠 것 같아 일단 하드코딩했습니다.
background: rgba(0, 0, 0, 0.7);
font-size: 0.875rem;
color: ${theme.colors.text.white};
padding: 0.25rem;
border-radius: 0.25rem;
}
`}
/>
</div>
>
<div
onClick={handleDeleteIconClick}
className="delete"
css={css`
display: none;
position: absolute;
top: 0.5rem;
left: 0.5rem;
padding: 0.25rem;
border-radius: 1rem;
background-color: ${theme.colors.surface.default};
z-index: 1000;
`}
>
<Icon id="trash" width="20" height="20" />
</div>
<img
src={image}
alt={videoName}
css={css`
aspect-ratio: 3 / 2;
width: 100%;
height: auto;
object-fit: cover;
border-radius: 1rem;
`}
/>
</div>
</CardCover>
);
};

Expand Down
4 changes: 2 additions & 2 deletions FE/src/hooks/mutations/video/useDeleteVideoMutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { QUERY_KEY } from '@/constants/queryKey';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { deleteVideoById } from '@/apis/video';

const useDeleteVideoMutation = (videoId: number) => {
const useDeleteVideoMutation = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: () => deleteVideoById(videoId),
mutationFn: deleteVideoById,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[p-5] 이제 정말 파라미터를 다 떼어버리는거야~

onSuccess: () => {
void queryClient.invalidateQueries({
queryKey: QUERY_KEY.VIDEO,
Expand Down
4 changes: 2 additions & 2 deletions FE/src/mocks/handlers/video.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ const videoHandlers = [
await delay(1000);
return HttpResponse.json(null, { status: 200 });
}),
http.delete(API.VIDEO_ID(), ({ request }) => {
return HttpResponse.json(null, { status: 204 });
http.delete(API.VIDEO_ID(), () => {
return new HttpResponse(null, { status: 204 });
}),
];

Expand Down
Loading