diff --git a/.env b/.env index cee2e3e..1157ee1 100644 --- a/.env +++ b/.env @@ -1,3 +1,3 @@ -REACT_APP_BACKEND_BASEURL=https://api.tempfiles.ml +REACT_APP_BACKEND_BASEURL=http://localhost:5000 # dev - http://localhost:5000 -# main - https://tfb.minpeter.cf +# main - https://api.tempfiles.ml diff --git a/src/components/common/DownLoadCountSlider/index.tsx b/src/components/common/DownLoadCountSlider/index.tsx new file mode 100644 index 0000000..aa976c8 --- /dev/null +++ b/src/components/common/DownLoadCountSlider/index.tsx @@ -0,0 +1,25 @@ +import React from 'react'; + +import { RangeSlider } from '../RangeSlider'; +import * as S from './styled'; + +type DownloadCountSliderProps = { + downloadCount: number; + setDownloadCount: any; +}; + +export const DownloadCountSlider: React.FC = ({ + downloadCount, + setDownloadCount, +}) => ( + + - 다운로드 횟수 - {downloadCount}번 + setDownloadCount(event.target.value)} + step={1} + /> + +); diff --git a/src/components/common/DownLoadCountSlider/styled.ts b/src/components/common/DownLoadCountSlider/styled.ts new file mode 100644 index 0000000..808b0b3 --- /dev/null +++ b/src/components/common/DownLoadCountSlider/styled.ts @@ -0,0 +1,14 @@ +import styled from '@emotion/styled'; + +export const DownloadCountContainer = styled.div` + width: 100%; + display: flex; + flex-direction: column; + margin-top: 2rem; +`; + +export const SectionText = styled.div` + color: var(--color-text-primary); + font-weight: 600; + margin-bottom: 0.5rem; +`; diff --git a/src/components/common/DownloadCount/index.tsx b/src/components/common/DownloadCount/index.tsx deleted file mode 100644 index ff293d0..0000000 --- a/src/components/common/DownloadCount/index.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react'; - -import { RangeSlider } from '../RangeSlider'; -import * as S from './styled'; - -export const DownLoadCount: React.FC = () => ( - - console.log(event.target.value)} - step={1} - /> - -); diff --git a/src/components/common/DownloadCount/styled.ts b/src/components/common/DownloadCount/styled.ts deleted file mode 100644 index c291307..0000000 --- a/src/components/common/DownloadCount/styled.ts +++ /dev/null @@ -1,3 +0,0 @@ -import styled from '@emotion/styled'; - -export const DownloadCountContainer = styled.div``; diff --git a/src/components/common/ExpireTime/index.tsx b/src/components/common/ExpireTime/index.tsx new file mode 100644 index 0000000..7706a55 --- /dev/null +++ b/src/components/common/ExpireTime/index.tsx @@ -0,0 +1,42 @@ +import React from 'react'; + +import * as S from './styled'; + +type ExpireTimeProps = { + expireTimePlusButton: string[]; + time: { day: number; hour: number; minute: number }; + expireTime: number; + setExpireTime: (expireTime: number) => void; +}; + +export const ExpireTime: React.FC = ({ + expireTimePlusButton, + setExpireTime, + expireTime, + time, +}) => ( + + + {time.day}일 {time.hour}시간 {time.minute}분 + +
+ {expireTimePlusButton.map((i) => ( + { + const item = + i.split(i.replace(/[^0-9]/g, ''))[1] === '시간' + ? Number(i.replace(/[^0-9]/g, '')) * 60 + : i.split(i.replace(/[^0-9]/g, ''))[1] === '일' + ? Number(i.replace(/[^0-9]/g, '')) * 1440 + : Number(i.replace(/[^0-9]/g, '')); + setExpireTime(expireTime + item); + }} + > + +{i} + + ))} +
+
+); +//i.replace(/[^0-9]/g, '') diff --git a/src/components/common/ExpireTime/styled.ts b/src/components/common/ExpireTime/styled.ts new file mode 100644 index 0000000..e8b6b7d --- /dev/null +++ b/src/components/common/ExpireTime/styled.ts @@ -0,0 +1,36 @@ +import styled from '@emotion/styled'; + +export const ExpireTimeContainer = styled.div` + width: 100%; + display: flex; + justify-content: space-between; + align-items: center; + margin-top: 2rem; +`; + +export const ExpireTimeText = styled.div` + flex: 1 1 auto; + height: 4rem; + display: flex; + align-items: center; + justify-content: center; + font-size: 2rem; + font-weight: 700; + border-radius: 8px; + background: var(--color-backgorund-black); +`; + +export const ExpireTimeButton = styled.div` + padding: 0 1rem 0 1rem; + margin: 0 0.5rem 0 0.5rem; + font-size: 1.6rem; + font-weight: 600; + color: var(--color-text-primary); + height: 4rem; + display: flex; + align-items: center; + justify-content: center; + background-color: var(--color-background-secondary); + border-radius: 0.8rem; + cursor: pointer; +`; diff --git a/src/components/common/RangeSlider/index.ts b/src/components/common/RangeSlider/index.ts index ab8928c..fa1dc7d 100644 --- a/src/components/common/RangeSlider/index.ts +++ b/src/components/common/RangeSlider/index.ts @@ -1,37 +1,19 @@ import styled from '@emotion/styled'; export const RangeSlider = styled.input` - margin: 0; - padding: 0; + -webkit-appearance: none; width: 100%; height: 4rem; - border-radius: 0.4rem; - -webkit-appearance: none; - -moz-appearance: none; + border-radius: 8px; + background: var(--color-backgorund-black); outline: none; - //Chrome, Safari, Opera, and Edge Chromium - &::-ms-fill-lower { - background-color: var(--color-background-secondary); - } - &::-ms-fill-upper { - background-color: var(--color-background-tertiary); - } &::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; - background-color: var(--color-text-primary); - height: 2rem; - width: 1rem; - border-radius: 0.4rem; - } - //Firefox - &::-moz-range-thumb { - -webkit-appearance: none; - appearance: none; - background-color: var(--color-text-primary); - height: 2rem; - width: 1rem; - border-radius: 0.4rem; + width: 3.9rem; + height: 4rem; + background: var(--color-background-secondary); + border-radius: 8px; } `; diff --git a/src/components/common/index.ts b/src/components/common/index.ts index b95b1f3..a337104 100644 --- a/src/components/common/index.ts +++ b/src/components/common/index.ts @@ -2,10 +2,11 @@ export * from './CheckBox'; export * from './PasswordInput'; export * from './UpLoadButton'; export * from './FileFind'; -export * from './DownloadCount'; +export * from './DownloadCountSlider'; export * from './Navbar'; export * from './Button'; export * from './FileListBox'; export * from './Progress'; export * from './SkeletonUIBox'; export * from './FileBox'; +export * from './ExpireTime'; diff --git a/src/pages/delete/index.tsx b/src/pages/delete/index.tsx index 52b0c72..299aa88 100644 --- a/src/pages/delete/index.tsx +++ b/src/pages/delete/index.tsx @@ -20,7 +20,7 @@ export const DeletePage: React.FC = () => { const deleteFile = async () => { await axios({ method: 'delete', - url: `${DeleteFileProps.delete_url}${ + url: `${process.env.REACT_APP_BACKEND_BASEURL}${DeleteFileProps.delete_url}${ DeleteFileProps.isEncrypted ? `?token=${DeleteFileProps.token}` : '' }`, }) diff --git a/src/pages/download/index.tsx b/src/pages/download/index.tsx index 734f498..fdbba3b 100644 --- a/src/pages/download/index.tsx +++ b/src/pages/download/index.tsx @@ -8,7 +8,7 @@ import { toast } from 'react-toastify'; import { Button, FileBox, SkeletonUI } from '../../components'; import { useDeletePageNavigator } from '../../hooks'; import { RootState } from '../../state/reducers'; -import { getDate, getFileSize } from '../../utils'; +import { getDate, getFileSize, getExpireTime } from '../../utils'; import * as S from './styled'; export const DownloadPage: React.FC = () => { @@ -24,6 +24,8 @@ export const DownloadPage: React.FC = () => { download_url: '', delete_url: '', isEncrypted: false, + downloadCount: 0, + expireTime: { day: 0, hour: 0, minute: 0 }, }); const [move] = useDeletePageNavigator( fileProps.delete_url, @@ -53,6 +55,8 @@ export const DownloadPage: React.FC = () => { download_url: res.data.download_url, delete_url: res.data.delete_url, isEncrypted: res.data.isEncrypted, + downloadCount: res.data.downloadLimit - res.data.downloadCount, + expireTime: getExpireTime(res.data.expireTime), }); } }) @@ -81,9 +85,13 @@ export const DownloadPage: React.FC = () => { 파일이름:{fileProps.filename} / 크기:{fileProps.size} / 업로드된 날짜: {fileProps.uploadDate.year}-{fileProps.uploadDate.month}-{fileProps.uploadDate.day} + + 만료까지 {fileProps.expireTime.day}일 {fileProps.expireTime.hour}시간{' '} + {fileProps.expireTime.minute}분 / {fileProps.downloadCount}회 남았습니다. + diff --git a/src/pages/download/styled.ts b/src/pages/download/styled.ts index 54ad386..8293d46 100644 --- a/src/pages/download/styled.ts +++ b/src/pages/download/styled.ts @@ -13,3 +13,10 @@ export const DownloadPageButtonSection = styled.div` justify-content: center; margin-top: 3rem; `; + +export const DownloadFileStatusText = styled.div` + color: var(--color-text-primary); + font-size: 2rem; + font-weight: 600; + margin-top: 3rem; +`; diff --git a/src/pages/main/index.tsx b/src/pages/main/index.tsx index 53653af..99e7d57 100644 --- a/src/pages/main/index.tsx +++ b/src/pages/main/index.tsx @@ -5,9 +5,17 @@ import { useNavigate } from 'react-router-dom'; import { toast } from 'react-toastify'; import { bindActionCreators } from 'redux'; -import { CheckBox, PasswordInput, UpLoadButton, FileFind, Progress } from '../../components'; +import { + CheckBox, + PasswordInput, + UpLoadButton, + FileFind, + Progress, + DownloadCountSlider, + ExpireTime, +} from '../../components'; import { actionCreators } from '../../state'; -import { getFileSize } from '../../utils'; +import { getFileSize, getTime } from '../../utils'; import * as S from './styled'; export const MainPage: React.FC = () => { @@ -17,11 +25,14 @@ export const MainPage: React.FC = () => { const [progressValue, setProgressValue] = useState(0); const [progressStateText, setProgressStateText] = useState('uploading'); - const [retentionPeriod, setRetentionPeriod] = useState(false); - const [downloadCount, setDownloadCount] = useState(false); + const [expireTimeBoolean, setExpireTimeBoolean] = useState(false); + const [downloadCountBoolean, setDownloadCountBoolean] = useState(false); const [passwordBoolean, setPasswordBoolean] = useState(false); + const [expireTime, setExpireTime] = useState(1); + const [downloadCount, setDownloadCount] = useState(100); const [password, setPassword] = useState(''); + const [fileProps, setFileProps] = useState({ filename: '', size: '', @@ -56,7 +67,10 @@ export const MainPage: React.FC = () => { data: formdata, headers: { 'Content-Type': 'multipart/form-data', + 'X-Download-Limit': downloadCountBoolean ? downloadCount : 100, + 'X-Time-Limit': expireTimeBoolean ? expireTime : 180, }, + withCredentials: true, onUploadProgress(progress) { setUploading(false); setProgressValue(Math.floor((progress.loaded / progress.total) * 100)); @@ -111,24 +125,17 @@ export const MainPage: React.FC = () => { { - setRetentionPeriod(false); - toast.success('제작중!', { - autoClose: 1000, - position: toast.POSITION.BOTTOM_RIGHT, - }); + setExpireTimeBoolean(!expireTimeBoolean); }} - isCheck={retentionPeriod} + isCheck={expireTimeBoolean} label={'유지기간'} /> { - setDownloadCount(false); - toast.success('제작중!', { - autoClose: 1000, - position: toast.POSITION.BOTTOM_RIGHT, - }); + setDownloadCountBoolean(!downloadCountBoolean); + setDownloadCount(1); }} - isCheck={downloadCount} + isCheck={downloadCountBoolean} label={'다운로드 횟수'} /> { label={'비밀번호'} /> - {passwordBoolean ? ( + {expireTimeBoolean && ( + + )} + {downloadCountBoolean && ( + + )} + {passwordBoolean && ( { setPassword(text.target.value.replace(/(\s*)/g, '')); }} placeholder="비밀번호를 입력해주세요." /> - ) : ( - <> )} diff --git a/src/styles/globalStyle.ts b/src/styles/globalStyle.ts index 5a8f153..f74dc44 100644 --- a/src/styles/globalStyle.ts +++ b/src/styles/globalStyle.ts @@ -30,6 +30,10 @@ export const globalStyle = css` --color-button-primary: var(--color-border); --color-button-secondary: #aa75ab; + --color-slider-thumb: var(--color-text-primary); + --color-slider-upper: #757bab; + --color-slider-lower: #2e2836; + --small-mobile-breakpoint: 575px; --mobile-breakpoint: 767px; --tablet-breakpoint: 991px; diff --git a/src/utils/getDate.ts b/src/utils/getDate.ts index 8bd3546..d5dbd03 100644 --- a/src/utils/getDate.ts +++ b/src/utils/getDate.ts @@ -1,4 +1,41 @@ +const today = new Date(); + export const getDate = (date: string) => { const NewDate = date.split('T')[0].split('-'); return { year: Number(NewDate[0]), month: Number(NewDate[1]), day: Number(NewDate[2]) }; }; + +export const getExpireTime = (date: string) => { + const expireTime = new Date(date); + const differenceTime = expireTime.getTime() - today.getTime(); + const differenceTimeDay = + differenceTime / (1000 * 60 * 60 * 24) <= 0 ? differenceTime / (1000 * 60 * 60 * 24) : 0; + let differenceTimeHour = differenceTime / (1000 * 60 * 60); + while (true) { + differenceTimeHour %= 24; + if (differenceTimeHour <= 24) { + break; + } + } + let differenceTimeMinute = differenceTime / (1000 * 60); + while (true) { + differenceTimeMinute %= 60; + if (differenceTimeMinute <= 60) { + break; + } + } + return { + day: Math.floor(differenceTimeDay), + hour: Math.floor(differenceTimeHour), + minute: Math.floor(differenceTimeMinute), + }; +}; + +export const getTime = (minute: number) => ({ + day: Math.floor(minute / 1440), + hour: + Math.floor(minute / 60) % Math.floor(minute % 1440) >= 0 + ? Math.floor(Math.floor(minute % 1440) / 60) + : Math.floor(minute / 60), + minute: minute % Math.floor(minute / 60) >= 0 ? Math.floor(minute % 60) : minute, +});