Skip to content

Commit

Permalink
[NDD-149] 마이페이지 영상 개별보기 페이지 완료 (8h/3h) (#81)
Browse files Browse the repository at this point in the history
* fix: myPageLoader 문제 수정

- url을 통해 mypage에 접근할 때 로더가 제대로 동작하지 않는 문제 발생
- rootLoader가 비동기라서 myPageloader보다 나중에 실행되는 문제였음
- mypageLoader에서도 ensureQueryData를 호출하는 방식으로 해결
- ensureQueryData는 캐시가 없을 때만 요청을 하기 때문에 중복 api 호출은 걱정하지 않아도 됨
- 단, 이렇게하면 rootLoader의 의미가 크게 없어지기 때문에 추후 다시 고민해볼것

* feat: 영상 공개용 페이지와 비공개 페이지 분리

* feat: video api mocks 서버 수정

* feat: 공개용 비디오 페이지는 해시가 올바르지 않다면 접근 불가능하도록 로더에서 처리

* feat: getAPIResponseData에서 에러를 상위로 던지도록 설정

* rename: VideoItem을 마이페이지에서만 사용하는 컴포넌트로 전환

* feat: 비공개용 비디오 플레이어와 공개용 비디오 플레이어 컴포넌트 분리

* chore: dayjs 추가

* feat: 유닉스 타임을 YYYY-MM-DD 포맷으로 변환

* feat: 해시값으로 영상 불러오기 실패시 404 페이지로 이동

* feat: 날짜 포맷 YYYY-MM-DD -> YYYY.MM.DD로 변환

* feat: 로딩중 화면을 위한 컴포넌트 생성 (임시)

* design: 메인화면으로 이동시 로고 위치 이동하지 않도록 padding 맞춤

* feat: 비디오 공개 페이지, 비공개 페이지 완료

* design: 플레이어 페이지에서는 제목 호버효과 제거

* design: 영상 비율 16:9 비율로 설정

- 나중에 모바일 지원 시 세로 영상이 들어올 수도 있어서 동영상 가로, 세로 길이를 고정해야함

* rename: StartButton을 common components로 이동

동영상 화면에서도 사용하기 위함

* design: 영상 공유하기 버튼 추가

* feat: 공개용 비디오 플레이어 페이지도 시작버튼 변경

* design: 영상 공유설정 모달을 위한 텍스트, 색상, 아이콘 추가

* feat: 토글 foundation 추가

* feat: 일정 길이만큼 문자열을 잘라주는 truncateText 유틸 추가

* feat: 모달을 띄우기 위해 아이콘 버튼 props에 클릭 이벤트 추가

* feat: 공개 범위에 따라서 다르게 보이는 아이콘 컴포넌트 구현

* fix: 토글에 기본 체크값 추가해서 기본값 설정 안되는 문제 해결

* design: foundation 버튼을 상속받아서 밝은 테마 버튼 제작

* rename: 링크 복사하기 아이콘 수정

* feat: 비디오 공유용 모달 마크업 완료

* feat: 영상 공유 옵션 설정할 수 있는 모달 기능구현 완료

* design: 인터뷰 영상페이지 레이아웃 변경

* feat: dev 브랜치 리베이스 후 충돌 해결

* fix: StartButton 링크 경로 수정

* fix: isFetching 대신 data로 조건부 랜더링을 해서 타입 추론이 동작하도록 변경

* fix: 괄호 짝이 맞지 않는 문제 수정
  • Loading branch information
milk717 authored Nov 22, 2023
1 parent 6dd084b commit f87d9c6
Show file tree
Hide file tree
Showing 35 changed files with 736 additions and 68 deletions.
6 changes: 6 additions & 0 deletions FE/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions FE/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"@tanstack/react-query": "^5.8.1",
"@tanstack/react-query-devtools": "^5.8.1",
"axios": "^1.6.1",
"dayjs": "^1.11.10",
"react": "^18.2.0",
"react-confetti": "^6.1.0",
"react-dom": "^18.2.0",
Expand Down
15 changes: 13 additions & 2 deletions FE/src/AppRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { createBrowserRouter, Outlet, RouterProvider } from 'react-router-dom';
import myPageLoader from '@routes/myPageLoader';
import invalidPathLoader from '@routes/invalidPathLoader';
import rootLoader from '@routes/rootLoader';
import InterviewVideoPublicPage from '@page/interviewVideoPublicPage';
import InterviewVideoPublicLoader from '@routes/interviewVideoPublicLoader';

const routes = ({ queryClient }: { queryClient: QueryClient }) => {
return createBrowserRouter([
Expand All @@ -36,13 +38,22 @@ const routes = ({ queryClient }: { queryClient: QueryClient }) => {
element: <MyPage />,
},
{
path: PATH.INTERVIEW_VIDEO, // ":videoId" is a URL parameter
path: PATH.INTERVIEW_VIDEO,
element: <InterviewVideoPage />,
},
{
path: PATH.INTERVIEW_VIDEO_PUBLIC,
element: <InterviewVideoPublicPage />,
loader: ({ params }) =>
InterviewVideoPublicLoader({
params: params,
queryClient: queryClient,
}),
},
{
path: '*',
loader: () => invalidPathLoader(),
element: <LandingPage />, //TODO url은 변경되지 않는 문제 해결해야함
element: <LandingPage />,
},
],
},
Expand Down
30 changes: 30 additions & 0 deletions FE/src/GlobalSvgProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,36 @@ const spliteSvgCode = (
/>
</g>
</symbol>
<symbol id="send" viewBox="0 0 24 24">
<path
d="M16.1401 2.95998L7.11012 5.95998C1.04012 7.98998 1.04012 11.3 7.11012 13.32L9.79012 14.21L10.6801 16.89C12.7001 22.96 16.0201 22.96 18.0401 16.89L21.0501 7.86998C22.3901 3.81998 20.1901 1.60998 16.1401 2.95998ZM16.4601 8.33998L12.6601 12.16C12.5101 12.31 12.3201 12.38 12.1301 12.38C11.9401 12.38 11.7501 12.31 11.6001 12.16C11.3101 11.87 11.3101 11.39 11.6001 11.1L15.4001 7.27998C15.6901 6.98998 16.1701 6.98998 16.4601 7.27998C16.7501 7.56998 16.7501 8.04998 16.4601 8.33998Z"
fill="#292D32"
/>
</symbol>
<symbol id="private" viewBox="0 0 18 18">
<path
d="M8.99984 13.5124C9.67501 13.5124 10.2223 12.9651 10.2223 12.2899C10.2223 11.6147 9.67501 11.0674 8.99984 11.0674C8.32468 11.0674 7.77734 11.6147 7.77734 12.2899C7.77734 12.9651 8.32468 13.5124 8.99984 13.5124Z"
fill="#292D32"
/>
<path
d="M13.71 7.6475V6.71C13.71 4.685 13.2225 2 9 2C4.7775 2 4.29 4.685 4.29 6.71V7.6475C2.19 7.91 1.5 8.975 1.5 11.5925V12.9875C1.5 16.0625 2.4375 17 5.5125 17H12.4875C15.5625 17 16.5 16.0625 16.5 12.9875V11.5925C16.5 8.975 15.81 7.91 13.71 7.6475ZM9 14.555C7.7475 14.555 6.735 13.535 6.735 12.29C6.735 11.0375 7.755 10.025 9 10.025C10.245 10.025 11.265 11.045 11.265 12.29C11.265 13.5425 10.2525 14.555 9 14.555ZM5.5125 7.58C5.4525 7.58 5.4 7.58 5.34 7.58V6.71C5.34 4.5125 5.9625 3.05 9 3.05C12.0375 3.05 12.66 4.5125 12.66 6.71V7.5875C12.6 7.5875 12.5475 7.5875 12.4875 7.5875H5.5125V7.58Z"
fill="#292D32"
/>
</symbol>
<symbol id="public" viewBox="0 0 18 18">
<path
d="M8.99935 0.666504C4.39935 0.666504 0.666016 4.39984 0.666016 8.99984C0.666016 13.5998 4.39935 17.3332 8.99935 17.3332C13.5993 17.3332 17.3327 13.5998 17.3327 8.99984C17.3327 4.39984 13.5993 0.666504 8.99935 0.666504ZM2.33268 8.99984C2.33268 8.4915 2.39935 7.9915 2.50768 7.5165L6.49102 11.4998V12.3332C6.49102 13.2498 7.24102 13.9998 8.15768 13.9998V15.6082C4.88268 15.1915 2.33268 12.3915 2.33268 8.99984ZM13.9077 13.4998C13.691 12.8248 13.0743 12.3332 12.3243 12.3332H11.491V9.83317C11.491 9.37484 11.116 8.99984 10.6577 8.99984H5.65768V7.33317H7.32435C7.78268 7.33317 8.15768 6.95817 8.15768 6.49984V4.83317H9.82435C10.741 4.83317 11.491 4.08317 11.491 3.1665V2.82484C13.9327 3.80817 15.666 6.20817 15.666 8.99984C15.666 10.7332 14.991 12.3165 13.9077 13.4998Z"
fill="#50924E"
/>
</symbol>
<symbol id="link" viewBox="0 0 20 20">
<path
d="M12.8427 15.4916C12.5094 15.4916 12.2344 15.2166 12.2344 14.8833C12.2344 14.5499 12.5094 14.2749 12.8427 14.2749C15.1927 14.2749 17.1094 12.3583 17.1094 10.0083C17.1094 7.65827 15.1927 5.7416 12.8427 5.7416C10.4927 5.7416 8.57604 7.65827 8.57604 10.0083C8.57604 10.3416 8.30104 10.6166 7.96771 10.6166C7.63438 10.6166 7.35938 10.3416 7.35938 10.0083C7.35938 6.98327 9.81771 4.5166 12.851 4.5166C15.8844 4.5166 18.3344 6.97493 18.3344 9.99993C18.3344 13.0249 15.876 15.4916 12.8427 15.4916Z"
fill="#292D32"
/>
<path
d="M7.15964 4.50879C7.49297 4.50879 7.76797 4.78379 7.76797 5.11712C7.76797 5.45046 7.49297 5.72546 7.15964 5.72546C4.80964 5.72546 2.89297 7.64212 2.89297 9.99212C2.89297 12.3421 4.80964 14.2588 7.15964 14.2588C9.50964 14.2588 11.4263 12.3421 11.4263 9.99212C11.4263 9.65879 11.7013 9.38379 12.0346 9.38379C12.368 9.38379 12.643 9.65879 12.643 9.99212C12.643 13.0171 10.1846 15.4838 7.1513 15.4838C4.11797 15.4838 1.66797 13.0255 1.66797 10.0005C1.66797 6.97546 4.1263 4.50879 7.15964 4.50879Z"
fill="#292D32"
<symbol id="edit" viewBox="0 0 32 32">
<path
d="M0 16C0 7.16344 7.16344 0 16 0C24.8366 0 32 7.16344 32 16C32 24.8366 24.8366 32 16 32C7.16344 32 0 24.8366 0 16Z"
Expand Down
44 changes: 44 additions & 0 deletions FE/src/components/common/LightButton/LightButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { HTMLElementTypes } from '@/types/utils';
import React from 'react';
import Button from '@foundation/Button/Button';
import { css } from '@emotion/react';
import { theme } from '@styles/theme';

type LightButtonProps = {
size?: 'sm' | 'md' | 'lg';
} & HTMLElementTypes<HTMLButtonElement> &
React.ButtonHTMLAttributes<HTMLButtonElement>;
const LightButton: React.FC<LightButtonProps> = ({
children,
size = 'md',
...args
}) => {
return (
<Button
size={size}
{...args}
css={css`
color: ${theme.colors.text.default};
border: 1px solid ${theme.colors.border.default};
background-color: ${theme.colors.surface.default};
outline: none;
transition: background-color 0.15s ease-in-out;
cursor: pointer;
&:disabled {
background-color: ${theme.colors.surface.weakHover};
cursor: not-allowed;
}
&:not(:disabled):hover {
background-color: ${theme.colors.surface.weak};
}
`}
>
{children}
</Button>
);
};

export default LightButton;
27 changes: 27 additions & 0 deletions FE/src/components/common/Loading/LoadingBounce.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { css, keyframes } from '@emotion/react';
import logo from '@assets/images/logo.png';

const LoadingBounce = () => {
const bounce = keyframes`
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-4rem); /* 공이 최대 높이까지 튀어오르는 지점 */
}
`;
return (
<img
src={logo}
alt={'곰돌이 로고'}
css={css`
width: 50px;
height: 50px;
animation: ${bounce} 1.3s infinite;
animation-timing-function: ease-in-out;
`}
/>
);
};

export default LoadingBounce;
36 changes: 36 additions & 0 deletions FE/src/components/common/VideoPlayer/IconButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import Button from '@foundation/Button/Button';
import { theme } from '@styles/theme';
import Icon from '@foundation/Icon/Icon';
import Typography from '@foundation/Typography/Typography';
import { css } from '@emotion/react';
import { MouseEventHandler } from 'react';

type IconButtonProps = {
text: string;
iconName: string;
onClick: MouseEventHandler<HTMLButtonElement>;
};
const IconButton: React.FC<IconButtonProps> = ({ text, iconName, onClick }) => {
return (
<Button
onClick={onClick}
css={css`
display: flex;
justify-content: center;
align-self: end;
gap: 0.5rem;
padding: 0.5rem 0.75rem;
color: ${theme.colors.text.default};
background-color: ${theme.colors.surface.weak};
&:not(:disabled):hover {
background-color: ${theme.colors.surface.weakHover};
}
`}
>
<Icon id={iconName} />
<Typography variant="body3">{text}</Typography>
</Button>
);
};

export default IconButton;
25 changes: 25 additions & 0 deletions FE/src/components/common/VideoPlayer/VideoPlayer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { css } from '@emotion/react';

type VideoPlayerProps = {
url: string;
};

const VideoPlayer: React.FC<VideoPlayerProps> = ({ url }) => {
return (
<video
src={url}
autoPlay
controls
muted
css={css`
//16:9 비율로 설정
width: 96vh;
height: 54vh;
object-fit: contain;
align-self: center;
`}
/>
);
};

export default VideoPlayer;
57 changes: 57 additions & 0 deletions FE/src/components/common/VideoPlayer/VideoPlayerFrame.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { css } from '@emotion/react';
import Typography from '@foundation/Typography/Typography';
import { theme } from '@styles/theme';
import React, { PropsWithChildren } from 'react';
import { VideoItemResDto } from '@/types/video';
import dayjs from 'dayjs';

type VideoItemProps = PropsWithChildren &
Pick<VideoItemResDto, 'videoName' | 'createdAt'>;

const VideoPlayerFrame: React.FC<VideoItemProps> = ({
children,
videoName,
createdAt,
}) => {
return (
<div
css={css`
display: flex;
flex-direction: column;
row-gap: 0.75rem;
`}
>
{children}
<div
css={css`
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 1rem;
height: 100%;
cursor: pointer;
`}
>
<Typography
variant="title3"
css={css`
line-height: 1.25rem;
`}
>
{videoName}
</Typography>
<div
css={css`
align-self: flex-end;
`}
>
<Typography variant="body3" color={theme.colors.text.subStrong}>
{dayjs(Number(createdAt)).format('YYYY.MM.DD')}
</Typography>
</div>
</div>
</div>
);
};

export default VideoPlayerFrame;
41 changes: 41 additions & 0 deletions FE/src/components/foundation/Toggle/Toggle.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { css } from '@emotion/react';
import { theme } from '@styles/theme';

export const ToggleLabelStyle = css`
position: relative;
cursor: pointer;
width: 2.25rem;
height: 1.25rem;
background: ${theme.colors.text.subStrong};
display: block;
border-radius: 1rem; // 세로 길이와 동일하게 설정하여 완전한 원형을 만듬
&:after {
content: '';
position: absolute;
top: 0.1875rem;
left: 0.1875rem;
width: 0.875rem;
height: 0.875rem;
background: #fff;
border-radius: 50%;
transition: 0.3s;
}
&:active:after {
width: 1.25rem;
}
`;

export const ToggleInputStyle = css`
&[type='checkbox'] {
height: 0;
width: 0;
visibility: hidden;
}
&:checked + label {
background: ${theme.colors.point.primary.default};
}
&:checked + label:after {
left: calc(100% - 0.1rem);
transform: translateX(-100%);
}
`;
25 changes: 25 additions & 0 deletions FE/src/components/foundation/Toggle/Toggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { HTMLElementTypes } from '@/types/utils';
import {
ToggleInputStyle,
ToggleLabelStyle,
} from '@foundation/Toggle/Toggle.styles';

type ToggleProps = {
isToggled: boolean;
} & HTMLElementTypes<HTMLInputElement>;
const Toggle: React.FC<ToggleProps> = ({ isToggled, ...args }) => {
return (
<>
<input
id="toggle"
type="checkbox"
defaultChecked={isToggled}
css={ToggleInputStyle}
{...args}
/>
<label htmlFor="toggle" css={ToggleLabelStyle} />
</>
);
};

export default Toggle;
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ const InterviewVideoPageLayout: React.FC<InterviewVideoPageLayoutProps> = ({
<div>
<div
css={css`
padding: 1.5rem;
display: flex;
padding: 2rem;
`}
>
<Logo />
Expand All @@ -24,7 +25,6 @@ const InterviewVideoPageLayout: React.FC<InterviewVideoPageLayoutProps> = ({
css={css`
align-items: center;
row-gap: 1rem;
padding: 1rem;
height: auto;
`}
>
Expand Down
Loading

0 comments on commit f87d9c6

Please sign in to comment.