Skip to content

Commit

Permalink
Merge pull request #63 from boostcamp-2020/dev
Browse files Browse the repository at this point in the history
[COMMON] 3주차 데모 버전
  • Loading branch information
joh16 authored Dec 4, 2020
2 parents c597257 + 1f26266 commit aed3527
Show file tree
Hide file tree
Showing 53 changed files with 1,115 additions and 150 deletions.
3 changes: 2 additions & 1 deletion client/src/api/video.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { requestPOST } from '@/api';
import { requestGET, requestPOST } from '@/api';

const VIDEO_BASE_URL = '/video';

const videoAPI = {
upload: (formData: FormData) =>
requestPOST(VIDEO_BASE_URL, formData, {}, true),
getList: () => requestGET(`${VIDEO_BASE_URL}/list`),
};

export default videoAPI;
19 changes: 17 additions & 2 deletions client/src/components/atoms/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,32 @@ const StyledButton = styled.button<StyledProps>`
&:focus {
outline: none;
}
&:disabled {
cursor: not-allowed;
opacity: 0.5;
}
&:hover {
background-color: ${color.BORDER};
box-shadow: 0 0 10px 8px rgba(255, 255, 255, 0.2);
}
`;

interface Props {
children?: React.ReactChild;
message: string;
onClick?: () => void;
type: ButtonType;
disabled: boolean;
}

const Button: React.FC<Props> = ({ children, message, onClick, type }) => (
<StyledButton buttonType={type} onClick={onClick}>
const Button: React.FC<Props> = ({
children,
message,
onClick,
type,
disabled,
}) => (
<StyledButton buttonType={type} onClick={onClick} disabled={disabled}>
{children}
{children && <br />}
{message}
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/atoms/Button/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export { default } from './Button';

export type ButtonType = 'default' | 'transparent';
export type ButtonType = 'default' | 'transparent' | 'selected';
5 changes: 5 additions & 0 deletions client/src/components/atoms/Button/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ export default (type: ButtonType) => {
return `
background : transparent;
`;
case 'selected':
return `
background : transparent;
color: ${color.PALE_PURPLE};
`;
default:
return ``;
}
Expand Down
8 changes: 0 additions & 8 deletions client/src/components/atoms/Canvas/Canvas.tsx

This file was deleted.

1 change: 0 additions & 1 deletion client/src/components/atoms/Canvas/index.ts

This file was deleted.

9 changes: 5 additions & 4 deletions client/src/components/atoms/Slider/Slider.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { MutableRefObject, useEffect, useState } from 'react';
import styled, { keyframes, css } from 'styled-components';
import { useSelector } from 'react-redux';
import { useSelector, shallowEqual } from 'react-redux';

import { getPlaying, getCurrentTime } from '@/store/selectors';
import { getPlaying, getCurrentTime, getStartEnd } from '@/store/selectors';
import color from '@/theme/colors';
import video from '@/video';

Expand Down Expand Up @@ -35,6 +35,7 @@ const StyledDiv = styled.div`
const Slider: React.FC<Props> = ({ thumbnailRef }) => {
const [location, setLocation] = useState(0);
const [duration, setDuration] = useState(0);
const { start, end } = useSelector(getStartEnd, shallowEqual);

const isPlaying = useSelector(getPlaying);
const time = useSelector(getCurrentTime);
Expand All @@ -43,10 +44,10 @@ const Slider: React.FC<Props> = ({ thumbnailRef }) => {
const currentTime = video.get('currentTime');

const width = thumbnailRef.current.clientWidth;
const totalDuration = video.get('duration');
const totalDuration = end - start;

const movedLocation = totalDuration
? (currentTime / totalDuration) * width
? ((currentTime - start) / totalDuration) * width
: 0;

const restWidth = width - movedLocation;
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/atoms/TimeText/TimeText.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import styled from 'styled-components';
import parseTime from '@/utils/time';
import { parseTime } from '@/utils/time';

const StyledP = styled.p`
margin: 0;
Expand Down
73 changes: 73 additions & 0 deletions client/src/components/atoms/VideoList/VideoItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React from 'react';
import styled from 'styled-components';

import { Video } from '@/store/video/actions';
import color from '@/theme/colors';
import { parseDateString } from '@/utils/time';

const StyledDiv = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid ${color.BORDER};
font-size: 13px;
${({ isChecked }) =>
`background-color: ${
isChecked ? `${color.DARK_PURPLE}` : `${color.MODAL}`
};`}
&:hover {
background-color: ${color.BORDER};
}
`;

const WrapperDiv = styled.div`
display: flex;
width: 100%;
align-items: center;
justify-content: space-between;
margin: 0 1rem;
`;

const Image = styled.img`
width: 2.5rem;
height: 2rem;
`;
const NameDiv = styled.div`
width: 70%;
margin-left: 1rem;
`;

const Name = styled.p`
white-space: nowrap;
`;

const Timestamp = styled.p`
font-size: 12px;
white-space: nowrap;
`;

interface Props {
video: Video;
selected: Video;
handleCheck: Function;
}

const VideoItem: React.FC<Props> = ({ video, handleCheck, selected }) => {
return (
<StyledDiv
onClick={() => handleCheck(video)}
isChecked={selected === video}
>
<WrapperDiv>
<Image src="https://user-images.githubusercontent.com/49153756/99666210-03b80600-2aae-11eb-95b9-f61f52694708.png" />
<NameDiv>
<Name>{video.name}</Name>
</NameDiv>
<Timestamp>{parseDateString(new Date(), video.updatedAt)}</Timestamp>
</WrapperDiv>
</StyledDiv>
);
};

export default VideoItem;
59 changes: 59 additions & 0 deletions client/src/components/atoms/VideoList/VideoList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React, { useEffect, useState } from 'react';
import styled from 'styled-components';
import { useSelector, useDispatch } from 'react-redux';

import { fetchListStart } from '@/store/video/actions';
import { getVideos } from '@/store/selectors';
import color from '@/theme/colors';
import VideoItem from './VideoItem';

const StyledDiv = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
background-color: ${color.MODAL};
border-radius: 12px 12px 0 0;
`;

const Header = styled.div`
display: flex;
align-items: center;
justify-content: center;
border-bottom: 1px solid ${color.BORDER};
padding: 10px;
`;

const List = styled.div`
height: 50vh;
overflow-y: auto;
`;

const VideoList: React.FC = () => {
const [selected, setSelected] = useState(null);
const videos = useSelector(getVideos);
const dispatch = useDispatch();

const handleCheck = video => setSelected(video);

useEffect(() => {
if (!videos) dispatch(fetchListStart());
}, [videos]);

return (
<StyledDiv>
<Header>Video List</Header>
<List>
{videos?.map(video => (
<VideoItem
key={video.name}
video={video}
handleCheck={handleCheck}
selected={selected}
/>
))}
</List>
</StyledDiv>
);
};

export default VideoList;
1 change: 1 addition & 0 deletions client/src/components/atoms/VideoList/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './VideoList';
4 changes: 3 additions & 1 deletion client/src/components/molecules/ButtonGroup/ButtonGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ const StyledDiv = styled.div<string>`
interface button {
onClick: () => void;
message: string;
type: 'default' | 'transparent';
type: 'default' | 'transparent' | 'selected';
children: React.ReactChild;
disabled: boolean;
}

interface Props {
Expand All @@ -31,6 +32,7 @@ const ButtonGroup: React.FC<Props> = ({ buttonData, StyledProps }) => (
onClick={data.onClick}
message={data.message}
type={data.type}
disabled={data.disabled}
>
{data.children}
</Button>
Expand Down
27 changes: 21 additions & 6 deletions client/src/components/molecules/CurrentTime/CurrentTime.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import React, { useState, useEffect } from 'react';
import { useSelector } from 'react-redux';
import { useSelector, useDispatch, shallowEqual } from 'react-redux';
import styled from 'styled-components';

import TimeText from '@/components/atoms/TimeText';
import video from '@/video';
import color from '@/theme/colors';
import { getVisible } from '@/store/selectors';
import {
getVisible,
getIsCropAndDuration,
getStartEnd,
} from '@/store/selectors';
import { moveTo, pause } from '@/store/currentVideo/actions';

const StyledDiv = styled.div`
display: flex;
Expand All @@ -17,16 +22,26 @@ const StyledDiv = styled.div`
`;

const CurrentTime: React.FC = () => {
const currentTime = () => Math.round(video.get('currentTime'));

const [time, setTime] = useState(currentTime());
const currentTime = () => video.get('currentTime');
const { start, end } = useSelector(getStartEnd, shallowEqual);
const cropState = useSelector(getIsCropAndDuration, shallowEqual);
const [time, setTime] = useState(Math.floor(currentTime() - start));
const visible = useSelector(getVisible);

const dispatch = useDispatch();

useEffect(() => {
const timer =
visible &&
setInterval(() => {
const newTime = currentTime();
let newTime = currentTime();
if (newTime >= end) {
if (!cropState.isCrop) video.pause();
dispatch(pause());
if (newTime > end) video.setCurrentTime((newTime = end));
dispatch(moveTo(end));
}
newTime = Math.floor(Number((newTime - start).toFixed(1)));
if (time !== newTime) setTime(newTime);
}, 50);
return () => clearInterval(timer);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import React from 'react';
import React, { useState } from 'react';
import styled, { keyframes } from 'styled-components';

import Modal from '@/components/molecules/Modal';
import VideoList from '@/components/atoms/VideoList';
import color from '@/theme/colors';

const slide = keyframes`
from {
transform: translate(0, -50px) rotate(90deg);
transform: translate(0, -2rem) rotate(90deg);
opacity: 0;
}
to {
Expand All @@ -20,7 +22,7 @@ const StyledDiv = styled.div`
flex-direction: column;
justify-content: center;
border-radius: 5px;
top: 2rem;
top: 3rem;
right: 0;
border: 1px solid ${color.BORDER};
background-color: ${color.BLACK};
Expand Down Expand Up @@ -57,18 +59,43 @@ interface Props {
handleChange: () => void;
}

const modalLayout = `
top: 20vh;
left: 35vw;
width: 30vw;
height: 60vh;
`;

const FileInput = React.forwardRef<HTMLInputElement, Props>(
({ handleChange }, forwardedRef) => {
const [modalVisible, setModalVisible] = useState(false);

const handleClick = () => setModalVisible(true);
const handleCancel = () => setModalVisible(false);
const handleConfirm = () => setModalVisible(false);

const handleOverlay = () => setModalVisible(false);
return (
<StyledDiv>
{modalVisible && (
<Modal
styleProps={modalLayout}
handleOverlay={handleOverlay}
handleButton1={handleCancel}
handleButton2={handleConfirm}
buttonMessage1="취소"
buttonMessage2="확인"
component={VideoList}
/>
)}
<FromLocal htmlFor="local">로컬</FromLocal>
<StyledInput
type="file"
id="local"
ref={forwardedRef}
onChange={handleChange}
/>
<FromServer>서버</FromServer>
<FromServer onClick={handleClick}>서버</FromServer>
</StyledDiv>
);
}
Expand Down
Loading

0 comments on commit aed3527

Please sign in to comment.